Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .claude/board/LATEST_STATE.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
## 2026-09-05 — PR #1181 MERGED (`80dbcc35`) + jc clippy sweep — INVENTORY DELTA

- **Merged:** #1181 — `contract::shape_rank` (`ShapeRankPayload`, `RemeasureKey`, `RemeasureLedger`, `RemeasureError::{AlreadySealed, VersionMismatch}`) and `planner::nested_bands` are on `main`. Consumers today: none outside the two crates' own tests — the D-BLW-5 loop that would inject the payload is PAUSED. See `PR_ARC_INVENTORY.md` 2026-09-05 #1181 entry.
- **jc:** `cargo clippy --manifest-path crates/jc/Cargo.toml --all-targets -- -D warnings` is green on `main` for the first time (TD-JC-CLIPPY-RED-ON-BASE-1 RESOLVED); `jc-proof.yml` now runs that command, same arming as sigker.

## 2026-09-05 — branch (D-NXG-4 → D-BLW-5, producer half): the payload has a producer and a transform — INVENTORY DELTA

- ADDED `lance_graph_planner::nested_bands::{Z2_SCALE, quantize_2z}`, `NestedBandsBuilder::calibrate_equal_width` (the D-BLW-5 design's equal-width-in-2z ladder, beside the equal-mass `calibrate`), `NestedBands::shape_rank(observed, V₀) -> ShapeRankPayload` (asserts 16 bands). Five tests, one on a REAL pooled prior (92 speech frames' lag-1 autocorrelation).
Expand Down
8 changes: 8 additions & 0 deletions .claude/board/PR_ARC_INVENTORY.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
## 2026-09-05 — lance-graph PR #1181 (merged `80dbcc35`, branch `claude/pr-294-ragged-path-validation-170zcy`) — NestedBands sealed + the D-BLW-5 `shape × rank` payload

- **Added:** `lance_graph_planner::nested_bands` (D-NXG-1/5: `NestedBandsBuilder` quantile / equal-width / explicit ladders, `NestedBands` with `rank`, `entropy`, `budget`, `split`/`merge` returning a NEW version, `best_achievable_floor`, `moments`, `sigma_exact`, `shape_rank`); `lance_graph_contract::shape_rank` (D-NXG-4: `ShapeRankPayload{shape:[u64;16], rank:u8, version}`, `RemeasureKey`, `RemeasureLedger` with `AlreadySealed` + `VersionMismatch`); `jc::stats::{fisher_2z, fisher_2z_inv}`.
- **Locked:** the D-BLW-5 payload law in code — the DTO carries `shape₀ × rank₀`, never the raw statistic; sealed once per `(stat_id, arm, cohort, metric, dataset_version)`; a payload whose frozen version differs from the key is refused. Top band is the universe (E-NXG-18); bucket-0 split bound is the column minimum, not 0 (signed columns).
- **Review arc:** CodeRabbit round 1 — six findings, all verified real, fixed in `7d9e03a3` (version guard, negative split, three length asserts, doc/title/plan wording); the seventh (builder panics → `Result`) declined with reason and accepted by the bot. The three tests the guard broke were fixture bugs, aligned not weakened.
- **Deferred:** the D-BLW-5 LOOP (four arms, bloom criterion, supervisor test file) stays PAUSED — only the payload half was relaunched. `out_of_support` bit on the DTO (E-NXG-22) awaits operator ruling. TD-JC-CLIPPY-RED-ON-BASE-1 filed, resolved in the follow-up PR.
- **Confidence:** High on the contract semantics (tests + bot-verified); Medium on `shape_rank` being the right producer shape for the F± arms, which nothing has exercised.

## 2026-09-05 — lance-graph PR #1177 (merged `eb84b275`, branch `claude/bindspace-soa-wiring-plan-2026-09`) — the BindSpace→MailboxSoA migration, re-derived from the tree

