create visible DisjunctiveConstraint class, add name to factory builder, move sequence var builder from solver to disjunctive constraint, port examples

This commit is contained in:
lperron@google.com
2012-07-18 19:54:04 +00:00
parent 152b3d0b6c
commit a819336e55
12 changed files with 133 additions and 103 deletions

View File

@@ -106,20 +106,16 @@ void Jobshop(const JobShopData& data) {
}
}
// Adds disjunctive constraints on unary resources.
for (int machine_id = 0; machine_id < machine_count; ++machine_id) {
solver.AddConstraint(
solver.MakeDisjunctiveConstraint(machines_to_tasks[machine_id]));
}
// Creates sequences variables on machines. A sequence variable is a
// dedicated variable whose job is to sequence interval variables.
// Adds disjunctive constraints on unary resources, and creates
// sequence variables. A sequence variable is a dedicated variable
// whose job is to sequence interval variables.
std::vector<SequenceVar*> all_sequences;
for (int machine_id = 0; machine_id < machine_count; ++machine_id) {
const string name = StringPrintf("Machine_%d", machine_id);
SequenceVar* const sequence =
solver.MakeSequenceVar(machines_to_tasks[machine_id], name);
all_sequences.push_back(sequence);
DisjunctiveConstraint* const ct =
solver.MakeDisjunctiveConstraint(machines_to_tasks[machine_id], name);
solver.AddConstraint(ct);
all_sequences.push_back(ct->MakeSequenceVar());
}
// Creates array of end_times of jobs.

View File

@@ -14,7 +14,7 @@
// This model implements a simple jobshop problem with
// earliness-tardiness costs.
//
// A earliness-tardinessjobshop is a standard scheduling problem where
// A earliness-tardiness jobshop is a standard scheduling problem where
// you must schedule a set of jobs on a set of machines. Each job is
// a sequence of tasks (a task can only start when the preceding task
// finished), each of which occupies a single specific machine during
@@ -278,20 +278,16 @@ void EtJobShop(const EtJobShopData& data) {
penalties.push_back(penalty);
}
// Adds disjunctive constraints on unary resources.
for (int machine_id = 0; machine_id < machine_count; ++machine_id) {
solver.AddConstraint(
solver.MakeDisjunctiveConstraint(machines_to_tasks[machine_id]));
}
// Creates sequences variables on machines. A sequence variable is a
// dedicated variable whose job is to sequence interval variables.
// Adds disjunctive constraints on unary resources, and creates
// sequence variables. A sequence variable is a dedicated variable
// whose job is to sequence interval variables.
std::vector<SequenceVar*> all_sequences;
for (int machine_id = 0; machine_id < machine_count; ++machine_id) {
const string name = StringPrintf("Machine_%d", machine_id);
SequenceVar* const sequence =
solver.MakeSequenceVar(machines_to_tasks[machine_id], name);
all_sequences.push_back(sequence);
DisjunctiveConstraint* const ct =
solver.MakeDisjunctiveConstraint(machines_to_tasks[machine_id], name);
solver.AddConstraint(ct);
all_sequences.push_back(ct->MakeSequenceVar());
}
// Objective: minimize the weighted penalties.

View File

@@ -118,20 +118,16 @@ void JobshopLs(const JobShopData& data) {
}
}
// Adds disjunctive constraints on unary resources.
for (int machine_id = 0; machine_id < machine_count; ++machine_id) {
solver.AddConstraint(
solver.MakeDisjunctiveConstraint(machines_to_tasks[machine_id]));
}
// Creates sequences variables on machines. A sequence variable is a
// dedicated variable whose job is to sequence interval variables.
// Adds disjunctive constraints on unary resources, and creates
// sequence variables. A sequence variable is a dedicated variable
// whose job is to sequence interval variables.
std::vector<SequenceVar*> all_sequences;
for (int machine_id = 0; machine_id < machine_count; ++machine_id) {
const string name = StringPrintf("Machine_%d", machine_id);
SequenceVar* const sequence =
solver.MakeSequenceVar(machines_to_tasks[machine_id], name);
all_sequences.push_back(sequence);
DisjunctiveConstraint* const ct =
solver.MakeDisjunctiveConstraint(machines_to_tasks[machine_id], name);
solver.AddConstraint(ct);
all_sequences.push_back(ct->MakeSequenceVar());
}
// Creates array of end_times of jobs.

View File

