discrete_optimization.generic_tasks_tools.solvers.cpsat package

Subpackages

Submodules

discrete_optimization.generic_tasks_tools.solvers.cpsat.allocation module

class discrete_optimization.generic_tasks_tools.solvers.cpsat.allocation.AllocationBinaryOrIntegerModellingCpSatSolver(problem: Problem, params_objective_function: ParamsObjectiveFunction | None = None, **kwargs: Any)[source]

Bases: AllocationIntegerModellingCpSatSolver[Task, UnaryResource]

Base class for allocation cp-sat solvers using a binary or integer modelling.

add_allocation_changes_constraints(ref: AllocationSolution[Task, UnaryResource]) → list[Any][source]

Add and return constraints so that change variables reflect diff to ref.

add_constraint_on_task_unary_resource_allocation(task: Task, unary_resource: UnaryResource, used: bool) → list[Any][source]

Add constraint on allocation of given unary resource for the given task

Parameters:
  • task

  • unary_resource

  • used – if True, we enforce the allocation of unary_resource to task, else we prevent it

Returns:

resulting constraints

allocation_modelling: AllocationModelling
abstractmethod get_binary_allocation_variable(task: Task, unary_resource: UnaryResource) → LinearExpr | IntVar | int | int8 | uint8 | int32 | uint32 | int64 | uint64[source]

“Return a 0-1 variable/expression telling if the unary_resource is used for the task.

Only to be called when allocation_modelling == AllocationModelling.BINARY.

NB: sometimes the given resource is never to be used by a task and the variable has not been created. The convention is to return 0 in that case.

abstractmethod get_integer_allocation_variable(task: Task) → LinearExpr | IntVar | int | int8 | uint8 | int32 | uint32 | int64 | uint64[source]

Return an integer variable/expression storing the index of the allocated unary_resource.

Assumes that exactly one unary resource is allocated to a task. Only to be called when allocation_modelling == AllocationModelling.INTEGER.

Parameters:

task

Returns:

get_task_allocation_variable(task: Task) → LinearExpr | IntVar | int | int8 | uint8 | int32 | uint32 | int64 | uint64[source]

Return an integer variable/expression storing the index of the allocated unary_resource.

Assumes that exactly one unary resource is allocated to a task.

get_task_unary_resource_is_present_variable(task: Task, unary_resource: UnaryResource) → LinearExpr | IntVar | int | int8 | uint8 | int32 | uint32 | int64 | uint64[source]

Return a 0-1 variable/expression telling if the unary_resource is used for the task.

NB: sometimes the given resource is never to be used by a task and the variable has not been created. The convention is to return 0 in that case.

class discrete_optimization.generic_tasks_tools.solvers.cpsat.allocation.AllocationCpSatSolver(problem: Problem, params_objective_function: ParamsObjectiveFunction | None = None, **kwargs: Any)[source]

Bases: TasksCpSatSolver[Task], AllocationCpSolver[Task, UnaryResource]

Base class for allocation cp-sat solvers using a binary modelling.

I.e. using 0-1 variables to model allocation status of each couple (task, unary_resource) This is a more general modelisation thant the integer one as it allows allocation of multiple resources.

add_allocation_changes_constraints(ref: AllocationSolution[Task, UnaryResource]) → list[Any][source]

Add and return constraints so that change variables reflect diff to ref.

add_allocation_constraints()[source]
add_constraint_nb_unary_resource_usages(sign: SignEnum, target: int, tasks: Iterable[Task] | None = None, unary_resources: Iterable[UnaryResource] | None = None) → list[Any][source]
add_constraint_on_nb_allocation_changes(ref: AllocationSolution[Task, UnaryResource], nb_changes: int, sign: SignEnum = SignEnum.LEQ) → list[Any][source]

Add contraint on maximal number of allocation changes from the given reference.

Parameters:
  • ref

  • nb_changes – maximal number of changes

Returns:

resulting constraints

add_constraint_on_task_unary_resource_allocation(task: Task, unary_resource: UnaryResource, used: bool) → list[Any][source]

Add constraint on allocation of given unary resource for the given task

Parameters:
  • task

  • unary_resource

  • used – if True, we enforce the allocation of unary_resource to task, else we prevent it

Returns:

resulting constraints

add_constraint_on_total_nb_usages(sign: SignEnum, target: int) → list[Any][source]
add_constraint_on_unary_resource_nb_usages(unary_resource: UnaryResource, sign: SignEnum, target: int) → list[Any][source]
add_same_unary_allocation_constraints()[source]
add_unary_resources_per_task_constraints()[source]

Add constraints on number min/max of allocated resources per task.

According to options at_most_one_unary_resource_per_task and exactly_one_unary_resource_per_task.

allocation_changes_variables: dict[tuple[Task, UnaryResource], IntVar]

Variables tracking allocation changes from a given reference.

allocation_changes_variables_created = False

Flag telling whether ‘allocation changes variables’ have been created

at_most_one_unary_resource_per_task = False

Flag telling if the problem accept at most one unary_resource per task.

Default to False, ie several resources allowed per task.

create_allocation_changes_variables()[source]

Create variables necessary for constraint on nb of changes.

create_task_allocated_variables()[source]
create_used_variables()[source]
exactly_one_unary_resource_per_task = False

Whether enforcing exactly one resource allocated to each task.

get_default_tasks_n_unary_resources(tasks: Iterable[Task] | None = None, unary_resources: Iterable[UnaryResource] | None = None) → tuple[Iterable[Task], Iterable[UnaryResource]][source]
get_nb_tasks_allocated_variable() → LinearExpr | IntVar | int | int8 | uint8 | int32 | uint32 | int64 | uint64[source]

Construct and get the variable tracking number of tasks with at least a resource allocated.

Returns:

objective variable to minimize

get_nb_unary_resources_used_variable() → LinearExpr | IntVar | int | int8 | uint8 | int32 | uint32 | int64 | uint64[source]

Construct and get the variable tracking number of tasks with at least a resource allocated.

Returns:

objective variable to minimize

abstractmethod get_task_unary_resource_is_present_variable(task: Task, unary_resource: UnaryResource) → LinearExpr | IntVar | int | int8 | uint8 | int32 | uint32 | int64 | uint64[source]

Return a 0-1 variable/expression telling if the unary_resource is used for the task.

This variable should be 0 whenever an optional task is absent. For instance via a constraint like cp_model.add(task_unary_resource_is_present = 0).only_enforce_if(~task_is_present). or cp_model.add(task_unary_resource_is_present<=task_is_present)

NB: sometimes the given resource is never to be used by a task and the variable has not been created. The convention is to return 0 in that case.

init_model(**kwargs: Any) → None[source]

