Exact linear algebra and Frames
Solve rational matrix systems and change tensor coordinates without losing tensor identity.
Inspect fraction-free elimination
Bareiss elimination keeps exact pivot and row-swap evidence. The stored stages make the recurrence visible without replacing the source matrix.
Reuse one exact factorization
The permutation is part of the mathematical record: P A = L U. Solving two right-hand sides does not repeat elimination.
Use .linalg.LDU(A) when the separated diagonal is useful. It satisfies P A = L D U, and its final U has unit diagonal.
Compute QR without leaving the Rational domain
This matrix has orthogonalization norms 5 and 3, so both reduced factors remain exact:
An input that needs sqrt(2) returns a diagnostic rather than approximate entries or a hidden coefficient-domain change:
Check :status before using Q() or R(). Successful results use :decomposed; other current statuses are :unsupportedCoefficientExtension, :rankDeficient, and :requiresTallOrSquareMatrix.
Compute the fundamental subspaces
For this matrix the dimensions are 1, 1, and 2. Each result keeps its original source matrix and exact pivot evidence.
Move vectors and covectors through a linear map
Pushforward uses A; pullback uses its exact transpose. Compose checks the middle abstract space and inserts a Frame change when needed. A square map's Inverse swaps domain and codomain and exactly inverts the matrix.
Tensor products and contractions
The contraction is 3 + 8 = 11. It is accepted because one slot is primal, one is dual, and both belong to V. Incompatible variance or spaces are an error instead of an implicit identification.
Give a Polynomial a linked Vector view
The coefficients are [3,2,1,0] in the monomial Frame, but p remains a callable Polynomial with Polynomial arithmetic. Serialized records contain stable IDs and data rather than the cyclic in-memory lineage graph.
Choose a dual Frame explicitly
.Plugin.Load("linalg");
space := .linalg.VectorSpace("dual example",2);
e := .linalg.Frame(space,"e",:defining);
chosen := e.Dual("chosen dual",[1,1;0,1]);
x := .linalg.Vector([2,3],e);
alpha := .linalg.Vector([4,5],chosen);
alpha.Pair(x) ##@ == 33
{: alpha.__type,alpha.Pair(x),alpha==.linalg.Covector([9,5],e),
e.Dual().Dual()[:frameidentity]==e[:frameidentity] };The pairing is 33. A dual basis changes coordinates by inverse transpose; no metric is needed to pair a Covector with a Vector.
Raise and lower indices with a metric
.Plugin.Load("linalg");
space := .linalg.VectorSpace("metric example",2);
e := .linalg.Frame(space,"e",:defining);
f := .linalg.Frame(space,{= relativeTo=e,basis=[1,1;0,1] });
metric := .linalg.Metric(e,[2,1;1,3]);
x := .linalg.Vector([2,3],e);
alpha := x.Lower(metric);
x.NormSquared(metric) ##@ == 47
alpha.Raise(metric)==x ##@ == 1
{=
covector=alpha.components,
recovered=alpha.Raise(metric)==x,
squaredNorm=x.NormSquared(metric),
invariant=x.Transform(f).Lower(metric.Transform(f))==alpha.Transform(f)
};The metric is part of the operation, not a consequence of choosing coordinates. It must be exact, symmetric and nonsingular. Norm and Angle additionally require positive definiteness and report unsupported coefficient extensions when a result is not Rational.
Project symmetry and distinguish components from tensor views
.Plugin.Load("linalg");
space := .linalg.VectorSpace("tensor example",2);
e := .linalg.Frame(space,"e",:defining);
t := .linalg.Tensor([1,2;3,4],[e,e]);
symmetric := t.Symmetrize();
antisymmetric := t.Antisymmetrize();
symmetric+antisymmetric==t ##@ == 1
{: symmetric.components,antisymmetric.components,symmetric+antisymmetric==t,
t.Permute([2,1]).components,t.View().SameTensor(t),t.ComponentSlice({: 1,1:2}) };The full view preserves identity. The slot permutation is a new derived tensor. The component slice is Shaped storage, since selecting coordinates generally fails to commute with a change of Frame.
.Plugin.Load("linalg");
space := .linalg.VectorSpace("trace example",2);
e := .linalg.Frame(space,"e",:defining);
x := .linalg.Vector([2,3],e);
alpha := .linalg.Covector([4,5],e);
x.TensorProduct(alpha).Trace() ##@ == 23
{: x.TensorProduct(alpha).Trace(),x.TensorPower(2).components,x.TensorPower(0) };The trace is 23. Same-variance traces require an explicit metric. Symmetry and tensor powers enforce finite work budgets before expanding coordinates.
Save and reconstruct a domain-linked graph
A graph carries the Polynomial source, its explicitly chosen ambient space, and every Frame needed by its coordinate view. Repeated references remain shared within an import, and a second import receives independent identities.
.Plugin.Load("linalg");
small := .linalg.PolynomialSpace(2,:x);
large := .linalg.PolynomialSpace(4,:x);
source := .p`x^2+2*x+3`;
a := small.Realize(source);
b := large.Realize(source);
saved := .MathEncodeJSON(.linalg.ExportGraph([source,a,b]));
loaded := .linalg.ImportGraph(.MathDecodeJSON(saved));
loaded[2].SameSource(loaded[3]) ##@ == 1
loaded[2].Vector().SameTensor(loaded[3].Vector()) ##@ == _
loaded[2].Reconstruct()==loaded[1] ##@ == 1
loaded[1].__type ##@ == "Polynomial"The first and third results are true, the second is _, and the final type is Polynomial. Use SameSource for domain provenance and SameTensor for the abstract tensor identity. Imported sources are frozen coefficient snapshots; they retain no provider closure or reactive subscription. Invalid references, contradictory coordinates and budget overruns are rejected before results are returned. See the README for graph limits and finite storage protocols.
Exact spectral information without a field extension
.Plugin.Load("linalg");
matrix := [1/2,1;0,2/3] ~!: :Matrix;
spectral := matrix.RationalEigenspaces();
spectral.CharacteristicPolynomial().Coefficients().All((entry,index)->entry==[1,-7/6,1/3][index]) ##@ == 1
spectral.Roots().All((entry,index)->entry==[1/2,2/3][index]) ##@ == 1
spectral.Verify() ##@ == 1
rotation := .linalg.RationalEigenspaces([0,-1;1,0]);
rotation.Roots().Len() ##@ == 0
rotation[:canonicalforms][:extensionfieldrequired] ##@ == 1The rotation has characteristic polynomial x^2+1 and no Rational eigenvalue. RiX records the need for a coefficient extension; it does not manufacture a Jordan basis over Q. An incomplete bounded root search reports ? for claims it has not decided.
Finite support in a countable polynomial space
.Plugin.Load("linalg");
polynomials := .linalg.PolynomialSpace(:unbounded);
small := polynomials.Bounded(2);
p := .p`x^5+3*x^2+2`;
r := polynomials.Realize(p);
r.Vector().components.SupportSize() ##@ == 3
r.Reconstruct()==p ##@ == 1
projected := small.Project(r);
projected.Verify() ##@ == 1
projected.Vector().components[1] ##@ == 2
projected.Vector().components[2] ##@ == 0
projected.Vector().components[3] ##@ == 3
polynomials.Include(projected.Realization()).Reconstruct()+projected.Remainder()==p ##@ == 1
saved := .MathEncodeJSON(r.Vector().components.Record());
.linalg.RestoreCoordinates(.MathDecodeJSON(saved)).Verify() ##@ == 1The countable Frame supplies monomials by nonnegative degree; every value has finite support. The bounded projection keeps degrees zero through two and reports the exact discarded term x^5. Sparse tensor products combine ordered coordinate slots with explicit support budgets. They do not create multivariate Polynomials or infinite series.