#[derive(Clone, Debug)]
struct ScalarRuntimeWorker;
#[derive(Clone, Debug)]
struct ScalarRuntimeTask {
worker_idx: Option<usize>,
}
#[derive(Clone, Debug)]
struct ScalarRuntimePlan {
score: Option<SoftScore>,
workers: Vec<ScalarRuntimeWorker>,
tasks: Vec<ScalarRuntimeTask>,
}
#[derive(Clone, Debug)]
struct ScalarRuntimeDirector {
working_solution: ScalarRuntimePlan,
descriptor: SolutionDescriptor,
score_mode: ScalarRuntimeScoreMode,
}
#[derive(Clone, Copy, Debug)]
enum ScalarRuntimeScoreMode {
PreferUnassigned,
ByWorker {
unassigned_score: i64,
assigned_scores: [i64; 3],
},
}
impl ScalarRuntimeDirector {
fn new(working_solution: ScalarRuntimePlan, descriptor: SolutionDescriptor) -> Self {
Self::with_score_mode(
working_solution,
descriptor,
ScalarRuntimeScoreMode::PreferUnassigned,
)
}
fn with_score_mode(
working_solution: ScalarRuntimePlan,
descriptor: SolutionDescriptor,
score_mode: ScalarRuntimeScoreMode,
) -> Self {
Self {
working_solution,
descriptor,
score_mode,
}
}
}
impl PlanningSolution for ScalarRuntimePlan {
type Score = SoftScore;
fn score(&self) -> Option<Self::Score> {
self.score
}
fn set_score(&mut self, score: Option<Self::Score>) {
self.score = score;
}
}
impl Director<ScalarRuntimePlan> for ScalarRuntimeDirector {
fn working_solution(&self) -> &ScalarRuntimePlan {
&self.working_solution
}
fn working_solution_mut(&mut self) -> &mut ScalarRuntimePlan {
&mut self.working_solution
}
fn calculate_score(&mut self) -> SoftScore {
let score = match self.score_mode {
ScalarRuntimeScoreMode::PreferUnassigned => {
if self.working_solution.tasks[0].worker_idx.is_none() {
SoftScore::of(0)
} else {
SoftScore::of(-1)
}
}
ScalarRuntimeScoreMode::ByWorker {
unassigned_score,
assigned_scores,
} => SoftScore::of(
self.working_solution.tasks[0]
.worker_idx
.map(|worker_idx| assigned_scores[worker_idx])
.unwrap_or(unassigned_score),
),
};
self.working_solution.set_score(Some(score));
score
}
fn solution_descriptor(&self) -> &SolutionDescriptor {
&self.descriptor
}
fn clone_working_solution(&self) -> ScalarRuntimePlan {
self.working_solution.clone()
}
fn before_variable_changed(&mut self, _descriptor_index: usize, _entity_index: usize) {}
fn after_variable_changed(&mut self, _descriptor_index: usize, _entity_index: usize) {}
fn entity_count(&self, descriptor_index: usize) -> Option<usize> {
(descriptor_index == 0).then_some(self.working_solution.tasks.len())
}
fn total_entity_count(&self) -> Option<usize> {
Some(self.working_solution.tasks.len())
}
fn constraint_metadata(&self) -> Vec<solverforge_scoring::ConstraintMetadata<'_>> {
Vec::new()
}
}
fn get_runtime_worker_idx(entity: &dyn std::any::Any) -> Option<usize> {
entity
.downcast_ref::<ScalarRuntimeTask>()
.expect("task expected")
.worker_idx
}
fn set_runtime_worker_idx(entity: &mut dyn std::any::Any, value: Option<usize>) {
entity
.downcast_mut::<ScalarRuntimeTask>()
.expect("task expected")
.worker_idx = value;
}
fn scalar_runtime_descriptor_with_allows_unassigned(allows_unassigned: bool) -> SolutionDescriptor {
SolutionDescriptor::new("ScalarRuntimePlan", TypeId::of::<ScalarRuntimePlan>())
.with_entity(
EntityDescriptor::new("Task", TypeId::of::<ScalarRuntimeTask>(), "tasks")
.with_extractor(Box::new(EntityCollectionExtractor::new(
"Task",
"tasks",
|solution: &ScalarRuntimePlan| &solution.tasks,
|solution: &mut ScalarRuntimePlan| &mut solution.tasks,
)))
.with_variable(
VariableDescriptor::genuine("worker_idx")
.with_allows_unassigned(allows_unassigned)
.with_value_range("workers")
.with_usize_accessors(get_runtime_worker_idx, set_runtime_worker_idx),
),
)
.with_problem_fact(
ProblemFactDescriptor::new("Worker", TypeId::of::<ScalarRuntimeWorker>(), "workers")
.with_extractor(Box::new(EntityCollectionExtractor::new(
"Worker",
"workers",
|solution: &ScalarRuntimePlan| &solution.workers,
|solution: &mut ScalarRuntimePlan| &mut solution.workers,
))),
)
}
fn scalar_runtime_descriptor() -> SolutionDescriptor {
scalar_runtime_descriptor_with_allows_unassigned(true)
}
fn scalar_runtime_task_count(solution: &ScalarRuntimePlan) -> usize {
solution.tasks.len()
}
fn scalar_runtime_worker_count(solution: &ScalarRuntimePlan, _provider_index: usize) -> usize {
solution.workers.len()
}
fn scalar_runtime_worker_get(
solution: &ScalarRuntimePlan,
entity_index: usize,
_variable_index: usize,
) -> Option<usize> {
solution.tasks[entity_index].worker_idx
}
fn scalar_runtime_worker_set(
solution: &mut ScalarRuntimePlan,
entity_index: usize,
_variable_index: usize,
value: Option<usize>,
) {
solution.tasks[entity_index].worker_idx = value;
}
fn scalar_runtime_value_order_key(
_solution: &ScalarRuntimePlan,
_entity_index: usize,
_variable_index: usize,
value: usize,
) -> Option<i64> {
Some(value as i64)
}
fn scalar_runtime_model_with_allows_unassigned(
allows_unassigned: bool,
) -> ModelContext<ScalarRuntimePlan, usize, DefaultMeter, DefaultMeter> {
scalar_runtime_model_with_hooks(allows_unassigned, None)
}
fn scalar_runtime_model_with_hooks(
allows_unassigned: bool,
value_order_key: Option<fn(&ScalarRuntimePlan, usize, usize, usize) -> Option<i64>>,
) -> ModelContext<ScalarRuntimePlan, usize, DefaultMeter, DefaultMeter> {
let mut ctx = ScalarVariableContext::new(
0,
0,
"Task",
scalar_runtime_task_count,
"worker_idx",
scalar_runtime_worker_get,
scalar_runtime_worker_set,
ValueSource::SolutionCount {
count_fn: scalar_runtime_worker_count,
provider_index: 0,
},
allows_unassigned,
);
if let Some(order_key) = value_order_key {
ctx = ctx.with_construction_value_order_key(order_key);
}
ModelContext::new(vec![VariableContext::Scalar(ctx)])
}
fn scalar_runtime_model() -> ModelContext<ScalarRuntimePlan, usize, DefaultMeter, DefaultMeter> {
scalar_runtime_model_with_allows_unassigned(true)
}