Table of Contents

Class Model

Namespace
OptalCP
Assembly
OptalCP.dll

Central class for building optimization models. Creates variables, constraints, and objectives.

public class Model
Inheritance
Model
Inherited Members

Remarks

Model captures the problem to be solved. It contains variables, constraints and objective function.

To create an optimization model, you must first create a Model object. Then you can use the methods of the Model to create variables (e.g. Model.IntervalVar), the objective function (Model.Minimize or Model.Maximize) and constraints (e.g. Model.NoOverlap). Note that a boolean expression becomes a constraint only by passing it to Model.Enforce; otherwise, it is not enforced.

To solve a model, pass it to function Model.Solve or to Solver class.

Available modeling elements

Variables

Interval variables can be created by function Model.IntervalVar, integer variables by function Model.IntVar.

Basic integer expressions

  • Model.Start: start of an interval variable (optional integer expression).
  • Model.End: end of an interval variable (optional integer expression).
  • Model.Length: length of an interval variable (optional integer expression).
  • Model.Guard: replaces absent value by a constant.

Integer arithmetics

Use standard arithmetic operators on integer expressions: +, -, unary -, *, /.

  • Model.Abs: absolute value.
  • Model.Min2: minimum of two integer expressions.
  • Model.Min: minimum of an array of integer expressions.
  • Model.Max2: maximum of two integer expressions.
  • Model.Max: maximum of an array of integer expressions.
  • Model.Sum: sum of an array of integer expressions.

Comparison operators for integer expressions

Use standard comparison operators on integer expressions: <, <=, ==, !=, >, >=.

  • Model.Identity: constraints two integer expressions to be equal, including the presence status.

Boolean operators

Functions returning BoolExpr

Basic constraints on interval variables

Disjunction (noOverlap)

  • Model.SequenceVar: sequence variable over a set of interval variables.
  • Model.NoOverlap: constraints a set of interval variables to not overlap (possibly with transition times).
  • Model.Position: returns the position of an interval variable in a sequence.

Basic cumulative expressions

Combining cumulative expressions

Use standard operators on cumulative expressions: +, -, unary -, and Model.Sum.

Constraints on cumulative expressions

Use comparison operators on cumulative expressions: <=, >=.

Objective

Example:

Our goal is to schedule a set of tasks such that it is finished as soon as possible (i.e., the makespan is minimized). Each task has a fixed duration, and cannot be interrupted. Moreover, each task needs a certain number of workers to be executed, and the total number of workers is limited. The input data are generated randomly.
using System;
using System.Linq;
using OptalCP;

// Constants for random problem generation:
int nbTasks = 100;
int nbWorkers = 5;
int maxDuration = 100;
var rng = new Random();

// Start by creating the model:
var model = new Model();

// For each task we will have an interval variable and a cumulative expression:
var tasks = new List<IntervalVar>();
var workerUsage = new List<CumulExpr>();

// Loop over the tasks:
for (int i = 0; i < nbTasks; i++) {
    int taskLength = 1 + rng.Next(maxDuration - 1);
    var task = model.IntervalVar(name: $"Task{i + 1}", length: taskLength);
    tasks.Add(task);
    int workersNeeded = 1 + rng.Next(nbWorkers - 1);
    workerUsage.Add(task.Pulse(workersNeeded));
}

// Limit the sum of the pulses to the number of workers available:
model.Enforce(model.Sum(workerUsage) <= nbWorkers);
// Minimize the maximum of the ends (makespan):
model.Minimize(model.Max(tasks.Select(t => t.End())));

// Solve the model:
var result = model.Solve(new Parameters {
    timeLimit = 3,
    nbWorkers = 4,
});

if (result.nbSolutions == 0)
    Console.WriteLine("No solution found.");
else {
    var solution = result.solution!;
    Console.WriteLine($"Solution found with makespan {solution.GetObjective()}");
    foreach (var task in tasks) {
        var start = solution.GetStart(task);
        if (start != null)
            Console.WriteLine($"Task {task.Name} starts at {start}");
        else
            Console.WriteLine($"Task {task.Name} is absent (not scheduled).");
    }
}

See also:

Constructors

Model(string?)

Creates an empty optimization model.

public Model(string? name = null)

Parameters

name string

Optional name for the model

Remarks

Creates an empty model with no variables, constraints, or objective.

The optional name parameter can be used to identify the model in logs, debugging output, and benchmarking reports. When not specified, the model remains unnamed.

After creating a model, use its methods to define:

// Create an unnamed model
var model = new Model();

// Create a named model (useful for debugging)
var namedModel = new Model(name: "JobShop");

// Add variables and constraints
var task = model.IntervalVar(length: 10, name: "task");
model.Minimize(task.End());

// Solve
var result = model.Solve();

See also:

Fields

IntVarMax

public const int IntVarMax = 1073741823

Field Value

int

Remarks

Maximum value of a decision variable or a decision expression (such as x+1 where x is a variable).

Arithmetic expressions must stay within the range [Model.IntVarMin, Model.IntVarMax]. If an expression exceeds this range for all possible variable assignments, the model becomes infeasible.

Example:

The following model is infeasible because x*x exceeds IntVarMax for all values in the variable's domain:
var model = new Model();
var x = model.IntVar(min: 10000000, max: 20000000);
// Constraint x*x >= 1:
model.Enforce(x * x >= 1);
var result = model.Solve();

For any value of x in the range [10000000, 20000000], the expression x*x exceeds Model.IntVarMax and cannot be computed, making the model infeasible.

IntVarMin

public const int IntVarMin = -1073741823

Field Value

int

Remarks

Minimum value of a decision variable or a decision expression (such as x+1 where x is a variable). The opposite of Model.IntVarMax.

Use IntVarMin when you need to allow the full range of negative values for an integer variable.

Example:

var model = new Model();
// IntVarMin is the minimum allowed value for integer variables
var x = model.IntVar(min: Model.IntVarMin, max: 0, name: "x");

IntervalMax

public const int IntervalMax = 715827882

Field Value

int

Remarks

Maximum value of start or end of an interval variable. The opposite of Model.IntervalMin.

Use IntervalMax when you want to leave the end time of an interval variable unconstrained.

Example:

var model = new Model();
// IntervalMax is the maximum allowed value for interval start/end
var task = model.IntervalVar(end: (0, Model.IntervalMax), length: 10, name: "task");

IntervalMin

public const int IntervalMin = -715827882

Field Value

int

Remarks

Minimum value of start or end of an interval variable. The opposite of Model.IntervalMax.

Use IntervalMin when you want to leave the start time of an interval variable unconstrained.

Example:

var model = new Model();
// IntervalMin is the minimum allowed value for interval start/end
var task = model.IntervalVar(start: (Model.IntervalMin, 0), length: 10, name: "task");

LengthMax

public const int LengthMax = 1431655764

Field Value

int

Remarks

Maximum length of an interval variable. The maximum length can be achieved by an interval that starts at Model.IntervalMin and ends at Model.IntervalMax.

Use LengthMax when you want to leave the length of an interval variable unconstrained.

Example:

var model = new Model();
// LengthMax is the maximum allowed length for an interval variable
var task = model.IntervalVar(length: (0, Model.LengthMax), name: "task");

Properties

Name

The name of the model.

public string? Name { get; set; }

Property Value

string

Remarks

The name is optional and primarily useful for distinguishing between different models during debugging and benchmarking. When set, it helps identify the model in logs and benchmark results.

The name can be set either in the constructor or by assigning to this property. Assigning overwrites any name that was previously set.

// Set name in constructor
var model = new Model(name: "MySchedulingProblem");
Console.WriteLine(model.Name);  // "MySchedulingProblem"

// Or set name later
model = new Model();
model.Name = "JobShop";
Console.WriteLine(model.Name);  // "JobShop"

// Clear the name
model.Name = null;

Methods

Abs(IntExpr)

Creates an integer expression which is absolute value of arg.

public IntExpr Abs(IntExpr arg)

Parameters

arg IntExpr

The argument (IntExpr or int).

Returns

IntExpr

The resulting integer expression

Remarks

If arg has value absent then the resulting expression has also value absent.

Same as IntExpr.Abs.

Abs(int)

Creates an integer expression which is absolute value of arg.

public IntExpr Abs(int arg)

Parameters

arg int

The argument (IntExpr or int).

Returns

IntExpr

The resulting integer expression

Remarks

If arg has value absent then the resulting expression has also value absent.

Same as IntExpr.Abs.

Alternative(IntervalVar, IEnumerable<IntervalVar>)

Alternative constraint models a choice between different ways to execute an interval.

public Constraint Alternative(IntervalVar main, IEnumerable<IntervalVar> options)

Parameters

main IntervalVar

The main interval variable.

options IEnumerable<IntervalVar>

Array of optional interval variables to choose from.

Returns

Constraint

The alternative constraint.

Remarks

Alternative constraint is a way to model various kinds of choices. For example, we can model a task that could be done by worker A, B, or C. To model such alternative, we use interval variable main that represents the task regardless the chosen worker and three interval variables options = [A, B, C] that represent the task when done by worker A, B, or C. Interval variables A, B, and C should be optional. This way, if e.g. option B is chosen, then B will be present and equal to main (they will start at the same time and end at the same time), the remaining options, A and C, will be absent.

We may also decide not to execute the main task at all (if it is optional). Then main will be absent and all options A, B and C will be absent too.

Formal definition

The constraint alternative(main, options) is satisfied in the following two cases:

  1. Interval main is absent and all options[i] are absent too.
  2. Interval main is present and exactly one of options[i] is present (the remaining options are absent). Let k be the index of the present option. Then main.start() == options[k].start() and main.end() == options[k].end().

Example:

Let's consider task T, which can be done by workers A, B, or C. The length of the task and a cost associated with it depends on the chosen worker:
  • If done by worker A, then its length is 10, and the cost is 5.
  • If done by worker B, then its length is 20, and the cost is 2.
  • If done by worker C, then its length is 3, and the cost is 10.

Each worker can execute only one task at a time. However, the remaining tasks are omitted in the model below. The objective could be, e.g., to minimize the total cost (also omitted in the model).

var model = new Model();

var T = model.IntervalVar(name: "T");
var T_A = model.IntervalVar(name: "T_A", optional: true, length: 10);
var T_B = model.IntervalVar(name: "T_B", optional: true, length: 20);
var T_C = model.IntervalVar(name: "T_C", optional: true, length: 3);

// T_A, T_B and T_C are different ways to execute task T:
model.Alternative(T, new[] { T_A, T_B, T_C });
// The cost depends on the chosen option:
var costOfT = model.Sum(new IntExpr[] {
    model.Presence(T_A) * 5,
    model.Presence(T_B) * 2,
    model.Presence(T_C) * 10
});

// Each worker A can perform only one task at a time:
model.NoOverlap(new[] { T_A /* ... other Worker A tasks */ });  // Worker A
model.NoOverlap(new[] { T_B /* ... other Worker B tasks */ });  // Worker B
model.NoOverlap(new[] { T_C /* ... other Worker C tasks */ });  // Worker C

// Minimize the total cost:
model.Minimize(model.Sum(new IntExpr[] { costOfT /* ... other costs */ }));

And(BoolExpr, BoolExpr)

Logical AND of boolean expressions lhs and rhs.

public BoolExpr And(BoolExpr lhs, BoolExpr rhs)

Parameters

lhs BoolExpr

The left-hand side operand (BoolExpr or bool).

rhs BoolExpr

The right-hand side operand (BoolExpr or bool).

Returns

BoolExpr

The resulting Boolean expression

Remarks

If one of the arguments has value absent, then the resulting expression also has value absent.

Same as BoolExpr.And.

And(BoolExpr, bool)

Logical AND of boolean expressions lhs and rhs.

public BoolExpr And(BoolExpr lhs, bool rhs)

Parameters

lhs BoolExpr

The left-hand side operand (BoolExpr or bool).

rhs bool

The right-hand side operand (BoolExpr or bool).

Returns

BoolExpr

The resulting Boolean expression

Remarks

If one of the arguments has value absent, then the resulting expression also has value absent.

Same as BoolExpr.And.

And(bool, BoolExpr)

Logical AND of boolean expressions lhs and rhs.

public BoolExpr And(bool lhs, BoolExpr rhs)

Parameters

lhs bool

The left-hand side operand (BoolExpr or bool).

rhs BoolExpr

The right-hand side operand (BoolExpr or bool).

Returns

BoolExpr

The resulting Boolean expression

Remarks

If one of the arguments has value absent, then the resulting expression also has value absent.

Same as BoolExpr.And.

BoolVar(bool, string?)

Creates a new boolean variable and adds it to the model.

public BoolVar BoolVar(bool optional = false, string? name = null)

Parameters

optional bool

If true, the variable can be absent in a solution. The default is false.

name string

Optional name for the variable (useful for debugging).

Returns

BoolVar

The created boolean variable.

Remarks

A boolean variable represents an unknown truth value (true or false) that the solver must find. Boolean variables are useful for modeling decisions, choices, or logical conditions in your problem.

By default, a boolean variable must be assigned a value (true or false) in every solution. When optional: true, the variable can also be absent, meaning the solution does not use the variable at all. This is useful when the variable represents a decision that may not apply in all scenarios.

Boolean variables support logical operators:

  • !x for logical NOT
  • x | y for logical OR
  • x & y for logical AND

Note: use & and | (bitwise operators), not && and || (short-circuit operators), as C# does not allow overloading &&/||.

Example:

Create boolean variables to model decisions:
var model = new Model();
var useMachineA = model.BoolVar(name: "useMachineA");
var useMachineB = model.BoolVar(name: "useMachineB");

// Constraint: must use at least one machine
model.Enforce(useMachineA | useMachineB);

// Constraint: cannot use both machines
model.Enforce(!(useMachineA & useMachineB));

See also:

Element(IEnumerable<int>, IntExpr)

Creates an integer expression for array element lookup by index.

public IntExpr Element(IEnumerable<int> array, IntExpr subscript)

Parameters

array IEnumerable<int>

Array of integer values to select from.

subscript IntExpr

Index into the array (0-based).

Returns

IntExpr

The resulting integer expression equal to array[subscript].

Remarks

The result of element(array, subscript) is an integer expression equal to array[subscript].

Creating the expression automatically adds a side constraint that restricts subscript to the valid index range 0 to n - 1, where n is the number of elements in array. This constraint must be satisfied in every solution, regardless of how the expression is used. For example, in element(array, subscript) == 5 || x == 1, the subscript must be a valid index even in solutions where x == 1 makes the disjunction true.

When the subscript is absent, the result is also absent.

Example:

In the following example, there are 3 machines with different processing times for a task. We use element to look up the processing time based on which machine is assigned.
var model = new Model();
// Processing times for each machine:
var durations = new[] { 5, 8, 3 };
// Decision variable: which machine to use (0, 1, or 2):
var machine = model.IntVar(min: 0, max: durations.Length - 1, name: "machine");
// Look up the duration for the chosen machine:
var duration = model.Element(durations, machine);
var task = model.IntervalVar(length: duration, name: "task");
model.Minimize(task.End());

See also:

Element(IEnumerable<int>, int)

Creates an integer expression for array element lookup by index.

public IntExpr Element(IEnumerable<int> array, int subscript)

Parameters

array IEnumerable<int>

Array of integer values to select from.

subscript int

Index into the array (0-based).

Returns

IntExpr

The resulting integer expression equal to array[subscript].

Remarks

The result of element(array, subscript) is an integer expression equal to array[subscript].

Creating the expression automatically adds a side constraint that restricts subscript to the valid index range 0 to n - 1, where n is the number of elements in array. This constraint must be satisfied in every solution, regardless of how the expression is used. For example, in element(array, subscript) == 5 || x == 1, the subscript must be a valid index even in solutions where x == 1 makes the disjunction true.

