add no overlap sample

This commit is contained in:
Laurent Perron
2018-07-24 09:50:07 -07:00
parent 84400a72ed
commit 55b2ae6acf
4 changed files with 539 additions and 0 deletions

View File

@@ -253,6 +253,264 @@ public class CodeSamplesSat
## NoOverlap constraint
A no overlap constraint simply states that all intervals are disjoint.
It is build with a list of interval variables. Fixed intervals are useful to
exclude part of the timeline.
### Python code
```python
"""Code sample to demonstrates how to build a no overlap constraint."""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from ortools.sat.python import cp_model
def NoOverlapSample():
"""No overlap sample with fixed activities."""
model = cp_model.CpModel()
horizon = 21 # 3 weeks.
# Task 0, duration 2.
start_0 = model.NewIntVar(0, horizon, 'start_0')
duration_0 = 2 # Python cp/sat code accept integer variables or constants.
end_0 = model.NewIntVar(0, horizon, 'end_0')
task_0 = model.NewIntervalVar(start_0, duration_0, end_0, 'task_0')
# Task 1, duration 4.
start_1 = model.NewIntVar(0, horizon, 'start_1')
duration_1 = 4 # Python cp/sat code accept integer variables or constants.
end_1 = model.NewIntVar(0, horizon, 'end_1')
task_1 = model.NewIntervalVar(start_1, duration_1, end_1, 'task_1')
# Task 2, duration 3.
start_2 = model.NewIntVar(0, horizon, 'start_2')
duration_2 = 3 # Python cp/sat code accept integer variables or constants.
end_2 = model.NewIntVar(0, horizon, 'end_2')
task_2 = model.NewIntervalVar(start_2, duration_2, end_2, 'task_2')
# Week ends.
weekend_0 = model.NewIntervalVar(5, 2, 7, 'weekend_0')
weekend_1 = model.NewIntervalVar(12, 2, 14, 'weekend_1')
weekend_2 = model.NewIntervalVar(19, 2, 21, 'weekend_2')
# No Overlap constraint.
model.AddNoOverlap([task_0, task_1, task_2, weekend_0, weekend_1, weekend_2])
# Makespan objective.
obj = model.NewIntVar(0, horizon, 'makespan')
model.AddMaxEquality(obj, [end_0, end_1, end_2])
model.Minimize(obj)
# Solve model.
solver = cp_model.CpSolver()
status = solver.Solve(model)
if status == cp_model.OPTIMAL:
# Print out makespan and the starts of all tasks.
print('Optimal Schedule Length: %i' % solver.ObjectiveValue())
print('Task 0 starts at %i' % solver.Value(start_0))
print('Task 1 starts at %i' % solver.Value(start_1))
print('Task 2 starts at %i' % solver.Value(start_2))
NoOverlapSample()
```
### C++ code
```cpp
#include "ortools/sat/cp_model.pb.h"
#include "ortools/sat/cp_model_solver.h"
#include "ortools/sat/cp_model_utils.h"
#include "ortools/sat/model.h"
namespace operations_research {
namespace sat {
void NoOverlapSample() {
CpModelProto cp_model;
const int kHorizon = 21; // 3 weeks.
auto new_variable = [&cp_model](int64 lb, int64 ub) {
CHECK_LE(lb, ub);
const int index = cp_model.variables_size();
IntegerVariableProto* const var = cp_model.add_variables();
var->add_domain(lb);
var->add_domain(ub);
return index;
};
auto new_constant = [&new_variable](int64 v) { return new_variable(v, v); };
auto new_interval = [&cp_model](int start, int duration, int end) {
const int index = cp_model.constraints_size();
IntervalConstraintProto* const interval =
cp_model.add_constraints()->mutable_interval();
interval->set_start(start);
interval->set_size(duration);
interval->set_end(end);
return index;
};
auto new_fixed_interval = [&cp_model, &new_constant](int64 start,
int64 duration) {
const int index = cp_model.constraints_size();
IntervalConstraintProto* const interval =
cp_model.add_constraints()->mutable_interval();
interval->set_start(new_constant(start));
interval->set_size(new_constant(duration));
interval->set_end(new_constant(start + duration));
return index;
};
auto add_no_overlap = [&cp_model](const std::vector<int>& intervals) {
NoOverlapConstraintProto* const no_overlap =
cp_model.add_constraints()->mutable_no_overlap();
for (const int i : intervals) {
no_overlap->add_intervals(i);
}
};
auto add_precedence = [&cp_model](int before, int after) {
LinearConstraintProto* const lin =
cp_model.add_constraints()->mutable_linear();
lin->add_vars(after);
lin->add_coeffs(1L);
lin->add_vars(before);
lin->add_coeffs(-1L);
lin->add_domain(0);
lin->add_domain(kint64max);
};
// Task 0, duration 2.
const int start_0 = new_variable(0, kHorizon);
const int duration_0 = new_constant(2);
const int end_0 = new_variable(0, kHorizon);
const int task_0 = new_interval(start_0, duration_0, end_0);
// Task 1, duration 4.
const int start_1 = new_variable(0, kHorizon);
const int duration_1 = new_constant(4);
const int end_1 = new_variable(0, kHorizon);
const int task_1 = new_interval(start_1, duration_1, end_1);
// Task 2, duration 3.
const int start_2 = new_variable(0, kHorizon);
const int duration_2 = new_constant(3);
const int end_2 = new_variable(0, kHorizon);
const int task_2 = new_interval(start_2, duration_2, end_2);
// Week ends.
const int weekend_0 = new_fixed_interval(5, 2);
const int weekend_1 = new_fixed_interval(12, 2);
const int weekend_2 = new_fixed_interval(19, 2);
// No Overlap constraint.
add_no_overlap({task_0, task_1, task_2, weekend_0, weekend_1, weekend_2});
// Makespan.
const int makespan = new_variable(0, kHorizon);
add_precedence(end_0, makespan);
add_precedence(end_1, makespan);
add_precedence(end_2, makespan);
CpObjectiveProto* const obj = cp_model.mutable_objective();
obj->add_vars(makespan);
obj->add_coeffs(1); // Minimization.
// Solving part.
Model model;
LOG(INFO) << CpModelStats(cp_model);
const CpSolverResponse response = SolveCpModel(cp_model, &model);
LOG(INFO) << CpSolverResponseStats(response);
if (response.status() == CpSolverStatus::OPTIMAL) {
LOG(INFO) << "Optimal Schedule Length: " << response.objective_value();
LOG(INFO) << "Task 0 starts at " << response.solution(start_0);
LOG(INFO) << "Task 1 starts at " << response.solution(start_1);
LOG(INFO) << "Task 2 starts at " << response.solution(start_2);
}
}
} // namespace sat
} // namespace operations_research
int main() {
operations_research::sat::NoOverlapSample();
return EXIT_SUCCESS;
}
```
### C\# code
```cs
using System;
using Google.OrTools.Sat;
public class CodeSamplesSat
{
static void NoOverlapSample()
{
CpModel model = new CpModel();
int horizon = 21;
// Task 0, duration 2.
IntVar start_0 = model.NewIntVar(0, horizon, "start_0");
int duration_0 = 2;
IntVar end_0 = model.NewIntVar(0, horizon, "end_0");
IntervalVar task_0 =
model.NewIntervalVar(start_0, duration_0, end_0, "task_0");
// Task 1, duration 4.
IntVar start_1 = model.NewIntVar(0, horizon, "start_1");
int duration_1 = 4;
IntVar end_1 = model.NewIntVar(0, horizon, "end_1");
IntervalVar task_1 =
model.NewIntervalVar(start_1, duration_1, end_1, "task_1");
// Task 2, duration 3.
IntVar start_2 = model.NewIntVar(0, horizon, "start_2");
int duration_2 = 3;
IntVar end_2 = model.NewIntVar(0, horizon, "end_2");
IntervalVar task_2 =
model.NewIntervalVar(start_2, duration_2, end_2, "task_2");
// Week ends.
IntervalVar weekend_0 = model.NewIntervalVar(5, 2, 7, "weekend_0");
IntervalVar weekend_1 = model.NewIntervalVar(12, 2, 14, "weekend_1");
IntervalVar weekend_2 = model.NewIntervalVar(19, 2, 21, "weekend_2");
// No Overlap constraint.
model.AddNoOverlap(new IntervalVar[] {task_0, task_1, task_2, weekend_0,
weekend_1, weekend_2});
// Makespan objective.
IntVar obj = model.NewIntVar(0, horizon, "makespan");
model.AddMaxEquality(obj, new IntVar[] {end_0, end_1, end_2});
model.Minimize(obj);
// Creates a solver and solves the model.
CpSolver solver = new CpSolver();
CpSolverStatus status = solver.Solve(model);
if (status == CpSolverStatus.Optimal)
{
Console.WriteLine("Optimal Schedule Length: " + solver.ObjectiveValue);
Console.WriteLine("Task 0 starts at " + solver.Value(start_0));
Console.WriteLine("Task 1 starts at " + solver.Value(start_1));
Console.WriteLine("Task 2 starts at " + solver.Value(start_2));
}
}
static void Main()
{
NoOverlapSample();
}
}
```
## Cumulative constraint
@@ -262,6 +520,8 @@ at that time point is less than a given capacity.
## Alternative resources for one interval
## Ranking or tasks in a disjunctive resource
## Transitions in a disjunctive resource
## Precedences between intervals

