use crate::api::constraint_set::IncrementalConstraint;
use crate::constraint::relational::OperatorTerminal;
use crate::stream::collection_extract::{source, ChangeSource};
use crate::stream::joiner::equal_bi;
use crate::stream::relational::{
operator::{CollectionNode, JoinNode, Pair},
Leaf,
};
use solverforge_core::{score::SoftScore, ConstraintRef, ImpactType};
#[derive(Clone, Debug)]
struct Value {
key: u32,
weight: i64,
}
struct Model {
values: Vec<Value>,
}
fn values(m: &Model) -> &[Value] {
&m.values
}
fn key(v: &Leaf<'_, Value>) -> u32 {
v.entity.key
}
fn leaf(
binding: u32,
) -> CollectionNode<Model, crate::stream::collection_extract::SourceExtract<fn(&Model) -> &[Value]>>
{
CollectionNode::new(
source(
values as fn(&Model) -> &[Value],
ChangeSource::Descriptor(0),
),
binding,
)
}
type L<'a> = Leaf<'a, Value>;
type P1<'a> = Pair<L<'a>, L<'a>>;
type P2<'a> = Pair<P1<'a>, L<'a>>;
type P3<'a> = Pair<P2<'a>, L<'a>>;
type P4<'a> = Pair<P3<'a>, L<'a>>;
type P5<'a> = Pair<P4<'a>, L<'a>>;
fn depth6_weight(_: &Model, row: &P5<'_>) -> SoftScore {
let sum = row.left.left.left.left.left.entity.weight
+ row.left.left.left.left.right.entity.weight
+ row.left.left.left.right.entity.weight
+ row.left.left.right.entity.weight
+ row.left.right.entity.weight
+ row.right.entity.weight;
SoftScore::of(sum)
}
#[test]
fn six_binding_typed_join_chain_matches_oracle_and_retracts_exactly() {
let n0 = leaf(0);
let n1 = leaf(1);
let n2 = leaf(2);
let n3 = leaf(3);
let n4 = leaf(4);
let n5 = leaf(5);
let j1 = JoinNode::new(n0, n1, equal_bi(key, key));
let j2 = JoinNode::new(j1, n2, equal_bi(|v: &P1<'_>| v.left.entity.key, key));
let j3 = JoinNode::new(j2, n3, equal_bi(|v: &P2<'_>| v.left.left.entity.key, key));
let j4 = JoinNode::new(
j3,
n4,
equal_bi(|v: &P3<'_>| v.left.left.left.entity.key, key),
);
let j5 = JoinNode::new(
j4,
n5,
equal_bi(|v: &P4<'_>| v.left.left.left.left.entity.key, key),
);
let mut c = OperatorTerminal::new(
ConstraintRef::new("test", "depth6"),
ImpactType::Penalty,
j5,
depth6_weight,
false,
);
let mut m = Model {
values: vec![Value { key: 1, weight: 1 }, Value { key: 1, weight: 2 }],
};
let oracle = |m: &Model| {
let mut sum = 0i64;
let mut matches = 0i64;
for a in &m.values {
for b in &m.values {
for d in &m.values {
for e in &m.values {
for f in &m.values {
for g in &m.values {
if a.key == b.key
&& b.key == d.key
&& d.key == e.key
&& e.key == f.key
&& f.key == g.key
{
sum += a.weight
+ b.weight
+ d.weight
+ e.weight
+ f.weight
+ g.weight;
matches += 1;
}
}
}
}
}
}
}
(SoftScore::of(-sum), matches)
};
assert_eq!(c.evaluate(&m), oracle(&m).0);
assert_eq!(c.match_count(&m) as i64, oracle(&m).1);
let mut score = c.initialize(&m);
for step in 0..60 {
let i = step % 2;
score = score + c.on_retract(&m, i, 0);
m.values[i].key = (step % 3) as u32;
m.values[i].weight = step as i64 - 30;
score = score + c.on_insert(&m, i, 0);
assert_eq!(score, oracle(&m).0);
assert_eq!(c.evaluate(&m), score);
assert_eq!(c.match_count(&m) as i64, oracle(&m).1);
}
c.reset();
assert_eq!(c.evaluate(&m), score);
assert_eq!(c.initialize(&m), score);
}