diff --git a/examples/cpp/jobshop.cc b/examples/cpp/jobshop.cc index b995221939..15e3cc20f3 100644 --- a/examples/cpp/jobshop.cc +++ b/examples/cpp/jobshop.cc @@ -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 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. diff --git a/examples/cpp/jobshop_earlytardy.cc b/examples/cpp/jobshop_earlytardy.cc index e72438e90e..201643edd7 100644 --- a/examples/cpp/jobshop_earlytardy.cc +++ b/examples/cpp/jobshop_earlytardy.cc @@ -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 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. diff --git a/examples/cpp/jobshop_ls.cc b/examples/cpp/jobshop_ls.cc index 5c09d1c235..598e22438d 100644 --- a/examples/cpp/jobshop_ls.cc +++ b/examples/cpp/jobshop_ls.cc @@ -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 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. diff --git a/examples/csharp/organize_day_intervals.cs b/examples/csharp/organize_day_intervals.cs index 86423895c4..01018680ea 100644 --- a/examples/csharp/organize_day_intervals.cs +++ b/examples/csharp/organize_day_intervals.cs @@ -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); diff --git a/examples/python/jobshop_ft06.py b/examples/python/jobshop_ft06.py index 39bce768ec..405d15ebc4 100644 --- a/examples/python/jobshop_ft06.py +++ b/examples/python/jobshop_ft06.py @@ -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() diff --git a/examples/python/simple_meeting.py b/examples/python/simple_meeting.py index 4ca746a6c4..92e9d011e6 100644 --- a/examples/python/simple_meeting.py +++ b/examples/python/simple_meeting.py @@ -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. diff --git a/makefiles/Makefile.python.mk b/makefiles/Makefile.python.mk index 3c541ceeab..a8152289ad 100644 --- a/makefiles/Makefile.python.mk +++ b/makefiles/Makefile.python.mk @@ -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 diff --git a/src/com/google/ortools/constraintsolver/IntervalVarArrayHelper.cs b/src/com/google/ortools/constraintsolver/IntervalVarArrayHelper.cs index 4d56b1963b..cb9239dde8 100644 --- a/src/com/google/ortools/constraintsolver/IntervalVarArrayHelper.cs +++ b/src/com/google/ortools/constraintsolver/IntervalVarArrayHelper.cs @@ -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, diff --git a/src/constraint_solver/constraint_solver.h b/src/constraint_solver/constraint_solver.h index 20c8b18610..64441d26f6 100644 --- a/src/constraint_solver/constraint_solver.h +++ b/src/constraint_solver/constraint_solver.h @@ -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& intervals); - - // The sequence variable is used to rank disjoint intervals. - // It will post a SequenceConstraint upon creation. - SequenceVar* MakeSequenceVar(const std::vector& intervals, - const string& name); + DisjunctiveConstraint* MakeDisjunctiveConstraint( + const std::vector& 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 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 diff --git a/src/constraint_solver/constraint_solver.swig b/src/constraint_solver/constraint_solver.swig index c21fb86da7..3a1b05348f 100644 --- a/src/constraint_solver/constraint_solver.swig +++ b/src/constraint_solver/constraint_solver.swig @@ -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; diff --git a/src/constraint_solver/io.cc b/src/constraint_solver/io.cc index 0e25d63204..354f69114c 100644 --- a/src/constraint_solver/io.cc +++ b/src/constraint_solver/io.cc @@ -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 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 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); diff --git a/src/constraint_solver/resource.cc b/src/constraint_solver/resource.cc index 06552b3f14..6798550a3b 100644 --- a/src/constraint_solver/resource.cc +++ b/src/constraint_solver/resource.cc @@ -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 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& intervals) { +DisjunctiveConstraint* Solver::MakeDisjunctiveConstraint( + const std::vector& intervals, + const string& name) { // Finds all intervals that may be performed std::vector 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* const rank_first, } } -// ----------------- Factory methods ------------------------------- +// ----- Public class ----- -SequenceVar* Solver::MakeSequenceVar(const std::vector& 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(&sequence_var_)); + sequence_var_ = solver()->RevAlloc(new SequenceVar(solver(), + intervals_.get(), + size_, + name())); + } + return sequence_var_; +} + +// ----------------- Factory methods ------------------------------- + Constraint* Solver::MakeCumulative(const std::vector& intervals, const std::vector& demands, int64 capacity,