use crate::api::constraint_set::IncrementalConstraint;
use crate::constraint::IncrementalPentaConstraint;
use crate::stream::collection_extract::{source, ChangeSource};
use solverforge_core::score::SoftScore;
use solverforge_core::{ConstraintRef, ImpactType};
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
struct Task {
team: u32,
}
#[derive(Clone)]
struct Solution {
tasks: Vec<Task>,
}
fn tasks(s: &Solution) -> &[Task] {
s.tasks.as_slice()
}
#[test]
fn test_penta_constraint_evaluate() {
let constraint = IncrementalPentaConstraint::new(
ConstraintRef::new("", "Cluster"),
ImpactType::Penalty,
source(
tasks as fn(&Solution) -> &[Task],
ChangeSource::Descriptor(0),
),
|_s: &Solution, t: &Task, _idx: usize| t.team,
|_s: &Solution,
_a: &Task,
_b: &Task,
_c: &Task,
_d: &Task,
_e: &Task,
_a_idx: usize,
_b_idx: usize,
_c_idx: usize,
_d_idx: usize,
_e_idx: usize| true,
|_s: &Solution,
_entities: &[Task],
_a: usize,
_b: usize,
_c: usize,
_d: usize,
_e: usize| { SoftScore::of(1) },
false,
);
let solution = Solution {
tasks: vec![
Task { team: 1 },
Task { team: 1 },
Task { team: 1 },
Task { team: 1 },
Task { team: 1 },
Task { team: 2 },
],
};
assert_eq!(constraint.evaluate(&solution), SoftScore::of(-1));
}
#[test]
fn test_penta_constraint_multiple_pentas() {
let constraint = IncrementalPentaConstraint::new(
ConstraintRef::new("", "Cluster"),
ImpactType::Penalty,
source(
tasks as fn(&Solution) -> &[Task],
ChangeSource::Descriptor(0),
),
|_s: &Solution, t: &Task, _idx: usize| t.team,
|_s: &Solution,
_a: &Task,
_b: &Task,
_c: &Task,
_d: &Task,
_e: &Task,
_a_idx: usize,
_b_idx: usize,
_c_idx: usize,
_d_idx: usize,
_e_idx: usize| true,
|_s: &Solution,
_entities: &[Task],
_a: usize,
_b: usize,
_c: usize,
_d: usize,
_e: usize| { SoftScore::of(1) },
false,
);
let solution = Solution {
tasks: vec![
Task { team: 1 },
Task { team: 1 },
Task { team: 1 },
Task { team: 1 },
Task { team: 1 },
Task { team: 1 },
],
};
assert_eq!(constraint.evaluate(&solution), SoftScore::of(-6));
}
#[test]
fn test_penta_constraint_incremental() {
let mut constraint = IncrementalPentaConstraint::new(
ConstraintRef::new("", "Cluster"),
ImpactType::Penalty,
source(
tasks as fn(&Solution) -> &[Task],
ChangeSource::Descriptor(0),
),
|_s: &Solution, t: &Task, _idx: usize| t.team,
|_s: &Solution,
_a: &Task,
_b: &Task,
_c: &Task,
_d: &Task,
_e: &Task,
_a_idx: usize,
_b_idx: usize,
_c_idx: usize,
_d_idx: usize,
_e_idx: usize| true,
|_s: &Solution,
_entities: &[Task],
_a: usize,
_b: usize,
_c: usize,
_d: usize,
_e: usize| { SoftScore::of(1) },
false,
);
let solution = Solution {
tasks: vec![
Task { team: 1 },
Task { team: 1 },
Task { team: 1 },
Task { team: 1 },
Task { team: 1 },
],
};
let total = constraint.initialize(&solution);
assert_eq!(total, SoftScore::of(-1));
let delta = constraint.on_retract(&solution, 0, 0);
assert_eq!(delta, SoftScore::of(1));
let delta = constraint.on_insert(&solution, 0, 0);
assert_eq!(delta, SoftScore::of(-1));
}
#[test]
fn penta_filter_receives_source_indexes() {
let mut constraint = IncrementalPentaConstraint::new(
ConstraintRef::new("", "Indexed cluster"),
ImpactType::Penalty,
source(
tasks as fn(&Solution) -> &[Task],
ChangeSource::Descriptor(0),
),
|_s: &Solution, t: &Task, _idx: usize| t.team,
|_s: &Solution,
_a: &Task,
_b: &Task,
_c: &Task,
_d: &Task,
_e: &Task,
a_idx: usize,
b_idx: usize,
c_idx: usize,
d_idx: usize,
e_idx: usize| { (a_idx, b_idx, c_idx, d_idx, e_idx) == (1, 2, 3, 4, 5) },
|_s: &Solution,
_entities: &[Task],
_a: usize,
_b: usize,
_c: usize,
_d: usize,
_e: usize| { SoftScore::of(1) },
false,
);
let solution = Solution {
tasks: vec![
Task { team: 1 },
Task { team: 1 },
Task { team: 1 },
Task { team: 1 },
Task { team: 1 },
Task { team: 1 },
],
};
assert_eq!(constraint.match_count(&solution), 1);
assert_eq!(constraint.evaluate(&solution), SoftScore::of(-1));
assert_eq!(constraint.initialize(&solution), SoftScore::of(-1));
}
#[test]
fn test_penta_constraint_reward() {
let constraint = IncrementalPentaConstraint::new(
ConstraintRef::new("", "Team bonus"),
ImpactType::Reward,
source(
tasks as fn(&Solution) -> &[Task],
ChangeSource::Descriptor(0),
),
|_s: &Solution, t: &Task, _idx: usize| t.team,
|_s: &Solution,
_a: &Task,
_b: &Task,
_c: &Task,
_d: &Task,
_e: &Task,
_a_idx: usize,
_b_idx: usize,
_c_idx: usize,
_d_idx: usize,
_e_idx: usize| true,
|_s: &Solution,
_entities: &[Task],
_a: usize,
_b: usize,
_c: usize,
_d: usize,
_e: usize| { SoftScore::of(5) },
false,
);
let solution = Solution {
tasks: vec![
Task { team: 1 },
Task { team: 1 },
Task { team: 1 },
Task { team: 1 },
Task { team: 1 },
],
};
assert_eq!(constraint.evaluate(&solution), SoftScore::of(5));
}