@@ -82,7 +82,8 @@ public class OrganizeDay
//
// Constraints
//
solver.Add(intervals.Disjunctive());
DisjunctiveConstraint disjunctive = intervals.Disjunctive("Sequence");
solver.Add(disjunctive);
// specific constraints
for(int t = 0; t < before_tasks.GetLength(0); t++) {
@@ -96,7 +97,7 @@ public class OrganizeDay
//
// Search
//
SequenceVar var = intervals.SequenceVar("Sequence");
SequenceVar var = disjunctive.SequenceVar();
SequenceVar[] seq_array = new SequenceVar[] { var };
DecisionBuilder db = solver.MakePhase(seq_array, Solver.SEQUENCE_DEFAULT);

View File

@@ -76,9 +76,9 @@ def main(unused_argv):
for k in all_machines:
if machines[j][k] == i:
machines_jobs.append(all_tasks[(j, k)])
all_sequences[i] = solver.SequenceVar(machines_jobs, 'machine %i' % i)
solver.Add(solver.DisjunctiveConstraint(machines_jobs))
disj = solver.DisjunctiveConstraint(machines_jobs, 'machine %i' % i)
all_sequences[i] = disj.SequenceVar()
solver.Add(disj)
# Makespan objective.
obj_var = solver.Max([all_tasks[(i, machines_count - 1)].EndExpr()

View File

@@ -117,9 +117,9 @@ def main(unused_argv):
calendar = [people_meeting_copies[p], lunch]
calendar.extend([t['meeting']
for t in existing_meetings if t['person'] == p])
all_people_calendars[p] = solver.SequenceVar(calendar,
'people %d calendar' % p)
solver.Add(solver.DisjunctiveConstraint(calendar))
disj = solver.DisjunctiveConstraint(calendar, 'people %d calendar' % p)
all_people_calendars[p] = disj.SequenceVar()
solver.Add(disj)
all_people_presence[p] = solver.BoolVar('presence of people %d' % p)
people_count = solver.IntVar(0, attendees, 'people count')
@@ -130,9 +130,9 @@ def main(unused_argv):
calendar = [room_meeting_copies[r]]
calendar.extend([t['reservation']
for t in room_reservations if t['room'] == r])
all_rooms_calendars[r] = solver.SequenceVar(calendar,
'room %d calendar' % r)
solver.Add(solver.DisjunctiveConstraint(calendar))
disj = solver.DisjunctiveConstraint(calendar, 'room %d calendar' % r)
all_rooms_calendars[r] = disj.SequenceVar()
solver.Add(disj)
all_rooms_presence[r] = solver.BoolVar('presence of room %d' %r)
# Objective: maximum number of people.

View File

@@ -108,13 +108,13 @@ endif
# Run a single example
rpy: $(LIB_DIR)/_pywraplp.$(SHAREDLIBEXT) $(LIB_DIR)/_pywrapcp.$(SHAREDLIBEXT) $(LIB_DIR)/_pywrapgraph.$(SHAREDLIBEXT) $(LIB_DIR)/_pywrapknapsack_solver.$(SHAREDLIBEXT) $(LIB_DIR)/_pywraprouting.$(SHAREDLIBEXT) $(SRC_DIR)/python/$(EX).py
rpy: $(LIB_DIR)/_pywraplp.$(SHAREDLIBEXT) $(LIB_DIR)/_pywrapcp.$(SHAREDLIBEXT) $(LIB_DIR)/_pywrapgraph.$(SHAREDLIBEXT) $(LIB_DIR)/_pywrapknapsack_solver.$(SHAREDLIBEXT) $(LIB_DIR)/_pywraprouting.$(SHAREDLIBEXT) $(EX_DIR)/python/$(EX).py
ifeq ($(SYSTEM),win)
@echo Running python$S$(EX).py
@set PYTHONPATH=$(OR_ROOT_FULL)\\src && $(WINDOWS_PYTHON_PATH)$Spython $(SRC_DIR)/python$S$(EX).py
@set PYTHONPATH=$(OR_ROOT_FULL)\\src && $(WINDOWS_PYTHON_PATH)$Spython $(EX_DIR)/python$S$(EX).py
else
@echo Running python$S$(EX).py
@PYTHONPATH=$(OR_ROOT_FULL)/src python$(PYTHONVERSION) $(SRC_DIR)/python$S$(EX).py
@PYTHONPATH=$(OR_ROOT_FULL)/src python$(PYTHONVERSION) $(EX_DIR)/python$S$(EX).py
endif

View File

@@ -27,15 +27,11 @@ namespace Google.OrTools.ConstraintSolver
return vars[0].solver();
}
public static Constraint Disjunctive(this IntervalVar[] vars)
public static DisjunctiveConstraint Disjunctive(this IntervalVar[] vars,
String name)
{
Solver solver = GetSolver(vars);
return solver.MakeDisjunctiveConstraint(vars);
}
public static SequenceVar SequenceVar(this IntervalVar[] vars, String name)
{
Solver solver = GetSolver(vars);
return solver.MakeSequenceVar(vars, name);
return solver.MakeDisjunctiveConstraint(vars, name);
}
public static Constraint Cumulative(this IntervalVar[] vars,
long[] demands,

View File

@@ -125,6 +125,7 @@ class DemonProfiler;
class DemonProfiler;
class DependencyGraph;
class Dimension;
class DisjunctiveConstraint;
class ExpressionCache;
class IntExpr;
class IntTupleSet;
@@ -1813,12 +1814,9 @@ class Solver {
// This constraint forces all interval vars into an non overlapping
// sequence.
Constraint* MakeDisjunctiveConstraint(const std::vector<IntervalVar*>& intervals);
// The sequence variable is used to rank disjoint intervals.
// It will post a SequenceConstraint upon creation.
SequenceVar* MakeSequenceVar(const std::vector<IntervalVar*>& intervals,
const string& name);
DisjunctiveConstraint* MakeDisjunctiveConstraint(
const std::vector<IntervalVar*>& intervals,
const string& name);
// This constraint forces that, for any integer t, the sum of the demands
// corresponding to an interval containing t does not exceed the given
@@ -4919,6 +4917,25 @@ class Pack : public Constraint {
bool in_process_;
};
// ----- Disjunctive Constraint -----
class DisjunctiveConstraint : public Constraint {
public:
DisjunctiveConstraint(Solver* const s,
IntervalVar* const * intervals,
int size,
const string& name);
virtual ~DisjunctiveConstraint();
SequenceVar* MakeSequenceVar();
protected:
scoped_array<IntervalVar*> intervals_;
const int size_;
SequenceVar* sequence_var_;
DISALLOW_COPY_AND_ASSIGN(DisjunctiveConstraint);
};
// ----- SolutionPool -----
// This class is used to manage a pool of solutions. It can transform

View File

@@ -1476,6 +1476,9 @@ struct FailureProtect {
// Rename rules on Solver.
%rename (Add) operations_research::Solver::AddConstraint;
// Rename rule on DisjunctiveConstraint.
%rename (SequenceVar) operations_research::DisjunctiveConstraint::MakeSequenceVar;
// Generic rename rules.
%rename (ToString) *::DebugString;

View File

@@ -591,6 +591,9 @@ class SecondPassVisitor : public ModelVisitor {
const int index = model_proto_->constraints_size();
CPConstraintProto* const constraint_proto = model_proto_->add_constraints();
ExportToProto(constraint, constraint_proto, type_name, index);
if (constraint->HasName()) {
constraint_proto->set_name(constraint->name());
}
PopArgumentHolder();
}
@@ -1189,7 +1192,7 @@ Constraint* BuildDisjunctive(CPModelLoader* const builder,
VERIFY(builder->ScanArguments(ModelVisitor::kIntervalsArgument,
proto,
&vars));
return builder->solver()->MakeDisjunctiveConstraint(vars);
return builder->solver()->MakeDisjunctiveConstraint(vars, proto.name());
}
// ----- kDistribute -----
@@ -2061,14 +2064,14 @@ IntExpr* BuildSemiContinuous(CPModelLoader* const builder,
// ----- kSequenceVariable -----
SequenceVar* BuildSequenceVariable(CPModelLoader* const builder,
const CPSequenceVariableProto& proto) {
std::vector<IntervalVar*> vars;
VERIFY(builder->ScanArguments(ModelVisitor::kIntervalsArgument,
proto,
&vars));
return builder->solver()->MakeSequenceVar(vars, proto.name());
}
// SequenceVar* BuildSequenceVariable(CPModelLoader* const builder,
// const CPSequenceVariableProto& proto) {
// std::vector<IntervalVar*> vars;
// VERIFY(builder->ScanArguments(ModelVisitor::kIntervalsArgument,
// proto,
// &vars));
// return builder->solver()->MakeSequenceVar(vars, proto.name());
// }
// ----- kSortingConstraint -----
@@ -2606,7 +2609,7 @@ void Solver::InitBuilders() {
REGISTER(kScalProdGreaterOrEqual, BuildScalProdGreaterOrEqual);
REGISTER(kScalProdLessOrEqual, BuildScalProdLessOrEqual);
REGISTER(kSemiContinuous, BuildSemiContinuous);
REGISTER(kSequenceVariable, BuildSequenceVariable);
// REGISTER(kSequenceVariable, BuildSequenceVariable);
REGISTER(kSortingConstraint, BuildSortingConstraint);
REGISTER(kSquare, BuildSquare);
REGISTER(kStartExpr, BuildStartExpr);

View File

@@ -748,18 +748,20 @@ bool EdgeFinderAndDetectablePrecedences::EdgeFinder() {
// A class that stores several propagators for the sequence constraint, and
// calls them until a fixpoint is reached.
class DisjunctiveConstraint : public Constraint {
class FullDisjunctiveConstraint : public DisjunctiveConstraint {
public:
DisjunctiveConstraint(Solver* const s,
IntervalVar* const * intervals,
int size);
virtual ~DisjunctiveConstraint() { }
FullDisjunctiveConstraint(Solver* const s,
IntervalVar* const * intervals,
int size,
const string& name);
virtual ~FullDisjunctiveConstraint() { }
virtual void Post() {
Demon* d = MakeDelayedConstraintDemon0(
solver(),
this,
&DisjunctiveConstraint::InitialPropagate,
&FullDisjunctiveConstraint::InitialPropagate,
"InitialPropagate");
for (int32 i = 0; i < straight_.size(); ++i) {
straight_.mutable_interval(i)->WhenAnything(d);
@@ -788,27 +790,23 @@ class DisjunctiveConstraint : public Constraint {
}
private:
scoped_array<IntervalVar*> intervals_;
const int size_;
EdgeFinderAndDetectablePrecedences straight_;
EdgeFinderAndDetectablePrecedences mirror_;
NotLast straight_not_last_;
NotLast mirror_not_last_;
DISALLOW_COPY_AND_ASSIGN(DisjunctiveConstraint);
DISALLOW_COPY_AND_ASSIGN(FullDisjunctiveConstraint);
};
DisjunctiveConstraint::DisjunctiveConstraint(Solver* const s,
IntervalVar* const * intervals,
int size)
: Constraint(s),
intervals_(new IntervalVar*[size]),
size_(size),
FullDisjunctiveConstraint::FullDisjunctiveConstraint(
Solver* const s,
IntervalVar* const * intervals,
int size,
const string& name)
: DisjunctiveConstraint(s, intervals, size, name),
straight_(s, intervals, size, false),
mirror_(s, intervals, size, true),
straight_not_last_(s, intervals, size, false),
mirror_not_last_(s, intervals, size, true) {
memcpy(intervals_.get(), intervals, size_ * sizeof(*intervals));
}
mirror_not_last_(s, intervals, size, true) {}
// =====================================================================
// Cumulative
@@ -1638,8 +1636,9 @@ class CumulativeConstraint : public Constraint {
if (high_demand_intervals.size() >= 2) {
// If there are less than 2 such intervals, the constraint would do
// nothing
// string seq_name = StrCat(name(), "-HighDemandSequence");
constraint = solver()->MakeDisjunctiveConstraint(high_demand_intervals);
string seq_name = StrCat(name(), "-HighDemandSequence");
constraint = solver()->MakeDisjunctiveConstraint(high_demand_intervals,
seq_name);
}
}
if (constraint != NULL) {
@@ -1724,8 +1723,9 @@ class CumulativeConstraint : public Constraint {
// Sequence Constraint
Constraint* Solver::MakeDisjunctiveConstraint(
const std::vector<IntervalVar*>& intervals) {
DisjunctiveConstraint* Solver::MakeDisjunctiveConstraint(
const std::vector<IntervalVar*>& intervals,
const string& name) {
// Finds all intervals that may be performed
std::vector<IntervalVar*> may_be_performed;
for (int i = 0; i < intervals.size(); ++i) {
@@ -1733,9 +1733,10 @@ Constraint* Solver::MakeDisjunctiveConstraint(
may_be_performed.push_back(intervals[i]);
}
}
return RevAlloc(new DisjunctiveConstraint(this,
may_be_performed.data(),
may_be_performed.size()));
return RevAlloc(new FullDisjunctiveConstraint(this,
may_be_performed.data(),
may_be_performed.size(),
name));
}
// ----- SequenceVar -----
@@ -2148,16 +2149,37 @@ void SequenceVar::FillSequence(std::vector<int>* const rank_first,
}
}
// ----------------- Factory methods -------------------------------
// ----- Public class -----
SequenceVar* Solver::MakeSequenceVar(const std::vector<IntervalVar*>& intervals,
const string& name) {
return RevAlloc(new SequenceVar(this,
intervals.data(),
intervals.size(),
name));
DisjunctiveConstraint::DisjunctiveConstraint(Solver* const s,
IntervalVar* const * intervals,
int size,
const string& name)
: Constraint(s),
intervals_(new IntervalVar*[size]),
size_(size),
sequence_var_(NULL) {
memcpy(intervals_.get(), intervals, size_ * sizeof(*intervals));
if (!name.empty()) {
set_name(name);
}
}
DisjunctiveConstraint::~DisjunctiveConstraint() {}
SequenceVar* DisjunctiveConstraint::MakeSequenceVar() {
if (sequence_var_ == NULL) {
solver()->SaveValue(reinterpret_cast<void**>(&sequence_var_));
sequence_var_ = solver()->RevAlloc(new SequenceVar(solver(),
intervals_.get(),
size_,
name()));
}
return sequence_var_;
}
// ----------------- Factory methods -------------------------------
Constraint* Solver::MakeCumulative(const std::vector<IntervalVar*>& intervals,
const std::vector<int64>& demands,
int64 capacity,