- **Added:** `.claude/plans/bindspace-mailbox-soa-wiring-v1.md` (D-BSW-0..4) + its `STATUS_BOARD` section + an `INTEGRATION_PLANS` index entry. DOC/BOARD ONLY — no code, nothing compiled, no `cargo` at any point (V3 worker rule 7).
Expand Down
2 changes: 1 addition & 1 deletion .claude/board/TECH_DEBT.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
## TD-JC-CLIPPY-RED-ON-BASE-1 (2026-09-05) — OPEN
## TD-JC-CLIPPY-RED-ON-BASE-1 (2026-09-05) — RESOLVED 2026-09-05 (lint sweep + `jc-proof.yml` clippy step, operator-directed after #1181)

**`crates/jc` does not pass `cargo clippy --manifest-path crates/jc/Cargo.toml --all-targets -- -D warnings`, and did not before this arc.** Measured by stashing the working tree: the same `unusual_byte_groupings` errors reproduce on `origin/main` in `dueker_zoubouloglou.rs`, `ewa_sandwich.rs`, `ewa_sandwich_3d.rs`, `koestenberger.rs`, `lib.rs`, `pearl.rs`, `pflug.rs`, `probe_p1_gamma_phase.rs`, `sigma_codebook_probe.rs`, `weyl.rs` — none touched by the D-NXG-4 arc; `stats.rs` (the file this arc edits) has zero findings. CI runs tests and `fmt --check` on jc (`jc-proof.yml`, `style.yml:226`) but no clippy step, which is how it went unseen. Same shape as `TD-SIGKER-CLIPPY-RED-ON-BASE-1` (resolved 2026-09-04 by fixing + arming the lint in CI); the same two-step fix applies. Not done here: it is not this arc's code and would widen a payload PR into a lint sweep.

Expand Down
8 changes: 8 additions & 0 deletions .github/workflows/jc-proof.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,14 @@ jobs:
- name: Run JC tests (6 unit tests)
run: cargo test --manifest-path crates/jc/Cargo.toml

# jc is workspace-excluded, so the root clippy job never reaches it; it
# went red unnoticed until TD-JC-CLIPPY-RED-ON-BASE-1 (2026-09-05). Same
# arming as sigker in rust-test.yml: fix once, then gate it here.
- name: Lint JC (workspace-excluded, so root clippy never reaches it)
run: |
cargo clippy --manifest-path crates/jc/Cargo.toml \
--all-targets -- -D warnings