View File

@@ -0,0 +1,134 @@
// Copyright 2010-2017 Google
// 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.
#include "ortools/sat/cp_model.pb.h"
#include "ortools/sat/cp_model_solver.h"
#include "ortools/sat/cp_model_utils.h"
#include "ortools/sat/model.h"
namespace operations_research {
namespace sat {
void NoOverlapSample() {
CpModelProto cp_model;
const int kHorizon = 21; // 3 weeks.
auto new_variable = [&cp_model](int64 lb, int64 ub) {
CHECK_LE(lb, ub);
const int index = cp_model.variables_size();
IntegerVariableProto* const var = cp_model.add_variables();
var->add_domain(lb);
var->add_domain(ub);
return index;
};
auto new_constant = [&new_variable](int64 v) { return new_variable(v, v); };
auto new_interval = [&cp_model](int start, int duration, int end) {
const int index = cp_model.constraints_size();
IntervalConstraintProto* const interval =
cp_model.add_constraints()->mutable_interval();
interval->set_start(start);
interval->set_size(duration);
interval->set_end(end);
return index;
};
auto new_fixed_interval = [&cp_model, &new_constant](int64 start,
int64 duration) {
const int index = cp_model.constraints_size();
IntervalConstraintProto* const interval =
cp_model.add_constraints()->mutable_interval();
interval->set_start(new_constant(start));
interval->set_size(new_constant(duration));
interval->set_end(new_constant(start + duration));
return index;
};
auto add_no_overlap = [&cp_model](const std::vector<int>& intervals) {
NoOverlapConstraintProto* const no_overlap =
cp_model.add_constraints()->mutable_no_overlap();
for (const int i : intervals) {
no_overlap->add_intervals(i);
}
};
auto add_precedence = [&cp_model](int before, int after) {
LinearConstraintProto* const lin =
cp_model.add_constraints()->mutable_linear();
lin->add_vars(after);
lin->add_coeffs(1L);
lin->add_vars(before);
lin->add_coeffs(-1L);
lin->add_domain(0);
lin->add_domain(kint64max);
};
// Task 0, duration 2.
const int start_0 = new_variable(0, kHorizon);
const int duration_0 = new_constant(2);
const int end_0 = new_variable(0, kHorizon);
const int task_0 = new_interval(start_0, duration_0, end_0);
// Task 1, duration 4.
const int start_1 = new_variable(0, kHorizon);
const int duration_1 = new_constant(4);
const int end_1 = new_variable(0, kHorizon);
const int task_1 = new_interval(start_1, duration_1, end_1);
// Task 2, duration 3.
const int start_2 = new_variable(0, kHorizon);
const int duration_2 = new_constant(3);
const int end_2 = new_variable(0, kHorizon);
const int task_2 = new_interval(start_2, duration_2, end_2);
// Week ends.
const int weekend_0 = new_fixed_interval(5, 2);
const int weekend_1 = new_fixed_interval(12, 2);
const int weekend_2 = new_fixed_interval(19, 2);
// No Overlap constraint.
add_no_overlap({task_0, task_1, task_2, weekend_0, weekend_1, weekend_2});
// Makespan.
const int makespan = new_variable(0, kHorizon);
add_precedence(end_0, makespan);
add_precedence(end_1, makespan);
add_precedence(end_2, makespan);
CpObjectiveProto* const obj = cp_model.mutable_objective();
obj->add_vars(makespan);
obj->add_coeffs(1); // Minimization.
// Solving part.
Model model;
LOG(INFO) << CpModelStats(cp_model);
const CpSolverResponse response = SolveCpModel(cp_model, &model);
LOG(INFO) << CpSolverResponseStats(response);
if (response.status() == CpSolverStatus::OPTIMAL) {
LOG(INFO) << "Optimal Schedule Length: " << response.objective_value();
LOG(INFO) << "Task 0 starts at " << response.solution(start_0);
LOG(INFO) << "Task 1 starts at " << response.solution(start_1);
LOG(INFO) << "Task 2 starts at " << response.solution(start_2);
}
}
} // namespace sat
} // namespace operations_research
int main() {
operations_research::sat::NoOverlapSample();
return EXIT_SUCCESS;
}

