Class: Model
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
-
Model.plus: addition.
-
Model.minus: subtraction.
-
Model.neg: negation (changes sign).
-
Model.times: multiplication.
-
Model.div: division (rounds to zero).
-
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
-
Model.eq: equality.
-
Model.ne: inequality.
-
Model.lt: less than.
-
Model.le: less than or equal to.
-
Model.gt: greater than.
-
Model.ge: greater than or equal to.
-
Model.identity: constraints two integer expressions to be equal, including the presence status.
Boolean operators
- Model.not: negation.
- Model.and: conjunction.
- Model.or: disjunction.
- Model.implies: implication.
Functions returning BoolExpr
- Model.presence: whether the argument is present or absent.
- Model.inRange: whether an integer expression is within the given range
Basic constraints on interval variables
- Model.alternative: an alternative between multiple interval variables.
- Model.span: span (cover) of interval variables.
- Model.endBeforeEnd, Model.endBeforeStart, Model.startBeforeEnd, Model.startBeforeStart, Model.endAtStart, Model.startAtEnd: precedence constraints.
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
- Model.pulse: changes value during the interval variable.
- Model.stepAtStart: changes value at the start of the interval variable.
- Model.stepAtEnd: changes value at the end of the interval variable.
- Model.stepAt: changes value at a given time.
Combining cumulative expressions
- CumulExpr.neg: negation.
- CumulExpr.plus: addition.
- CumulExpr.minus: subtraction.
- Model.sum: sum of multiple expressions.
Constraints on cumulative expressions
- CumulExpr.ge: greater than or equal to a constant.
- CumulExpr.le: less than or equal to a constant.
Objective
- Model.minimize: minimize an integer expression.
- Model.maximize: maximize an integer expression.
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.
import * as CP from '@scheduleopt/optalcp';
// Constants for random problem generation:
const nbTasks = 100;
const nbWorkers = 5;
const maxDuration = 100;
// Start by creating the model:
let model = new CP.Model();
// For each task we will have an interval variable and a cumulative expression:
let tasks : CP.IntervalVar[] = [];
let workerUsage: CP.CumulExpr[] = [];
// Loop over the tasks:
for (let i = 0; i < nbTasks; i++) {
// Generate random task length:
const taskLength = 1 + Math.floor(Math.random() * (maxDuration - 1));
// Create the interval variable for the task:
let task = model.intervalVar({ name: "Task" + (i + 1), length: taskLength });
// And store it in the array:
tasks.push(task);
// Generate random number of workers needed for the task:
const workersNeeded = 1 + Math.floor(Math.random() * (nbWorkers - 1));
// Create the pulse that increases the number of workers used during the task:
workerUsage.push(task.pulse(workersNeeded));
}
// Limit the sum of the pulses to the number of workers available:
model.sum(workerUsage).le(nbWorkers);
// From an array of tasks, create an array of their ends:
let ends = tasks.map(t => t.end());
// And minimize the maximum of the ends:
model.max(ends).minimize();
try {
// Solve the model with the provided parameters:
let result = await model.solve({
timeLimit: 3, // Stop after 3 seconds
nbWorkers: 4, // Use for CPU threads
});
if (result.nbSolutions == 0)
console.log("No solution found.");
else {
const solution = result.solution!;
// Note that in the preview version of the solver, the variable values in
// the solution are masked, i.e. they are all *absent* (`null` in JavaScript).
// Objective value is not masked though.
console.log("Solution found with makespan " + solution.getObjective());
for (let task of tasks) {
let start = solution.getStart(task);
if (start !== null)
console.log("Task " + task.name + " starts at " + start);
else
console.log("Task " + task.name + " is absent (not scheduled).")
}
}
} catch (e) {
// In case of error, model.solve returns a rejected promise.
// Therefore, "await model.solve" throws an exception.
console.log("Error: " + (e as Error).message);
}
See
Constructors
new Model()
new Model(
name?:string):Model
Creates an empty optimization model.
Parameters
| Parameter | Type | Description |
|---|---|---|
name? | string | Optional name for the model |
Returns
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:
- Variables: Model.intervalVar, Model.intVar, Model.boolVar
- Constraints: Model.noOverlap, Model.endBeforeStart, Model.enforce, etc.
- Objective: Model.minimize or Model.maximize
import * as CP from "optalcp";
// Create an unnamed model
const model = new CP.Model();
// Create a named model (useful for debugging)
const namedModel = new CP.Model("JobShop");
// Add variables and constraints
const task = model.intervalVar({ length: 10, name: "task" });
model.minimize(task.end());
// Solve
const result = await model.solve();
See
- Model for available modeling methods.
- Model.solve to solve the model.
Solving
solve()
solve(
parameters?:Parameters,warmStart?:Solution):Promise<SolveResult>
Solves the model and returns the result.
Parameters
| Parameter | Type | Description |
|---|---|---|
parameters? | Parameters | The parameters for solving |
warmStart? | Solution | The solution to start with |
Returns
Promise<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, orNoneif no solution was found. Use this to query variable values via methods likeget_start(),get_end(), andget_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, andnb_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.
import * as CP from "optalcp";
const model = new CP.Model();
const x = model.intervalVar({ length: 10, name: "task_x" });
const y = model.intervalVar({ length: 20, name: "task_y" });
x.endBeforeStart(y);
model.minimize(y.end());
// Basic solve
let result = await model.solve();
console.log(`Objective: ${result.objective}`);
// Solve with parameters
const params = { timeLimit: 60, searchType: "LNS" };
result = await model.solve(params);
// Solve with warm start
if (result.solution) {
const result2 = await model.solve(params, result.solution);
}
See
- Solver for async solving with event callbacks.
- Parameters for available solver parameters.
- SolveResult for the result structure.
- Solution for working with solutions.
Model exporting
toJS()
toJS(
parameters?:Parameters,warmStart?:Solution):Promise<undefined|string>
Converts the model to equivalent JavaScript code.
Parameters
| Parameter | Type | Description |
|---|---|---|
parameters? | Parameters | Optional solver parameters (included in generated code) |
warmStart? | Solution | Optional initial solution to include |
Returns
Promise<undefined | 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.
import * as CP from "optalcp";
import * as fs from "fs";
const model = new CP.Model();
const x = model.intervalVar({ length: 10, name: "task_x" });
const y = model.intervalVar({ length: 20, name: "task_y" });
x.endBeforeStart(y);
model.minimize(y.end());
// Convert to JavaScript code
const jsCode = model.toJS();
console.log(jsCode);
// Save to file
fs.writeFileSync("model.js", jsCode);
See
- Model.toText to export as text format.
- Model.toJSON to export as JSON (can be imported back).
toJSON()
toJSON(
parameters?:Parameters,warmStart?:Solution):string
Exports the model to JSON format.
Parameters
| Parameter | Type | Description |
|---|---|---|
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.
import * as CP from "optalcp";
import * as fs from "fs";
const model = new CP.Model();
const x = model.intervalVar({ length: 10, name: "task_x" });
const y = model.intervalVar({ length: 20, name: "task_y" });
x.endBeforeStart(y);
model.minimize(y.end());
// Export to JSON
const jsonStr = model.toJSON();
// Save to file
fs.writeFileSync("model.json", jsonStr);
// Later, load from JSON
const { model: model2, parameters: params2, warmStart: warmStart2 } =
CP.Model.fromJSON(jsonStr);
See
- Model.fromJSON to import from JSON.
- Model.toText to export as text format.
- Model.toJS to export as JavaScript code.
toText()
toText(
parameters?:Parameters,warmStart?:Solution):Promise<undefined|string>
Converts the model to text format similar to IBM CP Optimizer file format.
Parameters
| Parameter | Type | Description |
|---|---|---|
parameters? | Parameters | Optional solver parameters (mostly unused) |
warmStart? | Solution | Optional initial solution to include |
Returns
Promise<undefined | 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(), useinterval.start_or(default)instead. - For the same reason, prefer precedence constraints such as
end_before_start()overmodel.enforce(x.end() <= y.start()). - Negative heights in cumulative expressions (e.g., in
step_at_start()) are not supported by CP Optimizer.
import * as CP from "optalcp";
import * as fs from "fs";
const model = new CP.Model();
const x = model.intervalVar({ length: 10, name: "task_x" });
const y = model.intervalVar({ length: 20, name: "task_y" });
x.endBeforeStart(y);
model.minimize(y.end());
// Convert to text format
const text = model.toText();
console.log(text);
// Save to file
fs.writeFileSync("model.txt", text);
See
- Model.toJS to export as JavaScript code.
- Model.toJSON to export as JSON (can be imported back).
fromJSON()
staticfromJSON(jsonStr:string): {model:Model;parameters:Parameters;warmStart:Solution; }
Creates a model from JSON format.
Parameters
| Parameter | Type | Description |
|---|---|---|
jsonStr | string | A string containing the model in JSON format |
Returns
{ model: Model; parameters: Parameters; warmStart: Solution; }
A tuple containing the model, optional parameters, and optional warm start solution.
model
model:
Model
parameters?
optionalparameters:Parameters
warmStart?
optionalwarmStart: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:
- The reconstructed Model
- Parameters (if they were included in the JSON), or None
- 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.
import * as CP from "optalcp";
import * as fs from "fs";
// Create and export a model
const model = new CP.Model();
const x = model.intervalVar({ length: 10, name: "task_x" });
model.minimize(x.end());
const params: CP.Parameters = { timeLimit: 60 };
const jsonStr = model.toJSON(params);
// Save to file
fs.writeFileSync("model.json", jsonStr);
// Later, load from file
const loadedJson = fs.readFileSync("model.json", "utf-8");
// Restore model (returns Model directly in TypeScript)
const model2 = CP.Model.fromJSON(loadedJson);
// Access variables
const intervalVars = model2.getIntervalVars();
console.log(`Loaded model with ${intervalVars.length} interval variables`);
// Solve with restored parameters
const result = await model2.solve(params);
See
Model.toJSON to export to JSON.
Other
name
Get Signature
get name():
undefined|string
The name of the model.
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.
import * as CP from "optalcp";
// Set name in constructor
let model = new CP.Model({ name: "MySchedulingProblem" });
console.log(model.name); // "MySchedulingProblem"
// Or set name later
model = new CP.Model();
model.name = "JobShop";
console.log(model.name); // "JobShop"
Returns
undefined | string
Set Signature
set name(
value:string):void
Parameters
| Parameter | Type |
|---|---|
value | string |
Returns
void
abs()
Creates an integer expression which is absolute value of arg.
Parameters
| Parameter | Type | Description |
|---|---|---|
arg | number | IntExpr | The integer expression. |
Returns
The resulting integer expression
Remarks
If arg has value absent then the resulting expression has also value absent.
Same as IntExpr.abs.
alternative()
alternative(
main:IntervalVar,options:IntervalVar[]):Constraint
Alternative constraint models a choice between different ways to execute an interval.
Parameters
| Parameter | Type | Description |
|---|---|---|
main | IntervalVar | The main interval variable. |
options | 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:
- Interval
mainis absent and alloptions[i]are absent too. - Interval
mainis present and exactly one ofoptions[i]is present (the remaining options are absent). Letkbe the index of the present option. Thenmain.start() == options[k].start()andmain.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).
let model = new CP.Model;
let T = model.intervalVar({ name: "T" });
let T_A = model.intervalVar({ name: "T_A", optional: true, length: 10 });
let T_B = model.intervalVar({ name: "T_B", optional: true, length: 20 });
let 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, [T_A, T_B, T_C]);
// The cost depends on the chosen option:
let costOfT = model.sum([
T_A.presence().times(5),
T_B.presence().times(2),
T_C.presence().times(10)
]);
// Each worker A can perform only one task at a time:
model.noOverlap([T_A, ...]); // Worker A
model.noOverlap([T_B, ...]); // Worker B
model.noOverlap([T_C, ...]); // Worker C
// Minimize the total cost:
model.sum([costOfT, ...]).minimize();
and()
and(
lhs:boolean|BoolExpr,rhs:boolean|BoolExpr):BoolExpr
Logical AND of boolean expressions lhs and rhs.
Parameters
| Parameter | Type | Description |
|---|---|---|
lhs | boolean | BoolExpr | The first boolean expression. |
rhs | boolean | BoolExpr | The second boolean expression. |
Returns
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()
boolVar(
params: {name:string;optional:boolean; }):BoolVar
Creates a new boolean variable and adds it to the model.
Parameters
| Parameter | Type | Description |
|---|---|---|
params | { name: string; optional: boolean; } | - |
params.name? | string | Name for the variable (useful for debugging) |
params.optional? | boolean | If true, the variable can be absent in a solution (default false) |
Returns
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 operations via methods:
- BoolExpr.not for logical NOT
- BoolExpr.or for logical OR
- BoolExpr.and for logical AND
See
- Model.intervalVar for the primary variable type for scheduling problems.
- Model.intVar for numeric decisions.
Example
Create boolean variables to model decisions:
let model = new CP.Model();
let useMachineA = model.boolVar({ name: "useMachineA" });
let useMachineB = model.boolVar({ name: "useMachineB" });
// Constraint: must use at least one machine
model.enforce(useMachineA.or(useMachineB));
// Constraint: cannot use both machines
model.enforce(useMachineA.and(useMachineB).not());
div()
Creates an integer division of the two integer expressions, i.e. lhs div rhs. The division rounds towards zero.
Parameters
| Parameter | Type | Description |
|---|---|---|
lhs | number | IntExpr | The first integer expression. |
rhs | number | IntExpr | The second integer expression. |
Returns
The resulting integer expression
Remarks
If one of the arguments has value absent, the resulting expression also has value absent.
Same as IntExpr.div.
end()
end(
interval:IntervalVar):IntExpr
Creates an integer expression for the end time of an interval variable.
Parameters
| Parameter | Type | Description |
|---|---|---|
interval | IntervalVar | The interval variable. |
Returns
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.
let model = new CP.Model;
let x = model.intervalVar({ name: "x", ... });
let y = model.intervalVar({ name: "y", ... });
model.enforce(model.end(x).plus(10).le(model.start(y)));
model.enforce(model.length(x).le(model.length(y)));
When x or y is absent then value of both constraints above is absent and therefore they are satisfied.
See
IntervalVar.end is equivalent function on IntervalVar.
endAtEnd()
endAtEnd(
predecessor:IntervalVar,successor:IntervalVar,delay:number|IntExpr):Constraint
Creates a precedence constraint between two interval variables.
Parameters
| Parameter | Type | Default value | Description |
|---|---|---|---|
predecessor | IntervalVar | undefined | The predecessor interval variable. |
successor | IntervalVar | undefined | The successor interval variable. |
delay | number | IntExpr | 0 | The minimum delay between intervals. |
Returns
Constraint
The precedence constraint.
Remarks
Same as:
model.enforce(predecessor.end().plus(delay).eq(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
- IntervalVar.endAtEnd is equivalent function on IntervalVar.
- IntervalVar.start, IntervalVar.end
- IntExpr.eq
endAtStart()
endAtStart(
predecessor:IntervalVar,successor:IntervalVar,delay:number|IntExpr):Constraint
Creates a precedence constraint between two interval variables.
Parameters
| Parameter | Type | Default value | Description |
|---|---|---|---|
predecessor | IntervalVar | undefined | The predecessor interval variable. |
successor | IntervalVar | undefined | The successor interval variable. |
delay | number | IntExpr | 0 | The minimum delay between intervals. |
Returns
Constraint
The precedence constraint.
Remarks
Same as:
model.enforce(predecessor.end().plus(delay).eq(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
- IntervalVar.endAtStart is equivalent function on IntervalVar.
- IntervalVar.start, IntervalVar.end
- IntExpr.eq
endBeforeEnd()
endBeforeEnd(
predecessor:IntervalVar,successor:IntervalVar,delay:number|IntExpr):Constraint
Creates a precedence constraint between two interval variables.
Parameters
| Parameter | Type | Default value | Description |
|---|---|---|---|
predecessor | IntervalVar | undefined | The predecessor interval variable. |
successor | IntervalVar | undefined | The successor interval variable. |
delay | number | IntExpr | 0 | The minimum delay between intervals. |
Returns
Constraint
The precedence constraint.
Remarks
Same as:
model.enforce(predecessor.end().plus(delay).le(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
- IntervalVar.endBeforeEnd is equivalent function on IntervalVar.
- IntervalVar.start, IntervalVar.end
- IntExpr.le
endBeforeStart()
endBeforeStart(
predecessor:IntervalVar,successor:IntervalVar,delay:number|IntExpr):Constraint
Creates a precedence constraint between two interval variables.
Parameters
| Parameter | Type | Default value | Description |
|---|---|---|---|
predecessor | IntervalVar | undefined | The predecessor interval variable. |
successor | IntervalVar | undefined | The successor interval variable. |
delay | number | IntExpr | 0 | The minimum delay between intervals. |
Returns
Constraint
The precedence constraint.
Remarks
Same as:
model.enforce(predecessor.end().plus(delay).le(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
- IntervalVar.endBeforeStart is equivalent function on IntervalVar.
- IntervalVar.start, IntervalVar.end
- IntExpr.le
endOr()
endOr(
interval:IntervalVar,absentValue:number):IntExpr
Creates an integer expression for the end time of the interval variable. If the interval is absent, then its value is absentValue.
Parameters
| Parameter | Type | Description |
|---|---|---|
interval | IntervalVar | The interval variable. |
absentValue | number | The value to use when the interval is absent. |
Returns
The resulting integer expression
Remarks
This function is equivalent to endOr(interval).guard(absentValue).
See
enforce()
enforce(
constraint:boolean|Constraint|BoolExpr|Iterable<boolean|Constraint|BoolExpr>):void
Enforces a boolean expression as a constraint in the model.
Parameters
| Parameter | Type | Description |
|---|---|---|
constraint | boolean | Constraint | BoolExpr | Iterable<boolean | Constraint | BoolExpr> | The constraint, boolean expression, or iterable of these to enforce in the model |
Returns
void
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:
- BoolExpr objects: Boolean expressions created from comparisons
(e.g.,
x <= 5,a == b) or logical operations (e.g.,a & b,~c). - bool values: Python boolean constants
TrueorFalse. - Constraint objects: Accepted but does nothing (constraints auto-register).
Use with cumulative constraints for clarity:
model.enforce(cumul <= capacity). - Iterables: Lists, tuples, or generators of the above types.
Examples
Basic usage with a boolean expression:
import * as CP from "optalcp";
const model = new CP.Model();
const x = model.intervalVar({ length: 10, name: "x" });
// Enforce boolean expressions as constraints
model.enforce(x.start().ge(0));
model.enforce(x.end().le(100));
Enforcing multiple constraints at once using an iterable:
const model = new CP.Model();
const tasks = Array.from({ length: 5 }, (_, i) =>
model.intervalVar({ length: 10, name: `task_${i}` })
);
// Enforce multiple constraints at once
const constraints = tasks.map(task => task.start().ge(0));
model.enforce(constraints);
// Or inline
model.enforce(tasks.map(task => task.end().le(100)));
Enforcing multiple boolean expressions:
const model = new CP.Model();
const x = model.intVar(0, 100, "x");
const y = model.intVar(0, 100, "y");
// Enforce various boolean expressions
model.enforce([
x.plus(y).le(50), // From comparison
x.ge(10), // From comparison
true, // Trivially satisfied constraint
]);
See
- BoolExpr.enforce for the fluent-style alternative.
- Model.noOverlap for creating no-overlap constraints.
- Model.minimize for creating minimization objectives.
- Model.maximize for creating maximization objectives.
eq()
Creates Boolean expression lhs = rhs.
Parameters
| Parameter | Type | Description |
|---|---|---|
lhs | number | IntExpr | The first integer expression. |
rhs | number | IntExpr | The second integer expression. |
Returns
The resulting Boolean expression
Remarks
If one of the arguments has value absent, then the resulting expression also has value absent.
Use Model.enforce to add this expression as a constraint to the model.
Same as IntExpr.eq.
eval()
eval(
func:IntStepFunction,arg:number|IntExpr):IntExpr
Evaluates a step function at a given point.
Parameters
| Parameter | Type | Description |
|---|---|---|
func | IntStepFunction | The step function. |
arg | number | IntExpr | The point at which to evaluate the step function. |
Returns
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
- IntStepFunction.eval for the equivalent function on IntStepFunction.
- Model.forbidStart, Model.forbidEnd are convenience functions built on top of
eval.
forbidEnd()
forbidEnd(
interval:IntervalVar,func:IntStepFunction):Constraint
Constrains the end of the interval variable to be outside of the zero-height segments of the step function.
Parameters
| Parameter | Type | Description |
|---|---|---|
interval | IntervalVar | The interval variable. |
func | IntStepFunction | The step function. |
Returns
Constraint
The constraint forbidding the end point.
Remarks
This function is equivalent to:
model.enforce(model.ne(model.eval(func, interval.end()), 0));
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):
See
- IntervalVar.forbidEnd for the equivalent function on IntervalVar.
- Model.forbidStart for similar function that constrains start an interval variable.
- Model.eval for evaluation of a step function.
forbidExtent()
forbidExtent(
interval:IntervalVar,func:IntStepFunction):Constraint
Forbid the interval variable to overlap with segments of the function where the value is zero.
Parameters
| Parameter | Type | Description |
|---|---|---|
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 is a segment of the step function where the value is zero, then the interval variable either ends before () or starts after ().
Example
A production task that cannot overlap with scheduled maintenance windows:
import * as CP from "optalcp";
const model = new CP.Model();
// A 3-hour production run
const production = model.intervalVar({ length: 3, name: "production" });
// Machine availability: 1 = available, 0 = under maintenance
const availability = model.stepFunction([
[0, 1], // Initially available
[8, 0], // 8h: maintenance starts
[10, 1], // 10h: maintenance ends
]);
// Production cannot overlap periods where availability is 0
model.forbidExtent(production, availability);
model.minimize(production.end());
const result = await model.solve();
// Production runs [0, 3) - finishes before maintenance window
See
- IntervalVar.forbidExtent for the equivalent function on IntervalVar.
- Model.forbidStart, Model.forbidEnd for similar functions that constrain the start/end of an interval variable.
- Model.eval for evaluation of a step function.
forbidStart()
forbidStart(
interval:IntervalVar,func:IntStepFunction):Constraint
Constrains the start of the interval variable to be outside of the zero-height segments of the step function.
Parameters
| Parameter | Type | Description |
|---|---|---|
interval | IntervalVar | The interval variable. |
func | IntStepFunction | The step function. |
Returns
Constraint
The constraint forbidding the start point.
Remarks
This function is equivalent to:
model.enforce(model.ne(model.eval(func, interval.start()), 0));
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):
See
- IntervalVar.forbidStart for the equivalent function on IntervalVar.
- Model.forbidEnd for similar function that constrains end an interval variable.
- Model.eval for evaluation of a step function.
ge()
Call Signature
Creates Boolean expression lhs ≥ rhs.
Parameters
| Parameter | Type | Description |
|---|---|---|
lhs | number | IntExpr | The first integer expression. |
rhs | number | IntExpr | The second integer expression. |
Returns
The resulting Boolean expression
Remarks
If one of the arguments has value absent, then the resulting expression also has value absent.
Use Model.enforce to add this expression as a constraint to the model.
Same as IntExpr.ge.
Call Signature
ge(
cumul:CumulExpr,minCapacity:number):Constraint
Constrains cumulative function cumul to be everywhere greater or equal to minCapacity.
Parameters
| Parameter | Type | Description |
|---|---|---|
cumul | CumulExpr | The cumulative expression. |
minCapacity | number | The minimum capacity value. |
Returns
Constraint
The constraint object
Remarks
This function can be used to specify the minimum limit of resource usage at any time. For example to make sure that there is never less than zero material on stock.
See Model.stepAtStart for an example with ge.
See
- CumulExpr.ge for the equivalent function on CumulExpr.
- Model.le for the opposite constraint.
getBoolVars()
getBoolVars():
BoolVar[]
Returns a list of all boolean variables in the model.
Returns
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.
See
Model.getIntervalVars, Model.getIntVars.
Example
import * as CP from "optalcp";
const model = new CP.Model();
const useMachineA = model.boolVar("use_machine_a");
const useMachineB = model.boolVar("use_machine_b");
const boolVars = model.getBoolVars();
console.log(boolVars.length); // 2
for (const bv of boolVars) {
console.log(bv.name); // "use_machine_a", "use_machine_b"
}
getIntervalVars()
getIntervalVars():
IntervalVar[]
Returns a list of all interval variables in the model.
Returns
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.
See
Model.getIntVars, Model.getBoolVars.
Example
import * as CP from "optalcp";
const model = new CP.Model();
const task1 = model.intervalVar({ length: 10, name: "task1" });
const task2 = model.intervalVar({ length: 20, name: "task2" });
const intervals = model.getIntervalVars();
console.log(intervals.length); // 2
for (const iv of intervals) {
console.log(iv.name); // "task1", "task2"
}
getIntVars()
getIntVars():
IntVar[]
Returns a list of all integer variables in the model.
Returns
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.
See
Model.getIntervalVars, Model.getBoolVars.
Example
import * as CP from "optalcp";
const model = new CP.Model();
const x = model.intVar(0, 10, "x");
const y = model.intVar(0, 100, "y");
const intVars = model.getIntVars();
console.log(intVars.length); // 2
for (const iv of intVars) {
console.log(iv.name); // "x", "y"
}
gt()
Creates Boolean expression lhs > rhs.
Parameters
| Parameter | Type | Description |
|---|---|---|
lhs | number | IntExpr | The first integer expression. |
rhs | number | IntExpr | The second integer expression. |
Returns
The resulting Boolean expression
Remarks
If one of the arguments has value absent, then the resulting expression also has value absent.
Use Model.enforce to add this expression as a constraint to the model.
Same as IntExpr.gt.
guard()
Creates an expression that replaces value absent by a constant.
Parameters
| Parameter | Type | Default value | Description |
|---|---|---|---|
arg | number | IntExpr | undefined | The integer expression to guard. |
absentValue | number | 0 | The value to use when the expression is absent. |
Returns
The resulting integer expression
Remarks
The resulting expression is:
- equal to
argifargis present - and equal to
absentValueotherwise (i.e. whenargis absent).
The default value of absentValue is 0.
The resulting expression is never absent.
Same as IntExpr.guard.
identity()
identity(
lhs:number|IntExpr,rhs:number|IntExpr):Constraint
Constrains lhs and rhs to be identical, including their presence status.
Parameters
| Parameter | Type | Description |
|---|---|---|
lhs | number | IntExpr | The first integer expression. |
rhs | number | IntExpr | The second integer expression. |
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()
implies(
lhs:boolean|BoolExpr,rhs:boolean|BoolExpr):BoolExpr
Logical implication of two boolean expressions, that is lhs implies rhs.
Parameters
| Parameter | Type | Description |
|---|---|---|
lhs | boolean | BoolExpr | The first boolean expression. |
rhs | boolean | BoolExpr | The second boolean expression. |
Returns
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()
inRange(
arg:number|IntExpr,lb:number,ub:number):BoolExpr
Creates Boolean expression lb ≤ arg ≤ ub.
Parameters
| Parameter | Type | Description |
|---|---|---|
arg | number | IntExpr | The integer expression to check. |
lb | number | The lower bound of the range. |
ub | number | The upper bound of the range. |
Returns
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.
integral()
integral(
func:IntStepFunction,interval:IntervalVar):IntExpr
Computes sum of values of the step function func over the interval interval.
Parameters
| Parameter | Type | Description |
|---|---|---|
func | IntStepFunction | The step function. |
interval | IntervalVar | The interval variable. |
Returns
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
IntStepFunction.integral for the equivalent function on IntStepFunction.
intervalVar()
intervalVar(
params: {end:number| [number?,number?];length:number| [number?,number?];name:string;optional:boolean;start:number| [number?,number?]; }):IntervalVar
Creates a new interval variable and adds it to the model.
Parameters
| Parameter | Type | Description |
|---|---|---|
params | { end: number | [number?, number?]; length: number | [number?, number?]; name: string; optional: boolean; start: number | [number?, number?]; } | - |
params.end? | number | [number?, number?] | Fixed end time or range [min, max] (default [0, IntervalMax]) |
params.length? | number | [number?, number?] | Fixed length or range [min, max] (default [0, IntervalMax]) |
params.name? | string | Name of the interval for debugging and display |
params.optional? | boolean | Whether the interval is optional (default false) |
params.start? | number | [number?, number?] | Fixed start time or range [min, max] (default [0, IntervalMax]) |
Returns
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 params.start, params.end, and params.length can be either a
number or a tuple of two numbers. If a number is given, it represents a
fixed value. If a tuple is given, it represents a range of possible values.
The default range for start, end and length is 0 to IntervalMax.
If a range is specified but one of the values is undefined (e.g. start: [, 100])
then the default value is used instead (in our case 0).
Example
let model = new CP.Model();
// Create a present interval variable with a fixed start but unknown length:
let x = model.intervalVar({ start: 0, length: [10, 20], name: "x" });
// Create an interval variable with a start and end ranges:
let y = model.intervalVar({ start: [0, 5], end: [10, 15], name: "y" });
// Create an optional interval variable with a length interval 5..10:
let z = model.intervalVar({ length: [5, 10], optional: true, name: "z" });
See
intVar()
intVar(
params?: {max:number;min:number;name:string;optional:boolean; }):IntVar
Creates a new integer variable and adds it to the model.
Parameters
| Parameter | Type | Description |
|---|---|---|
params? | { max: number; min: number; name: string; optional: boolean; } | - |
params.max? | number | Maximum value of the variable (default IntVarMax) |
params.min? | number | Minimum value of the variable (default 0) |
params.name? | string | Name of the variable for debugging and display |
params.optional? | boolean | Whether the variable is optional (default false) |
Returns
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.
Example
let model = new CP.Model();
// Create a present integer variable with possible values 1..10:
let x = model.intVar({ min: 1, max: 10, name: "x" });
// Create an optional integer variable with possible values 5..IntVarMax:
let y = model.intVar({ min: 5, optional: true, name: "y" });
// Create an integer variable with a fixed value 10 (optional):
let z = model.intVar({ min: 10, max: 10, optional: true, name: "z" });
le()
Call Signature
Creates Boolean expression lhs ≤ rhs.
Parameters
| Parameter | Type | Description |
|---|---|---|
lhs | number | IntExpr | The first integer expression. |
rhs | number | IntExpr | The second integer expression. |
Returns
The resulting Boolean expression
Remarks
If one of the arguments has value absent, then the resulting expression also has value absent.
Use Model.enforce to add this expression as a constraint to the model.
Same as IntExpr.le.
Call Signature
le(
cumul:CumulExpr,maxCapacity:number):Constraint
Constrains cumulative function cumul to be everywhere less or equal to maxCapacity.
Parameters
| Parameter | Type | Description |
|---|---|---|
cumul | CumulExpr | The cumulative expression. |
maxCapacity | number | The maximum capacity value. |
Returns
Constraint
The constraint object
Remarks
This function can be used to specify the maximum limit of resource usage at any time. For example, to limit the number of workers working simultaneously, limit the maximum amount of material on stock, etc.
See Model.pulse for an example with le.
See
- CumulExpr.le for the equivalent function on CumulExpr.
- Model.ge for the opposite constraint.
length()
length(
interval:IntervalVar):IntExpr
Creates an integer expression for the duration (end - start) of an interval variable.
Parameters
| Parameter | Type | Description |
|---|---|---|
interval | IntervalVar | The interval variable. |
Returns
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.
let model = new CP.Model;
let x = model.intervalVar({ name: "x", ... });
let y = model.intervalVar({ name: "y", ... });
model.enforce(model.end(x).plus(10).le(model.start(y)));
model.enforce(model.length(x).le(model.length(y)));
When x or y is absent then value of both constraints above is absent and therefore they are satisfied.
See
IntervalVar.length is equivalent function on IntervalVar.
lengthOr()
lengthOr(
interval:IntervalVar,absentValue:number):IntExpr
Creates an integer expression for the duration (end - start) of the interval variable. If the interval is absent, then its value is absentValue.
Parameters
| Parameter | Type | Description |
|---|---|---|
interval | IntervalVar | The interval variable. |
absentValue | number | The value to use when the interval is absent. |
Returns
The resulting integer expression
Remarks
This function is equivalent to lengthOr(interval).guard(absentValue).
See
lexGe()
lexGe(
lhs: (number|IntExpr)[],rhs: (number|IntExpr)[]):Constraint
Lexicographic greater than or equal constraint: lhs ≥ rhs.
Parameters
| Parameter | Type | Description |
|---|---|---|
lhs | (number | IntExpr)[] | The left-hand side array of integer expressions. |
rhs | (number | 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 lhs ≥ rhs holds if and only if:
- all elements are equal (
lhs[i] == rhs[i]for alli), or - there exists a position
kwherelhs[k] > rhs[k]and all preceding elements are equal (lhs[i] == rhs[i]for alli < 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
const model = new CP.Model();
// Variables for a 3x3 matrix where rows should be lexicographically ordered
const rows = Array.from({ length: 3 }, (_, i) =>
Array.from({ length: 3 }, (_, j) => model.intVar(0, 9, `x_${i}_${j}`))
);
// Break row symmetry: row[0] ≥ row[1] ≥ row[2] lexicographically
model.lexGe(rows[0], rows[1]);
model.lexGe(rows[1], rows[2]);
See
Model.lexLe, Model.lexLt, Model.lexGt for other lexicographic comparisons.
lexGt()
lexGt(
lhs: (number|IntExpr)[],rhs: (number|IntExpr)[]):Constraint
Lexicographic strictly greater than constraint: lhs > rhs.
Parameters
| Parameter | Type | Description |
|---|---|---|
lhs | (number | IntExpr)[] | The left-hand side array of integer expressions. |
rhs | (number | 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
const model = new CP.Model();
// Variables for a 3x3 matrix where rows should be lexicographically ordered
const rows = Array.from({ length: 3 }, (_, i) =>
Array.from({ length: 3 }, (_, j) => model.intVar(0, 9, `x_${i}_${j}`))
);
// Break row symmetry: row[0] > row[1] > row[2] lexicographically
model.lexGt(rows[0], rows[1]);
model.lexGt(rows[1], rows[2]);
See
Model.lexLe, Model.lexLt, Model.lexGe for other lexicographic comparisons.
lexLe()
lexLe(
lhs: (number|IntExpr)[],rhs: (number|IntExpr)[]):Constraint
Lexicographic less than or equal constraint: lhs ≤ rhs.
Parameters
| Parameter | Type | Description |
|---|---|---|
lhs | (number | IntExpr)[] | The left-hand side array of integer expressions. |
rhs | (number | 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 lhs ≤ rhs holds if and only if:
- all elements are equal (
lhs[i] == rhs[i]for alli), or - there exists a position
kwherelhs[k] < rhs[k]and all preceding elements are equal (lhs[i] == rhs[i]for alli < 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
const model = new CP.Model();
// Variables for a 3x3 matrix where rows should be lexicographically ordered
const rows = Array.from({ length: 3 }, (_, i) =>
Array.from({ length: 3 }, (_, j) => model.intVar(0, 9, `x_${i}_${j}`))
);
// Break row symmetry: row[0] ≤ row[1] ≤ row[2] lexicographically
model.lexLe(rows[0], rows[1]);
model.lexLe(rows[1], rows[2]);
See
Model.lexLt, Model.lexGe, Model.lexGt for other lexicographic comparisons.
lexLt()
lexLt(
lhs: (number|IntExpr)[],rhs: (number|IntExpr)[]):Constraint
Lexicographic strictly less than constraint: lhs < rhs.
Parameters
| Parameter | Type | Description |
|---|---|---|
lhs | (number | IntExpr)[] | The left-hand side array of integer expressions. |
rhs | (number | 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
const model = new CP.Model();
// Variables for a 3x3 matrix where rows should be lexicographically ordered
const rows = Array.from({ length: 3 }, (_, i) =>
Array.from({ length: 3 }, (_, j) => model.intVar(0, 9, `x_${i}_${j}`))
);
// Break row symmetry: row[0] < row[1] < row[2] lexicographically
model.lexLt(rows[0], rows[1]);
model.lexLt(rows[1], rows[2]);
See
Model.lexLe, Model.lexGe, Model.lexGt for other lexicographic comparisons.
lt()
Creates Boolean expression lhs < rhs.
Parameters
| Parameter | Type | Description |
|---|---|---|
lhs | number | IntExpr | The first integer expression. |
rhs | number | IntExpr | The second integer expression. |
Returns
The resulting Boolean expression
Remarks
If one of the arguments has value absent, then the resulting expression also has value absent.
Use Model.enforce to add this expression as a constraint to the model.
Same as IntExpr.lt.
max()
Creates an integer expression for the maximum of the arguments.
Parameters
| Parameter | Type | Description |
|---|---|---|
args | (number | IntExpr)[] | Array of integer expressions to compute maximum of. |
Returns
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).
let model = new CP.Model;
let tasks: CP.IntervalVar[] = ...;
...
// Create an array of end times of the tasks:
let endTimes = tasks.map(task => task.end());
let 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
- Binary Model.max2.
- Function Model.span constraints interval variable to start and end at minimum and maximum of the given set of intervals.
max2()
Creates an integer expression which is the maximum of lhs and rhs.
Parameters
| Parameter | Type | Description |
|---|---|---|
lhs | number | IntExpr | The first integer expression. |
rhs | number | IntExpr | The second integer expression. |
Returns
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()
Creates a maximization objective for the provided expression.
Parameters
| Parameter | Type | Description |
|---|---|---|
expr | number | IntExpr | The expression to maximize |
Returns
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:
let model = new CP.Model;
let x = model.intervalVar({ length: [10, 20], name: "x" });
model.maximize(x.length());
let result = await model.solve();
See
- Model.minimize.
- IntExpr.maximize for fluent-style maximization.
min()
Creates an integer expression for the minimum of the arguments.
Parameters
| Parameter | Type | Description |
|---|---|---|
args | (number | IntExpr)[] | Array of integer expressions to compute minimum of. |
Returns
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.
let model = new CP.Model;
let tasks: CP.IntervalVar[] = ...;
...
// Create an array of start times of the tasks:
let startTimes = tasks.map(task => task.start());
let 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
- Binary Model.min2.
- Function Model.span constraints interval variable to start and end at minimum and maximum of the given set of intervals.
min2()
Creates an integer expression which is the minimum of lhs and rhs.
Parameters
| Parameter | Type | Description |
|---|---|---|
lhs | number | IntExpr | The first integer expression. |
rhs | number | IntExpr | The second integer expression. |
Returns
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()
Creates a minimization objective for the provided expression.
Parameters
| Parameter | Type | Description |
|---|---|---|
expr | number | IntExpr | The expression to minimize |
Returns
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:
let model = new CP.Model();
let x = model.intervalVar({ length: 10, name: "x" });
let y = model.intervalVar({ length: 20, name: "y" });
model.minimize(model.max2(x.end(), y.end()));
let result = await model.solve();
See
- Model.maximize.
- IntExpr.minimize for fluent-style minimization.
minus()
Call Signature
minus(
lhs:number|IntExpr,rhs:number|IntExpr):IntExpr
Creates a subtraction of the two integer expressions, i.e. lhs - rhs.
Parameters
| Parameter | Type | Description |
|---|---|---|
lhs | number | IntExpr | The first integer expression. |
rhs | number | IntExpr | The second integer expression. |
Returns
The resulting integer expression
Remarks
If one of the arguments has value absent, then the resulting expression also has value absent.
Same as IntExpr.minus.
Call Signature
Subtraction of two cumulative expressions.
Parameters
| Parameter | Type | Description |
|---|---|---|
lhs | CumulExpr | The left-hand side cumulative expression. |
rhs | CumulExpr | The right-hand side cumulative expression. |
Returns
The resulting cumulative expression
Remarks
Computes subtraction of two cumulative functions.
Formal definition
Let result = minus(lhs, rhs). Then for any number x in range IntervalMin..IntervalMax the value of result at x is equal to lhs at x minus rhs at x.
minus(lhs, rhs) is the same as sum([lhs, neg(rhs)]).
See
- CumulExpr.minus for the equivalent function on CumulExpr.
- Model.sum, Model.plus, Model.neg for other ways to combine cumulative functions.
ne()
Creates Boolean expression lhs ≠ rhs.
Parameters
| Parameter | Type | Description |
|---|---|---|
lhs | number | IntExpr | The first integer expression. |
rhs | number | IntExpr | The second integer expression. |
Returns
The resulting Boolean expression
Remarks
If one of the arguments has value absent, then the resulting expression also has value absent.
Use Model.enforce to add this expression as a constraint to the model.
Same as IntExpr.ne.
neg()
Call Signature
Creates negation of the integer expression, i.e. -arg.
Parameters
| Parameter | Type | Description |
|---|---|---|
arg | number | IntExpr | The integer expression. |
Returns
The resulting integer expression
Remarks
If the value of arg has value absent then the resulting expression has also value absent.
Same as IntExpr.neg.
Call Signature
Negation of a cumulative expression.
Parameters
| Parameter | Type | Description |
|---|---|---|
arg | CumulExpr | The cumulative expression. |
Returns
The resulting cumulative expression
Remarks
Computes negation of a cumulative function. That is, the resulting function has the opposite values.
See
- CumulExpr.neg for the equivalent function on CumulExpr.
- Model.sum, Model.plus, Model.minus for other ways to combine cumulative functions.
noOverlap()
noOverlap(
intervals:IntervalVar[] |SequenceVar,transitions?:number[][]):void
Constrain a set of interval variables not to overlap.
Parameters
| Parameter | Type | Description |
|---|---|---|
intervals | IntervalVar[] | SequenceVar | An array of interval variables or a sequence variable to constrain |
transitions? | number[][] | A 2D square array of minimum transition times between the intervals |
Returns
void
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:
- Interval variable
xoryis 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. - Interval variable
xis beforey, that is,x.end()is less than or equal toy.start(). - The interval variable
yis beforex. That is,y.end()is less than or equal tox.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:
x.end() + transitions[i][j]is less than or equal toy.start().y.end() + transitions[j][i]is less than or equal tox.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.
import * as CP from "optalcp";
const tasks = [
{ length: 10, deadline: 70 },
{ length: 20, deadline: 50 },
{ length: 15, deadline: 50 },
{ length: 30, deadline: 100 },
{ length: 20, deadline: 120 },
{ length: 25, deadline: 90 },
{ length: 30, deadline: 80 },
{ length: 10, deadline: 40 },
{ length: 20, deadline: 60 },
{ length: 25, deadline: 150 },
];
const model = new CP.Model();
// An interval variable for each task:
const taskVars = [];
// A boolean expression that is true if the task is late:
const isLate = [];
for (let i = 0; i < tasks.length; i++) {
const task = tasks[i];
const taskVar = model.intervalVar({ name: `Task${i}`, length: task.length });
taskVars.push(taskVar);
isLate.push(taskVar.end().ge(task.deadline));
}
// Tasks cannot overlap:
model.noOverlap(taskVars);
// Minimize the number of late tasks:
model.minimize(model.sum(isLate));
const result = await model.solve();
See
SequenceVar.noOverlap is the equivalent method on SequenceVar.
not()
Negation of the boolean expression arg.
Parameters
| Parameter | Type | Description |
|---|---|---|
arg | boolean | BoolExpr | The boolean expression to negate. |
Returns
The resulting Boolean expression
Remarks
If the argument has value absent then the resulting expression has also value absent.
Same as BoolExpr.not.
or()
or(
lhs:boolean|BoolExpr,rhs:boolean|BoolExpr):BoolExpr
Logical OR of boolean expressions lhs and rhs.
Parameters
| Parameter | Type | Description |
|---|---|---|
lhs | boolean | BoolExpr | The first boolean expression. |
rhs | boolean | BoolExpr | The second boolean expression. |
Returns
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.
plus()
Call Signature
Creates an addition of the two integer expressions, i.e. lhs + rhs.
Parameters
| Parameter | Type | Description |
|---|---|---|
lhs | number | IntExpr | The first integer expression. |
rhs | number | IntExpr | The second integer expression. |
Returns
The resulting integer expression
Remarks
If one of the arguments has value absent, then the resulting expression also has value absent.
Same as IntExpr.plus.
Call Signature
Addition of two cumulative expressions.
Parameters
| Parameter | Type | Description |
|---|---|---|
lhs | CumulExpr | The left-hand side cumulative expression. |
rhs | CumulExpr | The right-hand side cumulative expression. |
Returns
The resulting cumulative expression
Remarks
Computes addition of two cumulative functions.
Formal definition
Let result = plus(lhs, rhs). Then for any number x in range IntervalMin..IntervalMax the value of result at x is equal to lhs at x plus rhs at x.
plus(lhs, rhs) is the same as sum([lhs, rhs]).
See
- CumulExpr.plus for the equivalent function on CumulExpr.
- Model.sum, Model.minus, Model.neg for other ways to combine cumulative functions.
position()
position(
interval:IntervalVar,sequence:SequenceVar):IntExpr
Creates an expression equal to the position of the interval on the sequence.
Parameters
| Parameter | Type | Description |
|---|---|---|
interval | IntervalVar | The interval variable. |
sequence | SequenceVar | The sequence variable. |
Returns
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
- IntervalVar.position is equivalent function on IntervalVar.
- Model.noOverlap for constraints on overlapping intervals.
- Model.sequenceVar for creating sequence variables.
presence()
presence(
arg:number|boolean|IntExpr|IntervalVar):BoolExpr
Creates a boolean expression that is true if the given argument is present in the solution.
Parameters
| Parameter | Type | Description |
|---|---|---|
arg | number | boolean | IntExpr | IntervalVar | The argument to check for presence in the solution |
Returns
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.
const model = new CP.Model();
let x = model.intervalVar({ name: "x", optional: true, length: 10, start: [0, 100] });
let y = model.intervalVar({ name: "y", optional: true, length: 10, start: [0, 100] });
model.enforce(model.presence(x).eq(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:
let x = model.intervalVar({ name: "x", optional: true, length: 10, start: [0, 100] });
let y = model.intervalVar({ name: "y", optional: true, length: 10, start: [0, 100] });
model.enforce(model.presence(x).eq(model.presence(y)));
// x.end <= y.start:
let precedence = x.end().le(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()
pulse(
interval:IntervalVar,height:number|IntExpr):CumulExpr
Creates cumulative function (expression) pulse for the given interval variable and height.
Parameters
| Parameter | Type | Description |
|---|---|---|
interval | IntervalVar | The interval variable. |
height | number | IntExpr | The height value. |
Returns
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:
0beforeinterval.start(),heightbetweeninterval.start()andinterval.end(),0afterinterval.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 CumulExpr.plus, CumulExpr.minus, CumulExpr.neg and Model.sum. A cumulative function's minimum and maximum height can be constrained using CumulExpr.le and CumulExpr.ge.
Examples
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:
const nbWorkers = 3;
const tasks = [
{ length: 10, demand: 3},
{ length: 20, demand: 2},
{ length: 15, demand: 1},
{ length: 30, demand: 2},
{ length: 20, demand: 1},
{ length: 25, demand: 2},
{ length: 10, demand: 1},
];
let model = new CP.Model;
// A set of pulses, one for each task:
let pulses: CP.CumulExpr[] = [];
// End times of the tasks:
let ends: CP.IntExpr[] = [];
for (let i = 0; i < tasks.length; i++) {
// Create a task:
let task = model.intervalVar({ name: "T" + (i+1), length: tasks[i].length} );
// Create a pulse for the task:
pulses.push(model.pulse(task, tasks[i].demand));
// Store the end of the task:
ends.push(task.end());
}
// The number of workers used at any time cannot exceed nbWorkers:
model.le(model.sum(pulses), nbWorkers);
// Minimize the maximum of the ends (makespan):
model.minimize(model.max(ends));
let result = await model.solve({ searchType: "FDS" });
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.
let model = CP.Model;
let x = model.intervalVar({ name: "x" });
let y = model.intervalVar({ name: "y" });
let z = model.intervalVar({ name: "z", optional: true });
let wx = model.intVar({ range: [1, 5], name: "wx" });
let wy = model.intVar({ range: [1, 5], name: "wy" });
let wz = model.intVar({ range: [1, 5], name: "wz", optional: true });
// wz is present if an only if z is present:
model.enforce(z.presence().eq(wz.presence()));
let px = model.pulse(x, wx);
let py = model.pulse(y, wy);
let pz = model.pulse(z, wz);
// There are at most 7 workers at any time:
model.sum([px, py, pz]).le(7);
// Length of the task depends on the number of workers using the following formula:
// length * wx = 12
model.enforce(x.length().times(wx).eq(12));
model.enforce(y.length().times(wy).eq(12));
model.enforce(z.length().times(wz).eq(12));
See
- IntervalVar.pulse is equivalent function on IntervalVar.
- Model.stepAtStart, Model.stepAtEnd, Model.stepAt for other basic cumulative functions.
- CumulExpr.le and CumulExpr.ge for constraints on cumulative functions.
sequenceVar()
sequenceVar(
intervals:IntervalVar[],types?:number[],name?:string):SequenceVar
Creates a sequence variable from the provided set of interval variables.
Parameters
| Parameter | Type | Description |
|---|---|---|
intervals | IntervalVar[] | Interval variables that will form the sequence in the solution |
types? | number[] | Types of the intervals, used in particular for transition times |
name? | string | Name assigned to the sequence variable |
Returns
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
- SequenceVar.noOverlap for an example of sequenceVar usage with transition times.
- SequenceVar.
- Model.noOverlap.
span()
span(
main:IntervalVar,covered:IntervalVar[]):Constraint
Constrains an interval variable to span (cover) a set of other interval variables.
Parameters
| Parameter | Type | Description |
|---|---|---|
main | IntervalVar | The spanning interval variable. |
covered | 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
mainis absent and all interval variables incoveredare absent too. -
Interval variable
mainis present, at least one interval incoveredis present and:main.start()is equal to the minimum starting time of all present intervals incovered.main.end()is equal to the maximum ending time of all present intervals incovered.
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.
let model = new CP.Model;
// Subtasks have known lengths:
let T1 = model.intervalVar({ name: "T1", length: 10 });
let T2 = model.intervalVar({ name: "T2", length: 5 });
let T3 = model.intervalVar({ name: "T3", length: 15 });
// The main task has unknown length though:
let T = model.intervalVar({ name: "T" });
// T spans/covers T1, T2 and T3:
model.span(T, [T1, T2, T3]);
// Tasks requiring the same location cannot overlap.
// Other tasks are not included in the example, therefore '...' below:
model.noOverlap([T, ...]);
See
IntervalVar.span is equivalent function on IntervalVar.
start()
start(
interval:IntervalVar):IntExpr
Creates an integer expression for the start time of an interval variable.
Parameters
| Parameter | Type | Description |
|---|---|---|
interval | IntervalVar | The interval variable. |
Returns
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.
let model = new CP.Model;
let x = model.intervalVar({ name: "x", ... });
let y = model.intervalVar({ name: "y", ... });
model.enforce(model.end(x).plus(10).le(model.start(y)));
model.enforce(model.length(x).le(model.length(y)));
When x or y is absent then value of both constraints above is absent and therefore they are satisfied.
See
IntervalVar.start is equivalent function on IntervalVar.
startAtEnd()
startAtEnd(
predecessor:IntervalVar,successor:IntervalVar,delay:number|IntExpr):Constraint
Creates a precedence constraint between two interval variables.
Parameters
| Parameter | Type | Default value | Description |
|---|---|---|---|
predecessor | IntervalVar | undefined | The predecessor interval variable. |
successor | IntervalVar | undefined | The successor interval variable. |
delay | number | IntExpr | 0 | The minimum delay between intervals. |
Returns
Constraint
The precedence constraint.
Remarks
Same as:
model.enforce(predecessor.start().plus(delay).eq(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
- IntervalVar.startAtEnd is equivalent function on IntervalVar.
- IntervalVar.start, IntervalVar.end
- IntExpr.eq
startAtStart()
startAtStart(
predecessor:IntervalVar,successor:IntervalVar,delay:number|IntExpr):Constraint
Creates a precedence constraint between two interval variables.
Parameters
| Parameter | Type | Default value | Description |
|---|---|---|---|
predecessor | IntervalVar | undefined | The predecessor interval variable. |
successor | IntervalVar | undefined | The successor interval variable. |
delay | number | IntExpr | 0 | The minimum delay between intervals. |
Returns
Constraint
The precedence constraint.
Remarks
Same as:
model.enforce(predecessor.start().plus(delay).eq(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
- IntervalVar.startAtStart is equivalent function on IntervalVar.
- IntervalVar.start, IntervalVar.end
- IntExpr.eq
startBeforeEnd()
startBeforeEnd(
predecessor:IntervalVar,successor:IntervalVar,delay:number|IntExpr):Constraint
Creates a precedence constraint between two interval variables.
Parameters
| Parameter | Type | Default value | Description |
|---|---|---|---|
predecessor | IntervalVar | undefined | The predecessor interval variable. |
successor | IntervalVar | undefined | The successor interval variable. |
delay | number | IntExpr | 0 | The minimum delay between intervals. |
Returns
Constraint
The precedence constraint.
Remarks
Same as:
model.enforce(predecessor.start().plus(delay).le(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
- IntervalVar.startBeforeEnd is equivalent function on IntervalVar.
- IntervalVar.start, IntervalVar.end
- IntExpr.le
startBeforeStart()
startBeforeStart(
predecessor:IntervalVar,successor:IntervalVar,delay:number|IntExpr):Constraint
Creates a precedence constraint between two interval variables.
Parameters
| Parameter | Type | Default value | Description |
|---|---|---|---|
predecessor | IntervalVar | undefined | The predecessor interval variable. |
successor | IntervalVar | undefined | The successor interval variable. |
delay | number | IntExpr | 0 | The minimum delay between intervals. |
Returns
Constraint
The precedence constraint.
Remarks
Same as:
model.enforce(predecessor.start().plus(delay).le(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
- IntervalVar.startBeforeStart is equivalent function on IntervalVar.
- IntervalVar.start, IntervalVar.end
- IntExpr.le
startOr()
startOr(
interval:IntervalVar,absentValue:number):IntExpr
Creates an integer expression for the start time of the interval variable. If the interval is absent, then its value is absentValue.
Parameters
| Parameter | Type | Description |
|---|---|---|
interval | IntervalVar | The interval variable. |
absentValue | number | The value to use when the interval is absent. |
Returns
The resulting integer expression
Remarks
This function is equivalent to startOr(interval).guard(absentValue).
See
stepAt()
Creates a cumulative function that changes value at a given point.
Parameters
| Parameter | Type | Description |
|---|---|---|
x | number | The point at which the cumulative function changes value. |
height | number | IntExpr | The height value (can be positive, negative, constant, or expression). |
Returns
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, heightafterx.
See
- Model.stepAtStart, Model.stepAtEnd for an example with
stepAt. - CumulExpr.le and CumulExpr.ge for constraints on cumulative functions.
stepAtEnd()
stepAtEnd(
interval:IntervalVar,height:number|IntExpr):CumulExpr
Creates cumulative function (expression) that changes value at end of the interval variable by the given height.
Parameters
| Parameter | Type | Description |
|---|---|---|
interval | IntervalVar | The interval variable. |
height | number | IntExpr | The height value. |
Returns
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 could be combined using CumulExpr.plus, CumulExpr.minus, CumulExpr.neg and Model.sum. A cumulative function's minimum and maximum height can be constrained using CumulExpr.le and CumulExpr.ge.
Formal definition
stepAtEnd creates a cumulative function which has the value:
0beforeinterval.end(),heightafterinterval.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:
const budget = 100;
const tasks = [
{ 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 },
];
let model = new CP.Model;
let taskVars: CP.IntervalVar[] = [];
// A set of steps, one for each task:
let steps: CP.CumulExpr[] = [];
for (let i = 0; i < tasks.length; i++) {
let interval = model.intervalVar({ name: "T" + (i+1), length: tasks[i].length} );
taskVars.push(interval);
if (tasks[i].money < 0) {
// Task costs some money:
steps.push(model.stepAtStart(interval, tasks[i].money));
} else {
// Tasks makes some money:
steps.push(model.stepAtEnd(interval, tasks[i].money));
}
}
// The initial budget increases the cumul at time 0:
steps.push(model.stepAt(0, budget));
// The money must be non-negative at any time:
model.ge(model.sum(steps), 0);
// Only one task at a time:
model.noOverlap(taskVars);
// Minimize the maximum of the ends (makespan):
model.max(taskVars.map(t => t.end())).minimize();
let result = await model.solve({ searchType: "FDS"});
See
- IntervalVar.stepAtEnd is equivalent function on IntervalVar.
- Model.stepAtStart, Model.stepAt, Model.pulse for other basic cumulative functions.
- CumulExpr.le and CumulExpr.ge for constraints on cumulative functions.
stepAtStart()
stepAtStart(
interval:IntervalVar,height:number|IntExpr):CumulExpr
Creates cumulative function (expression) that changes value at start of the interval variable by the given height.
Parameters
| Parameter | Type | Description |
|---|---|---|
interval | IntervalVar | The interval variable. |
height | number | IntExpr | The height value. |
Returns
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 could be combined using CumulExpr.plus, CumulExpr.minus, CumulExpr.neg and Model.sum. A cumulative function's minimum and maximum height can be constrained using CumulExpr.le and CumulExpr.ge.
Formal definition
stepAtStart creates a cumulative function which has the value:
0beforeinterval.start(),heightafterinterval.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:
const budget = 100;
const tasks = [
{ 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 },
];
let model = new CP.Model;
let taskVars: CP.IntervalVar[] = [];
// A set of steps, one for each task:
let steps: CP.CumulExpr[] = [];
for (let i = 0; i < tasks.length; i++) {
let interval = model.intervalVar({ name: "T" + (i+1), length: tasks[i].length} );
taskVars.push(interval);
if (tasks[i].money < 0) {
// Task costs some money:
steps.push(model.stepAtStart(interval, tasks[i].money));
} else {
// Tasks makes some money:
steps.push(model.stepAtEnd(interval, tasks[i].money));
}
}
// The initial budget increases the cumul at time 0:
steps.push(model.stepAt(0, budget));
// The money must be non-negative at any time:
model.ge(model.sum(steps), 0);
// Only one task at a time:
model.noOverlap(taskVars);
// Minimize the maximum of the ends (makespan):
model.max(taskVars.map(t => t.end())).minimize();
let result = await model.solve({ searchType: "FDS"});
See
- IntervalVar.stepAtStart is equivalent function on IntervalVar.
- Model.stepAtEnd, Model.stepAt, Model.pulse for other basic cumulative functions.
- CumulExpr.le and CumulExpr.ge for constraints on cumulative functions.
stepFunction()
stepFunction(
values:number[][]):IntStepFunction
Creates a new integer step function.
Parameters
| Parameter | Type | Description |
|---|---|---|
values | number[][] | 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
The created step function
Remarks
Integer step function is a piecewise constant function defined on integer values in range IntVarMin to IntVarMax. The function is defined as follows:
- for ,
- for
- for .
Step functions can be used in the following ways:
- Function Model.eval evaluates the function at the given point (given as IntExpr).
- Function Model.integral computes a sum (integral) of the function over an IntervalVar.
- Constraints Model.forbidStart and Model.forbidEnd forbid the start/end of an IntervalVar to be in a zero-value interval of the function.
- Constraint Model.forbidExtent forbids the extent of an IntervalVar to be in a zero-value interval of the function.
sum()
Call Signature
Creates an integer expression for the sum of the arguments.
Parameters
| Parameter | Type | Description |
|---|---|---|
args | (number | IntExpr)[] | Array of integer expressions to sum. |
Returns
The resulting integer expression
Remarks
Absent arguments are ignored (treated as zeros). Therefore, the resulting expression is never absent.
Note that binary function Model.plus handles absent values differently. For example, when x is absent then:
plus(x, 3)is absent.sum([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:
const lengths = [10, 20, 15, 30, 20, 25, 30, 10, 20, 25];
const profits = [ 5, 6, 7, 8, 9, 10, 11, 12, 13, 14];
let model = new CP.Model;
let tasks: CP.IntervalVar[] = [];
// Profits of individual tasks. The value will be zero if the task is not executed.
let taskProfits: CP.IntExpr[] = [];
for (let i = 0; i < lengths.length; i++) {
// All tasks must finish before time 100:
let task = model.intervalVar({ name: "Task" + i, optional: true, length: lengths[i], end: [, 100]});
tasks.push(task);
taskProfits.push(model.times(task.presence(), profits[i]));
}
model.sum(taskProfits).maximize();
// Tasks cannot overlap:
model.noOverlap(tasks);
let result = await model.solve({ searchType: "FDS" });
Call Signature
Sum of cumulative expressions.
Parameters
| Parameter | Type | Description |
|---|---|---|
args | CumulExpr[] | Array of cumulative expressions to sum. |
Returns
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.
times()
times(
lhs:number|IntExpr,rhs:number|IntExpr):IntExpr
Creates a multiplication of the two integer expressions, i.e. lhs * rhs.
Parameters
| Parameter | Type | Description |
|---|---|---|
lhs | number | IntExpr | The first integer expression. |
rhs | number | IntExpr | The second integer expression. |
Returns
The resulting integer expression
Remarks
If one of the arguments has value absent, then the resulting expression also has value absent.
Same as IntExpr.times.