Init cp model and reset stored variables if any.

property subset_tasks_of_interest: Iterable[Task]

Subset of tasks of interest used for the objective.

By default, all tasks.

property subset_unaryresources_allowed: Iterable[UnaryResource]

Unary resources allowed to solve the problem.

By default, all unary resources.

task_allocated_variables: dict[Task, IntVar]

Variables tracking whether a task has at least one unary resource allocated.

task_allocated_variables_created = False

Flag telling whether ‘task_allocated_variables’ have been created

used_variables: dict[UnaryResource, IntVar]

Variables tracking whether a unary resource has been used at least once.

used_variables_created = False

Flag telling whether ‘used variables’ have been created

class discrete_optimization.generic_tasks_tools.solvers.cpsat.allocation.AllocationIntegerModellingCpSatSolver(problem: Problem, params_objective_function: ParamsObjectiveFunction | None = None, **kwargs: Any)[source]

Bases: AllocationCpSatSolver[Task, UnaryResource]

Base class for allocation cp-sat solvers using an integer modelling.

I.e. using integer variables to model allocation of a task. This assumes that at most one unary_resource can be allocated to a task.

add_allocation_changes_constraints(ref: AllocationSolution[Task, UnaryResource]) → list[Any][source]

Add and return constraints so that change variables reflect diff to ref.

add_constraint_on_task_unary_resource_allocation(task: Task, unary_resource: UnaryResource, used: bool) → list[Any][source]

Add constraint on allocation of given unary resource for the given task

Parameters:
  • task

  • unary_resource

  • used – if True, we enforce the allocation of unary_resource to task, else we prevent it

Returns:

resulting constraints

create_is_present_variables() → None[source]
abstractmethod get_task_allocation_variable(task: Task) → LinearExpr | IntVar | int | int8 | uint8 | int32 | uint32 | int64 | uint64[source]

Return an integer variable/expression storing the index of the allocated unary_resource.

Assumes that exactly one unary resource is allocated to a task.

get_task_unary_resource_is_present_variable(task: Task, unary_resource: UnaryResource) → LinearExpr | IntVar | int | int8 | uint8 | int32 | uint32 | int64 | uint64[source]

Return a 0-1 variable/expression telling if the unary_resource is used for the task.

NB: sometimes the given resource is never to be used by a task and the variable has not been created. The convention is to return 0 in that case.

init_model(**kwargs: Any) → None[source]

Init cp model and reset stored variables if any.

is_present_variables: dict[tuple[Task, UnaryResource], IntVar]
is_present_variables_created = False
class discrete_optimization.generic_tasks_tools.solvers.cpsat.allocation.AllocationModelling(*values)[source]

Bases: Enum

BINARY = 'binary'
INTEGER = 'integer'

discrete_optimization.generic_tasks_tools.solvers.cpsat.alternative_subproblems module

class discrete_optimization.generic_tasks_tools.solvers.cpsat.alternative_subproblems.AlternativeSubproblemCpSatSolver(problem: Problem, params_objective_function: ParamsObjectiveFunction | None = None, **kwargs: Any)[source]

Bases: MultimodeSchedulingCpSatSolver[Task], Generic[Task]

create_alternative_path_constraint(alternative_problem: AlternativeSchedulingSubProblem, tag_alternative_problem: str, strict_alternative_path: bool)[source]
create_alternative_subproblems_constraints()[source]
problem: AlternativeSchedulingProblem[Task]

discrete_optimization.generic_tasks_tools.solvers.cpsat.auto module

class discrete_optimization.generic_tasks_tools.solvers.cpsat.auto.GenericSchedulingAutoCpSatSolver(problem: Problem, params_objective_function: ParamsObjectiveFunction | None = None, **kwargs: Any)[source]

Bases: GenericSchedulingCpSatSolver[Task, UnaryResource, Skill, NonSkillCumulativeResource, NonRenewableResource], WarmstartMixin

Generic cpsat solver for scheduling problems (with or without allocation).

The needed variables are automatically created, with common constraints (precedence, resource capacity). The objective is set by default to global makespan but can be changed by modifying solver.default_objective value.

This solver class needs still to be derived to create a solution from the proper class. You will need at least to implement the conversion from the task variables to the actual solution object.

If custom constraints are needed, override init_model(). If a custom objective is needed, set solver.default_objective to Objective.CUSTOM so that no objective is set by default and override init_model() to define your objective.

add_cumulative_approximation_nb_unary_resource_used = False
add_redundant_skill_cumulative_constraints = False

Whether adding redundant calendar cumulative constraints on skills.

These constraints are redundant with the calendar constraints on unary_resources as the calendar for a skill is deduce from unary_resource calendars.

all_used_variables: dict[AnyResource, IntVar]

Variables tracking whether a (unary, cumulative, or non-renewable) resource has been used at least once.

all_used_variables_created = False

Flag telling whether ‘all_used_variables’ have been created

allocation_intervals: dict[Task, dict[UnaryResource, IntervalVar]]
allocation_is_present: dict[Task, dict[UnaryResource, LinearExprT]]
avoid_interval_optional_for_cumulative_resources: bool = True

Whether using task intervals + demand vars or optional intervals depending on is_present[unary_resource] in cumulative/no_overlap constraints.

avoid_interval_optional_for_unary_resources: bool = False

Whether using task intervals + is_present(unary_resource) as demand variables or optional intervals depending on is_present(unary_resource) in cumulative/no_overlap constraints.

check_resources_lists()[source]
compute_task_bounds() → None[source]

Compute tighter bounds for tasks.

  • if use_cpm_for_task_bounds, propagate bounds forward and backward in the precedence by

using the min possible duration for the task. - else only use min possible duration with 0, new_horizon (set by the solver in self.get_makespan_upper_bound())

abstractmethod convert_task_variables_to_solution(raw_sol: RawSolution[Task, UnaryResource, Skill]) → GenericSchedulingSolution[Task, UnaryResource, Skill, NonSkillCumulativeResource, NonRenewableResource][source]

Convert solution from autosolver format into do format.

To be used in self.retrieve_solution().

Parameters:

raw_sol

Returns:

create_energy_constraints(branches: list[tuple[Task, Task, set[Task]]]) → None[source]
create_present_task_variables_for_all_tasks = False

Either creating present var for all task (not only for optional tasks)

demand_cumulative_modeling: ModeToValueModeling = 1
demand_non_renewable_modeling: ModeToValueModeling = 1

Specify how the demand vars are defined with the modes

demand_variables: dict[Task, dict[AnyResource, LinearExprT]]
dict_objective_expr: dict[Objective | str, LinearExprT]
duplicate_start_var_per_mode = False

Whether adding a start variable for each task mode.