View File

@@ -0,0 +1,76 @@
// Copyright 2010-2017 Google
// 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.
using System;
using Google.OrTools.Sat;
public class CodeSamplesSat
{
static void NoOverlapSample()
{
CpModel model = new CpModel();
int horizon = 21;
// Task 0, duration 2.
IntVar start_0 = model.NewIntVar(0, horizon, "start_0");
int duration_0 = 2;
IntVar end_0 = model.NewIntVar(0, horizon, "end_0");
IntervalVar task_0 =
model.NewIntervalVar(start_0, duration_0, end_0, "task_0");
// Task 1, duration 4.
IntVar start_1 = model.NewIntVar(0, horizon, "start_1");
int duration_1 = 4;
IntVar end_1 = model.NewIntVar(0, horizon, "end_1");
IntervalVar task_1 =
model.NewIntervalVar(start_1, duration_1, end_1, "task_1");
// Task 2, duration 3.
IntVar start_2 = model.NewIntVar(0, horizon, "start_2");
int duration_2 = 3;
IntVar end_2 = model.NewIntVar(0, horizon, "end_2");
IntervalVar task_2 =
model.NewIntervalVar(start_2, duration_2, end_2, "task_2");
// Week ends.
IntervalVar weekend_0 = model.NewIntervalVar(5, 2, 7, "weekend_0");
IntervalVar weekend_1 = model.NewIntervalVar(12, 2, 14, "weekend_1");
IntervalVar weekend_2 = model.NewIntervalVar(19, 2, 21, "weekend_2");
// No Overlap constraint.
model.AddNoOverlap(new IntervalVar[] {task_0, task_1, task_2, weekend_0,
weekend_1, weekend_2});
// Makespan objective.
IntVar obj = model.NewIntVar(0, horizon, "makespan");
model.AddMaxEquality(obj, new IntVar[] {end_0, end_1, end_2});
model.Minimize(obj);
// Creates a solver and solves the model.
CpSolver solver = new CpSolver();
CpSolverStatus status = solver.Solve(model);
if (status == CpSolverStatus.Optimal)
{
Console.WriteLine("Optimal Schedule Length: " + solver.ObjectiveValue);
Console.WriteLine("Task 0 starts at " + solver.Value(start_0));
Console.WriteLine("Task 1 starts at " + solver.Value(start_1));
Console.WriteLine("Task 2 starts at " + solver.Value(start_2));
}
}
static void Main()
{
NoOverlapSample();
}
}

