matrix

package module
v0.0.0-...-18d9569 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 17, 2026 License: BSD-3-Clause Imports: 6 Imported by: 0

README

go-ruby-matrix/matrix

matrix — go-ruby-matrix

Docs License Go Coverage

A pure-Go (no cgo) reimplementation of Ruby's matrix standard libraryMatrix and Vector with MRI 4.0.5-faithful behaviour. It matches MRI's to_s / inspect formatting, its error classes, and — crucially — its exact arithmetic: an Integer matrix's determinant stays an Integer, and inverse produces exact Rationals (Matrix[[1,2],[3,4]].inverseMatrix[[(-2/1), (1/1)], [(3/2), (-1/2)]]) — without any Ruby runtime.

It is the matrix backend for go-embedded-ruby, but is a standalone, reusable module with no dependency on the Ruby runtime — a sibling of go-ruby-regexp (the Onigmo engine), go-ruby-erb (the ERB compiler) and go-ruby-yaml (the Psych port).

Exact where MRI is exact. Ruby's matrix carries Ruby's numeric tower: Integer and Rational entries stay exact, and a division only escapes to Float when the input is Float. This package mirrors that with a Num tower built on math/big*big.Int for Integers, *big.Rat for Rationals, float64 for Floats — and reproduces MRI's inverse_from Gauss-Jordan step for step (partial pivoting on the largest absolute pivot), so even a Float matrix's inverse reproduces MRI's exact rounding (e.g. -1.9999999999999998).

Features

Faithful port of the Matrix and Vector API, validated against the ruby binary on every supported platform:

  • ConstructorsNew / Build / Identity / Zero / Diagonal / Scalar / RowVector / ColumnVector / Rows / Columns / HStack / VStack.
  • AccessorsRowCount / ColumnCount / At / Row / Column / Each / EachWithIndex / Minor / FirstMinor / ToA.
  • OperationsAdd / Sub / Neg / Mul (matrix·matrix, ·scalar, ·vector) / Div / Pow / Transpose / Trace / Determinant / Inverse / Rank / RoundEntries — all exact over the numeric tower.
  • PredicatesSquare / IsDiagonal / Symmetric / Orthogonal / Singular / Regular / LowerTriangular / UpperTriangular / IsZero.
  • Equality & formattingEql (==), Hash, ToS / Inspect (Matrix[[…], […]], Matrix.empty(r, c)).
  • VectorElements / At / Size / Add / Sub / Mul / InnerProduct (dot) / CrossProduct / Magnitude (norm) / Normalize / Each / Map / Angle / Eql / Independent.
  • ErrorsErrDimensionMismatch, ErrNotRegular, ErrOperationNotDefined, with MRI's messages.

CGO-free, dependency-free, 100% test coverage, gofmt + go vet clean, and green across the six 64-bit Go targets (amd64, arm64, riscv64, loong64, ppc64le, s390x) and three OSes (Linux, macOS, Windows).

Install

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

Usage

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

Tests & coverage

The suite pairs deterministic, ruby-free tests (which alone hold coverage at 100%, so the qemu cross-arch and Windows lanes pass the gate) with a differential MRI oracle: every operation's ToS is compared 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. 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.

COVERPKG=$(go list ./... | paste -sd, -)
go test -race -coverpkg="$COVERPKG" -coverprofile=cover.out ./...
go tool cover -func=cover.out | tail -1   # 100.0%

License

BSD-3-Clause — see LICENSE. Copyright the go-ruby-matrix/matrix authors.

WebAssembly

Being pure Go (CGO=0), this library also compiles to WebAssembly — both GOOS=js GOARCH=wasm (browser / Node.js) and GOOS=wasip1 GOARCH=wasm (WASI). CI builds both targets on every push, alongside the six 64-bit native/qemu arches.

GOOS=js     GOARCH=wasm go build ./...   # browser / Node
GOOS=wasip1 GOARCH=wasm go build ./...   # WASI (wasmtime, wasmer, wasmedge, …)

Documentation

Overview

Package matrix is a pure-Go (CGO=0) reimplementation of Ruby's `matrix` standard library: Matrix and Vector with MRI-faithful behaviour.

