///|
pub struct FieldMatrix {
cells : Array[Symbols]
columns : Int32
}
///|
pub fn FieldMatrix::new(
rows : Array[Array[Int32]],
) -> FieldMatrix raise CodeError {
if rows.length() == 0 || rows.length() > 64 {
raise Limit("matrix row count must be 1..64")
}
let columns = rows[0].length()
if columns == 0 || columns > 64 {
raise Limit("matrix column count must be 1..64")
}
let cells : Array[Symbols] = []
for row in rows {
if row.length() != columns {
raise Shape("ragged matrix")
}
cells.push(Symbols::new(row))
}
{ cells, columns, }
}
///|
pub fn FieldMatrix::identity(size : Int32) -> FieldMatrix raise CodeError {
if size < 1 || size > 64 {
raise Limit("identity size must be 1..64")
}
let rows : Array[Array[Int32]] = []
for i in 0.. Int32 {
self.cells.length()
}
///|
pub fn FieldMatrix::cols(self : FieldMatrix) -> Int32 {
self.columns
}
///|
pub fn FieldMatrix::to_arrays(self : FieldMatrix) -> Array[Array[Int32]] {
self.cells.map(row => row.to_array())
}
///|
pub fn FieldMatrix::transpose(self : FieldMatrix) -> FieldMatrix {
let cells : Array[Symbols] = []
for col in 0.. FieldMatrix raise CodeError {
if self.cols() != other.rows() {
raise Shape("matrix multiplication dimension mismatch")
}
let right = other.transpose()
let cells : Array[Symbols] = []
for row in self.cells {
let values : Array[Int32] = []
for col in right.cells {
values.push(row.dot(col))
}
cells.push({ values, })
}
{ cells, columns: other.cols(), }
}
///|
// This independent batch elimination is also a reference for streaming rank.
pub fn FieldMatrix::rank(self : FieldMatrix) -> Int32 {
let rows = self.to_arrays()
let mut pivot = 0
for col in 0.. FieldMatrix raise CodeError {
if self.rows() != self.cols() {
raise Shape("inverse requires a square matrix")
}
let n = self.rows()
let rows = self.to_arrays()
let result = FieldMatrix::identity(n).to_arrays()
for col in 0..