When the subscript is absent, the result is also absent.

Example:

In the following example, there are 3 machines with different processing times for a task. We use element to look up the processing time based on which machine is assigned.
var model = new Model();
// Processing times for each machine:
var durations = new[] { 5, 8, 3 };
// Decision variable: which machine to use (0, 1, or 2):
var machine = model.IntVar(min: 0, max: durations.Length - 1, name: "machine");
// Look up the duration for the chosen machine:
var duration = model.Element(durations, machine);
var task = model.IntervalVar(length: duration, name: "task");
model.Minimize(task.End());

See also:

End(IntervalVar)

Creates an integer expression for the end time of an interval variable.

public IntExpr End(IntervalVar interval)

Parameters

interval IntervalVar

The interval variable.

Returns

IntExpr

The resulting integer expression

Remarks

If the interval is absent, the resulting expression is also absent.

Example:

In the following example, we constrain interval variable y to start after the end of x with a delay of at least 10. In addition, we constrain the length of x to be less or equal to the length of y.
var model = new Model();
var x = model.IntervalVar(name: "x");
var y = model.IntervalVar(name: "y");
model.Enforce(model.End(x) + 10 <= model.Start(y));
model.Enforce(model.Length(x) <= model.Length(y));

When x or y is absent then value of both constraints above is absent and therefore they are satisfied.

See also:

EndAtEnd(IntervalVar, IntervalVar, IntExpr)

Creates a precedence constraint between two interval variables.

public Constraint EndAtEnd(IntervalVar predecessor, IntervalVar successor, IntExpr delay)

Parameters

predecessor IntervalVar

The predecessor interval variable.

successor IntervalVar

The successor interval variable.

delay IntExpr

The minimum delay between intervals.

Returns

Constraint

The precedence constraint.

Remarks

Same as:

model.Enforce(predecessor.End() + delay == successor.End());

In other words, end of predecessor plus delay must be equal to end of successor.

When one of the two interval variables is absent, then the constraint is satisfied.

See also:

EndAtEnd(IntervalVar, IntervalVar, int)

Creates a precedence constraint between two interval variables.

public Constraint EndAtEnd(IntervalVar predecessor, IntervalVar successor, int delay = 0)

Parameters

predecessor IntervalVar

The predecessor interval variable.

successor IntervalVar

The successor interval variable.

delay int

The minimum delay between intervals.

Returns

Constraint

The precedence constraint.

Remarks

Same as:

model.Enforce(predecessor.End() + delay == successor.End());

In other words, end of predecessor plus delay must be equal to end of successor.

When one of the two interval variables is absent, then the constraint is satisfied.

See also:

EndAtStart(IntervalVar, IntervalVar, IntExpr)

Creates a precedence constraint between two interval variables.

public Constraint EndAtStart(IntervalVar predecessor, IntervalVar successor, IntExpr delay)

Parameters

predecessor IntervalVar

The predecessor interval variable.

successor IntervalVar

The successor interval variable.

delay IntExpr

The minimum delay between intervals.

Returns

Constraint

The precedence constraint.

Remarks

Same as:

model.Enforce(predecessor.End() + delay == successor.Start());

In other words, end of predecessor plus delay must be equal to start of successor.

When one of the two interval variables is absent, then the constraint is satisfied.

See also:

EndAtStart(IntervalVar, IntervalVar, int)

Creates a precedence constraint between two interval variables.

public Constraint EndAtStart(IntervalVar predecessor, IntervalVar successor, int delay = 0)

Parameters

predecessor IntervalVar

The predecessor interval variable.

successor IntervalVar

The successor interval variable.

delay int

The minimum delay between intervals.

Returns

Constraint

The precedence constraint.

Remarks

Same as:

model.Enforce(predecessor.End() + delay == successor.Start());

In other words, end of predecessor plus delay must be equal to start of successor.

When one of the two interval variables is absent, then the constraint is satisfied.

See also:

EndBeforeEnd(IntervalVar, IntervalVar, IntExpr)

Creates a precedence constraint between two interval variables.

public Constraint EndBeforeEnd(IntervalVar predecessor, IntervalVar successor, IntExpr delay)

Parameters

predecessor IntervalVar

The predecessor interval variable.

successor IntervalVar

The successor interval variable.

delay IntExpr

The minimum delay between intervals.

Returns

Constraint

The precedence constraint.

Remarks

Same as:

model.Enforce(predecessor.End() + delay <= successor.End());

In other words, end of predecessor plus delay must be less than or equal to end of successor.

When one of the two interval variables is absent, then the constraint is satisfied.

See also:

EndBeforeEnd(IntervalVar, IntervalVar, int)

Creates a precedence constraint between two interval variables.

public Constraint EndBeforeEnd(IntervalVar predecessor, IntervalVar successor, int delay = 0)

Parameters

predecessor IntervalVar

The predecessor interval variable.

successor IntervalVar

The successor interval variable.

delay int

The minimum delay between intervals.

Returns

Constraint

The precedence constraint.

Remarks

Same as:

model.Enforce(predecessor.End() + delay <= successor.End());

In other words, end of predecessor plus delay must be less than or equal to end of successor.

When one of the two interval variables is absent, then the constraint is satisfied.

See also:

EndBeforeStart(IntervalVar, IntervalVar, IntExpr)

Creates a precedence constraint between two interval variables.

public Constraint EndBeforeStart(IntervalVar predecessor, IntervalVar successor, IntExpr delay)

Parameters

predecessor IntervalVar

The predecessor interval variable.

successor IntervalVar

The successor interval variable.

delay IntExpr

The minimum delay between intervals.

Returns

Constraint

The precedence constraint.

Remarks

Same as:

model.Enforce(predecessor.End() + delay <= successor.Start());

In other words, end of predecessor plus delay must be less than or equal to start of successor.

When one of the two interval variables is absent, then the constraint is satisfied.

See also:

EndBeforeStart(IntervalVar, IntervalVar, int)

Creates a precedence constraint between two interval variables.

public Constraint EndBeforeStart(IntervalVar predecessor, IntervalVar successor, int delay = 0)

Parameters

predecessor IntervalVar

The predecessor interval variable.

successor IntervalVar

The successor interval variable.

delay int

The minimum delay between intervals.

Returns

Constraint

The precedence constraint.

Remarks

Same as:

model.Enforce(predecessor.End() + delay <= successor.Start());

In other words, end of predecessor plus delay must be less than or equal to start of successor.

When one of the two interval variables is absent, then the constraint is satisfied.

See also:

Enforce(BoolExpr)

Enforces a boolean expression as a constraint in the model.

public void Enforce(BoolExpr expr)

Parameters

expr BoolExpr

Remarks

This is the primary method for enforcing boolean expressions as constraints in the model.

A constraint is satisfied if it is not false. In other words, a constraint is satisfied if it is true or absent.

A boolean expression that is not enforced as a constraint can have arbitrary value in a solution (true, false, or absent). Once enforced as a constraint, it can only be true or absent in the solution.

Note: Constraint objects are automatically registered when created. Passing them to enforce() is accepted but does nothing. For cumulative constraints (cumul <= capacity, cumul >= min_level), using enforce() is recommended for code clarity even though it's not required.

Accepted argument types

The enforce method accepts several types of arguments:

  1. BoolExpr objects: Boolean expressions created from comparisons (e.g., x <= 5, a == b) or logical operations (e.g., a & b, ~c).
  2. bool values: Python boolean constants True or False.
  3. Constraint objects: Accepted but does nothing (constraints auto-register). Use with cumulative constraints for clarity: model.enforce(cumul <= capacity).
  4. Iterables: Lists, tuples, or generators of the above types.

Example:

Basic usage with a boolean expression:
var model = new Model();
var x = model.IntervalVar(length: 10, name: "x");

// Enforce boolean expressions as constraints
model.Enforce(x.Start() >= 0);
model.Enforce(x.End() <= 100);

Example:

Enforcing multiple constraints at once using an iterable:
var model = new Model();
var tasks = new IntervalVar[5];
for (int i = 0; i < 5; i++)
    tasks[i] = model.IntervalVar(length: 10, name: $"task_{i}");

// Enforce multiple constraints at once
model.Enforce(tasks.Select(task => task.Start() >= 0));

// Or inline
model.Enforce(tasks.Select(task => task.End() <= 100));

Example:

Enforcing multiple boolean expressions:
var model = new Model();
var x = model.IntVar(min: 0, max: 100, name: "x");
var y = model.IntVar(min: 0, max: 100, name: "y");

// Enforce various boolean expressions
model.Enforce(new BoolExpr[] {
    x + y <= 50,           // From comparison
    x >= 10,               // From comparison
});

See also:

Enforce(Constraint)

Enforces a boolean expression as a constraint in the model.

public void Enforce(Constraint constraint)

Parameters

constraint Constraint

The constraint, boolean expression, or iterable of these to enforce in the model

Remarks

This is the primary method for enforcing boolean expressions as constraints in the model.

A constraint is satisfied if it is not false. In other words, a constraint is satisfied if it is true or absent.

A boolean expression that is not enforced as a constraint can have arbitrary value in a solution (true, false, or absent). Once enforced as a constraint, it can only be true or absent in the solution.

Note: Constraint objects are automatically registered when created. Passing them to enforce() is accepted but does nothing. For cumulative constraints (cumul <= capacity, cumul >= min_level), using enforce() is recommended for code clarity even though it's not required.

Accepted argument types

The enforce method accepts several types of arguments:

  1. BoolExpr objects: Boolean expressions created from comparisons (e.g., x <= 5, a == b) or logical operations (e.g., a & b, ~c).
  2. bool values: Python boolean constants True or False.
  3. Constraint objects: Accepted but does nothing (constraints auto-register). Use with cumulative constraints for clarity: model.enforce(cumul <= capacity).
  4. Iterables: Lists, tuples, or generators of the above types.

Example:

Basic usage with a boolean expression:
var model = new Model();
var x = model.IntervalVar(length: 10, name: "x");

// Enforce boolean expressions as constraints
model.Enforce(x.Start() >= 0);
model.Enforce(x.End() <= 100);

Example:

Enforcing multiple constraints at once using an iterable:
var model = new Model();
var tasks = new IntervalVar[5];
for (int i = 0; i < 5; i++)
    tasks[i] = model.IntervalVar(length: 10, name: $"task_{i}");

// Enforce multiple constraints at once
model.Enforce(tasks.Select(task => task.Start() >= 0));

// Or inline
model.Enforce(tasks.Select(task => task.End() <= 100));

Example:

Enforcing multiple boolean expressions:
var model = new Model();
var x = model.IntVar(min: 0, max: 100, name: "x");
var y = model.IntVar(min: 0, max: 100, name: "y");

// Enforce various boolean expressions
model.Enforce(new BoolExpr[] {
    x + y <= 50,           // From comparison
    x >= 10,               // From comparison
});

See also:

Enforce(bool)

Enforces a boolean expression as a constraint in the model.

public void Enforce(bool value)

Parameters

value bool

Remarks

This is the primary method for enforcing boolean expressions as constraints in the model.

A constraint is satisfied if it is not false. In other words, a constraint is satisfied if it is true or absent.

A boolean expression that is not enforced as a constraint can have arbitrary value in a solution (true, false, or absent). Once enforced as a constraint, it can only be true or absent in the solution.

Note: Constraint objects are automatically registered when created. Passing them to enforce() is accepted but does nothing. For cumulative constraints (cumul <= capacity, cumul >= min_level), using enforce() is recommended for code clarity even though it's not required.

Accepted argument types

The enforce method accepts several types of arguments:

  1. BoolExpr objects: Boolean expressions created from comparisons (e.g., x <= 5, a == b) or logical operations (e.g., a & b, ~c).
  2. bool values: Python boolean constants True or False.
  3. Constraint objects: Accepted but does nothing (constraints auto-register). Use with cumulative constraints for clarity: model.enforce(cumul <= capacity).
  4. Iterables: Lists, tuples, or generators of the above types.

Example:

Basic usage with a boolean expression:
var model = new Model();
var x = model.IntervalVar(length: 10, name: "x");

// Enforce boolean expressions as constraints
model.Enforce(x.Start() >= 0);
model.Enforce(x.End() <= 100);

Example:

Enforcing multiple constraints at once using an iterable:
var model = new Model();
var tasks = new IntervalVar[5];
for (int i = 0; i < 5; i++)
    tasks[i] = model.IntervalVar(length: 10, name: $"task_{i}");

// Enforce multiple constraints at once
model.Enforce(tasks.Select(task => task.Start() >= 0));

// Or inline
model.Enforce(tasks.Select(task => task.End() <= 100));

Example:

Enforcing multiple boolean expressions:
var model = new Model();
var x = model.IntVar(min: 0, max: 100, name: "x");
var y = model.IntVar(min: 0, max: 100, name: "y");

// Enforce various boolean expressions
model.Enforce(new BoolExpr[] {
    x + y <= 50,           // From comparison
    x >= 10,               // From comparison
});

See also:

Enforce(IEnumerable<BoolExpr>)

Enforces a boolean expression as a constraint in the model.

public void Enforce(IEnumerable<BoolExpr> expressions)

Parameters

expressions IEnumerable<BoolExpr>

Remarks

This is the primary method for enforcing boolean expressions as constraints in the model.

A constraint is satisfied if it is not false. In other words, a constraint is satisfied if it is true or absent.

A boolean expression that is not enforced as a constraint can have arbitrary value in a solution (true, false, or absent). Once enforced as a constraint, it can only be true or absent in the solution.

Note: Constraint objects are automatically registered when created. Passing them to enforce() is accepted but does nothing. For cumulative constraints (cumul <= capacity, cumul >= min_level), using enforce() is recommended for code clarity even though it's not required.

Accepted argument types

The enforce method accepts several types of arguments:

  1. BoolExpr objects: Boolean expressions created from comparisons (e.g., x <= 5, a == b) or logical operations (e.g., a & b, ~c).
  2. bool values: Python boolean constants True or False.
  3. Constraint objects: Accepted but does nothing (constraints auto-register). Use with cumulative constraints for clarity: model.enforce(cumul <= capacity).
  4. Iterables: Lists, tuples, or generators of the above types.

Example:

Basic usage with a boolean expression:
var model = new Model();
var x = model.IntervalVar(length: 10, name: "x");

// Enforce boolean expressions as constraints
model.Enforce(x.Start() >= 0);
model.Enforce(x.End() <= 100);

Example:

Enforcing multiple constraints at once using an iterable:
var model = new Model();
var tasks = new IntervalVar[5];
for (int i = 0; i < 5; i++)
    tasks[i] = model.IntervalVar(length: 10, name: $"task_{i}");

// Enforce multiple constraints at once
model.Enforce(tasks.Select(task => task.Start() >= 0));

// Or inline
model.Enforce(tasks.Select(task => task.End() <= 100));

Example:

Enforcing multiple boolean expressions:
var model = new Model();
var x = model.IntVar(min: 0, max: 100, name: "x");
var y = model.IntVar(min: 0, max: 100, name: "y");

// Enforce various boolean expressions
model.Enforce(new BoolExpr[] {
    x + y <= 50,           // From comparison
    x >= 10,               // From comparison
});

See also:

Enforce(IEnumerable<Constraint>)

Enforces a boolean expression as a constraint in the model.

public void Enforce(IEnumerable<Constraint> constraints)

Parameters

constraints IEnumerable<Constraint>

Remarks

This is the primary method for enforcing boolean expressions as constraints in the model.

A constraint is satisfied if it is not false. In other words, a constraint is satisfied if it is true or absent.

A boolean expression that is not enforced as a constraint can have arbitrary value in a solution (true, false, or absent). Once enforced as a constraint, it can only be true or absent in the solution.

