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
34 changes: 17 additions & 17 deletions .agents/onboard.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,42 +45,42 @@ complete all reading instructions immediately upon starting any conversation. do

read ./README.md and the ./math-1-0.md geometric number spec

learn how to construct angles with new, new_with_blade, new_from_cartesian, from_parts from src/angle.rs:25~190
learn how to construct angles with new, new_with_blade, new_from_cartesian, from_parts from src/angle.rs:25~194

learn how the half-tangent representation works: struct definition, cos_sin, and t accessor in src/angle.rs:4~22 and src/angle.rs:245~270
learn how the half-tangent representation works: struct definition in src/angle.rs:4~23, t accessor in src/angle.rs:229~232, and cos_sin in src/angle.rs:533~551

learn how geonum defines geometric grades with the grade function in src/angle.rs:257~280
learn how geonum defines geometric grades with the grade function in src/angle.rs:242~259

learn how angle addition generates the blade lattice via overflow in src/angle.rs:321~388
learn how angle addition generates the blade lattice via overflow in src/angle.rs:308~381

learn how angle subtraction borrows blades rationally in src/angle.rs:390~450
learn how angle subtraction borrows blades rationally in src/angle.rs:383~445

learn how geonum implements the dual in src/angle.rs:473~490
learn how geonum implements the dual in src/angle.rs:463~478

learn how angle impls PartialEq and Eq in src/angle.rs:572~590
learn how angle impls PartialEq and Eq in src/angle.rs:635~653

learn how angle overloads arithmetic operators in src/angle.rs:592~805
learn how angle overloads arithmetic operators in src/angle.rs:655~844

learn how to construct geonum with new, new_with_angle from src/geonum_mod.rs:32~49

learn how geonum overloads arithmetic operators in src/geonum_mod.rs:737~1005
learn how geonum overloads arithmetic operators in src/geonum_mod.rs:778~1044

learn how geonum can express any number type from the its_a_scalar:8-37, its_a_vector:39-73, its_a_real_number:75-109, its_an_imaginary_number:111-140, its_a_complex_number:142-175, its_a_dual_number:177-296, its_an_octonion:298-342 tests in tests/numbers_test.rs
learn how geonum can express any number type from the its_a_scalar:8-36, its_a_vector:39-72, its_a_real_number:75-108, its_an_imaginary_number:111-139, its_a_complex_number:142-174, its_a_dual_number:177-295, its_an_octonion:298-341 tests in tests/numbers_test.rs

learn how geonum eliminates angle slack created by decomposing angles into scalar coefficients by reading the it_proves_decomposing_angles_with_linearly_combined_basis_vectors_loses_angle_addition:13-86, it_proves_decomposition_distributes_one_angle_across_multiple_scalars:87-161, it_proves_quaternion_tables_add_back_what_decomposition_subtracts:519-662, it_proves_anticommutativity_exists_because_decomposition_subtracts_different_amounts:663-726 tests in tests/linear_algebra_test.rs
learn how geonum eliminates angle slack created by decomposing angles into scalar coefficients by reading the it_proves_decomposing_angles_with_linearly_combined_basis_vectors_loses_angle_addition:13-84, it_proves_decomposition_distributes_one_angle_across_multiple_scalars:87-160, it_proves_quaternion_tables_add_back_what_decomposition_subtracts:519-660, it_proves_anticommutativity_exists_because_decomposition_subtracts_different_amounts:663-726 tests in tests/linear_algebra_test.rs

learn how geonum replaces scalar based quadratic forms with simple angle based rotations in the it_proves_rotational_quadrature_expresses_quadratic_forms:1419-1593 test in tests/dimension_test.rs
learn how geonum replaces scalar based quadratic forms with simple angle based rotations in the it_proves_rotational_quadrature_expresses_quadratic_forms:640-814 test in tests/dimension_test.rs

