use crate::api::constraint_set::IncrementalConstraint;
use crate::constraint::IncrementalQuadConstraint;
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_quad_constraint_evaluate() {
let constraint = IncrementalQuadConstraint::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,
_a_idx: usize,
_b_idx: usize,
_c_idx: usize,
_d_idx: usize| true,
|_s: &Solution, _entities: &[Task], _a: usize, _b: usize, _c: usize, _d: usize| {
SoftScore::of(1)
},
false,
);
let solution = Solution {
tasks: vec![
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_quad_constraint_multiple_quads() {
let constraint = IncrementalQuadConstraint::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,
_a_idx: usize,
_b_idx: usize,
_c_idx: usize,
_d_idx: usize| true,
|_s: &Solution, _entities: &[Task], _a: usize, _b: usize, _c: usize, _d: 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 },
],
};
assert_eq!(constraint.evaluate(&solution), SoftScore::of(-5));
}
#[test]
fn test_quad_constraint_incremental() {
let mut constraint = IncrementalQuadConstraint::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,
_a_idx: usize,
_b_idx: usize,
_c_idx: usize,
_d_idx: usize| true,
|_s: &Solution, _entities: &[Task], _a: usize, _b: usize, _c: usize, _d: usize| {
SoftScore::of(1)
},
false,
);
let solution = Solution {
tasks: vec![
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 quad_filter_receives_source_indexes() {
let mut constraint = IncrementalQuadConstraint::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,
a_idx: usize,
b_idx: usize,
c_idx: usize,
d_idx: usize| { (a_idx, b_idx, c_idx, d_idx) == (1, 2, 3, 4) },
|_s: &Solution, _entities: &[Task], _a: usize, _b: usize, _c: usize, _d: 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 },
],
};
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_quad_constraint_reward() {
let constraint = IncrementalQuadConstraint::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,
_a_idx: usize,
_b_idx: usize,
_c_idx: usize,
_d_idx: usize| true,
|_s: &Solution, _entities: &[Task], _a: usize, _b: usize, _c: usize, _d: usize| {
SoftScore::of(5)
},
false,
);
let solution = Solution {
tasks: vec![
Task { team: 1 },
Task { team: 1 },
Task { team: 1 },
Task { team: 1 },
],
};
assert_eq!(constraint.evaluate(&solution), SoftScore::of(5));
}