Like MRI, arithmetic is exact wherever the input is exact. Entries flow through the Num numeric tower (Integer / Rational / Float), so Matrix#determinant of an Integer matrix stays an Integer and Matrix#inverse produces exact Rationals — `New([][]any{{1,2},{3,4}}).Inverse()` renders `Matrix[[(-2/1), (1/1)], [(3/2), (-1/2)]]`, exactly as `Matrix[[1,2],[3,4]].inverse` does under Ruby 4.0.

The formatting (ToS / Inspect), the error classes (ErrDimensionMismatch / ErrNotRegular / ErrOperationNotDefined) and the numeric promotion rules all track MRI so a binding (rbgo) can present this as the genuine `Matrix` class.

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrDimensionMismatch corresponds to Matrix::ErrDimensionMismatch
	// ("Dimension mismatch"): operands whose shapes are incompatible.
	ErrDimensionMismatch = errors.New("Dimension mismatch")

	// ErrNotRegular corresponds to Matrix::ErrNotRegular ("Not Regular
	// Matrix"): inverting or dividing by a singular matrix.
	ErrNotRegular = errors.New("Not Regular Matrix")

	// ErrOperationNotDefined corresponds to Matrix::ErrOperationNotDefined: an
	// operation that is not defined for the given operand.
	ErrOperationNotDefined = errors.New("operation not defined")

	// ErrArgument corresponds to Ruby's ArgumentError. The concrete error
	// carries MRI's exact message (e.g. "wrong number of arguments (1 for 0)")
	// and wraps this sentinel so callers can match it with errors.Is.
	ErrArgument = errors.New("ArgumentError")
)

These mirror the exceptions Ruby's matrix library raises under ExceptionForMatrix. The messages match MRI's so a binding can surface them verbatim.

Functions

func Independent

func Independent(vs ...*Vector) (bool, error)

Independent reports whether the given vectors are linearly independent, like `Vector.independent?(*vs)`. Vectors of differing sizes are not independent (MRI raises ErrDimensionMismatch); this returns an error for that case.

Types

type Matrix

type Matrix struct {
	// contains filtered or unexported fields
}

Matrix is an immutable r×c matrix of Num entries, stored row-major.

func Build

func Build(r, c int, fn func(i, j int) any) (*Matrix, error)

Build returns an r×c matrix whose (i,j) entry is fn(i,j), like `Matrix.build(r, c) { |i, j| ... }`.

func ColumnVector

func ColumnVector(values []any) (*Matrix, error)

ColumnVector returns an n×1 matrix from the values, like `Matrix.column_vector([...])`.

func Columns

func Columns(cols [][]any) (*Matrix, error)

Columns builds a Matrix treating each inner slice as a column, like `Matrix.columns(...)`.

func Diagonal

func Diagonal(values ...any) (*Matrix, error)

Diagonal returns a square matrix with the given values on the diagonal and Integer zeros elsewhere, like `Matrix.diagonal(*values)`.

func HStack

func HStack(ms ...*Matrix) (*Matrix, error)

HStack returns the matrices joined left-to-right; all must have equal row counts, like `Matrix.hstack(*matrices)`.

func Identity

func Identity(n int) *Matrix

Identity returns the n×n identity matrix (Integer entries), like `Matrix.identity(n)`.

func New

func New(rows [][]any) (*Matrix, error)

New builds a Matrix from rows of values (each value convertible via the Num tower: int kinds, *big.Int, *big.Rat, float kinds, or Num). All rows must have the same length; an empty input yields a 0×0 matrix. It mirrors `Matrix[[...],[...]]` / `Matrix.rows`.

func RowVector

func RowVector(values []any) (*Matrix, error)

RowVector returns a 1×n matrix from the values, like `Matrix.row_vector([...])`.

func Rows

func Rows(rows [][]any) (*Matrix, error)

Rows builds a Matrix treating each inner slice as a row. It is an alias of New matching `Matrix.rows(...)`.

func Scalar

func Scalar(n int, value any) (*Matrix, error)