- name: Run prove_it (substrate proof binary)
run: |
cargo run --manifest-path crates/jc/Cargo.toml --release --example prove_it
Expand Down
6 changes: 4 additions & 2 deletions crates/jc/examples/l9_loci_real_text.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
//!
//! - `ante` — pronoun → antecedent (pronoun events only; gold-labeled)
//! - `kausal` — effect-clause event → the cause clause across a causal
//! connective (because/so; gold from the text's connectives)
//! connective (because/so; gold from the text's connectives)
//! - `noun-gnd` — nearest nominal grounding (S/O-meaning on this substrate)
//! - `verb-gnd` — nearest verbal grounding (P-meaning)
//! - `temporal` — nearest temporal marker (closed class: then/when/day/…)
Expand Down Expand Up @@ -60,6 +60,7 @@
//! 1. WELL-POSED: every jc measure returns `Some`.
//! 2. `ante` accuracy ≥ 0.60 AND ≥ the agreement-blind baseline.
//! 3. `kausal` hit rate ≥ 0.50.
//!
//! KILL: any gate fails (recorded loudly). Agreement magnitudes are not
//! gated — their direction is measured, not assumed.
//!
Expand Down Expand Up @@ -575,7 +576,8 @@ fn main() {

// ── RELIABILITY: Method A vs Method B on the always-computable loci ────
let content_idx: Vec<usize> = (0..toks.len()).filter(|&i| is_content(&toks[i])).collect();
let dims: [(&str, Box<dyn Fn(usize, bool) -> Option<i8>>); 5] = [
type LocusFn<'a> = Box<dyn Fn(usize, bool) -> Option<i8> + 'a>;
let dims: [(&str, LocusFn); 5] = [
(
"noun-gnd",
Box::new(|i, sem| {
Expand Down
1 change: 1 addition & 0 deletions crates/jc/examples/partof_isa_vs_palette256.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
//! under is_a (separation ≥ 0.20 on the [0,1] closeness scale).
//! 3. The two readings are NOT redundant: cross-reading Spearman |ρ| < 0.70
//! (if they agreed strongly, one would be redundant — they do not).
//!
//! KILL: any gate fails (recorded). Agreement magnitude is reported, its
//! direction measured not assumed.
//!
Expand Down
11 changes: 7 additions & 4 deletions crates/jc/examples/splat_jaccard_adamic_adar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,11 @@
//! ## What this probe proves
//!
//! 1. **Jaccard reduces to L2 popcount-AND / popcount-OR:**
//! J(u, v) = |N(u) ∩ N(v)| / |N(u) ∪ N(v)|
//! = popcount(plane[u] AND plane[v]) / popcount(plane[u] OR plane[v])
//! `J(u, v) = |N(u) ∩ N(v)| / |N(u) ∪ N(v)|
//! = popcount(plane[u] AND plane[v]) / popcount(plane[u] OR plane[v])`
//! 2. **Adamic-Adar reduces to L2 AND-iter + L1 popcount:**
//! AA(u, v) = Σ_{w ∈ N(u) ∩ N(v)} 1 / log(|N(w)|)
//! = sum over set bits of (plane[u] AND plane[v]) of 1/log(degree[w])
//! `AA(u, v) = Σ_{w ∈ N(u) ∩ N(v)} 1 / log(|N(w)|)
//! = sum over set bits of (plane[u] AND plane[v]) of 1/log(degree[w])`
//! 3. **Same-community pairs score measurably higher** on both metrics
//! than cross-community pairs (the "found edges" signal).
//! 4. **Mutate-back is one-pass:** for top-K most-similar pairs, deposit
Expand Down Expand Up @@ -70,6 +70,7 @@ fn or_popcount(a: &AwarenessPlane16K, b: &AwarenessPlane16K) -> u32 {
acc
}

#[allow(dead_code)] // documented L2 AND-iter shape; kept beside the popcount path it explains
fn iter_set_bits(p: &AwarenessPlane16K, mut f: impl FnMut(u32)) {
for (word_idx, &word) in p.0.iter().enumerate() {
let mut w = word;
Expand All @@ -92,7 +93,9 @@ fn splitmix64(state: &mut u64) -> u64 {
// ── planted graph (same template as LPA + Louvain probes) ──────────────────

struct PlantedGraph {
#[allow(dead_code)] // planted-graph descriptor; read by the sibling probes
n: u32,
#[allow(dead_code)]
k_communities: u32,
ground_truth: Vec<u16>,
planes: Vec<AwarenessPlane16K>,
Expand Down
1 change: 1 addition & 0 deletions crates/jc/examples/splat_louvain_modularity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ fn splitmix64(state: &mut u64) -> u64 {

struct PlantedGraph {
n: u32,
#[allow(dead_code)] // planted-graph descriptor; read by the sibling probes
k_communities: u32,
ground_truth: Vec<u16>,
planes: Vec<AwarenessPlane16K>,
Expand Down
10 changes: 6 additions & 4 deletions crates/jc/examples/splat_lpa_label_propagation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ fn splitmix64(state: &mut u64) -> u64 {

struct PlantedGraph {
n: u32,
#[allow(dead_code)] // planted-graph descriptor; read by the sibling probes
k_communities: u32,
/// `ground_truth[u]` = community id of node `u` (0..k_communities).
ground_truth: Vec<u16>,
Expand Down Expand Up @@ -152,10 +153,11 @@ fn lpa_superstep(graph: &PlantedGraph, labels: &[u16], next_labels: &mut [u16])
// Pick majority label; tie-break by sticking with `cur` if `cur` is
// among the tied set (stability heuristic — converges faster).
let max_count = tally.iter().map(|(_, c)| *c).max().unwrap_or(0);
let new_label = if max_count == 0 {
cur // isolated node — keep label
} else if tally.iter().any(|(l, c)| *l == cur && *c == max_count) {
cur // current label is among the tied max — stay
// isolated node (max_count == 0) keeps its label; so does a node whose
// current label is among the tied max — stay.
let new_label = if max_count == 0 || tally.iter().any(|(l, c)| *l == cur && *c == max_count)
{
cur
} else {
// pick lowest label id among tied for max
tally
Expand Down
9 changes: 7 additions & 2 deletions crates/jc/examples/splat_perturbationslernen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ fn sandwich(m: &Mat2, n: &Mat2) -> Mat2 {

struct PlantedGraph {
n: u32,
#[allow(dead_code)] // planted-graph descriptor; read by the sibling probes
k_communities: u32,
ground_truth: Vec<u16>,
planes: Vec<AwarenessPlane16K>,
Expand Down Expand Up @@ -347,7 +348,11 @@ fn main() {

// Print only key checkpoints + saturation event (avoids 200 lines of output).
fn should_print(i: usize, max: usize) -> bool {
i == 1 || i == max || (i <= 20 && i % 5 == 0) || (i <= 50 && i % 10 == 0) || i % 25 == 0
i == 1
|| i == max
|| (i <= 20 && i.is_multiple_of(5))
|| (i <= 50 && i.is_multiple_of(10))
|| i.is_multiple_of(25)
}

let t0 = std::time::Instant::now();
Expand All @@ -367,7 +372,7 @@ fn main() {
} else {
1.0
};
let alpha_iter = (1.0 - relative_change).max(0.0).min(1.0);
let alpha_iter = (1.0 - relative_change).clamp(0.0, 1.0);
let saturated = alpha_iter >= ALPHA_SATURATION_THRESHOLD;
if saturated {
consecutive += 1;
Expand Down
2 changes: 1 addition & 1 deletion crates/jc/src/dueker_zoubouloglou.rs
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ fn measure_trace(d: usize, n: usize, m: usize, phi: f64, seed: u64) -> (f64, f64
// ════════════════════════════════════════════════════════════════════════════

pub fn prove() -> PillarResult {
let (measured, predicted) = measure_trace(D, N, M, PHI, 0x0D_15_EA_5E_DEAD_BEEF);
let (measured, predicted) = measure_trace(D, N, M, PHI, 0x0D15_EA5E_DEAD_BEEF);

let relative_error = (measured - predicted).abs() / predicted;
let pass = relative_error < TOLERANCE;
Expand Down
13 changes: 7 additions & 6 deletions crates/jc/src/ewa_sandwich.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,11 @@
//! the σ-codebook probe — heteroscedastic SPD around I, controlled spread)
//! - Σ_0 = I (initial state); apply sandwich iteratively
//! - Measure:
//! (a) PSD-preservation rate: fraction of (path, hop) pairs where
//! resulting Σ_n is numerically SPD (det > eps, both eigenvalues > 0)
//! (b) log-norm growth: ‖log(Σ_n)‖_F vs n; rate-of-growth indicator
//! (c) variance concentration: how does sample variance of ‖log(Σ_n)‖_F²
//! across paths scale with n?
//! (a) PSD-preservation rate: fraction of (path, hop) pairs where
//! resulting Σ_n is numerically SPD (det > eps, both eigenvalues > 0)
//! (b) log-norm growth: ‖log(Σ_n)‖_F vs n; rate-of-growth indicator
//! (c) variance concentration: how does sample variance of ‖log(Σ_n)‖_F²
//! across paths scale with n?
//!
//! # PASS criteria
//!
Expand All @@ -71,7 +71,7 @@ use crate::PillarResult;

const N_PATHS: usize = 1_000;
const PATH_LENGTH: usize = 10;
const SEED: u64 = 0xEDA_5A_DC_5A_DC;
const SEED: u64 = 0xEDA_5ADC_5ADC;

// ════════════════════════════════════════════════════════════════════════════
// Deterministic RNG (consistent with other pillars)
Expand Down Expand Up @@ -237,6 +237,7 @@ fn sample_step_sigma(state: &mut u64, sigma_step: f64) -> Spd2 {

#[derive(Clone, Copy, Debug)]
struct PathResult {
#[cfg_attr(not(test), allow(dead_code))]
final_sigma: Spd2,
log_norm_sq: f64, // ‖log(Σ_n)‖_F^2
psd_hops: usize, // how many of the `length` hops kept Σ in SPD
Expand Down
5 changes: 3 additions & 2 deletions crates/jc/src/ewa_sandwich_3d.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,15 +59,15 @@
//!
//! - 1000 paths × 10 hops, σ_step = 0.2, PSD eps = 1e-12
//! - Same splitmix64/rand_uniform/rand_normal RNG declared locally
//! - SEED = 0xEDA_5A_DC_5A_DD (one byte higher than Pillar 6's 0xEDA_5A_DC_5A_DC)
//! - SEED = 0xEDA_5ADC_5ADD (one byte higher than Pillar 6's 0xEDA_5A_DC_5A_DC)
//! - Σ_0 = I; each hop: step ~ from_scale_quat(exp-normal scales, uniform quat)
//! - M = sqrt(step); Σ_{n+1} = M · Σ_n · Mᵀ

use crate::PillarResult;

const N_PATHS: usize = 1_000;
const PATH_LENGTH: usize = 10;
const SEED: u64 = 0xEDA_5A_DC_5A_DD;
const SEED: u64 = 0xEDA_5ADC_5ADD;

// ════════════════════════════════════════════════════════════════════════════
// Deterministic RNG (consistent with other pillars)
Expand Down Expand Up @@ -438,6 +438,7 @@ fn sample_step_sigma(state: &mut u64, sigma_step: f64) -> Spd3 {

#[derive(Clone, Copy, Debug)]
struct PathResult {
#[cfg_attr(not(test), allow(dead_code))]
final_sigma: Spd3,
log_norm_sq: f64,
psd_hops: usize,
Expand Down
4 changes: 2 additions & 2 deletions crates/jc/src/koestenberger.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@
//! - μ = I (identity) is both the population mean and each μ_k by construction
//! - Heteroscedastic: σ_k = 0.3 / √(k+1) — variance shrinks per sample index
//! - X_k = R(θ_k) · diag(exp(σ_k·n1), exp(σ_k·n2)) · R(θ_k)ᵀ
//! with θ_k uniform on [0,π) and n1, n2 ~ N(0,1) iid
//! with θ_k uniform on [0,π) and n1, n2 ~ N(0,1) iid
//! - Var(X_k) = E[d²(X_k, μ_k)] = 2 σ_k² (rotational symmetry argument)
//! - Σ d(μ_k, μ) = 0 (we set μ_k = μ = I, so the 6·D_n term vanishes)
//! - Predicted bound therefore reduces to (1/n²) · Σ Var(X_k) = (2/n²) · Σ σ_k²
Expand Down Expand Up @@ -256,7 +256,7 @@ pub fn prove() -> PillarResult {

// Monte Carlo estimate of E[d²(S_n, I)].
let mu = Spd2::I;
let mut state: u64 = 0xC0FFEE_BEEF_5EED;
let mut state: u64 = 0xC0_FFEE_BEEF_5EED;
let mut sum_sq_dist = 0.0f64;
let mut samples_buf = Vec::with_capacity(N_SAMPLES);

Expand Down
15 changes: 9 additions & 6 deletions crates/jc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@
//! 3. Optimal collocation without aliasing (φ-Weyl)
//! 4. Fast prolongation convergence (γ+φ preconditioner)
//! 5. Bounded noise floor under correct dependence model (Jirak 2016)
//! 5b. Pearl 2³ mask-classification accuracy (three-plane Index regime
//! vs CAM-PQ-shaped bundled regime) — the task-level downstream
//! consequence of pillar 5's sup-error inflation.
//! - 5b. Pearl 2³ mask-classification accuracy (three-plane Index regime
//! vs CAM-PQ-shaped bundled regime) — the task-level downstream
//! consequence of pillar 5's sup-error inflation.
//! 7. Concentration on Hadamard space (Köstenberger-Stark 2024)
//! 8. Hilbert-space CLT for AR(1) (Düker-Zoubouloglou 2024)
//! 9. EWA-sandwich Σ-push-forward along multi-hop edge paths
//! 9b. EWA-Sandwich 3D: Σ-push-forward on symmetric 3×3 SPD covariances
//! (3D analogue of pillar 9; certifies J·W·Σ·Wᵀ·Jᵀ for ndarray::hpc::splat3d)
//! - 9b. EWA-Sandwich 3D: Σ-push-forward on symmetric 3×3 SPD covariances
//! (3D analogue of pillar 9; certifies J·W·Σ·Wᵀ·Jᵀ for ndarray::hpc::splat3d)
//! 10. Nested-distance Lipschitz on Sigma DN-trees (Pflug-Pichler 2012)
//! — certifies CAM-PQ tree quantization preserves FreeEnergy within Lε.
//! 11. Signature uniqueness on tree-quotient (Hambly-Lyons 2010)
Expand Down Expand Up @@ -130,8 +130,11 @@ impl PillarResult {
}
}

/// A named pillar probe: label plus the function that runs it.
type Pillar = (&'static str, fn() -> PillarResult);

pub fn run_all_pillars() -> Vec<PillarResult> {
let pillars: Vec<(&str, fn() -> PillarResult)> = vec![
let pillars: Vec<Pillar> = vec![
(
"E-SUBSTRATE-1: bundle associativity @ d=10000",
substrate::prove,
Expand Down
1 change: 1 addition & 0 deletions crates/jc/src/pearl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ fn hamming(a: &[u8], b: &[u8]) -> u32 {

/// Classify Pearl mask from three independent lossless planes.
/// Each plane carries exactly one role's binding — no interference.
#[allow(clippy::too_many_arguments)] // probe harness: three planes + three role keys + content + threshold
fn classify_three_planes(
plane_s: &[u8],
plane_p: &[u8],
Expand Down
1 change: 1 addition & 0 deletions crates/jc/src/pflug.rs
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ impl BinaryTree {
}

/// Stage of node k (0-indexed; root is stage 0).
#[cfg(test)]
fn stage(k: usize) -> usize {
// Stage = floor(log2(k+1)).
let mut s = 0;
Expand Down
2 changes: 1 addition & 1 deletion crates/jc/src/probe_p1_gamma_phase.rs
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,7 @@ mod tests {
fn apply_offset_wraps_modulo_one() {
// value 0.9 + offset k=4 (4 * 1/(4φ) = 1/φ ≈ 0.618) → 1.518 mod 1 = 0.518
let r = apply_offset(0.9, 4);
assert!(r >= 0.0 && r < 1.0, "result out of [0,1): {r}");
assert!((0.0..1.0).contains(&r), "result out of [0,1): {r}");
}

#[test]
Expand Down
2 changes: 1 addition & 1 deletion crates/jc/src/sigma_codebook_probe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -461,7 +461,7 @@ mod tests {
);
assert_eq!(centroids.len(), 3);
let used = {
let mut seen = vec![false; 3];
let mut seen = [false; 3];
for &a in &assignments {
seen[a] = true;
}
Expand Down
2 changes: 1 addition & 1 deletion crates/jc/src/weyl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
use crate::PillarResult;

const PHI_INV: f64 = 0.618_033_988_749_894_9; // 1/φ = (√5 - 1) / 2
const QUINTENZIRKEL: f64 = 0.584_962_500_721_156_0; // log₂(3/2) ≈ 0.585
const QUINTENZIRKEL: f64 = 0.584_962_500_721_156; // log₂(3/2) ≈ 0.585

fn frac(x: f64) -> f64 {
x - x.floor()
Expand Down
Loading