5 people like it.
Like the snippet!
Bin Packing
Implementation of the 'best fit' heuristic algorithm for bin packing problems. Incudes an implementation of 'binary tree with duplicates'.
See this blog post for details: http://fwaris.wordpress.com/2013/04/01/best-fit-bin-packing/
Update: Bug fixes and added 'worst fit' heuristic implementation
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
|
module BinPacking
[<RequireQualifiedAccess>]
module Btd =
//binary tree with duplicates: key-value, size, left subtree and right subtree
type T<'a,'b> = T of ('a*'b)*int*T<'a,'b> option*T<'a,'b> option
type private Direction = Left | Right
let empty = None
let size t = match t with None -> 0 | Some (T(_,s,_,_)) -> s
let private (~~) = size
let rec private percolate t path =
match path with
| [] -> t
| (Left,T(kv,s,left,right))::rest ->
percolate (Some (T(kv,s - ~~left + ~~t, t, right))) rest
| (Right,T(kv,s,left,right))::rest -> percolate (Some (T(kv,s - ~~right + ~~t, left, t))) rest
let rec private insert child t path =
match t with
| None -> percolate child path
| Some (T((pk,_),_,l,r) as t2) ->
match child with
| None -> t
| Some (T((ck,_),_,_,_)) ->
if ck < pk then insert child l ((Left,t2)::path)
else insert child r ((Right,t2)::path)
let add e t = insert (Some(T(e,1,None,None))) t []
let merge l r =
match l,r with
| None, t -> t
| t, None -> t
| Some(T(_,ls,_,_)),Some(T(_,rs,_,_)) ->
if ls < rs then insert r l []
else insert l r []
let remove kv t =
let rec remove ((k,v) as kv) t path =
match t with
| None -> None
| Some (T((k',v') as kv',s,l,r) as t) ->
if kv = kv' then
match path with
| [] -> merge l r //root removed
| _ -> percolate None path
elif k < k' then remove kv l ((Left,t)::path)
else remove kv r ((Right,t)::path)
match remove kv t [] with
| None -> t
| x -> x
let findBestFit c t =
let rec findBestFit c t currentBest =
match t with
| None -> currentBest
| Some (T((k,v),_,l,r)) ->
if c = k then Some(k,v)
elif c < k then findBestFit c l (Some(k,v))
else findBestFit c r currentBest
findBestFit c t None
type Bin<'a> = {Size:int; Id:string; Data:'a}
type Item<'a> = {Size:int; Data:'a}
let rec private fillItems (map:Map<Bin<_>,Item<_>list>, t, remaining) =
match remaining with
| [] -> map, t, []
| x::rest ->
match t |> Btd.findBestFit x.Size with
| None -> map,t,remaining //can't add any more items into the current bin tree structure
| Some ((capacity,bin) as kv) ->
let remainingCapacity = capacity - x.Size
let t' = t |> Btd.remove kv |> Btd.add (remainingCapacity,bin)
let map' =
match map |> Map.tryFind bin with
| None -> map |> Map.add bin [x]
| Some l -> map |> Map.add bin (x::l)
fillItems (map', t', rest)
///implements the best-fit heuristic algorithm for 1-dimensional bin packing
let pack (availableBins:Bin<_> list) (items:Item<_> list) =
let map,t,remaining =
((Map.empty,Btd.empty,items), availableBins) ||> List.fold (fun (map,t,remaining) bin ->
match remaining with
| [] -> map,t,[] //no more items remaining
| xs -> fillItems (map,t |> Btd.add (bin.Size,bin),xs)) //add a bin to tree and fill items
map,remaining
(* usage:
let bins = [{Size=150; Id="a"; Data="a"}; {Size=235; Id="b"; Data="b"}; {Size=215;Id="c"; Data="c"}]
let rng = System.Random()
let items = [for i in 1..40 -> {Size = rng.Next(1,30); Data=i.ToString()}]
//sort items in descending order of size for best-fit decreasing order
let sortedItems = items |> List.sortBy (fun i -> -i.Size)
let schedule,leftOverItems = pack bins sortedItems
*)
|
module BinPacking
Multiple items
type RequireQualifiedAccessAttribute =
inherit Attribute
new : unit -> RequireQualifiedAccessAttribute
Full name: Microsoft.FSharp.Core.RequireQualifiedAccessAttribute
--------------------
new : unit -> RequireQualifiedAccessAttribute
type T<'a,'b> = | T of ('a * 'b) * int * T<'a,'b> option * T<'a,'b> option
Full name: BinPacking.Btd.T<_,_>
union case T.T: ('a * 'b) * int * T<'a,'b> option * T<'a,'b> option -> T<'a,'b>
Multiple items
val int : value:'T -> int (requires member op_Explicit)
Full name: Microsoft.FSharp.Core.Operators.int
--------------------
type int = int32
Full name: Microsoft.FSharp.Core.int
--------------------
type int<'Measure> = int
Full name: Microsoft.FSharp.Core.int<_>
type 'T option = Option<'T>
Full name: Microsoft.FSharp.Core.option<_>
type private Direction =
| Left
| Right
Full name: BinPacking.Btd.Direction
union case Direction.Left: Direction
union case Direction.Right: Direction
val empty : 'a option
Full name: BinPacking.Btd.empty
union case Option.None: Option<'T>
val size : t:T<'a,'b> option -> int
Full name: BinPacking.Btd.size
val t : T<'a,'b> option
union case Option.Some: Value: 'T -> Option<'T>
val s : int
val private percolate : t:T<'a,'b> option -> path:(Direction * T<'a,'b>) list -> T<'a,'b> option
Full name: BinPacking.Btd.percolate
val path : (Direction * T<'a,'b>) list
val kv : 'a * 'b
val left : T<'a,'b> option
val right : T<'a,'b> option
val rest : (Direction * T<'a,'b>) list
val private insert : child:T<'a,'b> option -> t:T<'a,'b> option -> path:(Direction * T<'a,'b>) list -> T<'a,'b> option (requires comparison)
Full name: BinPacking.Btd.insert
val child : T<'a,'b> option (requires comparison)
val t : T<'a,'b> option (requires comparison)
val path : (Direction * T<'a,'b>) list (requires comparison)
val pk : 'a (requires comparison)
val l : T<'a,'b> option (requires comparison)
val r : T<'a,'b> option (requires comparison)
val t2 : T<'a,'b> (requires comparison)
val ck : 'a (requires comparison)
val add : 'a * 'b -> t:T<'a,'b> option -> T<'a,'b> option (requires comparison)
Full name: BinPacking.Btd.add
val e : 'a * 'b (requires comparison)
val merge : l:T<'a,'b> option -> r:T<'a,'b> option -> T<'a,'b> option (requires comparison)
Full name: BinPacking.Btd.merge
val ls : int
val rs : int
val remove : 'a * 'b -> t:T<'a,'b> option -> T<'a,'b> option (requires comparison and equality)
Full name: BinPacking.Btd.remove
val kv : 'a * 'b (requires comparison and equality)
val t : T<'a,'b> option (requires comparison and equality)
val remove : ('c * 'd -> T<'c,'d> option -> (Direction * T<'c,'d>) list -> T<'c,'d> option) (requires comparison and equality)
val k : 'c (requires comparison)
val v : 'd (requires equality)
val kv : 'c * 'd (requires comparison and equality)
val t : T<'c,'d> option (requires comparison and equality)
val path : (Direction * T<'c,'d>) list (requires comparison and equality)
val k' : 'c (requires comparison)
val v' : 'd (requires equality)
val kv' : 'c * 'd (requires comparison and equality)
val l : T<'c,'d> option (requires comparison and equality)
val r : T<'c,'d> option (requires comparison and equality)
val t : T<'c,'d> (requires comparison and equality)
val x : T<'a,'b> option (requires comparison and equality)
val findBestFit : c:'a -> t:T<'a,'b> option -> ('a * 'b) option (requires comparison)
Full name: BinPacking.Btd.findBestFit
val c : 'a (requires comparison)
val findBestFit : ('c -> T<'c,'d> option -> ('c * 'd) option -> ('c * 'd) option) (requires comparison)
val c : 'c (requires comparison)
val t : T<'c,'d> option (requires comparison)
val currentBest : ('c * 'd) option (requires comparison)
val v : 'd
val l : T<'c,'d> option (requires comparison)
val r : T<'c,'d> option (requires comparison)
type Bin<'a> =
{Size: int;
Id: string;
Data: 'a;}
Full name: BinPacking.Bin<_>
Bin.Size: int
Bin.Id: string
Multiple items
val string : value:'T -> string
Full name: Microsoft.FSharp.Core.Operators.string
--------------------
type string = System.String
Full name: Microsoft.FSharp.Core.string
Multiple items
Bin.Data: 'a
--------------------
namespace Microsoft.FSharp.Data
type Item<'a> =
{Size: int;
Data: 'a;}
Full name: BinPacking.Item<_>
Item.Size: int
Multiple items
Item.Data: 'a
--------------------
namespace Microsoft.FSharp.Data
val private fillItems : map:Map<Bin<'a>,Item<'b> list> * t:Btd.T<int,Bin<'a>> option * remaining:Item<'b> list -> Map<Bin<'a>,Item<'b> list> * Btd.T<int,Bin<'a>> option * Item<'b> list (requires comparison)
Full name: BinPacking.fillItems
val map : Map<Bin<'a>,Item<'b> list> (requires comparison)
Multiple items
module Map
from Microsoft.FSharp.Collections
--------------------
type Map<'Key,'Value (requires comparison)> =
interface IEnumerable
interface IComparable
interface IEnumerable<KeyValuePair<'Key,'Value>>
interface ICollection<KeyValuePair<'Key,'Value>>
interface IDictionary<'Key,'Value>
new : elements:seq<'Key * 'Value> -> Map<'Key,'Value>
member Add : key:'Key * value:'Value -> Map<'Key,'Value>
member ContainsKey : key:'Key -> bool
override Equals : obj -> bool
member Remove : key:'Key -> Map<'Key,'Value>
...
Full name: Microsoft.FSharp.Collections.Map<_,_>
--------------------
new : elements:seq<'Key * 'Value> -> Map<'Key,'Value>
type 'T list = List<'T>
Full name: Microsoft.FSharp.Collections.list<_>
val t : Btd.T<int,Bin<'a>> option (requires comparison)
val remaining : Item<'b> list
val x : Item<'b>
val rest : Item<'b> list
module Btd
from BinPacking
val findBestFit : c:'a -> t:Btd.T<'a,'b> option -> ('a * 'b) option (requires comparison)
Full name: BinPacking.Btd.findBestFit
val capacity : int
val bin : Bin<'a> (requires comparison)
val kv : int * Bin<'a> (requires comparison)
val remainingCapacity : int
val t' : Btd.T<int,Bin<'a>> option (requires comparison)
val remove : 'a * 'b -> t:Btd.T<'a,'b> option -> Btd.T<'a,'b> option (requires comparison and equality)
Full name: BinPacking.Btd.remove
val add : 'a * 'b -> t:Btd.T<'a,'b> option -> Btd.T<'a,'b> option (requires comparison)
Full name: BinPacking.Btd.add
val map' : Map<Bin<'a>,Item<'b> list> (requires comparison)
val tryFind : key:'Key -> table:Map<'Key,'T> -> 'T option (requires comparison)
Full name: Microsoft.FSharp.Collections.Map.tryFind
val add : key:'Key -> value:'T -> table:Map<'Key,'T> -> Map<'Key,'T> (requires comparison)
Full name: Microsoft.FSharp.Collections.Map.add
val l : Item<'b> list
val pack : availableBins:Bin<'a> list -> items:Item<'b> list -> Map<Bin<'a>,Item<'b> list> * Item<'b> list (requires comparison)
Full name: BinPacking.pack
implements the best-fit heuristic algorithm for 1-dimensional bin packing
val availableBins : Bin<'a> list (requires comparison)
val items : Item<'b> list
val empty<'Key,'T (requires comparison)> : Map<'Key,'T> (requires comparison)
Full name: Microsoft.FSharp.Collections.Map.empty
Multiple items
module List
from Microsoft.FSharp.Collections
--------------------
type List<'T> =
| ( [] )
| ( :: ) of Head: 'T * Tail: 'T list
interface IEnumerable
interface IEnumerable<'T>
member Head : 'T
member IsEmpty : bool
member Item : index:int -> 'T with get
member Length : int
member Tail : 'T list
static member Cons : head:'T * tail:'T list -> 'T list
static member Empty : 'T list
Full name: Microsoft.FSharp.Collections.List<_>
val fold : folder:('State -> 'T -> 'State) -> state:'State -> list:'T list -> 'State
Full name: Microsoft.FSharp.Collections.List.fold
val xs : Item<'b> list
More information