Scalar returns the n×n matrix with value on the diagonal and zeros elsewhere, like `Matrix.scalar(n, value)`.

func VStack

func VStack(ms ...*Matrix) (*Matrix, error)

VStack returns the matrices stacked top-to-bottom; all must have equal column counts, like `Matrix.vstack(*matrices)`.

func Zero

func Zero(r, c int) *Matrix

Zero returns an r×c matrix of Integer zeros, like `Matrix.zero(r, c)`.

func (*Matrix) Add

func (m *Matrix) Add(other *Matrix) (*Matrix, error)

Add returns m + other (entry-wise); shapes must match, like `Matrix#+`.

func (*Matrix) At

func (m *Matrix) At(i, j int) (Num, bool)

At returns the (i,j) entry. It returns false when the indices are out of range, matching `Matrix#[]` which returns nil there.

func (*Matrix) Column

func (m *Matrix) Column(j int) (*Vector, bool)

Column returns column j as a Vector, like `Matrix#column(j)`.

func (*Matrix) ColumnCount

func (m *Matrix) ColumnCount() int

ColumnCount returns the number of columns.

func (*Matrix) Determinant

func (m *Matrix) Determinant() (Num, error)

Determinant returns the determinant; the matrix must be square, like `Matrix#determinant` / `#det`. It uses cofactor (Laplace) expansion with only +, − and ×, so an Integer matrix yields an Integer determinant exactly as MRI does (no Rational/Float drift).

func (*Matrix) Div

func (m *Matrix) Div(other *Matrix) (*Matrix, error)

Div returns m·other⁻¹ (matrix division), like `Matrix#/` between matrices.

func (*Matrix) DivScalar

func (m *Matrix) DivScalar(scalar any) (*Matrix, error)

DivScalar returns m with each entry divided by scalar, like `Matrix#/` with a scalar. Division follows Ruby's `/` operator per operand kind: Integer/Integer floors to an Integer, any Rational stays Rational, and any Float yields a Float — see Num.Div.

func (*Matrix) Each

func (m *Matrix) Each(fn func(v Num))

Each calls fn for every entry in row-major order, like `Matrix#each`.

func (*Matrix) EachWithIndex

func (m *Matrix) EachWithIndex(fn func(v Num, i, j int))

EachWithIndex calls fn(v, i, j) for every entry in row-major order, like `Matrix#each_with_index`.

func (*Matrix) Eql

func (m *Matrix) Eql(other *Matrix) bool

Eql reports whether two matrices have the same shape and numerically equal entries, like `Matrix#==`.

func (*Matrix) FirstMinor

func (m *Matrix) FirstMinor(i, j int) (*Matrix, error)

FirstMinor returns the matrix with row i and column j removed, like `Matrix#first_minor(i, j)`.

func (*Matrix) Hash

func (m *Matrix) Hash() uint64

Hash returns a hash of the matrix derived from its shape and entry values, consistent with Eql, like `Matrix#hash`.

func (*Matrix) Inspect

func (m *Matrix) Inspect() string

Inspect is an alias of ToS, matching that MRI's Matrix#inspect and #to_s produce the same text.

func (*Matrix) Inverse

func (m *Matrix) Inverse() (*Matrix, error)

Inverse returns the inverse matrix; the matrix must be square and regular, like `Matrix#inverse` / `#inv`. It reproduces MRI's `inverse_from` algorithm step for step — Gauss-Jordan with partial pivoting on the largest absolute pivot, dividing with the exact Num.Quo — so an Integer matrix inverts to exact Rationals (`[[1,2],[3,4]].inverse` → `[[(-2/1),(1/1)],[(3/2),(-1/2)]]`) and a Float matrix reproduces MRI's exact rounding, including the same elimination order that yields values like `-1.9999999999999998`.

func (*Matrix) IsDiagonal

func (m *Matrix) IsDiagonal() bool

IsDiagonal reports whether the matrix is square with zeros off the diagonal, like `Matrix#diagonal?`.

func (*Matrix) IsZero

func (m *Matrix) IsZero() bool

IsZero reports whether every entry is zero, like `Matrix#zero?`.

