solverforge-scoring 0.19.10

Incremental constraint scoring for SolverForge
Documentation
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, FlattenNode, FlattenView, JoinNode, Pair},
    Leaf,
};
use solverforge_core::{score::SoftScore, ConstraintRef, ImpactType};
#[derive(Clone, Debug)]
struct Entity {
    key: u32,
    children: Vec<i64>,
}
struct Model(Vec<Entity>);
fn entities(m: &Model) -> &[Entity] {
    &m.0
}
fn key(row: &Leaf<'_, Entity>) -> u32 {
    row.entity.key
}
fn children<'a>(_: &'a Model, row: Pair<Leaf<'a, Entity>, Leaf<'a, Entity>>) -> &'a [i64] {
    &row.right.entity.children
}
fn weight(
    _: &Model,
    row: &FlattenView<'_, Pair<Leaf<'_, Entity>, Leaf<'_, Entity>>, i64>,
) -> SoftScore {
    SoftScore::of(*row.value)
}
#[test]
fn borrowed_flattening_preserves_child_duplicates_and_both_owner_bindings() {
    let leaf = |binding| {
        CollectionNode::new(
            source(
                entities as fn(&Model) -> &[Entity],
                ChangeSource::Descriptor(0),
            ),
            binding,
        )
    };
    let joined = JoinNode::new(leaf(0), leaf(1), equal_bi(key, key));
    let flattened = FlattenNode::new(joined, children);
    let mut c = OperatorTerminal::new(
        ConstraintRef::new("test", "flatten"),
        ImpactType::Reward,
        flattened,
        weight,
        false,
    );
    let mut m = Model(vec![
        Entity {
            key: 1,
            children: vec![2, 2],
        },
        Entity {
            key: 1,
            children: vec![3],
        },
    ]);
    assert_eq!(c.evaluate(&m), SoftScore::of(14));
    assert_eq!(c.match_count(&m), 6);
    assert!(c
        .get_matches(&m)
        .iter()
        .all(|x| x.justification.entities.len() == 2));
    let mut score = c.initialize(&m);
    score = score + c.on_retract(&m, 0, 0);
    m.0[0].children = vec![9, 0, 9];
    m.0[0].key = 2;
    score = score + c.on_insert(&m, 0, 0);
    assert_eq!(score, SoftScore::of(21));
    assert_eq!(score, c.evaluate(&m));
    assert_eq!(c.match_count(&m), 4);
    score = score + c.on_retract(&m, 1, 0);
    m.0[1].children.clear();
    score = score + c.on_insert(&m, 1, 0);
    assert_eq!(score, SoftScore::of(18));
    assert_eq!(c.match_count(&m), 3);
    c.reset();
    assert_eq!(c.evaluate(&m), score);
    assert_eq!(c.initialize(&m), score);
}