duration_variables: dict[Task, LinearExprT]
energy_variables: dict[Task, dict[AnyResource, LinearExprT]]
get_duration_variable(task: Task, task_interval_will_exist: bool | None = None) → LinearExpr | IntVar | int | int8 | uint8 | int32 | uint32 | int64 | uint64[source]

Get duration variable for given task

Parameters:
  • task

  • task_interval_will_exist – if you know that the task interval will also be created, set this to True to avoid redundant constraints. Ignored if the duration variable has already been created.

Returns:

get_makespan_lower_bound() → int[source]

Get a lower bound on global makespan.

Can be overriden in solvers wanting to specify it in init_model() for instance.

get_skill_variable(task: Task, unary_resource: UnaryResource, skill: Skill) → LinearExpr | IntVar | int | int8 | uint8 | int32 | uint32 | int64 | uint64[source]

Get skill boolean variable telling if given skill is used by given unary resource for given task.

This variable should be 0 whenever an optional task is absent. For instance via a constraint like cp_model.add(task_unary_resource_skill_used = 0).only_enforce_if(~task_is_present).

get_task_interval(task: Task) → IntervalVar[source]

Get interval variable for given task.

get_task_is_present_variable(task: Task) → LinearExpr | IntVar | int | int8 | uint8 | int32 | uint32 | int64 | uint64[source]

Return a boolean variable telling whether a given task is scheduled.

get_task_mode_interval(task: Task, mode: int) → IntervalVar[source]

Get the interval variable corresponding to given task and mode.

get_task_mode_is_present_variable(task: Task, mode: int) → LinearExpr | IntVar | int | int8 | uint8 | int32 | uint32 | int64 | uint64[source]

Retrieve the 0-1 variable/expression telling if the mode is used for the task.

The variable value should be 0 when the task is optional and absent. For instance via a constraint like cp_model.add(task_mode_is_present = 0).only_enforce_if(~task_is_present).

Parameters:
  • task

  • mode

Returns:

get_task_start_or_end_lower_bound(task: Task, start_or_end: StartOrEnd) → int[source]

Get a lower bound on start or end of a given task.

Use either the bounds given in __init__() or computed via compute_tasks_bounds().

Parameters:
  • task

  • start_or_end

Returns:

get_task_start_or_end_upper_bound(task: Task, start_or_end: StartOrEnd) → int[source]

Get an upper bound on start or end of a given task.

Use either the bounds given in __init__() or computed via compute_tasks_bounds().

Parameters:
  • task

  • start_or_end

Returns:

get_task_start_or_end_variable(task: Task, start_or_end: StartOrEnd) → LinearExpr | IntVar | int | int8 | uint8 | int32 | uint32 | int64 | uint64[source]

Retrieve the variable storing the start or end time of given task.

For optional tasks, the start and end should be 0 when absent so that the makespan/sum of starts/sum of ends variables do not take them into account.

Parameters:
  • task

  • start_or_end

Returns:

get_task_unary_resource_interval(task: Task, unary_resource: UnaryResource) → IntervalVar[source]

Get the interval variable corresponding to given task conditioned to allocation of the given unary resource.

The method may return an error (no variable existing) if self.problem.is_compatible_task_unary_resource(task=task, unary_resource=unary_resource) is false.

get_task_unary_resource_is_present_variable(task: Task, unary_resource: UnaryResource) → LinearExpr | IntVar | int | int8 | uint8 | int32 | uint32 | int64 | uint64[source]

Return a 0-1 variable/expression telling if the unary_resource is used for the task.

The value will be 0 if the (optional) task is absent.

NB: sometimes the given resource is never to be used by a task and the variable has not been created. The convention is to return 0 in that case.

hyperparameters = [CategoricalHyperparameter(name='avoid_interval_optional_for_unary_resources', default=False, depends_on=None, name_in_kwargs='avoid_interval_optional_for_unary_resources'), CategoricalHyperparameter(name='avoid_interval_optional_for_cumulative_resources', default=True, depends_on=None, name_in_kwargs='avoid_interval_optional_for_cumulative_resources'), CategoricalHyperparameter(name='use_demand_variables_for_non_renewable_resources', default=False, depends_on=None, name_in_kwargs='use_demand_variables_for_non_renewable_resources'), CategoricalHyperparameter(name='add_redundant_skill_cumulative_constraints', default=False, depends_on=None, name_in_kwargs='add_redundant_skill_cumulative_constraints'), CategoricalHyperparameter(name='use_cpm_for_task_bounds', default=False, depends_on=None, name_in_kwargs='use_cpm_for_task_bounds'), CategoricalHyperparameter(name='duplicate_start_var_per_mode', default=False, depends_on=('avoid_interval_optional_for_cumulative_resources', [False]), name_in_kwargs='duplicate_start_var_per_mode'), CategoricalHyperparameter(name='use_energy_constraints', default=False, depends_on=None, name_in_kwargs='use_energy_constraints'), CategoricalHyperparameter(name='keep_only_most_nested_energy_constraints', default=True, depends_on=('use_energy_constraints', [True]), name_in_kwargs='keep_only_most_nested_energy_constraints'), EnumHyperparameter(name='demand_non_renewable_modeling', default=<ModeToValueModeling.ENFORCE_IF: 1>, depends_on=None, name_in_kwargs='demand_non_renewable_modeling'), EnumHyperparameter(name='demand_cumulative_modeling', default=<ModeToValueModeling.ENFORCE_IF: 1>, depends_on=None, name_in_kwargs='demand_cumulative_modeling')]

Hyperparameters available for this solver.

These hyperparameters are to be feed to **kwargs found in
  • __init__()

  • init_model() (when available)

  • solve()

include_constraint_on_cumulative_resource(resource: Skill | NonSkillCumulativeResource) → bool[source]

Whether the cp model should take into account the constraint on the given cumulative resource.

Some problems define “redundant” cumulative resources that are computed from others. If you want to avoid adding redundant constraints in your model, please override this method.

Parameters:

resource

Returns:

init_list_obj_modelers()[source]
init_model(tasks_bounds: dict[Task, tuple[int, int, int, int]] | None = None, use_cpm_for_task_bounds: bool | None = None, avoid_interval_optional_for_unary_resources: bool | None = None, avoid_interval_optional_for_cumulative_resources: bool | None = None, use_demand_variables_for_non_renewable_resources: bool | None = None, duplicate_start_var_per_mode: bool | None = None, use_energy_constraints: bool | None = None, keep_only_most_nested_energy_constraints: bool | None = None, add_redundant_skill_cumulative_constraints: bool | None = None, demand_cumulative_modeling: ModeToValueModeling | None = None, demand_non_renewable_modeling: ModeToValueModeling | None = None, create_present_task_variables_for_all_tasks: bool | None = None, **kwargs: Any) → None[source]