func (*Matrix) LowerTriangular

func (m *Matrix) LowerTriangular() bool

LowerTriangular reports whether all entries above the diagonal are zero, like `Matrix#lower_triangular?`.

func (*Matrix) Minor

func (m *Matrix) Minor(r0, r1, c0, c1 int) (*Matrix, error)

Minor returns the submatrix spanning rows [r0,r1) and columns [c0,c1), like `Matrix#minor(r0...r1, c0...c1)`. Bounds are clamped to the matrix as MRI does for ranges that overshoot; an empty span yields an empty matrix.

func (*Matrix) Mul

func (m *Matrix) Mul(other *Matrix) (*Matrix, error)

Mul returns the matrix product m·other; m.cols must equal other.rows, like `Matrix#*` between matrices.

func (*Matrix) MulScalar

func (m *Matrix) MulScalar(scalar any) (*Matrix, error)

MulScalar returns m scaled by a single value, like `Matrix#*` with a scalar.

func (*Matrix) MulVector

func (m *Matrix) MulVector(v *Vector) (*Vector, error)

MulVector returns the matrix-times-column-vector product m·v, returning a Vector, like `Matrix#*` with a Vector. m.cols must equal v.Size().

func (*Matrix) Neg

func (m *Matrix) Neg() *Matrix

Neg returns -m, like `Matrix#-@`.

func (*Matrix) Orthogonal

func (m *Matrix) Orthogonal() (bool, error)

Orthogonal reports whether the matrix is square and its transpose is its inverse (mᵀ·m == I), like `Matrix#orthogonal?`.

func (*Matrix) Pow

func (m *Matrix) Pow(p int) (*Matrix, error)

Pow returns m raised to an integer power. Positive powers multiply m by itself; m**0 is the identity; negative powers use the inverse. The matrix must be square. Mirrors `Matrix#**`.

func (*Matrix) Rank

func (m *Matrix) Rank() int

Rank returns the rank of the matrix (the number of linearly independent rows) computed by exact Gaussian elimination over the numeric tower, like `Matrix#rank`. It works for non-square matrices.

func (*Matrix) Regular

func (m *Matrix) Regular() (bool, error)

Regular reports whether the matrix is square and non-singular (invertible), like `Matrix#regular?`.

func (*Matrix) RoundEntries

func (m *Matrix) RoundEntries(ndigits int) *Matrix

RoundEntries returns the matrix with every entry rounded to ndigits decimal places, like `Matrix#round(ndigits)`. Per Ruby's per-kind round semantics, ndigits <= 0 (which includes the no-arg `Matrix#round`, called as RoundEntries(0)) produces Integer entries, while ndigits >= 1 keeps each entry's kind — see Num.Round.

func (*Matrix) Row

func (m *Matrix) Row(i int) (*Vector, bool)

Row returns row i as a Vector, like `Matrix#row(i)`.

func (*Matrix) RowCount

func (m *Matrix) RowCount() int

RowCount returns the number of rows.

func (*Matrix) Singular

func (m *Matrix) Singular() (bool, error)

Singular reports whether the matrix is square and has determinant zero, like `Matrix#singular?`.

func (*Matrix) Square

func (m *Matrix) Square() bool

Square reports whether the matrix is square, like `Matrix#square?`.

func (*Matrix) Sub

func (m *Matrix) Sub(other *Matrix) (*Matrix, error)

Sub returns m - other (entry-wise); shapes must match, like `Matrix#-`.

func (*Matrix) Symmetric

func (m *Matrix) Symmetric() bool

Symmetric reports whether the matrix equals its transpose, like `Matrix#symmetric?`. Non-square matrices are not symmetric.

func (*Matrix) ToA

func (m *Matrix) ToA() [][]Num

ToA returns the entries as a slice of rows (a fresh copy), like `Matrix#to_a`.

func (*Matrix) ToS

func (m *Matrix) ToS() string

ToS renders the matrix as `Matrix[[...], [...]]`, identical to MRI's `Matrix#to_s` and `#inspect` for populated matrices. An empty matrix renders as `Matrix.empty(r, c)`.

