diff --git a/.claude/SURGERY_BLACKBOARD.md b/.claude/SURGERY_BLACKBOARD.md index 4336789..60134c4 100644 --- a/.claude/SURGERY_BLACKBOARD.md +++ b/.claude/SURGERY_BLACKBOARD.md @@ -1,5 +1,17 @@ # Brain Surgery Blackboard — Session State +## Audit Status (2026-03-22) + +- All 25 tasks across 5 roles (Surgeon, Locksmith, Bridge, Bouncer, Seal) remain PENDING — 0/25 completed +- server.rs (3717 lines) still uses CogRedis directly, not RedisAdapter +- P1 (src/query/cypher.rs) and P3 (src/query/lance_parser/) still exist — deletion tasks not started +- SPO module promoted to src/spo/ (18 files) — DONE +- SPO Merkle hardening — DONE +- 16K-bit container — DONE +- Graph SPO on BindSpace (src/graph/spo/) — PARTIAL (9 files, disconnected from server) +- Awareness loop — NOT STARTED (no awareness_loop files found) +- Path dependencies: 11 path deps, compilation requires all siblings present + session_id: "brain-surgery-2026-03" started: "2026-03-12" orchestration_prompt: ".claude/prompts/18_brain_surgery_orchestration.md" @@ -44,3 +56,24 @@ decisions_made: [] notes: | Read .claude/prompts/18_brain_surgery_orchestration.md for full context. Read prompts 15, 16, 17, 17a BEFORE starting any work. + +## Integration Plan Reference (2026-03-22) + +The brain surgery tasks are now sequenced within the master integration plan. +They fall under **Plateau 2, Phase 2C** — only executed AFTER rustynum→ndarray +migration (2A) and lance-graph wiring (2B) are stable. + +**Pre-conditions for surgery:** +- ndarray builds and tests pass (Plateau 0) +- ladybug-rs compiles with ndarray (Phase 2A) +- P1/P3 dead code deleted (Phase 2B.1-2B.2) +- lance-graph Cypher works end-to-end through server.rs (Phase 2B.4) + +**Surgery task dependencies on integration phases:** +- S1/S2 (delete P1/P3): Unblocked → moved to Phase 2B.1/2B.2 +- L1-L5 (crystal API, codebook, truth): Blocked on Phase 2A.4 (ndarray types) +- B1-B5 (wire SPO to server): Blocked on Phase 2B.5 (lance-graph SPO backend) +- N1-N5 (cargo deps, dedup): Blocked on Phase 2B.4 (lance-graph Cypher) +- K1-K5 (UDF, query seal): Blocked on Phase 2B.6 (server.rs rewire) + +See: /home/user/INTEGRATION_PLAN.md diff --git a/.github/workflows/ci-master.yml b/.github/workflows/ci-master.yml index c4f43ad..424dfca 100644 --- a/.github/workflows/ci-master.yml +++ b/.github/workflows/ci-master.yml @@ -29,18 +29,15 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Init vendor submodules - run: git submodule update --init vendor/rustynum - - name: Clone sibling repos (OBLIGATORY deps) run: | - git clone --depth 1 https://github.com/AdaWorldAPI/rustynum.git ../rustynum + git clone --depth 1 https://github.com/AdaWorldAPI/ndarray.git ../ndarray git clone --depth 1 https://github.com/AdaWorldAPI/crewai-rust.git ../crewai-rust git clone --depth 1 https://github.com/AdaWorldAPI/n8n-rs.git ../n8n-rs - uses: dtolnay/rust-toolchain@master with: - toolchain: "1.93.0" + toolchain: "1.94.0" components: clippy, rustfmt - uses: Swatinem/rust-cache@v2 @@ -61,18 +58,15 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Init vendor submodules - run: git submodule update --init vendor/rustynum - - name: Clone sibling repos (OBLIGATORY deps) run: | - git clone --depth 1 https://github.com/AdaWorldAPI/rustynum.git ../rustynum + git clone --depth 1 https://github.com/AdaWorldAPI/ndarray.git ../ndarray git clone --depth 1 https://github.com/AdaWorldAPI/crewai-rust.git ../crewai-rust git clone --depth 1 https://github.com/AdaWorldAPI/n8n-rs.git ../n8n-rs - uses: dtolnay/rust-toolchain@master with: - toolchain: "1.93.0" + toolchain: "1.94.0" - uses: Swatinem/rust-cache@v2 @@ -98,18 +92,15 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Init vendor submodules - run: git submodule update --init vendor/rustynum - - name: Clone sibling repos (OBLIGATORY deps) run: | - git clone --depth 1 https://github.com/AdaWorldAPI/rustynum.git ../rustynum + git clone --depth 1 https://github.com/AdaWorldAPI/ndarray.git ../ndarray git clone --depth 1 https://github.com/AdaWorldAPI/crewai-rust.git ../crewai-rust git clone --depth 1 https://github.com/AdaWorldAPI/n8n-rs.git ../n8n-rs - uses: dtolnay/rust-toolchain@master with: - toolchain: "1.93.0" + toolchain: "1.94.0" components: clippy, rustfmt - uses: Swatinem/rust-cache@v2 @@ -120,47 +111,12 @@ jobs: - name: Rustfmt run: cargo fmt --all -- --check - # --------------------------------------------------------------------------- - # Miri — catches UB in unsafe code (split_at_mut, raw pointers, etc.) - # --------------------------------------------------------------------------- - miri: - name: Miri (unsafe validation) - needs: build - runs-on: ubuntu-latest - timeout-minutes: 15 - steps: - - uses: actions/checkout@v4 - - - name: Init vendor submodules - run: git submodule update --init vendor/rustynum - - - name: Clone sibling repos (OBLIGATORY deps) - run: | - git clone --depth 1 https://github.com/AdaWorldAPI/rustynum.git ../rustynum - git clone --depth 1 https://github.com/AdaWorldAPI/crewai-rust.git ../crewai-rust - git clone --depth 1 https://github.com/AdaWorldAPI/n8n-rs.git ../n8n-rs - - - uses: dtolnay/rust-toolchain@nightly - with: - components: miri - - - uses: Swatinem/rust-cache@v2 - with: - prefix-key: miri - - # 5 min timeout per target — Miri can run 1-3h without timeout - - name: Miri — lib tests (5 min timeout) - run: timeout 300 cargo miri test --lib -- --test-threads=1 - env: - MIRIFLAGS: "-Zmiri-disable-isolation" - continue-on-error: true - # --------------------------------------------------------------------------- # Summary # --------------------------------------------------------------------------- ci-summary: name: CI Summary - needs: [build, test, lint, miri] + needs: [build, test, lint] runs-on: ubuntu-latest if: always() steps: @@ -173,7 +129,6 @@ jobs: echo " Build: ${{ needs.build.result }}" echo " Test: ${{ needs.test.result }}" echo " Lint: ${{ needs.lint.result }}" - echo " Miri: ${{ needs.miri.result }}" echo "" PASS=true for r in "${{ needs.build.result }}" "${{ needs.test.result }}" "${{ needs.lint.result }}"; do diff --git a/.github/workflows/proof.yml b/.github/workflows/proof.yml index c547bda..856c96f 100644 --- a/.github/workflows/proof.yml +++ b/.github/workflows/proof.yml @@ -12,7 +12,7 @@ # # Total: 39 proofs verifying cognitive substrate invariants. # -# Rust version: pinned to 1.93.0 to match Dockerfile build environment. +# Rust version: pinned to 1.94.0 to match Dockerfile build environment. # RUSTFLAGS: -D warnings with targeted -A for noise lints in evolving codebase. # ============================================================================= @@ -56,18 +56,16 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Init vendor submodules - run: git submodule update --init vendor/rustynum - name: Clone sibling repos (OBLIGATORY deps) run: | - git clone --depth 1 https://github.com/AdaWorldAPI/rustynum.git ../rustynum + git clone --depth 1 https://github.com/AdaWorldAPI/ndarray.git ../ndarray git clone --depth 1 https://github.com/AdaWorldAPI/crewai-rust.git ../crewai-rust git clone --depth 1 https://github.com/AdaWorldAPI/n8n-rs.git ../n8n-rs - uses: dtolnay/rust-toolchain@master with: - toolchain: "1.93.0" + toolchain: "1.94.0" - uses: Swatinem/rust-cache@v2 - name: cargo check run: cargo check --lib --tests @@ -82,18 +80,16 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Init vendor submodules - run: git submodule update --init vendor/rustynum - name: Clone sibling repos (OBLIGATORY deps) run: | - git clone --depth 1 https://github.com/AdaWorldAPI/rustynum.git ../rustynum + git clone --depth 1 https://github.com/AdaWorldAPI/ndarray.git ../ndarray git clone --depth 1 https://github.com/AdaWorldAPI/crewai-rust.git ../crewai-rust git clone --depth 1 https://github.com/AdaWorldAPI/n8n-rs.git ../n8n-rs - uses: dtolnay/rust-toolchain@master with: - toolchain: "1.93.0" + toolchain: "1.94.0" - uses: Swatinem/rust-cache@v2 - name: Run foundation proofs run: cargo test --test proof_foundation -- --test-threads=1 --show-output @@ -108,18 +104,16 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Init vendor submodules - run: git submodule update --init vendor/rustynum - name: Clone sibling repos (OBLIGATORY deps) run: | - git clone --depth 1 https://github.com/AdaWorldAPI/rustynum.git ../rustynum + git clone --depth 1 https://github.com/AdaWorldAPI/ndarray.git ../ndarray git clone --depth 1 https://github.com/AdaWorldAPI/crewai-rust.git ../crewai-rust git clone --depth 1 https://github.com/AdaWorldAPI/n8n-rs.git ../n8n-rs - uses: dtolnay/rust-toolchain@master with: - toolchain: "1.93.0" + toolchain: "1.94.0" - uses: Swatinem/rust-cache@v2 - name: Run reasoning ladder proofs run: cargo test --test proof_reasoning_ladder -- --test-threads=1 --show-output @@ -134,18 +128,16 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Init vendor submodules - run: git submodule update --init vendor/rustynum - name: Clone sibling repos (OBLIGATORY deps) run: | - git clone --depth 1 https://github.com/AdaWorldAPI/rustynum.git ../rustynum + git clone --depth 1 https://github.com/AdaWorldAPI/ndarray.git ../ndarray git clone --depth 1 https://github.com/AdaWorldAPI/crewai-rust.git ../crewai-rust git clone --depth 1 https://github.com/AdaWorldAPI/n8n-rs.git ../n8n-rs - uses: dtolnay/rust-toolchain@master with: - toolchain: "1.93.0" + toolchain: "1.94.0" - uses: Swatinem/rust-cache@v2 - name: Run tactics proofs run: cargo test --test proof_tactics -- --test-threads=1 --show-output @@ -160,18 +152,16 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Init vendor submodules - run: git submodule update --init vendor/rustynum - name: Clone sibling repos (OBLIGATORY deps) run: | - git clone --depth 1 https://github.com/AdaWorldAPI/rustynum.git ../rustynum + git clone --depth 1 https://github.com/AdaWorldAPI/ndarray.git ../ndarray git clone --depth 1 https://github.com/AdaWorldAPI/crewai-rust.git ../crewai-rust git clone --depth 1 https://github.com/AdaWorldAPI/n8n-rs.git ../n8n-rs - uses: dtolnay/rust-toolchain@master with: - toolchain: "1.93.0" + toolchain: "1.94.0" - uses: Swatinem/rust-cache@v2 - name: Run level A gap proofs run: cargo test --test proof_level_a_gaps -- --test-threads=1 @@ -186,18 +176,16 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Init vendor submodules - run: git submodule update --init vendor/rustynum - name: Clone sibling repos (OBLIGATORY deps) run: | - git clone --depth 1 https://github.com/AdaWorldAPI/rustynum.git ../rustynum + git clone --depth 1 https://github.com/AdaWorldAPI/ndarray.git ../ndarray git clone --depth 1 https://github.com/AdaWorldAPI/crewai-rust.git ../crewai-rust git clone --depth 1 https://github.com/AdaWorldAPI/n8n-rs.git ../n8n-rs - uses: dtolnay/rust-toolchain@master with: - toolchain: "1.93.0" + toolchain: "1.94.0" - uses: Swatinem/rust-cache@v2 - name: Run all unit tests run: cargo test --lib -- --test-threads=4 diff --git a/CLAUDE.md b/CLAUDE.md index 57e8dd7..2bfbd3a 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -15,7 +15,8 @@ ladybug-rs CANNOT compile alone. It depends on sibling repos via relative paths: ``` REQUIRED (clone alongside ladybug-rs): ../rustynum/ rustynum-rs, rustynum-core, rustynum-bnn, rustynum-arrow, - rustynum-holo, rustynum-clam + rustynum-holo, rustynum-clam [MIGRATING → ndarray] + ../ndarray/ AdaWorldAPI/ndarray fork — HPC compute (Plateau 2 migration target) ../crewai-rust/ crewai-vendor (feature-gated behind "crewai") ../n8n-rs/ n8n-core, n8n-workflow, n8n-arrow, n8n-grpc, n8n-hamming ``` @@ -109,7 +110,7 @@ There is no `fn cold_to_hot()`. Their absence IS the architecture. ``` ladybug-rs role: "The Brain" in the four-repo architecture. - rustynum = The Muscle (SIMD substrate) + rustynum = The Muscle (SIMD substrate) [MIGRATING → ndarray, see INTEGRATION_PLAN.md] ladybug-rs = The Brain (BindSpace, SPO, server) ← THIS REPO staunen = The Bet (6 instructions, no GPU) lance-graph = The Face (Cypher/SQL query surface) @@ -152,6 +153,36 @@ cargo build --bin ladybug-server --- +## 8. Migration: rustynum → ndarray (Plateau 2) + +ladybug-rs currently depends on 6 rustynum crates for SIMD compute. These are being +superseded by `AdaWorldAPI/ndarray` (fork with 55 HPC modules, 880 tests). + +**What changes:** +- `rustynum::Fingerprint` → `ndarray::hpc::fingerprint::Fingerprint<256>` +- `rustynum::hamming_distance` → `ndarray::hpc::bitwise::hamming_distance_raw` +- `rustynum::TruthValue` → `ndarray::hpc::bf16_truth::BF16Truth` +- `rustynum::Cascade` → `ndarray::hpc::cascade::Cascade` +- BLAS L1-3: `rustyblas::*` → `ndarray::hpc::blas_level{1,2,3}::*` + +**What also changes:** +- lance-graph becomes the Cypher/graph query surface (replacing P1/P3 dead code) +- lance-graph semiring algebra replaces ad-hoc graph ops in src/graph/spo/ +- rs-graph-llm becomes the orchestration layer (replacing direct crewAI integration) + +**Migration order** (from INTEGRATION_PLAN.md Plateau 2): +1. Add ndarray as path dep (alongside rustynum, not replacing) +2. Create compat bridge (src/compat/ndarray_bridge.rs) +3. Migrate src/spo/ to ndarray types — CHECKPOINT: cargo check +4. Migrate src/nars/ to ndarray types +5. Migrate src/storage/ BindSpace — CHECKPOINT: cargo test +6. Remove rustynum deps — only after all tests pass + +**DO NOT** start this migration before ndarray builds clean (Plateau 0). +**DO NOT** migrate BindSpace and SPO simultaneously — SPO first, then BindSpace. + +--- + ## Session Documents (read in order for full context) ``` diff --git a/Cargo.toml b/Cargo.toml index eb46b23..1f7d8a2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,7 @@ exclude = ["vendor"] name = "ladybug" version = "0.3.0" edition = "2024" -rust-version = "1.93" +rust-version = "1.94" license = "Apache-2.0" description = "Crystal Lake: Unified Cognitive Database with 4096 CAM Operations, Quantum-Inspired Operators, and 144 Verb Graph Substrate" repository = "https://github.com/AdaWorldAPI/ladybug-rs" @@ -48,8 +48,8 @@ bench = [] # Benchmark suite (comparison vs Qdrant/Milvus) flight = ["arrow-flight", "tonic", "prost"] # Arrow Flight MCP server crewai = ["flight"] # crewAI orchestration (A2A, agent cards, thinking templates) json_fallback = [] # Legacy JSON MCP types (backwards compat) -# rustynum is OBLIGATORY — always included. Feature kept for test isolation only. -rustynum = [] +# ndarray replaces rustynum (2026-03-22). Feature kept for test isolation only. +ndarray-hpc = [] # vendor-n8n and vendor-crewai are OBLIGATORY — always included. # Feature flags kept as no-ops for backwards compatibility only. @@ -201,24 +201,22 @@ n8n-hamming = { path = "../n8n-rs/n8n-rust/crates/n8n-hamming" } crewai-vendor = { package = "crewai", path = "../crewai-rust" } # ----------------------------------------------------------------------------- -# Vendor: rustynum-rs (SIMD numerical library with AVX-512 VPOPCNTDQ + VNNI) -# Source: https://github.com/AdaWorldAPI/rustynum +# Vendor: ndarray (AdaWorldAPI fork with 55 HPC modules, replaces rustynum) +# Source: https://github.com/AdaWorldAPI/ndarray # Provides runtime-dispatched kernels: -# - VPOPCNTDQ popcount/hamming (8× speedup over scalar POPCNT) -# - VNNI VPDPBUSD int8 dot product (64× speedup for embeddings) -# - Optimized bundle (ripple-carry > per-bit counting) -# - GEMM for batch operations +# - VPOPCNTDQ popcount/hamming via hpc::bitwise +# - VNNI int8 dot product via simd_avx2::dot_i8 +# - Majority-vote bundle via hpc::hdc::HdcOps +# - BNN causal trajectory, cross-plane, shift detection +# - SigmaGate, CollapseGate, SignificanceLevel # - Zero-copy Container bridge: view_u64_as_bytes() -# Requires: stable Rust 1.93+ (AVX-512 intrinsics stabilized in 1.89) +# Requires: stable Rust 1.94+ # OBLIGATORY — always included, not behind a feature gate. # Uses sibling directory locally, vendor/ in Docker. # ----------------------------------------------------------------------------- -rustynum-rs = { path = "../rustynum/rustynum-rs" } -rustynum-core = { path = "../rustynum/rustynum-core", features = ["avx512"] } -rustynum-bnn = { path = "../rustynum/rustynum-bnn", features = ["avx512"] } -rustynum-arrow = { path = "../rustynum/rustynum-arrow", default-features = false, features = ["arrow"] } -rustynum-holo = { path = "../rustynum/rustynum-holo", features = ["avx512"] } -rustynum-clam = { path = "../rustynum/rustynum-clam", features = ["avx512"] } +ndarray = { path = "../ndarray" } + +# All rustynum dependencies removed (2026-03-22). ndarray replaces everything. # ============================================================================= # DEV DEPENDENCIES diff --git a/Dockerfile b/Dockerfile index ac3d7f9..c3b9e85 100644 --- a/Dockerfile +++ b/Dockerfile @@ -20,9 +20,9 @@ # ============================================================================= # STAGE 1: Builder — compile three binaries -# Rust 1.93 stable (edition 2024 support, full rmp-serde/time compat) +# Rust 1.94 stable (edition 2024 support, full rmp-serde/time compat) # ============================================================================= -FROM rust:1.93-slim-bookworm AS builder +FROM rust:1.94-slim-bookworm AS builder RUN apt-get update && apt-get install -y \ pkg-config libssl-dev cmake protobuf-compiler git \ diff --git a/Dockerfile.crewai b/Dockerfile.crewai index 053ed2b..c7f4bfd 100644 --- a/Dockerfile.crewai +++ b/Dockerfile.crewai @@ -15,7 +15,7 @@ # ============================================================================= # STAGE 1: Builder # ============================================================================= -FROM rust:1.93-slim-bookworm AS builder +FROM rust:1.94-slim-bookworm AS builder RUN apt-get update && apt-get install -y \ pkg-config libssl-dev cmake protobuf-compiler git \ diff --git a/Dockerfile.full b/Dockerfile.full index f5a2e4a..1371e65 100644 --- a/Dockerfile.full +++ b/Dockerfile.full @@ -14,7 +14,7 @@ # ============================================================================= # STAGE 1: Builder # ============================================================================= -FROM rust:1.93-slim-bookworm AS builder +FROM rust:1.94-slim-bookworm AS builder RUN apt-get update && apt-get install -y \ pkg-config libssl-dev cmake protobuf-compiler git \ diff --git a/Dockerfile.n8n b/Dockerfile.n8n index a463fc0..4dbc671 100644 --- a/Dockerfile.n8n +++ b/Dockerfile.n8n @@ -15,7 +15,7 @@ # ============================================================================= # STAGE 1: Builder # ============================================================================= -FROM rust:1.93-slim-bookworm AS builder +FROM rust:1.94-slim-bookworm AS builder RUN apt-get update && apt-get install -y \ pkg-config libssl-dev cmake protobuf-compiler git \ diff --git a/Dockerfile.release b/Dockerfile.release index b552910..f5d9959 100644 --- a/Dockerfile.release +++ b/Dockerfile.release @@ -12,7 +12,7 @@ # ============================================================================= # --- Stage 0: Chef planner --------------------------------------------------- -FROM rust:1.93-slim-bookworm AS chef +FROM rust:1.94-slim-bookworm AS chef RUN cargo install cargo-chef --locked WORKDIR /build diff --git a/MIGRATION_INVENTORY.md b/MIGRATION_INVENTORY.md new file mode 100644 index 0000000..cfe2b35 --- /dev/null +++ b/MIGRATION_INVENTORY.md @@ -0,0 +1,345 @@ +# Migration Inventory: rustynum → ndarray/hpc + +> Generated 2026-03-22. Covers the full `src/hpc/` surface plus upstream +> `rustynum-core`, `rustyblas`, `rustynum-bnn`, `rustynum-clam`, +> `rustynum-arrow`, and `rustynum-holo` crates. + +--- + +## Section 1 — Module Map & Line Counts + +### ndarray `src/hpc/` (target, 36 868 LOC total) + +| Module | LOC | Pub items | Origin crate | +|--------|----:|----------:|--------------| +| `activations.rs` | 86 | 1 | rustynum-core | +| `arrow_bridge.rs` | 931 | 26 | rustynum-arrow | +| `bf16_truth.rs` | 680 | 15 | rustynum-core | +| `binding_matrix.rs` | 416 | 6 | rustynum-core | +| `bitwise.rs` | 639 | 4 | rustynum-core | +| `blackboard.rs` | 781 | 48 | rustynum-core | +| `blas_level1.rs` | 278 | 3 | rustyblas | +| `blas_level2.rs` | 321 | 3 | rustyblas | +| `blas_level3.rs` | 345 | 2 | rustyblas | +| `bnn.rs` | 942 | 32 | rustynum-bnn | +| `bnn_causal_trajectory.rs` | 2116 | 62 | rustynum-bnn | +| `bnn_cross_plane.rs` | 1631 | 53 | rustynum-bnn | +| `cam_index.rs` | 478 | 18 | rustynum-core | +| `cascade.rs` | 758 | 17 | rustynum-core | +| `causality.rs` | 468 | 11 | rustynum-core | +| `clam.rs` | 2593 | 59 | rustynum-clam | +| `clam_compress.rs` | 707 | 16 | rustynum-clam | +| `clam_search.rs` | 612 | 6 | rustynum-clam | +| `cogrecord.rs` | 238 | 12 | rustynum-holo | +| `compression_curves.rs` | 1733 | — | ndarray-native | +| `crystal_encoder.rs` | 883 | 16 | ndarray-native | +| `cyclic_bundle.rs` | 741 | 13 | ndarray-native | +| `deepnsm.rs` | 845 | 13 | ndarray-native | +| `dn_tree.rs` | 739 | 21 | rustynum-core | +| `fft.rs` | 209 | 5 | ndarray-native | +| `fingerprint.rs` | 394 | 12 | rustynum-core | +| `graph.rs` | 282 | 15 | ndarray-native | +| `hdc.rs` | 178 | 1 | ndarray-native | +| `kernels.rs` | 1589 | 45 | rustynum-core | +| `lapack.rs` | 310 | 4 | ndarray-native | +| `merkle_tree.rs` | 521 | 8 | ndarray-native | +| `mod.rs` | 301 | — | — | +| `nars.rs` | 747 | 28 | ndarray-native | +| `node.rs` | 312 | 8 | rustynum-core | +| `organic.rs` | 783 | 18 | rustynum-core | +| `packed.rs` | 355 | 13 | rustynum-core | +| `plane.rs` | 758 | 25 | rustynum-core | +| `prefilter.rs` | 448 | 6 | rustynum-core | +| `projection.rs` | 143 | 3 | ndarray-native | +| `qualia.rs` | 613 | 8 | ndarray-native | +| `qualia_gate.rs` | 328 | 14 | rustynum-core | +| `quantized.rs` | 416 | 21 | rustyblas | +| `seal.rs` | 99 | 6 | rustynum-core | +| `spo_bundle.rs` | 1514 | 18 | ndarray-native | +| `statistics.rs` | 325 | 1 | ndarray-native (trait) | +| `substrate.rs` | 933 | 26 | rustynum-core | +| `surround_metadata.rs` | 1283 | 18 | ndarray-native | +| `tekamolo.rs` | 502 | 9 | ndarray-native | +| `udf_kernels.rs` | 789 | 10 | ndarray-native | +| `vml.rs` | 154 | 14 | ndarray-native | +| `vsa.rs` | 727 | 21 | ndarray-native | + +### rustynum upstream crates (source, ≈ 57 256 LOC total) + +| Crate | LOC | Key modules | +|-------|----:|-------------| +| `rustynum-core` | 26 055 | simd, kernels, bf16_hamming, substrate, blackboard, organic, packed, plane, prefilter, qualia_gate, cam_index, causality, cascade, dn_tree, fingerprint, node, seal, simd_avx2/512, backends/ | +| `rustyblas` | 5 584 | level1, level2, level3, bf16_gemm, int8_gemm | +| `rustynum-bnn` | 5 917 | bnn, causal_trajectory, cross_plane, rif_net_integration, belichtungsmesser | +| `rustynum-clam` | 5 869 | tree, search, compress, qualia_cam, semantic_protocol | +| `rustynum-arrow` | 5 010 | arrow_bridge, fragment_index, three_plane, horizontal_sweep, indexed_cascade, datafusion_bridge, lance_io, channel_index | +| `rustynum-holo` | 8 821 | holograph, focus, carrier, phase, cogrecord_v3, delta_layer, lod_pyramid, holo_search | + +--- + +## Section 2 — BLAS Parity (rustyblas → ndarray) + +### Level 1 (`blas_level1.rs` — 278 LOC, 3 pub fns) + +| rustyblas `level1.rs` | ndarray `blas_level1.rs` | Status | +|-----------------------|--------------------------|--------| +| `pub fn dot()` | `pub fn dot()` | PRESENT | +| `pub fn axpy()` | `pub fn axpy()` | PRESENT | +| `pub fn nrm2()` | `pub fn nrm2()` | PRESENT | +| `pub fn scal()` | — | MISSING | +| `pub fn asum()` | — | MISSING | +| `pub fn iamax()` | — | MISSING | +| `pub fn swap()` | — | MISSING | +| `pub fn copy()` | — | MISSING | +| `pub fn rotg()` | — | MISSING | + +**Gap**: 6 of 9 Level 1 routines missing. Only `dot`, `axpy`, `nrm2` ported. + +### Level 2 (`blas_level2.rs` — 321 LOC, 3 pub fns) + +| rustyblas `level2.rs` | ndarray `blas_level2.rs` | Status | +|-----------------------|--------------------------|--------| +| `pub fn gemv()` | `pub fn gemv()` | PRESENT | +| `pub fn ger()` | `pub fn ger()` | PRESENT | +| `pub fn trmv()` | `pub fn trmv()` | PRESENT | +| `pub fn trsv()` | — | MISSING | +| `pub fn symv()` | — | MISSING | +| `pub fn syr()` | — | MISSING | +| `pub fn syr2()` | — | MISSING | +| `pub fn gbmv()` | — | MISSING | +| `pub fn sbmv()` | — | MISSING | + +**Gap**: 6 of 9 Level 2 routines missing. Only `gemv`, `ger`, `trmv` ported. + +### Level 3 (`blas_level3.rs` — 345 LOC, 2 pub fns) + +| rustyblas `level3.rs` | ndarray `blas_level3.rs` | Status | +|-----------------------|--------------------------|--------| +| `pub fn gemm()` | `pub fn gemm()` | PRESENT | +| `pub fn syrk()` | `pub fn syrk()` | PRESENT | +| `pub fn trmm()` | — | MISSING | +| `pub fn trsm()` | — | MISSING | +| `pub fn symm()` | — | MISSING | + +**Gap**: 3 of 5 Level 3 routines missing. Only `gemm`, `syrk` ported. + +### Summary: 15 of 23 BLAS routines not yet migrated. + +--- + +## Section 3 — Statistics Trait (ndarray-native) + +The `statistics.rs` module defines a trait `StatisticsExt` with **13 methods** (not derived from rustynum; ndarray-native): + +| Method | Signature | +|--------|-----------| +| `sorted` | `fn sorted(&self) -> Array` | +| `median` | `fn median(&self) -> A` | +| `variance` | `fn variance(&self) -> A` | +| `std_dev` | `fn std_dev(&self) -> A` | +| `var_axis` | `fn var_axis(&self, axis: Axis) -> Array` | +| `std_axis` | `fn std_axis(&self, axis: Axis) -> Array` | +| `percentile` | `fn percentile(&self, p: A) -> A` | +| `cosine_similarity` | `fn cosine_similarity(&self, other: &Self) -> A` | +| `norm` | `fn norm(&self, p: u32) -> A` | +| `argmax` | `fn argmax(&self) -> usize` | +| `argmin` | `fn argmin(&self) -> usize` | +| `top_k` | `fn top_k(&self, k: usize) -> (Vec, Vec)` | +| `cumsum` | `fn cumsum(&self) -> Array` | + +--- + +## Section 4 — Quantized GEMM Verification + +All required quantized GEMM functions from `rustyblas` are present in `ndarray/hpc/quantized.rs`. + +### BF16 Type & Conversions + +| Symbol | rustyblas `bf16_gemm.rs` | ndarray `quantized.rs` | Match? | +|--------|--------------------------|------------------------|--------| +| `struct BF16(pub u16)` | line 33 | line 26 | YES | +| `BF16::from_f32()` | line 45 (rounded) | line 30 (truncate) | PARTIAL — naming inverted | +| `BF16::to_f32()` | line 56 | line 44 | YES | +| `BF16::ZERO` / `BF16::ONE` | lines 60-61 | — | MISSING | +| `f32_to_bf16_slice()` | line 84 | line 50 | YES | +| `f32_to_bf16_rounded()` | line 125 | line 58 | YES | +| `bf16_to_f32_slice()` | line 191 | line 66 | YES | +| `f32_vec_to_bf16()` | line 230 | line 74 | YES | +| `bf16_vec_to_f32()` | line 237 | line 79 | YES | + +### GEMM Functions + +| Symbol | rustyblas | ndarray | Match? | +|--------|-----------|---------|--------| +| `bf16_gemm_f32()` | bf16_gemm.rs:257 | quantized.rs:86 | YES | +| `mixed_precision_gemm()` | bf16_gemm.rs:429 | quantized.rs:136 | YES | + +### INT8 Quantization & GEMM + +| Symbol | rustyblas `int8_gemm.rs` | ndarray `quantized.rs` | Match? | +|--------|--------------------------|------------------------|--------| +| `QuantParams` | line 70 | line 155 | YES | +| `PerChannelQuantParams` | line 79 | line 168 | YES | +| `quantize_f32_to_u8()` | line 92 | line 176 | YES | +| `quantize_f32_to_i8()` | line 199 | line 196 | YES | +| `quantize_per_channel_i8()` | line 272 | line 211 | YES | +| `int8_gemm_i32()` | line 357 | line 238 | YES | +| `int8_gemm_f32()` | line 533 | line 253 | YES | +| `int8_gemm_per_channel_f32()` | line 582 | line 283 | YES | +| `quantize_f32_to_i4()` | line 659 | line 306 | YES | +| `dequantize_i4_to_f32()` | line 742 | line 335 | YES | + +### Quantized Gaps + +- `BF16::ZERO` and `BF16::ONE` constants exist in rustyblas but not in ndarray. +- `from_f32` / `from_f32_truncate` naming convention is inverted between codebases. + +--- + +## Section 5 — NaN Guard Audit + +### Unguarded Division Risks (action required) + +| File | Lines | Issue | Severity | +|------|-------|-------|----------| +| `statistics.rs` | 103, 123, 132 | `var_axis()` divides by `ax_len` without guarding for zero-length axis → NaN | **HIGH** | +| `cascade.rs` | 222-223 | Warmup mean/variance divides by `warmup_n` which is `128.min(num_vectors)` — zero if `num_vectors=0` | **MEDIUM** | +| `bf16_truth.rs` | 342-345 | `awareness_classify()` divides by `n_dims` (as f32) without guarding → `0.0/0.0 = NaN` | **MEDIUM** | + +### Properly Guarded Divisions (no action needed) + +| File | Location | Guard | +|------|----------|-------| +| `statistics.rs` | `median()` line 80 | n=0 early return (line 76-78) | +| `statistics.rs` | `variance()` lines 92, 96 | n=0 early return (line 88-90) | +| `statistics.rs` | `percentile()` line 158 | n=0,1 early returns (lines 151, 154) | +| `statistics.rs` | `cosine_similarity()` line 225 | norm=0 returns 0 (line 222) | +| `clam.rs` | LFD (line 92) | `count_half_r == 0` → return 0.0 (line 89) | +| `clam.rs` | leaf radius mean (line 228) | `num_leaves > 0` guard (line 227) | +| `clam.rs` | percentiles (lines 448-454) | n=0 early return (line 441) | +| `clam.rs` | cluster dist stats (lines 544, 552) | empty returns default (line 537-538) | +| `clam.rs` | inverse LFD (line 791) | clamped to `max(0.1)` (line 790) | +| `clam.rs` | NARS truth (line 1398) | overlap=0 returns ignorance (line 1395) | +| `clam.rs` | CHAODA anomaly (line 1579) | range clamped to `max(1e-10)` (line 1579) | +| `clam.rs` | compression ratio (line 1090) | `compressed_bytes > 0` (line 1089) | +| `cascade.rs` | calibrate (lines 109-110) | empty early return (line 105-106) | +| `cascade.rs` | observe (line 147) | observations incremented before division | +| `cascade.rs` | cosine similarity (lines 396, 428, 449) | norm guards at lines 383/410, 395/427, 445/448 | +| `cascade.rs` | BF16Hamming norm (line 471) | `max_total > 0` (line 470) | +| `bf16_truth.rs` | finest_distance (line 399) | `finest_max > 0` (line 399) | +| `nars.rs` | `from_evidence` (line 65) | `total <= 0.0` returns ignorance (line 62-63) | +| `nars.rs` | `to_evidence` (line 94) | `denom <= 1e-9` guard (line 87-92) | +| `nars.rs` | comparison (line 408) | `denom > 1e-9` guard | + +### CLAM Distance Note + +CLAM distances are `u64` Hamming — NaN is structurally impossible for the distance values themselves. Only derived floating-point statistics (LFD, anomaly scores, means) carry NaN risk, all audited above. + +--- + +## Section 6 — Not-Yet-Migrated rustynum Modules + +These modules exist in the upstream rustynum workspace but have **no counterpart** in ndarray `src/hpc/`: + +### rustynum-core + +| Module | LOC | Description | +|--------|----:|-------------| +| `simd.rs` | 1 092 | Portable SIMD abstractions | +| `simd_avx2.rs` | 600 | AVX2-specific kernels | +| `simd_avx512.rs` | 2 643 | AVX-512 kernels | +| `simd_isa.rs` | 215 | ISA detection | +| `simd_compat.rs` | 4 | Compat shim | +| `hybrid.rs` | 2 355 | Hybrid compute pipeline | +| `jitson.rs` | 1 688 | JIT JSON/binary codec | +| `jit_scan.rs` | 385 | JIT scan operations | +| `hdr.rs` | 631 | Header/metadata format | +| `tail_backend.rs` | 884 | Tail-read backend | +| `soaking.rs` | 407 | Soaking/warmup logic | +| `spatial_resonance.rs` | 758 | Spatial resonance | +| `layer_stack.rs` | 341 | Layer stack abstraction | +| `layout.rs` | 57 | Layout helpers | +| `mkl_ffi.rs` | 430 | MKL FFI bindings | +| `parallel.rs` | 101 | Parallelism utilities | +| `rng.rs` | 117 | RNG utilities | +| `compute.rs` | 316 | Compute dispatch | +| `delta.rs` | 209 | Delta encoding | +| `scalar_fns.rs` | 302 | Scalar math functions | +| `graph_hv.rs` | 869 | Graph hypervector ops | +| `backends/gemm.rs` | 453 | GEMM backend dispatch | +| `backends/popcnt.rs` | 153 | Popcount backend | +| `backends/xsmm.rs` | 659 | XSMM integration | + +### rustynum-arrow (partially migrated) + +| Module | LOC | In ndarray? | +|--------|----:|-------------| +| `arrow_bridge.rs` | 488 | YES (expanded to 931 LOC) | +| `fragment_index.rs` | 237 | NO | +| `three_plane.rs` | 857 | NO | +| `horizontal_sweep.rs` | 1 135 | NO | +| `indexed_cascade.rs` | 1 005 | NO | +| `datafusion_bridge.rs` | 779 | NO | +| `lance_io.rs` | 174 | NO | +| `channel_index.rs` | 239 | NO | + +### rustynum-holo (partially migrated) + +| Module | LOC | In ndarray? | +|--------|----:|-------------| +| `cogrecord_v3.rs` | 390 | YES (as `cogrecord.rs`, 238 LOC) | +| `holograph.rs` | 3 788 | NO | +| `focus.rs` | 1 378 | NO | +| `carrier.rs` | 1 090 | NO | +| `phase.rs` | 701 | NO | +| `delta_layer.rs` | 457 | NO | +| `lod_pyramid.rs` | 403 | NO | +| `holo_search.rs` | 477 | NO | + +### rustynum-bnn (partially migrated) + +| Module | LOC | In ndarray? | +|--------|----:|-------------| +| `bnn.rs` | 1 308 | YES (942 LOC) | +| `causal_trajectory.rs` | 2 072 | YES (2 116 LOC) | +| `cross_plane.rs` | 1 595 | YES (1 631 LOC) | +| `rif_net_integration.rs` | 776 | NO | +| `belichtungsmesser.rs` | 111 | NO | + +### rustynum-clam (partially migrated) + +| Module | LOC | In ndarray? | +|--------|----:|-------------| +| `tree.rs` | 1 112 | YES (as `clam.rs`, 2 593 LOC — expanded) | +| `search.rs` | 626 | YES (612 LOC) | +| `compress.rs` | 711 | YES (707 LOC) | +| `qualia_cam.rs` | 1 434 | NO | +| `semantic_protocol.rs` | 1 928 | NO | + +--- + +## Section 7 — Priority Recommendations + +### P0 — Fix Now (NaN bugs) +1. **`statistics.rs:var_axis()`** — add `if ax_len == 0 { return zeros }` guard +2. **`cascade.rs` warmup** — add `if warmup_n == 0 { return }` guard +3. **`bf16_truth.rs:awareness_classify()`** — add `if n_dims == 0 { return }` guard + +### P1 — Complete BLAS Surface +Port remaining 15 BLAS routines from rustyblas (`scal`, `asum`, `iamax`, `swap`, `copy`, `rotg`, `trsv`, `symv`, `syr`, `syr2`, `gbmv`, `sbmv`, `trmm`, `trsm`, `symm`). + +### P2 — Quantized Constants +Add `BF16::ZERO` and `BF16::ONE` constants. Reconcile `from_f32` naming convention with rustyblas. + +### P3 — Migrate High-Value Modules +- `rustynum-core/simd*.rs` (4 554 LOC) — portable SIMD + AVX2/512 kernels +- `rustynum-core/hybrid.rs` (2 355 LOC) — hybrid compute pipeline +- `rustynum-arrow/*` (4 426 LOC unmigrated) — horizontal_sweep, indexed_cascade, datafusion_bridge +- `rustynum-clam/semantic_protocol.rs` + `qualia_cam.rs` (3 362 LOC) +- `rustynum-holo/*` (8 294 LOC unmigrated) — holograph, focus, carrier, phase + +### P4 — Migrate Remaining Modules +- `rustynum-core/jitson.rs` + `jit_scan.rs` (2 073 LOC) +- `rustynum-core/backends/` (1 276 LOC) +- `rustynum-bnn/rif_net_integration.rs` + `belichtungsmesser.rs` (887 LOC) +- `rustynum-core` remaining small modules (~3 642 LOC) diff --git a/PROGRESS.md b/PROGRESS.md new file mode 100644 index 0000000..0a8d8f8 --- /dev/null +++ b/PROGRESS.md @@ -0,0 +1,44 @@ +# ladybug-rs — Progress Tracker + +> Tracks progress against the master integration plan plateaus. +> See /home/user/INTEGRATION_PLAN.md for full context. + +## Plateau 0: Everything Compiles + +- [ ] ladybug-rs is EXCLUDED from Plateau 0 (needs sibling repos) +- [x] Minimal build works: `cargo check --no-default-features --features "simd"` +- [ ] Full build requires all siblings present + +## Plateau 2: rustynum → ndarray + lance-graph Wiring + +### Phase 2A: ndarray Replaces rustynum +- [ ] 2A.1: Add ndarray as path dep alongside rustynum +- [ ] 2A.2: Create src/compat/ndarray_bridge.rs +- [ ] 2A.3: Migrate src/spo/ to ndarray Fingerprint — CHECKPOINT +- [ ] 2A.4: Migrate src/nars/ to ndarray BF16Truth +- [ ] 2A.5: Migrate src/storage/ BindSpace — HIGH RISK CHECKPOINT +- [ ] 2A.6: Full test suite passes +- [ ] 2A.7: Remove rustynum path deps + +### Phase 2B: lance-graph Wiring +- [ ] 2B.1: Delete P1 (src/query/cypher.rs, 1560 lines) +- [ ] 2B.2: Delete P3 (src/query/lance_parser/, 5532 lines) +- [ ] 2B.3: Wire lance-graph semirings into src/graph/spo/ +- [ ] 2B.4: Delegate Cypher execution to lance-graph — CHECKPOINT +- [ ] 2B.5: Wire lance-graph SPO store as backend +- [ ] 2B.6: Connect server.rs to lance-graph query surface + +### Phase 2C: Brain Surgery (25 tasks, 0/25 done) +- [ ] Surgeon S1-S5: Delete dead code, clean PRs, rename P4 +- [ ] Locksmith L1-L5: Crystal API, codebook, TruthValue unification +- [ ] Bridge B1-B5: Wire SPO to server, merge SPO variants +- [ ] Bouncer N1-N5: Cargo deps, dedup, logical plan +- [ ] Seal K1-K5: UDF registration, query sealing, Neo4j + +## Plateau 3: Full Stack + +- [ ] 3C.1: Implement SubstrateView in ladybug-rs (crewai-rust connection) +- [ ] 3C.2: Wire JitProfile into n8n-rs ModuleRuntime + +--- +*Last updated: 2026-03-22* diff --git a/crates/ladybug-contract/Cargo.toml b/crates/ladybug-contract/Cargo.toml index 7a484b5..1a5e527 100644 --- a/crates/ladybug-contract/Cargo.toml +++ b/crates/ladybug-contract/Cargo.toml @@ -2,7 +2,7 @@ name = "ladybug-contract" version = "0.1.0" edition = "2024" -rust-version = "1.93" +rust-version = "1.94" license = "Apache-2.0" description = "Substrate types for LadybugDB: Container, CogRecord, CAM codebook, CognitiveAddress" repository = "https://github.com/AdaWorldAPI/ladybug-rs" diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 5355133..76a06e6 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,2 +1,2 @@ [toolchain] -channel = "1.93.1" +channel = "1.94.0" diff --git a/src/core/rustynum_accel.rs b/src/core/rustynum_accel.rs index 847e698..a9d07e3 100644 --- a/src/core/rustynum_accel.rs +++ b/src/core/rustynum_accel.rs @@ -1,12 +1,12 @@ -//! RustyNum-accelerated operations for Fingerprint and Container. +//! ndarray-accelerated operations for Fingerprint and Container. //! -//! Provides runtime-dispatched AVX-512 kernels when the `rustynum` feature -//! is enabled. Key advantages over ladybug's built-in SIMD: +//! Provides runtime-dispatched AVX-512 kernels via ndarray's HPC modules +//! (replacing rustynum as of 2026-03-22). Key capabilities: //! //! - **Runtime dispatch** (`is_x86_feature_detected!`) — same binary works //! on any x86_64 CPU vs compile-time `#[cfg(target_feature)]` -//! - **VNNI int8 dot product** — new capability for embedding containers -//! - **Optimized bundle** — ripple-carry > per-bit counting for large n +//! - **VNNI int8 dot product** — for embedding similarity +//! - **Majority-vote bundle** — via ndarray::hpc::hdc::HdcOps //! - **Zero-copy bridge** — `view_u64_as_bytes` reinterprets `[u64; N]` as `&[u8]` //! without allocation //! @@ -25,6 +25,10 @@ use crate::FINGERPRINT_U64; use ladybug_contract::Container; use ladybug_contract::container::CONTAINER_WORDS; +// ndarray HPC imports (replacing rustynum-core::simd and rustynum-rs) +use ndarray::hpc::bitwise::{hamming_distance_raw, popcount_raw}; +use ndarray::hpc::hdc::HdcOps; + // ──────────────────────────────────────────────────────────────── // Zero-copy reinterpretation: [u64] → [u8] // ──────────────────────────────────────────────────────────────── @@ -51,7 +55,7 @@ pub fn view_u64_as_bytes(words: &[u64]) -> &[u8] { /// On AVX-512 VPOPCNTDQ hardware: 32 instructions (vs 256 scalar POPCNT). #[inline] pub fn fingerprint_popcount(fp: &Fingerprint) -> u32 { - rustynum_core::simd::popcount(view_u64_as_bytes(fp.as_raw())) as u32 + popcount_raw(view_u64_as_bytes(fp.as_raw())) as u32 } /// Hamming distance between two Fingerprints using runtime-dispatched VPOPCNTDQ. @@ -59,7 +63,7 @@ pub fn fingerprint_popcount(fp: &Fingerprint) -> u32 { /// On AVX-512 VPOPCNTDQ hardware: 32 XOR + 32 VPOPCNTDQ = 64 instructions. #[inline] pub fn fingerprint_hamming(a: &Fingerprint, b: &Fingerprint) -> u32 { - rustynum_core::simd::hamming_distance( + hamming_distance_raw( view_u64_as_bytes(a.as_raw()), view_u64_as_bytes(b.as_raw()), ) as u32 @@ -77,7 +81,7 @@ pub fn fingerprint_similarity(a: &Fingerprint, b: &Fingerprint) -> f32 { /// Useful for embedding similarity in CogRecord Container 3. #[inline] pub fn fingerprint_dot_i8(a: &Fingerprint, b: &Fingerprint) -> i64 { - rustynum_core::simd::dot_i8( + ndarray::simd_avx2::dot_i8( view_u64_as_bytes(a.as_raw()), view_u64_as_bytes(b.as_raw()), ) @@ -92,13 +96,13 @@ pub fn fingerprint_dot_i8(a: &Fingerprint, b: &Fingerprint) -> i64 { /// On AVX-512 VPOPCNTDQ hardware: 16 instructions (vs 128 scalar POPCNT). #[inline] pub fn container_popcount(c: &Container) -> u32 { - rustynum_core::simd::popcount(view_u64_as_bytes(&c.words)) as u32 + popcount_raw(view_u64_as_bytes(&c.words)) as u32 } /// Hamming distance between two Containers using runtime-dispatched VPOPCNTDQ. #[inline] pub fn container_hamming(a: &Container, b: &Container) -> u32 { - rustynum_core::simd::hamming_distance( + hamming_distance_raw( view_u64_as_bytes(&a.words), view_u64_as_bytes(&b.words), ) as u32 @@ -116,17 +120,16 @@ pub fn container_similarity(a: &Container, b: &Container) -> f32 { /// For embedding containers (CogRecord Container 3). #[inline] pub fn container_dot_i8(a: &Container, b: &Container) -> i64 { - rustynum_core::simd::dot_i8( + ndarray::simd_avx2::dot_i8( view_u64_as_bytes(&a.words), view_u64_as_bytes(&b.words), ) } -/// Bundle multiple Containers using rustynum's optimized majority-vote algorithm. +/// Bundle multiple Containers using ndarray's majority-vote algorithm. /// /// Zero-copy input: uses `view_u64_as_bytes` to reinterpret Container words -/// as byte slices without allocation. The `bundle_byte_slices` function -/// processes the slices directly — no intermediate NumArrayU8 wrapping. +/// as byte slices without allocation. pub fn container_bundle(items: &[&Container]) -> Container { if items.is_empty() { return Container::zero(); @@ -141,8 +144,7 @@ pub fn container_bundle(items: &[&Container]) -> Container { .map(|c| view_u64_as_bytes(&c.words)) .collect(); - let result_bytes = rustynum_rs::NumArrayU8::try_bundle_byte_slices(&slices) - .expect("bundle_byte_slices: all slices same length"); + let result_bytes = ndarray::Array::::hdc_bundle_byte_slices(&slices); // Convert back to Container let mut container = Container::zero(); @@ -163,21 +165,21 @@ pub fn container_bundle(items: &[&Container]) -> Container { /// Popcount on any `&[u64]` slice (zero-copy). Works for any container size. #[inline] pub fn slice_popcount(data: &[u64]) -> u64 { - rustynum_core::simd::popcount(view_u64_as_bytes(data)) + popcount_raw(view_u64_as_bytes(data)) } /// Hamming distance on any two `&[u64]` slices (zero-copy). #[inline] pub fn slice_hamming(a: &[u64], b: &[u64]) -> u64 { debug_assert_eq!(a.len(), b.len()); - rustynum_core::simd::hamming_distance(view_u64_as_bytes(a), view_u64_as_bytes(b)) + hamming_distance_raw(view_u64_as_bytes(a), view_u64_as_bytes(b)) } /// Signed i8 × i8 dot product on any two `&[u64]` slices. #[inline] pub fn slice_dot_i8(a: &[u64], b: &[u64]) -> i64 { debug_assert_eq!(a.len(), b.len()); - rustynum_core::simd::dot_i8(view_u64_as_bytes(a), view_u64_as_bytes(b)) + ndarray::simd_avx2::dot_i8(view_u64_as_bytes(a), view_u64_as_bytes(b)) } // ──────────────────────────────────────────────────────────────── @@ -186,7 +188,7 @@ pub fn slice_dot_i8(a: &[u64], b: &[u64]) -> i64 { /// Compute Hamming distance between two fingerprints. /// -/// Delegates to rustynum's runtime-dispatched SIMD (AVX-512 → AVX2 → scalar). +/// Delegates to ndarray's runtime-dispatched SIMD (AVX-512 → AVX2 → scalar). #[inline] pub fn hamming_distance(a: &Fingerprint, b: &Fingerprint) -> u32 { fingerprint_hamming(a, b) @@ -287,7 +289,7 @@ impl Default for HammingEngine { /// Detect SIMD capability at runtime pub fn simd_level() -> &'static str { - "rustynum-runtime-dispatch" + "ndarray-runtime-dispatch" } // ──────────────────────────────────────────────────────────────── diff --git a/src/graph/spo/store.rs b/src/graph/spo/store.rs index 4c1f638..d4883d8 100644 --- a/src/graph/spo/store.rs +++ b/src/graph/spo/store.rs @@ -804,9 +804,9 @@ impl SpoStore { /// - Gate 3: No SparseContainer::from_dense() in query path. Query operates on /// raw bytes via ClamTree SIMD Hamming. Y-axis check uses `hamming_dense_vs_sparse()`. /// - Gate 4: O(⌈d⌉·log 𝒩) via DFS pruning vs O(n) linear scan. -/// - Gate 7: Uses rustynum_clam::search::rho_nn (existing primitive). +/// - Gate 7: Uses ndarray::hpc::clam::rho_nn (existing primitive). pub struct ClamSpoIndex { - tree: rustynum_clam::tree::ClamTree, + tree: ndarray::hpc::clam::ClamTree, /// Flat byte buffer: X-axis dense fingerprints concatenated. /// Layout: [record_0: CONTAINER_BYTES] [record_1: CONTAINER_BYTES] ... data: Vec, @@ -900,13 +900,13 @@ impl ClamSpoIndex { } let count = dn_map.len(); - let config = rustynum_clam::tree::BuildConfig::default(); + let config = ndarray::hpc::clam::BuildConfig::default(); let tree = if count > 0 { - rustynum_clam::tree::ClamTree::build(&data, vec_len, count, &config) + ndarray::hpc::clam::ClamTree::build_with_config(&data, vec_len, count, &config) } else { // Empty tree for empty store — build with 1 zero vector let zero = vec![0u8; vec_len]; - rustynum_clam::tree::ClamTree::build(&zero, vec_len, 1, &config) + ndarray::hpc::clam::ClamTree::build_with_config(&zero, vec_len, 1, &config) }; Self { tree, data, dn_map } @@ -941,7 +941,7 @@ impl ClamSpoIndex { // Use 2× radius for X-axis alone since combined is (dx+dy)/2 ≤ radius // → dx can be up to 2×radius if dy=0. This ensures no false negatives. let x_rho = (radius as u64).saturating_mul(2); - let rho_result = rustynum_clam::search::rho_nn( + let rho_result = ndarray::hpc::clam::rho_nn( &self.tree, &self.data, SPARSE_VEC_LEN, @@ -1004,7 +1004,7 @@ impl ClamSpoIndex { query_bytes[start..start + 8].copy_from_slice(&src_fp.words[i].to_ne_bytes()); } let x_rho = (radius as u64).saturating_mul(2); - let result = rustynum_clam::search::rho_nn( + let result = ndarray::hpc::clam::rho_nn( &self.tree, &self.data, SPARSE_VEC_LEN, diff --git a/src/nars/truth.rs b/src/nars/truth.rs index 9660fd5..ef96b14 100644 --- a/src/nars/truth.rs +++ b/src/nars/truth.rs @@ -4,7 +4,7 @@ use std::fmt; -use rustynum_bnn::causal_trajectory::NarsTruth; +use ndarray::hpc::bnn_causal_trajectory::NarsTruth; /// NARS truth value: /// diff --git a/src/query/cognitive_udfs.rs b/src/query/cognitive_udfs.rs index d485a43..b0344b9 100644 --- a/src/query/cognitive_udfs.rs +++ b/src/query/cognitive_udfs.rs @@ -45,7 +45,7 @@ pub const FP_BYTES: usize = crate::FINGERPRINT_BYTES; /// when available (64 bytes/iteration), falling back to scalar POPCNT. #[inline] pub fn hamming_bytes(a: &[u8], b: &[u8]) -> u32 { - rustynum_core::simd::hamming_distance(a, b) as u32 + ndarray::hpc::bitwise::hamming_distance_raw(a, b) as u32 } /// Compute similarity from Hamming distance diff --git a/src/search/hdr_cascade.rs b/src/search/hdr_cascade.rs index 86be12c..1c2c7c9 100644 --- a/src/search/hdr_cascade.rs +++ b/src/search/hdr_cascade.rs @@ -208,7 +208,7 @@ impl MexicanHat { /// /// This replaces hardcoded DEFAULT_EXCITE/DEFAULT_INHIBIT with thresholds /// derived from the actual data distribution (μ, σ of the fingerprint space). - pub fn from_sigma_gate(gate: &rustynum_core::SigmaGate) -> Self { + pub fn from_sigma_gate(gate: &ndarray::hpc::kernels::SigmaGate) -> Self { Self { excite: gate.discovery, inhibit: gate.hint, @@ -661,7 +661,7 @@ impl AlienSearch { /// /// Uses `SigmaGate::sku_16k()` for 16K-bit fingerprints: /// excite = Discovery (3σ below noise), inhibit = Hint (1.5σ below noise). - pub fn with_sigma_gate(gate: &rustynum_core::SigmaGate) -> Self { + pub fn with_sigma_gate(gate: &ndarray::hpc::kernels::SigmaGate) -> Self { Self { index: HdrIndex::new(), hat: MexicanHat::from_sigma_gate(gate), @@ -675,7 +675,7 @@ impl AlienSearch { } /// Recalibrate Mexican hat from a SigmaGate. - pub fn calibrate_from_sigma(&mut self, gate: &rustynum_core::SigmaGate) { + pub fn calibrate_from_sigma(&mut self, gate: &ndarray::hpc::kernels::SigmaGate) { self.hat = MexicanHat::from_sigma_gate(gate); } @@ -1372,29 +1372,29 @@ pub fn classify_signal(mean: u8, sd: u8, distance: u32) -> SignalClass { /// This is the statistically grounded replacement for the hardcoded `classify_signal`. pub fn classify_sigma( distance: u32, - gate: &rustynum_core::SigmaGate, -) -> rustynum_core::SignificanceLevel { + gate: &ndarray::hpc::kernels::SigmaGate, +) -> ndarray::hpc::kernels::SignificanceLevel { if distance < gate.discovery { - rustynum_core::SignificanceLevel::Discovery + ndarray::hpc::kernels::SignificanceLevel::Discovery } else if distance < gate.strong { - rustynum_core::SignificanceLevel::Strong + ndarray::hpc::kernels::SignificanceLevel::Strong } else if distance < gate.evidence { - rustynum_core::SignificanceLevel::Evidence + ndarray::hpc::kernels::SignificanceLevel::Evidence } else if distance < gate.hint { - rustynum_core::SignificanceLevel::Hint + ndarray::hpc::kernels::SignificanceLevel::Hint } else { - rustynum_core::SignificanceLevel::Noise + ndarray::hpc::kernels::SignificanceLevel::Noise } } /// Bridge: convert `SignificanceLevel` to `SignalClass` for backwards compatibility. -pub fn significance_to_signal(level: rustynum_core::SignificanceLevel) -> SignalClass { +pub fn significance_to_signal(level: ndarray::hpc::kernels::SignificanceLevel) -> SignalClass { match level { - rustynum_core::SignificanceLevel::Discovery - | rustynum_core::SignificanceLevel::Strong => SignalClass::Strong, - rustynum_core::SignificanceLevel::Evidence => SignalClass::Moderate, - rustynum_core::SignificanceLevel::Hint => SignalClass::WeakButStackable, - rustynum_core::SignificanceLevel::Noise => SignalClass::Noise, + ndarray::hpc::kernels::SignificanceLevel::Discovery + | ndarray::hpc::kernels::SignificanceLevel::Strong => SignalClass::Strong, + ndarray::hpc::kernels::SignificanceLevel::Evidence => SignalClass::Moderate, + ndarray::hpc::kernels::SignificanceLevel::Hint => SignalClass::WeakButStackable, + ndarray::hpc::kernels::SignificanceLevel::Noise => SignalClass::Noise, } } diff --git a/src/spo/causal_trajectory.rs b/src/spo/causal_trajectory.rs index e5252c3..8382a04 100644 --- a/src/spo/causal_trajectory.rs +++ b/src/spo/causal_trajectory.rs @@ -33,13 +33,13 @@ //! full causal trajectory recording, NARS truth grounded in convergence dynamics, //! DN mutation guidance, and warm-start capability. -use rustynum_bnn::causal_trajectory::{ +use ndarray::hpc::bnn_causal_trajectory::{ CausalArrow, CausalChain, CausalDirection, CausalLink, CausalRelation, CausalSaliency, CausalTrajectory, DominantPlane, NarsCausalStatement, NarsTruth, ResonatorSnapshot, SigmaEdge, }; -use rustynum_bnn::{GrowthPath, InferenceMode, MutationOp}; -use rustynum_core::{CollapseGate, SigmaGate, SignificanceLevel}; +use ndarray::hpc::bnn_cross_plane::{CollapseGate, GrowthPath, InferenceMode, MutationOp}; +use ndarray::hpc::kernels::{SigmaGate, SignificanceLevel}; use crate::nars::TruthValue; use super::gestalt::GestaltState; diff --git a/src/spo/gestalt.rs b/src/spo/gestalt.rs index 7bce2ab..ef396bb 100644 --- a/src/spo/gestalt.rs +++ b/src/spo/gestalt.rs @@ -169,13 +169,13 @@ pub struct BundlingProposal { pub nars_confidence: f32, /// σ-significance level of the cross-plane evidence. - pub significance: rustynum_core::SignificanceLevel, + pub significance: ndarray::hpc::kernels::SignificanceLevel, /// Number of cross-matches supporting the bundling. pub evidence_count: u32, /// Current collapse gate state (tentative lifecycle). - pub gate: rustynum_core::CollapseGate, + pub gate: ndarray::hpc::bnn_cross_plane::CollapseGate, /// Timestamp of proposal creation (Unix millis). pub proposed_at_ms: u64, @@ -192,7 +192,7 @@ pub struct BundlingReview { /// When the decision was made (Unix millis). pub reviewed_at_ms: u64, /// The decision: Flow (approve), Block (reject). - pub decision: rustynum_core::CollapseGate, + pub decision: ndarray::hpc::bnn_cross_plane::CollapseGate, /// Reason text from the reviewer. pub reason: String, /// Machine confidence at time of review (may have changed since proposal). @@ -210,7 +210,7 @@ impl BundlingProposal { o_distance: u32, nars_frequency: f32, nars_confidence: f32, - significance: rustynum_core::SignificanceLevel, + significance: ndarray::hpc::kernels::SignificanceLevel, evidence_count: u32, ) -> Self { let now = std::time::SystemTime::now() @@ -229,7 +229,7 @@ impl BundlingProposal { nars_confidence, significance, evidence_count, - gate: rustynum_core::CollapseGate::Hold, + gate: ndarray::hpc::bnn_cross_plane::CollapseGate::Hold, proposed_at_ms: now, review: None, } @@ -237,17 +237,17 @@ impl BundlingProposal { /// Whether this proposal is still tentative (pending review). pub fn is_tentative(&self) -> bool { - matches!(self.gate, rustynum_core::CollapseGate::Hold) + matches!(self.gate, ndarray::hpc::bnn_cross_plane::CollapseGate::Hold) } /// Whether this proposal was committed (approved). pub fn is_committed(&self) -> bool { - matches!(self.gate, rustynum_core::CollapseGate::Flow) + matches!(self.gate, ndarray::hpc::bnn_cross_plane::CollapseGate::Flow) } /// Whether this proposal was rejected. pub fn is_rejected(&self) -> bool { - matches!(self.gate, rustynum_core::CollapseGate::Block) + matches!(self.gate, ndarray::hpc::bnn_cross_plane::CollapseGate::Block) } /// Approve the bundling proposal (Flow). @@ -257,11 +257,11 @@ impl BundlingProposal { .unwrap_or_default() .as_millis() as u64; - self.gate = rustynum_core::CollapseGate::Flow; + self.gate = ndarray::hpc::bnn_cross_plane::CollapseGate::Flow; self.review = Some(BundlingReview { reviewer, reviewed_at_ms: now, - decision: rustynum_core::CollapseGate::Flow, + decision: ndarray::hpc::bnn_cross_plane::CollapseGate::Flow, reason, auto_confidence_at_review: self.nars_confidence, }); @@ -274,11 +274,11 @@ impl BundlingProposal { .unwrap_or_default() .as_millis() as u64; - self.gate = rustynum_core::CollapseGate::Block; + self.gate = ndarray::hpc::bnn_cross_plane::CollapseGate::Block; self.review = Some(BundlingReview { reviewer, reviewed_at_ms: now, - decision: rustynum_core::CollapseGate::Block, + decision: ndarray::hpc::bnn_cross_plane::CollapseGate::Block, reason, auto_confidence_at_review: self.nars_confidence, }); @@ -316,7 +316,7 @@ pub fn detect_bundling( center_b_s: &[u64], center_b_p: &[u64], center_b_o: &[u64], - gate: &rustynum_core::SigmaGate, + gate: &ndarray::hpc::kernels::SigmaGate, ) -> Option<(BundlingType, u32, u32, u32)> { // Per-plane Hamming distance let s_dist = crate::core::rustynum_accel::slice_hamming(center_a_s, center_b_s) as u32; @@ -419,16 +419,16 @@ impl TiltReport { #[derive(Debug, Clone)] pub struct PlaneCalibration { /// S-plane σ thresholds (calibrated to S⊕P distribution). - pub s_gate: rustynum_core::SigmaGate, + pub s_gate: ndarray::hpc::kernels::SigmaGate, /// P-plane σ thresholds (calibrated to P⊕O distribution). - pub p_gate: rustynum_core::SigmaGate, + pub p_gate: ndarray::hpc::kernels::SigmaGate, /// O-plane σ thresholds (calibrated to S⊕O distribution). - pub o_gate: rustynum_core::SigmaGate, + pub o_gate: ndarray::hpc::kernels::SigmaGate, } impl PlaneCalibration { /// Create from a single shared gate (no tilt correction). - pub fn uniform(gate: rustynum_core::SigmaGate) -> Self { + pub fn uniform(gate: ndarray::hpc::kernels::SigmaGate) -> Self { Self { s_gate: gate, p_gate: gate, @@ -442,9 +442,9 @@ impl PlaneCalibration { /// standard deviation (σ) rather than the global 16K-bit assumption. pub fn from_plane_stats(s_mu: u32, s_sigma: u32, p_mu: u32, p_sigma: u32, o_mu: u32, o_sigma: u32) -> Self { Self { - s_gate: rustynum_core::SigmaGate::custom(s_mu, s_sigma), - p_gate: rustynum_core::SigmaGate::custom(p_mu, p_sigma), - o_gate: rustynum_core::SigmaGate::custom(o_mu, o_sigma), + s_gate: ndarray::hpc::kernels::SigmaGate::custom(s_mu, s_sigma), + p_gate: ndarray::hpc::kernels::SigmaGate::custom(p_mu, p_sigma), + o_gate: ndarray::hpc::kernels::SigmaGate::custom(o_mu, o_sigma), } } @@ -462,7 +462,7 @@ impl PlaneCalibration { &self, plane: ContestedPlane, distance: u32, - ) -> rustynum_core::SignificanceLevel { + ) -> ndarray::hpc::kernels::SignificanceLevel { let gate = match plane { ContestedPlane::Subject => &self.s_gate, ContestedPlane::Predicate => &self.p_gate, @@ -487,7 +487,7 @@ pub struct EvidenceEvent { pub nars_frequency: f32, pub nars_confidence: f32, /// σ-significance at this moment. - pub significance: rustynum_core::SignificanceLevel, + pub significance: ndarray::hpc::kernels::SignificanceLevel, /// Evidence count at this moment. pub evidence_count: u32, /// Per-plane gestalt state at this moment. @@ -637,15 +637,15 @@ impl CollapseMode { } /// Decide the CollapseGate for a given confidence level. - pub fn decide(&self, confidence: f32) -> rustynum_core::CollapseGate { + pub fn decide(&self, confidence: f32) -> ndarray::hpc::bnn_cross_plane::CollapseGate { if confidence >= self.auto_threshold() { - rustynum_core::CollapseGate::Flow // auto-approve + ndarray::hpc::bnn_cross_plane::CollapseGate::Flow // auto-approve } else if confidence >= self.proposal_threshold() { - rustynum_core::CollapseGate::Hold // tentative, awaiting review + ndarray::hpc::bnn_cross_plane::CollapseGate::Hold // tentative, awaiting review } else { match self { - CollapseMode::Regulated => rustynum_core::CollapseGate::Hold, - _ => rustynum_core::CollapseGate::Block, // below proposal threshold + CollapseMode::Regulated => ndarray::hpc::bnn_cross_plane::CollapseGate::Hold, + _ => ndarray::hpc::bnn_cross_plane::CollapseGate::Block, // below proposal threshold } } } @@ -663,9 +663,9 @@ impl CollapseMode { #[derive(Debug, Clone, Copy)] pub struct AntialiasedSigma { /// Primary significance band. - pub primary: rustynum_core::SignificanceLevel, + pub primary: ndarray::hpc::kernels::SignificanceLevel, /// Adjacent significance band (for boundary items). - pub secondary: rustynum_core::SignificanceLevel, + pub secondary: ndarray::hpc::kernels::SignificanceLevel, /// Weight of primary band (0.0..1.0). pub primary_weight: f32, /// Weight of secondary band (0.0..1.0, = 1 - primary_weight). @@ -679,7 +679,7 @@ impl AntialiasedSigma { /// /// The continuous sigma position is interpolated between band boundaries, /// and weights reflect how close the distance is to each boundary. - pub fn from_distance(distance: u32, gate: &rustynum_core::SigmaGate) -> Self { + pub fn from_distance(distance: u32, gate: &ndarray::hpc::kernels::SigmaGate) -> Self { // Continuous sigma: how many σ below the noise floor let dist_f = distance as f32; let mu_f = gate.mu as f32; @@ -695,8 +695,8 @@ impl AntialiasedSigma { let (primary, secondary, primary_weight) = if distance < gate.discovery { // Deep in Discovery zone ( - rustynum_core::SignificanceLevel::Discovery, - rustynum_core::SignificanceLevel::Strong, + ndarray::hpc::kernels::SignificanceLevel::Discovery, + ndarray::hpc::kernels::SignificanceLevel::Strong, 1.0_f32, ) } else if distance < gate.strong { @@ -705,8 +705,8 @@ impl AntialiasedSigma { let pos = (distance - gate.discovery) as f32; let w = 1.0 - (pos / range); ( - rustynum_core::SignificanceLevel::Discovery, - rustynum_core::SignificanceLevel::Strong, + ndarray::hpc::kernels::SignificanceLevel::Discovery, + ndarray::hpc::kernels::SignificanceLevel::Strong, w, ) } else if distance < gate.evidence { @@ -714,8 +714,8 @@ impl AntialiasedSigma { let pos = (distance - gate.strong) as f32; let w = 1.0 - (pos / range); ( - rustynum_core::SignificanceLevel::Strong, - rustynum_core::SignificanceLevel::Evidence, + ndarray::hpc::kernels::SignificanceLevel::Strong, + ndarray::hpc::kernels::SignificanceLevel::Evidence, w, ) } else if distance < gate.hint { @@ -723,14 +723,14 @@ impl AntialiasedSigma { let pos = (distance - gate.evidence) as f32; let w = 1.0 - (pos / range); ( - rustynum_core::SignificanceLevel::Evidence, - rustynum_core::SignificanceLevel::Hint, + ndarray::hpc::kernels::SignificanceLevel::Evidence, + ndarray::hpc::kernels::SignificanceLevel::Hint, w, ) } else { ( - rustynum_core::SignificanceLevel::Noise, - rustynum_core::SignificanceLevel::Noise, + ndarray::hpc::kernels::SignificanceLevel::Noise, + ndarray::hpc::kernels::SignificanceLevel::Noise, 1.0, ) }; @@ -1033,21 +1033,21 @@ impl GestaltEngine { // Determine bundling type from dominant halo let bundling_type = match harvest.dominant_inference() { - rustynum_bnn::HaloType::SO => BundlingType::PredicateInversion, - rustynum_bnn::HaloType::PO => BundlingType::AgentConvergence, - rustynum_bnn::HaloType::SP => BundlingType::TargetDivergence, + ndarray::hpc::bnn_cross_plane::HaloType::SO => BundlingType::PredicateInversion, + ndarray::hpc::bnn_cross_plane::HaloType::PO => BundlingType::AgentConvergence, + ndarray::hpc::bnn_cross_plane::HaloType::SP => BundlingType::TargetDivergence, _ => return None, // Core/S/P/O/Noise don't trigger bundling }; // Derive σ-significance from accumulated confidence let significance = if confidence > 0.95 { - rustynum_core::SignificanceLevel::Discovery + ndarray::hpc::kernels::SignificanceLevel::Discovery } else if confidence > 0.85 { - rustynum_core::SignificanceLevel::Strong + ndarray::hpc::kernels::SignificanceLevel::Strong } else if confidence > 0.70 { - rustynum_core::SignificanceLevel::Evidence + ndarray::hpc::kernels::SignificanceLevel::Evidence } else { - rustynum_core::SignificanceLevel::Hint + ndarray::hpc::kernels::SignificanceLevel::Hint }; // CollapseGate decision from mode @@ -1065,7 +1065,7 @@ impl GestaltEngine { ); // If Research mode auto-approved, mark it - if matches!(gate, rustynum_core::CollapseGate::Flow) { + if matches!(gate, ndarray::hpc::bnn_cross_plane::CollapseGate::Flow) { proposal.approve("auto".to_string(), "Research mode auto-approval".to_string()); } @@ -1090,13 +1090,13 @@ impl GestaltEngine { let confidence = harvest.accumulated_truth.confidence; let significance = if confidence > 0.95 { - rustynum_core::SignificanceLevel::Discovery + ndarray::hpc::kernels::SignificanceLevel::Discovery } else if confidence > 0.85 { - rustynum_core::SignificanceLevel::Strong + ndarray::hpc::kernels::SignificanceLevel::Strong } else if confidence > 0.70 { - rustynum_core::SignificanceLevel::Evidence + ndarray::hpc::kernels::SignificanceLevel::Evidence } else { - rustynum_core::SignificanceLevel::Hint + ndarray::hpc::kernels::SignificanceLevel::Hint }; trajectory.record_event(EvidenceEvent { @@ -1222,7 +1222,7 @@ mod tests { 300, // o_dist: close 0.78, 0.87, - rustynum_core::SignificanceLevel::Strong, + ndarray::hpc::kernels::SignificanceLevel::Strong, 500, ); @@ -1264,47 +1264,47 @@ mod tests { // Research mode: auto-approve above 0.95 assert_eq!( CollapseMode::Research.decide(0.97), - rustynum_core::CollapseGate::Flow + ndarray::hpc::bnn_cross_plane::CollapseGate::Flow ); assert_eq!( CollapseMode::Research.decide(0.85), - rustynum_core::CollapseGate::Hold + ndarray::hpc::bnn_cross_plane::CollapseGate::Hold ); assert_eq!( CollapseMode::Research.decide(0.50), - rustynum_core::CollapseGate::Block + ndarray::hpc::bnn_cross_plane::CollapseGate::Block ); // Production mode: never auto-approve, propose above 0.80 assert_eq!( CollapseMode::Production.decide(0.99), - rustynum_core::CollapseGate::Hold + ndarray::hpc::bnn_cross_plane::CollapseGate::Hold ); assert_eq!( CollapseMode::Production.decide(0.50), - rustynum_core::CollapseGate::Block + ndarray::hpc::bnn_cross_plane::CollapseGate::Block ); // Regulated mode: always Hold (propose at any confidence) assert_eq!( CollapseMode::Regulated.decide(0.10), - rustynum_core::CollapseGate::Hold + ndarray::hpc::bnn_cross_plane::CollapseGate::Hold ); } #[test] fn test_antialiased_sigma() { - let gate = rustynum_core::SigmaGate::sku_16k(); + let gate = ndarray::hpc::kernels::SigmaGate::sku_16k(); // Deep discovery: should be firmly in Discovery band let aa = AntialiasedSigma::from_distance(100, &gate); - assert_eq!(aa.primary, rustynum_core::SignificanceLevel::Discovery); + assert_eq!(aa.primary, ndarray::hpc::kernels::SignificanceLevel::Discovery); assert!(aa.primary_weight > 0.9); assert!(aa.continuous_sigma > 3.0); // Deep noise: should be firmly Noise let aa = AntialiasedSigma::from_distance(gate.mu + 100, &gate); - assert_eq!(aa.primary, rustynum_core::SignificanceLevel::Noise); + assert_eq!(aa.primary, ndarray::hpc::kernels::SignificanceLevel::Noise); // NARS confidence from sigma let high_sigma = AntialiasedSigma::from_distance(100, &gate); @@ -1323,7 +1323,7 @@ mod tests { 300, 0.78, 0.87, - rustynum_core::SignificanceLevel::Strong, + ndarray::hpc::kernels::SignificanceLevel::Strong, 500, ); @@ -1337,7 +1337,7 @@ mod tests { event_type: EvidenceEventType::MatchesAdded(112), nars_frequency: 0.83, nars_confidence: 0.91, - significance: rustynum_core::SignificanceLevel::Strong, + significance: ndarray::hpc::kernels::SignificanceLevel::Strong, evidence_count: 612, gestalt: GestaltState::Crystallizing, }); @@ -1355,7 +1355,7 @@ mod tests { event_type: EvidenceEventType::CounterEvidence(3), nars_frequency: 0.79, nars_confidence: 0.84, - significance: rustynum_core::SignificanceLevel::Evidence, + significance: ndarray::hpc::kernels::SignificanceLevel::Evidence, evidence_count: 615, gestalt: GestaltState::Contested, }); @@ -1371,7 +1371,7 @@ mod tests { #[test] fn test_engine_below_threshold() { - let gate = rustynum_core::SigmaGate::sku_16k(); + let gate = ndarray::hpc::kernels::SigmaGate::sku_16k(); let calibration = PlaneCalibration::uniform(gate); let mut engine = GestaltEngine::new(CollapseMode::Production, calibration); @@ -1388,7 +1388,7 @@ mod tests { #[test] fn test_engine_creates_proposal() { - let gate = rustynum_core::SigmaGate::sku_16k(); + let gate = ndarray::hpc::kernels::SigmaGate::sku_16k(); let calibration = PlaneCalibration::uniform(gate); let mut engine = GestaltEngine::new(CollapseMode::Production, calibration); @@ -1410,7 +1410,7 @@ mod tests { #[test] fn test_engine_research_auto_approves() { - let gate = rustynum_core::SigmaGate::sku_16k(); + let gate = ndarray::hpc::kernels::SigmaGate::sku_16k(); let calibration = PlaneCalibration::uniform(gate); let mut engine = GestaltEngine::new(CollapseMode::Research, calibration); @@ -1428,7 +1428,7 @@ mod tests { #[test] fn test_engine_feed_evidence_and_auto_approve() { - let gate = rustynum_core::SigmaGate::sku_16k(); + let gate = ndarray::hpc::kernels::SigmaGate::sku_16k(); let calibration = PlaneCalibration::uniform(gate); let mut engine = GestaltEngine::new(CollapseMode::Research, calibration); engine.bundling_evidence_threshold = 5; @@ -1492,7 +1492,7 @@ mod tests { "a".to_string(), "b".to_string(), BundlingType::PredicateInversion, 200, 7500, 300, 0.5, 0.5, - rustynum_core::SignificanceLevel::Evidence, 10, + ndarray::hpc::kernels::SignificanceLevel::Evidence, 10, ); let mut trajectory = TruthTrajectory::new(proposal); @@ -1503,7 +1503,7 @@ mod tests { event_type: EvidenceEventType::MatchesAdded(10), nars_frequency: 0.5 + i as f32 * 0.08, nars_confidence: 0.5 + i as f32 * 0.08, - significance: rustynum_core::SignificanceLevel::Evidence, + significance: ndarray::hpc::kernels::SignificanceLevel::Evidence, evidence_count: i as u32 * 10, gestalt: GestaltState::Crystallizing, }); @@ -1525,7 +1525,7 @@ mod tests { "a".to_string(), "b".to_string(), BundlingType::PredicateInversion, 200, 7500, 300, 0.95, 0.95, - rustynum_core::SignificanceLevel::Discovery, 3, + ndarray::hpc::kernels::SignificanceLevel::Discovery, 3, ); let mut trajectory = TruthTrajectory::new(proposal); @@ -1535,7 +1535,7 @@ mod tests { event_type: EvidenceEventType::MatchesAdded(10), nars_frequency: 0.96, nars_confidence: 0.96, - significance: rustynum_core::SignificanceLevel::Discovery, + significance: ndarray::hpc::kernels::SignificanceLevel::Discovery, evidence_count: 13, gestalt: GestaltState::Crystallizing, }); @@ -1551,7 +1551,7 @@ mod tests { "a".to_string(), "b".to_string(), BundlingType::PredicateInversion, 200, 7500, 300, 0.4, 0.4, - rustynum_core::SignificanceLevel::Hint, 5, + ndarray::hpc::kernels::SignificanceLevel::Hint, 5, ); let mut trajectory = TruthTrajectory::new(proposal); @@ -1562,7 +1562,7 @@ mod tests { event_type: EvidenceEventType::MatchesAdded(10), nars_frequency: 0.4 + i as f32 * 0.06, nars_confidence: 0.4 + i as f32 * 0.06, - significance: rustynum_core::SignificanceLevel::Evidence, + significance: ndarray::hpc::kernels::SignificanceLevel::Evidence, evidence_count: (5 + i * 10) as u32, gestalt: GestaltState::Crystallizing, }); @@ -1579,7 +1579,7 @@ mod tests { #[test] fn test_engine_gestalt_summary() { - let gate = rustynum_core::SigmaGate::sku_16k(); + let gate = ndarray::hpc::kernels::SigmaGate::sku_16k(); let calibration = PlaneCalibration::uniform(gate); let mut engine = GestaltEngine::new(CollapseMode::Research, calibration); engine.bundling_evidence_threshold = 5; diff --git a/src/spo/shift_detector.rs b/src/spo/shift_detector.rs index 3d80cd7..5e34977 100644 --- a/src/spo/shift_detector.rs +++ b/src/spo/shift_detector.rs @@ -19,10 +19,11 @@ //! Stable → no bias (use existing gate logic) //! ``` -use rustynum_bnn::causal_trajectory::{ +use ndarray::hpc::bnn_causal_trajectory::{ ShiftDetector as BnnShiftDetector, ShiftDirection, ShiftSignal, StripeHistogram, }; -use rustynum_core::{CollapseGate, SigmaGate}; +use ndarray::hpc::bnn_cross_plane::CollapseGate; +use ndarray::hpc::kernels::SigmaGate; use super::spo_harvest::SpoDistanceResult; diff --git a/src/spo/spo_harvest.rs b/src/spo/spo_harvest.rs index 4bec259..1742d38 100644 --- a/src/spo/spo_harvest.rs +++ b/src/spo/spo_harvest.rs @@ -24,13 +24,13 @@ //! | Bits of information | ~23 | ~169 | //! | Information per cycle | 0.0074 bits/cycle | 13.0 bits/cycle | -use rustynum_bnn::{ - CrossPlaneVote, HaloDistribution, HaloType, InferenceMode, NarsTruth, +use ndarray::hpc::bnn_cross_plane::{ + CrossPlaneVote, HaloDistribution, HaloType, InferenceMode, }; -use rustynum_bnn::causal_trajectory::{ - CausalRelation, SigmaEdge, SigmaNode, +use ndarray::hpc::bnn_causal_trajectory::{ + CausalRelation, NarsTruth, SigmaEdge, SigmaNode, }; -use rustynum_core::{SigmaGate, SignificanceLevel}; +use ndarray::hpc::kernels::{SigmaGate, SignificanceLevel}; use crate::nars::TruthValue; @@ -107,14 +107,14 @@ impl SpoDistanceResult { } /// Suggested mutation operator based on weakest plane. - pub fn suggested_mutation(&self) -> rustynum_bnn::MutationOp { + pub fn suggested_mutation(&self) -> ndarray::hpc::bnn_cross_plane::MutationOp { match self.weakest_plane() { // S⊕P weakest → S or P needs revision. Conservative: mutate S. - Plane::X => rustynum_bnn::MutationOp::MutateS, + Plane::X => ndarray::hpc::bnn_cross_plane::MutationOp::MutateS, // P⊕O weakest → P or O needs revision. Conservative: mutate P. - Plane::Y => rustynum_bnn::MutationOp::MutateP, + Plane::Y => ndarray::hpc::bnn_cross_plane::MutationOp::MutateP, // S⊕O weakest → S or O needs revision. Conservative: mutate O. - Plane::Z => rustynum_bnn::MutationOp::MutateO, + Plane::Z => ndarray::hpc::bnn_cross_plane::MutationOp::MutateO, } } } @@ -623,14 +623,14 @@ impl AccumulatedHarvest { } /// Suggested growth path based on accumulated weakest plane. - pub fn suggested_growth_path(&self) -> Option { + pub fn suggested_growth_path(&self) -> Option { match self.weakest_plane? { // S⊕P weakest → approach from the other two (S+O → SO → SPO) - Plane::X => Some(rustynum_bnn::GrowthPath::SubjectObject), + Plane::X => Some(ndarray::hpc::bnn_cross_plane::GrowthPath::SubjectObject), // P⊕O weakest → approach via S first (S → SP → SPO) - Plane::Y => Some(rustynum_bnn::GrowthPath::SubjectFirst), + Plane::Y => Some(ndarray::hpc::bnn_cross_plane::GrowthPath::SubjectFirst), // S⊕O weakest → approach via action (P → PO → SPO) - Plane::Z => Some(rustynum_bnn::GrowthPath::ActionObject), + Plane::Z => Some(ndarray::hpc::bnn_cross_plane::GrowthPath::ActionObject), } } } @@ -968,6 +968,6 @@ mod tests { ); assert_eq!(result.weakest_plane(), Plane::X); - assert_eq!(result.suggested_mutation(), rustynum_bnn::MutationOp::MutateS); + assert_eq!(result.suggested_mutation(), ndarray::hpc::bnn_cross_plane::MutationOp::MutateS); } } diff --git a/src/storage/bind_space.rs b/src/storage/bind_space.rs index 10ce840..d3fa7a8 100644 --- a/src/storage/bind_space.rs +++ b/src/storage/bind_space.rs @@ -48,6 +48,7 @@ use std::collections::HashMap; use crate::container::adjacency::PackedDn; use crate::container::{CONTAINER_WORDS, Container, MetaView, MetaViewMut}; use crate::spo::clam_path::{ClamPath, MerkleRoot}; +use ndarray::hpc::hdc::HdcOps; // ============================================================================= // ADDRESS CONSTANTS (8-bit prefix : 8-bit slot) @@ -1777,8 +1778,7 @@ impl BindSpace { let slices: Vec<&[u8]> = nodes.iter() .map(|n| crate::core::rustynum_accel::view_u64_as_bytes(&n.fingerprint)) .collect(); - let result_bytes = rustynum_rs::NumArrayU8::try_bundle_byte_slices(&slices) - .expect("bundle_byte_slices: all slices same length"); + let result_bytes = ndarray::Array::::hdc_bundle_byte_slices(&slices); let mut fp = [0u64; FINGERPRINT_WORDS]; for (i, chunk) in result_bytes.chunks_exact(8).enumerate() { fp[i] = u64::from_ne_bytes(chunk.try_into().unwrap()); @@ -1856,13 +1856,13 @@ impl BindSpace { let node_bytes = crate::core::rustynum_accel::view_u64_as_bytes(&node.fingerprint); // Stage 1: quick reject on 1/16 sample - let est_16 = rustynum_core::simd::hamming_distance(sample_16, &node_bytes[..128]) as u32 * scale_16; + let est_16 = ndarray::hpc::bitwise::hamming_distance_raw(sample_16, &node_bytes[..128]) as u32 * scale_16; if est_16 > threshold + margin_16 { continue; } // Stage 2: refine on 1/4 sample - let est_4 = rustynum_core::simd::hamming_distance(sample_4, &node_bytes[..512]) as u32 * scale_4; + let est_4 = ndarray::hpc::bitwise::hamming_distance_raw(sample_4, &node_bytes[..512]) as u32 * scale_4; if est_4 > threshold + margin_4 { continue; } @@ -2236,14 +2236,14 @@ impl BindSpace { pub fn phase_bind(&self, a: Addr, b: Addr) -> Option> { let ab = self.fp_bytes(a)?; let bb = self.fp_bytes(b)?; - Some(rustynum_holo::phase_bind_i8(ab, bb)) + Some(ndarray::hpc::holo::phase_bind_i8(ab, bb)) } /// Phase unbind (SUB mod 256): recover `a` from `bound` and `key`. pub fn phase_unbind(&self, bound: Addr, key: Addr) -> Option> { let bb = self.fp_bytes(bound)?; let kb = self.fp_bytes(key)?; - Some(rustynum_holo::phase_unbind_i8(bb, kb)) + Some(ndarray::hpc::holo::phase_unbind_i8(bb, kb)) } /// Wasserstein (Earth Mover's) distance on sorted phase vectors. @@ -2251,20 +2251,20 @@ impl BindSpace { pub fn wasserstein(&self, a: Addr, b: Addr) -> Option { let ab = self.fp_bytes(a)?; let bb = self.fp_bytes(b)?; - Some(rustynum_holo::wasserstein_sorted_i8(ab, bb)) + Some(ndarray::hpc::holo::wasserstein_sorted_i8(ab, bb)) } /// Circular distance for unsorted phase vectors (EMBED channel). pub fn circular_distance(&self, a: Addr, b: Addr) -> Option { let ab = self.fp_bytes(a)?; let bb = self.fp_bytes(b)?; - Some(rustynum_holo::circular_distance_i8(ab, bb)) + Some(ndarray::hpc::holo::circular_distance_i8(ab, bb)) } /// 16-bin spatial histogram of a node's phase vector. pub fn phase_histogram(&self, addr: Addr) -> Option<[u16; 16]> { let b = self.fp_bytes(addr)?; - Some(rustynum_holo::phase_histogram_16(b)) + Some(ndarray::hpc::holo::phase_histogram_16(b)) } /// Circular-mean bundle of multiple nodes' phase vectors into output buffer. @@ -2274,21 +2274,21 @@ impl BindSpace { .collect(); if vecs.is_empty() { return; } let refs: Vec<&[u8]> = vecs.iter().map(|v| v.as_slice()).collect(); - rustynum_holo::phase_bundle_circular(&refs, out); + ndarray::hpc::holo::phase_bundle_circular(&refs, out); } /// Sort a node's phase vector (write-time preparation for Wasserstein). /// Returns (sorted_bytes, permutation). pub fn sort_phase(&self, addr: Addr) -> Option<(Vec, Vec)> { let b = self.fp_bytes(addr)?; - Some(rustynum_holo::sort_phase_vector(b)) + Some(ndarray::hpc::holo::sort_phase_vector(b)) } /// L1 distance between two phase histograms (for coarse filtering). pub fn histogram_distance(&self, a: Addr, b: Addr) -> Option { let ha = self.phase_histogram(a)?; let hb = self.phase_histogram(b)?; - Some(rustynum_holo::histogram_l1_distance(&ha, &hb)) + Some(ndarray::hpc::holo::histogram_l1_distance(&ha, &hb)) } // ========================================================================= @@ -2307,27 +2307,27 @@ impl BindSpace { pub fn carrier_distance(&self, a: Addr, b: Addr) -> Option { let ab = self.fp_bytes(a)?; let bb = self.fp_bytes(b)?; - Some(rustynum_holo::carrier_distance_l1(Self::as_i8(ab), Self::as_i8(bb))) + Some(ndarray::hpc::holo::carrier_distance_l1(Self::as_i8(ab), Self::as_i8(bb))) } /// Carrier cosine correlation between two nodes (i8 domain). pub fn carrier_correlation(&self, a: Addr, b: Addr) -> Option { let ab = self.fp_bytes(a)?; let bb = self.fp_bytes(b)?; - Some(rustynum_holo::carrier_correlation(Self::as_i8(ab), Self::as_i8(bb))) + Some(ndarray::hpc::holo::carrier_correlation(Self::as_i8(ab), Self::as_i8(bb))) } /// Frequency spectrum of a node's fingerprint (16 frequency bins). - pub fn carrier_spectrum(&self, addr: Addr, basis: &rustynum_holo::CarrierBasis) -> Option<[f32; 16]> { + pub fn carrier_spectrum(&self, addr: Addr, basis: &ndarray::hpc::holo::CarrierBasis) -> Option<[f32; 16]> { let b = self.fp_bytes(addr)?; - Some(rustynum_holo::carrier_spectrum(Self::as_i8(b), basis)) + Some(ndarray::hpc::holo::carrier_spectrum(Self::as_i8(b), basis)) } /// Spectral distance (L2) between two nodes' frequency spectra. - pub fn spectral_distance(&self, a: Addr, b: Addr, basis: &rustynum_holo::CarrierBasis) -> Option { + pub fn spectral_distance(&self, a: Addr, b: Addr, basis: &ndarray::hpc::holo::CarrierBasis) -> Option { let sa = self.carrier_spectrum(a, basis)?; let sb = self.carrier_spectrum(b, basis)?; - Some(rustynum_holo::spectral_distance(&sa, &sb)) + Some(ndarray::hpc::holo::spectral_distance(&sa, &sb)) } // ========================================================================= @@ -2338,7 +2338,7 @@ impl BindSpace { pub fn focus_xor(&mut self, addr: Addr, mask_x: u8, mask_y: u8, mask_z: u32, value: &[u8]) { if let Some(node) = self.read_mut(addr) { let mut buf = crate::core::rustynum_accel::view_u64_as_bytes(&node.fingerprint).to_vec(); - rustynum_holo::focus_xor(&mut buf, mask_x, mask_y, mask_z, value); + ndarray::hpc::holo::focus_xor(&mut buf, mask_x, mask_y, mask_z, value); for (i, chunk) in buf.chunks_exact(8).enumerate() { node.fingerprint[i] = u64::from_ne_bytes(chunk.try_into().unwrap()); } @@ -2349,7 +2349,7 @@ impl BindSpace { /// Read bytes from focused region of a node's fingerprint. pub fn focus_read(&self, addr: Addr, mask_x: u8, mask_y: u8, mask_z: u32) -> Option> { let b = self.fp_bytes(addr)?; - Some(rustynum_holo::focus_read(b, mask_x, mask_y, mask_z)) + Some(ndarray::hpc::holo::focus_read(b, mask_x, mask_y, mask_z)) } /// Hamming distance within focused region of two nodes. @@ -2357,7 +2357,7 @@ impl BindSpace { pub fn focus_hamming(&self, a: Addr, b: Addr, mask_x: u8, mask_y: u8, mask_z: u32) -> Option<(u64, u32)> { let ab = self.fp_bytes(a)?; let bb = self.fp_bytes(b)?; - Some(rustynum_holo::focus_hamming(ab, bb, mask_x, mask_y, mask_z)) + Some(ndarray::hpc::holo::focus_hamming(ab, bb, mask_x, mask_y, mask_z)) } /// L1 distance within focused region of two nodes. @@ -2365,14 +2365,14 @@ impl BindSpace { pub fn focus_l1(&self, a: Addr, b: Addr, mask_x: u8, mask_y: u8, mask_z: u32) -> Option<(u64, u32)> { let ab = self.fp_bytes(a)?; let bb = self.fp_bytes(b)?; - Some(rustynum_holo::focus_l1(ab, bb, mask_x, mask_y, mask_z)) + Some(ndarray::hpc::holo::focus_l1(ab, bb, mask_x, mask_y, mask_z)) } /// Phase bind (ADD) concept_vec into focused region of a node's fingerprint. pub fn focus_bind_phase(&mut self, addr: Addr, mask_x: u8, mask_y: u8, mask_z: u32, concept_vec: &[u8]) { if let Some(node) = self.read_mut(addr) { let mut buf = crate::core::rustynum_accel::view_u64_as_bytes(&node.fingerprint).to_vec(); - rustynum_holo::focus_bind_phase(&mut buf, mask_x, mask_y, mask_z, concept_vec); + ndarray::hpc::holo::focus_bind_phase(&mut buf, mask_x, mask_y, mask_z, concept_vec); for (i, chunk) in buf.chunks_exact(8).enumerate() { node.fingerprint[i] = u64::from_ne_bytes(chunk.try_into().unwrap()); } @@ -2384,7 +2384,7 @@ impl BindSpace { pub fn focus_unbind_phase(&mut self, addr: Addr, mask_x: u8, mask_y: u8, mask_z: u32, concept_vec: &[u8]) { if let Some(node) = self.read_mut(addr) { let mut buf = crate::core::rustynum_accel::view_u64_as_bytes(&node.fingerprint).to_vec(); - rustynum_holo::focus_unbind_phase(&mut buf, mask_x, mask_y, mask_z, concept_vec); + ndarray::hpc::holo::focus_unbind_phase(&mut buf, mask_x, mask_y, mask_z, concept_vec); for (i, chunk) in buf.chunks_exact(8).enumerate() { node.fingerprint[i] = u64::from_ne_bytes(chunk.try_into().unwrap()); } @@ -2396,7 +2396,7 @@ impl BindSpace { pub fn focus_xor_auto(&mut self, addr: Addr, mask_x: u8, mask_y: u8, mask_z: u32, value: &[u8]) { if let Some(node) = self.read_mut(addr) { let mut buf = crate::core::rustynum_accel::view_u64_as_bytes(&node.fingerprint).to_vec(); - rustynum_holo::focus_xor_auto(&mut buf, mask_x, mask_y, mask_z, value); + ndarray::hpc::holo::focus_xor_auto(&mut buf, mask_x, mask_y, mask_z, value); for (i, chunk) in buf.chunks_exact(8).enumerate() { node.fingerprint[i] = u64::from_ne_bytes(chunk.try_into().unwrap()); } @@ -2423,7 +2423,7 @@ impl BindSpace { let addr = Addr::new(prefix, slot); if let Some(node) = self.read(addr) { let node_bytes = crate::core::rustynum_accel::view_u64_as_bytes(&node.fingerprint); - let dist = rustynum_core::simd::hamming_distance(query_bytes, node_bytes); + let dist = ndarray::hpc::bitwise::hamming_distance_raw(query_bytes, node_bytes); results.push((addr, dist)); } }