learn why dimensions are an unnecessary abstraction in the it_proves_quadrature_creates_dimensional_structure:91-140, it_shows_dimensions_are_quarter_turns:141-200 tests in tests/dimension_test.rs
learn why dimensions are an unnecessary abstraction in the it_proves_quadrature_creates_dimensional_structure:91-138, it_shows_dimensions_are_quarter_turns:141-199 tests in tests/dimension_test.rs

learn why geonum deprecates grade decomposition in the it_proves_grade_decomposition_ignores_angle_addition:202-267, it_solves_the_exponential_complexity_explosion:520-581 tests in tests/dimension_test.rs
learn why geonum deprecates grade decomposition in the it_proves_grade_decomposition_ignores_angle_addition:17-80 test in tests/grade_test.rs, and how it dissolves the 2^n explosion in the it_solves_the_exponential_complexity_explosion:18-79 test in tests/pseudoscalar_test.rs

learn how geonum maps grades with the it_replaces_k_to_n_minus_k_with_k_to_4_minus_k:899-981, it_compresses_traditional_ga_grades_to_two_involutive_pairs:1131-1166 tests in tests/dimension_test.rs
learn how geonum maps grades with the it_replaces_k_to_n_minus_k_with_k_to_4_minus_k:259-341, it_compresses_traditional_ga_grades_to_two_involutive_pairs:344-379 tests in tests/grade_test.rs

learn about angle forward only geometry from the it_sets_angle_forward_geometry_as_primitive:1247-1381 test in tests/dimension_test.rs
learn about angle forward only geometry from the it_sets_angle_forward_geometry_as_primitive:503-637 test in tests/dimension_test.rs

read only tests/angle_arithmetic_test.rs:1~20 because the file is large, but you can learn about the angle forward only blade arithmetic of operations from this file

read the it_shows_limits_discard_what_angles_preserve:350-387, it_proves_differentiation_cycles_grades:586-664 tests in tests/calculus_test.rs to understand how geonum automates calculus

tests are styled as trojan horses for simplicity. conventional jargon promising symbol salad but readers get simple arithmetic in test contents. example tests: it_handles_conformal_split:4694-4805, it_handles_inversive_distance:4807-4937 in tests/cga_test.rs
tests are styled as trojan horses for simplicity. conventional jargon promising symbol salad but readers get simple arithmetic in test contents. example tests: it_handles_conformal_split:4694-4804, it_handles_inversive_distance:4807-4936 in tests/cga_test.rs
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,19 @@
# changelog

## 0.13.0 (2026-05-24)

### breaking
- `Geonum::disperse` now carries the phase `kx − ωt` in the angle (was a sign-only blade) — `disperse` finally matches its docstring; the return is `[1, kx − ωt]`, so `.cos_sin()` reads the wave

### fixed
- `Angle::boost(0.0)` returns the `(grade 2, t = 0)` backward pole instead of `NaN` — the horizon limit, every ray collapsing to one null direction

### added
- general relativity test series: schwarzschild_test (the bondi field — redshift, precession, horizon), einstein_test (the field equation as one local condition on that field), gravitational_wave_test (`disperse` on the light cone), sr_gr_collapse_test (SR/GR as one boost, the knob constant or position/time-varying)

### changed
- split dimension_test.rs into pseudoscalar_test.rs (the 2^n/pseudoscalar elimination) and grade_test.rs (grades and the k→4−k duality)

## 0.12.1 (2026-05-22)