View File

@@ -0,0 +1,69 @@
# Copyright 2010-2017 Google
# 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.
"""Code sample to demonstrates how to build a no overlap constraint."""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from ortools.sat.python import cp_model
def NoOverlapSample():
"""No overlap sample with fixed activities."""
model = cp_model.CpModel()
horizon = 21 # 3 weeks.
# Task 0, duration 2.
start_0 = model.NewIntVar(0, horizon, 'start_0')
duration_0 = 2 # Python cp/sat code accept integer variables or constants.
end_0 = model.NewIntVar(0, horizon, 'end_0')
task_0 = model.NewIntervalVar(start_0, duration_0, end_0, 'task_0')
# Task 1, duration 4.
start_1 = model.NewIntVar(0, horizon, 'start_1')
duration_1 = 4 # Python cp/sat code accept integer variables or constants.
end_1 = model.NewIntVar(0, horizon, 'end_1')
task_1 = model.NewIntervalVar(start_1, duration_1, end_1, 'task_1')
# Task 2, duration 3.
start_2 = model.NewIntVar(0, horizon, 'start_2')
duration_2 = 3 # Python cp/sat code accept integer variables or constants.
end_2 = model.NewIntVar(0, horizon, 'end_2')
task_2 = model.NewIntervalVar(start_2, duration_2, end_2, 'task_2')
# Week ends.
weekend_0 = model.NewIntervalVar(5, 2, 7, 'weekend_0')
weekend_1 = model.NewIntervalVar(12, 2, 14, 'weekend_1')
weekend_2 = model.NewIntervalVar(19, 2, 21, 'weekend_2')
# No Overlap constraint.
model.AddNoOverlap([task_0, task_1, task_2, weekend_0, weekend_1, weekend_2])
# Makespan objective.
obj = model.NewIntVar(0, horizon, 'makespan')
model.AddMaxEquality(obj, [end_0, end_1, end_2])
model.Minimize(obj)
# Solve model.
solver = cp_model.CpSolver()
status = solver.Solve(model)
if status == cp_model.OPTIMAL:
# Print out makespan and the starts of all tasks.
print('Optimal Schedule Length: %i' % solver.ObjectiveValue())
print('Task 0 starts at %i' % solver.Value(start_0))
print('Task 1 starts at %i' % solver.Value(start_1))
print('Task 2 starts at %i' % solver.Value(start_2))
NoOverlapSample()