non working version of steel_lns
This commit is contained in:
@@ -416,7 +416,7 @@ class Solver {
|
||||
// Current memory usage in bytes
|
||||
static int64 MemoryUsage();
|
||||
|
||||
|
||||
|
||||
|
||||
// wall_time() in ms since the creation of the solver.
|
||||
int64 wall_time() const;
|
||||
@@ -1143,7 +1143,7 @@ class Solver {
|
||||
SymmetryBreaker* const v3,
|
||||
SymmetryBreaker* const v4);
|
||||
|
||||
|
||||
|
||||
|
||||
// ----- Search Decicions and Decision Builders -----
|
||||
|
||||
@@ -1425,22 +1425,22 @@ class Solver {
|
||||
DecisionBuilder* first_solution,
|
||||
LocalSearchPhaseParameters* parameters);
|
||||
|
||||
|
||||
|
||||
|
||||
// Solution Pool.
|
||||
SolutionPool* MakeDefaultSolutionPool();
|
||||
|
||||
// Local Search Phase Parameters
|
||||
LocalSearchPhaseParameters* MakeLocalSearchPhaseParameters(
|
||||
LocalSearchOperator* ls_operator,
|
||||
DecisionBuilder* sub_decision_builder);
|
||||
LocalSearchOperator* const ls_operator,
|
||||
DecisionBuilder* const sub_decision_builder);
|
||||
LocalSearchPhaseParameters* MakeLocalSearchPhaseParameters(
|
||||
LocalSearchOperator* ls_operator,
|
||||
DecisionBuilder* sub_decision_builder,
|
||||
LocalSearchOperator* const ls_operator,
|
||||
DecisionBuilder* const sub_decision_builder,
|
||||
SearchLimit* const limit);
|
||||
LocalSearchPhaseParameters* MakeLocalSearchPhaseParameters(
|
||||
LocalSearchOperator* ls_operator,
|
||||
DecisionBuilder* sub_decision_builder,
|
||||
LocalSearchOperator* const ls_operator,
|
||||
DecisionBuilder* const sub_decision_builder,
|
||||
SearchLimit* const limit,
|
||||
const vector<LocalSearchFilter*>& filters);
|
||||
|
||||
@@ -2488,7 +2488,7 @@ class IntVarElement : public AssignmentElement {
|
||||
max_ = var_->Max();
|
||||
}
|
||||
void Restore() { var_->SetRange(min_, max_); }
|
||||
|
||||
|
||||
|
||||
int64 Min() const { return min_; }
|
||||
void SetMin(int64 m) { min_ = m; }
|
||||
@@ -2527,7 +2527,7 @@ class IntervalVarElement : public AssignmentElement {
|
||||
IntervalVar* Var() const { return var_; }
|
||||
void Store();
|
||||
void Restore();
|
||||
|
||||
|
||||
|
||||
int64 StartMin() const { return start_min_; }
|
||||
int64 StartMax() const { return start_max_; }
|
||||
@@ -2730,7 +2730,7 @@ class Assignment : public PropagationBaseObject {
|
||||
void Store();
|
||||
void Restore();
|
||||
|
||||
|
||||
|
||||
|
||||
void AddObjective(IntVar* const v);
|
||||
IntVar* Objective() const;
|
||||
|
||||
219
python/steel_lns.py
Normal file
219
python/steel_lns.py
Normal file
@@ -0,0 +1,219 @@
|
||||
# Copyright 2010 Pierre Schaus pschaus@gmail.com, lperron@google.com
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the 'License');
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an 'AS IS' BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from constraint_solver import pywrapcp
|
||||
from google.apputils import app
|
||||
import gflags
|
||||
import random
|
||||
|
||||
FLAGS = gflags.FLAGS
|
||||
|
||||
gflags.DEFINE_string('data',
|
||||
'python/data/steel_mill/steel_mill_slab.txt',
|
||||
'path to data file')
|
||||
gflags.DEFINE_integer('lns_fragment_size', 5, 'size of the random lns fragment')
|
||||
gflags.DEFINE_integer('lns_random_seed', 0, 'seed for the lns random generator')
|
||||
|
||||
|
||||
# ---------- helper for binpacking posting ----------
|
||||
|
||||
|
||||
def BinPacking(solver, binvars, weights, loadvars):
|
||||
'''post the load constraint on bins.
|
||||
|
||||
constraints forall j: loadvars[j] == sum_i (binvars[i] == j) * weights[i])
|
||||
'''
|
||||
pack = solver.Pack(binvars, len(binvars))
|
||||
pack.AddWeightedSumEqualVarDimension(weights, loadvars);
|
||||
solver.Add(pack)
|
||||
solver.Add(solver.SumEquality(loadvars, sum(weights)))
|
||||
|
||||
# ---------- data reading ----------
|
||||
|
||||
def ReadData(filename):
|
||||
'''Read data from <filename>.'''
|
||||
f = open(filename)
|
||||
capacity = [int(nb) for nb in f.readline().split()]
|
||||
capacity.pop(0)
|
||||
capacity = [0] + capacity
|
||||
max_capacity = max(capacity)
|
||||
nb_colors = int(f.readline())
|
||||
nb_slabs = int(f.readline())
|
||||
wc = [[int(j) for j in f.readline().split()] for i in range(nb_slabs)]
|
||||
weights = [x[0] for x in wc]
|
||||
colors = [x[1] for x in wc]
|
||||
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)]
|
||||
print 'Solving steel mill with', nb_slabs, 'slabs'
|
||||
return (nb_slabs, capacity, max_capacity, weights, colors, loss, color_orders)
|
||||
|
||||
# ---------- dedicated search for this problem ----------
|
||||
|
||||
|
||||
class SteelDecisionBuilder(pywrapcp.PyDecisionBuilder):
|
||||
'''Dedicated Decision Builder for steel mill slab.
|
||||
|
||||
Search for the steel mill slab problem with Dynamic Symmetry
|
||||
Breaking during search is an adaptation (for binary tree) from the
|
||||
paper of Pascal Van Hentenryck and Laurent Michel CPAIOR-2008.
|
||||
|
||||
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, loss_array, loads):
|
||||
self.__x = x
|
||||
self.__nb_slabs = nb_slabs
|
||||
self.__weights = weights
|
||||
self.__loss_array = loss_array
|
||||
self.__loads = loads
|
||||
self.__max_capacity = len(loss_array)-1
|
||||
|
||||
|
||||
def Next(self, solver):
|
||||
var,weight = self.NextVar()
|
||||
if var:
|
||||
v = self.MaxBound()
|
||||
if v + 1 == var.Min():
|
||||
# Symmetry breaking. If you need to assign to a new bin,
|
||||
# select the first one.
|
||||
solver.Add(var == v + 1)
|
||||
return self.Next(solver)
|
||||
else:
|
||||
# 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.__loss_array[loads[i] + weight], i)
|
||||
for i in range(var.Min(), var.Max() + 1)
|
||||
if var.Contains(i) and \
|
||||
loads[i] + weight <= self.__max_capacity)
|
||||
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()
|
||||
for o in range(self.__nb_slabs)
|
||||
if self.__x[o].Bound()])
|
||||
|
||||
def NextVar(self):
|
||||
''' mindom size heuristic with tie break on the weights of orders '''
|
||||
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][2], -res[0][1]) #returns the order var and its weight
|
||||
else:
|
||||
return (None, None)
|
||||
|
||||
def DebugString(self):
|
||||
return 'SteelMillDecisionBuilder(' + str(self.__x) + ')'
|
||||
|
||||
# ----------- LNS Operator ----------
|
||||
|
||||
class SteelLns(object):
|
||||
"""Random LNS for Steel."""
|
||||
|
||||
def __init__(self, rand):
|
||||
self.__random = rand
|
||||
|
||||
def NextFragment(self, fragment, values):
|
||||
counter = 0
|
||||
while counter < FLAGS.lns_fragment_size:
|
||||
index = self.__random.randint(0, values.Size() - 1)
|
||||
fragment.append(index)
|
||||
counter += 1
|
||||
return True
|
||||
|
||||
# ----------- Main Function -----------
|
||||
|
||||
|
||||
def main(unused_argv):
|
||||
# ----- solver and variable declaration -----
|
||||
(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 - 1, 'load_vars' + str(i))
|
||||
for i in range(nb_slabs)]
|
||||
|
||||
# ----- post of the constraints -----
|
||||
|
||||
# Bin Packing.
|
||||
BinPacking(solver, x, weights, load_vars)
|
||||
# At most two colors per slab.
|
||||
for s in range(nb_slabs):
|
||||
solver.Add(solver.SumLessOrEqual(
|
||||
[solver.Max([solver.IsEqualCstVar(x[c], s) for c in o])
|
||||
for o in color_orders], 2))
|
||||
|
||||
# ----- Objective -----
|
||||
|
||||
objective_var = \
|
||||
solver.Sum([load_vars[s].IndexOf(loss) for s in range(nb_slabs)]).Var()
|
||||
objective = solver.Minimize(objective_var, 1)
|
||||
|
||||
# ----- start the search and optimization -----
|
||||
|
||||
assign_db = SteelDecisionBuilder(x, nb_slabs, weights, loss, load_vars)
|
||||
first_solution = solver.Assignment()
|
||||
first_solution.Add(x)
|
||||
first_solution.AddObjective(objective_var)
|
||||
store_db = solver.StoreAssignment(first_solution)
|
||||
first_solution_db = solver.Compose([assign_db, store_db])
|
||||
print 'searching for initial solution,',
|
||||
solver.Solve(first_solution_db)
|
||||
print 'initial cost =', first_solution.ObjectiveValue()
|
||||
|
||||
inner_db = solver.Phase(x,
|
||||
solver.CHOOSE_RANDOM,
|
||||
solver.ASSIGN_MIN_VALUE)
|
||||
rand = random.Random()
|
||||
rand.seed(FLAGS.lns_random_seed)
|
||||
local_search_operator = solver.LNSOperator(x, SteelLns(rand))
|
||||
local_search_parameters = solver.LocalSearchPhaseParameters(
|
||||
local_search_operator, inner_db)
|
||||
local_search_db = solver.LocalSearchPhase(first_solution,
|
||||
local_search_parameters)
|
||||
|
||||
print 'using LNS to improve the initial solution'
|
||||
|
||||
search_log = solver.SearchLog(100000, objective_var)
|
||||
solver.Solve(local_search_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))
|
||||
# solver.EndSearch()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
app.run()
|
||||
Reference in New Issue
Block a user