### added
Expand Down
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "geonum"
version = "0.12.1"
version = "0.13.0"
edition = "2021"
repository = "https://github.com/mxfactorial/geonum"
description = "geometric number library supporting unlimited dimensions with O(1) complexity"
Expand Down
62 changes: 37 additions & 25 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -148,13 +148,17 @@ astrophysics_test.rs
calculus_test.rs
category_theory_test.rs
cga_test.rs
chem_constants_test.rs
chemistry_test.rs
computer_vision_test.rs
dimension_test.rs
economics_test.rs
einstein_test.rs
em_field_theory_test.rs
fem_test.rs
finance_test.rs
grade_test.rs
gravitational_wave_test.rs
linear_algebra_test.rs
machine_learning_test.rs
mechanics_test.rs
Expand All @@ -167,10 +171,14 @@ numbers_test.rs
optics_test.rs
optimization_test.rs
pga_test.rs
pseudoscalar_test.rs
qm_test.rs
rendering_test.rs
robotics_test.rs
schwarzschild_test.rs
set_theory_test.rs
spacetime_test.rs
sr_gr_collapse_test.rs
taylor_series_test.rs
tensor_test.rs
trigonometry_test.rs
Expand Down Expand Up @@ -382,26 +390,30 @@ geometric numbers build dimensions by rotating—not stacking

test suites:
- tests/numbers_test.rs
- its_a_scalar:8-37
- its_a_vector:39-73
- its_a_real_number:75-109
- its_an_imaginary_number:111-140
- its_a_complex_number:142-175
- its_a_dual_number:177-296
- its_an_octonion:298-342
- its_a_matrix:344-399
- its_a_tensor:401-596
- it_dualizes_log2_geometric_algebra_components:647-682
- its_a_clifford_number:940-1022
- its_a_scalar:8-36
- its_a_vector:39-72
- its_a_real_number:75-108
- its_an_imaginary_number:111-139
- its_a_complex_number:142-174
- its_a_dual_number:177-295
- its_an_octonion:298-341
- its_a_matrix:344-398
- its_a_tensor:401-595
- it_dualizes_log2_geometric_algebra_components:647-680
- its_a_clifford_number:940-1020

- tests/pseudoscalar_test.rs
- it_solves_the_exponential_complexity_explosion:18-79
- it_doesnt_need_a_pseudoscalar:93-288
- it_demonstrates_pseudoscalar_elimination_benefits:291-328
- it_proves_dualization_as_angle_ops_compresses_ga:331-394

- tests/grade_test.rs
- it_replaces_k_to_n_minus_k_with_k_to_4_minus_k:259-341
- it_compresses_traditional_ga_grades_to_two_involutive_pairs:344-379

- tests/dimension_test.rs
- it_solves_the_exponential_complexity_explosion:520-593
- it_doesnt_need_a_pseudoscalar:595-791
- it_demonstrates_pseudoscalar_elimination_benefits:793-831
- it_proves_dualization_as_angle_ops_compresses_ga:833-897
- it_replaces_k_to_n_minus_k_with_k_to_4_minus_k:899-981
- it_compresses_traditional_ga_grades_to_two_involutive_pairs:1131-1166
- it_proves_rotational_quadrature_expresses_quadratic_forms:1419-1593
- it_proves_rotational_quadrature_expresses_quadratic_forms:640-814

- tests/calculus_test.rs
- it_encodes_the_power_in_the_angle:35-88
Expand All @@ -417,13 +429,13 @@ geometric numbers build dimensions by rotating—not stacking
- its_a_surface_integral:934-948

- tests/mechanics_test.rs
- it_changes_kinematic_level_by_cycling_grade:46-195
- it_encodes_velocity:268-322
- it_encodes_acceleration:324-363
- it_encodes_jerk:365-414
- it_encodes_kinetic_energy:959-1046
- it_handles_energy_conservation:1783-1940
- it_handles_momentum_conservation:1942-2051
- it_changes_kinematic_level_by_cycling_grade:46-193
- it_encodes_velocity:268-321
- it_encodes_acceleration:324-362
- it_encodes_jerk:365-412
- it_encodes_kinetic_energy:959-1044
- it_handles_energy_conservation:1783-1939
- it_handles_momentum_conservation:1942-2050
- it_handles_angular_momentum_conservation:2053-2157