Init cp model and reset stored variables if any.

is_list_obj_modeler_init()[source]
keep_only_most_nested_energy_constraints = True

Whether to keep only most nested subgraphs for energy constraints.

list_obj_modeler_weight: list[tuple[ObjectiveModelerCpSat, float]]
mode_cost_variables: dict[Task, LinearExprT]
modes_intervals: dict[Task, dict[int, IntervalVar]]
modes_is_present: dict[Task, dict[int, LinearExprT]]
modes_start_variables: dict[Task, dict[int, LinearExprT]]
property needs_duration_variables: bool

Whether the task duration variables are needed by the model.

Default implementation, returns True if - the problem is an allocation one (at least one unary resource) and use optional intervals for correspondant cumulative/nooverlap constraints, - or need task intervals (according to self.needs_task_interval)

If additional custom constraints require them, override it.

property needs_task_intervals: bool

Whether the task interval variables are needed by the model.

By default, these variables are needed only if we are not using the optional intervals for cumulative constraints. NB: Even if no cumulative resources are present, optional intervals per mode or task intervals are still needed to create the duration constraints between start and end. If additional custom constraints require them, override this property.

prepare_energy_constraints() → list[tuple[Task, Task, set[Task]]][source]

Analyses the dependency graph to improve the model. :returns: a list of (task1, task2, in_between_tasks) with task2 and indirect successor

of task1, and in_between_tasks being the list of all tasks after task1 and before task2.

resource_level_variables: dict[AnyResource, LinearExprT]

Variables tracking level (capacity needed) of each (unary, cumulative, or non-renewable) resource.

resource_level_variables_created = False

Flag telling whether ‘resource_level_variables’ have been created

retrieve_solution(cpsolvercb: CpSolverSolutionCallback) → Solution[source]

Construct a do solution from the cpsat solver internal solution.

It will be called each time the cpsat solver find a new solution. At that point, value of internal variables are accessible via cpsolvercb.Value(VARIABLE_NAME).

Parameters:

cpsolvercb – the ortools callback called when the cpsat solver finds a new solution.

Returns:

the intermediate solution, at do format.

retrieve_tasks_variables(cpsolvercb: CpSolverSolutionCallback) → RawSolution[Task, UnaryResource, Skill][source]

Construct each task variable from the cpsat solver internal solution.

It will be called each time the cpsat solver find a new solution. At that point, value of internal variables are accessible via cpsolvercb.Value(VARIABLE_NAME).

This method is called in self.retrieve_solution() before self.convert_task_variables_to_solution(). Override it if you need additional information to be stored (either in res.metadata or res.task_variables[task].info).

Parameters:

cpsolvercb – the ortools callback called when the cpsat solver finds a new solution.

Returns:

the task variables for the intermediate solution

set_warm_start(solution: Solution) → None[source]

Make the solver warm start from the given solution.

skill_variables: dict[Task, dict[UnaryResource, dict[Skill, LinearExprT]]]
start_or_end_variables: dict[tuple[Task, StartOrEnd], LinearExprT]
task_interval_variables

alias of dict[Task, IntervalVar]

task_is_scheduled: dict[Task, IntVar]
unary_resource_cost_variables: dict[Task, dict[UnaryResource, LinearExprT]]
use_cpm_for_task_bounds = False

Flag telling whether cpm should be used to refine task bounds.

use_demand_variables_for_non_renewable_resources: bool = False

Whether using dedicated demand variables or a linear combination with is_present variables to compute demand.

use_energy_constraints = False

Whether using energy constraints.

class discrete_optimization.generic_tasks_tools.solvers.cpsat.auto.SinglemodeGenericSchedulingAutoCpSatSolver(problem: Problem, params_objective_function: ParamsObjectiveFunction | None = None, **kwargs: Any)[source]

Bases: GenericSchedulingAutoCpSatSolver[Task, UnaryResource, Skill, NonSkillCumulativeResource, NonRenewableResource], SinglemodeSchedulingCpSatSolver[Task]

Subclass of GenericSchedulingAutoCpSatSolver for single mode problems.

Give access to task intervals without dealing with modes.

get_task_interval(task: Task) → IntervalVar[source]

Task interval with fixed duration, single mode.

problem: SinglemodeProblem[Task]

discrete_optimization.generic_tasks_tools.solvers.cpsat.auto_impl module

class discrete_optimization.generic_tasks_tools.solvers.cpsat.auto_impl.GenericSchedulingAutoCpSatImplSolver(problem: GenericSchedulingImplProblem, params_objective_function: ParamsObjectiveFunction | None = None, objective: Objective | None = None, custom_objective_factory: Callable[[GenericSchedulingAutoCpSatImplSolver], LinearExprT] | None = None, **kwargs: Any)[source]

Bases: GenericSchedulingAutoCpSatSolver[Hashable, Hashable, Hashable, Hashable, Hashable]

Generic implementation of cpsat solver for scheduling problems (with or without allocation).

It implements abstract class GenericSchedulingAutoCpSatSolver.

convert_task_variables_to_solution(raw_sol: RawSolution[Hashable, Hashable, Hashable]) → GenericSchedulingImplSolution[source]

Convert solution from autosolver format into do format.

To be used in self.retrieve_solution().

Parameters:

raw_sol

Returns:

get_makespan_upper_bound() → int[source]

Get a upper bound on global makespan.

init_model(new_horizon: int | None = None, tasks_bounds: dict[Hashable, tuple[int, int, int, int]] | None = None, use_cpm_for_task_bounds: bool | None = None, avoid_interval_optional_for_unary_resources: bool | None = None, avoid_interval_optional_for_cumulative_resources: bool | None = None, use_demand_variables_for_non_renewable_resources: bool | None = None, duplicate_start_var_per_mode: bool | None = None, use_energy_constraints: bool | None = None, keep_only_most_nested_energy_constraints: bool | None = None, add_redundant_skill_cumulative_constraints: bool | None = None, exactly_one_unary_resource_per_task: bool | None = None, at_most_one_unary_resource_per_task: bool | None = None, use_exact_skill: bool | None = None, use_slack_for_skill: bool | None = None, max_slack_for_skill: int | None = None, use_only_skill_to_allocate: bool | None = None, use_no_overlap_for_capa_1: bool | None = None, use_cumulative_for_capa_1: bool | None = None, **kwargs: Any) → None[source]

Init cp model and reset stored variables if any.

objective = 'custom_objective'
problem: GenericSchedulingImplProblem

discrete_optimization.generic_tasks_tools.solvers.cpsat.base module