Note: Constraint objects are automatically registered when created. Passing them to enforce() is accepted but does nothing. For cumulative constraints (cumul <= capacity, cumul >= min_level), using enforce() is recommended for code clarity even though it's not required.

Accepted argument types

The enforce method accepts several types of arguments:

  1. BoolExpr objects: Boolean expressions created from comparisons (e.g., x <= 5, a == b) or logical operations (e.g., a & b, ~c).
  2. bool values: Python boolean constants True or False.
  3. Constraint objects: Accepted but does nothing (constraints auto-register). Use with cumulative constraints for clarity: model.enforce(cumul <= capacity).
  4. Iterables: Lists, tuples, or generators of the above types.

Example:

Basic usage with a boolean expression:
var model = new Model();
var x = model.IntervalVar(length: 10, name: "x");

// Enforce boolean expressions as constraints
model.Enforce(x.Start() >= 0);
model.Enforce(x.End() <= 100);

Example:

Enforcing multiple constraints at once using an iterable:
var model = new Model();
var tasks = new IntervalVar[5];
for (int i = 0; i < 5; i++)
    tasks[i] = model.IntervalVar(length: 10, name: $"task_{i}");

// Enforce multiple constraints at once
model.Enforce(tasks.Select(task => task.Start() >= 0));

// Or inline
model.Enforce(tasks.Select(task => task.End() <= 100));

Example:

Enforcing multiple boolean expressions:
var model = new Model();
var x = model.IntVar(min: 0, max: 100, name: "x");
var y = model.IntVar(min: 0, max: 100, name: "y");

// Enforce various boolean expressions
model.Enforce(new BoolExpr[] {
    x + y <= 50,           // From comparison
    x >= 10,               // From comparison
});

See also:

Eval(IntStepFunction, IntExpr)

Evaluates a step function at a given point.

public IntExpr Eval(IntStepFunction func, IntExpr arg)

Parameters

func IntStepFunction

The step function.

arg IntExpr

The point at which to evaluate the step function.

Returns

IntExpr

The resulting integer expression

Remarks

The result is the value of the step function func at the point arg. If the value of arg is absent, then the result is also absent.

By constraining the returned value, it is possible to limit arg to be only within certain segments of the segmented function. In particular, functions Model.ForbidStart and Model.ForbidEnd work that way.

See also:

Eval(IntStepFunction, int)

Evaluates a step function at a given point.

public IntExpr Eval(IntStepFunction func, int arg)

Parameters

func IntStepFunction

The step function.

arg int

The point at which to evaluate the step function.

Returns

IntExpr

The resulting integer expression

Remarks

The result is the value of the step function func at the point arg. If the value of arg is absent, then the result is also absent.

By constraining the returned value, it is possible to limit arg to be only within certain segments of the segmented function. In particular, functions Model.ForbidStart and Model.ForbidEnd work that way.

See also:

ForbidEnd(IntervalVar, IntStepFunction)

Constrains the end of the interval variable to be outside of the zero-height segments of the step function.

public Constraint ForbidEnd(IntervalVar interval, IntStepFunction func)

Parameters

interval IntervalVar

The interval variable.

func IntStepFunction

The step function.

Returns

Constraint

The constraint forbidding the end point.

Remarks

This function is equivalent to:

I.e., the function value at the end of the interval variable cannot be zero.

@example A delivery task that must complete during business hours (not during lunch break):

var model = new Model();

// A 1-hour delivery task
var delivery = model.IntervalVar(length: 1, name: "delivery");

// Allowed end times: 1 = allowed, 0 = forbidden
var allowedEnds = model.StepFunction(new[] {
    (0, 0),   // Before 9h: forbidden
    (9, 1),   // 9h: business opens, allowed
    (12, 0),  // 12h: lunch break, forbidden
    (13, 1),  // 13h: lunch ends, allowed
    (17, 0),  // 17h: business closes, forbidden
});

// Delivery cannot end when allowedEnds is 0
model.ForbidEnd(delivery, allowedEnds);
model.Minimize(delivery.End());

var result = model.Solve();

See also:

ForbidExtent(IntervalVar, IntStepFunction)

Forbid the interval variable to overlap with segments of the function where the value is zero.

public Constraint ForbidExtent(IntervalVar interval, IntStepFunction func)

Parameters

interval IntervalVar

The interval variable.

func IntStepFunction

The step function.

Returns

Constraint

The constraint forbidding the extent (entire interval).

Remarks

This function prevents the specified interval variable from overlapping with segments of the step function where the value is zero. That is, if \([s, e)\) is a segment of the step function where the value is zero, then the interval variable either ends before \(s\) (\(\mathtt{interval.end()} \le s\)) or starts after \(e\) (\(e \le \mathtt{interval.start()}\)).

@example A production task that cannot overlap with scheduled maintenance windows:

var model = new Model();
var production = model.IntervalVar(length: 3, name: "production");
var availability = model.StepFunction(new[] {
    (0, 1), (8, 0), (10, 1),
});
model.ForbidExtent(production, availability);
model.Minimize(production.End());
var result = model.Solve();

See also:

ForbidStart(IntervalVar, IntStepFunction)

Constrains the start of the interval variable to be outside of the zero-height segments of the step function.

public Constraint ForbidStart(IntervalVar interval, IntStepFunction func)

Parameters

interval IntervalVar

The interval variable.

func IntStepFunction

The step function.

Returns

Constraint

The constraint forbidding the start point.

Remarks

This function is equivalent to:

I.e., the function value at the start of the interval variable cannot be zero.

@example A factory task that can only start during work hours (excluding breaks):

var model = new Model();

// A 2-hour task on a machine
var task = model.IntervalVar(length: 2, name: "task");

// Allowed start times: 1 = allowed, 0 = forbidden
var allowedStarts = model.StepFunction(new[] {
    (0, 0),   // Before 6h: forbidden
    (6, 1),   // 6h: shift starts, allowed
    (10, 0),  // 10h: break, forbidden
    (11, 1),  // 11h: break ends, allowed
    (14, 0),  // 14h: shift ends, forbidden
});

// Task cannot start when allowedStarts is 0
model.ForbidStart(task, allowedStarts);
model.Minimize(task.Start());

var result = model.Solve();

See also:

FromJSON(string)

Creates a model from JSON format.

public static (Model Model, Parameters? Parameters, Solution? WarmStart) FromJSON(string jsonStr)

Parameters

jsonStr string

A string containing the model in JSON format

Returns

(Model Model, Parameters Parameters, Solution WarmStart)

A tuple containing the model, optional parameters, and optional warm start solution.

Remarks

Creates a new Model instance from a JSON string that was previously exported using Model.ToJSON.

The method returns a tuple with three elements:

  1. The reconstructed Model
  2. Parameters (if they were included in the JSON), or None
  3. Warm start Solution (if it was included in the JSON), or None

Variables in the new model can be accessed using methods like Model.GetIntervalVars, Model.GetIntVars, etc.

// Create and export a model
var model = new Model();
var x = model.IntervalVar(length: 10, name: "task_x");
model.Minimize(x.End());

var parameters = new Parameters { timeLimit = 60 };
var jsonStr = model.ToJSON(parameters);

// Save to file
File.WriteAllText("model.json", jsonStr);

// Later, load from file
var loadedJson = File.ReadAllText("model.json");

// Restore model, parameters, and warm start
var (model2, params2, warmStart2) = Model.FromJSON(loadedJson);

// Access variables
var intervalVars = model2.GetIntervalVars();
Console.WriteLine($"Loaded model with {intervalVars.Count} interval variables");

// Solve with restored parameters
var result = model2.Solve(params2);

See also:

GetBoolVars()

Returns a list of all boolean variables in the model.

public IReadOnlyList<BoolVar> GetBoolVars()

Returns

IReadOnlyList<BoolVar>

A list of all boolean variables in the model

Remarks

Returns a copy of the list containing all boolean variables that have been created in this model using Model.BoolVar.

Example:

var model = new Model();
var useMachineA = model.BoolVar(name: "use_machine_a");
var useMachineB = model.BoolVar(name: "use_machine_b");

var boolVars = model.GetBoolVars(); Console.WriteLine(boolVars.Count); // 2 foreach (var bv in boolVars) Console.WriteLine(bv.Name); // "use_machine_a", "use_machine_b"

See also:

GetIntVars()

Returns a list of all integer variables in the model.

public IReadOnlyList<IntVar> GetIntVars()

Returns

IReadOnlyList<IntVar>

A list of all integer variables in the model

Remarks

Returns a copy of the list containing all integer variables that have been created in this model using Model.IntVar.

Example:

var model = new Model();
var x = model.IntVar(min: 0, max: 10, name: "x");
var y = model.IntVar(min: 0, max: 100, name: "y");

var intVars = model.GetIntVars(); Console.WriteLine(intVars.Count); // 2 foreach (var iv in intVars) Console.WriteLine(iv.Name); // "x", "y"

See also:

GetIntervalVars()

Returns a list of all interval variables in the model.

public IReadOnlyList<IntervalVar> GetIntervalVars()

Returns

IReadOnlyList<IntervalVar>

A list of all interval variables in the model

Remarks

Returns a copy of the list containing all interval variables that have been created in this model using Model.IntervalVar.

Example:

var model = new Model();
var task1 = model.IntervalVar(length: 10, name: "task1");
var task2 = model.IntervalVar(length: 20, name: "task2");

var intervals = model.GetIntervalVars(); Console.WriteLine(intervals.Count); // 2 foreach (var iv in intervals) Console.WriteLine(iv.Name); // "task1", "task2"

See also:

Guard(IntExpr, int)

Creates an expression that replaces value absent by a constant.

public IntExpr Guard(IntExpr arg, int absentValue = 0)

Parameters

arg IntExpr

The argument to guard (IntExpr or int).

absentValue int

The value to use when the expression is absent.

Returns

IntExpr

The resulting integer expression

Remarks

The resulting expression is:

  • equal to arg if arg is present
  • and equal to absentValue otherwise (i.e. when arg is absent).

The default value of absentValue is 0.

The resulting expression is never absent.

Same as IntExpr.Guard.

Guard(int, int)

Creates an expression that replaces value absent by a constant.

public IntExpr Guard(int arg, int absentValue = 0)

Parameters

arg int

The argument to guard (IntExpr or int).

absentValue int

The value to use when the expression is absent.

Returns

IntExpr

The resulting integer expression

Remarks

The resulting expression is:

  • equal to arg if arg is present
  • and equal to absentValue otherwise (i.e. when arg is absent).

The default value of absentValue is 0.

The resulting expression is never absent.

Same as IntExpr.Guard.

Identity(IntExpr, IntExpr)

Constrains lhs and rhs to be identical, including their presence status.

public Constraint Identity(IntExpr lhs, IntExpr rhs)

Parameters

lhs IntExpr

The left-hand side operand (IntExpr or int).

rhs IntExpr

The right-hand side operand (IntExpr or int).

Returns

Constraint

The identity constraint.

Remarks

Identity is different than equality. For example, if x is absent, then eq(x, 0) is absent, but identity(x, 0) is false.

Same as IntExpr.Identity.

Identity(IntExpr, int)

Constrains lhs and rhs to be identical, including their presence status.

public Constraint Identity(IntExpr lhs, int rhs)

Parameters

lhs IntExpr

The left-hand side operand (IntExpr or int).

rhs int

The right-hand side operand (IntExpr or int).

Returns

Constraint

The identity constraint.

Remarks

Identity is different than equality. For example, if x is absent, then eq(x, 0) is absent, but identity(x, 0) is false.

Same as IntExpr.Identity.

Identity(int, IntExpr)

Constrains lhs and rhs to be identical, including their presence status.

public Constraint Identity(int lhs, IntExpr rhs)

Parameters

lhs int

The left-hand side operand (IntExpr or int).

rhs IntExpr

The right-hand side operand (IntExpr or int).

Returns

Constraint

The identity constraint.

Remarks

Identity is different than equality. For example, if x is absent, then eq(x, 0) is absent, but identity(x, 0) is false.

Same as IntExpr.Identity.

Implies(BoolExpr, BoolExpr)

Logical implication of two boolean expressions, that is lhs implies rhs.

public BoolExpr Implies(BoolExpr lhs, BoolExpr rhs)

Parameters

lhs BoolExpr

The left-hand side operand (BoolExpr or bool).

rhs BoolExpr

The right-hand side operand (BoolExpr or bool).

Returns

BoolExpr

The resulting Boolean expression

Remarks

If one of the arguments has value absent, then the resulting expression also has value absent.

Same as BoolExpr.Implies.

Implies(BoolExpr, bool)

Logical implication of two boolean expressions, that is lhs implies rhs.

public BoolExpr Implies(BoolExpr lhs, bool rhs)

Parameters

lhs BoolExpr

The left-hand side operand (BoolExpr or bool).

rhs bool

The right-hand side operand (BoolExpr or bool).

Returns

BoolExpr

The resulting Boolean expression

Remarks

If one of the arguments has value absent, then the resulting expression also has value absent.

Same as BoolExpr.Implies.

Implies(bool, BoolExpr)

Logical implication of two boolean expressions, that is lhs implies rhs.

public BoolExpr Implies(bool lhs, BoolExpr rhs)

Parameters

lhs bool

The left-hand side operand (BoolExpr or bool).

rhs BoolExpr

The right-hand side operand (BoolExpr or bool).

Returns

BoolExpr

The resulting Boolean expression

Remarks

If one of the arguments has value absent, then the resulting expression also has value absent.

Same as BoolExpr.Implies.

InRange(IntExpr, int, int)

Creates Boolean expression lb &le; arg &le; ub.

public BoolExpr InRange(IntExpr arg, int lb, int ub)

Parameters

arg IntExpr

The argument to check (IntExpr or int).

lb int

The lower bound of the range.

ub int

The upper bound of the range.

Returns

BoolExpr

The resulting Boolean expression

Remarks

If arg has value absent then the resulting expression has also value absent.

Use Model.Enforce to add this expression as a constraint to the model.

Same as IntExpr.InRange.

InRange(int, int, int)

Creates Boolean expression lb &le; arg &le; ub.

public BoolExpr InRange(int arg, int lb, int ub)

Parameters

arg int

The argument to check (IntExpr or int).

lb int

The lower bound of the range.

ub int

The upper bound of the range.

Returns

BoolExpr

The resulting Boolean expression

Remarks

If arg has value absent then the resulting expression has also value absent.

Use Model.Enforce to add this expression as a constraint to the model.

Same as IntExpr.InRange.

IntVar(int?, int?, bool, string?)

Creates a new integer variable and adds it to the model.

public IntVar IntVar(int? min = null, int? max = null, bool optional = false, string? name = null)

Parameters

min int?

Minimum value for the variable. Default is 0.

max int?

Maximum value for the variable. Default is Model.IntVarMax.

optional bool

If true, the variable can be absent in a solution. The default is false.

name string

Optional name for debugging purposes.

Returns

IntVar

The created integer variable.

Remarks

An integer variable represents an unknown value the solver must find. The variable can be optional. In this case, its value in a solution could be absent, meaning that the solution does not use the variable at all.

The default domain is 0 to Model.IntVarMax. If min or max is not specified (or null), the default value is used.

Example:

var model = new Model();

// Create an integer variable with possible values 1..10: var x = model.IntVar(min: 1, max: 10, name: "x");

// Create an optional integer variable with possible values 5..Model.IntVarMax: var y = model.IntVar(min: 5, optional: true, name: "y");

// Create a non-negative integer variable: var z = model.IntVar(max: 100, name: "z");

Integral(IntStepFunction, IntervalVar)

Computes sum of values of the step function func over the interval interval.

public IntExpr Integral(IntStepFunction func, IntervalVar interval)

Parameters

func IntStepFunction

The step function.

interval IntervalVar

The interval variable.

Returns

IntExpr

The resulting integer expression

Remarks

