API reference
All exported functions, grouped by task. Only user-facing functions are listed; backend helpers are internal.
Grothendieck–Witt classes
Constructing stable and unstable classes and combining them with the Grothendieck–Witt ring operations.
MotivicHomotopy.GWClass — Type
GWClass(M)The isomorphism class of the nondegenerate symmetric bilinear form with Gram matrix M, as an element of the Grothendieck–Witt ring $\text{GW}(k)$ of a field (or finite étale algebra over a field) of characteristic not 2.
Given a basis $e_1, …, e_n$ of a $k$-vector space $V$, a symmetric bilinear form $β : V × V → k$ is encoded by its Gram matrix $(β(e_i, e_j))_{i,j}$; a change of basis replaces the Gram matrix by a congruent one, so a symmetric matrix determines the form up to congruence. The constructor checks that M is symmetric, nondegenerate, and defined over a supported coefficient ring, and errors otherwise.
Supported Gram matrices:
- an Oscar matrix (
MatElem) overQQ, a finite field of odd characteristic, or a finite étale algebra (a zero-dimensionalMPolyQuoRingwith nondegenerate trace form); - a plain Julia matrix of real or complex numbers, stored as
Matrix{Float64}orMatrix{ComplexF64}— these play the role of forms over $\mathbb{R}$ and $\mathbb{C}$.
Equality == compares Gram matrices literally (same base ring, same entries). Mathematical equality in $\text{GW}(k)$ is tested with is_isomorphic_form.
The Gram matrix, coefficient algebra, and base field are recovered with gw_matrix, gw_algebra, and gw_base_field; a diagonal representative with diagonal_class. Further invariants: form_rank, form_signature, integral_discriminant, hasse_witt_invariant, anisotropic_dimension, anisotropic_part, sum_decomposition, is_isotropic_form, is_anisotropic_form.
Examples
julia> beta = GWClass(QQ[2 1; 1 3])
[2 1]
[1 3]
julia> gw_matrix(beta)
[2 1]
[1 3]
julia> gw_base_field(beta)
Rational field
julia> GWClass([0.0 1.0; 1.0 0.0]) # a form over the real numbers
2×2 Matrix{Float64}:
0.0 1.0
1.0 0.0MotivicHomotopy.gw_algebra — Method
gw_algebra(beta)The coefficient algebra over which a GWClass or GWuClass is defined — a field or a finite étale algebra over a field. Over $\mathbb{R}$ / $\mathbb{C}$ (float-backed classes) this returns the type Float64 / ComplexF64.
Examples
julia> gw_algebra(GWClass(QQ[2 1; 1 3]))
Rational fieldSee also gw_base_field, gw_matrix.
MotivicHomotopy.gw_base_field — Method
gw_base_field(beta)The base field of a GWClass or GWuClass, when the class is defined over a field. For a class over an étale algebra this checks that the zero ideal is prime (i.e. the algebra is a field) and errors otherwise; for a class that already lives over QQ or a finite field it returns that field. Over $\mathbb{R}$ / $\mathbb{C}$ (float-backed classes) it returns the type Float64 / ComplexF64.
Examples
julia> gw_base_field(GWClass(QQ[2 1; 1 3]))
Rational fieldSee also gw_algebra.
MotivicHomotopy.gw_direct_sum — Method
gw_direct_sum(beta, gamma)The direct (block) sum of two classes over the same base field — addition in the Grothendieck–Witt ring. For two GWClass inputs the result has the block-diagonal Gram matrix; for two GWuClass inputs the Gram matrices are block-summed and the scalars multiplied. beta + gamma is an alias.
Examples
julia> beta1 = GWClass(QQ[1 2; 2 3]);
julia> beta2 = GWClass(QQ[3 4; 4 5]);
julia> gw_direct_sum(beta1, beta2)
[1 2 0 0]
[2 3 0 0]
[0 0 3 4]
[0 0 4 5]
julia> gw_direct_sum(GWuClass(QQ[2 1; 1 2]), GWuClass(QQ[1 2; 2 6]))
([2 1 0 0; 1 2 0 0; 0 0 1 2; 0 0 2 6], 6)See also gw_tensor_product, divisorial_sum.
MotivicHomotopy.gw_matrix — Method
gw_matrix(beta)The Gram matrix of a GWClass or GWuClass: a symmetric matrix over the coefficient algebra of the class (MatElem for exact fields and étale algebras, Matrix{Float64} / Matrix{ComplexF64} over $\mathbb{R}$ / $\mathbb{C}$).
Examples
julia> beta = GWClass(QQ[2 1; 1 3]);
julia> gw_matrix(beta)
[2 1]
[1 3]See also gw_scalar, gw_algebra, gw_base_field.
MotivicHomotopy.gw_tensor_product — Method
gw_tensor_product(beta, gamma)The tensor product of two GWClasses over the same base field — multiplication in the Grothendieck–Witt ring. The resulting Gram matrix is the Kronecker product of the two Gram matrices. beta * gamma is an alias.
Examples
julia> beta1 = GWClass(QQ[1 2; 2 3]);
julia> beta2 = GWClass(QQ[3 4; 4 5]);
julia> gw_tensor_product(beta1, beta2)
[3 4 6 8]
[4 5 8 10]
[6 8 9 12]
[8 10 12 15]See also gw_direct_sum.
MotivicHomotopy.GWuClass — Type
GWuClass(M)
GWuClass(M, a)
GWuClass(beta)
GWuClass(beta, a)An element of the unstable Grothendieck–Witt group $\text{GW}^u(k) = \text{GW}(k) ×_{k^×/(k^×)^2} k^×$ of a field (or finite étale algebra) of characteristic not 2: the data of a GWClass together with a nonzero scalar whose square class agrees with the determinant of the Gram matrix.
The constructor takes a symmetric matrix M (or an existing GWClass beta) and optionally a scalar a; when the scalar is omitted, the determinant of the Gram matrix is used. Over $\mathbb{Q}$, $\mathbb{R}$, and finite fields of odd characteristic the constructor verifies that a agrees with the determinant up to squares and errors otherwise. Over an arbitrary finite étale algebra this verification is not possible; any nonzero scalar is accepted and a warning is printed when it differs from the determinant — the user must check the square-class condition by hand.
Accessors: gw_matrix, gw_scalar, gw_algebra, gw_base_field, and stable_part for the underlying $\text{GW}(k)$-class. Operations: gw_direct_sum (alias +) and divisorial_sum. Equality == compares the Gram matrix and the scalar literally; use is_isomorphic_form for equality in $\text{GW}^u(k)$.
Examples
julia> M = QQ[0 1; 1 0];
julia> alpha = GWuClass(M, -4)
([0 1; 1 0], -4)
julia> gw_scalar(alpha)
-4
julia> GWuClass(M) # scalar defaults to det(M)
([0 1; 1 0], -1)
julia> GWuClass(GWClass(M), -9)
([0 1; 1 0], -9)MotivicHomotopy.divisorial_sum — Method
divisorial_sum(class_list, root_list)The divisorial sum of a list of unstable local degrees with respect to the divisor of roots at which they were computed.
For a pointed rational function $f/g : \mathbb{P}^1_k → \mathbb{P}^1_k$ with zeros $r_1, …, r_n$ and unstable local $\mathbb{A}^1$-degrees $β_1, …, β_n$ at those zeros, the global unstable degree is not the gw_direct_sum of the local degrees: the local-to-global formula of Igieobo et al. [I+24] weights the sum by the configuration of the zeros. Concretely, the Gram matrices are block-summed while the scalar picks up the factor $∏_{i<j} (r_i - r_j)^{2 m_i m_j}$ (with $m_i$ the rank of $β_i$) on top of the product of the scalars.
class_list is a vector of GWuClasses over a common base field and root_list the corresponding vector of base-field elements.
Examples
The local degrees of $(x^2 + x - 2)/(3x + 5)$ at its zeros −2 and 1 are $(⟨1/3⟩, 1/3)$ and $(⟨8/3⟩, 8/3)$; their divisorial sum recovers the global unstable degree:
julia> alpha = GWuClass(matrix(QQ, 1, 1, [1//3]));
julia> beta = GWuClass(matrix(QQ, 1, 1, [8//3]));
julia> divisorial_sum([alpha, beta], [-2, 1])
([1//3 0; 0 8//3], 8)References
- [I+24] J. Igieobo et al., Motivic configurations on the line, Advances in Mathematics 482 (2025), 110637.
See also global_unstable_A1_degree, local_unstable_A1_degree.
MotivicHomotopy.gw_scalar — Method
gw_scalar(beta::GWuClass)The $k^×$-factor of an unstable Grothendieck–Witt class: the nonzero scalar that, together with the Gram matrix, determines the class. It is an element of the coefficient algebra of beta.
Examples
julia> gw_scalar(GWuClass(QQ[0 1; 1 0], -4))
-4See also GWuClass, gw_matrix, stable_part.
MotivicHomotopy.stable_part — Method
stable_part(beta::GWuClass)The image of an unstable Grothendieck–Witt class under the projection $\text{GW}^u(k) → \text{GW}(k)$: the GWClass with the same Gram matrix, forgetting the scalar.
Examples
julia> stable_part(GWuClass(QQ[0 1; 1 0], -4))
[0 1]
[1 0]Working with forms
Building standard forms, diagonalizing them, extracting simplified representatives, and computing the Witt (sum) decomposition and anisotropic part.
MotivicHomotopy.diagonal_form — Method
diagonal_form(kk, (a₁, …, aₙ))
diagonal_form(kk, a₁, a₂, …)The GWClass of the diagonal form $⟨a_1, …, a_n⟩$ over the field or finite étale algebra kk: the block sum of the rank-one forms $⟨a_i⟩ : k × k → k$, $(x, y) ↦ a_i x y$. A single entry produces a rank-one form. For forms over $\mathbb{R}$ / $\mathbb{C}$ pass Float64 / ComplexF64 as kk.
Examples
julia> diagonal_form(QQ, (3, 5, 7))
[3 0 0]
[0 5 0]
[0 0 7]
julia> diagonal_form(GF(29), 5//13)
[16]
julia> diagonal_form(Float64, 2)
1×1 Matrix{Float64}:
2.0See also hyperbolic_form, pfister_form, diagonal_unstable_form, diagonal_entries.
MotivicHomotopy.diagonal_unstable_form — Method
diagonal_unstable_form(kk, (a₁, …, aₙ))
diagonal_unstable_form(kk, a₁, a₂, …)The GWuClass represented by the diagonal form $⟨a_1, …, a_n⟩$ over the field or finite étale algebra kk, with scalar the determinant $a_1 ⋯ a_n$. See diagonal_form for the stable counterpart.
Examples
julia> diagonal_unstable_form(QQ, (3, 5, 7))
([3 0 0; 0 5 0; 0 0 7], 105)MotivicHomotopy.hyperbolic_form — Method
hyperbolic_form(kk)
hyperbolic_form(kk, n)The GWClass of the hyperbolic form $\mathbb{H} = ⟨1, -1⟩$ over the field or finite étale algebra kk, or of the totally hyperbolic form $(n/2)·\mathbb{H}$ when an (even) rank n is specified. Odd n is an error.
Examples
julia> hyperbolic_form(GF(7))
[1 0]
[0 6]
julia> hyperbolic_form(Float64, 4)
4×4 Matrix{Float64}:
1.0 0.0 0.0 0.0
0.0 -1.0 0.0 0.0
0.0 0.0 1.0 0.0
0.0 0.0 0.0 -1.0See also diagonal_form, hyperbolic_unstable_form, sum_decomposition.
MotivicHomotopy.hyperbolic_unstable_form — Method
hyperbolic_unstable_form(kk)
hyperbolic_unstable_form(kk, n)The GWuClass represented by the hyperbolic form $\mathbb{H} = ⟨1, -1⟩$ (or the totally hyperbolic form of even rank n) over the field or finite étale algebra kk, with scalar its determinant. See hyperbolic_form for the stable counterpart.
Examples
julia> hyperbolic_unstable_form(GF(7))
([1 0; 0 6], 6)MotivicHomotopy.pfister_form — Method
pfister_form(kk, (a₁, …, aₙ))
pfister_form(kk, a₁, a₂, …)The GWClass of the Pfister form $⟨⟨a_1, …, a_n⟩⟩$ over the field kk: the rank-$2^n$ tensor product $⟨1, -a_1⟩ ⊗ ⋯ ⊗ ⟨1, -a_n⟩$. A single entry produces a one-fold Pfister form.
Examples
julia> pfister_form(QQ, (2, 6))
[1 0 0 0]
[0 -6 0 0]
[0 0 -2 0]
[0 0 0 12]
julia> pfister_form(GF(13), -2//3)
[1 0]
[0 5]See also diagonal_form, gw_tensor_product.
MotivicHomotopy.diagonalize_via_congruence — Method
diagonalize_via_congruence(M)A diagonal matrix congruent to the symmetric matrix M, computed by symmetric Gaussian elimination (simultaneous row and column operations). M may be defined over a field, a finite étale algebra, or as a Matrix{Float64} / Matrix{ComplexF64} for $\mathbb{R}$ / $\mathbb{C}$. The order (and scaling) of the diagonal entries is an artifact of the algorithm and is not normalized; use diagonal_class for square-class-reduced entries.
Over étale algebras that are not domains the elimination is performed fraction-free (rows and columns are scaled by the pivot instead of divided), so the result is congruent but its entries may carry square factors.
Examples
julia> diagonalize_via_congruence(QQ[0 2; 2 0])
[4 0]
[0 -1]
julia> S, (y,) = polynomial_ring(QQ, ["y"]);
julia> A, _ = quo(S, ideal(S, [y^2 - 1]));
julia> diagonalize_via_congruence(A[A(1) A(2); A(2) A(y)])
[1 0]
[0 y - 4]See also diagonal_class, diagonal_entries.
MotivicHomotopy.diagonal_class — Method
diagonal_class(beta)A class isomorphic to beta with a diagonal Gram matrix, with simplified diagonal entries: over $\mathbb{Q}$ each entry is replaced by its squarefree integral representative; over a finite field entries become 1 or a fixed nonsquare; over $\mathbb{R}$ entries become ±1 and over $\mathbb{C}$ they become 1. For a GWuClass the stable part is diagonalized and the scalar carried through unchanged.
The result is cached on beta, so repeated calls are free. Note that sum_decomposition overwrites this cache with its own representative, so the value returned by diagonal_class can change after a call to sum_decomposition.
Examples
julia> beta = GWClass(QQ[9 1 7 4; 1 10 3 2; 7 3 6 7; 4 2 7 5]);
julia> diagonal_class(beta)
[1 0 0 0]
[0 89 0 0]
[0 0 445 0]
[0 0 0 -55]See also diagonalize_via_congruence, diagonal_entries.
MotivicHomotopy.diagonal_entries — Method
diagonal_entries(beta::GWClass)The entries $a_1, …, a_n$ such that $β ≅ ⟨a_1, …, a_n⟩$, obtained by diagonalizing the Gram matrix via congruence (without square-class simplification) and reading off the diagonal. If beta is already diagonal the entries are returned as-is.
Examples
julia> diagonal_entries(GWClass(QQ[3 0 0; 0 2 0; 0 0 7]))
3-element Vector{QQFieldElem}:
3
2
7
julia> diagonal_entries(GWClass([0.0 0.0 1.0; 0.0 1.0 0.0; 1.0 0.0 0.0]))
3-element Vector{Float64}:
2.0
1.0
-0.5See also diagonal_class, diagonalize_via_congruence.
MotivicHomotopy.anisotropic_part — Method
anisotropic_part(beta::GWClass)
anisotropic_part(A)The anisotropic part of a symmetric bilinear form over $\mathbb{Q}$, $\mathbb{R}$, $\mathbb{C}$, or a finite field of odd characteristic: the (unique up to isomorphism) anisotropic form $β_a$ in the Witt decomposition $β ≅ β_a ⊕ n·\mathbb{H}$.
Over $\mathbb{C}$, $\mathbb{R}$, and finite fields this is a short computation from the rank, signature, or discriminant. Over $\mathbb{Q}$ it uses the number-field algorithms of Koprowski–Rothkegel [KR23]: ranks ≥ 4 are peeled off by signs of the signature, rank 3 via a CRT-constructed splitting element, and the rank-2 base case via a Hilbert-symbol exponent system solved over GF(2).
Examples
julia> anisotropic_part(diagonal_form(QQ, (3, -3, 2, 5, 1, -9)))
[2 0]
[0 5]References
- [KR23] P. Koprowski and B. Rothkegel, The anisotropic part of a quadratic form over a number field, Journal of Symbolic Computation, 2023.
See also anisotropic_dimension, gw_witt_index, sum_decomposition.
MotivicHomotopy.sum_decomposition — Method
sum_decomposition(beta)A simplified diagonal representative of a GWClass or GWuClass over $\mathbb{Q}$, $\mathbb{R}$, $\mathbb{C}$, or a finite field of odd characteristic: the class rewritten as its anisotropic_part plus gw_witt_index-many hyperbolic forms. For an unstable class the decomposition is applied to the stable part and the scalar kept. Over $\mathbb{R}$ this reflects the classification of a form by its rank and signature ([L05, II Proposition 3.5]).
The result overwrites the diagonal_class cache slot on beta, so a later diagonal_class call returns this representative.
Examples
julia> gamma = GWClass(QQ[1 2 3; 2 4 5; 3 5 6]);
julia> sum_decomposition(gamma)
[1 0 0]
[0 1 0]
[0 0 -1]
julia> delta = GWClass(GF(13)[9 1 7 4; 1 10 3 2; 7 3 6 7; 4 2 7 5]);
julia> sum_decomposition(delta)
[1 0 0 0]
[0 8 0 0]
[0 0 1 0]
[0 0 0 12]References
- [L05] T. Y. Lam, Introduction to quadratic forms over fields, American Mathematical Society, 2005.
See also sum_decomposition_string, anisotropic_part, gw_witt_index.
MotivicHomotopy.sum_decomposition_string — Method
sum_decomposition_string(beta)A human-readable string for the sum_decomposition of a GWClass or GWuClass: hyperbolic summands are written H (with a multiplicity prefix) and rank-one summands <a>. For an unstable class the result is the pair "(decomposition, scalar)".
Examples
julia> sum_decomposition_string(GWClass(QQ[1 2 3; 2 4 5; 3 5 6]))
"H + <1>"
julia> sum_decomposition_string(GWClass(GF(13)[9 1 7 4; 1 10 3 2; 7 3 6 7; 4 2 7 5]))
"H + <1> + <-5>"See also sum_decomposition.
Invariants and classification
Numerical and arithmetic invariants of a form (rank, signature, discriminant, Hilbert symbols, Hasse–Witt invariants, anisotropic dimension, Witt index), the isotropy predicates, and the isomorphism test that classifies forms up to equivalence.
MotivicHomotopy.form_rank — Method
form_rank(beta::GWClass)
form_rank(M)The rank of a symmetric bilinear form. On a GWClass (which is nondegenerate by construction) this is the size of the Gram matrix; on a raw matrix it is the matrix rank, so degenerate directions are not counted.
Examples
julia> form_rank(diagonal_form(QQ, (3, 5, 7, 11)))
4See also form_signature, anisotropic_dimension.
MotivicHomotopy.form_signature — Method
form_signature(beta::GWClass)The signature of a symmetric bilinear form over $\mathbb{Q}$ or $\mathbb{R}$: after diagonalizing, the number of positive diagonal entries minus the number of negative ones. Together with the rank it classifies forms over $\mathbb{R}$; over $\mathbb{Q}$ it is one of the invariants entering is_isomorphic_form.
Examples
julia> form_signature(GWClass([0.0 0.0 1.0; 0.0 1.0 0.0; 1.0 0.0 0.0]))
1
julia> form_signature(diagonal_form(QQ, (1, -1, 1)))
1See also form_rank, integral_discriminant, is_isomorphic_form.
MotivicHomotopy.hasse_witt_invariant — Method
hasse_witt_invariant(beta::GWClass, p)
hasse_witt_invariant(L::AbstractVector, p)The Hasse–Witt invariant at the prime p of a form over $\mathbb{Q}$: for a diagonalization $⟨a_1, …, a_n⟩$, the product $∏_{i<j} (a_i, a_j)_p$ of pairwise Hilbert symbols (see hilbert_symbol_padic). The list variant takes the diagonal entries directly.
The invariant equals 1 for all but finitely many primes — for p not dividing any entry of a squarefree diagonal representative it is automatically 1 — so only the relevant_primes need checking.
Examples
julia> beta = GWClass(QQ[1 4 7; 4 3 -1; 7 -1 5]);
julia> hasse_witt_invariant(beta, 7)
1
julia> hasse_witt_invariant([6, 7, 22], 2)
-1See also hilbert_symbol_padic, relevant_primes, is_isomorphic_form.
MotivicHomotopy.integral_discriminant — Method
integral_discriminant(beta::GWClass)A squarefree integral representative of the discriminant of a form over $\mathbb{Q}$: the square class of the determinant of any Gram matrix representing beta, normalized to a squarefree integer. The discriminant is one of the invariants classifying rational forms (see is_isomorphic_form).
Examples
julia> beta = GWClass(QQ[1 4 7; 4 3 -1; 7 -1 5]);
julia> integral_discriminant(beta)
-269See also form_signature, hasse_witt_invariant.
MotivicHomotopy.relevant_primes — Method
relevant_primes(beta::GWClass)A finite list of primes containing every prime at which the Hasse–Witt invariant of the rational form beta can be nontrivial. The Hasse–Witt invariants of a form equal 1 at all but finitely many primes ([S73, IV §3.3]); since they are products of Hilbert symbols of the diagonal entries, it suffices to take the primes dividing the entries of a squarefree diagonal representative.
Examples
julia> relevant_primes(diagonal_form(QQ, (6, 7, 22)))
4-element Vector{ZZRingElem}:
2
3
7
11References
- [S73] J. P. Serre, A course in arithmetic, Springer-Verlag, 1973.
See also hasse_witt_invariant.
MotivicHomotopy.hilbert_symbol_padic — Method
hilbert_symbol_padic(a, b, p)The Hilbert symbol $(a, b)_p$ of two nonzero rational numbers, viewed as elements of $\mathbb{Q}_p$:
$(a, b)_p = 1$ if $z^2 = ax^2 + by^2$ has a nonzero solution over $\mathbb{Q}_p$, and $-1$ otherwise ([S73, Chapter III]).
Products of Hilbert symbols compute the hasse_witt_invariant, a key step in classifying rational forms and certifying their (an)isotropy.
The name carries the _padic suffix because Oscar itself exports hilbert_symbol (which this function calls internally).
Examples
$z^2 = 2x^2 + y^2$ has the solution $(1, 0, 3)$ mod 7, hence a 7-adic solution by Hensel's lemma, while $z^2 = 7x^2 + 3y^2$ has no nonzero solution mod 7:
julia> hilbert_symbol_padic(2, 1, 7)
1
julia> hilbert_symbol_padic(7, 3, 7)
-1
julia> hilbert_symbol_padic(2, 2, 2)
1
julia> hilbert_symbol_padic(2, 3, 2)
-1References
- [S73] J. P. Serre, A course in arithmetic, Springer-Verlag, 1973.
See also hilbert_symbol_real, hasse_witt_invariant.
MotivicHomotopy.hilbert_symbol_real — Method
hilbert_symbol_real(a, b)The Hilbert symbol $(a, b)_{\mathbb{R}}$ of two nonzero rational numbers viewed as real numbers: $-1$ if $z^2 = ax^2 + by^2$ has no nonzero real solution — which happens exactly when both a and b are negative — and $1$ otherwise ([S73, Chapter III]).
Examples
julia> hilbert_symbol_real(-3, -2//3)
-1
julia> hilbert_symbol_real(3, -5)
1References
- [S73] J. P. Serre, A course in arithmetic, Springer-Verlag, 1973.
See also hilbert_symbol_padic, form_signature.
MotivicHomotopy.padic_valuation — Method
padic_valuation(a, p)The $p$-adic valuation of a nonzero integer or rational number a: the integer $n$ with $a = u·p^n$ for a unit $u$ of $\mathbb{Z}_p$. Errors on $a = 0$.
Examples
$363/7 = 3·11^2/7$, so the 11-adic valuation is 2:
julia> padic_valuation(363//7, 11)
2MotivicHomotopy.anisotropic_dimension — Method
anisotropic_dimension(beta::GWClass)
anisotropic_dimension(A)The anisotropic dimension of a symmetric bilinear form over $\mathbb{Q}$, $\mathbb{R}$, $\mathbb{C}$, or a finite field of odd characteristic. By the Witt decomposition theorem any nondegenerate form decomposes uniquely as $β ≅ n·\mathbb{H} ⊕ β_a$ with $β_a$ anisotropic; the anisotropic dimension is the rank of $β_a$.
Over $\mathbb{Q}$ it is the maximum of the anisotropic dimensions over all completions: $\lvert \text{signature} \rvert$ at the real place and anisotropic_dimension_qqp at 2 and the relevant_primes ([KC18, Algorithm 9]).
Examples
julia> anisotropic_dimension(diagonal_form(QQ, (1, -1, 2)))
1References
- [KC18] P. Koprowski and A. Czogała, Computing with quadratic forms over number fields, Journal of Symbolic Computation, 2018.
See also gw_witt_index, anisotropic_part, is_anisotropic_form.
MotivicHomotopy.anisotropic_dimension_qqp — Method
anisotropic_dimension_qqp(beta::GWClass, p)The anisotropic dimension of a rational form over the $p$-adic completion $\mathbb{Q}_p$: the rank of the anisotropic part of beta base-changed to $\mathbb{Q}_p$. Every form of rank ≥ 5 over $\mathbb{Q}_p$ is isotropic, so the result is always 0, 1, 2, 3, or 4. This implements [KC18, Algorithm 8].
Examples
julia> anisotropic_dimension_qqp(diagonal_form(QQ, (1, -1, 2)), 2)
1References
- [KC18] P. Koprowski and A. Czogała, Computing with quadratic forms over number fields, Journal of Symbolic Computation, 2018.
See also anisotropic_dimension.
MotivicHomotopy.gw_witt_index — Method
gw_witt_index(beta::GWClass)The Witt index of a form over $\mathbb{Q}$, $\mathbb{R}$, $\mathbb{C}$, or a finite field of odd characteristic: the number $n$ of hyperbolic summands in the Witt decomposition $β ≅ n·\mathbb{H} ⊕ β_a$ ([L05, I.4.3]), computed as (rank − anisotropic dimension)/2.
The name carries the gw_ prefix because Oscar exports witt_index.
Examples
julia> gw_witt_index(diagonal_form(QQ, (1, -1, 2)))
1References
- [L05] T. Y. Lam, Introduction to quadratic forms over fields, American Mathematical Society, 2005.
See also anisotropic_dimension, sum_decomposition.
MotivicHomotopy.is_anisotropic_form — Method
is_anisotropic_form(beta::GWClass)
is_anisotropic_form(A)Whether a symmetric bilinear form over $\mathbb{Q}$, $\mathbb{R}$, $\mathbb{C}$, or a finite field of odd characteristic is anisotropic, i.e. has no nonzero vector $v$ with $β(v, v) = 0$. Computed as the statement that the anisotropic dimension equals the dimension of the form.
What this takes per field: over $\mathbb{C}$ only rank-one forms are anisotropic; over $\mathbb{R}$ a form is anisotropic iff its diagonal entries are all positive or all negative; over $\mathbb{Q}$ the Hasse–Minkowski principle ([L05, VI.3.1]) reduces the question to the completions (forms of rank ≥ 5 over $\mathbb{Q}_p$ are always isotropic ([S73, IV Theorem 6]), so only finitely many invariant computations are needed); over a finite field a nondegenerate form is anisotropic iff its rank is ≤ 2 and it is not hyperbolic.
Examples
julia> is_anisotropic_form(GWClass(ComplexF64[2 0; 0 5]))
false
julia> is_anisotropic_form(GWClass([3.0 0 0; 0 5 0; 0 0 7]))
true
julia> is_anisotropic_form(GWClass(GF(7)[1 0 0; 0 1 0; 0 0 1]))
falseReferences
- [L05] T. Y. Lam, Introduction to quadratic forms over fields, American Mathematical Society, 2005.
- [S73] J. P. Serre, A course in arithmetic, Springer-Verlag, 1973.
See also is_isotropic_form, anisotropic_dimension, anisotropic_part.
MotivicHomotopy.is_isotropic_form — Method
is_isotropic_form(beta::GWClass)
is_isotropic_form(A)Whether a symmetric bilinear form over $\mathbb{Q}$, $\mathbb{R}$, $\mathbb{C}$, or a finite field of odd characteristic is isotropic — the negation of is_anisotropic_form; see there for the per-field criteria.
Examples
julia> is_isotropic_form(diagonal_form(QQ, (1, -1)))
true
julia> is_isotropic_form(GWClass(GF(7)[3 0; 0 3]))
falseSee also gw_witt_index, anisotropic_dimension.
MotivicHomotopy.is_isomorphic_form — Method
is_isomorphic_form(alpha, beta; linear_tolerance = 1e-6)Whether two Grothendieck–Witt classes (or unstable classes, or raw symmetric matrices) over $\mathbb{Q}$, $\mathbb{R}$, $\mathbb{C}$, or a finite field of odd characteristic represent the same element of $\text{GW}(k)$ (resp. $\text{GW}^u(k)$). This is the mathematical notion of equality; == on classes compares Gram matrices literally.
The classification used per field:
- $\mathbb{C}$ (and any quadratically closed field): rank alone, since every nonzero element is a square.
- $\mathbb{R}$: rank and signature (Sylvester's law of inertia).
- $\mathbb{Q}$: rank, signature, discriminant, and the Hasse–Witt invariants at all
relevant_primes— by the Hasse–Minkowski principle forms over $\mathbb{Q}$ are isomorphic iff they are isomorphic over every completion ([S73, IV Thm. 7]; [L05, VI.3.3]). Each Hasse–Witt invariant is a product of values of a symbol on the diagonal entries ([MH73, III.5.4]). - finite fields: rank and the square class of the discriminant.
For GWuClasses the fibered-product structure of $\text{GW}^u(k)$ reduces the test to: stable parts isomorphic and $k^×$-factors equal. Over $\mathbb{Q}$ and finite fields the scalars must agree exactly; over $\mathbb{R}$ and $\mathbb{C}$ they are considered equal when the absolute value of their difference is below linear_tolerance (default 1e-6).
Examples
julia> alpha = GWClass(ComplexF64[2 3 1; 3 -1 0; 1 0 0]);
julia> beta = GWClass(ComplexF64[2 4 -1; 4 5 7; -1 7 9]);
julia> is_isomorphic_form(alpha, beta)
true
julia> is_isomorphic_form(GWClass(QQ[1 4 7; 4 3 2; 7 2 -1]),
GWClass(QQ[0 0 1; 0 2 7; 1 7 3]))
false
julia> u1 = GWuClass(QQ[2 3 1; 3 -1 0; 1 0 0], 1);
julia> u2 = GWuClass(QQ[2 3 1; 3 -1 0; 1 0 0], 4);
julia> is_isomorphic_form(u1, u2) # same stable part, scalars 1 ≠ 4 in ℚ×
falseReferences
- [S73] J. P. Serre, A course in arithmetic, Springer-Verlag, 1973.
- [L05] T. Y. Lam, Introduction to quadratic forms over fields, American Mathematical Society, 2005.
- [MH73] J. Milnor and D. Husemoller, Symmetric bilinear forms, Springer-Verlag, 1973.
See also form_rank, form_signature, integral_discriminant, hasse_witt_invariant.
Computing $\mathbb{A}^1$-degrees
The local and global $\mathbb{A}^1$-Brouwer degrees, both stable and unstable.
MotivicHomotopy.global_A1_degree — Method
global_A1_degree(F)The global $\mathbb{A}^1$-Brouwer degree of an endomorphism of affine space $f = (f_1, …, f_n) : \mathbb{A}^n_k → \mathbb{A}^n_k$ with isolated zeros, as a GWClass in $\text{GW}(k)$. F is a vector of $n$ polynomials in $n$ variables over a field $k$ of characteristic not 2.
The $\mathbb{A}^1$-Brouwer degree, first defined by Morel [M12], is an algebro-geometric enrichment of the classical topological Brouwer degree. Using the tools of motivic homotopy theory one associates to an endomorphism of affine space the isomorphism class of a nondegenerate symmetric bilinear form whose invariants encode geometric data about how the morphism transforms space: its rank recovers the degree of the associated complex map, and its signature the degree of the associated real map. Such a form appears in the work of Eisenbud–Levine [EL77] and Khimshiashvili [K77], whose signature computes the local degree of a smooth map of real manifolds even where the Jacobian vanishes; this was shown to agree with Morel's degree by Kass–Wickelgren [KW19]. A related form attached to a complete intersection, due to Scheja–Storch [SS76], was aligned with the $\mathbb{A}^1$-degree in [BW23]. Following Brazelton–McKean–Pauli [BMP23], the degree is computed here as a multivariate Bézoutian bilinear form.
Following McKean [M21] one may read the degree $\deg^{\mathbb{A}^1}(f)$ as a quadratically enriched intersection multiplicity of the hypersurfaces $V(f_1) ∩ ⋯ ∩ V(f_n)$. It equals the sum of the local_A1_degrees over the points of the zero locus $V(f)$.
The Gram matrix is expressed in a standard-monomial basis; an equivalent form in a different basis represents the same class, so compare results with is_isomorphic_form rather than entrywise.
Base field
- $\mathbb{Q}$ and finite fields of odd characteristic — the form is computed exactly.
- $\mathbb{C}$ — a symmetric bilinear form over $\mathbb{C}$ is determined by its rank, so the degree is simply the identity form of rank equal to the $\mathbb{C}$-dimension of the coordinate algebra $k[x_1,…,x_n]/(f_1,…,f_n)$ — the number of zeros counted with multiplicity. This dimension is a discrete invariant equal to the rank of the degree computed over $\mathbb{Q}$, so it is obtained from the exact computation with no numerical root-finding.
- $\mathbb{R}$ — compute the degree over $\mathbb{Q}$ and base-change the resulting Gram matrix to $\mathbb{R}$ (its
form_signatureis the real degree); real input is not accepted directly.
Examples
For $z ↦ z^2$ the degree is a rank-2 form of signature 0: the complex map $\mathbb{C}$ → $\mathbb{C}$ has degree 2, while the real map $\mathbb{R}$ → $\mathbb{R}$ has degree 0.
julia> S, (x,) = polynomial_ring(QQ, ["x"]);
julia> beta = global_A1_degree([x^2 + 1])
[0 1]
[1 0]
julia> form_rank(beta), form_signature(beta)
(2, 0)The cubic $y = x(x-1)(x+1)$ meeting the $x$-axis, read as an enriched count of intersection points: rank 3 (three complex intersections) and signature 1 (the signed real count).
julia> S, (x, y) = polynomial_ring(QQ, ["x", "y"]);
julia> f = [x^3 - x^2 - y, y];
julia> global_A1_degree(f)
[0 0 1]
[0 1 -1]
[1 -1 0]
julia> form_signature(global_A1_degree(f))
1The global degree is the sum of the local degrees over the zero locus $V(f) = \{(1,0), (0,0)\}$:
julia> d1 = local_A1_degree(f, ideal(S, [x - 1, y]));
julia> d2 = local_A1_degree(f, ideal(S, [x, y]));
julia> is_isomorphic_form(global_A1_degree(f), gw_direct_sum(d1, d2))
trueReferences
- [M12] F. Morel, $\mathbb{A}^1$-algebraic topology over a field, Springer Lecture Notes in Mathematics, 2012.
- [EL77] D. Eisenbud and H. Levine, An algebraic formula for the degree of a C∞ map germ, Annals of Mathematics, 1977.
- [K77] G. Khimshiashvili, The local degree of a smooth mapping, Sakharth. SSR Mecn. Akad. Moambe, 1977.
- [SS76] G. Scheja and U. Storch, Über Spurfunktionen bei vollständigen Durchschnitten, J. Reine Angew. Math., 1975.
- [KW19] J. L. Kass and K. Wickelgren, The class of Eisenbud–Khimshiashvili–Levine is the local $\mathbb{A}^1$-Brouwer degree, Duke Mathematical Journal, 2019.
- [BW23] T. Bachmann and K. Wickelgren, Euler classes: six-functors formalism, dualities, integrality and linear subspaces of complete intersections, J. Inst. Math. Jussieu, 2023.
- [BMP23] T. Brazelton, S. McKean, and S. Pauli, Bézoutians and the $\mathbb{A}^1$-degree, Algebra & Number Theory, 2023.
- [M21] S. McKean, An arithmetic enrichment of Bézout's Theorem, Mathematische Annalen, 2021.
See also local_A1_degree, global_unstable_A1_degree, sum_decomposition.
MotivicHomotopy.global_unstable_A1_degree — Method
global_unstable_A1_degree(q)
global_unstable_A1_degree(f, g)The global unstable $\mathbb{A}^1$-Brouwer degree of a pointed rational function $f/g : \mathbb{P}^1_k → \mathbb{P}^1_k$ — pointed meaning $(f/g)(∞) = ∞$, i.e. $\deg f > \deg g$ — as a GWuClass in the unstable Grothendieck–Witt group $\text{GW}^u(k) = \text{GW}(k) ×_{k^×/(k^×)^2} k^×$.
Morel's $\mathbb{A}^1$-Brouwer degree generalizes the classical Brouwer degree by assigning to an endomorphism of the motivic sphere a class in the Grothendieck–Witt ring. That degree map is an isomorphism in dimensions two and above, but in dimension one it is only surjective [M12]; there, a computation of Morel [M12] and Cazanave [C12] refines it to an isomorphism $[\mathbb{P}^1_k, \mathbb{P}^1_k] ≅ \text{GW}^u(k)$ onto the unstable group, which records not only the stable class but also a $k^×$-scalar. Building on Cazanave's work, Kass–Wickelgren [KW20] and Igieobo et al. [I+24] give an explicit bilinear form representing the degree of $f/g$ in both the local and global settings, a variant of the Bézoutian form (Cazanave [C12, Thm. 3.6]).
Unlike the stable degree, the global unstable degree is not the sum of the local_unstable_A1_degrees at the zeros of $f/g$: it is their divisorial_sum [I+24], which weights each zero's contribution by the configuration of the whole divisor of zeros.
Input and base field
q is an element of the fraction field of a one-variable polynomial ring over $\mathbb{Q}$ or a finite field of odd characteristic (a plain polynomial is treated as $f/1$); the two-argument form supplies numerator and denominator separately. If $f$ and $g$ share a common factor it is cancelled and the reduced function checked for pointedness before the degree is computed. Over $\mathbb{R}$, compute over $\mathbb{Q}$ and base-change.
Over $\mathbb{C}$ — the one case that needs numerical computation, since the class carries a $k^×$-scalar and so the actual complex roots must be found — pass two HomotopyContinuation expressions f, g. Roots of f and g closer than the linear_tolerance keyword (default 1e-6) are treated as a common factor and cancelled.
Examples
A degree-5 pointed rational function; its rank equals the number of zeros of $f/g$ counted with multiplicity over $\mathbb{C}$:
julia> S, (x,) = polynomial_ring(QQ, ["x"]);
julia> q = (x^5 - 6*x^4 + 11*x^3 - 2*x^2 - 12*x + 8) // (x^4 - 5*x^2 + 7*x + 1);
julia> global_unstable_A1_degree(q)
([-68 38 11 -14 1; 38 -63 63 -29 7; 11 63 -84 39 -5; -14 -29 39 -16 0; 1 7 -5 0 1], -53240)The divisorial sum of the local degrees at the zeros $-1, 1, 2$ recovers the global degree:
julia> degs = [local_unstable_A1_degree(q, r) for r in [-1, 1, 2]];
julia> is_isomorphic_form(divisorial_sum(degs, [-1, 1, 2]),
global_unstable_A1_degree(q))
trueThe same computation over $\mathbb{C}$ with HomotopyContinuation input:
julia> import HomotopyContinuation; HomotopyContinuation.@var x;
julia> global_unstable_A1_degree((x-1)*(x-2)*(x-3), (x-1)*(x-4))
(ComplexF64[1.0 + 0.0im 0.0 + 0.0im; 0.0 + 0.0im 1.0 + 0.0im], -1.9999999999999987 + 3.337899271044116e-15im)References
- [M12] F. Morel, $\mathbb{A}^1$-algebraic topology over a field, Springer Lecture Notes in Mathematics, 2012.
- [C12] C. Cazanave, Algebraic homotopy classes of rational functions, Annales Scientifiques de l'École Normale Supérieure, 2012.
- [KW20] J. L. Kass and K. Wickelgren, A classical proof that the algebraic homotopy class of a rational function is the residue pairing, Linear Algebra and its Applications, 2020.
- [I+24] J. Igieobo et al., Motivic configurations on the line, Advances in Mathematics 482 (2025), 110637.
See also local_unstable_A1_degree, divisorial_sum, global_A1_degree.
MotivicHomotopy.local_A1_degree — Method
local_A1_degree(F, p)The local $\mathbb{A}^1$-Brouwer degree of an endomorphism of affine space $f = (f_1, …, f_n) : \mathbb{A}^n_k → \mathbb{A}^n_k$ at an isolated zero, as a GWClass in $\text{GW}(k)$. F is a vector of $n$ polynomials in $n$ variables over a field of characteristic not 2, and p is the prime ideal of a point in the zero locus $V(f)$.
The local degree is the class of the Bézoutian bilinear form on the local algebra $Q_p(f) = k[x_1,…,x_n]_{\mathfrak{m}_p}/(f_1,…,f_n)$ at the point (see local_algebra_basis). Summed over the points of $V(f)$ it recovers the global_A1_degree; see there for the background and references.
The base field is handled as for the global degree: exactly over $\mathbb{Q}$ and finite fields of odd characteristic; over $\mathbb{C}$ the class is the identity form of rank equal to the $\mathbb{C}$-dimension of $Q_p(f)$ (the multiplicity of the zero), obtained from the exact computation; over $\mathbb{R}$, compute over $\mathbb{Q}$ and base-change.
Examples
julia> S, (x, y) = polynomial_ring(QQ, ["x", "y"]);
julia> f = [x^3 - x^2 - y, y];
julia> d1 = local_A1_degree(f, ideal(S, [x - 1, y]))
[1]
julia> d2 = local_A1_degree(f, ideal(S, [x, y]))
[ 1 -1]
[-1 0]
julia> is_isomorphic_form(global_A1_degree(f), gw_direct_sum(d1, d2))
trueSee also global_A1_degree, local_unstable_A1_degree, local_algebra_basis.
MotivicHomotopy.local_algebra_basis — Method
local_algebra_basis(L, p)A monomial basis of the local algebra $Q_p(f) = k[x_1,…,x_n]_{\mathfrak{m}_p}/(f)$ of an endomorphism of affine space at an isolated zero: L is the list of polynomials $f = (f_1, …, f_n)$ and p the prime ideal of the zero. The local algebra is realized as $k[x]/(I : (I : p^∞))$ ([S02, Proposition 2.5]) and its standard monomials are returned.
Examples
julia> S, (x, y) = polynomial_ring(QQ, ["x", "y"]);
julia> local_algebra_basis([x^2 + 1 - y, y], ideal(S, [x^2 + 1, y]))
2-element Vector{QQMPolyRingElem}:
x
1References
- [S02] B. Sturmfels, Solving Systems of Polynomial Equations, American Mathematical Society, 2002.
See also local_A1_degree.
MotivicHomotopy.local_unstable_A1_degree — Method
local_unstable_A1_degree(q, r)
local_unstable_A1_degree(f, g, r)The local unstable $\mathbb{A}^1$-Brouwer degree of a pointed rational function $f/g : \mathbb{P}^1_k → \mathbb{P}^1_k$ at a zero r in the base field, as a GWuClass in $\text{GW}^u(k)$. If r is a zero of multiplicity $m$, the result is the $m × m$ antidiagonal form with entry the value of $(u - r)^m · g/f$ at $r$.
Input shapes match global_unstable_A1_degree (see there for background and references): a fraction or polynomial plus the root, or numerator and denominator separately; the numerical $\mathbb{C}$ path takes two HomotopyContinuation expressions and a number. Non-reduced input is reduced (and re-checked for pointedness) first.
Examples
julia> S, (x,) = polynomial_ring(QQ, ["x"]);
julia> local_unstable_A1_degree((x^2 + x - 2) // (3*x + 5), -2)
([1//3], 1//3)See also global_unstable_A1_degree, divisorial_sum, local_A1_degree.
Étale algebras and transfer
Multiplication matrices, trace and norm of an étale algebra, and the transfer (corestriction) of a Grothendieck–Witt class.
MotivicHomotopy.algebra_norm — Method
algebra_norm(A, a)
algebra_norm(S, I, b)The norm over $k$ of an element of a finite-dimensional $k$-algebra: the determinant of its multiplication_matrix. Accepts the same input shapes as multiplication_matrix.
Examples
julia> S, (x, y) = polynomial_ring(QQ, ["x", "y"]);
julia> I = ideal(S, [x^2 + y^2 + 1, 3*x + 2]);
julia> A, _ = quo(S, I);
julia> algebra_norm(A, 1 + y*x^2)
937//729See also multiplication_matrix, algebra_trace.
MotivicHomotopy.algebra_trace — Method
algebra_trace(A, a)
algebra_trace(S, I, b)The trace over $k$ of an element of a finite-dimensional $k$-algebra: the trace of its multiplication_matrix. Accepts the same input shapes as multiplication_matrix (a quotient ring and an element, or a polynomial ring, ideal, and element).
Examples
julia> S, (x, y) = polynomial_ring(QQ, ["x", "y"]);
julia> I = ideal(S, [x^2 + y^2 + 1, 3*x + 2]);
julia> algebra_trace(S, I, 1 + y*x^2)
2See also multiplication_matrix, algebra_norm, transfer_gw.
MotivicHomotopy.multiplication_matrix — Method
multiplication_matrix(A, a)
multiplication_matrix(S, I, b)The matrix, over the coefficient field $k$, of multiplication by an element on a monomial basis of a finite-dimensional $k$-algebra. The algebra is given either directly as a quotient ring A (an MPolyQuoRing) with a an element coercible into it, or as a polynomial ring S with an ideal I and b an element of S (the algebra then being $S/I$). The basis is the standard monomials in ascending order.
Examples
julia> S, (x, y) = polynomial_ring(QQ, ["x", "y"]);
julia> I = ideal(S, [x^2 + y^2 + 1, 3*x + 2]);
julia> A, _ = quo(S, I);
julia> multiplication_matrix(A, 1 + y*x^2)
[ 1 -52//81]
[4//9 1]See also algebra_trace, algebra_norm.
MotivicHomotopy.transfer_gw — Method
transfer_gw(beta::GWClass)The image of a Grothendieck–Witt class over a finite étale algebra $L/k$ under the canonical transfer map $\text{GW}(L) → \text{GW}(k)$, computed by diagonalizing over $L$ and applying the trace form: the result is the diagonal form over $k$ whose entries are the traces (algebra_trace) of the diagonal entries.
If the trace of a diagonal entry vanishes, the would-be output is degenerate and the constructor errors.
Examples
julia> S, (t,) = polynomial_ring(QQ, ["t"]);
julia> A, _ = quo(S, ideal(S, [t^2 - 1]));
julia> beta = GWClass(A[A(1) A(2); A(2) A(t)]);
julia> transfer_gw(beta)
[2 0]
[0 -8]See also algebra_trace, GWClass.