nalgebra icon indicating copy to clipboard operation
nalgebra copied to clipboard

Add Tensor structures and operations

Open notxvilka opened this issue 8 months ago • 1 comments

Currently, there is no support for some of the Tensor operations, also it would be helpful to have a structures/aliases named Tensor* of any dimensionality.

There are exist two small Rust libraries but they are incomplete or abandoned:

  • https://github.com/alphal00p/spenso
  • https://github.com/wildfunctions/tensor

And a small implementation inside Candle:

  • https://github.com/huggingface/candle/blob/main/candle-core/src/tensor.rs

I believe, nalgebra is the place to implement it, since most of the code is already here, just some minor modifications are needed

See also:

  • https://github.com/pytearcat/pytearcat
  • https://arxiv.org/pdf/2106.15016
  • https://hal.science/hal-03298805v1/file/tensors.pdf

notxvilka avatar Apr 15 '25 18:04 notxvilka

try https://crates.io/crates/geonum

tensors scale their complexity exponentially with k rank, or O(n^k)

the geonum tensor_test.rs suite demonstrates a 10^9× speedup for 1000×1000×1000 tensor operations requiring the traditional O(n^3) complexity

even in million-dimensional spaces (1,000,000) geonum completes operations in less than 100ms while traditional tensor designs require operations exceeding atoms in the universe

specific benchmarks in the tests also show a 64× speedup for 4×4×4 tensors (requiring 64 operations traditionally vs 1 for geonum), 1000× for 10×10×10 tensors, and astronomical speedups for quantum simulations with 20 qubits (2^20 states) computed in one operation

you dont need to use tensors or matrices anymore

and you can work with high dimensional multivectors instead, see multivector_test.rs:

#[test]
fn it_operates_on_high_dimensional_multivectors() {
    let space = Dimensions::new(1_000);

    // basis vectors with distinct angles to avoid wedge collapse
    let e1 = Geonum {
        length: 1.0,
        angle: space.base_angle(0),
        blade: 1,
    }; // angle 0, grade 1
    let e2 = Geonum {
        length: 1.0,
        angle: space.base_angle(1),
        blade: 1,
    }; // angle π/2, grade 1
    let e3 = Geonum {
        length: 1.0,
        angle: space.base_angle(3),
        blade: 1,
    }; // angle 3π/2, grade 1

    // step 1: construct bivector B = e1 ∧ e2
    let b12 = e1.wedge(&e2);
    let b12_mv = Multivector(vec![b12]);

    // assert bivector lives in grade 2
    let g2 = b12_mv.grade_range([2, 2]);
    assert!(g2.0.iter().any(|g| g.length > 0.0));

    // step 2: trivector T = (e1 ∧ e2) ∧ e3
    // create e3 as multivector
    let e3_mv = Multivector(vec![e3]);

    // rotating e3 with a different angle to prevent wedge collapse
    let e3_rotated = Geonum {
        length: 1.0,
        angle: PI / 4.0,
        blade: 1,
    };

    // create trivector directly using wedge product between b12 and e3_rotated
    let t123 = b12.wedge(&e3_rotated);
    let t123_mv = Multivector(vec![t123]);

    // assert trivector has a nonzero component in grade 3
    let g3 = t123_mv.grade_range([3, 3]);
    assert!(g3.0.iter().any(|g| g.length > 0.0));

    // step 3: reflect e3 across bivector plane
    let reflected = e3_mv.reflect(&b12_mv);
    assert!(!reflected.0.is_empty());

    // step 4: compute dual of trivector and test result
    let pseudo = Multivector(vec![Geonum {
        length: 1.0,
        angle: PI / 2.0,
        blade: 1000,
    }]); // dummy pseudoscalar with high dimension
    let dual = t123_mv.dual(&pseudo);
    assert!(dual.0.iter().any(|g| g.length > 0.0));

    // step 5: rotate a vector using bivector rotor
    let v = Geonum {
        length: 1.0,
        angle: PI / 4.0,
        blade: 1,
    };
    let v_mv = Multivector(vec![v]);
    let rotated = v_mv.rotate(&b12_mv);
    assert!(rotated.0.iter().any(|g| g.length > 0.0));

    // step 6: project and reject vector from e3
    let proj = v_mv.project(&e3_mv);
    let rej = v_mv.reject(&e3_mv);
    assert!(!proj.0.is_empty()); // test execution
    assert!(!rej.0.is_empty());

    // step 7: confirm mean angle is finite and within expected bounds
    let mean = t123_mv.weighted_circular_mean_angle();
    assert!((0.0..=TAU).contains(&mean));
}

other scientific computing domains are covered in the tests directory

run them all and output their explanations:

git clone https://github.com/mxfactorial/geonum.git
cd geonum
cargo test -- --show-output

welcome to extend those cases to reveal any feature gaps, see https://github.com/pygae/galgebra/issues/532#issuecomment-2813837713

mxfactorial avatar Apr 24 '25 02:04 mxfactorial