diff --git a/python/data/steel_mill/steel_mill_slab_hard.txt b/python/data/steel_mill/steel_mill_slab_hard.txt new file mode 100644 index 0000000000..7153c824d6 --- /dev/null +++ b/python/data/steel_mill/steel_mill_slab_hard.txt @@ -0,0 +1,115 @@ +14 11 20 22 23 24 26 27 29 32 38 42 43 44 50 +88 +111 +4 1 +22 2 +9 3 +5 4 +8 5 +3 6 +3 4 +4 7 +7 4 +7 8 +3 6 +2 6 +2 4 +8 9 +5 10 +7 11 +4 7 +7 11 +5 10 +7 11 +8 9 +3 1 +25 12 +14 13 +3 6 +22 14 +19 15 +19 15 +22 16 +22 17 +22 18 +20 19 +22 20 +5 21 +4 22 +10 23 +26 24 +17 25 +20 26 +16 27 +10 28 +19 29 +10 30 +10 31 +23 32 +22 33 +26 34 +27 35 +22 36 +27 37 +22 38 +22 39 +13 40 +14 41 +16 27 +26 34 +26 42 +27 35 +22 36 +20 43 +26 24 +22 44 +13 45 +19 46 +20 47 +16 48 +15 49 +17 50 +10 28 +20 51 +5 52 +26 24 +19 53 +15 54 +10 55 +10 56 +13 57 +13 58 +13 59 +12 60 +12 61 +18 62 +10 63 +18 64 +16 65 +20 66 +12 67 +6 68 +6 68 +15 69 +15 70 +15 70 +21 71 +30 72 +30 73 +30 74 +30 75 +23 76 +15 77 +15 78 +27 79 +27 80 +27 81 +27 82 +27 83 +27 84 +27 79 +27 85 +27 86 +10 87 +3 88 + diff --git a/python/data/steel_mill/steel_mill_slab_medium.txt b/python/data/steel_mill/steel_mill_slab_medium.txt new file mode 100644 index 0000000000..231a150d22 --- /dev/null +++ b/python/data/steel_mill/steel_mill_slab_medium.txt @@ -0,0 +1,115 @@ +17 12 14 17 18 21 25 29 32 33 34 35 37 38 40 44 45 48 +88 +111 +4 1 +22 2 +9 3 +5 4 +8 5 +3 6 +3 4 +4 7 +7 4 +7 8 +3 6 +2 6 +2 4 +8 9 +5 10 +7 11 +4 7 +7 11 +5 10 +7 11 +8 9 +3 1 +25 12 +14 13 +3 6 +22 14 +19 15 +19 15 +22 16 +22 17 +22 18 +20 19 +22 20 +5 21 +4 22 +10 23 +26 24 +17 25 +20 26 +16 27 +10 28 +19 29 +10 30 +10 31 +23 32 +22 33 +26 34 +27 35 +22 36 +27 37 +22 38 +22 39 +13 40 +14 41 +16 27 +26 34 +26 42 +27 35 +22 36 +20 43 +26 24 +22 44 +13 45 +19 46 +20 47 +16 48 +15 49 +17 50 +10 28 +20 51 +5 52 +26 24 +19 53 +15 54 +10 55 +10 56 +13 57 +13 58 +13 59 +12 60 +12 61 +18 62 +10 63 +18 64 +16 65 +20 66 +12 67 +6 68 +6 68 +15 69 +15 70 +15 70 +21 71 +30 72 +30 73 +30 74 +30 75 +23 76 +15 77 +15 78 +27 79 +27 80 +27 81 +27 82 +27 83 +27 84 +27 79 +27 85 +27 86 +10 87 +3 88 + diff --git a/python/steel.py b/python/steel.py index 9a3289909e..66c07967e4 100644 --- a/python/steel.py +++ b/python/steel.py @@ -1,4 +1,4 @@ -# Copyright 2010 Pierre Schaus pschaus@gmail.com +# Copyright 2010 Pierre Schaus pschaus@gmail.com, Laurent Perron # # Licensed under the Apache License, Version 2.0 (the 'License'); # you may not use this file except in compliance with the License. @@ -54,7 +54,7 @@ def ReadData(filename): loss = [min(filter(lambda x: x >= c, capacity)) - c for c in range(max_capacity + 1)] color_orders = [filter(lambda o: colors[o] == c, range(nb_slabs)) - for c in range(1, nb_colors + 1)] + for c in range(1, nb_colors + 1)] print 'Solving steel mill with', nb_slabs, 'slabs' return (nb_slabs, capacity, max_capacity, weights, colors, loss, color_orders) @@ -65,30 +65,50 @@ class SteelDecisionBuilder(pywrapcp.PyDecisionBuilder): '''Dedicated Decision Builder for steel mill slab. Search for the steel mill slab problem with Dynamic Symmetry - Breaking during search (see the paper of Pascal Van Hentenryck and - Laurent Michel CPAIOR-2008). - ''' - # TODO: add the value heuristic from the paper Schaus et. al. - # to appear in Constraints 2010 + Breaking during search is an adaptation (for binary tree) from the paper of Pascal Van Hentenryck and + Laurent Michel CPAIOR-2008. - def __init__(self, x, nb_slabs, weights): + The value heuristic comes from the paper + Solving Steel Mill Slab Problems with Constraint-Based Techniques: CP, LNS, and CBLS, + Schaus et. al. to appear in Constraints 2010 + ''' + + def __init__(self, x, nb_slabs, weights, losstab, loads): self.__x = x self.__nb_slabs = nb_slabs self.__weights = weights + self.__losstab = losstab + self.__loads = loads + self.__maxcapa = len(losstab)-1 + def Next(self, solver): - var = self.NextVar() + var,weight = self.NextVar() if var: v = self.MaxBound() if v + 1 == var.Min(): - var.SetValue(v + 1) + solver.Add(var == v + 1) return self.Next(solver) else: - decision = solver.AssignVariableValue(var, var.Min()) + #value heuristic (important for difficult problem): + # try first to place the order in the slab that will induce the least increase of the loss + loads = self.getLoads() + l,v = min((self.__losstab[loads[i]+weight],i) + for i in range(var.Min(),var.Max()+1) + if var.Contains(i) and loads[i]+weight <= self.__maxcapa) + decision = solver.AssignVariableValue(var, v) return decision else: return None + def getLoads(self): + load = [0]*len(self.__loads) + for w,x in zip(self.__weights,self.__x): + if x.Bound(): + load[x.Min()] += w + return load + + def MaxBound(self): ''' returns the max value bound to a variable, -1 if no variables bound''' return max([-1] + [self.__x[o].Min() @@ -97,14 +117,14 @@ class SteelDecisionBuilder(pywrapcp.PyDecisionBuilder): def NextVar(self): ''' mindom size heuristic with tie break on the weights of orders ''' - res = [(self.__x[o].Size(), -self.__weights[o], o, self.__x[o]) + res = [(self.__x[o].Size(), -self.__weights[o], self.__x[o]) for o in range(self.__nb_slabs) if self.__x[o].Size() > 1] if res: res.sort() - return res[0][3] + return res[0][2],-res[0][1] #returns the order var and its weight else: - return None + return None, None def DebugString(self): return 'SteelMillDecisionBuilder(' + str(self.__x) + ')' @@ -112,13 +132,13 @@ class SteelDecisionBuilder(pywrapcp.PyDecisionBuilder): def main(unused_argv): #------------------solver and variable declaration------------- - (nb_slabs, capacity, max_capacity, weights, colors, loss, color_orders) = \ + (nb_slabs, capacity, max_capacity, weights, colors, loss, color_orders) =\ ReadData(FLAGS.data) nb_colors = len(color_orders) solver = pywrapcp.Solver('Steel Mill Slab') x = [solver.IntVar(0, nb_slabs - 1, 'x' + str(i)) for i in range(nb_slabs)] - load_vars = [solver.IntVar(0, max_capacity, 'load_vars' + str(i)) + load_vars = [solver.IntVar(0, max_capacity - 1, 'load_vars' + str(i)) for i in range(nb_slabs)] #-------------------post of the constraints-------------- @@ -139,17 +159,14 @@ def main(unused_argv): #------------start the search and optimization----------- - db = SteelDecisionBuilder(x, nb_slabs, weights) + db = SteelDecisionBuilder(x, nb_slabs, weights, loss, load_vars) search_log = solver.SearchLog(100000, objective_var) - solver.NewSearch(db, [objective]) + solver.NewSearch(db, [objective, search_log]) while solver.NextSolution(): print 'Objective:', objective_var.Value(),\ - 'check:', sum(loss[load_vars[s].Min()] for s in range(nb_slabs)),\ - ', time = ', solver.wall_time(), 'ms' + 'check:', sum(loss[load_vars[s].Min()] for s in range(nb_slabs)) solver.EndSearch() - print 'time =', solver.wall_time(), 'ms' - print 'failures =', solver.failures() if __name__ == '__main__': - main('cp sample') + app.run()