Source code for discrete_optimization.workforce.allocation.transformations.to_generic
# 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.
"""
Transformation from Coloring to RCPSP.
"""
from discrete_optimization.generic_tasks_tools.generic_scheduling_impl import (
GenericSchedulingImplProblem,
GenericSchedulingImplSolution,
)
from discrete_optimization.generic_tasks_tools.objectives.unary_resource_used import (
UnaryResourcesUsedComputer,
)
from discrete_optimization.generic_tools.transformation.problem_transformation import (
ProblemTransformation,
)
from discrete_optimization.generic_tools.transformation.transformation_metadata import (
TransformationMetadata,
exact_transformation,
)
from discrete_optimization.workforce.allocation.problem import (
TeamAllocationProblem,
TeamAllocationSolution,
)
[docs]
class WorkforceAllocationToGenericSchedulingTransformation(
ProblemTransformation[
TeamAllocationProblem,
TeamAllocationSolution,
GenericSchedulingImplProblem,
GenericSchedulingImplSolution,
]
):
"""
Transform AllocationProblem to RCPSP.
"""
[docs]
def get_forward_metadata(self) -> TransformationMetadata:
"""Metadata for forward problem transformation (BinPack → RCPSP).
This direction is EXACT: all constraints can be represented in RCPSP.
"""
return exact_transformation(
use_cases=[
"Exact encoding of workforce alloc problem as scheduling problem",
]
)
[docs]
def transform_problem(
self, source_problem: TeamAllocationProblem
) -> GenericSchedulingImplProblem:
"""Transform BinPacking to RCPSP.
Args:
source_problem: BinPacking problem instance
Returns:
Equivalent GenericSchedulingImpl problem
"""
tasks = source_problem.tasks_list
unary = source_problem.unary_resources_list
time_window = {}
for t in source_problem.schedule:
st, end = source_problem.schedule[t]
print(st, end)
time_window[t] = (st, end, st, end)
compatible_teams = source_problem.compute_compatibility_for_all_tasks()
return GenericSchedulingImplProblem(
horizon=max([x[1] for x in time_window.values()]),
skills={"team"},
unary_resources=unary,
resource_consumptions={t: {0: {"team": 1}} for t in tasks},
unary_resources_skills={ur: {"team": 1} for ur in unary},
durations_per_mode={
n: {0: source_problem.schedule[n][1] - source_problem.schedule[n][0]}
for n in source_problem.tasks_list
},
time_windows=time_window,
unary_resources_task_compatibility=compatible_teams,
list_objective_computer=[
UnaryResourcesUsedComputer(
weight_objective=1,
weight_per_unary_resource={ur: 1 for ur in unary},
)
],
)
[docs]
def back_transform_solution(
self,
solution: GenericSchedulingImplSolution,
source_problem: TeamAllocationProblem,
) -> TeamAllocationSolution:
"""Transform GenericSchedulingImpl solution back to TeamAllocation solution.
Returns:
Equivalent TeamAllocation solution
"""
# Extract bin assignment from start times
# Tasks scheduled at time t are assigned to bin t
teams = [-1] * len(source_problem.tasks_list)
for i, item in enumerate(source_problem.tasks_list):
if solution.is_present(item):
allocated = solution.get_task_allocation(item)
if len(allocated) >= 1:
team = list(allocated)[0]
teams[i] = source_problem.index_teams_name[team]
return TeamAllocationSolution(problem=source_problem, allocation=teams)