diff options
Diffstat (limited to 'ipl/gprogs/bpack.icn')
-rw-r--r-- | ipl/gprogs/bpack.icn | 435 |
1 files changed, 435 insertions, 0 deletions
diff --git a/ipl/gprogs/bpack.icn b/ipl/gprogs/bpack.icn new file mode 100644 index 0000000..1a01764 --- /dev/null +++ b/ipl/gprogs/bpack.icn @@ -0,0 +1,435 @@ +############################################################################ +# +# File: bpack.icn +# +# Subject: Program to demonstrate some bin packing algorithms +# +# Author: Gregg M. Townsend +# +# Date: August 7, 1998 +# +############################################################################ +# +# This file is in the public domain. +# +############################################################################ +# +# Usage: bpack [window options] +# +# Bpack illustrates several approximation algorithms for solving the +# one-dimensional bin packing problem. +# +# For a discussion of this program, see +# http://www.cs.arizona.edu/icon/oddsends/bpack/bpack.htm +# +# For references, see the "about" screen. +# +############################################################################ +# +# Requires: Version 9 graphics +# +############################################################################ +# +# Links: numbers, graphics, random, vsetup +# +############################################################################ + + + +link numbers +link graphics +link random +link vsetup + +$define Version "Binpack Lite (November, 1997)" + +$define FULL 61261200 # value representing a full bin + # (least common multiple of {1 to 18, 20, and 25}) + +$define PieceWidth 6 # width of one piece +$define BinWidth 7 # width of one bin + + + +# pieces +global pieces # list of piece sizes + +# current output parameters +global xll, yll # display origin +global bin # list of current bin sizes +global nfilled # number of bins (partially) filled + +# colors +global color # array of GCs of different colors +global cscale # conversion from piece size to color index + +# display regions +global shelf1 # input segments +global shelf2 # packed bins + + + +######################### main program ######################### + +procedure main(args) + local v, r, c, gc + + randomize() # set irreproducible mode + + v := ui(args) # open window, set up vib-built vidgets + r := v["root"] + shelf1 := v["shelf1"] + shelf2 := v["shelf2"] + if shelf1.uw ~= shelf2.uw | shelf1.uw ~= shelf2.uw then + runerr(500, "inconsistent layout") + + # make a set of colors for different bin heights + # note that exactly half are reds/yellows and half are blues & darker + color := [] + every c := Blend( + "black", 1, "deep purple-magenta", 10, "cyan-blue", + 1, "reddish-yellow", 11, "orange-red") do { + gc := Clone(&window) + Fg(gc, c) + put(color, gc) + } + color := copy(color) # ensure contiguous array + cscale := *color / real(FULL + 1) + + reload() # initialize random bins + GetEvents(r) # enter event loop +end + + + +######################### bin packing primitives ######################### + + +# prepare(v) -- prepare shelf v for placing pieces + +procedure prepare(v) + xll := v.ux + yll := v.uy + v.uh + bin := list(*pieces, 0) + nfilled := 0 + EraseArea(v.ux, v.uy, v.uw, v.uh) + return +end + + +# place(p, b) -- add a piece of size p to bin b + +procedure place(p, b) + local o, t, x, y0, y1 + static m + initial m := shelf1.uh / real(FULL) + + o := bin[b] | fail + if (t := o + p) > FULL then + fail + bin[b] := t + nfilled <:= b + + x := xll + (b - 1) * (PieceWidth + 1) + y0 := integer(yll - m * o) + y1 := integer(yll - m * t) + 1 + FillRectangle(color[cscale * p + 1], x, y1, PieceWidth, 0 < (y0 - y1)) + return +end + + +# status(s) -- write string s and shelf population at end of output shelf + +procedure status(s) + local x + + x := xll + nfilled * BinWidth + 4 + x >:= xll + shelf1.uw - TextWidth("000 ") + GotoXY(x, yll - WAttrib("leading") - WAttrib("descent")) + WWrites(s) + GotoXY(x, yll - WAttrib("descent")) + WWrites(nfilled) + return +end + + + +######################### source set manipulation ######################### + + +# reload() -- reload first shelf with random-sized pieces. + +procedure reload() + local i, j, z, p + + pieces := list(shelf1.uw / BinWidth) + prepare(shelf1) + every place(pieces[i := 1 to *pieces] := ?FULL, i) + status("") + return +end + + + +# mix() -- randomly reorder the first shelf. + +procedure mix() + local i + + every i := *pieces to 2 by -1 do + pieces[?i] :=: pieces[i] + + prepare(shelf1) + every place(pieces[i := 1 to *pieces], i) + status("") + return +end + + + +# regular() -- place equally-spaced using golden ratio + +procedure regular() + local i, n, p + + n := integer(*pieces / &phi + 1) + while gcd(*pieces, n) > 1 do + n -:= 1 + i := 0 + every p := !sort(pieces) do { + i := (i + n) % *pieces + pieces[i + 1] := p + } + + prepare(shelf1) + every place(pieces[i := 1 to *pieces], i) + status("") + return +end + + + +# ascending() -- sort the first shelf in ascending order + +procedure ascending() + local i + + pieces := sort(pieces) + prepare(shelf1) + every place(pieces[i := 1 to *pieces], i) + status("") + return +end + + + +# descending() -- sort the first shelf in descending order + +procedure descending() + local i + + pieces := sort(pieces) + every i := 1 to *pieces / 2 do # change from ascending to descending + pieces[i] :=: pieces[-i] + + prepare(shelf1) + every place(pieces[i := 1 to *pieces], i) + status("") + return +end + + + +######################### packing algorithms ######################### + + +# nextfit(l) -- pack using next-fit algorithm + +procedure nextfit(l) + local p + + every p := !l do + place(p, nfilled | nfilled + 1) + return +end + + + +# firstfit(l) -- pack using first-fit algorithm + +procedure firstfit(l) + local p + + every p := !l do + place(p, 1 to nfilled + 1) + return +end + + +# lastfit(l) -- pack using last-fit algorithm + +procedure lastfit(l) + local p + + every p := !l do + place(p, (nfilled to 1 by -1) | (nfilled + 1)) + return +end + + +# bestfit(l) -- pack using best-fit algorithm + +procedure bestfit(l) + local p, b, i, max, found + + every p := !l do { + max := FULL - p # fullest acceptable bin size + found := 0 # size of best bin found so far + b := nfilled + 1 # index of where found + every i := 1 to nfilled do + if found <:= (max >= bin[i]) then + b := i + place(p, b) # place in best bin found + } + return +end + + +# worstfit(l, n) -- pack using worst-fit algorithm + +procedure worstfit(l, n) + local p, b, i, found + + every p := !l do { + found := FULL - p # size of best bin found so far + b := nfilled + 1 # index of where found + every i := 1 to nfilled do + if found >:= bin[i] then + b := i + place(p, b) # place in best bin found + } + return +end + + +# nearworst(l, n) -- pack using almost-worst-fit algorithm + +procedure nearworst(l, n) + local p, a, b, i, found + + every p := !l do { + found := FULL - p # size of best bin found so far + a := b := &null + every i := 1 to nfilled do + if found >:= bin[i] then { + a := b + b := i + } + place(p, \a | \b | (nfilled + 1)) # place in second-best bin found + } + return +end + + + +######################### event handling ######################### + + + +# menu_cb(v, a) -- File and Reorder menu callback + +procedure menu_cb(v, a) + case a[1] of { + "About": about() + "New": reload() + "Quit": exit() + "Random": mix() + "Regular": regular() + "Ascending": ascending() + "Descending": descending() + } +end + + + +# pack_cb(v, a) -- Pack menu callback + +procedure pack_cb(v, a) + local s, p + + a[1] ? { + s := tab(upto(' ')) # get 2- or 3-letter name + } + + prepare(shelf2) # clear the shelf + p := copy(pieces) + case s of { + "FF": firstfit(p) + "LF": lastfit(p) + "NF": nextfit(p) + "BF": bestfit(p) + "WF": worstfit(p) + "AWF": nearworst(p) + } + + status(s) + return +end + + + +# about() -- handle "about" menu entry + +procedure about(x, v) + static text + initial text := ["", + Version, + "by Gregg Townsend, The University of Arizona", + "", + "", + "BF Best Fit picks the fullest possible bin", + "WF Worst Fit picks the emptiest bin", + "AWF Almost Worst Fit picks second-emptiest bin", + "FF First Fit picks the oldest possible bin", + "LF Last Fit picks the newest possible bin", + "NF Next Fit tries only the current bin", + "", + "", + "For more information about bin packing algorithms, see:", + "", + " `Approximation Algorithms for Bin-Packing -- An Updated Survey'", + " by E.G. Coffman, Jr., M.R. Garey, and D.S. Johnson, in", + " Algorithm Design for Computer System Design, ed. by", + " Ausiello, Lucertini, and Serafini, Springer-Verlag, 1984", + "", + " `Fast Algorithms for Bin Packing' by David S. Johnson,", + " Journal of Computer and System Sciences 8, 272-314 (1974)", + ""] + + Notice ! text + return +end + + + +#===<<vib:begin>>=== modify using vib; do not remove this marker line +procedure ui_atts() + return ["size=600,400", "bg=pale gray", "label=Bin Packer"] +end + +procedure ui(win, cbk) +return vsetup(win, cbk, + [":Sizer:::0,0,600,400:Bin Packer",], + ["file:Menu:pull::0,0,36,21:File",menu_cb, + ["About","New","Quit"]], + ["line:Line:::0,22,599,22:",], + ["pack:Menu:pull::93,0,36,21:Pack",pack_cb, + ["FF first fit","LF last fit","NF next fit","BF best fit","WF worst fit", + "AWF almost worst"]], + ["reorder:Menu:pull::36,0,57,21:Reorder",menu_cb, + ["Random","Regular","Ascending","Descending"]], + ["shelf1:Rect:sunken::12,34,576,170:",], + ["shelf2:Rect:sunken::12,217,576,170:",], + ) +end +#===<<vib:end>>=== end of section maintained by vib |