Skip to content

Usage & API

The public API lives at the module root (github.com/go-ruby-matrix/matrix). It is Ruby-shaped but Go-idiomatic: the Matrix / Vector surface mirrors Ruby's matrix standard library, while following Go conventions — explicit error returns, value types, no global state.

Status: implemented

The library is built and importable as github.com/go-ruby-matrix/matrix, bound into rbgo as a native module; see Roadmap.

Install

go get github.com/go-ruby-matrix/matrix

Worked example

package main

import (
    "fmt"

    "github.com/go-ruby-matrix/matrix"
)

func main() {
    m, _ := matrix.New([][]any{{1, 2}, {3, 4}})

    d, _ := m.Determinant()
    fmt.Println(d)             // -2          (Integer — exact)

    inv, _ := m.Inverse()
    fmt.Println(inv.ToS())     // Matrix[[(-2/1), (1/1)], [(3/2), (-1/2)]]  (exact Rationals)

    p2, _ := m.Pow(2)
    fmt.Println(p2.ToS())      // Matrix[[7, 10], [15, 22]]

    v1 := mustVec(1, 2, 3)
    v2 := mustVec(4, 5, 6)
    dot, _ := v1.InnerProduct(v2)
    fmt.Println(dot)           // 32

    cross, _ := mustVec(1, 0, 0).CrossProduct(mustVec(0, 1, 0))
    fmt.Println(cross.ToS())   // Vector[0, 0, 1]

    fmt.Println(mustVec(3, 4).Magnitude()) // 5.0
}

func mustVec(xs ...any) *matrix.Vector { v, _ := matrix.NewVector(xs); return v }

The numeric tower (exact arithmetic)

Entries flow through matrix.Num, the slice of Ruby's numeric tower the matrix library depends on. A host (rbgo) maps its own numerics to and from it:

Ruby Go (constructors accept) Num kind String() form
Integer int…, uint…, *big.Int Integer 5, -2
Rational *big.Rat Rational (3/2), (0/1)
Float float32, float64 Float 2.0, 0.6, Infinity

Promotion follows Ruby: Integer op Integer stays Integer; any Rational (no Float) yields a Rational that stays Rational even when whole (so inverse prints (1/1), not 1); any Float dominates. Exact division uses Num.Quo (Ruby's Integer#quo), which turns Integer/Integer into a Rational — exactly how MRI's inverse, normalize and matrix / divide. Determinant uses cofactor (Laplace) expansion with only + − ×, so an Integer matrix yields an Integer determinant; Inverse and Rank run exact Gaussian elimination over the tower.

API

// Matrix
func New(rows [][]any) (*Matrix, error)
func Build(r, c int, fn func(i, j int) any) (*Matrix, error)
func Identity(n int) *Matrix
func Zero(r, c int) *Matrix
func Diagonal(values ...any) (*Matrix, error)
func Scalar(n int, value any) (*Matrix, error)
func RowVector(values []any) (*Matrix, error)
func ColumnVector(values []any) (*Matrix, error)
func Rows(rows [][]any) (*Matrix, error)
func Columns(cols [][]any) (*Matrix, error)
func HStack(ms ...*Matrix) (*Matrix, error)
func VStack(ms ...*Matrix) (*Matrix, error)

func (m *Matrix) RowCount() int
func (m *Matrix) ColumnCount() int
func (m *Matrix) At(i, j int) (Num, bool)
func (m *Matrix) Row(i int) (*Vector, bool)
func (m *Matrix) Column(j int) (*Vector, bool)
func (m *Matrix) Each(fn func(v Num))
func (m *Matrix) EachWithIndex(fn func(v Num, i, j int))
func (m *Matrix) ToA() [][]Num
func (m *Matrix) Minor(r0, r1, c0, c1 int) (*Matrix, error)
func (m *Matrix) FirstMinor(i, j int) (*Matrix, error)

func (m *Matrix) Add(other *Matrix) (*Matrix, error)
func (m *Matrix) Sub(other *Matrix) (*Matrix, error)
func (m *Matrix) Neg() *Matrix
func (m *Matrix) Mul(other *Matrix) (*Matrix, error)
func (m *Matrix) MulScalar(scalar any) (*Matrix, error)
func (m *Matrix) MulVector(v *Vector) (*Vector, error)
func (m *Matrix) Div(other *Matrix) (*Matrix, error)
func (m *Matrix) DivScalar(scalar any) (*Matrix, error)
func (m *Matrix) Pow(p int) (*Matrix, error)
func (m *Matrix) Transpose() *Matrix
func (m *Matrix) Trace() (Num, error)
func (m *Matrix) Determinant() (Num, error)
func (m *Matrix) Inverse() (*Matrix, error)
func (m *Matrix) Rank() int
func (m *Matrix) RoundEntries(ndigits int) *Matrix

func (m *Matrix) Square() bool
func (m *Matrix) IsZero() bool
func (m *Matrix) IsDiagonal() bool
func (m *Matrix) Symmetric() bool
func (m *Matrix) LowerTriangular() bool
func (m *Matrix) UpperTriangular() bool
func (m *Matrix) Singular() (bool, error)
func (m *Matrix) Regular() (bool, error)
func (m *Matrix) Orthogonal() (bool, error)
func (m *Matrix) Eql(other *Matrix) bool
func (m *Matrix) Hash() uint64
func (m *Matrix) ToS() string
func (m *Matrix) Inspect() string

// Vector
func NewVector(values []any) (*Vector, error)
func Independent(vs ...*Vector) (bool, error)
func (v *Vector) Elements() []Num
func (v *Vector) Size() int
func (v *Vector) At(i int) (Num, bool)
func (v *Vector) Each(fn func(n Num))
func (v *Vector) Map(fn func(n Num) any) (*Vector, error)
func (v *Vector) Add(other *Vector) (*Vector, error)
func (v *Vector) Sub(other *Vector) (*Vector, error)
func (v *Vector) Mul(scalar any) (*Vector, error)
func (v *Vector) InnerProduct(other *Vector) (Num, error)
func (v *Vector) CrossProduct(other *Vector) (*Vector, error)
func (v *Vector) Magnitude() Num
func (v *Vector) Normalize() (*Vector, error)
func (v *Vector) Angle(other *Vector) (Num, error)
func (v *Vector) Eql(other *Vector) bool
func (v *Vector) ToS() string
func (v *Vector) Inspect() string

// Num (numeric tower)
func NewInt(v int64) Num
func NewBigInt(v *big.Int) Num
func NewRat(n, d int64) Num
func NewBigRat(v *big.Rat) Num
func NewFloat(v float64) Num

// Errors (mirror ExceptionForMatrix)
var ErrDimensionMismatch   // "Dimension mismatch"
var ErrNotRegular          // "Not Regular Matrix"
var ErrOperationNotDefined

MRI conformance

Correctness is defined by reference Ruby. A differential oracle compares every operation's ToS against the system ruby's -rmatrix … .inspect — including the exact-arithmetic results (Integer determinant, Rational inverse, Float-matrix inverse rounding) and the Ruby-faithful float formatter — not approximated from memory. The oracle binmodes stdin/stdout so Windows text-mode never pollutes the bytes, gates itself on RUBY_VERSION >= "4.0", and skips where ruby is absent (the qemu cross-arch lanes), so the cross-arch builds still validate the library.

Relationship to Ruby

go-ruby-matrix/matrix is standalone and reusable, and is the backend bound into go-embedded-ruby by rbgo as a native module — the same way go-ruby-regexp and go-ruby-erb are bound. The dependency runs the other way: this library has no dependency on the Ruby runtime.