#![allow(deprecated)]
#![cfg(all(
feature = "math-linalg",
feature = "nn-norm",
feature = "nn-attention",
feature = "matching-substring",
feature = "matching-dfa",
feature = "crypto-blake3",
))]
fn split_buffers(program: &vyre::ir::Program) -> (Vec<String>, Vec<String>) {
let mut bindings = Vec::new();
let mut scratch = Vec::new();
for buffer in program.buffers() {
if buffer.kind() == vyre::ir::MemoryKind::Shared {
scratch.push(buffer.name().to_string());
} else {
bindings.push(buffer.name().to_string());
}
}
(bindings, scratch)
}
#[test]
fn contract_nn_softmax_exists() {
use vyre_libs::nn::attention::softmax;
let p = softmax("x", "y", 64);
let (bindings, scratch) = split_buffers(&p);
assert_eq!(bindings, vec!["x", "y"]);
assert_eq!(scratch, vec!["softmax_scratch", "softmax_max"]);
}
#[test]
fn contract_nn_layer_norm_exists() {
use vyre_libs::nn::norm::layer_norm;
let p = layer_norm("x", "out", 64, 1e-5);
let (bindings, scratch) = split_buffers(&p);
assert_eq!(bindings, vec!["x", "out"]);
assert_eq!(
scratch,
vec!["ln_sum_scratch", "ln_sq_scratch", "ln_stats"],
"layer_norm reduces through workgroup memory; these are its scratch tiles"
);
}
#[test]
fn contract_nn_attention_exists() {
use vyre_libs::nn::attention::attention;
let p = attention("q", "k", "v", "out", 64, 8);
let (bindings, scratch) = split_buffers(&p);
assert_eq!(bindings, vec!["q", "k", "v", "out"]);
assert_eq!(scratch, vec!["attention_scratch"]);
}
#[test]
fn contract_nn_attention_small_shapes_unroll_directly() {
use vyre_libs::nn::attention::attention;
let p = attention("q", "k", "v", "out", 8, 4);
let (bindings, scratch) = split_buffers(&p);
assert_eq!(bindings, vec!["q", "k", "v", "out"]);
assert!(
scratch.is_empty(),
"the unrolled path performs no workgroup reduction, so it needs no scratch: {scratch:?}"
);
assert_eq!(
p.workgroup_size(),
[1, 1, 1],
"straight-line code runs one invocation, not a cooperative tile"
);
}
#[test]
fn contract_matching_aho_corasick_exists() {
use vyre_libs::scan::aho_corasick;
let p = aho_corasick("haystack", "transitions", "accept", "matches", 16, 8);
assert_eq!(p.buffers().len(), 4);
}
#[test]
fn contract_crypto_blake3_exists() {
use vyre_libs::hash::blake3_compress;
let p = blake3_compress("chaining_in", "message", "params", "chaining_out");
assert_eq!(p.buffers().len(), 4);
}
#[test]
fn contract_substring_real_byte_compare() {
use vyre::ir::{Expr, Node};
use vyre_libs::scan::substring_search;
let program = substring_search("haystack", "needle", "matches", 5, 2);
fn contains_load_load_eq(nodes: &[Node]) -> bool {
nodes.iter().any(node_contains)
}
fn node_contains(node: &Node) -> bool {
match node {
Node::Block(children) | Node::Loop { body: children, .. } => {
contains_load_load_eq(children)
}
Node::If {
then,
otherwise,
cond,
} => {
expr_contains(cond)
|| contains_load_load_eq(then)
|| contains_load_load_eq(otherwise)
}
Node::Let { value, .. } | Node::Assign { value, .. } => expr_contains(value),
Node::Region { body, .. } => contains_load_load_eq(body),
_ => false,
}
}
fn expr_contains(expr: &Expr) -> bool {
use Expr::*;
match expr {
BinOp { op, left, right } => {
matches!(op, vyre::ir::BinOp::Eq)
&& matches!(left.as_ref(), Load { .. })
&& matches!(right.as_ref(), Load { .. })
|| expr_contains(left)
|| expr_contains(right)
}
Select {
cond,
true_val,
false_val,
} => expr_contains(cond) || expr_contains(true_val) || expr_contains(false_val),
_ => false,
}
}
assert!(
contains_load_load_eq(program.entry()),
"substring_search must contain a Load-vs-Load equality inside its k-loop; \
if this regresses, the inner compare has been replaced with a constant predicate (LAW 1)"
);
use vyre_reference::value::Value;
let haystack_bytes: Vec<u8> = "hello"
.bytes()
.flat_map(|b| u32::from(b).to_le_bytes())
.chain(std::iter::repeat_n(0u8, 12))
.collect();
let needle_bytes: Vec<u8> = "lo"
.bytes()
.flat_map(|b| u32::from(b).to_le_bytes())
.collect();
let matches_bytes = vec![0u8; 5 * 4];
let inputs = [
Value::from(haystack_bytes),
Value::from(needle_bytes),
Value::from(matches_bytes),
];
let outputs =
vyre_reference::reference_eval(&program, &inputs).expect("execute substring_search");
assert_eq!(outputs.len(), 1, "only matches buffer is ReadWrite");
let raw = outputs[0].to_bytes();
let words: Vec<u32> = raw
.chunks_exact(4)
.map(|c| u32::from_le_bytes(c.try_into().unwrap()))
.collect();
assert_eq!(words.len(), 5, "matches buffer has 5 u32 slots");
assert_eq!(words[3], 1, "match at byte offset 3");
for (i, w) in words.iter().enumerate() {
if i == 3 {
continue;
}
assert_eq!(*w, 0, "no match at byte offset {i}, got {w}");
}
}
#[test]
fn contract_math_matmul_tiled_exists() {
use vyre_libs::math::linalg::matmul_tiled;
let p = matmul_tiled("a", "b", "c", 64, 64, 64, 16);
let (bindings, scratch) = split_buffers(&p);
assert_eq!(bindings, vec!["a", "b", "c"]);
assert_eq!(
scratch.len(),
2,
"matmul_tiled stages one workgroup tile per input: {scratch:?}"
);
assert_eq!(p.workgroup_size(), [256, 1, 1]);
}