Matrices
Run Symbolica in your browser
Python examples with a Run button can be edited and run here. The first run loads Python, Symbolica, hover documentation, and code completion.
Use display(expr) to pretty-print an intermediate result. The last expression is displayed automatically.
The Matrix data structure allows users to do linear algebra operations in Symbolica.
Construction
Constructors validate matrix shapes: nested rows must have equal lengths, and linear data must have exactly rows * columns entries. 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]])
display("i =", i)
display("e =", e)
display("l =", l)
nuse symbolica::prelude::*;
fn main() {
let i = Matrix::identity(2, IntegerRing::new());
let e = Matrix::eye(&[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![
vec![1.into(), 2.into(), 3.into()],
vec![4.into(), 5.into(), 6.into()],
],
IntegerRing::new(),
)
.unwrap();
}Output
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.
from symbolica import *
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)use symbolica::prelude::*;
fn main() {
let l = Matrix::from_linear(vec![1.into(), 2.into(), 3.into(), 4.into(), 5.into(), 6.into()], 3, 2, Z).unwrap();
let n = Matrix::from_nested_vec(vec![vec![1.into(), 2.into(), 3.into()], vec![4.into(), 5.into(), 6.into()]], Z).unwrap();
let c = &(&l * &n) + &Matrix::identity(3, Z);
println!("{c}");
}Output
{{10,12,15},{19,27,33},{29,40,52}}
In Rust, the type of argument of the matrix can be selected, e.g. Matrix<Q>. 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. Inverting a singular matrix raises an error in Python and returns an error in Rust.
from symbolica import *
t = Expression.symbol('t')
a = Matrix.from_nested([[t, 2], [3, 4]])
display('a =', a)
display('a^-1 =', a.inv())
display('det(a) =', a.det())Here we specialize t = 1 and use rational coefficients.
use symbolica::prelude::*;
fn main() {
let a: Matrix<Q> = Matrix::from_nested_vec(
vec![vec![1.into(), 2.into()], vec![3.into(), 4.into()]], Q,
).unwrap();
println!("a = {}", a);
println!("a^-1 = {}", a.inv().unwrap());
println!("det(a) = {}", a.det().unwrap());
}Output
a = {{t,2},{3,4}}
a^-1 = {{2/(-3+2*t),-1/(-3+2*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]))Here we specialize t = 1 and use rational coefficients.
use symbolica::prelude::*;
fn main() {
let a: Matrix<Q> = Matrix::from_nested_vec(
vec![vec![1.into(), 2.into()], vec![3.into(), 4.into()]], Q,
).unwrap();
let b = Matrix::from_nested_vec(vec![vec![4.into()], vec![3.into()]], Q).unwrap();
let r = a.solve(&b).unwrap();
println!("{} . x = {} => x = {}", a, b, r);
}Output
{{5/(-3+2*t)},{(-12+3*t)/(-6+4*t)}}
Matrices can also be indexed using a (row, column) tuple, which yields the entry.