khive-fold 0.14.0

Cognitive primitives — Fold, Anchor, Objective, Selector
Documentation
#[test]
fn empty_input() {
    let inputs: Vec<SelectorInput<()>> = vec![];
    let out = GreedySelector.select(inputs, 1000, &weights(0.0)).unwrap();
    assert!(out.selected.is_empty());
    assert_eq!(out.total_size, 0);
    assert_eq!(out.budget, 1000);
}

#[test]
fn packs_highest_scores_first() {
    let inputs = vec![
        input("a", 100, 0.5),
        input("b", 100, 0.9),
        input("c", 100, 0.7),
    ];
    let out = GreedySelector.select(inputs, 200, &weights(0.0)).unwrap();
    assert_eq!(out.selected.len(), 2);
    assert_eq!(out.selected[0].id, "b");
    assert_eq!(out.selected[1].id, "c");
    assert_eq!(out.total_size, 200);
}

#[test]
fn respects_budget() {
    let inputs = vec![
        input("a", 300, 0.9),
        input("b", 300, 0.8),
        input("c", 300, 0.7),
    ];
    let out = GreedySelector.select(inputs, 500, &weights(0.0)).unwrap();
    assert_eq!(out.selected.len(), 1);
    assert_eq!(out.selected[0].id, "a");
    assert_eq!(out.total_size, 300);
}

#[test]
fn filters_below_min_score() {
    let inputs = vec![
        input("a", 10, 0.8),
        input("b", 10, 0.1),
        input("c", 10, 0.5),
    ];
    let out = GreedySelector.select(inputs, 1000, &weights(0.3)).unwrap();
    assert_eq!(out.selected.len(), 2);
    assert_eq!(out.selected[0].id, "a");
    assert_eq!(out.selected[1].id, "c");
}

#[test]
fn filters_nan_and_inf() {
    let inputs = vec![
        input("nan", 10, f32::NAN),
        input("inf", 10, f32::INFINITY),
        input("neg_inf", 10, f32::NEG_INFINITY),
        input("ok", 10, 0.5),
    ];
    let out = GreedySelector.select(inputs, 1000, &weights(0.0)).unwrap();
    assert_eq!(out.selected.len(), 1);
    assert_eq!(out.selected[0].id, "ok");
}

#[test]
fn tie_break_size_ascending() {
    let inputs = vec![input("big", 200, 0.5), input("small", 50, 0.5)];
    let out = GreedySelector.select(inputs, 1000, &weights(0.0)).unwrap();
    assert_eq!(out.selected[0].id, "small");
    assert_eq!(out.selected[1].id, "big");
}

#[test]
fn tie_break_id_ascending() {
    let inputs = vec![input("z", 100, 0.5), input("a", 100, 0.5)];
    let out = GreedySelector.select(inputs, 1000, &weights(0.0)).unwrap();
    assert_eq!(out.selected[0].id, "a");
    assert_eq!(out.selected[1].id, "z");
}

#[test]
fn skips_oversized_items_takes_smaller() {
    let inputs = vec![
        input("huge", 900, 0.9),
        input("small1", 40, 0.3),
        input("small2", 40, 0.2),
    ];
    let out = GreedySelector.select(inputs, 100, &weights(0.0)).unwrap();
    assert_eq!(out.selected.len(), 2);
    assert_eq!(out.selected[0].id, "small1");
    assert_eq!(out.selected[1].id, "small2");
    assert_eq!(out.total_size, 80);
}

#[test]
fn zero_budget() {
    let inputs = vec![input("a", 1, 0.9)];
    let out = GreedySelector.select(inputs, 0, &weights(0.0)).unwrap();
    assert!(out.selected.is_empty());
}

#[test]
fn deterministic_across_input_order() {
    let a = vec![
        input("x", 50, 0.7),
        input("y", 50, 0.7),
        input("z", 50, 0.7),
    ];
    let b = vec![
        input("z", 50, 0.7),
        input("x", 50, 0.7),
        input("y", 50, 0.7),
    ];
    let out_a = GreedySelector.select(a, 100, &weights(0.0)).unwrap();
    let out_b = GreedySelector.select(b, 100, &weights(0.0)).unwrap();
    let ids_a: Vec<&str> = out_a.selected.iter().map(|i| i.id.as_str()).collect();
    let ids_b: Vec<&str> = out_b.selected.iter().map(|i| i.id.as_str()).collect();
    assert_eq!(ids_a, ids_b);
    assert_eq!(ids_a, vec!["x", "y"]);
}

#[test]
fn exact_budget_fit() {
    let inputs = vec![input("a", 50, 0.9), input("b", 50, 0.8)];
    let out = GreedySelector.select(inputs, 100, &weights(0.0)).unwrap();
    assert_eq!(out.selected.len(), 2);
    assert_eq!(out.total_size, 100);
}