The sum is computed over all points in range interval.start() .. interval.end()-1. The sum includes the function value at the start time but not the value at the end time. If the interval variable has zero length, then the result is 0. If the interval variable is absent, then the result is absent.

Requirement: The step function func must be non-negative.

See also:

IntervalVar(IntBound?, IntBound?, IntBound?, bool, string?)

Creates a new interval variable and adds it to the model.

public IntervalVar IntervalVar(IntBound? start = null, IntBound? end = null, IntBound? length = null, bool optional = false, string? name = null)

Parameters

start IntBound?

Fixed start time or range [min, max]. Pass an int for a fixed value, a tuple (min, max) for a range, or null for the default range [0, Model.IntervalMax].

end IntBound?

Fixed end time or range [min, max]. Pass an int for a fixed value, a tuple (min, max) for a range, or null for the default range [0, Model.IntervalMax].

length IntBound?

Fixed length or range [min, max]. Pass an int for a fixed value, a tuple (min, max) for a range, or null for the default range [0, Model.IntervalMax].

optional bool

If true, the interval can be absent in a solution. The default is false.

name string

Optional name for debugging purposes.

Returns

IntervalVar

The created interval variable.

Remarks

An interval variable represents an unknown interval (a task, operation, action) that the solver assigns a value in such a way as to satisfy all constraints. An interval variable has a start, end, and length. In a solution, start <= end and length = end - start.

The interval variable can be optional. In this case, its value in a solution could be absent, meaning that the task/operation is not performed.

Parameters start, end, and length accept an IntBound, which can be:

  • An int for a fixed value
  • A tuple (int min, int max) for a range (use null for either bound to keep the default)

The default range for start, end and length is 0 to Model.IntervalMax.

Example:

var model = new Model();

// Create an interval variable with a fixed start but unknown length: var x = model.IntervalVar(start: 0, length: (10, 20), name: "x");

// Create an interval variable with start and end ranges: var y = model.IntervalVar(start: (0, 5), end: (10, 15), name: "y");

// Create an optional interval variable with length range 5..10: var z = model.IntervalVar(length: (5, 10), optional: true, name: "z");

// Set only startMax (startMin remains the default 0): var w = model.IntervalVar(start: (null, 100), name: "w");

See also:

Length(IntervalVar)

Creates an integer expression for the duration (end - start) of an interval variable.

public IntExpr Length(IntervalVar interval)

Parameters

interval IntervalVar

The interval variable.

Returns

IntExpr

The resulting integer expression

Remarks

If the interval is absent, the resulting expression is also absent.

Example:

In the following example, we constrain interval variable y to start after the end of x with a delay of at least 10. In addition, we constrain the length of x to be less or equal to the length of y.
var model = new Model();
var x = model.IntervalVar(name: "x");
var y = model.IntervalVar(name: "y");
model.Enforce(model.End(x) + 10 <= model.Start(y));
model.Enforce(model.Length(x) <= model.Length(y));

When x or y is absent then value of both constraints above is absent and therefore they are satisfied.

See also:

LexGe(IEnumerable<IntExpr>, IEnumerable<IntExpr>)

Lexicographic greater than or equal constraint: lhsrhs.

public Constraint LexGe(IEnumerable<IntExpr> lhs, IEnumerable<IntExpr> rhs)

Parameters

lhs IEnumerable<IntExpr>

The left-hand side array of integer expressions.

rhs IEnumerable<IntExpr>

The right-hand side array of integer expressions.

Returns

Constraint

The lexicographic constraint.

Remarks

Constrains lhs to be lexicographically greater than or equal rhs.

Both arrays must have the same length, and the length must be at least 1.

Lexicographic ordering compares arrays element by element from the first position. The comparison lhsrhs holds if and only if:

  • all elements are equal (lhs[i] == rhs[i] for all i), or
  • there exists a position k where lhs[k] > rhs[k] and all preceding elements are equal (lhs[i] == rhs[i] for all i < k)

Lexicographic constraints are useful for symmetry breaking. For example, when you have multiple equivalent solutions that differ only in the ordering of symmetric variables, adding a lexicographic constraint can eliminate redundant solutions.

Example:

var model = new Model();

// Variables for a 3x3 matrix where rows should be lexicographically ordered var rows = Enumerable.Range(0, 3).Select(i => Enumerable.Range(0, 3).Select(j => model.IntVar(min: 0, max: 9, name: $"x_{i}_{j}")).ToArray() ).ToArray();

// Break row symmetry: row[0] ≥ row[1] ≥ row[2] lexicographically model.LexGe(rows[0], rows[1]); model.LexGe(rows[1], rows[2]);

See also:

LexGe(IEnumerable<object>, IEnumerable<object>)

Lexicographic greater than or equal constraint: lhsrhs.

public Constraint LexGe(IEnumerable<object> lhs, IEnumerable<object> rhs)

Parameters

lhs IEnumerable<object>

The left-hand side array of integer expressions.

rhs IEnumerable<object>

The right-hand side array of integer expressions.

Returns

Constraint

The lexicographic constraint.

Remarks

Constrains lhs to be lexicographically greater than or equal rhs.

Both arrays must have the same length, and the length must be at least 1.

Lexicographic ordering compares arrays element by element from the first position. The comparison lhsrhs holds if and only if:

  • all elements are equal (lhs[i] == rhs[i] for all i), or
  • there exists a position k where lhs[k] > rhs[k] and all preceding elements are equal (lhs[i] == rhs[i] for all i < k)

Lexicographic constraints are useful for symmetry breaking. For example, when you have multiple equivalent solutions that differ only in the ordering of symmetric variables, adding a lexicographic constraint can eliminate redundant solutions.

Example:

var model = new Model();

// Variables for a 3x3 matrix where rows should be lexicographically ordered var rows = Enumerable.Range(0, 3).Select(i => Enumerable.Range(0, 3).Select(j => model.IntVar(min: 0, max: 9, name: $"x_{i}_{j}")).ToArray() ).ToArray();

// Break row symmetry: row[0] ≥ row[1] ≥ row[2] lexicographically model.LexGe(rows[0], rows[1]); model.LexGe(rows[1], rows[2]);

See also:

LexGt(IEnumerable<IntExpr>, IEnumerable<IntExpr>)

Lexicographic strictly greater than constraint: lhs > rhs.

public Constraint LexGt(IEnumerable<IntExpr> lhs, IEnumerable<IntExpr> rhs)

Parameters

lhs IEnumerable<IntExpr>

The left-hand side array of integer expressions.

rhs IEnumerable<IntExpr>

The right-hand side array of integer expressions.

Returns

Constraint

The lexicographic constraint.

Remarks

Constrains lhs to be lexicographically strictly greater than rhs.

Both arrays must have the same length, and the length must be at least 1.

Lexicographic ordering compares arrays element by element from the first position. The comparison lhs > rhs holds if and only if: there exists a position k where lhs[k] > rhs[k] and all preceding elements are equal (lhs[i] == rhs[i] for all i < k)

Lexicographic constraints are useful for symmetry breaking. For example, when you have multiple equivalent solutions that differ only in the ordering of symmetric variables, adding a lexicographic constraint can eliminate redundant solutions.

Example:

var model = new Model();

// Variables for a 3x3 matrix where rows should be lexicographically ordered var rows = Enumerable.Range(0, 3).Select(i => Enumerable.Range(0, 3).Select(j => model.IntVar(min: 0, max: 9, name: $"x_{i}_{j}")).ToArray() ).ToArray();

// Break row symmetry: row[0] > row[1] > row[2] lexicographically model.LexGt(rows[0], rows[1]); model.LexGt(rows[1], rows[2]);

See also:

LexGt(IEnumerable<object>, IEnumerable<object>)

Lexicographic strictly greater than constraint: lhs > rhs.

public Constraint LexGt(IEnumerable<object> lhs, IEnumerable<object> rhs)

Parameters

lhs IEnumerable<object>

The left-hand side array of integer expressions.

rhs IEnumerable<object>

The right-hand side array of integer expressions.

Returns

Constraint

The lexicographic constraint.

Remarks

Constrains lhs to be lexicographically strictly greater than rhs.

Both arrays must have the same length, and the length must be at least 1.

Lexicographic ordering compares arrays element by element from the first position. The comparison lhs > rhs holds if and only if: there exists a position k where lhs[k] > rhs[k] and all preceding elements are equal (lhs[i] == rhs[i] for all i < k)

Lexicographic constraints are useful for symmetry breaking. For example, when you have multiple equivalent solutions that differ only in the ordering of symmetric variables, adding a lexicographic constraint can eliminate redundant solutions.

Example:

var model = new Model();

// Variables for a 3x3 matrix where rows should be lexicographically ordered var rows = Enumerable.Range(0, 3).Select(i => Enumerable.Range(0, 3).Select(j => model.IntVar(min: 0, max: 9, name: $"x_{i}_{j}")).ToArray() ).ToArray();

// Break row symmetry: row[0] > row[1] > row[2] lexicographically model.LexGt(rows[0], rows[1]); model.LexGt(rows[1], rows[2]);

See also:

LexLe(IEnumerable<IntExpr>, IEnumerable<IntExpr>)

Lexicographic less than or equal constraint: lhsrhs.

public Constraint LexLe(IEnumerable<IntExpr> lhs, IEnumerable<IntExpr> rhs)

Parameters

lhs IEnumerable<IntExpr>

The left-hand side array of integer expressions.

rhs IEnumerable<IntExpr>

The right-hand side array of integer expressions.

Returns

Constraint

The lexicographic constraint.

Remarks

Constrains lhs to be lexicographically less than or equal rhs.

Both arrays must have the same length, and the length must be at least 1.

Lexicographic ordering compares arrays element by element from the first position. The comparison lhsrhs holds if and only if:

  • all elements are equal (lhs[i] == rhs[i] for all i), or
  • there exists a position k where lhs[k] < rhs[k] and all preceding elements are equal (lhs[i] == rhs[i] for all i < k)

Lexicographic constraints are useful for symmetry breaking. For example, when you have multiple equivalent solutions that differ only in the ordering of symmetric variables, adding a lexicographic constraint can eliminate redundant solutions.

Example:

var model = new Model();

// Variables for a 3x3 matrix where rows should be lexicographically ordered var rows = Enumerable.Range(0, 3).Select(i => Enumerable.Range(0, 3).Select(j => model.IntVar(min: 0, max: 9, name: $"x_{i}_{j}")).ToArray() ).ToArray();

// Break row symmetry: row[0] ≤ row[1] ≤ row[2] lexicographically model.LexLe(rows[0], rows[1]); model.LexLe(rows[1], rows[2]);

See also:

LexLe(IEnumerable<object>, IEnumerable<object>)

Lexicographic less than or equal constraint: lhsrhs.

public Constraint LexLe(IEnumerable<object> lhs, IEnumerable<object> rhs)

Parameters

lhs IEnumerable<object>

The left-hand side array of integer expressions.

rhs IEnumerable<object>

The right-hand side array of integer expressions.

Returns

Constraint

The lexicographic constraint.

Remarks

Constrains lhs to be lexicographically less than or equal rhs.

Both arrays must have the same length, and the length must be at least 1.

Lexicographic ordering compares arrays element by element from the first position. The comparison lhsrhs holds if and only if:

  • all elements are equal (lhs[i] == rhs[i] for all i), or
  • there exists a position k where lhs[k] < rhs[k] and all preceding elements are equal (lhs[i] == rhs[i] for all i < k)

Lexicographic constraints are useful for symmetry breaking. For example, when you have multiple equivalent solutions that differ only in the ordering of symmetric variables, adding a lexicographic constraint can eliminate redundant solutions.

Example:

var model = new Model();

// Variables for a 3x3 matrix where rows should be lexicographically ordered var rows = Enumerable.Range(0, 3).Select(i => Enumerable.Range(0, 3).Select(j => model.IntVar(min: 0, max: 9, name: $"x_{i}_{j}")).ToArray() ).ToArray();

// Break row symmetry: row[0] ≤ row[1] ≤ row[2] lexicographically model.LexLe(rows[0], rows[1]); model.LexLe(rows[1], rows[2]);

See also:

LexLt(IEnumerable<IntExpr>, IEnumerable<IntExpr>)

Lexicographic strictly less than constraint: lhs < rhs.

public Constraint LexLt(IEnumerable<IntExpr> lhs, IEnumerable<IntExpr> rhs)

Parameters

lhs IEnumerable<IntExpr>

The left-hand side array of integer expressions.

rhs IEnumerable<IntExpr>

The right-hand side array of integer expressions.

Returns

Constraint

The lexicographic constraint.

Remarks

Constrains lhs to be lexicographically strictly less than rhs.

Both arrays must have the same length, and the length must be at least 1.

Lexicographic ordering compares arrays element by element from the first position. The comparison lhs < rhs holds if and only if: there exists a position k where lhs[k] < rhs[k] and all preceding elements are equal (lhs[i] == rhs[i] for all i < k)

Lexicographic constraints are useful for symmetry breaking. For example, when you have multiple equivalent solutions that differ only in the ordering of symmetric variables, adding a lexicographic constraint can eliminate redundant solutions.

Example:

var model = new Model();

// Variables for a 3x3 matrix where rows should be lexicographically ordered var rows = Enumerable.Range(0, 3).Select(i => Enumerable.Range(0, 3).Select(j => model.IntVar(min: 0, max: 9, name: $"x_{i}_{j}")).ToArray() ).ToArray();

// Break row symmetry: row[0] < row[1] < row[2] lexicographically model.LexLt(rows[0], rows[1]); model.LexLt(rows[1], rows[2]);

See also:

LexLt(IEnumerable<object>, IEnumerable<object>)

Lexicographic strictly less than constraint: lhs < rhs.

public Constraint LexLt(IEnumerable<object> lhs, IEnumerable<object> rhs)

Parameters

lhs IEnumerable<object>

The left-hand side array of integer expressions.

rhs IEnumerable<object>

The right-hand side array of integer expressions.

Returns

Constraint

The lexicographic constraint.

Remarks

Constrains lhs to be lexicographically strictly less than rhs.

Both arrays must have the same length, and the length must be at least 1.

Lexicographic ordering compares arrays element by element from the first position. The comparison lhs < rhs holds if and only if: there exists a position k where lhs[k] < rhs[k] and all preceding elements are equal (lhs[i] == rhs[i] for all i < k)

Lexicographic constraints are useful for symmetry breaking. For example, when you have multiple equivalent solutions that differ only in the ordering of symmetric variables, adding a lexicographic constraint can eliminate redundant solutions.

Example:

var model = new Model();

// Variables for a 3x3 matrix where rows should be lexicographically ordered var rows = Enumerable.Range(0, 3).Select(i => Enumerable.Range(0, 3).Select(j => model.IntVar(min: 0, max: 9, name: $"x_{i}_{j}")).ToArray() ).ToArray();

// Break row symmetry: row[0] < row[1] < row[2] lexicographically model.LexLt(rows[0], rows[1]); model.LexLt(rows[1], rows[2]);

See also:

Max(IEnumerable<IntExpr>)

Creates an integer expression for the maximum of the arguments.

public IntExpr Max(IEnumerable<IntExpr> args)

Parameters

args IEnumerable<IntExpr>

Array of integer expressions to compute maximum of.

Returns

IntExpr

The resulting integer expression

Remarks