class discrete_optimization.generic_tasks_tools.solvers.cpsat.base.TasksCpSatSolver(problem: Problem, params_objective_function: ParamsObjectiveFunction | None = None, **kwargs: Any)[source]

Bases: TasksCpSolver[Task], OrtoolsCpSatSolver

get_task_is_present_variable(task: Task) → LinearExpr | IntVar | int | int8 | uint8 | int32 | uint32 | int64 | uint64[source]

Get the boolean variable whether the (optional) task is present.

Default implementation returns 1 for mandatory task. To be overriden when optional tasks to get an actual boolean variable.

discrete_optimization.generic_tasks_tools.solvers.cpsat.calendar_resource module

class discrete_optimization.generic_tasks_tools.solvers.cpsat.calendar_resource.CalendarResourceCpSatSolver(problem: Problem, params_objective_function: ParamsObjectiveFunction | None = None, **kwargs: Any)[source]

Bases: SchedulingCpSatSolver[Task], Generic[Task, Resource]

create_calendar_resources_constraint(resource: Resource)[source]

Add the constraint for renewable resources with an availability calendar to the cpsat model.

Constraint ensuring that the total demand on the given resource stay below its capacity.

abstractmethod get_resource_consumption_intervals(resource: Resource) → list[tuple[IntervalVar, LinearExpr | IntVar | int | int8 | uint8 | int32 | uint32 | int64 | uint64]][source]

Get all intervals where a given resource is consumed by a task, and related consumption value.

To take into account optional tasks; - either the resource returned should constrainted to 0 when the task is absent, - or the interval should be optional with the corresponding is_present variable being 0 when the task is absent.

Parameters:

resource

Returns: list of tuples (interval_var, consumption_value)

problem: CalendarResourceProblem[Task, Resource]
use_cumulative_for_capa_1: bool = False

Flag to use rather cumulative constraint when resource capacity is 1.

use_no_overlap_for_capa_1: bool = True

Flag to use rather no_overlap constraint when resource capacity is 1.

discrete_optimization.generic_tasks_tools.solvers.cpsat.cumulative_resource module

class discrete_optimization.generic_tasks_tools.solvers.cpsat.cumulative_resource.CumulativeResourceSchedulingCpSatSolver(problem: Problem, params_objective_function: ParamsObjectiveFunction | None = None, **kwargs: Any)[source]

Bases: CalendarResourceCpSatSolver[Task, CumulativeResource | OtherCalendarResource], MultimodeSchedulingCpSatSolver[Task], Generic[Task, CumulativeResource, OtherCalendarResource]

Base class for cpsat solvers dealing with scheduling problems handling cumulative resources.

avoid_interval_optional_for_cumulative_resources: bool = False

Whether using task intervals + demand vars or optional intervals depending on is_present[unary_resource] in cumulative/no_overlap constraints.

cumulative_demand_resource_task_initialized: bool = False
demand_cumulative_modeling: ModeToValueModeling
demand_cumulative_resource_task_initialized: bool = False
demands_cumulative_resource_vars: dict[tuple[CumulativeResource, Task], LinearExpr | IntVar | int | int8 | uint8 | int32 | uint32 | int64 | uint64]
demands_resource_task: dict[tuple[CumulativeResource, Task], LinearExpr | IntVar | int | int8 | uint8 | int32 | uint32 | int64 | uint64]
get_cumulative_resource_demand_variable(task: Task, resource: CumulativeResource) → LinearExpr | IntVar | int | int8 | uint8 | int32 | uint32 | int64 | uint64[source]

Get the variable representing the resource demand by the task.

Default to a linear expression using consumption per mode and is_present variables. If demand variables are indeed created in the cp_model, this should be overriden to return it so that cumulative resource constraints are constraining these variables.

Needed if self.avoid_interval_optional_for_cumulative_resources is set to True.

Parameters:
  • task

  • resource

Returns:

get_resource_consumption_intervals(resource: CumulativeResource | OtherCalendarResource) → list[tuple[IntervalVar, LinearExpr | IntVar | int | int8 | uint8 | int32 | uint32 | int64 | uint64]][source]

Get all intervals where a given resource is consumed by a task, and related consumption value.

To take into account optional tasks; - either the resource returned should constrainted to 0 when the task is absent, - or the interval should be optional with the corresponding is_present variable being 0 when the task is absent.

Parameters:

resource

Returns: list of tuples (interval_var, consumption_value)

initialize_cumulative_resource_demand_vars()[source]

Build either expression or variable array for resource demand. For task for which resource demand only depends on its own mode, this is a simple expression, While for dependent consumption based of other task mode, additional variable is added.

problem: CumulativeResourceProblem[Task, CumulativeResource, OtherCalendarResource]

discrete_optimization.generic_tasks_tools.solvers.cpsat.generic_scheduling module

class discrete_optimization.generic_tasks_tools.solvers.cpsat.generic_scheduling.GenericSchedulingCpSatSolver(problem: Problem, params_objective_function: ParamsObjectiveFunction | None = None, **kwargs: Any)[source]

Bases: ResourceBlockingCpSatSolver[Task, NonSkillCumulativeResource, UnaryResource], SkillSchedulingCpSatSolver[Task, UnaryResource, Skill, NonSkillCumulativeResource, UnaryResource], NonRenewableCpSatSolver[Task, NonRenewableResource], PrecedenceSchedulingCpSatSolver[Task], TimelagCpSatSolver[Task], NoOverlapCpSatSolver[Task], AlternativeSubproblemCpSatSolver[Task], Generic[Task, UnaryResource, Skill, NonSkillCumulativeResource, NonRenewableResource]

Mixin for cpsat solver dealing with scheduling + allocation problems.

Has access to helping methods to create constraints for - precedence - renewable resource with calendar (unary resource to allocate, or cumulative resource) - non-renewable resource capacity - skills brought to tasks by allocated unary resources - resource blocking (gaps and spans)

For a more all-in-one version actually creating variables, constraints and objectives, see GenericSchedulingAutoCpSatSolver.

avoid_interval_optional_for_unary_resources: bool = False

Whether using task intervals + is_present(unary_resource) as demand variables or optional intervals depending on is_present(unary_resource) in cumulative/no_overlap constraints.

get_makespan_upper_bound() → int[source]

Get a upper bound on global makespan.

get_resource_consumption_intervals(resource: Skill | NonSkillCumulativeResource | UnaryResource) → list[tuple[IntervalVar, LinearExpr | IntVar | int | int8 | uint8 | int32 | uint32 | int64 | uint64]][source]

Get all intervals where a given resource is consumed by a task, and related consumption value.

To take into account optional tasks; - either the resource returned should constrainted to 0 when the task is absent, - or the interval should be optional with the corresponding is_present variable being 0 when the task is absent.

