Skip to content

add matvec builtin for matrix-vector product#517

Merged
danieljohnmorris merged 2 commits into
mainfrom
feature/matvec-builtin
May 21, 2026
Merged

add matvec builtin for matrix-vector product#517
danieljohnmorris merged 2 commits into
mainfrom
feature/matvec-builtin

Conversation

@danieljohnmorris
Copy link
Copy Markdown
Collaborator

Summary

Adds matvec xm ys > L n, a native matrix-vector product. Skips the wrap-as-column-matrix + flatten ceremony every linear-regression-style persona was paying:

flat (matmul xm (map (y:n>L n;[y]) ys))   ->   matvec xm ys

Three lines, ~10 tokens per use-site, gone. The linear-regression persona that surfaced this would have its flatten (matmul (transpose xm) (map (y:n>L n;[y]) ys)) recipe collapse to matvec (transpose xm) ys.

Closes pending.md #5an (P1+S).

Repro before / after

Before (manual recipe):

out = flat (matmul [[1,2,3],[4,5,6]] (map (y:n>L n;[y]) [7,8,9]))

After:

out = matvec [[1,2,3],[4,5,6]] [7,8,9]

Both produce [50, 122]; the regression suite asserts they stay equal.

What's in the diff

Single logical commit:

  • Builtin::Matvec variant + name/from-name/ALL (appended to preserve every existing on-wire tag) + builtin-name round-trip test arrays.
  • Verifier: ("matvec", &["L (L n)", "L n"], "L n") table row + a per-arg ILO-T013 arm.
  • Interpreter: #[inline(never)] fn matvec_run next to matrix_from_value / vec_from_value. Errors return ILO-R009 on empty matrix, zero-cols, ragged rows, and dim mismatch. The call_function arm is a single tail-call into the helper, matching the lstsq feature: add lstsq builtin for ordinary least squares #515 / feature: crypto primitives - sha256, hmac-sha256, base64, hex, ct-eq #494 / feat(builtins): URL + base64url encoding cluster (urlenc/urldec/b64u/b64u-dec) #506 pattern that keeps the dispatch frame off cargo-nextest's tighter stack budget.
  • VM: (Builtin::Matvec, 2) => true in is_tree_bridge_eligible, so VM and Cranelift JIT/AOT inherit semantics with no new opcodes.
  • Docs: SPEC.md linalg table row + linalg prose section, ai.txt (auto-regenerated by build.rs), skills/ilo/SKILL.md 4-char+ list, new Linear algebra section in skills/ilo/ilo-builtins-math.md, CHANGELOG Unreleased Added entry.
  • Tests: 9 cross-engine cases in tests/regression_matvec.rs (identity, 2x2, 2x3, 1x1, negatives+zeros, parity vs flat matmul ceremony, dim mismatch, empty, ragged). VM + Cranelift JIT; error tests are VM-only (matches the existing regression_linalg_basic.rs convention since the JIT path bubbles tree-bridge errors as nil).
  • examples/matvec.ilo worked example with -- run: / -- out: markers across every engine via tests/examples_engines.rs.

Test plan

  • cargo test --release --features cranelift --test regression_matvec — 9/9 pass
  • cargo test --release --features cranelift --test examples_engines — pass (matvec example runs through every engine)
  • cargo test --release --features cranelift full suite — pass (after the standard libilo.a symlink workaround for the AOT tests, pending #5av in flight as Claude/playwright ilo exploration r opnx #63)
  • cargo fmt --check clean
  • cargo clippy --release --features cranelift --all-targets -- -D warnings clean
  • Verifier rejects matvec [1,2,3] [4,5,6] (first arg not L (L n)) with ILO-T013
  • Verifier rejects matvec [[1,2],[3,4]] [[5,6]] (second arg not L n) with ILO-T013

Follow-ups

matvec xm ys returns the flat vector r[i] = sum_j xm[i][j] * ys[j].
One call instead of the wrap-as-column + matmul + flatten ceremony
every linear-regression-style persona was paying:

  flat (matmul xm (map (y:n>L n;[y]) ys))   ->   matvec xm ys

Three lines, ~10 tokens per use-site, gone. Same precision tier as
matmul (direct row-by-row dot product over f64), errors as ILO-R009
on dim mismatch, empty matrix, or ragged rows.

Tree-bridge eligible: composes existing matrix/vector helpers so VM
and Cranelift inherit through the bridge without new opcodes. The
implementation is wrapped #[inline(never)] from the start, matching
the recurring band-aid in #494 / #506 / lstsq for call_function's
oversized dispatch frame on cargo-nextest stack budgets.

Doc sync: SPEC.md linalg row + prose, ai.txt (auto-regenerated by
build.rs from SPEC.md), skills/ilo/SKILL.md 4-char+ list, new
Linear algebra section in skills/ilo/ilo-builtins-math.md, CHANGELOG
Unreleased Added entry.

9 cross-engine regression tests in tests/regression_matvec.rs cover
identity, 2x2 / 2x3 / 1x1 happy paths, negatives + zeros, parity
with the flat+matmul ceremony, and the ILO-R009 dim-mismatch /
empty / ragged error paths. examples/matvec.ilo gives agents a
worked example with -- run / -- out assertions across every engine.

Closes pending.md #5an.
@codecov
Copy link
Copy Markdown

codecov Bot commented May 21, 2026

Codecov Report

❌ Patch coverage is 90.80460% with 8 lines in your changes missing coverage. Please review.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
src/interpreter/mod.rs 91.66% 4 Missing ⚠️
src/verify.rs 88.23% 4 Missing ⚠️

📢 Thoughts on this report? Let us know!

Two ILO-T013 cases mirroring the matmul / dot pattern in
coverage_verify.rs. Lifts the codecov patch coverage past the
threshold by exercising the per-arg verifier rejections directly
(the runtime regression tests in tests/regression_matvec.rs hit
the happy path through the verifier, not the error branches).
@danieljohnmorris danieljohnmorris merged commit 6deeefe into main May 21, 2026
5 checks passed
@danieljohnmorris danieljohnmorris deleted the feature/matvec-builtin branch May 21, 2026 08:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant