vyre-libs 0.7.2

vyre Category A library ecosystem - pure-IR compositions over foundation IR and primitive-owned kernels
Documentation
//! Elementwise logical operations (nand, nor).
//!
//! `and`, `or`, and `xor` are registered once, in `vyre_primitives::bitset`.
//! Only the synthesized combinations with no single-kernel equivalent live here.

macro_rules! define_synthesized_logical_binary {
    ($module:ident, $function:ident, $op_id:literal, $expr:expr, $expected:expr, $doc:literal) => {
        #[doc = $doc]
        pub mod $module {
            use super::wrap::build_logical_binary;
            use vyre_foundation::ir::Program;

            const OP_ID: &str = $op_id;

            /// Build the synthesized logical binary operation.
            #[must_use]
            pub fn $function(a: &str, b: &str, out: &str, size: u32) -> Program {
                build_logical_binary(OP_ID, a, b, out, size, $expr)
            }

            inventory::submit! {
                vyre_foundation::operation::OperationRegistration {
                    semantic_version: 1,
                    signature: None,
                    tier: vyre_foundation::operation::OperationTier::Library,
                    laws: &[],
                    tolerance: vyre_foundation::operation::TolerancePolicy::EXACT,
                    id: OP_ID,
                    build: Some(|| $function("a", "b", "out", 4)),
                    test_inputs: Some(|| {
                        let a = [0xFF00_FF00u32, 0x00FF_00FF, 0xFFFF_FFFF, 0x0000_0000];
                        let b = [0xF0F0_F0F0u32, 0x0F0F_0F0F, 0xFFFF_FFFF, 0x0000_0000];
                        let to_bytes = vyre_primitives::wire::pack_u32_slice;
                        vec![vec![to_bytes(&a), to_bytes(&b), vec![0u8; 16]]]
                    }),
                    expected_output: Some(|| {
                        let to_bytes = vyre_primitives::wire::pack_u32_slice;
                        vec![vec![to_bytes($expected)]]
                    }),
                    category: None,
                }
            }
        }
    };
}

define_synthesized_logical_binary!(
    nand,
    nand,
    "vyre-libs::logical::nand",
    |left, right| vyre_foundation::ir::Expr::bitnot(vyre_foundation::ir::Expr::bitand(left, right)),
    &[0x0FFF_0FFF, 0xFFF0_FFF0, 0x0000_0000, 0xFFFF_FFFF],
    "Bitwise NAND."
);
define_synthesized_logical_binary!(
    nor,
    nor,
    "vyre-libs::logical::nor",
    |left, right| vyre_foundation::ir::Expr::bitnot(vyre_foundation::ir::Expr::bitor(left, right)),
    &[0x000F_000F, 0xF000_F000, 0x0000_0000, 0xFFFF_FFFF],
    "Bitwise NOR."
);
mod wrap;

pub use nand::nand;
pub use nor::nor;

#[cfg(test)]
mod tests {
    use super::*;
    use vyre_reference::value::Value;

    fn eval_u32_binary(program: &vyre_foundation::ir::Program, a: &[u32], b: &[u32]) -> Vec<u32> {
        let outputs = vyre_reference::reference_eval(
            program,
            &[
                Value::from(vyre_primitives::wire::pack_u32_slice(a)),
                Value::from(vyre_primitives::wire::pack_u32_slice(b)),
                Value::from(vec![0_u8; a.len() * core::mem::size_of::<u32>()]),
            ],
        )
        .expect("Fix: logical elementwise program must execute in the reference interpreter.");
        vyre_primitives::wire::decode_u32_le_bytes_all(&outputs[0].to_bytes())
    }

    #[test]
    fn generated_nand_nor_match_scalar_reference() {
        let mut state = 0x10CC_A11E_u32;
        for case in 0..1024_u32 {
            state = state.wrapping_mul(1_664_525).wrapping_add(1_013_904_223);
            let len = (state as usize % 33) + 1;
            let mut a = Vec::with_capacity(len);
            let mut b = Vec::with_capacity(len);
            for index in 0..len {
                state = state.rotate_left(5) ^ (index as u32).wrapping_mul(0x9E37_79B9);
                a.push(match index % 4 {
                    0 => state,
                    1 => !state,
                    2 => 0,
                    _ => u32::MAX,
                });
                state = state.rotate_left(9) ^ (case.wrapping_mul(0x85EB_CA6B));
                b.push(match index % 5 {
                    0 => state,
                    1 => !state,
                    2 => 0xAAAA_AAAA,
                    3 => 0x5555_5555,
                    _ => u32::MAX,
                });
            }

            let nand_program = nand("a", "b", "out", len as u32);
            let nor_program = nor("a", "b", "out", len as u32);
            let expected_nand: Vec<u32> = a
                .iter()
                .zip(&b)
                .map(|(left, right)| !(left & right))
                .collect();
            let expected_nor: Vec<u32> = a
                .iter()
                .zip(&b)
                .map(|(left, right)| !(left | right))
                .collect();

            assert_eq!(
                eval_u32_binary(&nand_program, &a, &b),
                expected_nand,
                "case {case}"
            );
            assert_eq!(
                eval_u32_binary(&nor_program, &a, &b),
                expected_nor,
                "case {case}"
            );
        }
    }
}