Parameters:

resource

Returns: list of tuples (interval_var, consumption_value)

abstractmethod get_task_unary_resource_interval(task: Task, unary_resource: UnaryResource) → IntervalVar[source]

Get the interval variable corresponding to given task conditioned to allocation of the given unary resource.

The method may return an error (no variable existing) if self.problem.is_compatible_task_unary_resource(task=task, unary_resource=unary_resource) is false.

problem: GenericSchedulingProblem[Task, UnaryResource, Skill, NonSkillCumulativeResource, NonRenewableResource]

discrete_optimization.generic_tasks_tools.solvers.cpsat.multimode module

class discrete_optimization.generic_tasks_tools.solvers.cpsat.multimode.MultimodeCpSatSolver(problem: Problem, params_objective_function: ParamsObjectiveFunction | None = None, **kwargs: Any)[source]

Bases: TasksCpSatSolver[Task], MultimodeCpSolver[Task]

add_constraint_on_task_mode(task: Task, mode: int) → list[Any][source]

Add constraint on task mode

The mode of task is fixed to mode.

Parameters:
  • task

  • mode

Returns:

resulting constraints

add_mode_constraints()[source]
abstractmethod get_task_mode_is_present_variable(task: Task, mode: int) → LinearExpr | IntVar | int | int8 | uint8 | int32 | uint32 | int64 | uint64[source]

Retrieve the 0-1 variable/expression telling if the mode is used for the task.

The variable value should be 0 when the task is optional and absent. For instance via a constraint like cp_model.add(task_mode_is_present = 0).only_enforce_if(~task_is_present).

Parameters:
  • task

  • mode

Returns:

class discrete_optimization.generic_tasks_tools.solvers.cpsat.multimode.SinglemodeCpSatSolver(problem: Problem, params_objective_function: ParamsObjectiveFunction | None = None, **kwargs: Any)[source]

Bases: MultimodeCpSatSolver[Task]

CpSat solver mixin for single mode problems.

get_task_mode_is_present_variable(task: Task, mode: int) → LinearExpr | IntVar | int | int8 | uint8 | int32 | uint32 | int64 | uint64[source]

Retrieve the 0-1 variable/expression telling if the mode is used for the task.

The variable value should be 0 when the task is optional and absent. For instance via a constraint like cp_model.add(task_mode_is_present = 0).only_enforce_if(~task_is_present).

Parameters:
  • task

  • mode

Returns:

problem: SinglemodeProblem[Task]

discrete_optimization.generic_tasks_tools.solvers.cpsat.multimode_scheduling module

class discrete_optimization.generic_tasks_tools.solvers.cpsat.multimode_scheduling.MultimodeSchedulingCpSatSolver(problem: Problem, params_objective_function: ParamsObjectiveFunction | None = None, **kwargs: Any)[source]

Bases: SchedulingCpSatSolver[Task], MultimodeCpSatSolver[Task], Generic[Task]

Base class for cpsat solvers dealing with scheduling problems whose tasks durations depend only on mode.

abstractmethod get_task_mode_interval(task: Task, mode: int) → IntervalVar[source]

Get the interval variable corresponding to given task and mode.

Needs to be created if avoid_interval_optional_for_cumulative_resources is False. Not necessary else.

The interval should be optional with the is_present variable being false whenever the task is optional and absent.

problem: MultimodeSchedulingProblem[Task]
class discrete_optimization.generic_tasks_tools.solvers.cpsat.multimode_scheduling.SinglemodeSchedulingCpSatSolver(problem: Problem, params_objective_function: ParamsObjectiveFunction | None = None, **kwargs: Any)[source]

Bases: MultimodeSchedulingCpSatSolver[Task], SinglemodeCpSatSolver[Task]

Base class for cpsat solvers dealing with single mode scheduling problems with fixed tasks durations.

abstractmethod get_task_interval(task: Task) → IntervalVar[source]

Get the interval variable corresponding to given task.

get_task_mode_interval(task: Task, mode: int) → IntervalVar[source]

Get the interval variable corresponding to given task and mode.

Needs to be created if avoid_interval_optional_for_cumulative_resources is False. Not necessary else.

The interval should be optional with the is_present variable being false whenever the task is optional and absent.

problem: SinglemodeSchedulingProblem[Task]

discrete_optimization.generic_tasks_tools.solvers.cpsat.no_overlap module

class discrete_optimization.generic_tasks_tools.solvers.cpsat.no_overlap.NoOverlapCpSatSolver(problem: Problem, params_objective_function: ParamsObjectiveFunction | None = None, **kwargs: Any)[source]

Bases: SchedulingCpSatSolver[Task]

Mixin for cpsat solvers dealing with scheduling problems with no overlap constraint between set of tasks

create_forbidden_intervals_constraints()[source]
create_no_overlap_constraints()[source]

Add no overlap constraints to cp model.

problem: NoOverlapProblem[Task]

discrete_optimization.generic_tasks_tools.solvers.cpsat.non_renewable_resource module

class discrete_optimization.generic_tasks_tools.solvers.cpsat.non_renewable_resource.NonRenewableCpSatSolver(problem: Problem, params_objective_function: ParamsObjectiveFunction | None = None, **kwargs: Any)[source]

Bases: MultimodeCpSatSolver[Task], Generic[Task, NonRenewableResource]

Base class for cpsat solvers dealing with problem with non-renewable resources.

create_non_renewable_resources_constraint(resource: NonRenewableResource)[source]

Add the constraint for a non-renewable resource to the cpsat model.

Constraint ensuring that the total demand on the given resource stay below its capacity.

demand_non_renewable_modeling: ModeToValueModeling
demands_non_renewable_resource_initialized: bool = False
demands_non_renewable_resource_vars: dict[tuple[Task, NonRenewableResource], LinearExpr | int | float | Real | number]
get_non_renewable_resource_demand_variable(task: Task, resource: NonRenewableResource) → LinearExpr | int | float | Real | number[source]

Get the variable representing the resource demand by the task.

Default to a linear expression using consumption per mode and is_present variables. If demand variables are indeed created in the cp_model, this should be overriden to return it so that non renewable resource constraints are constraining these variables.

Needed if self.use_demand_variables_for_non_renewable_resources is set to True.

Parameters:
  • task

  • resource

Returns:

initialize_non_renewable_resource_demand_vars()[source]

Build either expression or variable array for resource demand. For task for which resource demand only depends on its own mode, this is a simple expression, While for dependent consumption based of other task mode, additional variable is added.

problem: NonRenewableResourceProblem

discrete_optimization.generic_tasks_tools.solvers.cpsat.precedence_scheduling module