Absent arguments are ignored as if they were not specified in the input array args. Maximum of an empty set (i.e. max([]) is absent. The maximum is absent also if all arguments are absent.

Note that binary function Model.Max2 handles absent values differently. For example, when x is absent then:

  • max2(x, 5) is absent.
  • max([x, 5]) is 5.
  • max([x]) is absent.

Example:

A common use case is to compute _makespan_ of a set of tasks, i.e. the time when the last task finishes. In the following example, we minimize the makespan of a set of tasks (other parts of the model are omitted).
var model = new Model();
var tasks = Enumerable.Range(0, 5)
    .Select(i => model.IntervalVar(length: 10, name: $"task_{i}")).ToArray();
// Create an array of end times of the tasks:
var endTimes = tasks.Select(t => t.End());
var makespan = model.Max(endTimes);
model.Minimize(makespan);

Notice that when a task is absent (not executed), then its end time is absent. And therefore, the absent task is not included in the maximum.

See also:

  • Model.Max2
  • Model.Span — constraints interval variable to start and end at minimum and maximum of the given set of intervals.

Max(IEnumerable<object>)

Creates an integer expression for the maximum of the arguments.

public IntExpr Max(IEnumerable<object> args)

Parameters

args IEnumerable<object>

Array of integer expressions to compute maximum of.

Returns

IntExpr

The resulting integer expression

Remarks

Absent arguments are ignored as if they were not specified in the input array args. Maximum of an empty set (i.e. max([]) is absent. The maximum is absent also if all arguments are absent.

Note that binary function Model.Max2 handles absent values differently. For example, when x is absent then:

  • max2(x, 5) is absent.
  • max([x, 5]) is 5.
  • max([x]) is absent.

Example:

A common use case is to compute _makespan_ of a set of tasks, i.e. the time when the last task finishes. In the following example, we minimize the makespan of a set of tasks (other parts of the model are omitted).
var model = new Model();
var tasks = Enumerable.Range(0, 5)
    .Select(i => model.IntervalVar(length: 10, name: $"task_{i}")).ToArray();
// Create an array of end times of the tasks:
var endTimes = tasks.Select(t => t.End());
var makespan = model.Max(endTimes);
model.Minimize(makespan);

Notice that when a task is absent (not executed), then its end time is absent. And therefore, the absent task is not included in the maximum.

See also:

  • Model.Max2
  • Model.Span — constraints interval variable to start and end at minimum and maximum of the given set of intervals.

Max2(IntExpr, IntExpr)

Creates an integer expression which is the maximum of lhs and rhs.

public IntExpr Max2(IntExpr lhs, IntExpr rhs)

Parameters

lhs IntExpr

The left-hand side operand (IntExpr or int).

rhs IntExpr

The right-hand side operand (IntExpr or int).

Returns

IntExpr

The resulting integer expression

Remarks

If one of the arguments has value absent, then the resulting expression also has value absent.

Same as IntExpr.Max2. See Model.Max for n-ary maximum.

Max2(IntExpr, int)

Creates an integer expression which is the maximum of lhs and rhs.

public IntExpr Max2(IntExpr lhs, int rhs)

Parameters

lhs IntExpr

The left-hand side operand (IntExpr or int).

rhs int

The right-hand side operand (IntExpr or int).

Returns

IntExpr

The resulting integer expression

Remarks

If one of the arguments has value absent, then the resulting expression also has value absent.

Same as IntExpr.Max2. See Model.Max for n-ary maximum.

Max2(int, IntExpr)

Creates an integer expression which is the maximum of lhs and rhs.

public IntExpr Max2(int lhs, IntExpr rhs)

Parameters

lhs int

The left-hand side operand (IntExpr or int).

rhs IntExpr

The right-hand side operand (IntExpr or int).

Returns

IntExpr

The resulting integer expression

Remarks

If one of the arguments has value absent, then the resulting expression also has value absent.

Same as IntExpr.Max2. See Model.Max for n-ary maximum.

Maximize(IntExpr)

Creates a maximization objective for the provided expression.

public Objective Maximize(IntExpr expr)

Parameters

expr IntExpr

The expression to maximize

Returns

Objective

An Objective that maximizes the expression.

Remarks

Creates an Objective to maximize the given expression. A model can have at most one objective. New objective replaces the old one.

Equivalent of function IntExpr.Maximize.

Example:

In the following model, we search for a solution that maximizes the length of the interval variable x:
var model = new Model();
var x = model.IntervalVar(length: (10, 20), name: "x");
model.Maximize(x.Length());
var result = model.Solve();

See also:

Maximize(int)

Creates a maximization objective for the provided expression.

public Objective Maximize(int value)

Parameters

value int

Returns

Objective

An Objective that maximizes the expression.

Remarks

Creates an Objective to maximize the given expression. A model can have at most one objective. New objective replaces the old one.

Equivalent of function IntExpr.Maximize.

Example:

In the following model, we search for a solution that maximizes the length of the interval variable x:
var model = new Model();
var x = model.IntervalVar(length: (10, 20), name: "x");
model.Maximize(x.Length());
var result = model.Solve();

See also:

Min(IEnumerable<IntExpr>)

Creates an integer expression for the minimum of the arguments.

public IntExpr Min(IEnumerable<IntExpr> args)

Parameters

args IEnumerable<IntExpr>

Array of integer expressions to compute minimum of.

Returns

IntExpr

The resulting integer expression

Remarks

Absent arguments are ignored as if they were not specified in the input array args. Minimum of an empty set (i.e. min([])) is absent. The minimum is absent also if all arguments are absent.

Note that binary function Model.Min2 handles absent values differently. For example, when x is absent then:

  • min2(x, 5) is absent.
  • min([x, 5]) is 5.
  • min([x]) is absent.

Example:

In the following example, we compute the time when the first task of tasks starts, i.e. the minimum of the starting times.
var model = new Model();
var tasks = Enumerable.Range(0, 5)
    .Select(i => model.IntervalVar(length: 10, name: $"task_{i}")).ToArray();
// Create an array of start times of the tasks:
var startTimes = tasks.Select(t => t.Start());
var firstStartTime = model.Min(startTimes);

Notice that when a task is absent (not executed), its end time is absent. And therefore, the absent task is not included in the minimum.

See also:

  • Model.Min2
  • Model.Span — constraints interval variable to start and end at minimum and maximum of the given set of intervals.

Min(IEnumerable<object>)

Creates an integer expression for the minimum of the arguments.

public IntExpr Min(IEnumerable<object> args)

Parameters

args IEnumerable<object>

Array of integer expressions to compute minimum of.

Returns

IntExpr

The resulting integer expression

Remarks

Absent arguments are ignored as if they were not specified in the input array args. Minimum of an empty set (i.e. min([])) is absent. The minimum is absent also if all arguments are absent.

Note that binary function Model.Min2 handles absent values differently. For example, when x is absent then:

  • min2(x, 5) is absent.
  • min([x, 5]) is 5.
  • min([x]) is absent.

Example:

In the following example, we compute the time when the first task of tasks starts, i.e. the minimum of the starting times.
var model = new Model();
var tasks = Enumerable.Range(0, 5)
    .Select(i => model.IntervalVar(length: 10, name: $"task_{i}")).ToArray();
// Create an array of start times of the tasks:
var startTimes = tasks.Select(t => t.Start());
var firstStartTime = model.Min(startTimes);

Notice that when a task is absent (not executed), its end time is absent. And therefore, the absent task is not included in the minimum.

See also:

  • Model.Min2
  • Model.Span — constraints interval variable to start and end at minimum and maximum of the given set of intervals.

Min2(IntExpr, IntExpr)

Creates an integer expression which is the minimum of lhs and rhs.

public IntExpr Min2(IntExpr lhs, IntExpr rhs)

Parameters

lhs IntExpr

The left-hand side operand (IntExpr or int).

rhs IntExpr

The right-hand side operand (IntExpr or int).

Returns

IntExpr

The resulting integer expression

Remarks

If one of the arguments has value absent, then the resulting expression also has value absent.

Same as IntExpr.Min2. See Model.Min for n-ary minimum.

Min2(IntExpr, int)

Creates an integer expression which is the minimum of lhs and rhs.

public IntExpr Min2(IntExpr lhs, int rhs)

Parameters

lhs IntExpr

The left-hand side operand (IntExpr or int).

rhs int

The right-hand side operand (IntExpr or int).

Returns

IntExpr

The resulting integer expression

Remarks

If one of the arguments has value absent, then the resulting expression also has value absent.

Same as IntExpr.Min2. See Model.Min for n-ary minimum.

Min2(int, IntExpr)

Creates an integer expression which is the minimum of lhs and rhs.

public IntExpr Min2(int lhs, IntExpr rhs)

Parameters

lhs int

The left-hand side operand (IntExpr or int).

rhs IntExpr

The right-hand side operand (IntExpr or int).

Returns

IntExpr

The resulting integer expression

Remarks

If one of the arguments has value absent, then the resulting expression also has value absent.

Same as IntExpr.Min2. See Model.Min for n-ary minimum.

Minimize(IntExpr)

Creates a minimization objective for the provided expression.

public Objective Minimize(IntExpr expr)

Parameters

expr IntExpr

The expression to minimize

Returns

Objective

An Objective that minimizes the expression.

Remarks

Creates an Objective to minimize the given expression. A model can have at most one objective. New objective replaces the old one.

Equivalent of function IntExpr.Minimize.

Example:

In the following model, we search for a solution that minimizes the maximum end of the two intervals x and y:
var model = new Model();
var x = model.IntervalVar(length: 10, name: "x");
var y = model.IntervalVar(length: 20, name: "y");
model.Minimize(model.Max2(x.End(), y.End()));
var result = model.Solve();

See also:

Minimize(int)

Creates a minimization objective for the provided expression.

public Objective Minimize(int value)

Parameters

value int

Returns

Objective

An Objective that minimizes the expression.

Remarks

Creates an Objective to minimize the given expression. A model can have at most one objective. New objective replaces the old one.

Equivalent of function IntExpr.Minimize.

Example:

In the following model, we search for a solution that minimizes the maximum end of the two intervals x and y:
var model = new Model();
var x = model.IntervalVar(length: 10, name: "x");
var y = model.IntervalVar(length: 20, name: "y");
model.Minimize(model.Max2(x.End(), y.End()));
var result = model.Solve();

See also:

NoOverlap(SequenceVar, IEnumerable<IEnumerable<int>>?)

Constrain a set of interval variables not to overlap.

public Constraint NoOverlap(SequenceVar sequence, IEnumerable<IEnumerable<int>>? transitions = null)

Parameters

sequence SequenceVar
transitions IEnumerable<IEnumerable<int>>

A 2D square array of minimum transition times between the intervals

Returns

Constraint

The no-overlap constraint.

Remarks

This function constrains a set of interval variables so they do not overlap. That is, for each pair of interval variables x and y, one of the following must hold:

  1. Interval variable x or y is absent. In this case, the absent interval is not scheduled (the task is not performed), so it cannot overlap with any other interval. Only optional interval variables can be absent.
  2. Interval variable x is before y, that is, x.end() is less than or equal to y.start().
  3. The interval variable y is before x. That is, y.end() is less than or equal to x.start().

The function can also take a square array transitions of minimum transition times between the intervals. The transition time is the time that must elapse between the end of the first interval and the start of the second interval. The transition time cannot be negative. When transition times are specified, the above conditions 2 and 3 are modified as follows:

  1. x.end() + transitions[i][j] is less than or equal to y.start().
  2. y.end() + transitions[j][i] is less than or equal to x.start().

Where i and j are types of x and y. When an array of intervals is passed, the type of each interval is its index in the array.

Note that minimum transition times are enforced between all pairs of intervals, not only between direct neighbors.

Instead of an array of interval variables, a SequenceVar can be passed. See Model.SequenceVar for how to assign types to intervals in a sequence.

Example:

The following example does not use transition times. For example with transition times see SequenceVar.NoOverlap.

Let's consider a set of tasks that must be performed by a single machine. The machine can handle only one task at a time. Each task is characterized by its length and a deadline. The goal is to schedule the tasks on the machine so that the number of missed deadlines is minimized.

var tasks = new[] {
    new { length = 10, deadline = 70 },
    new { length = 20, deadline = 50 },
    new { length = 15, deadline = 50 },
    new { length = 30, deadline = 100 },
    new { length = 20, deadline = 120 },
    new { length = 25, deadline = 90 },
    new { length = 30, deadline = 80 },
    new { length = 10, deadline = 40 },
    new { length = 20, deadline = 60 },
    new { length = 25, deadline = 150 },
};

var model = new Model();

// An interval variable for each task:
var taskVars = new List<IntervalVar>();
// A boolean expression that is true if the task is late:
var isLate = new List<BoolExpr>();

for (int i = 0; i < tasks.Length; i++) {
    var taskVar = model.IntervalVar(name: $"Task{i}", length: tasks[i].length);
    taskVars.Add(taskVar);
    isLate.Add(taskVar.End() >= tasks[i].deadline);
}

// Tasks cannot overlap:
model.NoOverlap(taskVars);
// Minimize the number of late tasks:
model.Minimize(model.Sum(isLate));

var result = model.Solve();

See also:

NoOverlap(IEnumerable<IntervalVar>, IEnumerable<IEnumerable<int>>?)

Constrain a set of interval variables not to overlap.

public Constraint NoOverlap(IEnumerable<IntervalVar> intervals, IEnumerable<IEnumerable<int>>? transitions = null)

Parameters

intervals IEnumerable<IntervalVar>

An array of interval variables or a sequence variable to constrain

transitions IEnumerable<IEnumerable<int>>

A 2D square array of minimum transition times between the intervals

Returns

Constraint

The no-overlap constraint.

Remarks

This function constrains a set of interval variables so they do not overlap. That is, for each pair of interval variables x and y, one of the following must hold:

  1. Interval variable x or y is absent. In this case, the absent interval is not scheduled (the task is not performed), so it cannot overlap with any other interval. Only optional interval variables can be absent.
  2. Interval variable x is before y, that is, x.end() is less than or equal to y.start().
  3. The interval variable y is before x. That is, y.end() is less than or equal to x.start().

The function can also take a square array transitions of minimum transition times between the intervals. The transition time is the time that must elapse between the end of the first interval and the start of the second interval. The transition time cannot be negative. When transition times are specified, the above conditions 2 and 3 are modified as follows:

  1. x.end() + transitions[i][j] is less than or equal to y.start().
  2. y.end() + transitions[j][i] is less than or equal to x.start().

Where i and j are types of x and y. When an array of intervals is passed, the type of each interval is its index in the array.

Note that minimum transition times are enforced between all pairs of intervals, not only between direct neighbors.

Instead of an array of interval variables, a SequenceVar can be passed. See Model.SequenceVar for how to assign types to intervals in a sequence.

Example:

The following example does not use transition times. For example with transition times see SequenceVar.NoOverlap.

Let's consider a set of tasks that must be performed by a single machine. The machine can handle only one task at a time. Each task is characterized by its length and a deadline. The goal is to schedule the tasks on the machine so that the number of missed deadlines is minimized.

var tasks = new[] {
    new { length = 10, deadline = 70 },
    new { length = 20, deadline = 50 },
    new { length = 15, deadline = 50 },
    new { length = 30, deadline = 100 },
    new { length = 20, deadline = 120 },
    new { length = 25, deadline = 90 },
    new { length = 30, deadline = 80 },
    new { length = 10, deadline = 40 },
    new { length = 20, deadline = 60 },
    new { length = 25, deadline = 150 },
};

var model = new Model();

// An interval variable for each task:
var taskVars = new List<IntervalVar>();
// A boolean expression that is true if the task is late:
var isLate = new List<BoolExpr>();

for (int i = 0; i < tasks.Length; i++) {
    var taskVar = model.IntervalVar(name: $"Task{i}", length: tasks[i].length);
    taskVars.Add(taskVar);
    isLate.Add(taskVar.End() >= tasks[i].deadline);
}

// Tasks cannot overlap:
model.NoOverlap(taskVars);
// Minimize the number of late tasks:
model.Minimize(model.Sum(isLate));

var result = model.Solve();

See also:

Not(BoolExpr)

Negation of the boolean expression arg.

public BoolExpr Not(BoolExpr arg)

Parameters

arg BoolExpr

The argument to negate (BoolExpr or bool).

Returns

BoolExpr

The resulting Boolean expression

Remarks

If the argument has value absent then the resulting expression has also value absent.

Same as BoolExpr.Not.

Not(bool)

Negation of the boolean expression arg.

public BoolExpr Not(bool arg)

Parameters

arg bool

The argument to negate (BoolExpr or bool).

Returns

BoolExpr

The resulting Boolean expression

Remarks

If the argument has value absent then the resulting expression has also value absent.

Same as BoolExpr.Not.

Or(BoolExpr, BoolExpr)

Logical OR of boolean expressions lhs and rhs.

public BoolExpr Or(BoolExpr lhs, BoolExpr rhs)

Parameters

lhs BoolExpr

The left-hand side operand (BoolExpr or bool).

rhs BoolExpr

The right-hand side operand (BoolExpr or bool).

Returns

BoolExpr

The resulting Boolean expression

Remarks

If one of the arguments has value absent, then the resulting expression also has value absent.

Same as BoolExpr.Or.

Or(BoolExpr, bool)

Logical OR of boolean expressions lhs and rhs.

public BoolExpr Or(BoolExpr lhs, bool rhs)

Parameters

lhs BoolExpr

The left-hand side operand (BoolExpr or bool).

rhs bool

The right-hand side operand (BoolExpr or bool).

Returns

BoolExpr

The resulting Boolean expression

Remarks

If one of the arguments has value absent, then the resulting expression also has value absent.

Same as BoolExpr.Or.

Or(bool, BoolExpr)

Logical OR of boolean expressions lhs and rhs.

public BoolExpr Or(bool lhs, BoolExpr rhs)

Parameters

lhs bool

The left-hand side operand (BoolExpr or bool).

rhs BoolExpr

The right-hand side operand (BoolExpr or bool).

Returns

BoolExpr

The resulting Boolean expression

Remarks

If one of the arguments has value absent, then the resulting expression also has value absent.

Same as BoolExpr.Or.

Position(IntervalVar, SequenceVar)

Creates an expression equal to the position of the interval on the sequence.

public IntExpr Position(IntervalVar interval, SequenceVar sequence)

Parameters

interval IntervalVar

The interval variable.

sequence SequenceVar

The sequence variable.

Returns

IntExpr

The resulting integer expression

Remarks

In the solution, the interval which is scheduled first has position 0, the second interval has position 1, etc. The position of an absent interval is absent.

The position expression cannot be used with interval variables of possibly zero length (because the position of two simultaneous zero-length intervals would be undefined). Also, position cannot be used in case of Model.NoOverlap constraint with transition times.

See also:

Presence(IntExpr)

Creates a boolean expression that is true if the given argument is present in the solution.

public BoolExpr Presence(IntExpr expr)

Parameters

expr IntExpr

Returns

BoolExpr

A boolean expression that is true if the argument is present in the solution.

Remarks

The value of the expression remains unknown until a solution is found. The expression can be used in a constraint to restrict possible solutions.

The function is equivalent to IntervalVar.Presence and IntExpr.Presence.

Example:

In the following example, interval variables x and y must have the same presence status. I.e. they must either be both *present* or both *absent*.
var model = new Model();

var x = model.IntervalVar(name: "x", optional: true, length: 10, start: (0, 100));
var y = model.IntervalVar(name: "y", optional: true, length: 10, start: (0, 100));
model.Enforce(model.Presence(x) == model.Presence(y));

Simple constraints over presence

The solver treats binary constraints over presence in a special way: it uses them to better propagate other constraints over the same pairs of variables. Let's extend the previous example by a constraint that x must end before y starts:

var x = model.IntervalVar(name: "x", optional: true, length: 10, start: (0, 100));
var y = model.IntervalVar(name: "y", optional: true, length: 10, start: (0, 100));
model.Enforce(model.Presence(x) == model.Presence(y));
// x.end <= y.start:
var precedence = x.End() <= y.Start();
model.Enforce(precedence);

In this example, the solver sees (propagates) that the minimum start time of y is 10 and maximum end time of x is 90. Without the constraint over presence, the solver could not propagate that because one of the intervals can be absent and the other one present (and so the value of precedence would be absent and the constraint would be satisfied).

To achieve good propagation, it is recommended to use binary constraints over presence when possible. For example, multiple binary constraints can be used instead of a single complicated constraint.

Presence(IntervalVar)

Creates a boolean expression that is true if the given argument is present in the solution.

public BoolExpr Presence(IntervalVar arg)

Parameters

arg IntervalVar

The argument to check for presence in the solution

Returns

BoolExpr

A boolean expression that is true if the argument is present in the solution.

Remarks

The value of the expression remains unknown until a solution is found. The expression can be used in a constraint to restrict possible solutions.

The function is equivalent to IntervalVar.Presence and IntExpr.Presence.

Example:

In the following example, interval variables x and y must have the same presence status. I.e. they must either be both *present* or both *absent*.
var model = new Model();

var x = model.IntervalVar(name: "x", optional: true, length: 10, start: (0, 100));
var y = model.IntervalVar(name: "y", optional: true, length: 10, start: (0, 100));
model.Enforce(model.Presence(x) == model.Presence(y));

Simple constraints over presence

The solver treats binary constraints over presence in a special way: it uses them to better propagate other constraints over the same pairs of variables. Let's extend the previous example by a constraint that x must end before y starts:

var x = model.IntervalVar(name: "x", optional: true, length: 10, start: (0, 100));
var y = model.IntervalVar(name: "y", optional: true, length: 10, start: (0, 100));
model.Enforce(model.Presence(x) == model.Presence(y));
// x.end <= y.start:
var precedence = x.End() <= y.Start();
model.Enforce(precedence);

In this example, the solver sees (propagates) that the minimum start time of y is 10 and maximum end time of x is 90. Without the constraint over presence, the solver could not propagate that because one of the intervals can be absent and the other one present (and so the value of precedence would be absent and the constraint would be satisfied).

To achieve good propagation, it is recommended to use binary constraints over presence when possible. For example, multiple binary constraints can be used instead of a single complicated constraint.

Presence(int)

Creates a boolean expression that is true if the given argument is present in the solution.

public BoolExpr Presence(int value)

Parameters

value int

Returns

BoolExpr

A boolean expression that is true if the argument is present in the solution.

Remarks

The value of the expression remains unknown until a solution is found. The expression can be used in a constraint to restrict possible solutions.

The function is equivalent to IntervalVar.Presence and IntExpr.Presence.

Example:

In the following example, interval variables x and y must have the same presence status. I.e. they must either be both *present* or both *absent*.
var model = new Model();

var x = model.IntervalVar(name: "x", optional: true, length: 10, start: (0, 100));
var y = model.IntervalVar(name: "y", optional: true, length: 10, start: (0, 100));
model.Enforce(model.Presence(x) == model.Presence(y));

Simple constraints over presence

The solver treats binary constraints over presence in a special way: it uses them to better propagate other constraints over the same pairs of variables. Let's extend the previous example by a constraint that x must end before y starts:

var x = model.IntervalVar(name: "x", optional: true, length: 10, start: (0, 100));
var y = model.IntervalVar(name: "y", optional: true, length: 10, start: (0, 100));
model.Enforce(model.Presence(x) == model.Presence(y));
// x.end <= y.start:
var precedence = x.End() <= y.Start();
model.Enforce(precedence);

In this example, the solver sees (propagates) that the minimum start time of y is 10 and maximum end time of x is 90. Without the constraint over presence, the solver could not propagate that because one of the intervals can be absent and the other one present (and so the value of precedence would be absent and the constraint would be satisfied).

To achieve good propagation, it is recommended to use binary constraints over presence when possible. For example, multiple binary constraints can be used instead of a single complicated constraint.

Pulse(IntervalVar, IntExpr)

Creates cumulative function (expression) pulse for the given interval variable and height.

public CumulExpr Pulse(IntervalVar interval, IntExpr height)

Parameters

interval IntervalVar

The interval variable.

height IntExpr

The height value.

Returns

CumulExpr

The resulting cumulative expression

Remarks

Pulse can be used to model a resource requirement during an interval variable. The given amount height of the resource is used throughout the interval (from start to end).

Limitation: The height must be non-negative. Pulses with negative height are not supported. If you need negative contributions, use step functions instead (see Model.StepAtStart and Model.StepAtEnd).

Formal definition

Pulse creates a cumulative function which has the value:

  • 0 before interval.start(),
  • height between interval.start() and interval.end(),
  • 0 after interval.end()

If interval is absent, the pulse is 0 everywhere.

The height can be a constant value or an expression. In particular, the height can be given by an IntVar. In such a case, the height is unknown at the time of the model creation but is determined during the search.

Note that the interval and the height may have different presence statuses (when the height is given by a variable or an expression). In this case, the pulse is present only if both the interval and the height are present. Therefore, it is helpful to constrain the height to have the same presence status as the interval.

Cumulative functions can be combined using operators (+, -, unary -) and Model.Sum. A cumulative function's minimum and maximum height can be constrained using comparison operators (<=, >=).

Example:

Let us consider a set of tasks and a group of 3 workers. Each task requires a certain number of workers (demand). Our goal is to schedule the tasks so that the length of the schedule (makespan) is minimal.
// The input data:
int nbWorkers = 3;
var tasks = new[] {
    new { length = 10, demand = 3 },
    new { length = 20, demand = 2 },
    new { length = 15, demand = 1 },
    new { length = 30, demand = 2 },
    new { length = 20, demand = 1 },
    new { length = 25, demand = 2 },
    new { length = 10, demand = 1 },
};

var model = new Model();
// A set of pulses, one for each task:
var pulses = new List<CumulExpr>();
// End times of the tasks:
var ends = new List<IntExpr>();

for (int i = 0; i < tasks.Length; i++) {
    // Create a task:
    var task = model.IntervalVar(name: $"T{i + 1}", length: tasks[i].length);
    // Create a pulse for the task:
    pulses.Add(model.Pulse(task, tasks[i].demand));
    // Store the end of the task:
    ends.Add(task.End());
}

// The number of workers used at any time cannot exceed nbWorkers:
model.Enforce(model.Sum(pulses) <= nbWorkers);
// Minimize the maximum of the ends (makespan):
model.Minimize(model.Max(ends));

var result = model.Solve(new Parameters { searchType = "FDS" });

Example:

In the following example, we create three interval variables x, y, and z that represent some tasks. Variables x and y are present, but variable z is optional. Each task requires a certain number of workers. The length of the task depends on the assigned number of workers. The number of assigned workers is modeled using integer variables wx, wy, and wz.

There are 7 workers. Therefore, at any time, the sum of the workers assigned to the running tasks must be less or equal to 7.

If the task z is absent, then the variable wz has no meaning, and therefore, it should also be absent.

var model = new Model();
var x = model.IntervalVar(name: "x");
var y = model.IntervalVar(name: "y");
var z = model.IntervalVar(name: "z", optional: true);

var wx = model.IntVar(min: 1, max: 5, name: "wx");
var wy = model.IntVar(min: 1, max: 5, name: "wy");
var wz = model.IntVar(min: 1, max: 5, name: "wz", optional: true);

// wz is present if and only if z is present:
model.Enforce(z.Presence() == wz.Presence());

var px = model.Pulse(x, wx);
var py = model.Pulse(y, wy);
var pz = model.Pulse(z, wz);

// There are at most 7 workers at any time:
model.Enforce(model.Sum(new[] { px, py, pz }) <= 7);

// Length of the task depends on the number of workers using the following formula:
//    length * wx = 12
model.Enforce(x.Length() * wx == 12);
model.Enforce(y.Length() * wy == 12);
model.Enforce(z.Length() * wz == 12);

See also:

Pulse(IntervalVar, int)

Creates cumulative function (expression) pulse for the given interval variable and height.

public CumulExpr Pulse(IntervalVar interval, int height)

Parameters

interval IntervalVar

The interval variable.

height int

The height value.

Returns

CumulExpr

The resulting cumulative expression

Remarks

Pulse can be used to model a resource requirement during an interval variable. The given amount height of the resource is used throughout the interval (from start to end).

Limitation: The height must be non-negative. Pulses with negative height are not supported. If you need negative contributions, use step functions instead (see Model.StepAtStart and Model.StepAtEnd).

Formal definition

Pulse creates a cumulative function which has the value:

  • 0 before interval.start(),
  • height between interval.start() and interval.end(),
  • 0 after interval.end()

If interval is absent, the pulse is 0 everywhere.

The height can be a constant value or an expression. In particular, the height can be given by an IntVar. In such a case, the height is unknown at the time of the model creation but is determined during the search.

Note that the interval and the height may have different presence statuses (when the height is given by a variable or an expression). In this case, the pulse is present only if both the interval and the height are present. Therefore, it is helpful to constrain the height to have the same presence status as the interval.

Cumulative functions can be combined using operators (+, -, unary -) and Model.Sum. A cumulative function's minimum and maximum height can be constrained using comparison operators (<=, >=).

Example:

Let us consider a set of tasks and a group of 3 workers. Each task requires a certain number of workers (demand). Our goal is to schedule the tasks so that the length of the schedule (makespan) is minimal.
// The input data:
int nbWorkers = 3;
var tasks = new[] {
    new { length = 10, demand = 3 },
    new { length = 20, demand = 2 },
    new { length = 15, demand = 1 },
    new { length = 30, demand = 2 },
    new { length = 20, demand = 1 },
    new { length = 25, demand = 2 },
    new { length = 10, demand = 1 },
};

var model = new Model();
// A set of pulses, one for each task:
var pulses = new List<CumulExpr>();
// End times of the tasks:
var ends = new List<IntExpr>();

for (int i = 0; i < tasks.Length; i++) {
    // Create a task:
    var task = model.IntervalVar(name: $"T{i + 1}", length: tasks[i].length);
    // Create a pulse for the task:
    pulses.Add(model.Pulse(task, tasks[i].demand));
    // Store the end of the task:
    ends.Add(task.End());
}

// The number of workers used at any time cannot exceed nbWorkers:
model.Enforce(model.Sum(pulses) <= nbWorkers);
// Minimize the maximum of the ends (makespan):
model.Minimize(model.Max(ends));

var result = model.Solve(new Parameters { searchType = "FDS" });

Example:

In the following example, we create three interval variables x, y, and z that represent some tasks. Variables x and y are present, but variable z is optional. Each task requires a certain number of workers. The length of the task depends on the assigned number of workers. The number of assigned workers is modeled using integer variables wx, wy, and wz.

There are 7 workers. Therefore, at any time, the sum of the workers assigned to the running tasks must be less or equal to 7.

If the task z is absent, then the variable wz has no meaning, and therefore, it should also be absent.

var model = new Model();
var x = model.IntervalVar(name: "x");
var y = model.IntervalVar(name: "y");
var z = model.IntervalVar(name: "z", optional: true);

var wx = model.IntVar(min: 1, max: 5, name: "wx");
var wy = model.IntVar(min: 1, max: 5, name: "wy");
var wz = model.IntVar(min: 1, max: 5, name: "wz", optional: true);

// wz is present if and only if z is present:
model.Enforce(z.Presence() == wz.Presence());

var px = model.Pulse(x, wx);
var py = model.Pulse(y, wy);
var pz = model.Pulse(z, wz);

// There are at most 7 workers at any time:
model.Enforce(model.Sum(new[] { px, py, pz }) <= 7);

// Length of the task depends on the number of workers using the following formula:
//    length * wx = 12
model.Enforce(x.Length() * wx == 12);
model.Enforce(y.Length() * wy == 12);
model.Enforce(z.Length() * wz == 12);

See also:

SequenceVar(IEnumerable<IntervalVar>, IEnumerable<int>?, string?)

Creates a sequence variable from the provided set of interval variables.

public SequenceVar SequenceVar(IEnumerable<IntervalVar> intervals, IEnumerable<int>? types = null, string? name = null)

Parameters

intervals IEnumerable<IntervalVar>

Interval variables that will form the sequence in the solution

types IEnumerable<int>

Types of the intervals, used in particular for transition times

name string

Name assigned to the sequence variable

Returns

SequenceVar

The created sequence variable

Remarks

Sequence variable is used together with SequenceVar.NoOverlap constraint to model a set of intervals that cannot overlap and so they form a sequence in the solution. Sequence variable allows us to constrain the sequence further. For example, by specifying sequence-dependent minimum transition times.

Types can be used to mark intervals with similar properties. In particular, they behave similarly in terms of transition times. Interval variable intervals[0] will have type type[0], intervals[1] will have type type[1] and so on.

If types are not specified then intervals[0] will have type 0, intervals[1] will have type 1, and so on.

The length of the array types must be the same as the length of the array intervals. Types should be integer numbers in the range 0 to n-1 where n is the number of types.

See also:

Solve(Parameters?, Solution?)

Solves the model and returns the result.

public SolveResult Solve(Parameters? parameters = null, Solution? warmStart = null)

Parameters

parameters Parameters

The parameters for solving

warmStart Solution

The solution to start with

Returns

SolveResult

The result of the solve.

Remarks

Solves the model using the OptalCP solver and returns the result. This is the main entry point for solving constraint programming models.

The solver searches for solutions that satisfy all constraints in the model. If an objective was specified (using Model.Minimize or Model.Maximize), the solver searches for optimal or near-optimal solutions within the given time limit.

The returned SolveResult contains:

  • solution - The best solution found, or None if no solution was found. Use this to query variable values via methods like get_start(), get_end(), and get_value().
  • objective - The objective value of the best solution (if an objective was specified).
  • nb_solutions - The total number of solutions found during the search.
  • proof - Whether the solver proved optimality or infeasibility.
  • duration - The total time spent solving.
  • Statistics like nb_branches, nb_fails, and nb_restarts.

When an error occurs (e.g., invalid model, solver not found), the function raises an exception.

Parameters

Solver behavior can be controlled via the parameters argument. Common parameters include:

  • timeLimit - Maximum solving time in seconds.
  • solutionLimit - Stop after finding this many solutions.
  • nbWorkers - Number of parallel threads to use.
  • searchType - Search strategy ("LNS", "FDS", etc.).

See Parameters for the complete list.

Warm start

If the warm_start parameter is specified, the solver will start with the given solution. The solution must be compatible with the model; otherwise, an error will be raised. The solver will take advantage of the solution to speed up the search: it will search only for better solutions (if it is a minimization or maximization problem). The solver may also try to improve the provided solution by Large Neighborhood Search.

Advanced usage

This is a simple blocking function for basic usage. For advanced features like event callbacks, progress monitoring, or async support, use the Solver class instead.

This method works seamlessly in both regular Python scripts and Jupyter notebooks. In Jupyter (where an event loop is already running), it automatically handles nested event loops.

var model = new Model();
var x = model.IntervalVar(length: 10, name: "task_x");
var y = model.IntervalVar(length: 20, name: "task_y");
x.EndBeforeStart(y);
model.Minimize(y.End());

// Basic solve
var result = model.Solve();
Console.WriteLine($"Objective: {result.objective}");

// Solve with parameters
var parameters = new Parameters { timeLimit = 60, searchType = "LNS" };
result = model.Solve(parameters);

// Solve with warm start
if (result.solution != null) {
    var result2 = model.Solve(parameters, result.solution);
}

See also:

  • Solver — for async solving with event callbacks.
  • Parameters — for available solver parameters.
  • SolveResult — for the result structure.
  • Solution — for working with solutions.

Span(IntervalVar, IEnumerable<IntervalVar>)

Constrains an interval variable to span (cover) a set of other interval variables.

public Constraint Span(IntervalVar main, IEnumerable<IntervalVar> covered)

Parameters

main IntervalVar

The spanning interval variable.

covered IEnumerable<IntervalVar>

The set of interval variables to cover.

Returns

Constraint

The span constraint.

Remarks

Span constraint can be used to model, for example, a composite task that consists of several subtasks.

The constraint makes sure that interval variable main starts with the first interval in covered and ends with the last interval in covered. Absent interval variables in covered are ignored.

Formal definition

Span constraint is satisfied in one of the following two cases:

  • Interval variable main is absent and all interval variables in covered are absent too.

  • Interval variable main is present, at least one interval in covered is present and:

    • main.start() is equal to the minimum starting time of all present intervals in covered.
    • main.end() is equal to the maximum ending time of all present intervals in covered.

Example:

Let's consider composite task T, which consists of 3 subtasks: T1, T2, and T3. Subtasks are independent, could be processed in any order, and may overlap. However, task T is blocking a particular location, and no other task can be processed there. The location is blocked as soon as the first task from T1, T2, T3 starts, and it remains blocked until the last one of them finishes.
var model = new Model();

// Subtasks have known lengths:
var T1 = model.IntervalVar(name: "T1", length: 10);
var T2 = model.IntervalVar(name: "T2", length: 5);
var T3 = model.IntervalVar(name: "T3", length: 15);
// The main task has unknown length though:
var T = model.IntervalVar(name: "T");

// T spans/covers T1, T2 and T3:
model.Span(T, new[] { T1, T2, T3 });

// Tasks requiring the same location cannot overlap.
// Other tasks are not included in the example, therefore '...' below:
model.NoOverlap(new[] { T /* ... other tasks sharing the same location */ });

See also:

Start(IntervalVar)

Creates an integer expression for the start time of an interval variable.

public IntExpr Start(IntervalVar interval)

Parameters

interval IntervalVar

The interval variable.

Returns

IntExpr

The resulting integer expression

Remarks

If the interval is absent, the resulting expression is also absent.

Example:

In the following example, we constrain interval variable y to start after the end of x with a delay of at least 10. In addition, we constrain the length of x to be less or equal to the length of y.
var model = new Model();
var x = model.IntervalVar(name: "x");
var y = model.IntervalVar(name: "y");
model.Enforce(model.End(x) + 10 <= model.Start(y));
model.Enforce(model.Length(x) <= model.Length(y));

When x or y is absent then value of both constraints above is absent and therefore they are satisfied.

See also:

StartAtEnd(IntervalVar, IntervalVar, IntExpr)

Creates a precedence constraint between two interval variables.

public Constraint StartAtEnd(IntervalVar predecessor, IntervalVar successor, IntExpr delay)

Parameters

predecessor IntervalVar

The predecessor interval variable.

successor IntervalVar

The successor interval variable.

delay IntExpr

The minimum delay between intervals.

Returns

Constraint

The precedence constraint.

Remarks

Same as:

model.Enforce(predecessor.Start() + delay == successor.End());

In other words, start of predecessor plus delay must be equal to end of successor.

When one of the two interval variables is absent, then the constraint is satisfied.

See also:

StartAtEnd(IntervalVar, IntervalVar, int)

Creates a precedence constraint between two interval variables.

public Constraint StartAtEnd(IntervalVar predecessor, IntervalVar successor, int delay = 0)

Parameters

predecessor IntervalVar

The predecessor interval variable.

successor IntervalVar

The successor interval variable.

delay int

The minimum delay between intervals.

Returns

Constraint

The precedence constraint.

Remarks

Same as:

model.Enforce(predecessor.Start() + delay == successor.End());

In other words, start of predecessor plus delay must be equal to end of successor.

When one of the two interval variables is absent, then the constraint is satisfied.

See also:

StartAtStart(IntervalVar, IntervalVar, IntExpr)

Creates a precedence constraint between two interval variables.

public Constraint StartAtStart(IntervalVar predecessor, IntervalVar successor, IntExpr delay)

Parameters

predecessor IntervalVar

The predecessor interval variable.

successor IntervalVar

The successor interval variable.

delay IntExpr

The minimum delay between intervals.

Returns

Constraint

The precedence constraint.

Remarks

Same as:

model.Enforce(predecessor.Start() + delay == successor.Start());

In other words, start of predecessor plus delay must be equal to start of successor.

When one of the two interval variables is absent, then the constraint is satisfied.

See also:

StartAtStart(IntervalVar, IntervalVar, int)

Creates a precedence constraint between two interval variables.

public Constraint StartAtStart(IntervalVar predecessor, IntervalVar successor, int delay = 0)

Parameters

predecessor IntervalVar

The predecessor interval variable.

successor IntervalVar

The successor interval variable.

delay int

The minimum delay between intervals.

Returns

Constraint

The precedence constraint.

Remarks

Same as:

model.Enforce(predecessor.Start() + delay == successor.Start());

In other words, start of predecessor plus delay must be equal to start of successor.

When one of the two interval variables is absent, then the constraint is satisfied.

See also:

StartBeforeEnd(IntervalVar, IntervalVar, IntExpr)

Creates a precedence constraint between two interval variables.

public Constraint StartBeforeEnd(IntervalVar predecessor, IntervalVar successor, IntExpr delay)

Parameters

predecessor IntervalVar

The predecessor interval variable.

successor IntervalVar

The successor interval variable.

delay IntExpr

The minimum delay between intervals.

Returns

Constraint

The precedence constraint.

Remarks

Same as:

model.Enforce(predecessor.Start() + delay <= successor.End());

In other words, start of predecessor plus delay must be less than or equal to end of successor.

When one of the two interval variables is absent, then the constraint is satisfied.

See also:

StartBeforeEnd(IntervalVar, IntervalVar, int)

Creates a precedence constraint between two interval variables.

public Constraint StartBeforeEnd(IntervalVar predecessor, IntervalVar successor, int delay = 0)

Parameters

predecessor IntervalVar

The predecessor interval variable.

successor IntervalVar

The successor interval variable.

delay int

The minimum delay between intervals.

Returns

Constraint

The precedence constraint.

Remarks

Same as:

model.Enforce(predecessor.Start() + delay <= successor.End());

In other words, start of predecessor plus delay must be less than or equal to end of successor.

When one of the two interval variables is absent, then the constraint is satisfied.

See also:

StartBeforeStart(IntervalVar, IntervalVar, IntExpr)

Creates a precedence constraint between two interval variables.

public Constraint StartBeforeStart(IntervalVar predecessor, IntervalVar successor, IntExpr delay)

Parameters

predecessor IntervalVar

The predecessor interval variable.

successor IntervalVar

The successor interval variable.

delay IntExpr

The minimum delay between intervals.

Returns

Constraint

The precedence constraint.

Remarks

Same as:

model.Enforce(predecessor.Start() + delay <= successor.Start());

In other words, start of predecessor plus delay must be less than or equal to start of successor.

When one of the two interval variables is absent, then the constraint is satisfied.

See also:

StartBeforeStart(IntervalVar, IntervalVar, int)

Creates a precedence constraint between two interval variables.

public Constraint StartBeforeStart(IntervalVar predecessor, IntervalVar successor, int delay = 0)

Parameters

predecessor IntervalVar

The predecessor interval variable.

successor IntervalVar

The successor interval variable.

delay int

The minimum delay between intervals.

Returns

Constraint

The precedence constraint.

Remarks

Same as:

model.Enforce(predecessor.Start() + delay <= successor.Start());

In other words, start of predecessor plus delay must be less than or equal to start of successor.

When one of the two interval variables is absent, then the constraint is satisfied.

See also:

StepAt(int, IntExpr)

Creates a cumulative function that changes value at a given point.

public CumulExpr StepAt(int x, IntExpr height)

Parameters

x int

The point at which the cumulative function changes value.

height IntExpr

The height value (can be positive, negative, constant, or expression).

Returns

CumulExpr

The resulting cumulative expression

Remarks

This function is similar to Model.StepAtStart and Model.StepAtEnd, but the time of the change is given by the constant value x instead of by the start/end of an interval variable. The height can be a constant or an expression (e.g., created by Model.IntVar).

Formal definition

stepAt creates a cumulative function which has the value:

  • 0 before x,
  • height after x.

See also:

StepAt(int, int)

Creates a cumulative function that changes value at a given point.

public CumulExpr StepAt(int x, int height)

Parameters

x int

The point at which the cumulative function changes value.

height int

The height value (can be positive, negative, constant, or expression).

Returns

CumulExpr

The resulting cumulative expression

Remarks

This function is similar to Model.StepAtStart and Model.StepAtEnd, but the time of the change is given by the constant value x instead of by the start/end of an interval variable. The height can be a constant or an expression (e.g., created by Model.IntVar).

Formal definition

stepAt creates a cumulative function which has the value:

  • 0 before x,
  • height after x.

See also:

StepAtEnd(IntervalVar, IntExpr)

Creates cumulative function (expression) that changes value at end of the interval variable by the given height.

public CumulExpr StepAtEnd(IntervalVar interval, IntExpr height)

Parameters

interval IntervalVar

The interval variable.

height IntExpr

The height value.

Returns

CumulExpr

The resulting cumulative expression

Remarks

Cumulative step functions could be used to model a resource that is consumed or produced and, therefore, changes in amount over time. Examples of such a resource are a battery, an account balance, a product's stock, etc.

A stepAtEnd can change the amount of such resource at the end of a given variable. The amount is changed by the given height, which can be positive or negative.

The height can be a constant value or an expression. In particular, the height can be given by an IntVar. In such a case, the height is unknown at the time of the model creation but is determined during the search.

Note that the interval and the height may have different presence statuses (when the height is given by a variable or an expression). In this case, the step is present only if both the interval and the height are present. Therefore, it is helpful to constrain the height to have the same presence status as the interval.

Cumulative steps can be combined using operators (+, -, unary -) and Model.Sum. A cumulative function's minimum and maximum height can be constrained using comparison operators (<=, >=).

Formal definition

stepAtEnd creates a cumulative function which has the value:

  • 0 before interval.end(),
  • height after interval.end().

If the interval or the height is absent, the created cumulative function is 0 everywhere.

Example:

Let us consider a set of tasks. Each task either costs a certain amount of money or makes some money. Money is consumed at the start of a task and produced at the end. We have an initial budget, and we want to schedule the tasks so that we do not run out of money (i.e., the amount is always non-negative).

Tasks cannot overlap. Our goal is to find the shortest schedule possible.

// The input data:
int budget = 100;
var tasksData = new[] {
    (length: 10, money: -150), (length: 20, money:   40),
    (length: 15, money:   20), (length: 30, money:  -10),
    (length: 20, money:   30), (length: 25, money:  -20),
    (length: 10, money:   10), (length: 20, money:   50),
};

var model = new Model();
var taskVars = new List<IntervalVar>();
var steps = new List<CumulExpr>();

for (int i = 0; i < tasksData.Length; i++) {
    var interval = model.IntervalVar(name: $"T{i + 1}", length: tasksData[i].length);
    taskVars.Add(interval);
    if (tasksData[i].money < 0)
        steps.Add(model.StepAtStart(interval, tasksData[i].money));
    else
        steps.Add(model.StepAtEnd(interval, tasksData[i].money));
}

// The initial budget increases the cumul at time 0:
steps.Add(model.StepAt(0, budget));
// The money must be non-negative at any time:
model.Enforce(model.Sum(steps) >= 0);
// Only one task at a time:
model.NoOverlap(taskVars);

// Minimize the maximum of the ends (makespan):
model.Minimize(model.Max(taskVars.Select(t => t.End())));

var result = model.Solve(new Parameters { searchType = "FDS" });

See also:

StepAtEnd(IntervalVar, int)

Creates cumulative function (expression) that changes value at end of the interval variable by the given height.

public CumulExpr StepAtEnd(IntervalVar interval, int height)

Parameters

interval IntervalVar

The interval variable.

height int

The height value.

Returns

CumulExpr

The resulting cumulative expression

Remarks

Cumulative step functions could be used to model a resource that is consumed or produced and, therefore, changes in amount over time. Examples of such a resource are a battery, an account balance, a product's stock, etc.

A stepAtEnd can change the amount of such resource at the end of a given variable. The amount is changed by the given height, which can be positive or negative.

The height can be a constant value or an expression. In particular, the height can be given by an IntVar. In such a case, the height is unknown at the time of the model creation but is determined during the search.

Note that the interval and the height may have different presence statuses (when the height is given by a variable or an expression). In this case, the step is present only if both the interval and the height are present. Therefore, it is helpful to constrain the height to have the same presence status as the interval.

Cumulative steps can be combined using operators (+, -, unary -) and Model.Sum. A cumulative function's minimum and maximum height can be constrained using comparison operators (<=, >=).

Formal definition

stepAtEnd creates a cumulative function which has the value:

  • 0 before interval.end(),
  • height after interval.end().

If the interval or the height is absent, the created cumulative function is 0 everywhere.

Example:

Let us consider a set of tasks. Each task either costs a certain amount of money or makes some money. Money is consumed at the start of a task and produced at the end. We have an initial budget, and we want to schedule the tasks so that we do not run out of money (i.e., the amount is always non-negative).

Tasks cannot overlap. Our goal is to find the shortest schedule possible.

// The input data:
int budget = 100;
var tasksData = new[] {
    (length: 10, money: -150), (length: 20, money:   40),
    (length: 15, money:   20), (length: 30, money:  -10),
    (length: 20, money:   30), (length: 25, money:  -20),
    (length: 10, money:   10), (length: 20, money:   50),
};

var model = new Model();
var taskVars = new List<IntervalVar>();
var steps = new List<CumulExpr>();

for (int i = 0; i < tasksData.Length; i++) {
    var interval = model.IntervalVar(name: $"T{i + 1}", length: tasksData[i].length);
    taskVars.Add(interval);
    if (tasksData[i].money < 0)
        steps.Add(model.StepAtStart(interval, tasksData[i].money));
    else
        steps.Add(model.StepAtEnd(interval, tasksData[i].money));
}

// The initial budget increases the cumul at time 0:
steps.Add(model.StepAt(0, budget));
// The money must be non-negative at any time:
model.Enforce(model.Sum(steps) >= 0);
// Only one task at a time:
model.NoOverlap(taskVars);

// Minimize the maximum of the ends (makespan):
model.Minimize(model.Max(taskVars.Select(t => t.End())));

var result = model.Solve(new Parameters { searchType = "FDS" });

See also:

StepAtStart(IntervalVar, IntExpr)

Creates cumulative function (expression) that changes value at start of the interval variable by the given height.

public CumulExpr StepAtStart(IntervalVar interval, IntExpr height)

Parameters

interval IntervalVar

The interval variable.

height IntExpr

The height value.

Returns

CumulExpr

The resulting cumulative expression

Remarks

Cumulative step functions could be used to model a resource that is consumed or produced and, therefore, changes in amount over time. Examples of such a resource are a battery, an account balance, a product's stock, etc.

A stepAtStart can change the amount of such resource at the start of a given variable. The amount is changed by the given height, which can be positive or negative.

The height can be a constant value or an expression. In particular, the height can be given by an IntVar. In such a case, the height is unknown at the time of the model creation but is determined during the search.

Note that the interval and the height may have different presence statuses (when the height is given by a variable or an expression). In this case, the step is present only if both the interval and the height are present. Therefore, it is helpful to constrain the height to have the same presence status as the interval.

Cumulative steps can be combined using operators (+, -, unary -) and Model.Sum. A cumulative function's minimum and maximum height can be constrained using comparison operators (<=, >=).

Formal definition

stepAtStart creates a cumulative function which has the value:

  • 0 before interval.start(),
  • height after interval.start().

If the interval or the height is absent, the created cumulative function is 0 everywhere.

Example:

Let us consider a set of tasks. Each task either costs a certain amount of money or makes some money. Money is consumed at the start of a task and produced at the end. We have an initial budget, and we want to schedule the tasks so that we do not run out of money (i.e., the amount is always non-negative).

Tasks cannot overlap. Our goal is to find the shortest schedule possible.

// The input data:
int budget = 100;
var tasksData = new[] {
    (length: 10, money: -150), (length: 20, money:   40),
    (length: 15, money:   20), (length: 30, money:  -10),
    (length: 20, money:   30), (length: 25, money:  -20),
    (length: 10, money:   10), (length: 20, money:   50),
};

var model = new Model();
var taskVars = new List<IntervalVar>();
var steps = new List<CumulExpr>();

for (int i = 0; i < tasksData.Length; i++) {
    var interval = model.IntervalVar(name: $"T{i + 1}", length: tasksData[i].length);
    taskVars.Add(interval);
    if (tasksData[i].money < 0)
        steps.Add(model.StepAtStart(interval, tasksData[i].money));
    else
        steps.Add(model.StepAtEnd(interval, tasksData[i].money));
}

// The initial budget increases the cumul at time 0:
steps.Add(model.StepAt(0, budget));
// The money must be non-negative at any time:
model.Enforce(model.Sum(steps) >= 0);
// Only one task at a time:
model.NoOverlap(taskVars);

// Minimize the maximum of the ends (makespan):
model.Minimize(model.Max(taskVars.Select(t => t.End())));

var result = model.Solve(new Parameters { searchType = "FDS" });

See also:

StepAtStart(IntervalVar, int)

Creates cumulative function (expression) that changes value at start of the interval variable by the given height.

public CumulExpr StepAtStart(IntervalVar interval, int height)

Parameters

interval IntervalVar

The interval variable.

height int

The height value.

Returns

CumulExpr

The resulting cumulative expression

Remarks

Cumulative step functions could be used to model a resource that is consumed or produced and, therefore, changes in amount over time. Examples of such a resource are a battery, an account balance, a product's stock, etc.

A stepAtStart can change the amount of such resource at the start of a given variable. The amount is changed by the given height, which can be positive or negative.

The height can be a constant value or an expression. In particular, the height can be given by an IntVar. In such a case, the height is unknown at the time of the model creation but is determined during the search.

Note that the interval and the height may have different presence statuses (when the height is given by a variable or an expression). In this case, the step is present only if both the interval and the height are present. Therefore, it is helpful to constrain the height to have the same presence status as the interval.

Cumulative steps can be combined using operators (+, -, unary -) and Model.Sum. A cumulative function's minimum and maximum height can be constrained using comparison operators (<=, >=).

Formal definition

stepAtStart creates a cumulative function which has the value:

  • 0 before interval.start(),
  • height after interval.start().

If the interval or the height is absent, the created cumulative function is 0 everywhere.

Example:

Let us consider a set of tasks. Each task either costs a certain amount of money or makes some money. Money is consumed at the start of a task and produced at the end. We have an initial budget, and we want to schedule the tasks so that we do not run out of money (i.e., the amount is always non-negative).

Tasks cannot overlap. Our goal is to find the shortest schedule possible.

// The input data:
int budget = 100;
var tasksData = new[] {
    (length: 10, money: -150), (length: 20, money:   40),
    (length: 15, money:   20), (length: 30, money:  -10),
    (length: 20, money:   30), (length: 25, money:  -20),
    (length: 10, money:   10), (length: 20, money:   50),
};

var model = new Model();
var taskVars = new List<IntervalVar>();
var steps = new List<CumulExpr>();

for (int i = 0; i < tasksData.Length; i++) {
    var interval = model.IntervalVar(name: $"T{i + 1}", length: tasksData[i].length);
    taskVars.Add(interval);
    if (tasksData[i].money < 0)
        steps.Add(model.StepAtStart(interval, tasksData[i].money));
    else
        steps.Add(model.StepAtEnd(interval, tasksData[i].money));
}

// The initial budget increases the cumul at time 0:
steps.Add(model.StepAt(0, budget));
// The money must be non-negative at any time:
model.Enforce(model.Sum(steps) >= 0);
// Only one task at a time:
model.NoOverlap(taskVars);

// Minimize the maximum of the ends (makespan):
model.Minimize(model.Max(taskVars.Select(t => t.End())));

var result = model.Solve(new Parameters { searchType = "FDS" });

See also:

StepFunction(IEnumerable<(int, int)>)

Creates a new integer step function.

public IntStepFunction StepFunction(IEnumerable<(int, int)> values)

Parameters

values IEnumerable<(int, int)>

An array of points defining the step function in the form [[x0, y0], [x1, y1], ..., [xn, yn]], where xi and yi are integers. The array must be sorted by xi

Returns

IntStepFunction

The created step function

Remarks

Integer step function is a piecewise constant function defined on integer values in range Model.IntVarMin to Model.IntVarMax. The function is defined as follows:

  • \(f(x) = 0\) for \(x < x_0\),
  • \(f(x) = y_i\) for \(x_i \leq x < x_{i+1}\)
  • \(f(x) = y_n\) for \(x \geq x_n\).

Step functions can be used in the following ways:

Sum(IEnumerable<CumulExpr>)

Sum of cumulative expressions.

public CumulExpr Sum(IEnumerable<CumulExpr> args)

Parameters

args IEnumerable<CumulExpr>

Array of cumulative expressions to sum.

Returns

CumulExpr

The resulting cumulative expression

Remarks

Computes the sum of cumulative functions. The sum can be used, e.g., to combine contributions of individual tasks to total resource consumption.

Limitation: Currently, pulse-based and step-based cumulative expressions cannot be mixed. All expressions in the sum must be either pulse-based or step-based.

Sum(IEnumerable<IntExpr>)

Creates an integer expression for the sum of the arguments.

public IntExpr Sum(IEnumerable<IntExpr> args)

Parameters

args IEnumerable<IntExpr>

Array of integer expressions to sum.

Returns

IntExpr

The resulting integer expression

Remarks

Absent arguments are ignored (treated as zeros). Therefore, the resulting expression is never absent.

Note that the binary operator + handles absent values differently. For example, when x is absent then:

  • x + 3 is absent.
  • model.Sum(new[] { x, 3 }) is 3.

Example:

Let's consider a set of optional tasks. Due to limited resources and time, only some of them can be executed. Every task has a profit, and we want to maximize the total profit from the executed tasks.
// Lengths and profits of the tasks:
int[] lengths = { 10, 20, 15, 30, 20, 25, 30, 10, 20, 25 };
int[] profits = {  5,  6,  7,  8,  9, 10, 11, 12, 13, 14 };

var model = new Model();
var tasks = new List<IntervalVar>();
// Profits of individual tasks. The value will be zero if the task is not executed.
var taskProfits = new List<IntExpr>();

for (int i = 0; i < lengths.Length; i++) {
    // All tasks must finish before time 100:
    var task = model.IntervalVar(name: $"Task{i}", optional: true, length: lengths[i], end: (null, 100));
    tasks.Add(task);
    taskProfits.Add(model.Presence(task) * profits[i]);
}
model.Maximize(model.Sum(taskProfits));
// Tasks cannot overlap:
model.NoOverlap(tasks);

var result = model.Solve(new Parameters { searchType = "FDS" });

Sum(IEnumerable<object>)

Creates an integer expression for the sum of the arguments.

public IntExpr Sum(IEnumerable<object> args)

Parameters

args IEnumerable<object>

Array of integer expressions to sum.

Returns

IntExpr

The resulting integer expression

Remarks

Absent arguments are ignored (treated as zeros). Therefore, the resulting expression is never absent.

Note that the binary operator + handles absent values differently. For example, when x is absent then:

  • x + 3 is absent.
  • model.Sum(new[] { x, 3 }) is 3.

Example:

Let's consider a set of optional tasks. Due to limited resources and time, only some of them can be executed. Every task has a profit, and we want to maximize the total profit from the executed tasks.
// Lengths and profits of the tasks:
int[] lengths = { 10, 20, 15, 30, 20, 25, 30, 10, 20, 25 };
int[] profits = {  5,  6,  7,  8,  9, 10, 11, 12, 13, 14 };

var model = new Model();
var tasks = new List<IntervalVar>();
// Profits of individual tasks. The value will be zero if the task is not executed.
var taskProfits = new List<IntExpr>();

for (int i = 0; i < lengths.Length; i++) {
    // All tasks must finish before time 100:
    var task = model.IntervalVar(name: $"Task{i}", optional: true, length: lengths[i], end: (null, 100));
    tasks.Add(task);
    taskProfits.Add(model.Presence(task) * profits[i]);
}
model.Maximize(model.Sum(taskProfits));
// Tasks cannot overlap:
model.NoOverlap(tasks);

var result = model.Solve(new Parameters { searchType = "FDS" });

ToJS(Parameters?, Solution?)

Converts the model to equivalent JavaScript code.

public string ToJS(Parameters? parameters = null, Solution? warmStart = null)

Parameters

parameters Parameters

Optional solver parameters (included in generated code)

warmStart Solution

Optional initial solution to include

Returns

string

JavaScript code representing the model.

Remarks

The output is human-readable, executable with Node.js, and can be stored in a file. It is meant as a way to export a model to a format that is executable, human-readable, editable, and independent of other libraries.

This feature is experimental and the result is not guaranteed to be valid in all cases.

var model = new Model();
var x = model.IntervalVar(length: 10, name: "task_x");
var y = model.IntervalVar(length: 20, name: "task_y");
x.EndBeforeStart(y);
model.Minimize(y.End());

// Convert to JavaScript code
var jsCode = model.ToJS();
Console.WriteLine(jsCode);

// Save to file
File.WriteAllText("model.js", jsCode);

See also:

ToJSON(Parameters?, Solution?)

Exports the model to JSON format.

public string ToJSON(Parameters? parameters = null, Solution? warmStart = null)

Parameters

parameters Parameters

Optional solver parameters to include

warmStart Solution

Optional initial solution to include

Returns

string

A string containing the model in JSON format.

Remarks

The result can be stored in a file for later use. The model can be converted back from JSON format using Model.FromJSON.

var model = new Model();
var x = model.IntervalVar(length: 10, name: "task_x");
var y = model.IntervalVar(length: 20, name: "task_y");
x.EndBeforeStart(y);
model.Minimize(y.End());

// Export to JSON
var jsonStr = model.ToJSON();

// Save to file
File.WriteAllText("model.json", jsonStr);

// Later, load from JSON
var (model2, params2, warmStart2) = Model.FromJSON(jsonStr);

See also:

ToText(Parameters?, Solution?)

Converts the model to text format similar to IBM CP Optimizer file format.

public string ToText(Parameters? parameters = null, Solution? warmStart = null)

Parameters

parameters Parameters

Optional solver parameters (mostly unused)

warmStart Solution

Optional initial solution to include

Returns

string

Text representation of the model.

Remarks

The output is human-readable and can be stored in a file. Unlike JSON format, there is no way to convert the text format back into a Model.

The result is so similar to the file format used by IBM CP Optimizer that, under some circumstances, the result can be used as an input file for CP Optimizer. However, some differences between OptalCP and CP Optimizer make it impossible to guarantee the result is always valid for CP Optimizer.

Known issues:

  • OptalCP supports optional integer expressions, while CP Optimizer does not. If the model contains optional integer expressions, the result will not be valid for CP Optimizer or may be badly interpreted. For example, to get a valid CP Optimizer file, don't use interval.start(), use interval.start_or(default) instead.
  • For the same reason, prefer precedence constraints such as end_before_start() over model.enforce(x.end() <= y.start()).
  • Negative heights in cumulative expressions (e.g., in step_at_start()) are not supported by CP Optimizer.
var model = new Model();
var x = model.IntervalVar(length: 10, name: "task_x");
var y = model.IntervalVar(length: 20, name: "task_y");
x.EndBeforeStart(y);
model.Minimize(y.End());

// Convert to text format
var text = model.ToText();
Console.WriteLine(text);

// Save to file
File.WriteAllText("model.txt", text);

See also: