non working version of steel_lns

This commit is contained in:
lperron@google.com
2010-10-14 13:47:55 +00:00
parent 9204d59384
commit 3956a70eb3
2 changed files with 231 additions and 12 deletions

View File

@@ -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
View 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()