create tests/my_test.rs with use geonum::*;
Expand Down
5 changes: 5 additions & 0 deletions src/angle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -605,6 +605,11 @@ impl Angle {

// the Möbius dilation, then rebuild into the quadrant it landed in
let s = s / k;
// k → 0 sends the coordinate to ±∞ — the backward pole θ=π, the boost's
// other fixed point. every ray collapses there (the horizon's one-way limit)
if !s.is_finite() {
return Angle::from_parts(2, 0.0);
}
if (0.0..=1.0).contains(&s) {
Angle::from_parts(0, s)
} else if s > 1.0 {
Expand Down
134 changes: 76 additions & 58 deletions src/traits/waves.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
//! defines the Waves trait and related functionality for wave propagation modeling

use crate::{angle::Angle, geonum_mod::Geonum};
use std::f64::consts::PI;

pub trait Waves: Sized {
/// propagates waves through spacetime using wave equation principles
Expand Down Expand Up @@ -37,13 +38,17 @@ impl Waves for Geonum {
}

fn disperse(position: Self, time: Self, wavenumber: Self, frequency: Self) -> Self {
// compute phase based on dispersion relation: φ = kx - ωt
// the dispersion relation φ = kx − ωt is the wave's ANGLE, the polar form
// E = [1, kx − ωt], so cos_sin reads the field straight off the angle
let k_x = wavenumber * position;
let omega_t = frequency * time;
let phase = k_x - omega_t;

// create new geometric number with unit magnitude and phase angle
Geonum::new_with_angle(1.0, phase.angle)
// signed phase = the (kx − ωt) vector projected onto the real axis. rotating
// a unit wave by it carries φ in the angle, where cos_sin can recover it —
// storing φ in the magnitude (the earlier form) collapsed it to a sign
let phi = phase.mag * phase.angle.grade_angle().cos();
Geonum::new_with_angle(1.0, Angle::new(phi / PI, 1.0))
}

fn frequency(&self, other: &Self, time_interval: Self) -> Self {
Expand Down Expand Up @@ -131,72 +136,85 @@ mod tests {

#[test]
fn it_disperses() {
// define wave parameters as geonums
let wavenumber = Geonum::new(2.0 * PI, 0.0, 1.0); // 2π rad/m (wavelength = 1m)
let frequency = Geonum::new(3.0e8 * 2.0 * PI, 0.0, 1.0); // ω = c·k for light
let position_1 = Geonum::new(0.0, 0.0, 1.0);
let position_2 = Geonum::new(0.5, 0.0, 1.0); // half a wavelength
let time_1 = Geonum::new(0.0, 0.0, 1.0);
let time_2 = Geonum::new(1.0 / (3.0e8 * 2.0 * PI / (2.0 * PI)), 0.0, 1.0); // one period

// create waves at different positions and times
let wave_x1_t1 = Geonum::disperse(position_1, time_1, wavenumber, frequency);
let wave_x2_t1 = Geonum::disperse(position_2, time_1, wavenumber, frequency);
let wave_x1_t2 = Geonum::disperse(position_1, time_2, wavenumber, frequency);

// prove all waves have unit amplitude
assert_eq!(wave_x1_t1.mag, 1.0, "dispersed waves have unit amplitude");
// a plane wave is E = [1, kx − ωt]: the dispersion relation lives in the
// ANGLE, so cos_sin reads the field. k = 2π gives wavelength 1; null
// dispersion ω = ck carries the wave at the speed of light
let c = 3.0e8;
let k = 2.0 * PI; // 2π rad/m, wavelength 1 m
let omega = c * k; // ω = ck for light
let wavenumber = Geonum::scalar(k);
let frequency = Geonum::scalar(omega);

// at the origin the phase is 0 — the wave sits at its crest, cos = 1
let crest = Geonum::disperse(
Geonum::scalar(0.0),
Geonum::scalar(0.0),
wavenumber,
frequency,
);
assert!(crest.near_mag(1.0), "dispersed waves have unit amplitude");
let (cos_crest, _) = crest.angle.cos_sin();
assert!(
(cos_crest - 1.0).abs() < 1e-12,
"phase 0 at the origin — the wave's crest, cos = 1"
);

// prove phase at origin and t=0 has blade 2 from 0-0 subtraction
// a quarter wavelength out kx = π/2: the phase lands at grade 1, a node
let node = Geonum::disperse(
Geonum::scalar(0.25),
Geonum::scalar(0.0),
wavenumber,
frequency,
);
assert_eq!(
wave_x1_t1.angle,
Angle::new_with_blade(2, 0.0, 1.0),
"phase at origin and t=0 has blade 2 from subtraction"
node.angle.grade(),
1,
"kx = π/2 lands at grade 1 — the node"
);
let (cos_node, _) = node.angle.cos_sin();
assert!(
cos_node.abs() < 1e-12,
"a quarter wavelength is a node — cos = 0"
);

// prove spatial phase difference after half a wavelength
// compute the actual phase difference from the disperse operations
let actual_phase_diff = wave_x2_t1.angle - wave_x1_t1.angle;

// compute phase difference using geonum operations
// (at half wavelength this represents π radians or blade 2 geometrically)
let k_x1 = wavenumber * position_1;
let k_x2 = wavenumber * position_2;
let omega_t = frequency * time_1;
let phase_1 = k_x1 - omega_t;
let phase_2 = k_x2 - omega_t;
let expected_phase_diff = phase_2.angle - phase_1.angle;

// half a wavelength out kx = π: the phase is grade 2, the trough, cos = −1
let trough = Geonum::disperse(
Geonum::scalar(0.5),
Geonum::scalar(0.0),
wavenumber,
frequency,
);
assert_eq!(
actual_phase_diff, expected_phase_diff,
"spatial phase difference equals wavenumber times distance"
trough.angle.grade(),
2,
"kx = π lands at grade 2 — the trough"
);
let (cos_trough, _) = trough.angle.cos_sin();
assert!(
(cos_trough + 1.0).abs() < 1e-12,
"half a wavelength is the trough — cos = −1"
);

// prove temporal phase difference after one period
// compute actual phase difference between t2 and t1
let k_x = wavenumber * position_1;
let omega_t1 = frequency * time_1;
let omega_t2 = frequency * time_2;
let phase_t1 = k_x - omega_t1;
let phase_t2 = k_x - omega_t2;

// the phase difference should complete a full cycle (2π)
let phase_diff_angle = wave_x1_t2.angle - wave_x1_t1.angle;
let expected_temporal_diff = phase_t2.angle - phase_t1.angle;

// test that blade difference is 4 (full rotation) or equivalent
assert_eq!(
phase_diff_angle, expected_temporal_diff,
"temporal phase evolution matches expected value"
// one period later t = 2π/ω the wave returns to the same phase — periodic,
// the angle's blade arithmetic handling the wraparound with no manual modulo
let period = 2.0 * PI / omega;
let later = Geonum::disperse(
Geonum::scalar(0.0),
Geonum::scalar(period),
wavenumber,
frequency,
);
let (cos_later, _) = later.angle.cos_sin();
assert!(
(cos_later - cos_crest).abs() < 1e-9,
"the wave repeats after one period T = 2π/ω"
);

// prove dispersion relation by comparing wave phase velocities
// For k=2π, ω=2πc, wave speed should be c
// the phase velocity ω/k recovers the speed of light — the null dispersion
let wave_speed = frequency.mag / wavenumber.mag;
let expected_speed = 3.0e8; // speed of light
assert!(
(wave_speed - expected_speed).abs() / expected_speed < 1e-10,
"dispersion relation yields correct wave speed"
(wave_speed - c).abs() / c < 1e-10,
"ω/k = c — the dispersion relation yields lightspeed"
);
}
}
Loading