class discrete_optimization.generic_tasks_tools.solvers.cpsat.precedence_scheduling.PrecedenceSchedulingCpSatSolver(problem: Problem, params_objective_function: ParamsObjectiveFunction | None = None, **kwargs: Any)[source]

Bases: SchedulingCpSatSolver[Task]

Mixin for cpsat solvers dealing with scheduling problems with precedence constraints.

create_precedence_constraints()[source]

Add precedence constraints to cp model.

problem: PrecedenceSchedulingProblem[Task]

discrete_optimization.generic_tasks_tools.solvers.cpsat.resource_blocking module

class discrete_optimization.generic_tasks_tools.solvers.cpsat.resource_blocking.ResourceBlockingCpSatSolver(problem: Problem, params_objective_function: ParamsObjectiveFunction | None = None, **kwargs: Any)[source]

Bases: CumulativeResourceSchedulingCpSatSolver[Task, CumulativeResource, OtherCalendarResource], Generic[Task, CumulativeResource, OtherCalendarResource]

CP-SAT mixin for handling resource blocking constraints.

This mixin adds support for: - Flexible gap blocking: resources blocked between two scheduling entities - Span blocking: resources blocked during the span of a set of tasks

The mixin handles overlaps between blocking intervals and: - Calendar unavailability periods (fake tasks) - Actual task execution intervals - Other blocking intervals

It creates appropriate cumulative constraints per resource, properly accounting for blocking intervals without double-counting consumption.

constrain_group_entity_times(entity: GroupEntity) → None[source]

Add constraints for group entity start/end times.

A group’s start is the minimum start of its tasks. A group’s end is the maximum end of its tasks.

Parameters:

entity – The group entity

create_calendar_resources_constraint(resource: CumulativeResource) → None[source]

Create calendar resource constraint, using blocking-aware version if needed.

Overrides the parent method to automatically use blocking-aware cumulative constraints when blocking intervals exist for this resource.

Parameters:

resource – The resource to constrain

create_cumulative_constraint_including_blocking(resource: CumulativeResource) → None[source]

Create cumulative constraints including blocking intervals.

Blocking is ALWAYS ADDITIVE: task consumption + blocking consumption.

Creates TWO cumulative constraints to properly handle BlockingMode:

Constraint 1 (WITHOUT calendar):
  • All task intervals

  • ALL blocking intervals (RESERVATION + ACTIVE)

  • NO fake tasks (calendar gaps)

Purpose: Enforces RESERVATION blocking even during unavailable periods

Constraint 2 (WITH calendar):
  • All task intervals

  • ONLY ACTIVE blocking intervals

  • Fake tasks (calendar gaps)

Purpose: Enforces ACTIVE blocking only during available periods

Parameters:

resource – The cumulative resource to constrain

create_entity_intervals() → None[source]
create_flexible_gap_blocking_intervals() → None[source]

Create interval variables for flexible gap blocking constraints.

For each flexible gap constraint, creates an interval from the first entity’s reference point to the second entity’s reference point, with the specified resource demands.

create_resource_blocking_constraints() → None[source]

Create all resource blocking interval variables.

This should be called during model initialization, before cumulative resource constraints are created (so that create_calendar_resources_constraint can check for blocking intervals).

create_span_blocking_intervals() → None[source]

Create interval variables for span blocking constraints.

For each span constraint, creates an interval from the minimum start time to the maximum end time of the specified tasks, with the specified resource demands.

get_lb_ub_entity(entity: SchedulingEntity) → tuple[int, int, int, int][source]

Return lbstart, ubstart, lbend, ubend

get_lb_ub_size(entity1: SchedulingEntity, start_or_end1: StartOrEnd, entity2: SchedulingEntity, start_or_end2: StartOrEnd)[source]
init_model(**kwargs: Any) → None[source]

Initialize model and reset blocking interval storage.

problem: GenericSchedulingProblem

discrete_optimization.generic_tasks_tools.solvers.cpsat.scheduling module

class discrete_optimization.generic_tasks_tools.solvers.cpsat.scheduling.SchedulingCpSatSolver(problem: Problem, params_objective_function: ParamsObjectiveFunction | None = None, **kwargs: Any)[source]

Bases: TasksCpSatSolver[Task], SchedulingCpSolver[Task]

Base class for most ortools/cpsat solvers handling scheduling problems.

Allows to have common code.

add_constraint_chaining_tasks(task1: Task, task2: Task) → list[Any][source]

Add constraint chaining task1 with task2

task2 start == task1 end

Parameters:
  • task1

  • task2

Returns:

resulting constraints

add_constraint_on_task(task: Task, start_or_end: StartOrEnd, sign: SignEnum, time: int) → list[Any][source]

Add constraint on given task start or end

task start or end must compare to time according to sign

Parameters:
  • task

  • start_or_end

  • sign

  • time

Returns:

resulting constraints

constraints_on_makespan: list[Any] | None = None

Constraints on partial makespan so that it can be considered as the objective.

get_global_makespan_variable() → LinearExpr | IntVar | int | int8 | uint8 | int32 | uint32 | int64 | uint64[source]

Construct and get the variable tracking the global makespan.

Default implementation uses get_subtasks_makespan_variable on last tasks. Beware: a further call to get_subtasks_makespan_variable with another subset of tasks can change the constraints on this variable and thus make it obsolete.

Returns:

objective variable to minimize

get_subtasks_makespan_variable(subtasks: Iterable[Task]) → LinearExpr | IntVar | int | int8 | uint8 | int32 | uint32 | int64 | uint64[source]

Construct and get the variable tracking the makespan on a subset of tasks.

Beware: a further call to get_subtasks_makespan_variable with another subset of tasks can change the constraints on this variable and thus make it obsolete.

Parameters:

subtasks

Returns:

objective variable to minimize

get_subtasks_sum_end_time_variable(subtasks: Iterable[Task]) → LinearExpr | IntVar | int | int8 | uint8 | int32 | uint32 | int64 | uint64[source]

Construct and get the variable tracking the sum of end times on a subset of tasks.

Parameters:

subtasks

Returns:

objective variable to minimize

get_subtasks_sum_start_time_variable(subtasks: Iterable[Task]) → LinearExpr | IntVar | int | int8 | uint8 | int32 | uint32 | int64 | uint64[source]

Construct and get the variable tracking the sum of start times on a subset of tasks.

Parameters:

subtasks

Returns:

objective variable to minimize

get_task_interval(task: Task) → IntervalVar[source]

Return interval variable for the task.

This variable corresponds to the task schedule, whatever the mode. This is needed when wanting to avoid using optional interval, e.g. if self.avoid_interval_optional_for_cumulative_resources or self.avoid_interval_optional_for_unary_resources is set to True.

