vyre-primitives 0.6.2

Compositional primitives for vyre - marker types (always on) + Tier 2.5 LEGO substrate (feature-gated per domain).
Documentation
use super::*;

#[test]
fn plan_owns_padding_outputs_and_grid() {
    let plan = plan_ifds_csr_dispatch(
        2,
        2,
        2,
        &[(0, 0, 1)],
        &[(0, 1, 1, 0)],
        &[(0, 0, 1)],
        &[(1, 0, 0)],
    )
    .expect("Fix: valid IFDS CSR dispatch plan should build");

    assert_eq!(plan.grid, ifds_csr_dispatch_grid(1, 8));
    assert_eq!(plan.killed_words, 8);
    assert_eq!(plan.intra_field_words, 1);
    assert_eq!(plan.inter_field_words, 1);
    assert_eq!(plan.gen_field_words, 1);
    assert_eq!(plan.kill_field_words, 1);
    assert_eq!(plan.row_ptr_words, 9);
    assert_eq!(plan.row_cursor_words, 8);
    assert_eq!(plan.col_idx_words, 5);
    assert_eq!(plan.col_len_words, 1);
    assert_eq!(plan.max_col_count, 5);
    assert_eq!(
        plan.program_cache_key(),
        IfdsCsrProgramCacheKey {
            num_procs: 2,
            blocks_per_proc: 2,
            facts_per_proc: 2,
            intra_count: 1,
            inter_count: 1,
            gen_count: 1,
            kill_count: 1,
            max_col_count: 5,
        }
    );
    assert!(!plan.layout.empty);
}

#[test]
fn empty_plan_keeps_dispatch_buffers_nonempty_without_fake_rules() {
    let plan = plan_ifds_csr_dispatch(0, 0, 0, &[], &[], &[], &[])
        .expect("Fix: empty no-rule IFDS dispatch plan should be representable");

    assert!(plan.layout.empty);
    assert_eq!(plan.intra_field_words, 1);
    assert_eq!(plan.inter_field_words, 1);
    assert_eq!(plan.gen_field_words, 1);
    assert_eq!(plan.kill_field_words, 1);
    assert_eq!(plan.row_ptr_words, 1);
    assert_eq!(plan.row_cursor_words, 1);
    assert_eq!(plan.col_idx_words, 1);
    assert_eq!(plan.col_len_words, 1);
    assert_eq!(plan.grid, IFDS_CSR_EMPTY_DISPATCH_GRID);
}

#[test]
fn dispatch_grid_stays_single_block_for_lane_zero_builder() {
    let plan = plan_ifds_csr_dispatch(2, 2, 2, &[(0, 0, 1), (0, 1, 0), (1, 0, 1)], &[], &[], &[])
        .expect("Fix: multi-edge IFDS dispatch plan should build");

    assert_eq!(plan.layout.total_nodes, 8);
    assert_eq!(plan.layout.intra_count, 3);
    assert_eq!(plan.grid, ifds_csr_dispatch_grid(3, 8));
    assert_eq!(plan.grid, [1, 1, 1]);
    assert_eq!(plan.program().workgroup_size, IFDS_CSR_WORKGROUP_SIZE);
}

#[test]
fn large_dispatch_plan_does_not_launch_idle_blocks() {
    let intra = (0..513).map(|edge| (0, edge, edge + 1)).collect::<Vec<_>>();
    let plan = plan_ifds_csr_dispatch(1, 515, 4, &intra, &[], &[], &[])
        .expect("Fix: large IFDS CSR dispatch plan should build");

    assert_eq!(plan.layout.total_nodes, 2060);
    assert_eq!(plan.layout.intra_count, 513);
    assert_eq!(plan.grid, [1, 1, 1]);
    assert_eq!(ifds_csr_dispatch_grid(513, 2060), [1, 1, 1]);
}

#[test]
fn rule_input_fingerprint_distinguishes_same_count_rule_content() {
    let base = IfdsCsrRuleInputFingerprint::from_rules(
        &[(0, 0, 1)],
        &[(0, 1, 1, 0)],
        &[(0, 0, 1)],
        &[(1, 0, 0)],
    );

    assert_eq!(
        base,
        IfdsCsrRuleInputFingerprint::from_rules(
            &[(0, 0, 1)],
            &[(0, 1, 1, 0)],
            &[(0, 0, 1)],
            &[(1, 0, 0)],
        )
    );
    assert_ne!(
        base,
        IfdsCsrRuleInputFingerprint::from_rules(
            &[(0, 1, 0)],
            &[(0, 1, 1, 0)],
            &[(0, 0, 1)],
            &[(1, 0, 0)],
        )
    );
    assert_ne!(
        base,
        IfdsCsrRuleInputFingerprint::from_rules(
            &[(0, 0, 1)],
            &[(0, 1, 1, 1)],
            &[(0, 0, 1)],
            &[(1, 0, 0)],
        )
    );
}

#[test]
fn static_input_key_combines_program_shape_and_rule_content() {
    let plan = plan_ifds_csr_dispatch(1, 2, 1, &[(0, 0, 1)], &[], &[], &[])
        .expect("Fix: valid IFDS dispatch plan should build");
    let first = IfdsCsrRuleInputFingerprint::from_rules(&[(0, 0, 1)], &[], &[], &[]);
    let changed = IfdsCsrRuleInputFingerprint::from_rules(&[(0, 1, 0)], &[], &[], &[]);

    assert_eq!(plan.static_input_key(first), plan.static_input_key(first));
    assert_ne!(plan.static_input_key(first), plan.static_input_key(changed));
    assert_eq!(
        plan.static_input_key(first).program_key,
        plan.program_cache_key()
    );
}

#[test]
fn readback_validator_rejects_malformed_csr_outputs() {
    let plan = plan_ifds_csr_dispatch(1, 2, 1, &[(0, 0, 1)], &[], &[], &[])
        .expect("Fix: valid IFDS dispatch plan should build");
    let layout = &plan.layout;

    assert_eq!(
        validate_ifds_csr_readback(layout, &[0, 1, 1], &[1], 1)
            .expect("Fix: canonical readback should validate"),
        1
    );
    assert!(validate_ifds_csr_readback(layout, &[1, 1, 1], &[1], 1)
        .expect_err("Fix: row_ptr[0] drift must be rejected")
        .contains("row_ptr[0]"));
    assert!(validate_ifds_csr_readback(layout, &[0, 1, 0], &[1], 1)
        .expect_err("Fix: nonmonotonic row_ptr must be rejected")
        .contains("not monotonic"));
    assert!(validate_ifds_csr_readback(layout, &[0, 1, 1], &[2], 1)
        .expect_err("Fix: out-of-domain column must be rejected")
        .contains("outside total_nodes"));
}