Source code for discrete_optimization.generic_tasks_tools.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 typing import Generic, Union

from discrete_optimization.generic_tasks_tools.allocation import (
    AllocationProblem,
    AllocationSolution,
    UnaryResource,
)
from discrete_optimization.generic_tasks_tools.base import Task
from discrete_optimization.generic_tasks_tools.cumulative_resource import (
    CumulativeResource,
    CumulativeResourceProblem,
    CumulativeResourceSolution,
)
from discrete_optimization.generic_tasks_tools.non_renewable_resource import (
    NonRenewableResource,
    NonRenewableResourceProblem,
    NonRenewableResourceSolution,
)
from discrete_optimization.generic_tasks_tools.precedence_scheduling import (
    PrecedenceSchedulingProblem,
    PrecedenceSchedulingSolution,
)

Resource = Union[CumulativeResource, UnaryResource]


[docs] class GenericSchedulingProblem( CumulativeResourceProblem[Task, CumulativeResource, UnaryResource], NonRenewableResourceProblem[Task, NonRenewableResource], AllocationProblem[Task, UnaryResource], PrecedenceSchedulingProblem[Task], Generic[Task, UnaryResource, CumulativeResource, NonRenewableResource], ): """Scheduling problem with all optional features This class derives from other mixins to provide utilities that require that mix: - scheduling: tasks need to be scheduled - calendar: the renewable resources have their own calendar that will be used for constraining allocations and schedule - multimode: the tasks have several mode on which the duration depends - cumulative: the tasks consume cumulative resources according to the chosen mode - allocation: the tasks can have unary resources allocated to them - non-renewable: the tasks consume non-renewable resources according to the chosen mode - precedence: precedence constraints between tasks Even though this class is generic but encompasses also more specific cases: - singlemode: actually only one mode per task - no cumulative ressources: if resources_list list only unary resources - no calendar: resource capacity can be given as a constant on [0, horizon) - no non-renewable ressources: if non_renewable_resources_list empty - no precedence constraints: precedence constraints empty We suppose that all renewable resources are - either cumulative ones - or unary resources This generic class is to be used to construct generic automatic solvers (e.g. ). """ @property def calendar_resources_list(self) -> list[Resource]: return self.unary_resources_list + self.cumulative_resources_list
[docs] def check_calendar_resources_list(self) -> None: """Check calendar resources list. Raises: AssertionError: if duplicates appear in the list Returns: """ calendar_resources_list = ( self.unary_resources_list + self.cumulative_resources_list ) assert len(calendar_resources_list) == len(set(calendar_resources_list)), ( "There are duplicates in calendar resources list, " "potentially because unary and cumulative resources intersect." )
[docs] def update_resource_availabilities(self) -> None: super().update_resource_availabilities() self.check_calendar_resources_list()
[docs] def is_unary_resource(self, resource: Resource) -> bool: """Check if given resource is a unary resource.""" return resource in self.unary_resources_list
[docs] class GenericSchedulingSolution( CumulativeResourceSolution[Task, CumulativeResource, UnaryResource], NonRenewableResourceSolution[Task, NonRenewableResource], PrecedenceSchedulingSolution[Task], AllocationSolution[Task, UnaryResource], Generic[Task, UnaryResource, CumulativeResource, NonRenewableResource], ): """Solution type associated to GenericSchedulingProblem.""" problem: GenericSchedulingProblem[ Task, UnaryResource, CumulativeResource, NonRenewableResource ]
[docs] def get_calendar_resource_consumption(self, resource: Resource, task: Task) -> int: """""" if self.problem.is_unary_resource(resource=resource): # unary resources: 0 (not allocated) or 1 (allocated) return int(self.is_allocated(task=task, unary_resource=resource)) else: # cumulative resources return super().get_calendar_resource_consumption( resource=resource, task=task )