Representations and arithmetic¶
All computational methods share an explicit Budget; see budgets and errors.
Fields describe canonical representations; use validated factories when
constructing values and preserve their invariants when inspecting fields.
Example¶
This computes \((x+1)^3\) and its derivative at \(x=3\), then checks a dense conversion and the kernel encoding. Zero and one have dedicated kernel representations, so the literal codec rejects those two polynomials.
"""Compute exact powers, derivatives, and kernel bytes with one shared budget."""
from std.testing import assert_equal
from apn_mojo import Rational
from polynomials import Budget, QQ, NoContext, MonomialOrder, SparsePoly, DensePoly, evaluate, evaluate_dense, derivative, to_kernel_bytes, from_kernel_bytes
def main() raises:
var budget = Budget(1000000)
var order = MonomialOrder()
var x = SparsePoly[QQ].variable(0, order, NoContext(), budget)
var one = SparsePoly[QQ].constant(QQ(Rational(1)), order, budget)
var p = x.add(one, budget).pow(3, budget)
var point: List[Tuple[Int64, QQ]] = [(Int64(0), QQ(Rational(3)))]
var value = evaluate(p, point, budget)
var slope = evaluate(derivative(p, 0, budget), point, budget)
assert_equal(value, QQ(Rational(64)))
assert_equal(slope, QQ(Rational(48)))
var dense = DensePoly[QQ].from_sparse(p, budget)
assert_equal(evaluate_dense(dense, point[0][1], budget), value)
var bytes = to_kernel_bytes(p, budget)
assert_equal(from_kernel_bytes(bytes[:], budget), p)
assert_equal(len(bytes), 100)
print("Value at 3:", value.value)
print("Derivative at 3:", slope.value)
print("Kernel bytes:", len(bytes))
Run from the repository root pixi run mojo run -I build docs/examples/arithmetic.mojo
Output
Value at 3: 64
Derivative at 3: 48
Kernel bytes: 100
Types and functions¶
PolyErrorKind¶
@fieldwise_init
struct PolyErrorKind(ImplicitlyCopyable, Equatable, Writable)
Classify a polynomial operation's failure.
Defined in src/polynomials/errors.mojo.
| Field | Type | |
|---|---|---|
code |
UInt8 |
The stable kind code. |
PolyErrorKind.LIMIT¶
comptime LIMIT = Self(1)
The work budget is exhausted.
PolyErrorKind.CAPACITY¶
comptime CAPACITY = Self(2)
A size or work counter cannot be represented.
PolyErrorKind.DOMAIN¶
comptime DOMAIN = Self(3)
The operands do not belong to the operation's domain.
PolyErrorKind.UNSUPPORTED¶
comptime UNSUPPORTED = Self(4)
The operation is not supported for these operands.
PolyErrorKind.ENCODING¶
comptime ENCODING = Self(5)
The bytes do not encode a canonical polynomial.
PolyError¶
@fieldwise_init
struct PolyError(Copyable, Movable, Writable)
A typed failure, with no implicit conversion from plain Error.
Defined in src/polynomials/errors.mojo.
| Field | Type | |
|---|---|---|
kind |
PolyErrorKind |
The machine-readable failure kind. |
message |
String |
The human-readable diagnostic. |
Budget¶
struct Budget(ImplicitlyCopyable, Writable)
A deterministic abstract-work allowance shared by nested calls.
Defined in src/polynomials/errors.mojo.
Budget.__init__¶
def __init__(out self, steps: UInt64 = UInt64.MAX)
Create a budget.
Arguments.
steps: The initial work allowance.
Budget.charge¶
def charge(mut self, n: UInt64) raises PolyError
Charge before performing work; a rejected charge changes nothing.
Arguments.
n: The work to charge.
Raises.
PolyError: LIMIT if the allowance is insufficient.
Budget.remaining¶
def remaining(self) -> UInt64
Return the unspent allowance.
Returns. The remaining abstract work units.
CoefficientRing¶
trait CoefficientRing(Copyable, Equatable, Writable, Deinitable)
An exact commutative ring with explicit context and charged arithmetic.
Defined in src/polynomials/coefficients.mojo.
CoefficientRing.Context¶
comptime Context: Copyable & Equatable & Writable & Deinitable
The type describing the coefficient ring.
CoefficientRing.zero¶
@staticmethod
def zero(ctx: Self.Context) -> Self
Construct the additive identity.
Arguments.
ctx: The ring context.
Returns. Zero in that ring.
CoefficientRing.one¶
@staticmethod
def one(ctx: Self.Context) -> Self
Construct the multiplicative identity.
Arguments.
ctx: The ring context.
Returns. One in that ring.
CoefficientRing.context¶
def context(self) -> Self.Context
Report the ring context.
Returns. This value's ring.
CoefficientRing.is_zero¶
def is_zero(self) -> Bool
Test the additive identity in constant time.
Returns. Whether the value is zero.
CoefficientRing.size¶
def size(self) -> Int
Report the magnitude storage size in bytes.
Returns. A positive size used for precharging arithmetic.
CoefficientRing.add¶
def add(self, other: Self, mut budget: Budget) raises PolyError -> Self
Compute the exact sum.
Arguments.
other: The other coefficient in the same ring.budget: The shared work allowance.
Returns. The result in the same ring.
Raises.
PolyError: DOMAIN for different rings, LIMIT or CAPACITY for work limits.
CoefficientRing.sub¶
def sub(self, other: Self, mut budget: Budget) raises PolyError -> Self
Compute the exact difference.
Arguments.
other: The other coefficient in the same ring.budget: The shared work allowance.
Returns. The result in the same ring.
Raises.
PolyError: DOMAIN for different rings, LIMIT or CAPACITY for work limits.
CoefficientRing.mul¶
def mul(self, other: Self, mut budget: Budget) raises PolyError -> Self
Compute the exact product.
Arguments.
other: The other coefficient in the same ring.budget: The shared work allowance.
Returns. The result in the same ring.
Raises.
PolyError: DOMAIN for different rings, LIMIT or CAPACITY for work limits.
CoefficientRing.neg¶
def neg(self, mut budget: Budget) raises PolyError -> Self
Compute the additive inverse.
Arguments.
budget: The shared work allowance.
Returns. The negated coefficient.
Raises.
PolyError: LIMIT or CAPACITY for work limits.
CoefficientField¶
trait CoefficientField(CoefficientRing)
A coefficient ring with inverses for nonzero elements.
Defined in src/polynomials/coefficients.mojo.
CoefficientField.inverse¶
def inverse(self, mut budget: Budget) raises PolyError -> Self
Compute the multiplicative inverse.
Arguments.
budget: The shared work allowance.
Returns. The inverse in this field.
Raises.
PolyError: DOMAIN for zero, LIMIT or CAPACITY for work limits.
NoContext¶
@fieldwise_init
struct NoContext(ImplicitlyCopyable, Equatable, Writable)
The unique context of integers, rationals, and Gaussian rationals.
Defined in src/polynomials/coefficients.mojo.
Modulus¶
struct Modulus(ImplicitlyCopyable, Equatable, Writable)
A validated prime strictly below two to the power 62.
Defined in src/polynomials/coefficients.mojo.
| Field | Type | |
|---|---|---|
value |
UInt64 |
The prime; callers must preserve the validated value. |
Modulus.__init__¶
def __init__(out self, value: UInt64, mut budget: Budget) raises PolyError
Validate a prime field context using deterministic Miller-Rabin.
Arguments.
value: The proposed prime.budget: The shared work allowance.
Raises.
PolyError: DOMAIN for a nonprime or out-of-range modulus, LIMIT on exhaustion.
Modulus.__init__¶
def __init__(out self, *, _prime_value: UInt64)
Recover an already validated internal prime context.
Arguments.
_prime_value: A prime previously checked by the public constructor.
ZZ¶
@fieldwise_init
struct ZZ(CoefficientRing)
An exact integer coefficient.
Defined in src/polynomials/coefficients.mojo.
| Field | Type | |
|---|---|---|
value |
Integer |
The canonical arbitrary-precision value. |
ZZ.Context¶
comptime Context = NoContext
The unique ring context.
ZZ.zero¶
@staticmethod
def zero(ctx: NoContext) -> Self
Construct zero.
Arguments.
ctx: The ring context.
Returns. The additive identity.
ZZ.one¶
@staticmethod
def one(ctx: NoContext) -> Self
Construct one.
Arguments.
ctx: The ring context.
Returns. The multiplicative identity.
ZZ.context¶
def context(self) -> NoContext
Report the unique context.
Returns. The ring's context.
ZZ.is_zero¶
def is_zero(self) -> Bool
Test whether this coefficient is zero.
Returns. Whether the value is zero.
ZZ.size¶
def size(self) -> Int
Report a positive magnitude size in bytes.
Returns. The size used by the work model.
ZZ.add¶
def add(self, other: Self, mut budget: Budget) raises PolyError -> Self
Compute the exact sum after charging its size.
Arguments.
other: The other coefficient.budget: The shared work allowance.
Returns. The exact result.
Raises.
PolyError: LIMIT or CAPACITY if the computation cannot proceed.
ZZ.sub¶
def sub(self, other: Self, mut budget: Budget) raises PolyError -> Self
Compute the exact difference after charging its size.
Arguments.
other: The other coefficient.budget: The shared work allowance.
Returns. The exact result.
Raises.
PolyError: LIMIT or CAPACITY if the computation cannot proceed.
ZZ.mul¶
def mul(self, other: Self, mut budget: Budget) raises PolyError -> Self
Compute the exact product after charging its size.
Arguments.
other: The other coefficient.budget: The shared work allowance.
Returns. The exact result.
Raises.
PolyError: LIMIT or CAPACITY if the computation cannot proceed.
ZZ.neg¶
def neg(self, mut budget: Budget) raises PolyError -> Self
Negate the coefficient after charging its size.
Arguments.
budget: The shared work allowance.
Returns. The additive inverse.
Raises.
PolyError: LIMIT if the allowance is insufficient.
QQ¶
@fieldwise_init
struct QQ(CoefficientField)
An exact rational coefficient.
Defined in src/polynomials/coefficients.mojo.
| Field | Type | |
|---|---|---|
value |
Rational |
The canonical arbitrary-precision value. |
QQ.Context¶
comptime Context = NoContext
The unique ring context.
QQ.zero¶
@staticmethod
def zero(ctx: NoContext) -> Self
Construct zero.
Arguments.
ctx: The ring context.
Returns. The additive identity.
QQ.one¶
@staticmethod
def one(ctx: NoContext) -> Self
Construct one.
Arguments.
ctx: The ring context.
Returns. The multiplicative identity.
QQ.context¶
def context(self) -> NoContext
Report the unique context.
Returns. The ring's context.
QQ.is_zero¶
def is_zero(self) -> Bool
Test whether this coefficient is zero.
Returns. Whether the value is zero.
QQ.size¶
def size(self) -> Int
Report a positive magnitude size in bytes.
Returns. The size used by the work model.
QQ.add¶
def add(self, other: Self, mut budget: Budget) raises PolyError -> Self
Compute the exact sum after charging its size.
Arguments.
other: The other coefficient.budget: The shared work allowance.
Returns. The exact result.
Raises.
PolyError: LIMIT or CAPACITY if the computation cannot proceed.
QQ.sub¶
def sub(self, other: Self, mut budget: Budget) raises PolyError -> Self
Compute the exact difference after charging its size.
Arguments.
other: The other coefficient.budget: The shared work allowance.
Returns. The exact result.
Raises.
PolyError: LIMIT or CAPACITY if the computation cannot proceed.
QQ.mul¶
def mul(self, other: Self, mut budget: Budget) raises PolyError -> Self
Compute the exact product after charging its size.
Arguments.
other: The other coefficient.budget: The shared work allowance.
Returns. The exact result.
Raises.
PolyError: LIMIT or CAPACITY if the computation cannot proceed.
QQ.neg¶
def neg(self, mut budget: Budget) raises PolyError -> Self
Negate the coefficient after charging its size.
Arguments.
budget: The shared work allowance.
Returns. The additive inverse.
Raises.
PolyError: LIMIT if the allowance is insufficient.
QQ.inverse¶
def inverse(self, mut budget: Budget) raises PolyError -> Self
Invert a nonzero rational.
Arguments.
budget: The shared work allowance.
Returns. The reciprocal.
Raises.
PolyError: DOMAIN on zero, LIMIT or CAPACITY on work limits.
QQi¶
@fieldwise_init
struct QQi(CoefficientField)
An exact Gaussian rational coefficient a + b*i, with rational a and b.
Defined in src/polynomials/exact_complex.mojo.
| Field | Type | |
|---|---|---|
value |
ExactComplex |
The canonical apn_mojo value with two exact rational components. |
QQi.Context¶
comptime Context = NoContext
The unique field context; no precision or rounding mode is needed.
QQi.zero¶
@staticmethod
def zero(ctx: NoContext) -> Self
Construct zero.
Arguments.
ctx: The field context.
Returns. The additive identity.
QQi.one¶
@staticmethod
def one(ctx: NoContext) -> Self
Construct one.
Arguments.
ctx: The field context.
Returns. The multiplicative identity.
QQi.context¶
def context(self) -> NoContext
Report the unique field context.
Returns. The field's context.
QQi.is_zero¶
def is_zero(self) -> Bool
Test whether both exact components are zero.
Returns. Whether the value is zero.
QQi.size¶
def size(self) -> Int
Report the sum of the rational component sizes in bytes.
Returns. The positive size used by the work model.
QQi.add¶
def add(self, other: Self, mut budget: Budget) raises PolyError -> Self
Add the exact coefficients with budgeted rational arithmetic.
Arguments.
other: The other coefficient.budget: The shared work allowance.
Returns. The exact sum.
Raises.
PolyError: LIMIT or CAPACITY on work limits.
QQi.sub¶
def sub(self, other: Self, mut budget: Budget) raises PolyError -> Self
Subtract the exact coefficients with budgeted rational arithmetic.
Arguments.
other: The other coefficient.budget: The shared work allowance.
Returns. The exact difference.
Raises.
PolyError: LIMIT or CAPACITY on work limits.
QQi.mul¶
def mul(self, other: Self, mut budget: Budget) raises PolyError -> Self
Multiply exactly, charging each rational intermediate operation.
Arguments.
other: The other coefficient.budget: The shared work allowance.
Returns. The exact product.
Raises.
PolyError: LIMIT or CAPACITY on work limits.
QQi.neg¶
def neg(self, mut budget: Budget) raises PolyError -> Self
Negate both rational components after charging their sizes.
Arguments.
budget: The shared work allowance.
Returns. The exact additive inverse.
Raises.
PolyError: LIMIT if the allowance is insufficient.
QQi.inverse¶
def inverse(self, mut budget: Budget) raises PolyError -> Self
Invert a nonzero coefficient using its conjugate and squared norm.
Arguments.
budget: The shared work allowance.
Returns. The exact reciprocal (a - bi)/(aa + b*b).
Raises.
PolyError: DOMAIN on zero, LIMIT or CAPACITY on work limits.
ModInt¶
struct ModInt(CoefficientField)
A canonical residue carrying its prime modulus.
Defined in src/polynomials/coefficients.mojo.
| Field | Type | |
|---|---|---|
value |
UInt64 |
The representative in the range zero through modulus minus one. |
modulus |
UInt64 |
The validated prime modulus. |
ModInt.Context¶
comptime Context = Modulus
The field context type.
ModInt.__init__¶
def __init__(out self, value: UInt64, ctx: Modulus)
Reduce a native unsigned integer in a validated field.
Arguments.
value: The integer to reduce.ctx: A validated prime context.
ModInt.zero¶
@staticmethod
def zero(ctx: Modulus) -> Self
Construct field zero.
Arguments.
ctx: The prime field.
Returns. Its additive identity.
ModInt.one¶
@staticmethod
def one(ctx: Modulus) -> Self
Construct field one.
Arguments.
ctx: The prime field.
Returns. Its multiplicative identity.
ModInt.context¶
def context(self) -> Modulus
Recover the validated context.
Returns. The field of this residue.
ModInt.size¶
def size(self) -> Int
Report the native residue storage size.
Returns. Eight bytes.
ModInt.is_zero¶
def is_zero(self) -> Bool
Test for the additive identity.
Returns. Whether the residue is zero.
ModInt.add¶
def add(self, other: Self, mut budget: Budget) raises PolyError -> Self
Compute the modular sum.
Arguments.
other: The other residue in the same field.budget: The shared work allowance.
Returns. The reduced result.
Raises.
PolyError: DOMAIN for mixed fields or LIMIT on exhaustion.
ModInt.sub¶
def sub(self, other: Self, mut budget: Budget) raises PolyError -> Self
Compute the modular difference.
Arguments.
other: The other residue in the same field.budget: The shared work allowance.
Returns. The reduced result.
Raises.
PolyError: DOMAIN for mixed fields or LIMIT on exhaustion.
ModInt.mul¶
def mul(self, other: Self, mut budget: Budget) raises PolyError -> Self
Compute the modular product.
Arguments.
other: The other residue in the same field.budget: The shared work allowance.
Returns. The reduced result.
Raises.
PolyError: DOMAIN for mixed fields or LIMIT on exhaustion.
ModInt.neg¶
def neg(self, mut budget: Budget) raises PolyError -> Self
Compute the additive inverse in this field.
Arguments.
budget: The shared work allowance.
Returns. The canonical additive inverse.
Raises.
PolyError: LIMIT on exhaustion.
ModInt.inverse¶
def inverse(self, mut budget: Budget) raises PolyError -> Self
Invert by Fermat's theorem using budgeted repeated squaring.
Arguments.
budget: The shared work allowance.
Returns. The multiplicative inverse.
Raises.
PolyError: DOMAIN for zero or LIMIT on exhaustion.
Monomial¶
struct Monomial(Copyable, Movable, Equatable, Hashable, Writable)
A product of variables with increasing indices and positive exponents.
Defined in src/polynomials/monomial.mojo.
| Field | Type | |
|---|---|---|
pairs |
List[Tuple[Int64, UInt32]] |
The canonical pairs; callers must preserve their invariant. |
Monomial.__init__¶
def __init__(out self)
Construct the unit monomial.
Monomial.__init__¶
def __init__(out self, var pairs: List[Tuple[Int64, UInt32]], mut budget: Budget) raises PolyError
Validate and take ownership of canonical pairs.
Arguments.
pairs: Increasing indices with positive exponents.budget: The shared work allowance.
Raises.
PolyError: DOMAIN for invalid pairs or LIMIT on exhaustion.
Monomial.check_invariants¶
def check_invariants(self, mut budget: Budget) raises PolyError
Check increasing indices and positive exponents.
Arguments.
budget: The shared work allowance.
Raises.
PolyError: DOMAIN for malformed pairs or LIMIT on exhaustion.
Monomial.degree¶
def degree(self, mut budget: Budget) raises PolyError -> UInt64
Sum the exponents with overflow checks.
Arguments.
budget: The shared work allowance.
Returns. The total degree.
Raises.
PolyError: CAPACITY on overflow or LIMIT on exhaustion.
Monomial.exponent¶
def exponent(self, index: Int64, mut budget: Budget) raises PolyError -> UInt32
Find a variable's exponent by binary search.
Arguments.
index: The variable index.budget: The shared work allowance.
Returns. Its exponent, or zero if absent.
Raises.
PolyError: LIMIT on exhaustion.
Monomial.mul¶
def mul(self, other: Self, mut budget: Budget) raises PolyError -> Self
Multiply by merging exponent lists.
Arguments.
other: The other monomial.budget: The shared work allowance.
Returns. The canonical product.
Raises.
PolyError: CAPACITY on exponent overflow or LIMIT on exhaustion.
Monomial.lcm¶
def lcm(self, other: Self, mut budget: Budget) raises PolyError -> Self
Take componentwise maximum exponents.
Arguments.
other: The other monomial.budget: The shared work allowance.
Returns. The least common multiple.
Raises.
PolyError: LIMIT or CAPACITY on work limits.
Monomial.divides¶
def divides(self, other: Self, mut budget: Budget) raises PolyError -> Bool
Test componentwise exponent inclusion.
Arguments.
other: The proposed multiple.budget: The shared work allowance.
Returns. Whether this monomial divides the other.
Raises.
PolyError: LIMIT on exhaustion.
Monomial.div¶
def div(self, other: Self, mut budget: Budget) raises PolyError -> Self
Divide by a monomial exactly.
Arguments.
other: The proposed divisor.budget: The shared work allowance.
Returns. The canonical quotient.
Raises.
PolyError: DOMAIN if indivisible or LIMIT on exhaustion.
MonomialOrder¶
struct MonomialOrder(Copyable, Movable, Equatable, Writable)
An explicit variable order, or the kernel's canonical storage order.
Defined in src/polynomials/monomial.mojo.
| Field | Type | |
|---|---|---|
kind |
UInt8 |
One of KERNEL, LEX, GRLEX, or GREVLEX. |
variables |
List[Int64] |
Variables from greatest to least; empty for KERNEL. |
MonomialOrder.KERNEL¶
comptime KERNEL = UInt8(0)
Lexicographic pairs, with a proper prefix first.
MonomialOrder.LEX¶
comptime LEX = UInt8(1)
Lexicographic exponent order.
MonomialOrder.GRLEX¶
comptime GRLEX = UInt8(2)
Total degree followed by lexicographic order.
MonomialOrder.GREVLEX¶
comptime GREVLEX = UInt8(3)
Total degree followed by reversed last differing exponent.
MonomialOrder.__init__¶
def __init__(out self)
Construct the kernel storage order.
MonomialOrder.__init__¶
def __init__(out self, kind: UInt8, var variables: List[Int64], mut budget: Budget) raises PolyError
Validate and construct an explicit order.
Arguments.
kind: The order kind.variables: The variable priority list.budget: The shared work allowance.
Raises.
PolyError: DOMAIN for invalid kind or repeated variables, LIMIT on exhaustion.
MonomialOrder.validate¶
def validate(self, monomial: Monomial, mut budget: Budget) raises PolyError
Check that a canonical monomial belongs to this variable domain.
Arguments.
monomial: The monomial to validate.budget: The shared work allowance.
Raises.
PolyError: DOMAIN for unknown variables or LIMIT on exhaustion.
MonomialOrder.compare¶
def compare(self, a: Monomial, b: Monomial, mut budget: Budget) raises PolyError -> Int
Compare monomials under this order after domain validation.
Arguments.
a: The left monomial.b: The right monomial.budget: The shared work allowance.
Returns. Minus one, zero, or one.
Raises.
PolyError: DOMAIN for unknown variables, LIMIT or CAPACITY for work limits.
Term¶
@fieldwise_init
struct Term[C: CoefficientRing](Copyable, Movable, Equatable, Writable)
One monomial and its coefficient.
Parameters.
C: The coefficient ring type.
Defined in src/polynomials/sparse.mojo.
| Field | Type | |
|---|---|---|
monomial |
Monomial |
The canonical monomial. |
coefficient |
Self.C |
The coefficient in the polynomial's ring. |
SparsePoly¶
struct SparsePoly[C: CoefficientRing](Copyable, Movable, Equatable, Writable)
A canonical polynomial whose nonzero terms increase in its order.
Parameters.
C: The coefficient ring type.
Defined in src/polynomials/sparse.mojo.
| Field | Type | |
|---|---|---|
order |
MonomialOrder |
The explicit monomial order. |
ring |
Self.C.Context |
The coefficient ring context, including for the zero polynomial. |
terms |
List[Term[Self.C]] |
The increasing nonzero terms; callers must preserve canonical form. |
SparsePoly.__init__¶
def __init__(out self, var order: MonomialOrder, var ring: Self.C.Context)
Take ownership of a validated order and context to construct zero.
Arguments.
order: The owned order (no input-sized copy occurs here).ring: The owned coefficient context.
SparsePoly.zero¶
@staticmethod
def zero(order: MonomialOrder, ring: Self.C.Context, mut budget: Budget) raises PolyError -> Self
Construct zero while charging the copied order.
Arguments.
order: The monomial order.ring: The coefficient context.budget: The shared work allowance.
Returns. The zero polynomial.
Raises.
PolyError: LIMIT on exhaustion.
SparsePoly.constant¶
@staticmethod
def constant(c: Self.C, order: MonomialOrder, mut budget: Budget) raises PolyError -> Self
Construct a constant with the coefficient's context.
Arguments.
c: The constant coefficient.order: The monomial order.budget: The shared work allowance.
Returns. The canonical constant polynomial.
Raises.
PolyError: LIMIT on exhaustion.
SparsePoly.variable¶
@staticmethod
def variable(index: Int64, order: MonomialOrder, ring: Self.C.Context, mut budget: Budget) raises PolyError -> Self
Construct a variable in the specified ring.
Arguments.
index: The variable index.order: The monomial order.ring: The coefficient context.budget: The shared work allowance.
Returns. The variable polynomial.
Raises.
PolyError: DOMAIN for an unknown variable or LIMIT on exhaustion.
SparsePoly.from_terms¶
@staticmethod
def from_terms(var terms: List[Term[Self.C]], order: MonomialOrder, ring: Self.C.Context, mut budget: Budget) raises PolyError -> Self
Validate, sort, combine equal monomials, and remove zero coefficients.
Arguments.
terms: The owned unsorted terms.order: The target order.ring: The coefficient context.budget: The shared work allowance.
Returns. The normalized polynomial.
Raises.
PolyError: DOMAIN for mixed rings or invalid monomials, LIMIT or CAPACITY on work limits.
SparsePoly.is_zero¶
def is_zero(self) -> Bool
Test for the empty canonical term list.
Returns. Whether the polynomial is zero.
SparsePoly.add¶
def add(self, other: Self, mut budget: Budget) raises PolyError -> Self
Add by a linear merge of canonical terms.
Arguments.
other: The other polynomial.budget: The shared work allowance.
Returns. The canonical sum.
Raises.
PolyError: DOMAIN for incompatible operands, LIMIT or CAPACITY on work limits.
SparsePoly.sub¶
def sub(self, other: Self, mut budget: Budget) raises PolyError -> Self
Subtract by a linear merge of canonical terms.
Arguments.
other: The other polynomial.budget: The shared work allowance.
Returns. The canonical difference.
Raises.
PolyError: DOMAIN for incompatible operands, LIMIT or CAPACITY on work limits.
SparsePoly.neg¶
def neg(self, mut budget: Budget) raises PolyError -> Self
Negate all coefficients without re-sorting.
Arguments.
budget: The shared work allowance.
Returns. The additive inverse.
Raises.
PolyError: LIMIT or CAPACITY on work limits.
SparsePoly.mul¶
def mul(self, other: Self, mut budget: Budget) raises PolyError -> Self
Multiply exact terms using sorted streams for admissible orders.
Arguments.
other: The other polynomial.budget: The shared work allowance.
Returns. The canonical product.
Raises.
PolyError: DOMAIN for incompatible operands, LIMIT or CAPACITY on work limits.
SparsePoly.scale¶
def scale(self, c: Self.C, mut budget: Budget) raises PolyError -> Self
Multiply every coefficient by a scalar in the same ring.
Arguments.
c: The scalar.budget: The shared work allowance.
Returns. The scaled canonical polynomial.
Raises.
PolyError: DOMAIN for a different coefficient ring, LIMIT or CAPACITY on work limits.
SparsePoly.pow¶
def pow(self, n: UInt64, mut budget: Budget) raises PolyError -> Self
Raise to a natural power by repeated squaring, with zero power equal to one.
Squaring runs from the exponent's leading bit down, so each step squares the power so far and multiplies by the base alone; the last and largest product is a square.
Arguments.
n: The exponent.budget: The shared work allowance.
Returns. The canonical power in the same ring and order.
Raises.
PolyError: LIMIT or CAPACITY on work limits.
SparsePoly.leading¶
def leading(self, mut budget: Budget) raises PolyError -> Term[Self.C]
Copy the greatest term.
Arguments.
budget: The shared work allowance.
Returns. The leading term.
Raises.
PolyError: DOMAIN for zero or LIMIT on exhaustion.
SparsePoly.total_degree¶
def total_degree(self, mut budget: Budget) raises PolyError -> Int
Find the greatest total degree, or minus one for zero.
Arguments.
budget: The shared work allowance.
Returns. The total degree.
Raises.
PolyError: LIMIT on exhaustion or CAPACITY if the degree cannot fit Int.
SparsePoly.degree_in¶
def degree_in(self, index: Int64, mut budget: Budget) raises PolyError -> Int
Find the degree in one variable, or minus one for zero.
Arguments.
index: The variable index.budget: The shared work allowance.
Returns. The greatest exponent of that variable.
Raises.
PolyError: LIMIT on exhaustion.
SparsePoly.variables¶
def variables(self, mut budget: Budget) raises PolyError -> List[Int64]
Collect occurring variable indices in increasing order.
Arguments.
budget: The shared work allowance.
Returns. The sorted distinct indices.
Raises.
PolyError: LIMIT on exhaustion.
SparsePoly.reorder¶
def reorder(self, order: MonomialOrder, mut budget: Budget) raises PolyError -> Self
Normalize under a new order.
Arguments.
order: The target monomial order.budget: The shared work allowance.
Returns. The same polynomial in that order.
Raises.
PolyError: DOMAIN for absent variables, LIMIT or CAPACITY on work limits.
SparsePoly.check_invariants¶
def check_invariants(self, mut budget: Budget) raises PolyError
Check the ring, monomials, coefficients, and strict term order.
Arguments.
budget: The shared work allowance.
Raises.
PolyError: DOMAIN for a broken invariant or LIMIT on exhaustion.
PackedPoly¶
struct PackedPoly[C: CoefficientRing](Copyable, Movable, Equatable, Sized)
A sparse polynomial stored as one exponent word per term and a contiguous coefficient list.
The order is LEX over the variables 0..n-1 in that order. Each monomial is
one word by mixed-radix substitution with radix_i = (largest exponent of
variable i) + 1, variable 0 most significant, so word order is LEX order;
the product of the radices is below 2**62. Products, powers and exact
quotients emit their words directly, with no per-term monomial lists until
to_sparse.
Parameters.
C: The coefficient ring type.
Defined in src/polynomials/packed.mojo.
PackedPoly.__init__¶
def __init__(out self, *, var _packed: _PackedPoly[Self.C])
Wrap packed storage whose radix is the exact exponent bound.
Arguments.
_packed: Canonical packed storage.
PackedPoly.from_sparse¶
@staticmethod
def from_sparse(p: SparsePoly[Self.C], mut budget: Budget) raises PolyError -> Optional[Self]
Pack a sparse polynomial, or return no value when it does not fit.
Arguments.
p: A polynomial in LEX order over the variables 0..n-1 in that order.budget: The shared work allowance.
Returns. The packed polynomial, or None for another order or a key range of 2**62 or more.
Raises.
PolyError: LIMIT or CAPACITY on work limits.
PackedPoly.to_sparse¶
def to_sparse(self, mut budget: Budget) raises PolyError -> SparsePoly[Self.C]
Materialize the canonical sparse form.
Arguments.
budget: The shared work allowance.
Returns. The same polynomial as a SparsePoly.
Raises.
PolyError: LIMIT or CAPACITY on work limits.
PackedPoly.is_zero¶
def is_zero(self) -> Bool
Report whether the polynomial has no terms.
Returns. Whether the polynomial is zero.
PackedPoly holds a LEX polynomial over the variables 0..n-1 as one exponent
word per term and a contiguous coefficient list, so large products and powers
build no per-term monomial lists. Its radices are the exact exponent bounds:
leading forms multiply without cancellation over an integral domain, so a
product, power or quotient knows its radix before it is computed.
packed_mul and packed_pow return no value when the result's key range would
reach 2**62; packed_divide_exact returns no value when the divisor does not
divide, as divide_exact does.
Convert with to_sparse for operations that PackedPoly does not provide.
packed_mul¶
def packed_mul[C: CoefficientRing](a: PackedPoly[C], b: PackedPoly[C], mut budget: Budget) raises PolyError -> Optional[PackedPoly[C]]
Multiply packed polynomials, keeping the product packed.
ZZ coefficients of at most 63 bits and prime-field residues take the packed
product kernel; other operands multiply as SparsePoly.mul does and are
packed again.
Parameters.
C: The coefficient ring type.
Arguments.
a: The left factor.b: The right factor in the same ring and order.budget: The shared work allowance.
Returns. The product, or None when its key range would reach 2**62.
Raises.
PolyError: DOMAIN for incompatible operands, LIMIT or CAPACITY on work limits.
Defined in src/polynomials/packed.mojo.
packed_pow¶
def packed_pow[C: CoefficientRing](f: PackedPoly[C], n: UInt64, mut budget: Budget) raises PolyError -> Optional[PackedPoly[C]]
Raise a packed polynomial to a natural power, keeping the power packed.
Few-term ZZ bases take the power recurrence where SparsePoly.pow would;
otherwise the power squares from the exponent's leading bit down with
packed products. Zero power equals one.
Parameters.
C: The coefficient ring type.
Arguments.
f: The base.n: The exponent.budget: The shared work allowance.
Returns. The power, or None when its key range would reach 2**62.
Raises.
PolyError: LIMIT or CAPACITY on work limits.
Defined in src/polynomials/packed.mojo.
packed_divide_exact¶
def packed_divide_exact[C: CoefficientRing](f: PackedPoly[C], g: PackedPoly[C], mut budget: Budget) raises PolyError -> Optional[PackedPoly[C]]
Return the exact packed quotient f / g, or no value when g does not divide f.
ZZ divisors with coefficients of at most 63 bits and prime-field divisors
take chunked packed division; other operands divide as divide_exact
does. The quotient is packed in its own radix.
Parameters.
C: ZZ or a coefficient field.
Arguments.
f: The dividend.g: The nonzero divisor in the same ring and order.budget: The shared work allowance.
Returns. The quotient if g divides f, otherwise None.
Raises.
PolyError: DOMAIN for invalid operands, UNSUPPORTED for another ring, LIMIT or CAPACITY on work limits.
Defined in src/polynomials/packed.mojo.
CoefficientBuffer¶
struct CoefficientBuffer[T: Copyable & Deinitable](Copyable, Movable, Sized, Iterable, Equatable where conforms_to(T, Equatable), Writable where conforms_to(T, Writable))
Ascending coefficients in contiguous or chunked owned storage.
Copies own independent storage. Polynomial arrays share their enclosing immutable polynomial handle instead. Indexing never flattens chunks.
Parameters.
T: The coefficient type.
Defined in src/polynomials/coefficient_buffer.mojo.
CoefficientBuffer.IteratorType¶
comptime IteratorType[iterable_mut: Bool, //, iterable_origin: Origin[mut=iterable_mut]]: Iterator = _BufferIterator[Self.T, ImmOrigin(iterable_origin)]
The iterator that borrows the owner and yields independent values.
Parameters.
iterable_mut: Whether the source origin is mutable.iterable_origin: The source lifetime.
CoefficientBuffer.__init__¶
def __init__(out self)
Construct an empty contiguous buffer.
CoefficientBuffer.__init__¶
@implicit
def __init__(out self, var values: List[Self.T])
Adopt a list without copying its coefficient storage.
Arguments.
values: The owned ascending coefficients.
CoefficientBuffer.__init__¶
def __init__(out self, *, copy: Self)
Copy coefficients into independently mutable storage.
Arguments.
copy: The source buffer.
CoefficientBuffer.write_to¶
def write_to[W: Writer](self, mut writer: W) where conforms_to(Self.T, Writable)
Write the coefficients in list notation.
Parameters.
W: The output writer type.
Arguments.
writer: The destination receiving the representation.
CoefficientBuffer.capacity¶
def capacity(self) -> Int
Return the total allocated coefficient capacity.
Returns. Initialized and spare slots, excluding chunk metadata.
CoefficientBuffer.is_contiguous¶
def is_contiguous(self) -> Bool
Test whether all coefficients occupy one list.
Returns. True for contiguous storage, including an empty buffer.
CoefficientBuffer.clear¶
def clear(mut self)
Release all coefficients and chunk metadata, leaving an empty buffer.
CoefficientBuffer.pop¶
def pop(mut self) -> Self.T
Remove and return the final coefficient.
Returns. The owned coefficient. The buffer must be nonempty.
CoefficientBuffer.append¶
def append(mut self, var value: Self.T)
Append a coefficient, preserving the current storage form.
Arguments.
value: The owned coefficient. Callers must charge growth first.
CoefficientBuffer.to_list¶
def to_list(self, mut budget: Budget) raises PolyError -> List[Self.T]
Copy into a mutable contiguous list with explicit allocation work.
Arguments.
budget: The shared work allowance for allocation and handle copies.
Returns. An independent list in coefficient order.
Raises.
PolyError: LIMIT or CAPACITY before unbudgeted work or allocation.
The buffer owns a contiguous list or bounded chunks. Indexing borrows entries;
iteration yields independent coefficient values without flattening the buffer.
copy() creates independent storage;
to_list(budget) explicitly copies into a contiguous list. See
dense coefficient storage for the
buffer's operations.
DensePoly¶
struct DensePoly[C: CoefficientRing](Copyable, Movable, Equatable, Writable)
A canonical univariate polynomial with coefficients in ascending degree.
Parameters.
C: The coefficient ring type.
Defined in src/polynomials/dense.mojo.
| Field | Type | |
|---|---|---|
variable |
Int64 |
The variable index, retained even for constants and zero. |
ring |
Self.C.Context |
The coefficient ring context. |
coefficients |
CoefficientBuffer[Self.C] |
Owned contiguous or chunked coefficients, empty for zero and otherwise ending in a nonzero value. |
DensePoly.__init__¶
def __init__(out self, variable: Int64, var ring: Self.C.Context)
Construct zero by taking ownership of its context.
Arguments.
variable: The retained variable index.ring: The owned ring context.
DensePoly.from_coefficients¶
@staticmethod
def from_coefficients(variable: Int64, ring: Self.C.Context, var coefficients: List[Self.C], mut budget: Budget) raises PolyError -> Self
Validate the ring and trim trailing zero coefficients.
Arguments.
variable: The variable index.ring: The coefficient context.coefficients: The owned ascending coefficient vector.budget: The shared work allowance.
Returns. The canonical dense polynomial.
Raises.
PolyError: DOMAIN for mixed contexts or LIMIT on exhaustion.
DensePoly.from_coefficients¶
@staticmethod
def from_coefficients(variable: Int64, ring: Self.C.Context, var coefficients: CoefficientBuffer[Self.C], mut budget: Budget) raises PolyError -> Self
Validate the ring and trim trailing zero coefficients.
Arguments.
variable: The variable index.ring: The coefficient context.coefficients: The owned ascending coefficient vector.budget: The shared work allowance.
Returns. The canonical dense polynomial.
Raises.
PolyError: DOMAIN for mixed contexts or LIMIT on exhaustion.
DensePoly.karatsuba_threshold¶
@staticmethod
def karatsuba_threshold() -> Int
Report the measured crossover for this coefficient type.
Returns. 64 coefficients for ModInt, otherwise 32.
DensePoly.degree¶
def degree(self) -> Int
Return the stored degree, or minus one for zero.
Returns. The degree in constant time.
DensePoly.is_zero¶
def is_zero(self) -> Bool
Test whether the coefficient vector is empty.
Returns. Whether the polynomial is zero.
DensePoly.add¶
def add(self, other: Self, mut budget: Budget) raises PolyError -> Self
Add coefficient vectors in the same ring and variable.
Arguments.
other: The other polynomial.budget: The shared work allowance.
Returns. The canonical sum.
Raises.
PolyError: DOMAIN for incompatible operands, LIMIT or CAPACITY on work limits.
DensePoly.sub¶
def sub(self, other: Self, mut budget: Budget) raises PolyError -> Self
Subtract coefficient vectors in the same ring and variable.
Arguments.
other: The other polynomial.budget: The shared work allowance.
Returns. The canonical difference.
Raises.
PolyError: DOMAIN for incompatible operands, LIMIT or CAPACITY on work limits.
DensePoly.neg¶
def neg(self, mut budget: Budget) raises PolyError -> Self
Negate the coefficient vector.
Arguments.
budget: The shared work allowance.
Returns. The additive inverse.
Raises.
PolyError: LIMIT or CAPACITY on work limits.
DensePoly.scale¶
def scale(self, c: Self.C, mut budget: Budget) raises PolyError -> Self
Multiply all coefficients by a scalar.
Arguments.
c: The scalar in the same ring.budget: The shared work allowance.
Returns. The scaled polynomial.
Raises.
PolyError: DOMAIN for a mixed ring, LIMIT or CAPACITY on work limits.
DensePoly.mul_schoolbook¶
def mul_schoolbook(self, other: Self, mut budget: Budget) raises PolyError -> Self
Multiply by direct convolution for testing and measurements.
Arguments.
other: The other polynomial.budget: The shared work allowance.
Returns. The canonical product.
Raises.
PolyError: DOMAIN for incompatible operands, LIMIT or CAPACITY on work limits.
DensePoly.mul¶
def mul(self, other: Self, mut budget: Budget) raises PolyError -> Self
Multiply with schoolbook or an explicit-stack Karatsuba traversal.
Arguments.
other: The other polynomial.budget: The shared work allowance.
Returns. The canonical product.
Raises.
PolyError: DOMAIN for incompatible operands, LIMIT or CAPACITY on work limits.
DensePoly.pow¶
def pow(self, n: UInt64, mut budget: Budget) raises PolyError -> Self
Raise to a natural power by repeated squaring.
Arguments.
n: The exponent.budget: The shared work allowance.
Returns. The power; exponent zero gives one in the same ring and variable.
Raises.
PolyError: LIMIT or CAPACITY on work limits.
DensePoly.to_sparse¶
def to_sparse(self, order: MonomialOrder, mut budget: Budget) raises PolyError -> SparsePoly[Self.C]
Convert to canonical sparse form under an explicit order.
Arguments.
order: The sparse monomial order.budget: The shared work allowance.
Returns. The sparse polynomial in the same coefficient ring.
Raises.
PolyError: DOMAIN for an unknown variable, CAPACITY for exponent overflow, LIMIT on exhaustion.
DensePoly.from_sparse¶
@staticmethod
def from_sparse(p: SparsePoly[Self.C], mut budget: Budget, *, variable: Optional[Int64] = None) raises PolyError -> Self
Convert a univariate sparse polynomial, optionally selecting its variable.
Arguments.
p: The sparse polynomial.budget: The shared work allowance.variable: The variable to retain; inferred from nonconstant terms, otherwise zero.
Returns. The dense polynomial in the same coefficient ring.
Raises.
PolyError: DOMAIN for another variable, LIMIT or CAPACITY on work limits.
DensePoly.check_invariants¶
def check_invariants(self, mut budget: Budget) raises PolyError
Check ring consistency and the nonzero leading coefficient.
Arguments.
budget: The shared work allowance.
Raises.
PolyError: DOMAIN for an invalid representation or LIMIT on exhaustion.
KARATSUBA_THRESHOLD¶
comptime KARATSUBA_THRESHOLD = 32
The measured Karatsuba threshold for arbitrary-precision coefficients.
Defined in src/polynomials/dense.mojo.
evaluate¶
def evaluate[C: CoefficientRing](p: SparsePoly[C], point: List[Tuple[Int64, C]], mut budget: Budget) raises PolyError -> C
Evaluate by nested sparse Horner schemes using an explicit work stack.
Parameters.
C: The coefficient ring type.
Arguments.
p: The polynomial.point: Distinct variable indices and values in the same ring.budget: The shared work allowance.
Returns. The exact value in the coefficient ring.
Raises.
PolyError: DOMAIN for missing or repeated variables or mixed rings, LIMIT or CAPACITY on work limits.
Defined in src/polynomials/evaluate.mojo.
evaluate_dense¶
def evaluate_dense[C: CoefficientRing](p: DensePoly[C], x: C, mut budget: Budget) raises PolyError -> C
Evaluate a dense polynomial by Horner's rule.
Parameters.
C: The coefficient ring type.
Arguments.
p: The polynomial.x: The value in the coefficient ring.budget: The shared work allowance.
Returns. The exact value.
Raises.
PolyError: DOMAIN for another ring, LIMIT or CAPACITY on work limits.
Defined in src/polynomials/evaluate.mojo.
substitute¶
def substitute[C: CoefficientRing](p: SparsePoly[C], index: Int64, q: SparsePoly[C], mut budget: Budget) raises PolyError -> SparsePoly[C]
Substitute a polynomial for one variable.
Parameters.
C: The coefficient ring type.
Arguments.
p: The source polynomial.index: The variable to replace.q: The replacement in the same ring and order.budget: The shared work allowance.
Returns. The canonical substituted polynomial.
Raises.
PolyError: DOMAIN for incompatible operands, LIMIT or CAPACITY on work limits.
Defined in src/polynomials/evaluate.mojo.
derivative¶
def derivative[C: CoefficientRing](p: SparsePoly[C], index: Int64, mut budget: Budget) raises PolyError -> SparsePoly[C]
Differentiate formally in one variable in any coefficient ring.
Parameters.
C: The coefficient ring type.
Arguments.
p: The polynomial.index: The variable to differentiate.budget: The shared work allowance.
Returns. The canonical formal derivative.
Raises.
PolyError: LIMIT or CAPACITY on work limits.
Defined in src/polynomials/evaluate.mojo.
to_kernel_bytes¶
def to_kernel_bytes(p: SparsePoly[QQ], mut budget: Budget) raises PolyError -> List[UInt8]
Encode a polynomial as a canonical kernel literal.
Arguments.
p: The rational polynomial, in any monomial order.budget: The shared work allowance.
Returns. The canonical little-endian payload.
Raises.
PolyError: ENCODING for zero or one, DOMAIN for broken invariants, CAPACITY beyond the kernel ceiling, LIMIT on exhaustion.
Defined in src/polynomials/codec.mojo.
from_kernel_bytes¶
def from_kernel_bytes(data: Span[UInt8, _], mut budget: Budget) raises PolyError -> SparsePoly[QQ]
Decode canonical kernel bytes without repairing malformed input.
Arguments.
data: The byte payload.budget: The shared work allowance.
Returns. The canonical polynomial in KERNEL order.
Raises.
PolyError: ENCODING for malformed or noncanonical bytes, CAPACITY beyond the size ceiling, LIMIT on exhaustion.
Defined in src/polynomials/codec.mojo.
MAX_KERNEL_BYTES¶
comptime MAX_KERNEL_BYTES = 1048576
The kernel's one-mebibyte literal size ceiling.
Defined in src/polynomials/codec.mojo.