func (*Matrix) Trace

func (m *Matrix) Trace() (Num, error)

Trace returns the sum of the diagonal entries; the matrix must be square, like `Matrix#trace` / `#tr`.

func (*Matrix) Transpose

func (m *Matrix) Transpose() *Matrix

Transpose returns the transpose mᵀ, like `Matrix#transpose` / `#t`.

func (*Matrix) UpperTriangular

func (m *Matrix) UpperTriangular() bool

UpperTriangular reports whether all entries below the diagonal are zero, like `Matrix#upper_triangular?`.

type Num

type Num struct {
	// contains filtered or unexported fields
}

Num is one entry of a Matrix or Vector. It models the slice of Ruby's numeric tower that the `matrix` stdlib actually depends on: Integer, Rational and Float. Keeping the three kinds distinct is what lets this package reproduce MRI's exact-arithmetic output byte for byte — `Matrix[[1,2],[3,4]].inverse` must print exact Rationals like `(-2/1)`, and `det` of an Integer matrix must stay an Integer, never silently degrade to Float.

The kinds promote following Ruby's coercion rules:

  • Integer op Integer → Integer (except Quo, see below)
  • any Rational, no Float → Rational (stays Rational even when whole)
  • any Float → Float

Quo is exact "/": Integer.quo(Integer) yields a Rational, matching how MRI's Matrix#inverse and Vector#normalize divide. Plain Ruby Integer "/" floors, but the matrix library never uses it, so Num offers only the exact Quo.

func NewBigInt

func NewBigInt(v *big.Int) Num

NewBigInt returns an Integer Num from a *big.Int (the value is copied).

func NewBigRat

func NewBigRat(v *big.Rat) Num

NewBigRat returns a Rational Num from a *big.Rat (the value is copied).

func NewFloat

func NewFloat(v float64) Num

NewFloat returns a Float Num.

func NewInt

func NewInt(v int64) Num

NewInt returns an Integer Num.

func NewRat

func NewRat(n, d int64) Num

NewRat returns a Rational Num n/d (reduced; d must be non-zero).

func (Num) Add

func (a Num) Add(b Num) Num

Add returns a+b.

func (Num) Div

func (a Num) Div(b Num) Num

Div returns a/b following Ruby's `/` operator per operand kind, as used by `Matrix#/` with a scalar. Unlike the exact Quo, this reproduces Ruby's type-directed division:

  • Integer / Integer → Integer, floor division (so 3/2 == 1, -3/2 == -2);
  • Integer / Rational, Rational / anything (non-Float) → Rational;
  • any Float involvement → Float.

b must be non-zero (callers guard against a zero divisor).

func (Num) Eql

func (a Num) Eql(b Num) bool

Eql reports numeric equality across kinds, matching Ruby's == (Rational(2,1) equals the Integer 2, and 2.0 equals 2).

func (Num) IsZero

func (a Num) IsZero() bool

IsZero reports whether a == 0.

func (Num) Mul

func (a Num) Mul(b Num) Num

Mul returns a*b.

func (Num) Neg

func (a Num) Neg() Num

Neg returns -a.

func (Num) Quo

func (a Num) Quo(b Num) Num

