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:
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user