fixes + substrate work: dn_tree, OntologySchema multi-parent, codex P2, simd_caps, PR-X10 A6 distance kernels#193
Conversation
Latent bug surfaced during the Pillar 13 drift-check wiring (#191): `make_probability_mask` used `p >= 0.5` to invert the (1-p) mask, which recursed with `1.0 - 0.5 = 0.5` infinitely whenever p was exactly 0.5. Pillar 13's independent re-derivation used the strict `p > 0.5` and correctly fell through to the AND-cascade — that's the canonical reference this fix matches. Real production usage (DNConfig default lr=0.03 with boost ~30 → effective_lr ≈ 0.9) never hit 0.5 exactly so the bug was dormant. Now that it's fixed: * Update Pillar 13's drift-check to use lr=0.5 (its canonical mid-range value per the pillar spec) instead of the lr=0.25 workaround. The drift-check now exercises the previously-broken branch and continues to pass bit-exactly. * Add two regression tests on dn_tree itself: - `make_probability_mask_at_half_terminates` — would stack-overflow if the fix regresses. - `make_probability_mask_at_half_is_bernoulli_half` — empirical popcount mean over N=1024 lands near 32 within 16 standard errors. No public API change. The fix is two characters: `>=` → `>`.
OWL permits a class to declare multiple `rdfs:subClassOf` triples (multi-inheritance); biomedical ontologies (FMA's ~75k anatomical classes, ChEBI, GO) use it extensively. Production `OntologySchema` previously stored a single `parent: Option<Box<str>>` and the `from_triples` loop silently overwrote on each new `subClassOf` triple — the second declared parent won, the first was discarded without warning. Identified during the FMA hydrator spec review (lance-graph/.claude/specs/pr-d-1-fma-owl-hydrator.md): Pattern D hydrates OWL ontologies through this code path, and silently losing half a class's inheritance edges would corrupt any downstream closure-based reasoning (is_ancestor, type-gated propagation). Changes: 1. `EntityClass` gains `extra_parents: Vec<Box<str>>` — additional parents beyond the first-observed. `parent: Option<Box<str>>` keeps the first observed parent (back-compat for single-parent consumers that read `.parent` directly). 2. `EntityClass::parents()` accessor — iterator over every parent in source order. Use this in preference to reading `.parent` when the caller's logic must cover multi-inheritance. 3. `from_triples` no longer silently overwrites: the first subClassOf populates `parent`; later ones append to `extra_parents` (dedup against the existing primary + extras). 4. `is_ancestor` walks the multi-parent DAG via BFS instead of the linear parent chain — this is the case the previous implementation silently missed. MAX_VISITS=4096 caps total work (defensive guard against cycles); single-parent chains still terminate at parent==None in the original O(depth) shape. 3 new regression tests: - `is_ancestor_multi_parent_direct` — two `subClassOf` triples on one class; both parents reachable. - `is_ancestor_multi_parent_transitive_through_second_parent` — the bug case: ancestor only reachable through the second parent chain. Would fail on the previous implementation. - `entity_class_parents_iterator_yields_all` — parents() surfaces every declared parent. All 18 ogit_bridge::schema tests pass; lib fmt + clippy clean.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 6a6acdf669
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if visits > MAX_VISITS { | ||
| return false; |
There was a problem hiding this comment.
Avoid false negatives from fixed MAX_VISITS limit
The new multi-parent traversal returns false once visits > 4096, which can incorrectly reject real ancestor relationships in large acyclic ontologies (or dense imported DAGs) where a descendant has more than 4096 reachable superclass nodes before the target ancestor is popped. This cap is now on total explored nodes rather than chain depth, so correctness depends on graph size/order rather than ancestry, and downstream closure checks can silently miss valid ancestors.
Useful? React with 👍 / 👎.
…(codex P2) Two CI fixes on PR #193: 1) Codex P2 — Drop the MAX_VISITS=4096 hard cap in `is_ancestor`. The previous cap could produce false-negatives on large biomedical ontologies (FMA: 75k classes; ChEBI: 200k+ classes) where a descendant has more than 4096 reachable superclass nodes before the target ancestor is popped. Termination is still guaranteed by the `visited: HashSet<&str>`: every parent IRI enters at most once, frontier pushes are gated on `visited.insert(...)`, so the total work bound is O(unique IRIs reachable from descendant) — finite by the schema's own finiteness. No explicit cap needed. 2) Rustfmt 1.95.0 collapse on the new `make_probability_mask_at_half_is_bernoulli_half` test assertion — same canonical-fmt collapse as prior hotfixes. No behavioral change beyond removing the artificial cap.
…t re-export First step in the substrate-graduation thread documented in #192's wrap-up: lift the substrate-tier modules out of `hpc/` (which was the rustynum migration staging area) to crate root, where they sit in scope of the W1a polyfill contract and no longer carry the spurious `std`-gate inherited from `hpc/`. `simd_caps` is the smallest and cleanest first move: * No internal `hpc/` dependencies (only `use std::sync::LazyLock`). * 8 internal callers; back-compat re-export keeps them working. * Pure CPU-detection metadata; the most polyfill-adjacent module in the entire `hpc/` set. Changes: 1. `src/hpc/simd_caps.rs` → `src/simd_caps.rs` (file move). 2. `src/lib.rs` adds `#[cfg(feature = "std")] pub mod simd_caps;`. The std-gate is retained for now (uses `std::sync::LazyLock`); lifting it to `core::sync::LazyLock` is a separate follow-up. 3. `src/hpc/mod.rs` replaces `pub mod simd_caps;` with `pub use crate::simd_caps;` — keeps `crate::hpc::simd_caps::*` resolving for cross-repo consumers (lance-graph, WoA, MedCare, q2 may have `use ndarray::hpc::simd_caps::*` imports that this preserves untouched). No public-API breakage; the test suite picks up the new path (test names now `simd_caps::tests::*` rather than `hpc::simd_caps::*`), all 10 tests pass under both default and `runtime-dispatch` configs. The 8 internal callers (`crate::simd_avx512`, `crate::hpc::p64_bridge`, `crate::simd_runtime::{cpu_ops, add_mul, vnni_dot}`) continue using `crate::hpc::simd_caps::*` via the re-export and work unmodified. Next graduation candidates (deferred to follow-up PRs): - `fingerprint` (bitwise substrate; raw `u64` polyfill audit) - `dn_tree` (bitwise substrate; same audit) - `ogit_bridge` (pure logic, no SIMD primitives) - `splat3d` (already uses `crate::simd::*` polyfilled types) Each move follows the same pattern: relocate file, drop std-gate inheritance where unneeded, keep back-compat re-export. Cognitive layer (pillar, plane, seal, merkle_tree, deepnsm, …) stays inside `hpc/` and keeps its legitimate std-gate.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughAdds three SIMD-polyfill distance kernels for arbitrary-length f64 slices, centralizes simd_caps at crate root, enables OWL-style multi-parent EntityClass with BFS ancestor resolution, and fixes make_probability_mask’s p==0.5 infinite-recursion bug with tests. ChangesSIMD Distance Functions
Ontology Schema Multi-Parent Inheritance
Probability Mask Edge Case Fix
Estimated Code Review Effort🎯 4 (Complex) | ⏱️ ~45 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 inconclusive)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
Lands the three slice-shape geometric distance kernels designated as worker A6 in `pr-x10-linalg-core-design.md` (lines 173-191). These are the salvaged kernels from the rolled-back PR #160 cross-repo arc (lance-graph `heel_f64x8::{l1, l2, linf}_f64_simd`), re-landed in ndarray at `crate::hpc::distance` per the `crate::hpc::linalg/mod.rs` hard boundary ("No distance metrics — those live in `crate::hpc::distance`"). The PR-X10 design doc named the destination as `linalg/distance.rs`, but the linalg-core sprint that landed on master made the call to keep distance at top-level `crate::hpc::distance` (sibling to linalg). This commit follows that decision — the slice-shape L1/L2/L∞ are natural extensions of the existing 3D-point-cloud distance functions already in the module. # Kernels - `l1_f64_simd(a, b) -> f64` — Σ |a_i - b_i| - `l2_f64_simd(a, b) -> f64` — √Σ (a_i - b_i)² - `linf_f64_simd(a, b) -> f64` — max |a_i - b_i| All three follow the `heel_f64x8::cosine_f64_simd` idiom: `F64x8` polyfill chunked path (8 elements per iteration) + scalar remainder. No `target_feature`, no `unsafe` — runtime dispatch is owned by the polyfill (AVX-512 native zmm / AVX2 2×ymm / scalar `[f64; 8]`). L1 and L∞ are EXACT precision (no rounding beyond the underlying subtract). L2 is VERIFY — final `sqrt` is 1 ULP; cross-chunk order matches the existing heel_f64x8 pattern (sequential across chunks + lane-tree within each F64x8). Documented in each function's docstring. # Tests (12 new) - Self-distance is exactly 0.0 for each kernel - Empty inputs return 0.0 - Boundary cases: 17 elements (1 chunk + 1 remainder), pythagoras on (3,0)/(0,4) for L2, max-pick within chunk for L∞ - Parity vs scalar on 10 sizes spanning chunk-aligned + remainder (n=1,7,8,15,16,17,64,199,200,1024), SplitMix64-seeded corpora - Mismatched-length slices use min(a.len(), b.len()), no panic All 24 `hpc::distance` tests pass; lib fmt + clippy clean. # Status of PR-X10's W1-W2 sprint after this commit A1-A12 worker outputs all present on master: A1 matrix.rs, A2 quat.rs, A3 inverse.rs, A4 eig_sym.rs, A5 svd.rs, A6 polar.rs + matfn.rs + distance.rs (this commit), A7 sh.rs, A8 conv.rs, A9 batched.rs/norm.rs/activations_ext.rs, A10 rope.rs/attention.rs, A11 loss.rs, A12 hilbert.rs The Hilbert-3D L4 P0-4 gate from pp13-brutally-honest-tester-verdict.md is already cleared on master — `hpc::linalg::hilbert` ships the Skilling 2004 algorithm (transpose-form + Gray code), with 13 tests including `level4_all_indices_unique` (exhaustive 4096-cell bijection) and `level4_curve_is_connected` (exhaustive 4095-pair Manhattan-1 connectivity). All pass. PP13's pillar-side P0-1/P0-2/P0-3 findings (Pillar 6/7.5/8 PASS-gate structural failures) are also resolved on master — 131 pillar tests pass under `--features pillar`, including the previously-flagged `prove_pillar_6_passes`, `prove_pillar_7_5_pass`, `prove_band_cardiac_pass`, `prove_band_respiratory_pass`, `prove_band_micro_pass`. PR-X10 W1-W2 sprint is now CLOSED.
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
src/hpc/ogit_bridge/schema.rs (1)
683-720: 💤 Low valueMinor doc inconsistency: comment says "BFS" but the algorithm is DFS.
The implementation uses
Vec::pop()(LIFO), making this a depth-first traversal rather than breadth-first. The reachability result is correct either way, but the comment at line 683 is technically inaccurate.📝 Suggested documentation fix
- // BFS over the multi-parent DAG. The previous version walked a + // DFS over the multi-parent DAG. The previous version walked aAlternatively, to make it true BFS, use
VecDeque::pop_front()instead ofVec::pop().🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/hpc/ogit_bridge/schema.rs` around lines 683 - 720, The comment incorrectly describes the traversal as "BFS" while the code performs DFS using `frontier: Vec<&str>` and `frontier.pop()` in the reachability loop; either update the comment to say "DFS (stack-based) over the multi-parent DAG" or switch the implementation to true BFS by replacing `frontier: Vec<&str>` with a `VecDeque<&str>`, use `frontier.push_back(descendant)` / `frontier.push_back(parent)` and `frontier.pop_front()` in the loop; reference the `frontier`, `visited`, `descendant`, `ancestor`, `self.entities.get(current)`, and `entity.parents()` symbols when making the change so the semantics remain identical apart from traversal order.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/hpc/pillar/hhtl_contraction.rs`:
- Around line 489-494: Comments and rationale around the test lr value are
stale: update all downstream commentary that references lr=0.25, “2 draws per
word”, and the “Why not lr=0.5” block to reflect TEST_LR = 0.5; specifically, in
hhtl_contraction.rs update any explanatory text near TEST_LR and in surrounding
doc/test comments (search for "lr=0.25", "2 draws per word", and "Why not
lr=0.5") so they describe the current behavior with lr=0.5 and why that value is
chosen, removing or rewriting any rationale that assumes the old 0.25 behavior.
---
Nitpick comments:
In `@src/hpc/ogit_bridge/schema.rs`:
- Around line 683-720: The comment incorrectly describes the traversal as "BFS"
while the code performs DFS using `frontier: Vec<&str>` and `frontier.pop()` in
the reachability loop; either update the comment to say "DFS (stack-based) over
the multi-parent DAG" or switch the implementation to true BFS by replacing
`frontier: Vec<&str>` with a `VecDeque<&str>`, use
`frontier.push_back(descendant)` / `frontier.push_back(parent)` and
`frontier.pop_front()` in the loop; reference the `frontier`, `visited`,
`descendant`, `ancestor`, `self.entities.get(current)`, and `entity.parents()`
symbols when making the change so the semantics remain identical apart from
traversal order.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 467d020f-14dc-4a8f-b483-5db7e29ebd8e
📒 Files selected for processing (7)
src/hpc/distance.rssrc/hpc/dn_tree.rssrc/hpc/mod.rssrc/hpc/ogit_bridge/schema.rssrc/hpc/pillar/hhtl_contraction.rssrc/lib.rssrc/simd_caps.rs
| // Was 0.25 to avoid the latent p=0.5 infinite-recursion bug in | ||
| // production's make_probability_mask; that bug is fixed in the | ||
| // same commit/PR that updates this constant. lr=0.5 now matches | ||
| // Pillar 13's canonical mid-range learning rate and exercises | ||
| // the previously-broken branch. | ||
| const TEST_LR: f64 = 0.5; |
There was a problem hiding this comment.
Update the drift-check rationale to match TEST_LR = 0.5.
After switching to 0.5, downstream comments in this test still describe lr=0.25 and “2 draws per word” assumptions. Please align those comments (including the “Why not lr=0.5” block) with current behavior to avoid misleading future edits.
Suggested comment-only cleanup
- // of next_u64() draws per word at p=0.25 (n=ceil(-log2(0.25))=2),
+ // of next_u64() draws per word at TEST_LR=0.5 (n=1),
...
- // 256 words × 2 draws = 1536) than pillar's bundle_step (16 words
- // × 2 draws = 32). Without re-seeding, post-trial-0 RNG states
+ // 256 words × 1 draw = 768) than pillar's bundle_step (16 words
+ // × 1 draw = 16). Without re-seeding, post-trial-0 RNG states
// diverge.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/hpc/pillar/hhtl_contraction.rs` around lines 489 - 494, Comments and
rationale around the test lr value are stale: update all downstream commentary
that references lr=0.25, “2 draws per word”, and the “Why not lr=0.5” block to
reflect TEST_LR = 0.5; specifically, in hhtl_contraction.rs update any
explanatory text near TEST_LR and in surrounding doc/test comments (search for
"lr=0.25", "2 draws per word", and "Why not lr=0.5") so they describe the
current behavior with lr=0.5 and why that value is chosen, removing or rewriting
any rationale that assumes the old 0.25 behavior.
|
@chatgpt-codex-connector this is fixed in Verification on current branch head // BFS over the multi-parent DAG. The previous version walked a
// linear chain via `EntityClass.parent` alone — correct for
// single-inheritance schemas but missed ancestors reachable
// only through `EntityClass.extra_parents` (OWL multi-inheritance,
// common in FMA / ChEBI).
//
// # Termination
//
// `visited` is a monotonically-growing `HashSet<&str>` keyed by
// IRI; each parent IRI enters the set at most once. Frontier
// pushes are gated on `visited.insert(...)`, so every IRI is
// pushed at most once across the entire walk. Total work is
// therefore O(unique IRIs reachable from descendant) — finite
// by the schema's finiteness, regardless of branching factor
// or depth. No explicit visit cap is needed; previous codex P2
// pointed out that a hard cap would produce false-negatives on
// large biomedical ontologies (FMA: 75k classes; ChEBI: 200k+).
let mut frontier: Vec<&str> = vec[descendant];
let mut visited: std::collections::HashSet<&str> = std::collections::HashSet::new();
visited.insert(descendant);
while let Some(current) = frontier.pop() {
// ... walk parents via entity.parents(), insert into visited+frontier
}No The fix-commit's message explicitly references this codex finding: "Codex P2 — Drop the MAX_VISITS=4096 hard cap in Generated by Claude Code |
|
To use Codex here, create an environment for this repo. |
Same canonical-fmt collapse as the prior pillar/ogit_bridge hotfixes on this PR. No behavioral change.
Continues the substrate-graduation thread documented in #192's wrap-up and extended in #193's simd_caps lift. Five more modules move from `crate::hpc::*` (the rustynum migration staging area) to crate root where they sit alongside `simd.rs`, `simd_runtime/`, `simd_caps`, and the W1a polyfill surface they're supposed to compose with. | Module | Reason | |---|---| | `bitwise` | Pure SIMD primitives (popcount, hamming over byte slices); already uses `crate::simd::U64x8` polyfill internally; already re-exported via `simd.rs:512`. | | `heel_f64x8` | All-F64x8 polyfill consumer (dot, cosine, sum-sq, weighted-hamming); already re-exported via `simd.rs:563`. | | `distance` | Spatial 3D + slice-shape L1/L2/L∞ (PR-X10 A6); the linalg/mod.rs hard-boundary comment now points here at root. | | `byte_scan` | Pure SIMD utility (needle search, delimiter find). | | `spatial_hash` | Pure SIMD utility (bucketing, candidate gather). | # Why these five, why now All five satisfied the low-hanging-fruit criteria from #193's wrap-up discussion: 1. No internal `hpc/` dependencies (only `super::simd_caps` which still resolves correctly because `simd_caps` is itself at crate root post-#192). 2. Already polyfill-clean — no raw-intrinsic refactor needed before the move. 3. Already partially exposed via `crate::simd::*` re-exports. The next graduation tier (`fingerprint`, `dn_tree`, `ogit_bridge`, `splat3d`) needs a polyfill audit before it can move, and `fingerprint` in particular is gated on the W1a-#5 POPCOUNT-U64 primitive landing (so its bit ops can route through `U64xN.popcnt()` instead of raw `u64.count_ones()`). # Back-compat preserved end-to-end Every cross-repo consumer using `ndarray::hpc::{bitwise, heel_f64x8, distance, byte_scan, spatial_hash}::*` continues to compile unmodified. The `src/hpc/mod.rs` declarations change from `pub mod X;` to `pub use crate::X;` — Rust re-exports modules just like other items, so `crate::hpc::X::*` resolves through to the same items as `crate::X::*`. Internal `super::simd_caps::simd_caps()` calls inside the moved files continue to work because `super::` at crate root resolves to `crate::*` which has `simd_caps` (graduated in #192). # Changes - `git mv` five files from `src/hpc/` to `src/`. - `src/lib.rs` gains five `#[cfg(feature = "std")] pub mod X;` declarations next to the existing `simd_caps` block, each with a one-liner docstring naming the graduation source and the substrate-tier reason for the move. - `src/hpc/mod.rs` replaces five `pub mod X;` with `pub use crate::X;` (back-compat re-exports). - `src/hpc/linalg/mod.rs` updates the hard-boundary comment from "No distance metrics — those live in `crate::hpc::distance`" to point at `crate::distance` (the new canonical path) with a parenthetical noting the back-compat re-export. - The `bitwise.rs` declaration in `src/hpc/mod.rs` is now a comment instead of being interleaved with `pub mod hdc`/`pub mod projection` to make the graduation status visible at a glance. # Verification - `cargo build -p ndarray --lib` — clean - `cargo build -p ndarray --lib --no-default-features` — clean (the new `#[cfg(feature = "std")]` gates match the existing `simd_caps` pattern; nostd targets see no change) - `cargo test -p ndarray --lib bitwise:: distance:: heel_f64x8:: byte_scan:: spatial_hash::` — all 119 tests on the five graduated modules pass at the new path (test names now `bitwise::tests::*` rather than `hpc::bitwise::tests::*`) - `cargo test -p ndarray --lib --features "pillar,ogit_bridge, runtime-dispatch" hpc::` — 2167 passed, 0 failed, 28 ignored - `cargo fmt --all --check` — clean - `cargo clippy --features "pillar,ogit_bridge,runtime-dispatch" --lib -- -D warnings` — clean # Next graduation candidates (deferred) - `hpc::fingerprint` — needs W1a-#5 POPCOUNT-U64 to land first so bit ops can route through `U64xN.popcnt()` instead of raw `u64.count_ones()`. Cognitive-shader-foundation explicitly names `Fingerprint<N>` as a MUST-be-in-`ndarray::simd::*` type. - `hpc::dn_tree` (bitwise core) — same polyfill-audit dependency. The cognitive DNTree/DNConfig/TraversalHit state stays in `hpc/` after the split. - `hpc::ogit_bridge` — pure logic, no SIMD, can move once the fingerprint + dn_tree audits are out of the way (avoids three partial graduations in flight at once). - `hpc::splat3d` — already mostly polyfill-clean; pure path rewrite. Defer because it's a larger consumer surface than the five in this PR.
Continues the substrate-graduation thread from #192 (simd_caps), #193 (clippy/doc cleanup), and #194 (bitwise/heel_f64x8/distance/ byte_scan/spatial_hash). Same low-hanging-fruit criteria — no internal hpc/ deps, polyfill-clean, single-line back-compat shim keeps every existing import resolving. | Module | Reason | |---|---| | `aabb` | SIMD AABB intersection/expansion/distance; only deps are | | | `crate::simd::F32x16` + `super::simd_caps` (graduated #192). | | `nibble` | 4-bit packed nibble batch ops; only dep is `crate::simd::U8x64`.| | `palette_codec` | Variable-width palette index codec (1-8 bit packing); zero deps.| | `property_mask` | AVX-512 VPTERNLOGD bitset queries on block state bits; | | | only dep is `crate::simd::U64x8`. | # Why these four, why now All four satisfy the criteria from #194's wrap-up: 1. No internal `hpc/` dependencies — only `crate::simd::*` (polyfill surface) and `super::simd_caps` (which is itself at crate root post-#192). 2. Polyfill-clean — no raw-intrinsic refactor required. 3. Single in-tree downstream caller (`hpc::framebuffer` uses `palette_codec`) → the `pub use crate::palette_codec;` back-compat shim keeps that resolution working zero-touch. # Mechanical changes - `git mv src/hpc/{aabb,nibble,palette_codec,property_mask}.rs src/` - `src/lib.rs`: added four `pub mod` declarations under `#[cfg(feature = "std")]`, each with a `# Example` rustdoc block per CLAUDE.md "all public APIs need doc comments with examples". - `src/hpc/mod.rs`: replaced the four `pub mod` declarations with `pub use crate::{aabb, nibble, palette_codec, property_mask};` back-compat re-exports. `crate::hpc::aabb::*` and friends keep resolving for every existing call site, identical to how `crate::hpc::bitwise::*` works post-#194. # Clippy / lint cleanup 17 clippy errors surfaced under `-D warnings` once the modules left the `hpc/mod.rs` `#![allow(clippy::all, ...)]` umbrella. Fixed each at the canonical Rust idiom (the #194 cleanup pattern, 417131b), no umbrella re-application: - **manual_div_ceil (6 sites)** — `(n + d - 1) / d` → `n.div_ceil(d)` in `nibble.rs` (x2), `palette_codec.rs` (x3), `property_mask.rs`. - **needless_range_loop (10 sites)** — `for i in start..vec.len()` rewrites to `for x in &vec[start..]` (when index unused) or `for (i, &x) in iter().enumerate().skip(start)` (when index used). Sites: `aabb.rs` x4, `nibble.rs` x3, `palette_codec.rs` x1, `property_mask.rs` x2. - **missing_docs (4 sites)** — added field doc comments on `pub struct Aabb { min, max }` and `pub struct Ray { origin, inv_dir }`. Previously masked by the `hpc/mod.rs` umbrella's `#![allow(missing_docs)]`. # Doctest correction Initial `# Example` in `src/lib.rs` for `palette_codec` asserted `bits_for_palette_size(1) == 1` per the module's own docstring table, but the impl returns 0 for `palette_size <= 1` (trivial- palette special case). Changed assertion to use `bits_for_palette_ size(2) == 1` — exercises the same code path with input the impl actually handles per spec. # Verification ``` cargo check --lib green cargo clippy --lib -- -D warnings green cargo clippy --lib --features rayon -- -D warnings green cargo clippy --features approx,serde,rayon -- -D warnings green cargo test --doc (15 graduated-module doctests) pass cargo test --lib (104 unit tests across 4 modules) pass ``` # What's next `hpc/` inventory: ~55 → ~51 modules at the staging path. Next-batch candidates per the same criteria need a deps audit before move: `framebuffer` (uses `palette_codec` shim, otherwise crate-root), `ocr_simd`/`ocr_felt`, `audio`. Filed in AGENT_LOG entry for the follow-up pass. https://claude.ai/code/session_01HbqooFZHAjaUtFEzhA1R2u
Summary
Five threads across the post-#192 backlog and the PR-X10 W1-W2 sprint, all on the same branch per the task's single-branch development constraint. Each commit is self-contained and independently mergeable; reviewer can request a split if preferred.
428f4969>=→>. Plus regression tests + Pillar 13 drift-check switches from lr=0.25 workaround to canonical lr=0.5.6a6acdf6EntityClass.extra_parentsfield,parents()iterator,is_ancestorBFS upgrade. 3 new regression tests.510d5f36visited: HashSetalready provides O(N) termination. Plus rustfmt 1.95.0 collapse.ef07808fsrc/hpc/simd_caps.rs→src/simd_caps.rswithpub use crate::simd_caps;back-compat re-export incrate::hpc::*. No API breakage; cross-repouse ndarray::hpc::simd_caps::*imports keep working unmodified.l1/l2/linf_f64_simdslice kernels5441435al1_f64_simd(Manhattan),l2_f64_simd(Euclidean),linf_f64_simd(Chebyshev). Salvaged from the rolled-back PR #160 cross-repo arc (lance-graphheel_f64x8::{l1, l2, linf}_f64_simd), re-landed atcrate::hpc::distanceper thecrate::hpc::linalg/mod.rshard boundary ("No distance metrics — those live incrate::hpc::distance"). 12 new tests, all 24hpc::distancetests pass. Polyfill-clean (notarget_feature, nounsafe).Why all in one PR
Branch constraint: the task description pins all development to
claude/continue-ndarray-x0Oaw, so commits stack on the same branch sequentially. Each commit is logically independent — if you want them split into separate PRs, the cleanest path is to merge in chronological order and then re-base any remaining commits onto fresh master. Otherwise they review fine together since they touch entirely disjoint files except for the back-compat re-export line insrc/hpc/mod.rs.dn_tree fix (
428f4969)Production usage (DNConfig default
lr=0.03with boost up to ~30 → effective_lr ≈ 0.9) never hit p=0.5 exactly so the bug was dormant. Pillar 13's independently-derivedprobability_maskused the strictp > 0.5and correctly fell through to the AND-cascade — that was the canonical reference this fix matches.Two regression tests:
make_probability_mask_at_half_terminates— would stack-overflow if the fix regresses.make_probability_mask_at_half_is_bernoulli_half— empirical popcount mean over N=1024 lands within 16 SEs of 32.The Pillar 13 drift-check (
pillar_13_matches_production_bundle_into) updatesTEST_LRfrom 0.25 → 0.5 — the canonical mid-range value the pillar was originally designed for. Still passes bit-exactly across all 16 trials.OntologySchema multi-parent (
6a6acdf6)Why it matters now: the lance-graph FMA OWL hydrator spec (PR-D-1) pipes ~75k anatomical classes through this code path. Silently discarding multi-parent edges would corrupt closure-based reasoning everywhere — type-gated cascade propagation in the cognitive shader,
is_ancestorqueries, the closure axes Pillar 14 drift-checks.Back-compat:
EntityClass.parent: Option<Box<str>>keeps its semantics — first-observed parent IRI. Newextra_parents: Vec<Box<str>>holds the rest. Single-parent ontologies (RDFS-style chain test fixtures) are unchanged byte-for-byte.is_ancestorBFS rewrite: previous linear walk viaentity.parentwould miss any ancestor reachable only through the second/third parent of a multi-inheritance class. Now uses BFS overentity.parents()(chains primary + extras). Single-parent chains still terminate atparent==Nonein the original O(depth) shape — no perf regression on the common case.3 new regression tests:
is_ancestor_multi_parent_direct,is_ancestor_multi_parent_transitive_through_second_parent(the bug case the previous implementation silently missed),entity_class_parents_iterator_yields_all.Codex P2 + FMT (
510d5f36)chatgpt-codex-connector on
6a6acdf669: the new BFS had a hardMAX_VISITS=4096cap that could produce false-negatives on schemas with more than 4096 reachable superclass nodes. FMA has 75k classes; ChEBI has 200k+. Removed; termination is still guaranteed byvisited: HashSet<&str>(each parent IRI enters at most once, gated frontier pushes ⇒ O(unique IRIs reachable) total work, finite by schema finiteness).simd_caps graduation (
ef07808f)First step in the substrate-graduation thread documented in #192's wrap-up note. The
hpc/namespace was the rustynum migration staging area; substrate-tier modules are accumulated there but architecturally belong at crate root next tosimd.rs/simd_runtime/.simd_capsis the smallest and cleanest first move:hpc/dependencies (onlystd::sync::LazyLock).hpc/.Changes:
src/hpc/simd_caps.rs→src/simd_caps.rs(git mv).src/lib.rsadds#[cfg(feature = "std")] pub mod simd_caps;. std-gate retained for now (usesstd::sync::LazyLock);core::sync::LazyLockfollow-up could lift it.src/hpc/mod.rsreplacespub mod simd_caps;withpub use crate::simd_caps;— keepscrate::hpc::simd_caps::*resolving for cross-repouse ndarray::hpc::simd_caps::*imports.Next graduation candidates (deferred):
fingerprint,dn_tree,ogit_bridge,splat3d. Each is its own focused PR following the same pattern; cognitive layer stays insidehpc/.PR-X10 A6 closeout — slice-shape geometric distance (
5441435a)Lands the three slice-shape kernels designated as worker A6 in
pr-x10-linalg-core-design.md(lines 173-191). These are the salvaged kernels from the rolled-back PR #160 cross-repo arc (lance-graphheel_f64x8::{l1, l2, linf}_f64_simd), re-landed in ndarray atcrate::hpc::distanceper thecrate::hpc::linalg/mod.rshard boundary ("No distance metrics — those live incrate::hpc::distance").The PR-X10 design doc named the destination as
linalg/distance.rs, but the linalg-core sprint that landed on master made the call to keep distance at top-levelcrate::hpc::distance(sibling to linalg). This commit follows that decision — the slice-shape L1/L2/L∞ are natural extensions of the existing 3D-point-cloud distance functions already in the module.Kernels:
l1_f64_simd(a, b) -> f64— Σ |a_i - b_i| (EXACT precision class)l2_f64_simd(a, b) -> f64— √Σ (a_i - b_i)² (VERIFY — 1 ULP from sqrt)linf_f64_simd(a, b) -> f64— max |a_i - b_i| (EXACT precision class)All three follow the
heel_f64x8::cosine_f64_simdidiom:F64x8polyfill chunked path (8 elements per iteration) + scalar remainder. Notarget_feature, nounsafe— runtime dispatch is owned by the polyfill (AVX-512 native zmm / AVX2 2×ymm / scalar[f64; 8]).Tests (12 new):
min(a.len(), b.len()), no panicStatus of PR-X10's W1-W2 sprint after this commit: all A1-A12 worker outputs present on master. The Hilbert-3D L4 P0-4 gate from
pp13-brutally-honest-tester-verdict.mdis already cleared on master (Skilling 2004 algorithm, 13 tests including exhaustive 4096-cell bijection + connectivity). PP13's pillar-side P0-1/P0-2/P0-3 findings (Pillar 6/7.5/8 structural threshold failures) are also resolved on master — 131 pillar tests pass under--features pillar. PR-X10 W1-W2 sprint is now CLOSED with this commit.Verification (across all five commits)
Threads accounted for
simd_capsonlyfingerprint/dn_tree/ogit_bridge/splat3ddeferred)Summary by CodeRabbit
New Features
Bug Fixes
Chores