Source code for discrete_optimization.generic_tasks_tools.solvers.cpsat.generic_scheduling

#  Copyright (c) 2026 AIRBUS and its affiliates.
#  This source code is licensed under the MIT license found in the
#  LICENSE file in the root directory of this source tree.

from abc import abstractmethod
from typing import Generic

from ortools.sat.python.cp_model import IntervalVar, LinearExprT

from discrete_optimization.generic_tasks_tools.allocation import UnaryResource
from discrete_optimization.generic_tasks_tools.base import Task
from discrete_optimization.generic_tasks_tools.generic_scheduling import (
    GenericSchedulingProblem,
    Resource,
)
from discrete_optimization.generic_tasks_tools.non_renewable_resource import (
    NonRenewableResource,
)
from discrete_optimization.generic_tasks_tools.skill import (
    NonSkillCumulativeResource,
    Skill,
)
from discrete_optimization.generic_tasks_tools.solvers.cpsat.no_overlap import (
    NoOverlapCpSatSolver,
)
from discrete_optimization.generic_tasks_tools.solvers.cpsat.non_renewable_resource import (
    NonRenewableCpSatSolver,
)
from discrete_optimization.generic_tasks_tools.solvers.cpsat.precedence_scheduling import (
    PrecedenceSchedulingCpSatSolver,
)
from discrete_optimization.generic_tasks_tools.solvers.cpsat.skill import (
    SkillSchedulingCpSatSolver,
)
from discrete_optimization.generic_tasks_tools.solvers.cpsat.timelag import (
    TimelagCpSatSolver,
)


[docs] class GenericSchedulingCpSatSolver( SkillSchedulingCpSatSolver[ Task, UnaryResource, Skill, NonSkillCumulativeResource, UnaryResource ], NonRenewableCpSatSolver[Task, NonRenewableResource], PrecedenceSchedulingCpSatSolver[Task], TimelagCpSatSolver[Task], NoOverlapCpSatSolver[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 For a more all-in-one version actually creating variables, constraints and objectives, see `GenericSchedulingAutoCpSatSolver`. """ problem: GenericSchedulingProblem[ Task, UnaryResource, Skill, NonSkillCumulativeResource, NonRenewableResource ]
[docs] def get_resource_consumption_intervals( self, resource: Resource ) -> list[tuple[IntervalVar, LinearExprT]]: if self.problem.is_unary_resource(resource=resource): if self.avoid_interval_optional: # no optional interval, use rather demand variables return [ (self.get_task_interval(task=task), conso) for task in self.problem.tasks_list if not isinstance( ( conso := self.get_task_unary_resource_is_present_variable( task=task, unary_resource=resource ) ), int, ) or conso > 0 ] else: return [ ( self.get_task_unary_resource_interval( task=task, unary_resource=resource ), 1, ) for task in self.problem.tasks_list if self.is_compatible_task_unary_resource( task=task, unary_resource=resource ) ] else: return super().get_resource_consumption_intervals(resource=resource)
[docs] @abstractmethod def get_task_unary_resource_interval( self, task: Task, unary_resource: UnaryResource ) -> IntervalVar: """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. """ ...
[docs] def get_makespan_upper_bound(self) -> int: return self.problem.get_makespan_tighter_upper_bound()