Skip to content

Instantly share code, notes, and snippets.

@manofstick
Created July 4, 2018 07:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save manofstick/33fefb8ac6b60d401375be738b521ac3 to your computer and use it in GitHub Desktop.
Save manofstick/33fefb8ac6b60d401375be738b521ac3 to your computer and use it in GitHub Desktop.
Modified
open Perf
open System
open System.Diagnostics
open System.IO
open System.Collections.Generic
let inline run<'key when 'key : equality> (comparer:IComparer<'key>) (createKey:int -> int -> 'key) =
let g_maxSize = 4480
let fileSizes = [ 1 .. 99 ]
let optimalResults = SortedDictionary comparer
let lastStep = SortedDictionary comparer
let inline FetchOrZero (dict:SortedDictionary<_,_>) (k:'key) =
let mutable v = Unchecked.defaultof<_>
if dict.TryGetValue (k, &v) then v else 0
for containerSize in 0 .. g_maxSize do
for (idx,fileSize) in List.mapi (fun i x -> (i,x)) fileSizes do
// We will index the "optimalResults" via tuples:
let cellCurrent = createKey containerSize idx // The current cell
let cellOnTheLeftOfCurrent = createKey containerSize (idx-1) // The cell on our left
// Does the file on column "idx" fit inside containerSize?
if containerSize<fileSize then
// it doesn't fit in containerSize
// so copy optimal value from the cell on its left
optimalResults.[cellCurrent] <- FetchOrZero optimalResults cellOnTheLeftOfCurrent
// Copy last step from cell on the left...
lastStep.[cellCurrent] <- FetchOrZero lastStep cellOnTheLeftOfCurrent
else
// It fits!
// Using file of column "idx", the remaining space is...
let remainingSpace = containerSize - fileSize
// and for that remaining space, the optimal result
// using the first idx-1 files has been found to be:
let optimalResultOfRemainingSpace = FetchOrZero optimalResults (createKey remainingSpace (idx-1))
// so let's check: do we improve things by using "idx"?
if optimalResultOfRemainingSpace + fileSize > FetchOrZero optimalResults cellOnTheLeftOfCurrent then
// we improved the best result, store it!
optimalResults.[cellCurrent] <- optimalResultOfRemainingSpace + fileSize
// Store last step - i.e. using file "idx"
lastStep.[cellCurrent] <- fileSize
else
// no improvement by using "idx" - copy from left...
optimalResults.[cellCurrent] <- FetchOrZero optimalResults cellOnTheLeftOfCurrent
// Copy last step from cell on the left...
lastStep.[cellCurrent] <- FetchOrZero lastStep cellOnTheLeftOfCurrent
// printfn "Attainable: %d" (FetchOrZero optimalResults (g_maxSize,fileSizes.Length-1))
// Navigate backwards... starting from the optimal result:
let rightMostIndex = fileSizes.Length-1
let mutable total = FetchOrZero optimalResults (createKey g_maxSize rightMostIndex)
while total>0 do
// The last step we used to get to "total" was...
let lastFileSize = lastStep.[createKey total rightMostIndex]
// printfn "%d removing %d" total lastFileSize
// And the one before the last step was... (loop)
total <- total - lastFileSize
total
let runTrials theType f =
let count = 10
printf "%s " theType
let runs = ResizeArray ()
for i = 1 to count do
System.GC.Collect ()
let sw = Stopwatch.StartNew ()
let t = f ()
System.GC.Collect ()
runs.Add sw.ElapsedMilliseconds
printf "."
runs.Sort ()
let averageTime =
runs
|> Seq.skip 2
|> Seq.take (count-4)
|> Seq.map float
|> Seq.average
printfn " %0.2f" averageTime
type GenericStruct<'a> =
struct
val Item1 : 'a
val Item2 : 'a
new (i1, i2) = { Item1 = i1; Item2 = i2 }
end
type Struct =
struct
val Item1 : int
val Item2 : int
new (i1, i2) = { Item1 = i1; Item2 = i2 }
end
type GenericRef<'a> = {
Item1 : 'a
Item2 : 'a
}
type Ref = {
Item1 : int
Item2 : int
}
module Help =
let IEquatable_Equals<'a when 'a :> IEquatable<'a>> (this:'a) (other:'a) =
this.Equals other
let IComparable_CompareTo<'a when 'a :> IComparable<'a>> (this:'a) (other:'a) =
this.CompareTo other
[<CustomEquality; CustomComparison>]
type CustomStruct =
struct
val Item1 : int
val Item2 : int
new (i1, i2) = { Item1 = i1; Item2 = i2 }
override this.Equals other =
match other with
| :? CustomStruct as other -> Help.IEquatable_Equals this other
| _ -> failwith "unexpected"
override this.GetHashCode () =
(this.Item1 <<< 5) + this.Item1 ^^^ this.Item2 // the same as Tuple
interface IEquatable<CustomStruct> with
member this.Equals other =
other.Item1 = this.Item1 && other.Item2 = this.Item2
interface IComparable<CustomStruct> with
member this.CompareTo other =
match other.Item1.CompareTo this.Item1 with
| 0 -> other.Item2.CompareTo this.Item2
| c -> c
interface IComparable with
member this.CompareTo other =
match other with
| :? CustomStruct as other -> Help.IComparable_CompareTo this other
| _ -> failwith "unexpected"
end
type Comparer<'a when 'a : comparison>() =
member __.Comparer = LanguagePrimitives.FastGenericComparer<'a>
type DynamicComparer<'a when 'a : comparison> =
static member Comparer =
let t = typedefof<Comparer<_>>.MakeGenericType [|typeof<'a>|]
match System.Activator.CreateInstance t with
| :? Comparer<'a> as c -> c.Comparer
| _ -> failwith "unexpected"
let customDynamic () = run DynamicComparer.Comparer (fun x y -> CustomStruct(x, y))
let customStructural () = run LanguagePrimitives.FastGenericComparer (fun x y -> CustomStruct(x, y))
let customDefault () = run Comparer.Default (fun x y -> CustomStruct(x, y))
let valueDynamic () = run DynamicComparer.Comparer (fun x y -> Struct(x, y))
let valueStructural () = run LanguagePrimitives.FastGenericComparer (fun x y -> Struct(x, y))
let valueDefault () = run Comparer.Default (fun x y -> Struct(x, y))
let genValueDynamic () = run DynamicComparer.Comparer (fun x y -> GenericStruct(x, y))
let genValueStructural () = run LanguagePrimitives.FastGenericComparer (fun x y -> GenericStruct(x, y))
let genValueDefault () = run Comparer.Default (fun x y -> GenericStruct(x, y))
let refDynamic () = run DynamicComparer.Comparer (fun x y -> { Ref.Item1 = x; Item2 = y })
let refStructural () = run LanguagePrimitives.FastGenericComparer (fun x y -> { Ref.Item1 = x; Item2 = y })
let refDefault () = run Comparer.Default (fun x y -> { Ref.Item1 = x; Item2 = y })
let genRefDynamic () = run DynamicComparer.Comparer (fun x y -> { GenericRef.Item1 = x; Item2 = y })
let genRefStructural () = run LanguagePrimitives.FastGenericComparer (fun x y -> { GenericRef.Item1 = x; Item2 = y })
let genRefDefault () = run Comparer.Default (fun x y -> { GenericRef.Item1 = x; Item2 = y })
let tupleDynamic () = run DynamicComparer.Comparer (fun x y -> x,y)
let tupleStructural () = run LanguagePrimitives.FastGenericComparer (fun x y -> x,y)
let tupleDefault () = run Comparer.Default (fun x y -> x,y)
let valueTupleDynamic () = run DynamicComparer.Comparer (fun x y -> struct (x,y))
let valueTupleStructural () = run LanguagePrimitives.FastGenericComparer (fun x y -> struct (x,y))
let valueTupleDefault () = run Comparer.Default (fun x y -> struct (x,y))
[<EntryPoint>]
let main (args : string[]) =
printfn "%s\n" Id.Name
runTrials "custom dynamic " customDynamic
runTrials "custom structural " customStructural
runTrials "custom default " customDefault
runTrials "value dynamic " valueDynamic
runTrials "value structural " valueStructural
runTrials "value default " valueDefault
runTrials "gen value dynamic " genValueDynamic
runTrials "gen value structural " genValueStructural
runTrials "gen value default " genValueDefault
runTrials "ref dynamic " refDynamic
runTrials "ref structural " refStructural
runTrials "ref default " refDefault
runTrials "gen ref dynamic " genRefDynamic
runTrials "gen ref structural " genRefStructural
runTrials "gen ref default " genRefDefault
runTrials "tuple dynamic " tupleDynamic
runTrials "tuple structural " tupleStructural
runTrials "tuple default " tupleDefault
runTrials "value tuple dynamic " valueTupleDynamic
runTrials "value tuple structural" valueTupleStructural
runTrials "value tuple default " valueTupleDefault
0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment