Matrices

The Matrix data structure allows users to do linear algebra operations in Symbolica.

Construction

Matrices can be created through one of the following constructors:

from symbolica import *
i = Matrix.identity(2)
e = Matrix.eye([1, 2, 3])
l = Matrix.from_linear(3, 2, [1, 2, 3, 4, 5, 6])
n = Matrix.from_nested([[1, 2, 3], [4, 5, 6]])
use symbolica::domains::integer::IntegerRing;
use symbolica::domains::rational::RationalField;
use symbolica::tensors::matrix::Matrix;

fn main() {
    let i = Matrix::identity(2, IntegerRing::new());
    let e = Matrix::identity(&[1.into(), 2.into(), 3.into()], IntegerRing::new());
    let l = Matrix::from_linear(
        vec![
            1u64.into(),
            2u64.into(),
            3u64.into(),
            4u64.into(),
            5u64.into(),
            6u64.into(),
        ],
        3,
        2,
        IntegerRing::new(),
    )
    .unwrap();
    let n = Matrix::from_nested(
        vec![
            vec![1.into(), 2.into(), 3.into()],
            vec![4.into(), 5.into(), 6.into()],
        ],
        IntegerRing::new(),
    )
    .unwrap();
}

yielding

i = {{1,0},{0,1}}
e = {{1,0,0},{0,2,0},{0,0,3}}
l = {{1,2},{3,4},{5,6}}
n = {{1,2,3},{4,5,6}}

Arithmetic

Matrices can be multiplied, added and subtracted using overloaded operators.

l = Matrix.from_linear(3, 2, [1, 2, 3, 4, 5, 6])
n = Matrix.from_nested([[1, 2, 3], [4, 5, 6]])
l * n + Matrix.identity(3)
    let c = &l * &n + &Matrix::identity(3, IntegerRing::new());

yielding

{{10,12,15},{19,27,33},{29,40,52}}

In Rust, the type of argument of the matrix can be selected, e.g. Matrix<Rational>. In Python, the default is a matrix over rational polynomials, i.e. Matrix<RationalPolynomial<Integer, u16>> in Rust.

Common operations

For matrices over fields, determinants and inverses can be computed.

t = Expression.symbol('t')

a = Matrix.from_nested([[t, 2], [3, 4]])
print('a       =', a)
print('a^-1    =', a.inv())
print('det(a)  =', a.det())
    println!("a      = {}", a);
    println!("a^-1   = {}", a.inv().unwrap());
    println!("det(a) = {}", a.det().unwrap());

which yields

a       = {{t,2},{3,4}}
a^-1    = {{2/(-3+2*t),-3/(-6+4*t)},{-3/(-6+4*t),t/(-6+4*t)}}
det(a)  = -6+4*t

The matrix equation \[\mathbf{A} \cdot \vec{x} = \vec{b}\] can be solved as well:

from symbolica import *
t = Expression.symbol('t')

a = Matrix.from_nested([[t, 2], [3, 4]])
a.solve(Matrix.vec([4, 3]))
    let r = a.solve(&b).unwrap();
    println!("{} . x = {} => x = {}", a, b, r);

which yields:

{{5/(-3+2*t)},{(-12+3*t)/(-6+4*t)}}

Matrices can also be indexed using a (row, column) tuple, which yields the entry.