If the task is optional, this interval should be also taken into account the presence/absence of the task.

abstractmethod get_task_start_or_end_variable(task: Task, start_or_end: StartOrEnd) → LinearExpr | IntVar | int | int8 | uint8 | int32 | uint32 | int64 | uint64[source]

Retrieve the variable storing the start or end time of given task.

For optional tasks, the start and end should be 0 when absent so that the makespan/sum of starts/sum of ends variables do not take them into account.

Parameters:
  • task

  • start_or_end

Returns:

init_model(**kwargs: Any) → None[source]

Init cp model and reset stored variables if any.

remove_constraints_on_objective() → None[source]

discrete_optimization.generic_tasks_tools.solvers.cpsat.skill module

class discrete_optimization.generic_tasks_tools.solvers.cpsat.skill.SkillSchedulingCpSatSolver(problem: Problem, params_objective_function: ParamsObjectiveFunction | None = None, **kwargs: Any)[source]

Bases: CumulativeResourceSchedulingCpSatSolver[Task, Skill | NonSkillCumulativeResource, OtherCalendarResource], AllocationCpSatSolver[Task, UnaryResource], Generic[Task, UnaryResource, Skill, NonSkillCumulativeResource, OtherCalendarResource]

Base class for cpsat solvers dealing with scheduling problems handling skills attached to unary resources.

create_coarse_skill_constraints()[source]

Create constraints on skills using only task allocation of each unary resource.

create_fine_skill_constraints()[source]

Create constraints on skills using variable on skill contribution of each unary resource.

abstractmethod get_skill_variable(task: Task, unary_resource: UnaryResource, skill: Skill) → LinearExpr | IntVar | int | int8 | uint8 | int32 | uint32 | int64 | uint64[source]

Get skill boolean variable telling if given skill is used by given unary resource for given task.

This variable should be 0 whenever an optional task is absent. For instance via a constraint like cp_model.add(task_unary_resource_skill_used = 0).only_enforce_if(~task_is_present).

is_compatible_task_unary_resource(task: Task, unary_resource: UnaryResource) → bool[source]

Should return False if the unary_resource can never be allocated to task.

This is only a hint used to reduce the number of variables or constraints generated. Default to use problem.is_compatible_task_unary_resource().

But you can override it if you want to have more constraints in the solver than in the problem.

max_slack_for_skill: int = 5

Maximum slack for skill value.

problem: SkillProblem[Task, UnaryResource, Skill, NonSkillCumulativeResource, OtherCalendarResource]
use_exact_skill: bool = False

Allocate exactly the needed skill value to each task.

use_only_skill_to_allocate: bool = False

Do not allocate a unary_resource if not contributing to a skill needed by a given task.

use_slack_for_skill: bool = False

Allow some additional slack on skill value, even when use_exact_skill is activated.

class discrete_optimization.generic_tasks_tools.solvers.cpsat.skill.WithoutSkillSchedulingCpSatSolver(problem: Problem, params_objective_function: ParamsObjectiveFunction | None = None, **kwargs: Any)[source]

Bases: SkillSchedulingCpSatSolver[Task, UnaryResource, None, NonSkillCumulativeResource, OtherCalendarResource], Generic[Task, UnaryResource, NonSkillCumulativeResource, OtherCalendarResource]

Mixin for solver on problems dealing with no skills.

get_skill_variable(task: Task, unary_resource: UnaryResource, skill: Skill) → LinearExpr | IntVar | int | int8 | uint8 | int32 | uint32 | int64 | uint64[source]

Get skill boolean variable telling if given skill is used by given unary resource for given task.

This variable should be 0 whenever an optional task is absent. For instance via a constraint like cp_model.add(task_unary_resource_skill_used = 0).only_enforce_if(~task_is_present).

discrete_optimization.generic_tasks_tools.solvers.cpsat.timelag module

class discrete_optimization.generic_tasks_tools.solvers.cpsat.timelag.TimelagCpSatSolver(problem: Problem, params_objective_function: ParamsObjectiveFunction | None = None, **kwargs: Any)[source]

Bases: SchedulingCpSatSolver[Task]

Mixin for cpsat solvers dealing with scheduling problems with time lag constraints.

create_timelag_constraints() → None[source]

Add precedence constraints to cp model.

problem: TimelagProblem[Task]

discrete_optimization.generic_tasks_tools.solvers.cpsat.utils module

class discrete_optimization.generic_tasks_tools.solvers.cpsat.utils.ModeToValueModeling(*values)[source]

Bases: Enum

This is some option to define constraint between x=[list of N boolean variables] with a sum <= 1 vals=[list of N int constants] and a variable Y that should value vals[i] when x[i] is True.

ENFORCE_IF = 1
LINEAR_SUM = 0
TABLE = 2
discrete_optimization.generic_tasks_tools.solvers.cpsat.utils.create_resource_dependent_variable(cp_model: CpModel, name_var: str, task: Task, task_mode_var: dict[tuple[Task, int], LinearExpr | IntVar | int | int8 | uint8 | int32 | uint32 | int64 | uint64], mode2mapping: dict[int, dict[frozenset[tuple[Task, int]], int] | None], possible_values: set[int] = None)[source]
discrete_optimization.generic_tasks_tools.solvers.cpsat.utils.create_variable_function_of_mode_on_solver(solver: MultimodeCpSatSolver, name: str, mode2value: dict[int, int], task: Task, modeling: ModeToValueModeling = ModeToValueModeling.ENFORCE_IF, conditional_var: LinearExpr | IntVar | int | int8 | uint8 | int32 | uint32 | int64 | uint64 | None = None, no_constraint: bool = False) → LinearExpr | IntVar | int | int8 | uint8 | int32 | uint32 | int64 | uint64[source]

Create a variable whose values depend on chosen mode

If the task is optional, we add the value 0 if no mode is chosen. The new variable can also be conditioned to another boolean variable (typically a given unary resource is allocated), which means its value will be 0 if the conditioning variable is false.

Args:

solver: name: mode2value: task: task for which the variable is created modeling: conditional_var: (optional) conditioning boolean variable implying the new variable to be 0 if false. no_constraint: if True, create a variable with proper domain without constraining

values on mode (e.g. because the constraints are created elsewhere via interval variables)

Returns:

The new variable

discrete_optimization.generic_tasks_tools.solvers.cpsat.utils.enforce_only_if_tasks_present(constraint: Constraint, tasks: Iterable[Task], solver: TasksCpSatSolver[Task])[source]

Enforce given constraints only if all given tasks are present.

Do nothing if all tasks are mandatory.

Parameters:
  • constraint

  • tasks

  • solver

Returns:

Module contents