Jacobian exposes a small native mathematical API under jacobian.math. Native
functions call the domain kernels directly and are independent of MCP.
from fractions import Fraction
import sympy
from jacobian.math import matrices, polynomials
from jacobian.math.number_theory import arithmetic
half = arithmetic.sum_rationals(Fraction(1, 3), Fraction(1, 6))
matrix = sympy.Matrix([[1, 2], [3, 4]])
determinant = matrices.determinant(matrix)The polynomial expression normalizer is available natively as
polynomials.normalize_polynomial_expression. It accepts the same typed
PolynomialExpressionSource value used by the native API; the catalog's wire
PolynomialExpressionNormalizeRequest is unwrapped in _tools.py before the
same function runs. It never parses or evaluates caller-authored source
strings.
Finite-dimensional Lie algebras expose exact operations from
jacobian.math.lie_algebras. The adjoint representation, Killing form,
derived and lower-central series, centralizers, and generated subalgebras and
ideals use the algebra's ordered basis and exact structure constants. The
upper central series returns subspaces on that basis, beginning with zero; it
reaches the whole algebra exactly when the algebra is nilpotent and otherwise
stops at its first stable proper term.
Each public jacobian.math.<domain> module declares its supported names in
__all__; that is the authoritative native API. Functions accept domain values
or a maintained backend type when it already carries the complete mathematical
meaning. Private backend modules perform lazy conversions and calls to SymPy,
NetworkX, FLINT, or Z3.
Public import paths follow mathematical ownership. Large owners expose
recognizable subdivisions, for example
jacobian.math.graphs.chip_firing or
jacobian.math.polynomials.interpolation; backend and transport structure does
not appear in the public path. When a pre-stable package is folded into its
canonical owner, callers move to the owner path in the same release. The old
path is removed rather than retained as a forwarding package, and operation IDs
and wire schemas remain unchanged unless their mathematical contract changes
independently.
Native values are mathematical values rather than wire envelopes. The architecture responsibility map distinguishes values, operation arguments, wire requests, and execution context. The native API can be broader than the published catalog: exporting a useful function does not require publishing another math tool. Native and MCP calls use the same domain-owned request admission, kernel path, canonical result construction, and typed outcome semantics. Most native functions simply normalize and validate their input, perform the computation, and return a canonical value. An operation uses a distinct execution plan only when admission derives information that its kernel or result construction needs to reuse. The MCP path adds only wire parsing and the final transport projection; native code must not inherit MCP byte/depth/echo policy. Intrinsic structural and computational limits still apply independently of the calling surface; sharing a numeric threshold does not make a transport limit mathematical.
This parity includes bounded execution. Deadlines, cancellation checkpoints,
deterministic work accounting, worker containment, and backend-failure
classification are transport-independent library behavior. A native call
receives the canonical result or the same typed timeout, cancellation, resource,
backend-availability, or backend-failure exception that a delivery adapter
would translate. It does not receive ToolError, an MCP task handle, protocol
progress metadata, or a CLI exit code.
The library execution context may carry an optional progress sink supplied by a caller. Progress reports only real completed units or phases and does not change the function's result type. MCP may connect that sink to protocol notifications; native applications may connect it to their own UI or leave it absent. Durable job identity, persistence, polling, authorization, and result retention belong to a serving runtime rather than the native mathematical API.
An MCP operation parses one wire request before calling the shared domain admission function. Native callers call that domain function directly rather than constructing a wire Pydantic model. Native and wire parity tests should assert equal exact results and typed outcomes, and should document any difference as an explicit transport-only constraint.
Every native callable that backs a public operation is itself an admission
boundary. Python type annotations and Pydantic field declarations do not
validate values supplied directly to that callable. The implementation must
validate strict runtime types, shape, axes, and domain; enforce the same
owner-defined work and intermediate limits; and enforce the same exact-output
or materialization bounds before indexing, unpacking, backend work, or result
allocation. Equivalent native and catalog invocations must use the same owner
admission helper. Expected invalid native values, shapes, axes, and dimensions
raise OperationDomainValidationError or the operation's declared subtype
while preserving its stable owner code and domain/resource classification. Use
OperationResourceAdmissionError when the operation contract distinguishes
execution-envelope refusal from other domain rejections. Neither path may leak
helper ValueError, IndexError, tuple-unpacking errors, or Pydantic
validation exceptions.
Legacy native-only helpers that have not yet been audited may violate this boundary; each such violation is migration debt. Audit and repair them before publishing them as public-operation implementations.
Pydantic request models are transport contracts, not containers for hidden
execution state. They may enforce typed shape, canonical representation, and
cheap intrinsic cross-field consistency. They must not store admission plans in
PrivateAttr fields or perform backend calls, candidate enumeration,
algorithm selection, or result-work planning in validators. Those steps belong
to the native function after wire-to-domain conversion.
The interoperability contract distinguishes shared values, meaningful refinements, representation transforms, and changes of parent. It also defines when conversions belong only in the native API and what serialization does and does not establish.
Reuse the owner-defined public type for the same mathematical value and
representation, normally from the domain's values.py. Producers return that
type and consumers accept it directly. Distinct storage or basis variants need
explicit semantics and conversions, not operation-specific copies of the same
fields. Request and result models may contain a canonical value alongside
genuine operation parameters, but must not reproduce it as a parallel set of
fields.
Finite probability uses this same rule. FiniteJointTable,
MutualInformationResult, and the asymmetric local-lemma witness and result
values are the same canonical types in native calls and JSON transport. Their
rational fields use CanonicalRational; use from_fraction(...) and
as_fraction() for explicit scalar conversion. Mutual-information results
retain both ordered label axes, including rows and columns of zero mass.
Joint-table normalization and local-lemma result-growth admission run when the
operation executes, while parsing retains structure and authored claims.
all_terminal_reliability(graph, probability) still accepts a native Fraction
probability and returns the same AllTerminalReliabilityResult as MCP, with
canonical rational probability fields.
For example, the finite-field API follows this ownership chain:
finite_field(...) -> FiniteFieldPresentation
FiniteDimensionalSubspace(...) -> FiniteDimensionalSubspace
linear_map_rank(subspace, direction) accepts that FiniteDimensionalSubspace
The same rule applies after serialization: a producer's canonical value must pass through the consumer's typed boundary without the caller reconstructing its field presentation, axes, ambient dimension, normalization, or other mathematical context. Empty and degenerate values retain that context too.
Integer encoding does not authorize flattening that value. A dynamics request
continues to accept RationalPolynomial or FinitePolynomialMap, rather than
separate coefficient and field parameters; only their integer leaves serialize
as decimal strings. This preserves direct producer-to-consumer composition and
keeps parent, variable, and domain/codomain data available to admission.
For example, a QQ matrix with row_count=0, column_count=3, and
entries=[] is a map from a three-dimensional space to the zero space.
Its dimensions survive dense/sparse conversion, backend conversion, and JSON
round trips. An empty quadratic matrix additionally supplies its radicand;
an embedded number-field matrix retains its embedding. Never infer a parent
from an entry when there may be no entries.
Likewise, FiniteDimensionalSubspace supplies presentation, row_axis, and
column_axis independently of its basis. An empty basis and empty
basis_axis.labels represent the zero subspace in that ambient matrix space;
scalar restriction retains the target axis even when its matrix has zero
columns. Nonempty basis matrices must match the declared parent and axes.
Consumers establish the basis's independence at admission, not during parsing.
Migrated integer fields hold Python int values, not decimal text. The same
model owns both native computation and JSON encoding:
from jacobian.math.matrices.values import IntegerMatrix
matrix = IntegerMatrix(entries=((2**53 + 1,),))
assert matrix.entries[0][0] == 2**53 + 1
assert matrix.model_dump()["entries"] == ((2**53 + 1,),)
assert matrix.model_dump(mode="json")["entries"] == [["9007199254740993"]]
assert IntegerMatrix.model_validate_json(matrix.model_dump_json()) == matrixUse native integers in mathematical tests. Test malformed decimal strings and
serialization separately through model_validate_json(). Passing a decoded
JSON dictionary to model_validate() selects the native path and does not
decode its strings. This encoding choice does not increase an operation's
work or output limits. See the migration requirements
for the remaining legacy-field and compound-rational scope.
The abelian operations use AbelianPresentation(invariant_factors=(2, 12)).
Its invariant factors and all element coordinates are exact Python integers.
model_dump() preserves them; model_dump(mode="json") and
model_dump_json() encode them as canonical decimal strings.
model_validate_json() validates and decodes that encoding back into the same
value type. Native construction does not accept numeric strings, and JSON
decoding does not accept numbers for these fields.
Finite based chain complexes and filtered chain data use Python int and
fractions.Fraction coefficients. Their JSON representation uses canonical
integer strings and reduced rational strings such as "-3/7"; read those
wire values with model_validate_json(). A ChainMapValue binds its
degreewise matrices to exact source and target ChainComplexValue endpoints;
optional basis labels bind named axes. Its shape and coefficient grammar are
structural, while consumers that rely on the chain-map equation replay that
relation at their own admitted boundary. Differential matrices, chain maps,
mapping cones, tensor products, filtered subspaces, and producer results retain
the same native coefficient types in Python.
reduce_element(group, coordinates) returns an ElementReduceResult retaining
the source coordinates and an AbelianElement with canonical coordinates.
element_order and elements_equal retain their source group and canonical
elements in their result values. generated_subgroup and quotient_group
similarly return parent-bound AbelianSubgroup values. Different presentations
are not implicitly identified merely because they present isomorphic groups.
normalize_presentation(source) retains the source cyclic-factor presentation
and returns an invariant-factor AbelianPresentation; quotient computation
returns an abstract AbelianQuotient. Neither result supplies a coordinate
isomorphism or quotient projection. Group order and exponent are mathematical
result fields, not duplicated serialized claims. Work bounds are checked at
native operation admission. Reduction accepts exact Python integers natively
and canonical decimal-string coordinates through JSON, with a 32,768-digit
encoding guard in both paths.
The abelian Smith operations still retain a 4,096 group-order admission cap; do not interpret canonical integer encoding as evidence that this separate scale limitation has been repaired. Other finite-group and character operations retain their own bounded coordinate contracts. See exact integer migrations and large-group admission for the required repairs.
A carrier's structural size limit is not an operation's admission limit. The QQ matrix carrier supports axes through 4,096 so it can represent the eventual hitting operation's state space. Each consumer separately admits its work, intermediate growth, and result size; this does not make arbitrary dense 4,096-by-4,096 computations admissible.
Deserialization checks structure and context, not mathematical claims such as primality, lattice rank, an order relation, or a functional graph's cycles. Operations check the properties they rely on during admission. A parsed result is still a claim from its source; serialization does not turn it into an independently verified certificate. Do not add certificates unless a consumer needs a concrete mathematical witness or checking relation.
The native surface also retains useful deterministic helpers intentionally
excluded from math.find, including classical combinatorial numbers, basic
formal-series transformations, Young-diagram projections, graph transforms and
decomposition projections, DFA complement, and finite-metric balls. Their
absence from the public operation catalog is deliberate: native availability
does not create a distinct agent discovery intent.
Python package dependencies install with Jacobian. Singular and QEPCAD are
optional system runtimes for a small declared subset of operations; ordinary
Python calls and imports do not require them. Use
from jacobian.backends import check_backend and check_backend("singular")
(or "qepcad") to inspect the current environment. Calls that need an unavailable
runtime raise jacobian.backends.BackendUnavailableError, with backend,
required_version, detail, and installation attributes. No runtime is
automatically installed. See backend requirements
for versions, operation coverage, and deployment instructions.
jacobian.math.number_theory.numerical_semigroups.relation_binomials is a
native-only conversion of supplied homogeneous factorization relations to
signed monomial pairs. Its RelationBinomialsResult retains the ordered
minimal-generator axis. Pass that canonical, strictly increasing axis
explicitly; the helper does not reorder generators or reinterpret relation
coordinates. The axis has at most 20 generators, each at most 500, bounding
the check that the supplied axis is minimal. Empty, redundant, and incomplete
relation families are valid inputs. Their conversion establishes neither generation of the toric kernel
nor minimality of a presentation.
For example, given a result from
number_theory.numerical_semigroup.minimal_presentation.compute, pass its
minimal_generators and relations to relation_binomials. Native callers can
construct individual pairs with the exported MinimalPresentationRelation;
the class name does not certify that a supplied family is a presentation.
The pre-stable public operation
number_theory.numerical_semigroup.presentation_binomials.compute and its
request/result names were removed. It only projected relation coordinates to
fixed-coefficient monomials and did not validate a presentation. There is no
replacement catalog alias: use the native conversion for this projection, or
retain the existing minimal-presentation operation when the presentation itself
is required.