Quo returns the exact quotient a/b. Integer/Integer yields a Rational (Ruby's Integer#quo), mirroring how Matrix#inverse divides; Float involvement yields a Float. b must be non-zero (callers guard against a zero pivot/divisor).

func (Num) Round

func (a Num) Round(ndigits int) Num

Round returns a rounded to ndigits decimal places, following Ruby's Integer#round / Rational#round / Float#round, which `Matrix#round` maps over the entries. Two rules drive the result kind, exactly as in MRI:

  • ndigits <= 0 always yields an Integer (this includes the no-arg form, called here as Round(0)), rounding half away from zero at the 10**(-ndigits) place;
  • ndigits >= 1 keeps the operand's kind: an Integer stays itself, a Rational stays a (rounded) Rational, a Float stays a (rounded) Float.

All kinds round half away from zero, matching Ruby's default rounding mode.

func (Num) Sqrt

func (a Num) Sqrt() Num

Sqrt returns the Float square root of a (always a Float, like Ruby's Integer#** with 0.5 / Math.sqrt used by Vector#magnitude).

func (Num) String

func (a Num) String() string

String renders the Num exactly as Ruby's Kernel#inspect would for that kind: Integers bare ("5", "-2"), Rationals as "(n/d)", Floats via Ruby's float formatting (e.g. "2.0", "0.6", "-1.9999999999999998").

func (Num) Sub

func (a Num) Sub(b Num) Num

Sub returns a-b.

type Vector

type Vector struct {
	// contains filtered or unexported fields
}

Vector is an immutable sequence of Num entries, the analogue of Ruby's Vector. Like Matrix, arithmetic is exact where the input is exact; magnitude, normalisation and angle go through Float because they involve a square root.

func NewVector

func NewVector(values []any) (*Vector, error)

NewVector builds a Vector from values (each convertible via the Num tower), like `Vector[...]` / `Vector.elements([...])`.

func (*Vector) Add

func (v *Vector) Add(other *Vector) (*Vector, error)

Add returns v + other (entry-wise); sizes must match, like `Vector#+`.

func (*Vector) Angle

func (v *Vector) Angle(other *Vector) (Num, error)

Angle returns the angle in radians between v and other (a Float), like `Vector#angle_with`. Neither vector may be zero.

func (*Vector) At

func (v *Vector) At(i int) (Num, bool)

At returns the i-th entry, like `Vector#[]`. The second result is false when i is out of range (Ruby returns nil there).

func (*Vector) CrossProduct

func (v *Vector) CrossProduct(other *Vector) (*Vector, error)

CrossProduct returns the cross product with one other vector, like the binary form of `Vector#cross_product`. It mirrors MRI exactly: the receiver must have dimension at least 2, and the cross product with a single argument is only defined when the receiver is 3-dimensional. MRI implements cross_product(*vs) requiring vs.size == size-2, so for a single argument any size other than 3 is the wrong number of arguments and raises ArgumentError; a sub-2 dimension instead raises ErrOperationNotDefined, and a dimension mismatch between the two vectors raises ErrDimensionMismatch.

func (*Vector) Each

func (v *Vector) Each(fn func(n Num))

Each calls fn for every entry in order, like `Vector#each`.

func (*Vector) Elements

func (v *Vector) Elements() []Num

Elements returns a copy of the entries, like `Vector#elements` / `#to_a`.

func (*Vector) Eql

func (v *Vector) Eql(other *Vector) bool

Eql reports whether two vectors have the same size and numerically equal entries, like `Vector#==`.

func (*Vector) InnerProduct

func (v *Vector) InnerProduct(other *Vector) (Num, error)

InnerProduct returns the dot product v·other; sizes must match, like `Vector#inner_product` / `#dot`.

func (*Vector) Inspect

func (v *Vector) Inspect() string

Inspect is an alias of ToS.

func (*Vector) Magnitude

func (v *Vector) Magnitude() Num

Magnitude returns the Euclidean norm √(Σ vᵢ²) as a Float, like `Vector#magnitude` / `#norm` / `#r`.

func (*Vector) Map

func (v *Vector) Map(fn func(n Num) any) (*Vector, error)

Map returns a new Vector with fn applied to each entry, like `Vector#map`.

func (*Vector) Mul

func (v *Vector) Mul(scalar any) (*Vector, error)

Mul returns v scaled by a single value, like `Vector#*` with a scalar.

func (*Vector) Normalize

func (v *Vector) Normalize() (*Vector, error)

Normalize returns v scaled to unit magnitude; the zero vector cannot be normalised, like `Vector#normalize`.

func (*Vector) Size

func (v *Vector) Size() int

Size returns the number of entries, like `Vector#size`.

func (*Vector) Sub

func (v *Vector) Sub(other *Vector) (*Vector, error)

Sub returns v - other (entry-wise); sizes must match, like `Vector#-`.

func (*Vector) ToS

func (v *Vector) ToS() string

ToS renders the vector as `Vector[...]`, identical to MRI's `Vector#to_s` and `#inspect`.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL