[CP-SAT] change constraints in CpModel C# API to allow incremental filling like in C++/Java
This commit is contained in:
@@ -89,7 +89,11 @@ public class GateSchedulingSat
|
||||
}
|
||||
|
||||
// Max Length constraint (modeled as a cumulative)
|
||||
model.AddCumulative(intervals, demands, max_length);
|
||||
CumulativeConstraint cumul = model.AddCumulative(max_length);
|
||||
foreach (var p in intervals.Zip(demands, (i, d) => new { Interval = i, Demand = d }))
|
||||
{
|
||||
cumul.AddDemand(p.Interval, p.Demand);
|
||||
}
|
||||
|
||||
// Choose which machine to perform the jobs on.
|
||||
model.AddNoOverlap(intervals0);
|
||||
|
||||
@@ -18,8 +18,8 @@ using Google.OrTools.Sat;
|
||||
|
||||
public class NurseSolutionObserver : CpSolverSolutionCallback
|
||||
{
|
||||
public NurseSolutionObserver(BoolVar[,,] shifts, int num_nurses, int num_days, int num_shifts, HashSet<int> to_print,
|
||||
int last_solution_explored)
|
||||
public NurseSolutionObserver(BoolVar[,,] shifts, int num_nurses, int num_days, int num_shifts,
|
||||
HashSet<int> to_print, int last_solution_explored)
|
||||
{
|
||||
shifts_ = shifts;
|
||||
num_nurses_ = num_nurses;
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Google.OrTools.Sat;
|
||||
|
||||
|
||||
@@ -72,8 +72,9 @@ class Tsp
|
||||
}
|
||||
|
||||
// Add dummy dimension to test API.
|
||||
routing.AddDimension(routing.RegisterUnaryTransitCallback((long index) => { return 1; }), size + 1, size + 1,
|
||||
true, "dummy");
|
||||
routing.AddDimension(routing.RegisterUnaryTransitCallback((long index) =>
|
||||
{ return 1; }),
|
||||
size + 1, size + 1, true, "dummy");
|
||||
|
||||
// Solve, returns a solution if any (owned by RoutingModel).
|
||||
RoutingSearchParameters search_parameters =
|
||||
|
||||
@@ -145,7 +145,7 @@ public class SatSolverTest
|
||||
CpSolverResponse response = solver.Response;
|
||||
Assert.Equal(30, response.ObjectiveValue);
|
||||
Assert.Equal(new long[] { 10, 10, 30 }, response.Solution);
|
||||
// Console.WriteLine("response = " + reponse.ToString());
|
||||
// Console.WriteLine("response = " + response.ToString());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -165,7 +165,7 @@ public class SatSolverTest
|
||||
CpSolverResponse response = solver.Response;
|
||||
Assert.Equal(30, response.ObjectiveValue);
|
||||
Assert.Equal(new long[] { 10, -10 }, response.Solution);
|
||||
// Console.WriteLine("response = " + reponse.ToString());
|
||||
// Console.WriteLine("response = " + response.ToString());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -188,7 +188,7 @@ public class SatSolverTest
|
||||
Assert.Equal(new long[] { -10, 10 }, response.Solution);
|
||||
Assert.Equal(-30, solver.Value(v1 - 2 * v2));
|
||||
Assert.Equal(-30, response.ObjectiveValue);
|
||||
// Console.WriteLine("response = " + reponse.ToString());
|
||||
// Console.WriteLine("response = " + response.ToString());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -233,7 +233,10 @@ public class SatSolverTest
|
||||
model.Add(delta == x - 5);
|
||||
long[,] tuples = { { -5, 25 }, { -4, 16 }, { -3, 9 }, { -2, 4 }, { -1, 1 }, { 0, 0 },
|
||||
{ 1, 1 }, { 2, 4 }, { 3, 9 }, { 4, 16 }, { 5, 25 } };
|
||||
model.AddAllowedAssignments(new IntVar[] { delta, squaredDelta }, tuples);
|
||||
TableConstraint ct = model.AddAllowedAssignments(new IntVar[] { delta, squaredDelta });
|
||||
for (int i = 0; i < tuples.GetLength(0); ++i) {
|
||||
ct.AddTuple(new long[] { tuples[i, 0], tuples[i, 1]});
|
||||
}
|
||||
model.Minimize(squaredDelta);
|
||||
|
||||
CpSolver solver = new CpSolver();
|
||||
@@ -266,7 +269,7 @@ public class SatSolverTest
|
||||
Assert.Equal(1, solver.Value(v2));
|
||||
Assert.Equal(new long[] { 3, 1 }, response.Solution);
|
||||
Assert.Equal(0, response.ObjectiveValue);
|
||||
// Console.WriteLine("response = " + reponse.ToString());
|
||||
// Console.WriteLine("response = " + response.ToString());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -287,7 +290,7 @@ public class SatSolverTest
|
||||
Assert.Equal(4, solver.Value(v2));
|
||||
Assert.Equal(new long[] { 3, 4 }, response.Solution);
|
||||
Assert.Equal(0, response.ObjectiveValue);
|
||||
// Console.WriteLine("response = " + reponse.ToString());
|
||||
// Console.WriteLine("response = " + response.ToString());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -376,6 +379,7 @@ public class SatSolverTest
|
||||
[Fact]
|
||||
public void LinearExprStaticCompileTest()
|
||||
{
|
||||
Console.WriteLine("LinearExprStaticCompileTest");
|
||||
CpModel model = new CpModel();
|
||||
IntVar v1 = model.NewIntVar(-10, 10, "v1");
|
||||
IntVar v2 = model.NewIntVar(-10, 10, "v2");
|
||||
@@ -406,6 +410,7 @@ public class SatSolverTest
|
||||
[Fact]
|
||||
public void LinearExprBuilderCompileTest()
|
||||
{
|
||||
Console.WriteLine("LinearExprBuilderCompileTest");
|
||||
CpModel model = new CpModel();
|
||||
IntVar v1 = model.NewIntVar(-10, 10, "v1");
|
||||
IntVar v2 = model.NewIntVar(-10, 10, "v2");
|
||||
@@ -443,8 +448,79 @@ public class SatSolverTest
|
||||
Console.WriteLine(e14.ToString());
|
||||
LinearExpr e15 = LinearExpr.NewBuilder().AddTerm(b1.Not(), -2);
|
||||
Console.WriteLine(e15.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void LinearExprIntVarOperatorTest()
|
||||
{
|
||||
Console.WriteLine("LinearExprIntVarOperatorTest");
|
||||
CpModel model = new CpModel();
|
||||
IntVar v = model.NewIntVar(-10, 10, "v");
|
||||
LinearExpr e = v * 2;
|
||||
Console.WriteLine(e);
|
||||
e = 2 * v;
|
||||
Console.WriteLine(e);
|
||||
e = v + 2;
|
||||
Console.WriteLine(e);
|
||||
e = 2 + v;
|
||||
Console.WriteLine(e);
|
||||
e = v;
|
||||
Console.WriteLine(e);
|
||||
e = -v;
|
||||
Console.WriteLine(e);
|
||||
e = 1 - v;
|
||||
Console.WriteLine(e);
|
||||
e = v - 1;
|
||||
Console.WriteLine(e);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void LinearExprBoolVarOperatorTest()
|
||||
{
|
||||
Console.WriteLine("LinearExprBoolVarOperatorTest");
|
||||
CpModel model = new CpModel();
|
||||
BoolVar v = model.NewBoolVar("v");
|
||||
LinearExpr e = v * 2;
|
||||
Console.WriteLine(e);
|
||||
e = 2 * v;
|
||||
Console.WriteLine(e);
|
||||
e = v + 2;
|
||||
Console.WriteLine(e);
|
||||
e = 2 + v;
|
||||
Console.WriteLine(e);
|
||||
e = v;
|
||||
Console.WriteLine(e);
|
||||
e = -v;
|
||||
Console.WriteLine(e);
|
||||
e = 1 - v;
|
||||
Console.WriteLine(e);
|
||||
e = v - 1;
|
||||
Console.WriteLine(e);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void LinearExprNotBoolVarOperatorTest()
|
||||
{
|
||||
Console.WriteLine("LinearExprBoolVarNotOperatorTest");
|
||||
CpModel model = new CpModel();
|
||||
ILiteral v = model.NewBoolVar("v");
|
||||
LinearExpr e = v.NotAsExpr() * 2;
|
||||
Console.WriteLine(e);
|
||||
e = 2 * v.NotAsExpr();
|
||||
Console.WriteLine(e);
|
||||
e = v.NotAsExpr() + 2;
|
||||
Console.WriteLine(e);
|
||||
e = 2 + v.NotAsExpr();
|
||||
Console.WriteLine(e);
|
||||
e = v.NotAsExpr();
|
||||
Console.WriteLine(e);
|
||||
e = -v.NotAsExpr();
|
||||
Console.WriteLine(e);
|
||||
e = 1 - v.NotAsExpr();
|
||||
Console.WriteLine(e);
|
||||
e = v.NotAsExpr() - 1;
|
||||
Console.WriteLine(e);
|
||||
}
|
||||
[Fact]
|
||||
public void ExportModel()
|
||||
{
|
||||
|
||||
@@ -59,4 +59,226 @@ public class Constraint
|
||||
private ConstraintProto constraint_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specialized circuit constraint.
|
||||
*
|
||||
* <p>This constraint allows adding arcs to the circuit constraint incrementally.
|
||||
*/
|
||||
public class CircuitConstraint : Constraint
|
||||
{
|
||||
public CircuitConstraint(CpModelProto model) : base(model)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an arc to the graph of the circuit constraint.
|
||||
*
|
||||
* @param tail the index of the tail node.
|
||||
* @param head the index of the head node.
|
||||
* @param literal it will be set to true if the arc is selected.
|
||||
*/
|
||||
public void AddArc(int tail, int head, ILiteral literal)
|
||||
{
|
||||
CircuitConstraintProto circuit = Proto.Circuit;
|
||||
circuit.Tails.Add(tail);
|
||||
circuit.Heads.Add(head);
|
||||
circuit.Literals.Add(literal.GetIndex());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Specialized multiple circuit constraint.
|
||||
*
|
||||
* <p>This constraint allows adding arcs to the multiple circuit constraint incrementally.
|
||||
*/
|
||||
public class MultipleCircuitConstraint : Constraint
|
||||
{
|
||||
public MultipleCircuitConstraint(CpModelProto model) : base(model)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an arc to the graph of the circuit constraint.
|
||||
*
|
||||
* @param tail the index of the tail node.
|
||||
* @param head the index of the head node.
|
||||
* @param literal it will be set to true if the arc is selected.
|
||||
*/
|
||||
public void AddArc(int tail, int head, ILiteral literal)
|
||||
{
|
||||
RoutesConstraintProto routes = Proto.Routes;
|
||||
routes.Tails.Add(tail);
|
||||
routes.Heads.Add(head);
|
||||
routes.Literals.Add(literal.GetIndex());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Specialized assignment constraint.
|
||||
*
|
||||
* <p>This constraint allows adding tuples to the allowed/forbidden assignment constraint
|
||||
* incrementally.
|
||||
*/
|
||||
public class TableConstraint : Constraint
|
||||
{
|
||||
public TableConstraint(CpModelProto model) : base(model)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a tuple of possible/forbidden values to the constraint.
|
||||
*
|
||||
* @param tuple the tuple to add to the constraint.
|
||||
* @throws CpModel.WrongLength if the tuple does not have the same length as the array of
|
||||
* variables of the constraint.
|
||||
*/
|
||||
public void AddTuple(IEnumerable<int> tuple)
|
||||
{
|
||||
TableConstraintProto table = Proto.Table;
|
||||
|
||||
int count = 0;
|
||||
foreach (int value in tuple)
|
||||
{
|
||||
table.Values.Add(value);
|
||||
count++;
|
||||
}
|
||||
if (count != table.Vars.Count)
|
||||
{
|
||||
throw new ArgumentException("addTuple", "tuple does not have the same length as the variables");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a tuple of possible/forbidden values to the constraint.
|
||||
*
|
||||
* @param tuple the tuple to add to the constraint.
|
||||
* @throws CpModel.WrongLength if the tuple does not have the same length as the array of
|
||||
* variables of the constraint.
|
||||
*/
|
||||
public void AddTuple(IEnumerable<long> tuple)
|
||||
{
|
||||
TableConstraintProto table = Proto.Table;
|
||||
|
||||
int count = 0;
|
||||
foreach (long value in tuple)
|
||||
{
|
||||
table.Values.Add(value);
|
||||
count++;
|
||||
}
|
||||
if (count != table.Vars.Count)
|
||||
{
|
||||
throw new ArgumentException("addTuple", "tuple does not have the same length as the variables");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Specialized automaton constraint.
|
||||
*
|
||||
* <p>This constraint allows adding transitions to the automaton constraint incrementally.
|
||||
*/
|
||||
public class AutomatonConstraint : Constraint
|
||||
{
|
||||
public AutomatonConstraint(CpModelProto model) : base(model)
|
||||
{
|
||||
}
|
||||
|
||||
/// Adds a transitions to the automaton.
|
||||
public void AddTransition(int tail, int head, long label)
|
||||
{
|
||||
AutomatonConstraintProto aut = Proto.Automaton;
|
||||
aut.TransitionTail.Add(tail);
|
||||
aut.TransitionLabel.Add(label);
|
||||
aut.TransitionHead.Add(head);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Specialized reservoir constraint.
|
||||
*
|
||||
* <p>This constraint allows adding events (time, levelChange, isActive (optional)) to the reservoir
|
||||
* constraint incrementally.
|
||||
*/
|
||||
public class ReservoirConstraint : Constraint
|
||||
{
|
||||
public ReservoirConstraint(CpModel cp_model, CpModelProto model) : base(model)
|
||||
{
|
||||
this.cp_model_ = cp_model;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a mandatory event
|
||||
*
|
||||
* <p>It will increase the used capacity by `levelChange` at time `time`. `time` must be an affine
|
||||
* expression.
|
||||
*/
|
||||
public void AddEvent<T, L>(T time, L level_change)
|
||||
{
|
||||
ReservoirConstraintProto res = Proto.Reservoir;
|
||||
res.TimeExprs.Add(cp_model_.GetLinearExpressionProto(cp_model_.GetLinearExpr(time)));
|
||||
res.LevelChanges.Add(Convert.ToInt64(level_change));
|
||||
res.ActiveLiterals.Add(cp_model_.TrueLiteral().GetIndex());
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an optional event
|
||||
*
|
||||
* <p>If `isActive` is true, It will increase the used capacity by `levelChange` at time `time`.
|
||||
* `time` must be an affine expression.
|
||||
*/
|
||||
public void AddOptionalEvent<T, L>(T time, L level_change, ILiteral literal)
|
||||
{
|
||||
ReservoirConstraintProto res = Proto.Reservoir;
|
||||
res.TimeExprs.Add(cp_model_.GetLinearExpressionProto(cp_model_.GetLinearExpr(time)));
|
||||
res.LevelChanges.Add(Convert.ToInt64(level_change));
|
||||
res.ActiveLiterals.Add(literal.GetIndex());
|
||||
}
|
||||
|
||||
private CpModel cp_model_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specialized cumulative constraint.
|
||||
*
|
||||
* <p>This constraint allows adding (interval, demand) pairs to the cumulative constraint
|
||||
* incrementally.
|
||||
*/
|
||||
public class CumulativeConstraint : Constraint
|
||||
{
|
||||
public CumulativeConstraint(CpModel cp_model, CpModelProto model) : base(model)
|
||||
{
|
||||
this.cp_model_ = cp_model;
|
||||
}
|
||||
|
||||
/// Adds a pair (interval, demand) to the constraint.
|
||||
public void AddDemand<D>(IntervalVar interval, D demand)
|
||||
{
|
||||
CumulativeConstraintProto cumul = Proto.Cumulative;
|
||||
cumul.Intervals.Add(interval.GetIndex());
|
||||
LinearExpr demandExpr = cp_model_.GetLinearExpr(demand);
|
||||
cumul.Demands.Add(cp_model_.GetLinearExpressionProto(demandExpr));
|
||||
}
|
||||
|
||||
private CpModel cp_model_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specialized NoOverlap2D constraint.
|
||||
*
|
||||
* <p>This constraint allows adding rectanles to the NoOverlap2D constraint incrementally.
|
||||
*/
|
||||
public class NoOverlap2dConstraint : Constraint
|
||||
{
|
||||
public NoOverlap2dConstraint(CpModelProto model) : base(model)
|
||||
{
|
||||
}
|
||||
|
||||
/// Adds a rectangle (xInterval, yInterval) to the constraint.
|
||||
public void AddRectangle(IntervalVar xInterval, IntervalVar yInterval)
|
||||
{
|
||||
Proto.NoOverlap2D.XIntervals.Add(xInterval.GetIndex());
|
||||
Proto.NoOverlap2D.YIntervals.Add(yInterval.GetIndex());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Google.OrTools.Sat
|
||||
|
||||
@@ -195,50 +195,43 @@ public class CpModel
|
||||
return ct;
|
||||
}
|
||||
|
||||
public Constraint AddCircuit(IEnumerable<Tuple<int, int, ILiteral>> arcs)
|
||||
public CircuitConstraint AddCircuit()
|
||||
{
|
||||
Constraint ct = new Constraint(model_);
|
||||
CircuitConstraintProto circuit = new CircuitConstraintProto();
|
||||
foreach (var arc in arcs)
|
||||
{
|
||||
circuit.Tails.Add(arc.Item1);
|
||||
circuit.Heads.Add(arc.Item2);
|
||||
circuit.Literals.Add(arc.Item3.GetIndex());
|
||||
}
|
||||
ct.Proto.Circuit = circuit;
|
||||
CircuitConstraint ct = new CircuitConstraint(model_);
|
||||
ct.Proto.Circuit = new CircuitConstraintProto();
|
||||
return ct;
|
||||
}
|
||||
|
||||
public Constraint AddAllowedAssignments(IEnumerable<IntVar> vars, long[,] tuples)
|
||||
public MultipleCircuitConstraint AddMultipleCircuit()
|
||||
{
|
||||
Constraint ct = new Constraint(model_);
|
||||
MultipleCircuitConstraint ct = new MultipleCircuitConstraint(model_);
|
||||
ct.Proto.Routes = new RoutesConstraintProto();
|
||||
return ct;
|
||||
}
|
||||
|
||||
public TableConstraint AddAllowedAssignments(IEnumerable<IntVar> vars)
|
||||
{
|
||||
TableConstraint ct = new TableConstraint(model_);
|
||||
TableConstraintProto table = new TableConstraintProto();
|
||||
foreach (IntVar var in vars)
|
||||
{
|
||||
table.Vars.Add(var.Index);
|
||||
}
|
||||
for (int i = 0; i < tuples.GetLength(0); ++i)
|
||||
{
|
||||
for (int j = 0; j < tuples.GetLength(1); ++j)
|
||||
{
|
||||
table.Values.Add(tuples[i, j]);
|
||||
}
|
||||
}
|
||||
ct.Proto.Table = table;
|
||||
return ct;
|
||||
}
|
||||
|
||||
public Constraint AddForbiddenAssignments(IEnumerable<IntVar> vars, long[,] tuples)
|
||||
public TableConstraint AddForbiddenAssignments(IEnumerable<IntVar> vars)
|
||||
{
|
||||
Constraint ct = AddAllowedAssignments(vars, tuples);
|
||||
TableConstraint ct = AddAllowedAssignments(vars);
|
||||
ct.Proto.Table.Negated = true;
|
||||
return ct;
|
||||
}
|
||||
|
||||
public Constraint AddAutomaton(IEnumerable<IntVar> vars, long starting_state, long[,] transitions,
|
||||
IEnumerable<long> final_states)
|
||||
public AutomatonConstraint AddAutomaton(IEnumerable<IntVar> vars, long starting_state,
|
||||
IEnumerable<long> final_states)
|
||||
{
|
||||
Constraint ct = new Constraint(model_);
|
||||
AutomatonConstraint ct = new AutomatonConstraint(model_);
|
||||
AutomatonConstraintProto aut = new AutomatonConstraintProto();
|
||||
foreach (IntVar var in vars)
|
||||
{
|
||||
@@ -249,38 +242,6 @@ public class CpModel
|
||||
{
|
||||
aut.FinalStates.Add(f);
|
||||
}
|
||||
for (int i = 0; i < transitions.GetLength(0); ++i)
|
||||
{
|
||||
aut.TransitionTail.Add(transitions[i, 0]);
|
||||
aut.TransitionLabel.Add(transitions[i, 1]);
|
||||
aut.TransitionHead.Add(transitions[i, 2]);
|
||||
}
|
||||
|
||||
ct.Proto.Automaton = aut;
|
||||
return ct;
|
||||
}
|
||||
|
||||
public Constraint AddAutomaton(IEnumerable<IntVar> vars, long starting_state,
|
||||
IEnumerable<Tuple<long, long, long>> transitions, IEnumerable<long> final_states)
|
||||
{
|
||||
Constraint ct = new Constraint(model_);
|
||||
AutomatonConstraintProto aut = new AutomatonConstraintProto();
|
||||
foreach (IntVar var in vars)
|
||||
{
|
||||
aut.Vars.Add(var.Index);
|
||||
}
|
||||
aut.StartingState = starting_state;
|
||||
foreach (long f in final_states)
|
||||
{
|
||||
aut.FinalStates.Add(f);
|
||||
}
|
||||
foreach (Tuple<long, long, long> transition in transitions)
|
||||
{
|
||||
aut.TransitionHead.Add(transition.Item1);
|
||||
aut.TransitionLabel.Add(transition.Item2);
|
||||
aut.TransitionTail.Add(transition.Item3);
|
||||
}
|
||||
|
||||
ct.Proto.Automaton = aut;
|
||||
return ct;
|
||||
}
|
||||
@@ -301,19 +262,10 @@ public class CpModel
|
||||
return ct;
|
||||
}
|
||||
|
||||
public Constraint AddReservoirConstraint<I>(IEnumerable<IntVar> times, IEnumerable<I> levelChanges, long minLevel,
|
||||
long maxLevel)
|
||||
public ReservoirConstraint AddReservoirConstraint(long minLevel, long maxLevel)
|
||||
{
|
||||
Constraint ct = new Constraint(model_);
|
||||
ReservoirConstraint ct = new ReservoirConstraint(this, model_);
|
||||
ReservoirConstraintProto res = new ReservoirConstraintProto();
|
||||
foreach (IntVar time in times)
|
||||
{
|
||||
res.TimeExprs.Add(GetLinearExpressionProto(time));
|
||||
}
|
||||
foreach (I d in levelChanges)
|
||||
{
|
||||
res.LevelChanges.Add(Convert.ToInt64(d));
|
||||
}
|
||||
|
||||
res.MinLevel = minLevel;
|
||||
res.MaxLevel = maxLevel;
|
||||
@@ -322,75 +274,6 @@ public class CpModel
|
||||
return ct;
|
||||
}
|
||||
|
||||
public Constraint AddReservoirConstraintWithActive<I>(IEnumerable<IntVar> times, IEnumerable<I> levelChanges,
|
||||
IEnumerable<IntVar> actives, long minLevel, long maxLevel)
|
||||
{
|
||||
Constraint ct = new Constraint(model_);
|
||||
ReservoirConstraintProto res = new ReservoirConstraintProto();
|
||||
foreach (IntVar time in times)
|
||||
{
|
||||
res.TimeExprs.Add(GetLinearExpressionProto(time));
|
||||
}
|
||||
foreach (I d in levelChanges)
|
||||
{
|
||||
res.LevelChanges.Add(Convert.ToInt64(d));
|
||||
}
|
||||
foreach (IntVar var in actives)
|
||||
{
|
||||
res.ActiveLiterals.Add(var.Index);
|
||||
}
|
||||
res.MinLevel = minLevel;
|
||||
res.MaxLevel = maxLevel;
|
||||
ct.Proto.Reservoir = res;
|
||||
|
||||
return ct;
|
||||
}
|
||||
|
||||
public Constraint AddReservoirConstraint<I>(IEnumerable<LinearExpr> times, IEnumerable<I> levelChanges,
|
||||
long minLevel, long maxLevel)
|
||||
{
|
||||
Constraint ct = new Constraint(model_);
|
||||
ReservoirConstraintProto res = new ReservoirConstraintProto();
|
||||
foreach (LinearExpr time in times)
|
||||
{
|
||||
res.TimeExprs.Add(GetLinearExpressionProto(time));
|
||||
}
|
||||
foreach (I d in levelChanges)
|
||||
{
|
||||
res.LevelChanges.Add(Convert.ToInt64(d));
|
||||
}
|
||||
|
||||
res.MinLevel = minLevel;
|
||||
res.MaxLevel = maxLevel;
|
||||
ct.Proto.Reservoir = res;
|
||||
|
||||
return ct;
|
||||
}
|
||||
|
||||
public Constraint AddReservoirConstraintWithActive<I>(IEnumerable<LinearExpr> times, IEnumerable<I> levelChanges,
|
||||
IEnumerable<IntVar> actives, long minLevel, long maxLevel)
|
||||
{
|
||||
Constraint ct = new Constraint(model_);
|
||||
ReservoirConstraintProto res = new ReservoirConstraintProto();
|
||||
foreach (LinearExpr time in times)
|
||||
{
|
||||
res.TimeExprs.Add(GetLinearExpressionProto(time));
|
||||
}
|
||||
foreach (I d in levelChanges)
|
||||
{
|
||||
res.LevelChanges.Add(Convert.ToInt64(d));
|
||||
}
|
||||
foreach (IntVar var in actives)
|
||||
{
|
||||
res.ActiveLiterals.Add(var.Index);
|
||||
}
|
||||
res.MinLevel = minLevel;
|
||||
res.MaxLevel = maxLevel;
|
||||
ct.Proto.Reservoir = res;
|
||||
|
||||
return ct;
|
||||
}
|
||||
|
||||
public void AddMapDomain(IntVar var, IEnumerable<IntVar> bool_vars, long offset = 0)
|
||||
{
|
||||
int i = 0;
|
||||
@@ -500,133 +383,89 @@ public class CpModel
|
||||
return ct;
|
||||
}
|
||||
|
||||
public Constraint AddMinEquality(LinearExpr target, IEnumerable<IntVar> vars)
|
||||
{
|
||||
Constraint ct = new Constraint(model_);
|
||||
LinearArgumentProto args = new LinearArgumentProto();
|
||||
foreach (IntVar var in vars)
|
||||
{
|
||||
args.Exprs.Add(GetLinearExpressionProto(var, /*negate=*/true));
|
||||
}
|
||||
args.Target = GetLinearExpressionProto(target, /*negate=*/true);
|
||||
ct.Proto.LinMax = args;
|
||||
return ct;
|
||||
}
|
||||
|
||||
public Constraint AddMinEquality(LinearExpr target, IEnumerable<LinearExpr> exprs)
|
||||
{
|
||||
Constraint ct = new Constraint(model_);
|
||||
LinearArgumentProto args = new LinearArgumentProto();
|
||||
LinearArgumentProto lin = new LinearArgumentProto();
|
||||
foreach (LinearExpr expr in exprs)
|
||||
{
|
||||
args.Exprs.Add(GetLinearExpressionProto(expr, /*negate=*/true));
|
||||
lin.Exprs.Add(GetLinearExpressionProto(expr, /*negate=*/true));
|
||||
}
|
||||
args.Target = GetLinearExpressionProto(target, /*negate=*/true);
|
||||
ct.Proto.LinMax = args;
|
||||
return ct;
|
||||
}
|
||||
|
||||
public Constraint AddMaxEquality(IntVar target, IEnumerable<IntVar> vars)
|
||||
{
|
||||
Constraint ct = new Constraint(model_);
|
||||
LinearArgumentProto args = new LinearArgumentProto();
|
||||
foreach (IntVar var in vars)
|
||||
{
|
||||
args.Exprs.Add(GetLinearExpressionProto(var));
|
||||
}
|
||||
args.Target = GetLinearExpressionProto(target);
|
||||
ct.Proto.LinMax = args;
|
||||
lin.Target = GetLinearExpressionProto(target, /*negate=*/true);
|
||||
ct.Proto.LinMax = lin;
|
||||
return ct;
|
||||
}
|
||||
|
||||
public Constraint AddMaxEquality(LinearExpr target, IEnumerable<LinearExpr> exprs)
|
||||
{
|
||||
Constraint ct = new Constraint(model_);
|
||||
LinearArgumentProto args = new LinearArgumentProto();
|
||||
LinearArgumentProto lin = new LinearArgumentProto();
|
||||
foreach (LinearExpr expr in exprs)
|
||||
{
|
||||
args.Exprs.Add(GetLinearExpressionProto(expr));
|
||||
lin.Exprs.Add(GetLinearExpressionProto(expr));
|
||||
}
|
||||
args.Target = GetLinearExpressionProto(target);
|
||||
ct.Proto.LinMax = args;
|
||||
lin.Target = GetLinearExpressionProto(target);
|
||||
ct.Proto.LinMax = lin;
|
||||
return ct;
|
||||
}
|
||||
|
||||
public Constraint AddDivisionEquality<T, N, D>(T target, N num, D denom)
|
||||
{
|
||||
Constraint ct = new Constraint(model_);
|
||||
LinearArgumentProto args = new LinearArgumentProto();
|
||||
args.Exprs.Add(GetLinearExpressionProto(GetLinearExpr(num)));
|
||||
args.Exprs.Add(GetLinearExpressionProto(GetLinearExpr(denom)));
|
||||
args.Target = GetLinearExpressionProto(GetLinearExpr(target));
|
||||
ct.Proto.IntDiv = args;
|
||||
LinearArgumentProto div = new LinearArgumentProto();
|
||||
div.Exprs.Add(GetLinearExpressionProto(GetLinearExpr(num)));
|
||||
div.Exprs.Add(GetLinearExpressionProto(GetLinearExpr(denom)));
|
||||
div.Target = GetLinearExpressionProto(GetLinearExpr(target));
|
||||
ct.Proto.IntDiv = div;
|
||||
return ct;
|
||||
}
|
||||
|
||||
public Constraint AddAbsEquality(LinearExpr target, LinearExpr expr)
|
||||
{
|
||||
Constraint ct = new Constraint(model_);
|
||||
LinearArgumentProto args = new LinearArgumentProto();
|
||||
args.Exprs.Add(GetLinearExpressionProto(expr));
|
||||
args.Exprs.Add(GetLinearExpressionProto(expr, /*negate=*/true));
|
||||
args.Target = GetLinearExpressionProto(target);
|
||||
ct.Proto.LinMax = args;
|
||||
LinearArgumentProto abs = new LinearArgumentProto();
|
||||
abs.Exprs.Add(GetLinearExpressionProto(expr));
|
||||
abs.Exprs.Add(GetLinearExpressionProto(expr, /*negate=*/true));
|
||||
abs.Target = GetLinearExpressionProto(target);
|
||||
ct.Proto.LinMax = abs;
|
||||
return ct;
|
||||
}
|
||||
|
||||
public Constraint AddModuloEquality<T, V, M>(T target, V v, M m)
|
||||
{
|
||||
Constraint ct = new Constraint(model_);
|
||||
LinearArgumentProto args = new LinearArgumentProto();
|
||||
args.Exprs.Add(GetLinearExpressionProto(GetLinearExpr(v)));
|
||||
args.Exprs.Add(GetLinearExpressionProto(GetLinearExpr(m)));
|
||||
args.Target = GetLinearExpressionProto(GetLinearExpr(target));
|
||||
ct.Proto.IntMod = args;
|
||||
return ct;
|
||||
}
|
||||
|
||||
public Constraint AddMultiplicationEquality(LinearExpr target, IEnumerable<IntVar> vars)
|
||||
{
|
||||
Constraint ct = new Constraint(model_);
|
||||
LinearArgumentProto args = new LinearArgumentProto();
|
||||
args.Target = GetLinearExpressionProto(target);
|
||||
foreach (IntVar var in vars)
|
||||
{
|
||||
args.Exprs.Add(GetLinearExpressionProto(var));
|
||||
}
|
||||
ct.Proto.IntProd = args;
|
||||
LinearArgumentProto mod = new LinearArgumentProto();
|
||||
mod.Exprs.Add(GetLinearExpressionProto(GetLinearExpr(v)));
|
||||
mod.Exprs.Add(GetLinearExpressionProto(GetLinearExpr(m)));
|
||||
mod.Target = GetLinearExpressionProto(GetLinearExpr(target));
|
||||
ct.Proto.IntMod = mod;
|
||||
return ct;
|
||||
}
|
||||
|
||||
public Constraint AddMultiplicationEquality(LinearExpr target, IEnumerable<LinearExpr> exprs)
|
||||
{
|
||||
Constraint ct = new Constraint(model_);
|
||||
LinearArgumentProto args = new LinearArgumentProto();
|
||||
args.Target = GetLinearExpressionProto(target);
|
||||
LinearArgumentProto prod = new LinearArgumentProto();
|
||||
prod.Target = GetLinearExpressionProto(target);
|
||||
foreach (LinearExpr expr in exprs)
|
||||
{
|
||||
args.Exprs.Add(GetLinearExpressionProto(expr));
|
||||
prod.Exprs.Add(GetLinearExpressionProto(expr));
|
||||
}
|
||||
ct.Proto.IntProd = args;
|
||||
ct.Proto.IntProd = prod;
|
||||
return ct;
|
||||
}
|
||||
|
||||
public Constraint AddMultiplicationEquality(LinearExpr target, LinearExpr left, LinearExpr right)
|
||||
{
|
||||
Constraint ct = new Constraint(model_);
|
||||
LinearArgumentProto args = new LinearArgumentProto();
|
||||
args.Target = GetLinearExpressionProto(target);
|
||||
args.Exprs.Add(GetLinearExpressionProto(left));
|
||||
args.Exprs.Add(GetLinearExpressionProto(right));
|
||||
ct.Proto.IntProd = args;
|
||||
LinearArgumentProto prod = new LinearArgumentProto();
|
||||
prod.Target = GetLinearExpressionProto(target);
|
||||
prod.Exprs.Add(GetLinearExpressionProto(left));
|
||||
prod.Exprs.Add(GetLinearExpressionProto(right));
|
||||
ct.Proto.IntProd = prod;
|
||||
return ct;
|
||||
}
|
||||
|
||||
public Constraint AddProdEquality(IntVar target, IEnumerable<IntVar> vars)
|
||||
{
|
||||
return AddMultiplicationEquality(target, vars);
|
||||
}
|
||||
|
||||
// Scheduling support
|
||||
|
||||
public IntervalVar NewIntervalVar<S, D, E>(S start, D duration, E end, string name)
|
||||
@@ -682,44 +521,26 @@ public class CpModel
|
||||
public Constraint AddNoOverlap(IEnumerable<IntervalVar> intervals)
|
||||
{
|
||||
Constraint ct = new Constraint(model_);
|
||||
NoOverlapConstraintProto args = new NoOverlapConstraintProto();
|
||||
NoOverlapConstraintProto no_overlap = new NoOverlapConstraintProto();
|
||||
foreach (IntervalVar var in intervals)
|
||||
{
|
||||
args.Intervals.Add(var.GetIndex());
|
||||
no_overlap.Intervals.Add(var.GetIndex());
|
||||
}
|
||||
ct.Proto.NoOverlap = args;
|
||||
ct.Proto.NoOverlap = no_overlap;
|
||||
return ct;
|
||||
}
|
||||
|
||||
public Constraint AddNoOverlap2D(IEnumerable<IntervalVar> x_intervals, IEnumerable<IntervalVar> y_intervals)
|
||||
public NoOverlap2dConstraint AddNoOverlap2D()
|
||||
{
|
||||
Constraint ct = new Constraint(model_);
|
||||
NoOverlap2DConstraintProto args = new NoOverlap2DConstraintProto();
|
||||
foreach (IntervalVar var in x_intervals)
|
||||
{
|
||||
args.XIntervals.Add(var.GetIndex());
|
||||
}
|
||||
foreach (IntervalVar var in y_intervals)
|
||||
{
|
||||
args.YIntervals.Add(var.GetIndex());
|
||||
}
|
||||
ct.Proto.NoOverlap2D = args;
|
||||
NoOverlap2dConstraint ct = new NoOverlap2dConstraint(model_);
|
||||
ct.Proto.NoOverlap2D = new NoOverlap2DConstraintProto();
|
||||
return ct;
|
||||
}
|
||||
|
||||
public Constraint AddCumulative<D, C>(IEnumerable<IntervalVar> intervals, IEnumerable<D> demands, C capacity)
|
||||
public CumulativeConstraint AddCumulative<C>(C capacity)
|
||||
{
|
||||
Constraint ct = new Constraint(model_);
|
||||
CumulativeConstraint ct = new CumulativeConstraint(this, model_);
|
||||
CumulativeConstraintProto cumul = new CumulativeConstraintProto();
|
||||
foreach (IntervalVar var in intervals)
|
||||
{
|
||||
cumul.Intervals.Add(var.GetIndex());
|
||||
}
|
||||
foreach (D demand in demands)
|
||||
{
|
||||
LinearExpr demandExpr = GetLinearExpr(demand);
|
||||
cumul.Demands.Add(GetLinearExpressionProto(demandExpr));
|
||||
}
|
||||
LinearExpr capacityExpr = GetLinearExpr(capacity);
|
||||
cumul.Capacity = GetLinearExpressionProto(capacityExpr);
|
||||
ct.Proto.Cumulative = cumul;
|
||||
@@ -890,7 +711,7 @@ public class CpModel
|
||||
throw new ArgumentException("Cannot extract index from argument");
|
||||
}
|
||||
|
||||
private LinearExpr GetLinearExpr<X>(X x)
|
||||
public LinearExpr GetLinearExpr<X>(X x)
|
||||
{
|
||||
if (typeof(X) == typeof(IntVar))
|
||||
{
|
||||
@@ -907,7 +728,7 @@ public class CpModel
|
||||
throw new ArgumentException("Cannot convert argument to LinearExpr");
|
||||
}
|
||||
|
||||
private LinearExpressionProto GetLinearExpressionProto(LinearExpr expr, bool negate = false)
|
||||
public LinearExpressionProto GetLinearExpressionProto(LinearExpr expr, bool negate = false)
|
||||
{
|
||||
Dictionary<IntVar, long> dict = new Dictionary<IntVar, long>();
|
||||
long constant = LinearExpr.GetVarValueMap(expr, 1L, dict);
|
||||
|
||||
@@ -22,6 +22,7 @@ public interface ILiteral
|
||||
{
|
||||
ILiteral Not();
|
||||
int GetIndex();
|
||||
LinearExpr NotAsExpr();
|
||||
}
|
||||
|
||||
// Holds a term (expression * coefficient)
|
||||
@@ -333,7 +334,7 @@ public class LinearExpr
|
||||
}
|
||||
else if (term.expr is NotBoolVar)
|
||||
{
|
||||
IntVar i = ((NotBoolVar)term.expr).NotVar();
|
||||
IntVar i = (IntVar)((NotBoolVar)term.expr).Not();
|
||||
if (dict.ContainsKey(i))
|
||||
{
|
||||
dict[i] -= term.coefficient;
|
||||
@@ -712,6 +713,11 @@ public class BoolVar : IntVar, ILiteral
|
||||
return negation_;
|
||||
}
|
||||
|
||||
public LinearExpr NotAsExpr()
|
||||
{
|
||||
return (LinearExpr)Not();
|
||||
}
|
||||
|
||||
private NotBoolVar negation_;
|
||||
}
|
||||
|
||||
@@ -739,9 +745,9 @@ public class NotBoolVar : LinearExpr, ILiteral
|
||||
return boolvar_;
|
||||
}
|
||||
|
||||
public BoolVar NotVar()
|
||||
public LinearExpr NotAsExpr()
|
||||
{
|
||||
return boolvar_;
|
||||
return (LinearExpr)Not();
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
|
||||
@@ -40,28 +40,28 @@ public class AssignmentGroupsSat
|
||||
|
||||
// Allowed groups of workers:
|
||||
// [START allowed_groups]
|
||||
long[,] group1 = {
|
||||
{ 0, 0, 1, 1 }, // Workers 2, 3
|
||||
{ 0, 1, 0, 1 }, // Workers 1, 3
|
||||
{ 0, 1, 1, 0 }, // Workers 1, 2
|
||||
{ 1, 1, 0, 0 }, // Workers 0, 1
|
||||
{ 1, 0, 1, 0 }, // Workers 0, 2
|
||||
long[][] group1 = {
|
||||
new long[] { 0, 0, 1, 1 }, // Workers 2, 3
|
||||
new long[] { 0, 1, 0, 1 }, // Workers 1, 3
|
||||
new long[] { 0, 1, 1, 0 }, // Workers 1, 2
|
||||
new long[] { 1, 1, 0, 0 }, // Workers 0, 1
|
||||
new long[] { 1, 0, 1, 0 }, // Workers 0, 2
|
||||
};
|
||||
|
||||
long[,] group2 = {
|
||||
{ 0, 0, 1, 1 }, // Workers 6, 7
|
||||
{ 0, 1, 0, 1 }, // Workers 5, 7
|
||||
{ 0, 1, 1, 0 }, // Workers 5, 6
|
||||
{ 1, 1, 0, 0 }, // Workers 4, 5
|
||||
{ 1, 0, 0, 1 }, // Workers 4, 7
|
||||
long[][] group2 = {
|
||||
new long[] { 0, 0, 1, 1 }, // Workers 6, 7
|
||||
new long[] { 0, 1, 0, 1 }, // Workers 5, 7
|
||||
new long[] { 0, 1, 1, 0 }, // Workers 5, 6
|
||||
new long[] { 1, 1, 0, 0 }, // Workers 4, 5
|
||||
new long[] { 1, 0, 0, 1 }, // Workers 4, 7
|
||||
};
|
||||
|
||||
long[,] group3 = {
|
||||
{ 0, 0, 1, 1 }, // Workers 10, 11
|
||||
{ 0, 1, 0, 1 }, // Workers 9, 11
|
||||
{ 0, 1, 1, 0 }, // Workers 9, 10
|
||||
{ 1, 0, 1, 0 }, // Workers 8, 10
|
||||
{ 1, 0, 0, 1 }, // Workers 8, 11
|
||||
long[][] group3 = {
|
||||
new long[] { 0, 0, 1, 1 }, // Workers 10, 11
|
||||
new long[] { 0, 1, 0, 1 }, // Workers 9, 11
|
||||
new long[] { 0, 1, 1, 0 }, // Workers 9, 10
|
||||
new long[] { 1, 0, 1, 0 }, // Workers 8, 10
|
||||
new long[] { 1, 0, 0, 1 }, // Workers 8, 11
|
||||
};
|
||||
// [END allowed_groups]
|
||||
|
||||
@@ -127,9 +127,21 @@ public class AssignmentGroupsSat
|
||||
}
|
||||
|
||||
// Define the allowed groups of worders
|
||||
model.AddAllowedAssignments(new IntVar[] { work[0], work[1], work[2], work[3] }, group1);
|
||||
model.AddAllowedAssignments(new IntVar[] { work[4], work[5], work[6], work[7] }, group2);
|
||||
model.AddAllowedAssignments(new IntVar[] { work[8], work[9], work[10], work[11] }, group3);
|
||||
TableConstraint group1_ct = model.AddAllowedAssignments(new IntVar[] { work[0], work[1], work[2], work[3] });
|
||||
foreach (long[] tuple in group1)
|
||||
{
|
||||
group1_ct.AddTuple(tuple);
|
||||
}
|
||||
TableConstraint group2_ct = model.AddAllowedAssignments(new IntVar[] { work[4], work[5], work[6], work[7] });
|
||||
foreach (long[] tuple in group2)
|
||||
{
|
||||
group2_ct.AddTuple(tuple);
|
||||
}
|
||||
TableConstraint group3_ct = model.AddAllowedAssignments(new IntVar[] { work[8], work[9], work[10], work[11] });
|
||||
foreach (long[] tuple in group3)
|
||||
{
|
||||
group3_ct.AddTuple(tuple);
|
||||
}
|
||||
// [END assignments]
|
||||
|
||||
// Objective
|
||||
|
||||
@@ -61,23 +61,23 @@ public class AssignmentTeamsSat
|
||||
// Constraints
|
||||
// [START constraints]
|
||||
// Each worker is assigned to at most one task.
|
||||
for (int i = 0; i < numWorkers; ++i)
|
||||
foreach (int worker in allWorkers)
|
||||
{
|
||||
List<ILiteral> tasks = new List<ILiteral>();
|
||||
for (int j = 0; j < numTasks; ++j)
|
||||
foreach (int task in allTasks)
|
||||
{
|
||||
tasks.Add(x[i, j]);
|
||||
tasks.Add(x[worker, task]);
|
||||
}
|
||||
model.AddAtMostOne(tasks);
|
||||
}
|
||||
|
||||
// Each task is assigned to exactly one worker.
|
||||
for (int j = 0; j < numTasks; ++j)
|
||||
foreach (int task in allTasks)
|
||||
{
|
||||
List<ILiteral> workers = new List<ILiteral>();
|
||||
for (int i = 0; i < numWorkers; ++i)
|
||||
foreach (int worker in allWorkers)
|
||||
{
|
||||
workers.Add(x[i, j]);
|
||||
workers.Add(x[worker, task]);
|
||||
}
|
||||
model.AddExactlyOne(workers);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user