diff --git a/src/sage/dynamics/arithmetic_dynamics/berkovich_ds.py b/src/sage/dynamics/arithmetic_dynamics/berkovich_ds.py index 96cc0d12d39..de956719603 100644 --- a/src/sage/dynamics/arithmetic_dynamics/berkovich_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/berkovich_ds.py @@ -926,7 +926,7 @@ def __call__(self, x, type_3_pole_check=True): variable = nth_derivative.parent().gens()[0] a = x.center()[0] Taylor_expansion = [] - from sage.functions.other import factorial + from sage.arith.misc import factorial for i in range(f.degree() + 1): Taylor_expansion.append(nth_derivative(a) * 1/factorial(i)) nth_derivative = nth_derivative.derivative(variable) diff --git a/src/sage/groups/misc_gps/argument_groups.py b/src/sage/groups/misc_gps/argument_groups.py index 9fa0fe07974..d6128ee7fdb 100644 --- a/src/sage/groups/misc_gps/argument_groups.py +++ b/src/sage/groups/misc_gps/argument_groups.py @@ -1192,7 +1192,7 @@ def __pow__(self, exponent): sage: a.parent() Symbolic Ring """ - from sage.symbolic.ring import SymbolicRing + from sage.rings.abc import SymbolicRing element = self._element_ ** exponent parent = element.parent() diff --git a/src/sage/modular/arithgroup/congroup_gamma0.py b/src/sage/modular/arithgroup/congroup_gamma0.py index ab38f518bb9..edd8108350a 100644 --- a/src/sage/modular/arithgroup/congroup_gamma0.py +++ b/src/sage/modular/arithgroup/congroup_gamma0.py @@ -593,8 +593,6 @@ def dimension_new_cusp_forms(self, k=2, p=0): sage: all(Gamma0(N).dimension_new_cusp_forms(2)==100 for N in L) True """ - from sage.functions.other import floor - N = self.level() k = ZZ(k) @@ -669,8 +667,8 @@ def v3(q, a): res = (k - 1) / 12 * N * prod(s0(q, a) for q, a in factors) res -= prod(vinf(q, a) for q, a in factors) / ZZ(2) - res += ((1 - k)/4 + floor(k/4)) * prod(v2(q, a) for q, a in factors) - res += ((1 - k)/3 + floor(k/3)) * prod(v3(q, a) for q, a in factors) + res += ((1 - k)/4 + k//4) * prod(v2(q, a) for q, a in factors) + res += ((1 - k)/3 + k//3) * prod(v3(q, a) for q, a in factors) if k == 2: res += moebius(N) return res diff --git a/src/sage/modules/fg_pid/fgp_module.py b/src/sage/modules/fg_pid/fgp_module.py index 719c781ddc3..c0e9181a141 100644 --- a/src/sage/modules/fg_pid/fgp_module.py +++ b/src/sage/modules/fg_pid/fgp_module.py @@ -2,7 +2,7 @@ Finitely generated modules over a PID You can use Sage to compute with finitely generated modules (FGM's) -over a principal ideal domain R presented as a quotient `V / W`, where `V` +over a principal ideal domain `R` presented as a quotient `V / W`, where `V` and `W` are free. .. NOTE:: @@ -13,44 +13,45 @@ obstruction to extending the implementation is only that one has to decide how elements print. -We represent ``M = V / W`` as a pair ``(V, W)`` with ``W`` contained in -``V``, and we internally represent elements of M non-canonically as elements -``x`` of ``V``. We also fix independent generators ``g[i]`` for ``M`` in -``V``, and when we print out elements of ``V`` we print their coordinates +We represent `M = V / W` as a pair `(V, W)` with `W` contained in +`V`, and we internally represent elements of `M` non-canonically as elements +`x` of `V`. We also fix independent generators ``g[i]`` for `M` in +`V`, and when we print out elements of `V` we print their coordinates with respect to the ``g[i]``; over `\ZZ` this is canonical, since each -coefficient is reduce modulo the additive order of ``g[i]``. To obtain -the vector in ``V`` corresponding to ``x`` in ``M``, use ``x.lift()``. +coefficient is reduced modulo the additive order of ``g[i]``. To obtain +the vector in `V` corresponding to `x` in `M`, use ``x.lift()``. -Morphisms between finitely generated R modules are well supported. +Morphisms between finitely generated `R`-modules are well supported. You create a homomorphism by simply giving the images of generators of -M0 in M1. Given a morphism phi:M0-->M1, you can compute the image of -phi, the kernel of phi, and using ``y = phi.lift(x)`` you can lift an -elements x in M1 to an element y in M0, if such a y exists. +`M_0` in `M_1`. Given a morphism `\phi: M_0 \to M_1`, you can compute the image of +`\phi`, the kernel of `\phi`, and using ``y = phi.lift(x)`` you can lift an +element `x` in `M_1` to an element `y` in `M_0`, if such a `y` exists. TECHNICAL NOTE: For efficiency, we introduce a notion of optimized representation for quotient modules. The optimized representation of -M=V/W is the quotient V'/W' where V' has as basis lifts of the -generators ``g[i]`` for M. We internally store a morphism from M0=V0/W0 -to M1=V1/W1 by giving a morphism from the optimized representation V0' -of M0 to V1 that sends W0 into W1. +`M=V/W` is the quotient `V'/W'` where `V'` has as basis lifts of the +generators ``g[i]`` for `M`. We internally store a morphism from `M_0=V_0/W_0` +to `M_1=V_1/W_1` by giving a morphism from the optimized representation `V_0'` +of `M_0` to `V_1` that sends `W_0` into `W_1`. The following TUTORIAL illustrates several of the above points. -First we create free modules V0 and W0 and the quotient module M0. -Notice that everything works fine even though V0 and W0 are not +First we create free modules `V_0` and `W_0` and the quotient module `M_0`. +Notice that everything works fine even though `V_0` and `W_0` are not contained inside `\ZZ^n`, which is extremely convenient. :: - sage: V0 = span([[1/2,0,0],[3/2,2,1],[0,0,1]],ZZ); W0 = V0.span([V0.0+2*V0.1, 9*V0.0+2*V0.1, 4*V0.2]) + sage: V0 = span([[1/2,0,0], [3/2,2,1], [0,0,1]], ZZ) + sage: W0 = V0.span([V0.0 + 2*V0.1, 9*V0.0 + 2*V0.1, 4*V0.2]) sage: M0 = V0/W0; M0 Finitely generated module V/W over Integer Ring with invariants (4, 16) The invariants are computed using the Smith normal form algorithm, and determine the structure of this finitely generated module. -You can get the V and W used in constructing the quotient module using -V() and W() methods:: +You can get the `V` and `W` used in constructing the quotient module using +the methods :meth:`V` and :meth:`W`:: sage: M0.V() Free module of degree 3 and rank 3 over Integer Ring @@ -65,8 +66,8 @@ [ 0 32 0] [ 0 0 4] -We note that the optimized representation of M0, mentioned above in -the technical note has a V that need not be equal to V0, in general. :: +We note that the optimized representation of `M_0`, mentioned above in +the technical note, has a `V` that need not be equal to `V_0`, in general. :: sage: M0.optimized()[0].V() Free module of degree 3 and rank 2 over Integer Ring @@ -74,9 +75,9 @@ [ 0 8 1] [ 0 -2 0] -Create elements of M0 either by coercing in elements of V0, getting generators, +Create elements of `M_0` either by coercing in elements of `V_0`, getting generators, or coercing in a list or tuple or coercing in 0. Finally, one can express an -element as a linear combination of the smith form generators :: +element as a linear combination of the Smith form generators :: sage: M0(V0.0) (0, 2) @@ -87,9 +88,9 @@ sage: 3*M0.0 + 20*M0.1 (3, 4) -We make an element of M0 by taking a difference of two generators, and +We make an element of `M_0` by taking a difference of two generators, and lift it. We also illustrate making an element from a list, which -coerces to V0, then take the equivalence class modulo W0. :: +coerces to `V_0`, then take the equivalence class modulo `W_0`. :: sage: x = M0.0 - M0.1; x (1, 15) @@ -100,23 +101,24 @@ sage: x.additive_order() 16 -Similarly, we construct V1 and W1, and the quotient M1, in a completely different -2-dimensional ambient space. :: +Similarly, we construct `V_1` and `W_1`, and the quotient `M_1`, +in a completely different 2-dimensional ambient space. :: - sage: V1 = span([[1/2,0],[3/2,2]],ZZ); W1 = V1.span([2*V1.0, 3*V1.1]) + sage: V1 = span([[1/2,0], [3/2,2]], ZZ); W1 = V1.span([2*V1.0, 3*V1.1]) sage: M1 = V1/W1; M1 Finitely generated module V/W over Integer Ring with invariants (6) -We create the homomorphism from M0 to M1 that sends both generators of -M0 to 3 times the generator of M1. This is well defined since 3 times +We create the homomorphism from `M_0` to `M_1` that sends both generators of +`M_0` to 3 times the generator of `M_1`. This is well-defined since 3 times the generator has order 2. :: sage: f = M0.hom([3*M1.0, 3*M1.0]); f - Morphism from module over Integer Ring with invariants (4, 16) to module with invariants (6,) that sends the generators to [(3), (3)] + Morphism from module over Integer Ring with invariants (4, 16) + to module with invariants (6,) that sends the generators to [(3), (3)] -We evaluate the homomorphism on our element x of the domain, and on the -first generator of the domain. We also evaluate at an element of V0, -which is coerced into M0. :: +We evaluate the homomorphism on our element `x` of the domain, and on the +first generator of the domain. We also evaluate at an element of `V_0`, +which is coerced into `M_0`. :: sage: f(x) (0) @@ -125,8 +127,8 @@ sage: f(V0.1) (3) -Here we illustrate lifting an element of the image of f, i.e., finding -an element of M0 that maps to a given element of M1:: +Here we illustrate lifting an element of the image of `f`, i.e., finding +an element of `M_0` that maps to a given element of `M_1`:: sage: y = f.lift(3*M1.0) sage: y # random @@ -134,10 +136,10 @@ sage: f(y) (3) -We compute the kernel of f, i.e., the submodule of elements of M0 that +We compute the kernel of `f`, i.e., the submodule of elements of `M_0` that map to 0. Note that the kernel is not explicitly represented as a -submodule, but as another quotient V/W where V is contained in V0. -You can explicitly coerce elements of the kernel into M0 though. :: +submodule, but as another quotient `V/W` where `V` is contained in `V_0`. +You can explicitly coerce elements of the kernel into `M_0` though. :: sage: K = f.kernel(); K Finitely generated module V/W over Integer Ring with invariants (2, 16) @@ -151,13 +153,13 @@ sage: f(M0(K.1)) (0) -We compute the image of f. :: +We compute the image of `f`. :: sage: f.image() Finitely generated module V/W over Integer Ring with invariants (2) Notice how the elements of the image are written as (0) and (1), -despite the image being naturally a submodule of M1, which has +despite the image being naturally a submodule of `M_1`, which has elements (0), (1), (2), (3), (4), (5). However, below we coerce the element (1) of the image into the codomain, and get (3):: @@ -174,8 +176,8 @@ TESTS:: sage: from sage.modules.fg_pid.fgp_module import FGP_Module - sage: V = span([[1/2,1,1],[3/2,2,1],[0,0,1]],ZZ) - sage: W = V.span([2*V.0+4*V.1, 9*V.0+12*V.1, 4*V.2]) + sage: V = span([[1/2,1,1], [3/2,2,1], [0,0,1]], ZZ) + sage: W = V.span([2*V.0 + 4*V.1, 9*V.0 + 12*V.1, 4*V.2]) sage: Q = FGP_Module(V, W); Q Finitely generated module V/W over Integer Ring with invariants (4, 12) sage: Q.linear_combination_of_smith_form_gens([1,3]) @@ -185,7 +187,7 @@ sage: Q(W([1,16,0])) (0, 0) sage: V = span([[1/2,1,1],[3/2,2,1],[0,0,1]],QQ) - sage: W = V.span([2*V.0+4*V.1, 9*V.0+12*V.1]) + sage: W = V.span([2*V.0 + 4*V.1, 9*V.0 + 12*V.1]) sage: Q = FGP_Module(V, W); Q Finitely generated module V/W over Rational Field with invariants (0) sage: q = Q.an_element(); q @@ -232,22 +234,23 @@ def FGP_Module(V, W, check=True): """ INPUT: - - ``V`` -- a free R-module + - ``V`` -- a free `R`-module - - ``W`` -- a free R-submodule of ``V`` + - ``W`` -- a free `R`-submodule of `V` - ``check`` -- bool (default: ``True``); if ``True``, more checks on correctness are performed; in particular, we check the data - types of ``V`` and ``W``, and that ``W`` is a submodule of ``V`` + types of ``V`` and ``W``, and that `W` is a submodule of `V` with the same base ring. OUTPUT: - - the quotient ``V / W`` as a finitely generated R-module + - the quotient `V/W` as a finitely generated `R`-module EXAMPLES:: - sage: V = span([[1/2,1,1],[3/2,2,1],[0,0,1]],ZZ); W = V.span([2*V.0+4*V.1, 9*V.0+12*V.1, 4*V.2]) + sage: V = span([[1/2,1,1], [3/2,2,1], [0,0,1]], ZZ) + sage: W = V.span([2*V.0 + 4*V.1, 9*V.0 + 12*V.1, 4*V.2]) sage: import sage.modules.fg_pid.fgp_module sage: Q = sage.modules.fg_pid.fgp_module.FGP_Module(V, W) sage: type(Q) @@ -273,7 +276,8 @@ def is_FGP_Module(x): EXAMPLES:: - sage: V = span([[1/2,1,1],[3/2,2,1],[0,0,1]],ZZ); W = V.span([2*V.0+4*V.1, 9*V.0+12*V.1, 4*V.2]); Q = V/W + sage: V = span([[1/2,1,1],[3/2,2,1],[0,0,1]],ZZ) + sage: W = V.span([2*V.0 + 4*V.1, 9*V.0 + 12*V.1, 4*V.2]); Q = V/W sage: sage.modules.fg_pid.fgp_module.is_FGP_Module(V) False sage: sage.modules.fg_pid.fgp_module.is_FGP_Module(Q) @@ -284,13 +288,13 @@ def is_FGP_Module(x): class FGP_Module_class(Module): """ - A finitely generated module over a PID presented as a quotient ``V / W``. + A finitely generated module over a PID presented as a quotient `V/W`. INPUT: - - ``V`` -- an R-module + - ``V`` -- an `R`-module - - ``W`` -- an R-submodule of V + - ``W`` -- an `R`-submodule of `V` - ``check`` -- bool (default: ``True``) @@ -305,8 +309,8 @@ class FGP_Module_class(Module): Echelon basis matrix: [100] - sage: V = span([[1/2,1,1],[3/2,2,1],[0,0,1]],ZZ) - sage: W = V.span([2*V.0+4*V.1, 9*V.0+12*V.1, 4*V.2]) + sage: V = span([[1/2,1,1], [3/2,2,1], [0,0,1]], ZZ) + sage: W = V.span([2*V.0 + 4*V.1, 9*V.0 + 12*V.1, 4*V.2]) sage: Q = V/W; Q Finitely generated module V/W over Integer Ring with invariants (4, 12) sage: type(Q) @@ -332,18 +336,19 @@ def __init__(self, V, W, check=True): """ INPUT: - - ``V`` -- an R-module + - ``V`` -- an `R`-module - - ``W`` -- an R-submodule of V + - ``W`` -- an `R`-submodule of `V` - ``check`` -- bool (default: ``True``); if ``True``, more checks on - correctness are performed; in particular, we check - the data types of V and W, and that W is a - submodule of V with the same base ring. + correctness are performed; in particular, we check the data types of + ``V`` and ``W``, and that `W` is a submodule of `V` with the same + base ring `R`. EXAMPLES:: - sage: V = span([[1/2,1,1],[3/2,2,1],[0,0,1]],ZZ); W = V.span([2*V.0+4*V.1, 9*V.0+12*V.1, 4*V.2]) + sage: V = span([[1/2,1,1], [3/2,2,1], [0,0,1]], ZZ) + sage: W = V.span([2*V.0 + 4*V.1, 9*V.0 + 12*V.1, 4*V.2]) sage: Q = V/W; Q Finitely generated module V/W over Integer Ring with invariants (4, 12) sage: type(Q) @@ -370,25 +375,26 @@ def __init__(self, V, W, check=True): def _module_constructor(self, V, W, check=True): r""" - Construct a quotient module ``V/W``. + Construct a quotient module `V/W`. This should be overridden in derived classes. INPUT: - - ``V`` -- an R-module. + - ``V`` -- an `R`-module - - ``W`` -- an R-submodule of ``V``. + - ``W`` -- an `R`-submodule of `V` - - ``check`` -- bool (default: ``True``). + - ``check`` -- bool (default: ``True``) OUTPUT: - The quotient ``V/W``. + The quotient `V/W`. EXAMPLES:: - sage: V = span([[1/2,1,1],[3/2,2,1],[0,0,1]],ZZ); W = V.span([2*V.0+4*V.1, 9*V.0+12*V.1, 4*V.2]) + sage: V = span([[1/2,1,1], [3/2,2,1], [0,0,1]], ZZ) + sage: W = V.span([2*V.0 + 4*V.1, 9*V.0 + 12*V.1, 4*V.2]) sage: Q = V/W; Q Finitely generated module V/W over Integer Ring with invariants (4, 12) sage: Q._module_constructor(V,W) @@ -402,7 +408,7 @@ def _coerce_map_from_(self, S): INPUT: - - ``S`` -- anything. + - ``S`` -- anything OUTPUT: @@ -410,7 +416,8 @@ def _coerce_map_from_(self, S): EXAMPLES:: - sage: V = span([[5, -1/2]],ZZ); W = span([[20,-2]],ZZ); Q = V/W; phi=Q.hom([2*Q.0]) + sage: V = span([[5, -1/2]], ZZ); W = span([[20,-2]], ZZ) + sage: Q = V/W; phi = Q.hom([2*Q.0]) sage: Q._coerce_map_from_(ZZ) False sage: Q._coerce_map_from_(phi.kernel()) @@ -448,10 +455,9 @@ def _mul_(self, other, switch_sides=False): EXAMPLES:: - sage: V = span([[1/2,1,1],[3/2,2,1],[0,0,1]],ZZ) - sage: W = span([2*V.0,4*V.1,3*V.2]) - sage: Q = V/W - sage: Q + sage: V = span([[1/2,1,1], [3/2,2,1], [0,0,1]], ZZ) + sage: W = span([2*V.0, 4*V.1, 3*V.2]) + sage: Q = V/W; Q Finitely generated module V/W over Integer Ring with invariants (2, 12) sage: 2*Q Finitely generated module V/W over Integer Ring with invariants (6) @@ -469,7 +475,8 @@ def _repr_(self): EXAMPLES:: - sage: V = span([[1/2,1,1],[3/2,2,1],[0,0,1]],ZZ); W = V.span([2*V.0+4*V.1, 9*V.0+12*V.1, 4*V.2]) + sage: V = span([[1/2,1,1], [3/2,2,1], [0,0,1]], ZZ) + sage: W = V.span([2*V.0 + 4*V.1, 9*V.0 + 12*V.1, 4*V.2]) sage: (V/W)._repr_() 'Finitely generated module V/W over Integer Ring with invariants (4, 12)' """ @@ -478,12 +485,13 @@ def _repr_(self): def __truediv__(self, other): """ - Return the quotient self/other, where other must be a - submodule of self. + Return the quotient ``self`` / ``other``, where ``other`` must be a + submodule of ``self``. EXAMPLES:: - sage: V = span([[5, -1/2]],ZZ); W = span([[20,-2]],ZZ); Q = V/W; phi=Q.hom([2*Q.0]) + sage: V = span([[5, -1/2]], ZZ); W = span([[20,-2]] ,ZZ) + sage: Q = V/W; phi = Q.hom([2*Q.0]) sage: Q Finitely generated module V/W over Integer Ring with invariants (4) sage: Q/phi.kernel() @@ -504,7 +512,8 @@ def __eq__(self, other): """ EXAMPLES:: - sage: V = span([[1/2,1,1],[3/2,2,1],[0,0,1]],ZZ); W = V.span([2*V.0+4*V.1, 9*V.0+12*V.1, 4*V.2]) + sage: V = span([[1/2,1,1], [3/2,2,1], [0,0,1]], ZZ) + sage: W = V.span([2*V.0 + 4*V.1, 9*V.0 + 12*V.1, 4*V.2]) sage: Q = V/W sage: Q == Q True @@ -521,13 +530,13 @@ def __eq__(self, other): def __ne__(self, other): """ - True iff self is not equal to other. + True iff ``self`` is not equal to ``other``. This may not be needed for modules created using the function :func:`FGP_Module`, since those have uniqueness built into them, but if the modules are created directly using the ``__init__`` method for this class, then this may fail; in - particular, for modules M and N with ``M == N`` returning + particular, for modules ``M`` and ``N`` with ``M == N`` returning True, it may be the case that ``M != N`` may also return True. In particular, for derived classes whose ``__init__`` methods just call the ``__init__`` method for this class need this. See @@ -619,12 +628,12 @@ def _element_constructor_(self, x, check=True): - ``x`` -- a vector or an fgp module element: - - vector: coerce vector into V and define the - corresponding element of V/W + - vector: coerce vector into `V` and define the + corresponding element of `V/W` - - fgp module element: lift to element of ambient vector - space and try to put into V. If x is in ``self`` already, - just return x. + - fgp module element: lift to element of ambient vector + space and try to put into `V`. If ``x`` is in ``self`` already, + just return ``x``. - `check` -- bool (default: ``True``) @@ -632,10 +641,10 @@ def _element_constructor_(self, x, check=True): EXAMPLES:: - sage: V = span([[1/2,1,1],[3/2,2,1],[0,0,1]],ZZ) - sage: W = V.span([2*V.0+4*V.1, 9*V.0+12*V.1, 4*V.2]) + sage: V = span([[1/2,1,1], [3/2,2,1], [0,0,1]], ZZ) + sage: W = V.span([2*V.0 + 4*V.1, 9*V.0 + 12*V.1, 4*V.2]) sage: Q = V/W - sage: x = Q(V.0-V.1); x # indirect doctest + sage: x = Q(V.0 - V.1); x # indirect doctest (0, 9) sage: type(x) @@ -651,11 +660,11 @@ def _element_constructor_(self, x, check=True): def linear_combination_of_smith_form_gens(self, x): r""" Compute a linear combination of the optimised generators of this module - as returned by :meth:`.smith_form_gens`. + as returned by :meth:`smith_form_gens`. EXAMPLES:: - sage: X = ZZ**2 / span([[3,0],[0,2]], ZZ) + sage: X = ZZ**2 / span([[3,0], [0,2]], ZZ) sage: X.linear_combination_of_smith_form_gens([1]) (1) @@ -668,11 +677,12 @@ def linear_combination_of_smith_form_gens(self, x): def __contains__(self, x): """ - Return true if x is contained in ``self``. + Return true if ``x`` is contained in ``self``. EXAMPLES:: - sage: V = span([[1/2,1,1],[3/2,2,1],[0,0,1]],ZZ); W = V.span([2*V.0+4*V.1, 9*V.0+12*V.1, 4*V.2]) + sage: V = span([[1/2,1,1], [3/2,2,1], [0,0,1]], ZZ) + sage: W = V.span([2*V.0 + 4*V.1, 9*V.0 + 12*V.1, 4*V.2]) sage: Q = V/W; Q Finitely generated module V/W over Integer Ring with invariants (4, 12) sage: Q.0 in Q @@ -696,7 +706,7 @@ def __contains__(self, x): def submodule(self, x): """ - Return the submodule defined by x. + Return the submodule defined by ``x``. INPUT: @@ -704,7 +714,8 @@ def submodule(self, x): EXAMPLES:: - sage: V = span([[1/2,1,1],[3/2,2,1],[0,0,1]],ZZ); W = V.span([2*V.0+4*V.1, 9*V.0+12*V.1, 4*V.2]) + sage: V = span([[1/2,1,1], [3/2,2,1], [0,0,1]], ZZ) + sage: W = V.span([2*V.0 + 4*V.1, 9*V.0 + 12*V.1, 4*V.2]) sage: Q = V/W; Q Finitely generated module V/W over Integer Ring with invariants (4, 12) sage: Q.gens() @@ -767,7 +778,8 @@ def has_canonical_map_to(self, A): EXAMPLES:: - sage: V = span([[1/2,1,1],[3/2,2,1],[0,0,1]],ZZ); W = V.span([2*V.0+4*V.1, 9*V.0+12*V.1, 4*V.2]) + sage: V = span([[1/2,1,1], [3/2,2,1], [0,0,1]], ZZ) + sage: W = V.span([2*V.0 + 4*V.1, 9*V.0 + 12*V.1, 4*V.2]) sage: Q = V/W; Q Finitely generated module V/W over Integer Ring with invariants (4, 12) sage: A = Q.submodule((Q.0, Q.0 + 3*Q.1)); A @@ -791,7 +803,7 @@ def is_submodule(self, A): More precisely, this returns ``True`` if ``self.V()`` is a submodule of ``A.V()``, with ``self.W()`` equal to ``A.W()``. - Compare :meth:`.has_canonical_map_to`. + Compare :meth:`has_canonical_map_to`. EXAMPLES:: @@ -829,7 +841,8 @@ def V(self): EXAMPLES:: - sage: V = span([[1/2,1,1],[3/2,2,1],[0,0,1]],ZZ); W = V.span([2*V.0+4*V.1, 9*V.0+12*V.1, 4*V.2]) + sage: V = span([[1/2,1,1], [3/2,2,1], [0,0,1]], ZZ) + sage: W = V.span([2*V.0 + 4*V.1, 9*V.0 + 12*V.1, 4*V.2]) sage: Q = V/W sage: Q.V() Free module of degree 3 and rank 3 over Integer Ring @@ -843,13 +856,14 @@ def V(self): def cover(self): """ - If this module was constructed as V/W, return the cover module V. + If this module was constructed as `V/W`, return the cover module `V`. This is the same as ``self.V()``. EXAMPLES:: - sage: V = span([[1/2,1,1],[3/2,2,1],[0,0,1]],ZZ); W = V.span([2*V.0+4*V.1, 9*V.0+12*V.1, 4*V.2]) + sage: V = span([[1/2,1,1], [3/2,2,1], [0,0,1]], ZZ) + sage: W = V.span([2*V.0 + 4*V.1, 9*V.0 + 12*V.1, 4*V.2]) sage: Q = V/W sage: Q.V() Free module of degree 3 and rank 3 over Integer Ring @@ -862,11 +876,12 @@ def cover(self): def W(self): """ - If this module was constructed as a quotient V/W, return W. + If this module was constructed as a quotient `V/W`, return `W`. EXAMPLES:: - sage: V = span([[1/2,1,1],[3/2,2,1],[0,0,1]],ZZ); W = V.span([2*V.0+4*V.1, 9*V.0+12*V.1, 4*V.2]) + sage: V = span([[1/2,1,1], [3/2,2,1], [0,0,1]], ZZ) + sage: W = V.span([2*V.0 + 4*V.1, 9*V.0 + 12*V.1, 4*V.2]) sage: Q = V/W sage: Q.W() Free module of degree 3 and rank 3 over Integer Ring @@ -879,15 +894,15 @@ def W(self): def relations(self): """ - If ``self`` was constructed as ``V / W``, return the - relations module ``W``. + If ``self`` was constructed as `V / W`, return the + relations module `W`. This is the same as ``self.W()``. EXAMPLES:: - sage: V = span([[1/2,1,1],[3/2,2,1],[0,0,1]],ZZ) - sage: W = V.span([2*V.0+4*V.1, 9*V.0+12*V.1, 4*V.2]) + sage: V = span([[1/2,1,1], [3/2,2,1], [0,0,1]], ZZ) + sage: W = V.span([2*V.0 + 4*V.1, 9*V.0 + 12*V.1, 4*V.2]) sage: Q = V / W sage: Q.relations() Free module of degree 3 and rank 3 over Integer Ring @@ -901,16 +916,17 @@ def relations(self): @cached_method def _relative_matrix(self): """ - V has a fixed choice of basis, and W has a fixed choice of - basis, and both V and W are free R-modules. Since W is - contained in V, we can write each basis element of W as an - R-linear combination of the basis for V. This function - returns that matrix over R, where each row corresponds to a - basis element of W. + `V` has a fixed choice of basis, and `W` has a fixed choice of + basis, and both `V` and `W` are free `R`-modules. Since `W` is + contained in `V`, we can write each basis element of `W` as an + `R`-linear combination of the basis for `V`. This function + returns that matrix over `R`, where each row corresponds to a + basis element of `W`. EXAMPLES:: - sage: V = span([[1/2,1,1],[3/2,2,1],[0,0,1]],ZZ); W = V.span([2*V.0+4*V.1, 9*V.0+12*V.1, 4*V.2]) + sage: V = span([[1/2,1,1], [3/2,2,1], [0,0,1]], ZZ) + sage: W = V.span([2*V.0 + 4*V.1, 9*V.0 + 12*V.1, 4*V.2]) sage: Q = V/W sage: Q._relative_matrix() [ 1 8 0] @@ -925,15 +941,16 @@ def _relative_matrix(self): @cached_method def _smith_form(self): """ - Return matrices S, U, and V such that S = U*R*V, and S is in - Smith normal form, and R is the relative matrix that defines + Return matrices `S`, `U`, and `V` such that `S = U*R*V`, and `S` is in + Smith normal form, and `R` is the relative matrix that defines self. - See :meth:`._relative_matrix`. + See :meth:`_relative_matrix`. EXAMPLES:: - sage: V = span([[1/2,1,1],[3/2,2,1],[0,0,1]],ZZ); W = V.span([2*V.0+4*V.1, 9*V.0+12*V.1, 4*V.2]) + sage: V = span([[1/2,1,1], [3/2,2,1], [0,0,1]], ZZ) + sage: W = V.span([2*V.0 + 4*V.1, 9*V.0 + 12*V.1, 4*V.2]) sage: Q = V/W sage: Q._smith_form() ( @@ -946,11 +963,12 @@ def _smith_form(self): def base_ring(self): """ - Return the base ring of self. + Return the base ring of ``self``. EXAMPLES:: - sage: V = span([[1/2,1,1],[3/2,2,1],[0,0,1]],ZZ); W = V.span([2*V.0+4*V.1, 9*V.0+12*V.1, 4*V.2]) + sage: V = span([[1/2,1,1], [3/2,2,1], [0,0,1]], ZZ) + sage: W = V.span([2*V.0 + 4*V.1, 9*V.0 + 12*V.1, 4*V.2]) sage: Q = V/W sage: Q.base_ring() Integer Ring @@ -959,12 +977,12 @@ def base_ring(self): @cached_method def invariants(self, include_ones=False): - """ - Return the diagonal entries of the smith form of the relative + r""" + Return the diagonal entries of the Smith form of the relative matrix that defines ``self`` (see :meth:`._relative_matrix`) - padded with zeros, excluding 1's by default. Thus if v is the + padded with zeros, excluding 1's by default. Thus if ``v`` is the list of integers returned, then self is abstractly isomorphic to - the product of cyclic groups `Z/nZ` where `n` is in `v`. + the product of cyclic groups `\ZZ/n\ZZ` where `n` is in ``v``. INPUT: @@ -973,14 +991,15 @@ def invariants(self, include_ones=False): EXAMPLES:: - sage: V = span([[1/2,1,1],[3/2,2,1],[0,0,1]],ZZ); W = V.span([2*V.0+4*V.1, 9*V.0+12*V.1, 4*V.2]) + sage: V = span([[1/2,1,1], [3/2,2,1], [0,0,1]], ZZ) + sage: W = V.span([2*V.0 + 4*V.1, 9*V.0 + 12*V.1, 4*V.2]) sage: Q = V/W sage: Q.invariants() (4, 12) An example with 1 and 0 rows:: - sage: V = ZZ^3; W = V.span([[1,2,0],[0,1,0], [0,2,0]]); Q = V/W; Q + sage: V = ZZ^3; W = V.span([[1,2,0], [0,1,0], [0,2,0]]); Q = V/W; Q Finitely generated module V/W over Integer Ring with invariants (0) sage: Q.invariants() (0,) @@ -999,9 +1018,9 @@ def invariants(self, include_ones=False): def gens(self): """ - Returns tuple of elements `g_0,...,g_n` of self such that the module generated by - the gi is isomorphic to the direct sum of R/ei*R, where ei are the - invariants of self and R is the base ring. + Return tuple of elements `g_0,...,g_n` of ``self`` such that the module generated by + the `g_i` is isomorphic to the direct sum of `R/e_i R`, where `e_i` are the + invariants of ``self`` and `R` is the base ring. Note that these are not generally uniquely determined, and depending on how Smith normal form is implemented for the base ring, they may not @@ -1011,7 +1030,8 @@ def gens(self): EXAMPLES:: - sage: V = span([[1/2,1,1],[3/2,2,1],[0,0,1]],ZZ); W = V.span([2*V.0+4*V.1, 9*V.0+12*V.1, 4*V.2]) + sage: V = span([[1/2,1,1], [3/2,2,1], [0,0,1]], ZZ) + sage: W = V.span([2*V.0 + 4*V.1, 9*V.0 + 12*V.1, 4*V.2]) sage: Q = V/W sage: Q.gens() ((1, 0), (0, 1)) @@ -1023,11 +1043,12 @@ def gens(self): @cached_method def smith_form_gens(self): """ - Return a set of generators for self which are in Smith normal form. + Return a set of generators for ``self`` which are in Smith normal form. EXAMPLES:: - sage: V = span([[1/2,1,1],[3/2,2,1],[0,0,1]],ZZ); W = V.span([2*V.0+4*V.1, 9*V.0+12*V.1, 4*V.2]) + sage: V = span([[1/2,1,1], [3/2,2,1], [0,0,1]], ZZ) + sage: W = V.span([2*V.0 + 4*V.1, 9*V.0 + 12*V.1, 4*V.2]) sage: Q = V/W sage: Q.smith_form_gens() ((1, 0), (0, 1)) @@ -1054,7 +1075,7 @@ def gens_to_smith(self): r""" Return the transformation matrix from the user to Smith form generators. - To go in the other direction use :meth:`smith_to_gens`. + To go in the other direction, use :meth:`smith_to_gens`. OUTPUT: @@ -1062,9 +1083,8 @@ def gens_to_smith(self): EXAMPLES:: - sage: L2 = IntegralLattice(3 * matrix([[-2,0,0],[0,1,0],[0,0,-4]])) - sage: D = L2.discriminant_group().normal_form() - sage: D + sage: L2 = IntegralLattice(3 * matrix([[-2,0,0], [0,1,0], [0,0,-4]])) + sage: D = L2.discriminant_group().normal_form(); D # optional - sage.libs.pari sage.rings.padics Finite quadratic module over Integer Ring with invariants (3, 6, 12) Gram matrix of the quadratic form with values in Q/Z: [1/2 0 0 0 0] @@ -1072,14 +1092,13 @@ def gens_to_smith(self): [ 0 0 1/3 0 0] [ 0 0 0 1/3 0] [ 0 0 0 0 2/3] - sage: D.gens_to_smith() + sage: D.gens_to_smith() # optional - sage.libs.pari sage.rings.padics [0 3 0] [0 0 3] [0 4 0] [1 2 0] [0 0 4] - sage: T = D.gens_to_smith()*D.smith_to_gens() - sage: T + sage: T = D.gens_to_smith() * D.smith_to_gens(); T # optional - sage.libs.pari sage.rings.padics [ 3 0 3 0 0] [ 0 33 0 0 3] [ 4 0 4 0 0] @@ -1088,9 +1107,9 @@ def gens_to_smith(self): The matrix `T` now satisfies a certain congruence:: - sage: for i in range(T.nrows()): + sage: for i in range(T.nrows()): # optional - sage.libs.pari sage.rings.padics ....: T[:,i] = T[:,i] % D.gens()[i].order() - sage: T + sage: T # optional - sage.libs.pari sage.rings.padics [1 0 0 0 0] [0 1 0 0 0] [0 0 1 0 0] @@ -1107,7 +1126,7 @@ def smith_to_gens(self): r""" Return the transformation matrix from Smith form to user generators. - To go in the other direction use :meth:`gens_to_smith`. + To go in the other direction, use :meth:`gens_to_smith`. OUTPUT: @@ -1115,9 +1134,8 @@ def smith_to_gens(self): EXAMPLES:: - sage: L2 = IntegralLattice(3 * matrix([[-2,0,0],[0,1,0],[0,0,-4]])) - sage: D = L2.discriminant_group().normal_form() - sage: D + sage: L2 = IntegralLattice(3 * matrix([[-2,0,0], [0,1,0], [0,0,-4]])) + sage: D = L2.discriminant_group().normal_form(); D # optional - sage.libs.pari sage.rings.padics Finite quadratic module over Integer Ring with invariants (3, 6, 12) Gram matrix of the quadratic form with values in Q/Z: [1/2 0 0 0 0] @@ -1125,35 +1143,33 @@ def smith_to_gens(self): [ 0 0 1/3 0 0] [ 0 0 0 1/3 0] [ 0 0 0 0 2/3] - sage: D.smith_to_gens() + sage: D.smith_to_gens() # optional - sage.libs.pari sage.rings.padics [ 0 0 1 1 0] [ 1 0 1 0 0] [ 0 11 0 0 1] - sage: T = D.smith_to_gens()*D.gens_to_smith() - sage: T + sage: T = D.smith_to_gens() * D.gens_to_smith(); T # optional - sage.libs.pari sage.rings.padics [ 1 6 0] [ 0 7 0] [ 0 0 37] This matrix satisfies the congruence:: - sage: for i in range(T.ncols()): + sage: for i in range(T.ncols()): # optional - sage.libs.pari sage.rings.padics ....: T[:, i] = T[:, i] % D.smith_form_gens()[i].order() - sage: T + sage: T # optional - sage.libs.pari sage.rings.padics [1 0 0] [0 1 0] [0 0 1] We create some element of our FGP module:: - sage: x = D.linear_combination_of_smith_form_gens((1,2,3)) - sage: x + sage: x = D.linear_combination_of_smith_form_gens((1,2,3)); x # optional - sage.libs.pari sage.rings.padics (1, 2, 3) and want to know some (it is not unique) linear combination - of the user defined generators that is x:: + of the user defined generators that is ``x``:: - sage: x.vector() * D.smith_to_gens() + sage: x.vector() * D.smith_to_gens() # optional - sage.libs.pari sage.rings.padics (2, 33, 3, 1, 3) """ if self.base_ring() != ZZ: @@ -1175,7 +1191,7 @@ def smith_to_gens(self): def gens_vector(self, x, reduce=False): r""" - Return coordinates of x with respect to the generators. + Return coordinates of ``x`` with respect to the generators. INPUT: @@ -1191,7 +1207,7 @@ def gens_vector(self, x, reduce=False): sage: from sage.modules.fg_pid.fgp_module import FGP_Module_class sage: W = ZZ^3 - sage: V = W.span(matrix.diagonal([1/6,1/3,1/12])) + sage: V = W.span(matrix.diagonal([1/6, 1/3, 1/12])) sage: class FGP_with_gens(FGP_Module_class): ....: def __init__(self, V, W, gens): ....: FGP_Module_class.__init__(self, V, W) @@ -1205,16 +1221,14 @@ def gens_vector(self, x, reduce=False): ((0, 3, 0), (0, 0, 3), (0, 4, 0), (1, 2, 0), (0, 0, 8)) - We create some element of D:: + We create some element of ``D``:: - sage: x = D.linear_combination_of_smith_form_gens((1,2,3)) - sage: x + sage: x = D.linear_combination_of_smith_form_gens((1,2,3)); x (1, 2, 3) In our generators:: - sage: v = D.gens_vector(x) - sage: v + sage: v = D.gens_vector(x); v (2, 9, 3, 1, 33) The output can be further reduced:: @@ -1239,12 +1253,12 @@ def gens_vector(self, x, reduce=False): def coordinate_vector(self, x, reduce=False): """ - Return coordinates of x with respect to the optimized - representation of self. + Return coordinates of ``x`` with respect to the optimized + representation of ``self``. INPUT: - - ``x`` -- element of self + - ``x`` -- element of ``self`` - ``reduce`` -- (default: False); if ``True``, reduce coefficients modulo invariants; this is @@ -1257,7 +1271,8 @@ def coordinate_vector(self, x, reduce=False): EXAMPLES:: - sage: V = span([[1/4,0,0],[3/4,4,2],[0,0,2]],ZZ); W = V.span([4*V.0+12*V.1]) + sage: V = span([[1/4,0,0], [3/4,4,2], [0,0,2]], ZZ) + sage: W = V.span([4*V.0 + 12*V.1]) sage: Q = V/W; Q Finitely generated module V/W over Integer Ring with invariants (4, 0, 0) sage: Q.coordinate_vector(-Q.0) @@ -1274,7 +1289,8 @@ def coordinate_vector(self, x, reduce=False): TESTS:: - sage: V = span([[1/2,0,0],[3/2,2,1],[0,0,1]],ZZ); W = V.span([2*V.0+4*V.1, 9*V.0+12*V.1, 4*V.2]) + sage: V = span([[1/2,0,0], [3/2,2,1], [0,0,1]], ZZ) + sage: W = V.span([2*V.0 + 4*V.1, 9*V.0 + 12*V.1, 4*V.2]) sage: Q = V/W; Q Finitely generated module V/W over Integer Ring with invariants (4, 12) sage: Q.coordinate_vector(Q.0 - Q.1, reduce=True) @@ -1345,7 +1361,8 @@ def gen(self, i): EXAMPLES:: - sage: V = span([[1/2,1,1],[3/2,2,1],[0,0,1]],ZZ); W = V.span([2*V.0+4*V.1, 9*V.0+12*V.1, 4*V.2]) + sage: V = span([[1/2,1,1], [3/2,2,1], [0,0,1]], ZZ) + sage: W = V.span([2*V.0 + 4*V.1, 9*V.0 + 12*V.1, 4*V.2]) sage: Q = V/W; Q Finitely generated module V/W over Integer Ring with invariants (4, 12) sage: Q.gen(0) @@ -1368,7 +1385,7 @@ def gen(self, i): def smith_form_gen(self, i): """ - Return the i-th generator of ``self``. + Return the ``i``-th generator of ``self``. This is a separate method so we can freely override :meth:`gen` in derived classes. @@ -1379,8 +1396,8 @@ def smith_form_gen(self, i): EXAMPLES:: - sage: V = span([[1/2,1,1],[3/2,2,1],[0,0,1]],ZZ) - sage: W = V.span([2*V.0+4*V.1, 9*V.0+12*V.1, 4*V.2]) + sage: V = span([[1/2,1,1], [3/2,2,1], [0,0,1]], ZZ) + sage: W = V.span([2*V.0 + 4*V.1, 9*V.0 + 12*V.1, 4*V.2]) sage: Q = V/W; Q Finitely generated module V/W over Integer Ring with invariants (4, 12) sage: Q.smith_form_gen(0) @@ -1394,27 +1411,28 @@ def smith_form_gen(self, i): return v[i] def optimized(self): - """ - Return a module isomorphic to this one, but with V replaced by - a submodule of V such that the generators of ``self`` all lift - trivially to generators of V. Replace W by the intersection - of V and W. This has the advantage that V has small dimension + r""" + Return a module isomorphic to this one, but with `V` replaced by + a submodule of `V` such that the generators of ``self`` all lift + trivially to generators of `V`. Replace `W` by the intersection + of `V` and `W`. This has the advantage that `V` has small dimension and any homomorphism from ``self`` trivially extends to a - homomorphism from V. + homomorphism from `V`. OUTPUT: - - ``Q`` -- an optimized quotient V0/W0 with V0 a submodule of V - such that phi: V0/W0 --> V/W is an isomorphism + - ``Q`` -- an optimized quotient `V_0/W_0` with `V_0` a submodule of `V` + such that `\phi: V_0/W_0 \to V/W` is an isomorphism - - ``Z`` -- matrix such that if x is in ``self.V()`` and - c gives the coordinates of x in terms of the - basis for ``self.V()``, then c*Z is in V0 - and c*Z maps to x via phi above. + - ``Z`` -- matrix such that if `x` is in ``self.V()`` and + ``c`` gives the coordinates of `x` in terms of the + basis for ``self.V()``, then ``c*Z`` is in `V_0` + and ``c*Z`` maps to `x` via `\phi` above. EXAMPLES:: - sage: V = span([[1/2,1,1],[3/2,2,1],[0,0,1]],ZZ); W = V.span([2*V.0+4*V.1, 9*V.0+12*V.1, 4*V.2]) + sage: V = span([[1/2,1,1], [3/2,2,1], [0,0,1]], ZZ) + sage: W = V.span([2*V.0 + 4*V.1, 9*V.0 + 12*V.1, 4*V.2]) sage: Q = V/W sage: O, X = Q.optimized(); O Finitely generated module V/W over Integer Ring with invariants (4, 12) @@ -1469,7 +1487,7 @@ def optimized(self): def hom(self, im_gens, codomain=None, check=True): """ Homomorphism defined by giving the images of ``self.gens()`` in some - fixed fg R-module. + fixed finitely generated `R`-module. .. NOTE:: @@ -1480,16 +1498,19 @@ def hom(self, im_gens, codomain=None, check=True): INPUT: - ``im_gens`` -- a list of the images of ``self.gens()`` in some - R-module + `R`-module EXAMPLES:: - sage: V = span([[1/2,1,1],[3/2,2,1],[0,0,1]],ZZ); W = V.span([2*V.0+4*V.1, 9*V.0+12*V.1, 4*V.2]) + sage: V = span([[1/2,1,1], [3/2,2,1], [0,0,1]], ZZ) + sage: W = V.span([2*V.0 + 4*V.1, 9*V.0 + 12*V.1, 4*V.2]) sage: Q = V/W sage: phi = Q.hom([3*Q.1, Q.0]) sage: phi - Morphism from module over Integer Ring with invariants (4, 12) to module with invariants (4, 12) that sends the generators to [(0, 3), (1, 0)] + Morphism from module over Integer Ring with invariants (4, 12) + to module with invariants (4, 12) + that sends the generators to [(0, 3), (1, 0)] sage: phi(Q.0) (0, 3) sage: phi(Q.1) @@ -1499,13 +1520,16 @@ def hom(self, im_gens, codomain=None, check=True): This example illustrates creating a morphism to a free module. The free module is turned into an FGP module (i.e., quotient - V/W with W=0), and the morphism is constructed:: + `V/W` with `W=0`), and the morphism is constructed:: - sage: V = span([[1/2,0,0],[3/2,2,1],[0,0,1]],ZZ); W = V.span([2*V.0+4*V.1]) + sage: V = span([[1/2,0,0], [3/2,2,1], [0,0,1]], ZZ) + sage: W = V.span([2*V.0 + 4*V.1]) sage: Q = V/W; Q Finitely generated module V/W over Integer Ring with invariants (2, 0, 0) - sage: phi = Q.hom([0,V.0,V.1]); phi - Morphism from module over Integer Ring with invariants (2, 0, 0) to module with invariants (0, 0, 0) that sends the generators to [(0, 0, 0), (1, 0, 0), (0, 1, 0)] + sage: phi = Q.hom([0, V.0, V.1]); phi + Morphism from module over Integer Ring with invariants (2, 0, 0) + to module with invariants (0, 0, 0) + that sends the generators to [(0, 0, 0), (1, 0, 0), (0, 1, 0)] sage: phi.domain() Finitely generated module V/W over Integer Ring with invariants (2, 0, 0) sage: phi.codomain() @@ -1522,25 +1546,28 @@ def hom(self, im_gens, codomain=None, check=True): sage: A = (ZZ^2)/(ZZ^2); A Finitely generated module V/W over Integer Ring with invariants () sage: A.hom([]) - Morphism from module over Integer Ring with invariants () to module with invariants () that sends the generators to [] + Morphism from module over Integer Ring with invariants () + to module with invariants () + that sends the generators to [] sage: A.hom([]).codomain() is A True sage: B = (ZZ^3)/(ZZ^3) - sage: A.hom([],codomain=B) - Morphism from module over Integer Ring with invariants () to module with invariants () that sends the generators to [] - sage: phi = A.hom([],codomain=B); phi - Morphism from module over Integer Ring with invariants () to module with invariants () that sends the generators to [] + sage: phi = A.hom([], codomain=B); phi + Morphism from module over Integer Ring with invariants () + to module with invariants () + that sends the generators to [] sage: phi(A(0)) () sage: phi(A(0)) == B(0) True - A degenerate case:: sage: A = (ZZ^2)/(ZZ^2) sage: phi = A.hom([]); phi - Morphism from module over Integer Ring with invariants () to module with invariants () that sends the generators to [] + Morphism from module over Integer Ring with invariants () + to module with invariants () + that sends the generators to [] sage: phi(A(0)) () @@ -1548,17 +1575,16 @@ def hom(self, im_gens, codomain=None, check=True): below we try to send a generator of order 2 to an element of order 14:: - sage: V = span([[1/14,3/14],[0,1/2]],ZZ); W = ZZ^2 + sage: V = span([[1/14,3/14], [0,1/2]], ZZ); W = ZZ^2 sage: Q = V/W; Q Finitely generated module V/W over Integer Ring with invariants (2, 14) sage: Q.linear_combination_of_smith_form_gens([1,11]).additive_order() 14 - sage: f = Q.hom([Q.linear_combination_of_smith_form_gens([1,11]), Q.linear_combination_of_smith_form_gens([1,3])]); f + sage: f = Q.hom([Q.linear_combination_of_smith_form_gens([1,11]), + ....: Q.linear_combination_of_smith_form_gens([1,3])]); f Traceback (most recent call last): ... ValueError: phi must send optimized submodule of M.W() into N.W() - - """ if len(im_gens) == 0: # 0 map @@ -1590,14 +1616,14 @@ def hom(self, im_gens, codomain=None, check=True): def _hom_general(self, im_gens, check=True): """ Homomorphism defined by giving the images of ``self.gens()`` in some - fixed fg R-module. We do not assume that the generators given by + fixed finitely generated `R`-module. We do not assume that the generators given by ``self.gens()`` are the same as the Smith form generators, since this may not be true for a general derived class. INPUT: - ``im_gens`` - a Sequence object giving the images of ``self.gens()``, - whose universe is some fixed fg R-module + whose universe is some fixed finitely generated `R`-module EXAMPLES:: @@ -1615,7 +1641,9 @@ def _hom_general(self, im_gens, check=True): ... ValueError: Images do not determine a valid homomorphism sage: A.hom([B.0, B.0], B) # indirect doctest - Morphism from module over Integer Ring with invariants (3,) to module with invariants (3,) that sends the generators to [(1), (1)] + Morphism from module over Integer Ring with invariants (3,) + to module with invariants (3,) + that sends the generators to [(1), (1)] """ m = self.ngens() @@ -1633,12 +1661,12 @@ def _hom_general(self, im_gens, check=True): def _hom_from_smith(self, im_smith_gens, check=True): """ Homomorphism defined by giving the images of the Smith-form generators - of self in some fixed fg R-module. + of ``self`` in some fixed finitely generated `R`-module. INPUT: - ``im_gens`` -- a Sequence object giving the images of the Smith-form - generators of self, whose universe is some fixed fg R-module + generators of ``self``, whose universe is some fixed finitely generated `R`-module EXAMPLES:: @@ -1652,7 +1680,9 @@ def _hom_from_smith(self, im_smith_gens, check=True): (1) sage: B = ZZ**1 / span([[3]], ZZ) sage: A._hom_from_smith(Sequence([B.0])) - Morphism from module over Integer Ring with invariants (3,) to module with invariants (3,) that sends the generators to [(1), (1)] + Morphism from module over Integer Ring with invariants (3,) + to module with invariants (3,) + that sends the generators to [(1), (1)] """ if len(im_smith_gens) != len(self.smith_form_gens()): raise ValueError("im_gens must have length the same as self.smith_form_gens()") @@ -1670,16 +1700,22 @@ def _Hom_(self, N, category=None): """ EXAMPLES:: - sage: V = span([[1/2,0,0],[3/2,2,1],[0,0,1]],ZZ); W = V.span([V.0+2*V.1, 9*V.0+2*V.1, 4*V.2]) + sage: V = span([[1/2,0,0], [3/2,2,1], [0,0,1]], ZZ); W = V.span([V.0 + 2*V.1, 9*V.0 + 2*V.1, 4*V.2]) sage: Q = V/W sage: Q.Hom(Q) # indirect doctest - Set of Morphisms from Finitely generated module V/W over Integer Ring with invariants (4, 16) to Finitely generated module V/W over Integer Ring with invariants (4, 16) in Category of modules over Integer Ring + Set of Morphisms + from Finitely generated module V/W over Integer Ring with invariants (4, 16) + to Finitely generated module V/W over Integer Ring with invariants (4, 16) + in Category of modules over Integer Ring sage: M = V/V.zero_submodule() sage: H = M.Hom(Q); H - Set of Morphisms from Finitely generated module V/W over Integer Ring with invariants (0, 0, 0) to Finitely generated module V/W over Integer Ring with invariants (4, 16) in Category of modules over Integer Ring - sage: Hom(M,Q) is H + Set of Morphisms + from Finitely generated module V/W over Integer Ring with invariants (0, 0, 0) + to Finitely generated module V/W over Integer Ring with invariants (4, 16) + in Category of modules over Integer Ring + sage: Hom(M, Q) is H True - sage: type(Hom(M,Q)) + sage: type(Hom(M, Q)) sage: H.category() Category of homsets of modules over Integer Ring @@ -1692,7 +1728,10 @@ def _Hom_(self, N, category=None): sage: V = ZZ^2 sage: W = V.quotient(V.span([[1, 1]])) sage: H = W.Hom(QQ); H - Set of Morphisms from Finitely generated module V/W over Integer Ring with invariants (0) to Rational Field in Category of commutative additive groups + Set of Morphisms + from Finitely generated module V/W over Integer Ring with invariants (0) + to Rational Field + in Category of commutative additive groups sage: type(H) @@ -1703,14 +1742,15 @@ def _Hom_(self, N, category=None): def random_element(self, *args, **kwds): """ - Create a random element of ``self`` = V/W, by creating a random element of V and - reducing it modulo W. + Create a random element of ``self`` = `V/W`, by creating a random element of `V` and + reducing it modulo `W`. - All arguments are passed onto the method :meth:`random_element` of V. + All arguments are passed on to the method :meth:`random_element` of `V`. EXAMPLES:: - sage: V = span([[1/2,1,1],[3/2,2,1],[0,0,1]],ZZ); W = V.span([2*V.0+4*V.1, 9*V.0+12*V.1, 4*V.2]) + sage: V = span([[1/2,1,1], [3/2,2,1], [0,0,1]], ZZ) + sage: W = V.span([2*V.0 + 4*V.1, 9*V.0 + 12*V.1, 4*V.2]) sage: Q = V/W sage: Q.random_element().parent() is Q True @@ -1728,7 +1768,7 @@ def cardinality(self): EXAMPLES:: - sage: V = ZZ^2; W = V.span([[1,2],[3,4]]); A = V/W; A + sage: V = ZZ^2; W = V.span([[1,2], [3,4]]); A = V/W; A Finitely generated module V/W over Integer Ring with invariants (2) sage: A.cardinality() 2 @@ -1738,10 +1778,10 @@ def cardinality(self): +Infinity sage: V = QQ^2; W = V.span([[1,2]]); A = V/W; A Vector space quotient V/W of dimension 1 over Rational Field where - V: Vector space of dimension 2 over Rational Field - W: Vector space of degree 2 and dimension 1 over Rational Field - Basis matrix: - [1 2] + V: Vector space of dimension 2 over Rational Field + W: Vector space of degree 2 and dimension 1 over Rational Field + Basis matrix: + [1 2] sage: A.cardinality() +Infinity """ @@ -1773,12 +1813,13 @@ def __iter__(self): EXAMPLES:: - sage: V = span([[1/2,0,0],[3/2,2,1],[0,0,1]],ZZ); W = V.span([V.0+2*V.1, 4*V.0+2*V.1, 4*V.2]) + sage: V = span([[1/2,0,0], [3/2,2,1], [0,0,1]], ZZ); W = V.span([V.0 + 2*V.1, 4*V.0 + 2*V.1, 4*V.2]) sage: Q = V/W; Q Finitely generated module V/W over Integer Ring with invariants (2, 12) sage: z = list(V/W) sage: z - [(0, 0), (0, 1), (0, 2), (0, 3), (0, 4), (0, 5), (0, 6), (0, 7), (0, 8), (0, 9), (0, 10), (0, 11), (1, 0), (1, 1), (1, 2), (1, 3), (1, 4), (1, 5), (1, 6), (1, 7), (1, 8), (1, 9), (1, 10), (1, 11)] + [(0, 0), (0, 1), (0, 2), (0, 3), (0, 4), (0, 5), (0, 6), (0, 7), (0, 8), (0, 9), (0, 10), (0, 11), + (1, 0), (1, 1), (1, 2), (1, 3), (1, 4), (1, 5), (1, 6), (1, 7), (1, 8), (1, 9), (1, 10), (1, 11)] sage: len(z) 24 @@ -1811,9 +1852,9 @@ def construction(self): sage: T1 = A1 / B1 sage: T1.construction() (QuotientModuleFunctor, - Free module of degree 2 and rank 1 over Integer Ring - Echelon basis matrix: - [1 0]) + Free module of degree 2 and rank 1 over Integer Ring + Echelon basis matrix: + [1 0]) TESTS:: @@ -1838,12 +1879,13 @@ def is_finite(self): EXAMPLES:: - sage: V = span([[1/2,0,0],[3/2,2,1],[0,0,1]],ZZ); W = V.span([V.0+2*V.1, 9*V.0+2*V.1, 4*V.2]) + sage: V = span([[1/2,0,0], [3/2,2,1], [0,0,1]], ZZ) + sage: W = V.span([V.0 + 2*V.1, 9*V.0 + 2*V.1, 4*V.2]) sage: Q = V/W; Q Finitely generated module V/W over Integer Ring with invariants (4, 16) sage: Q.is_finite() True - sage: Q = V/V.zero_submodule(); Q + sage: Q = V / V.zero_submodule(); Q Finitely generated module V/W over Integer Ring with invariants (0, 0, 0) sage: Q.is_finite() False @@ -1858,20 +1900,21 @@ def annihilator(self): EXAMPLES:: - sage: V = span([[1/2,0,0],[3/2,2,1],[0,0,1]],ZZ); W = V.span([V.0+2*V.1, 9*V.0+2*V.1, 4*V.2]) + sage: V = span([[1/2,0,0], [3/2,2,1], [0,0,1]], ZZ) + sage: W = V.span([V.0 + 2*V.1, 9*V.0 + 2*V.1, 4*V.2]) sage: Q = V/W; Q.annihilator() Principal ideal (16) of Integer Ring sage: Q.annihilator().gen() 16 - sage: Q = V/V.span([V.0]); Q + sage: Q = V / V.span([V.0]); Q Finitely generated module V/W over Integer Ring with invariants (0, 0) sage: Q.annihilator() Principal ideal (0) of Integer Ring We check that :trac:`22720` is resolved:: - sage: H=AdditiveAbelianGroup([]) + sage: H = AdditiveAbelianGroup([]) sage: H.annihilator() Principal ideal (1) of Integer Ring """ @@ -1887,7 +1930,7 @@ def ngens(self): r""" Return the number of generators of ``self``. - (Note for developers: This is just the length of :meth:`.gens`, rather + (Note for developers: This is just the length of :meth:`gens`, rather than of the minimal set of generators as returned by :meth:`.smith_form_gens`; these are the same in the :class:`~sage.modules.fg_pid.fgp_module.FGP_Module_class`, but not @@ -1895,7 +1938,7 @@ def ngens(self): EXAMPLES:: - sage: A = (ZZ**2) / span([[4,0],[0,3]], ZZ) + sage: A = (ZZ**2) / span([[4,0], [0,3]], ZZ) sage: A.ngens() 1 @@ -1913,7 +1956,7 @@ def __hash__(self): EXAMPLES:: - sage: A = (ZZ**2) / span([[4,0],[0,3]], ZZ) + sage: A = (ZZ**2) / span([[4,0], [0,3]], ZZ) sage: hash(A) == hash(((2, ZZ), ((4, 0), (0, 3)))) True """ @@ -1950,7 +1993,7 @@ def random_fgp_module(n, R=ZZ, finite=False): - ``R`` -- base ring (default: ``ZZ``) - - ``finite`` -- bool (default: ``True``); if True, make the random module finite. + - ``finite`` -- bool (default: ``True``); if True, make the random module finite EXAMPLES:: diff --git a/src/sage/modules/free_quadratic_module_integer_symmetric.py b/src/sage/modules/free_quadratic_module_integer_symmetric.py index 7d7c87db87f..31eda7e683a 100644 --- a/src/sage/modules/free_quadratic_module_integer_symmetric.py +++ b/src/sage/modules/free_quadratic_module_integer_symmetric.py @@ -59,9 +59,7 @@ from sage.matrix.constructor import matrix from sage.structure.element import is_Matrix from sage.arith.misc import gcd -from sage.combinat.root_system.cartan_matrix import CartanMatrix from sage.misc.cachefunc import cached_method -from sage.quadratic_forms.quadratic_form import QuadraticForm ############################################################################### # @@ -240,6 +238,7 @@ def IntegralLattice(data, basis=None): elif data == "U" or data == "H": inner_product_matrix = matrix([[0,1],[1,0]]) else: + from sage.combinat.root_system.cartan_matrix import CartanMatrix inner_product_matrix = CartanMatrix(data) if basis is None: basis = matrix.identity(ZZ, inner_product_matrix.ncols()) @@ -728,7 +727,7 @@ def is_even(self): EXAMPLES:: - sage: G = Matrix(ZZ,2,2,[-1,1,1,2]) + sage: G = Matrix(ZZ, 2, 2, [-1,1,1,2]) sage: L = IntegralLattice(G) sage: L.is_even() False @@ -752,8 +751,7 @@ def dual_lattice(self): EXAMPLES:: sage: L = IntegralLattice("A2") - sage: Ldual=L.dual_lattice() - sage: Ldual + sage: Ldual = L.dual_lattice(); Ldual Free module of degree 2 and rank 2 over Integer Ring Echelon basis matrix: [1/3 2/3] @@ -781,7 +779,7 @@ def discriminant_group(self, s=0): EXAMPLES:: - sage: L = IntegralLattice(Matrix(ZZ,2,2,[2,1,1,-2])*2) + sage: L = IntegralLattice(Matrix(ZZ, 2, 2, [2,1,1,-2]) * 2) sage: L.discriminant_group() Finite quadratic module over Integer Ring with invariants (2, 10) Gram matrix of the quadratic form with values in Q/2Z: @@ -849,7 +847,6 @@ def signature_pair(self): EXAMPLES:: - sage: A2 = IntegralLattice("A2") sage: A2.signature_pair() (2, 0) @@ -907,12 +904,12 @@ def is_primitive(self, M): True sage: U.is_primitive(L2) True - sage: U.is_primitive(L1+L2) + sage: U.is_primitive(L1 + L2) False We can also compute the index:: - sage: (L1+L2).index_in(U) + sage: (L1 + L2).index_in(U) 2 """ return (gcd((self/M).invariants()) == 0) @@ -928,7 +925,7 @@ def orthogonal_complement(self, M): EXAMPLES:: - sage: H5 = Matrix(ZZ,2,[2,1,1,-2]) + sage: H5 = Matrix(ZZ, 2, [2,1,1,-2]) sage: L = IntegralLattice(H5) sage: S = L.span([vector([1,1])]) sage: L.orthogonal_complement(S) @@ -940,7 +937,7 @@ def orthogonal_complement(self, M): [ 1 -2] sage: L = IntegralLattice(2) - sage: L.orthogonal_complement([vector(ZZ,[1,0])]) + sage: L.orthogonal_complement([vector(ZZ, [1,0])]) Lattice of degree 2 and rank 1 over Integer Ring Basis matrix: [0 1] @@ -969,8 +966,7 @@ def sublattice(self, basis): EXAMPLES:: sage: U = IntegralLattice("U") - sage: S = U.sublattice([vector([1,1])]) - sage: S + sage: S = U.sublattice([vector([1,1])]); S Lattice of degree 2 and rank 1 over Integer Ring Basis matrix: [1 1] @@ -1005,7 +1001,7 @@ def overlattice(self, gens): EXAMPLES:: - sage: L = IntegralLattice(Matrix(ZZ,2,2,[2,0,0,2])) + sage: L = IntegralLattice(Matrix(ZZ, 2, 2, [2,0,0,2])) sage: M = L.overlattice([vector([1,1])/2]) sage: M.gram_matrix() [1 1] @@ -1167,8 +1163,7 @@ def orthogonal_group(self, gens=None, is_finite=None): EXAMPLES:: sage: A4 = IntegralLattice("A4") - sage: Aut = A4.orthogonal_group() - sage: Aut + sage: Aut = A4.orthogonal_group(); Aut Group of isometries with 4 generators ( [0 0 0 1] [-1 -1 -1 0] [ 1 0 0 0] [ 1 0 0 0] [0 0 1 0] [ 0 0 0 -1] [-1 -1 -1 -1] [ 0 1 0 0] @@ -1179,15 +1174,14 @@ def orthogonal_group(self, gens=None, is_finite=None): The group acts from the right on the lattice and its discriminant group:: sage: x = A4.an_element() - sage: g = Aut.an_element() - sage: g + sage: g = Aut.an_element(); g [-1 -1 -1 0] [ 0 0 1 0] [ 0 0 -1 -1] [ 0 1 1 1] sage: x*g (-1, -1, -1, 0) - sage: (x*g).parent()==A4 + sage: (x*g).parent() == A4 True sage: (g*x).parent() Vector space of dimension 4 over Rational Field @@ -1207,7 +1201,7 @@ def orthogonal_group(self, gens=None, is_finite=None): The lattice can live in a larger ambient space:: - sage: A2 = IntegralLattice(matrix.identity(3),Matrix(ZZ,2,3,[1,-1,0,0,1,-1])) + sage: A2 = IntegralLattice(matrix.identity(3), Matrix(ZZ, 2, 3, [1,-1,0,0,1,-1])) sage: A2.orthogonal_group() Group of isometries with 2 generators ( [ 2/3 2/3 -1/3] [1 0 0] @@ -1217,7 +1211,7 @@ def orthogonal_group(self, gens=None, is_finite=None): It can be negative definite as well:: - sage: A2m = IntegralLattice(-Matrix(ZZ,2,[2,1,1,2])) + sage: A2m = IntegralLattice(-Matrix(ZZ, 2, [2,1,1,2])) sage: G = A2m.orthogonal_group() sage: G.order() 12 @@ -1225,16 +1219,17 @@ def orthogonal_group(self, gens=None, is_finite=None): If the lattice is indefinite, sage does not know how to compute generators. Can you teach it?:: - sage: U = IntegralLattice(Matrix(ZZ,2,[0,1,1,0])) + sage: U = IntegralLattice(Matrix(ZZ, 2, [0,1,1,0])) sage: U.orthogonal_group() Traceback (most recent call last): ... - NotImplementedError: currently, we can only compute generators for orthogonal groups over definite lattices. + NotImplementedError: currently, we can only compute generators + for orthogonal groups over definite lattices. But we can define subgroups:: - sage: S = IntegralLattice(Matrix(ZZ,2,[2, 3, 3, 2])) - sage: f = Matrix(ZZ,2,[0,1,-1,3]) + sage: S = IntegralLattice(Matrix(ZZ, 2, [2, 3, 3, 2])) + sage: f = Matrix(ZZ, 2, [0,1,-1,3]) sage: S.orthogonal_group([f]) Group of isometries with 1 generator ( [ 0 1] @@ -1245,7 +1240,7 @@ def orthogonal_group(self, gens=None, is_finite=None): We can handle the trivial group:: - sage: S = IntegralLattice(Matrix(ZZ,2,[2, 3, 3, 2])) + sage: S = IntegralLattice(Matrix(ZZ, 2, [2, 3, 3, 2])) sage: S.orthogonal_group([]) Group of isometries with 1 generator ( [1 0] @@ -1323,14 +1318,12 @@ def tensor_product(self, other, discard_basis=False): - ``other`` -- an integral lattice - ``discard_basis`` -- a boolean (default: ``False``). If ``True``, then the lattice - returned is equipped with the standard basis. + returned is equipped with the standard basis. EXAMPLES:: sage: L = IntegralLattice("D3", [[1,-1,0], [0,1,-1]]) - sage: L1 = L.tensor_product(L) - sage: L2 = L.tensor_product(L, True) - sage: L1 + sage: L1 = L.tensor_product(L); L1 Lattice of degree 9 and rank 4 over Integer Ring Basis matrix: [ 1 -1 0 -1 1 0 0 0 0] @@ -1352,7 +1345,7 @@ def tensor_product(self, other, discard_basis=False): [-12 24 4 -8] [-12 4 24 -8] [ 4 -8 -8 16] - sage: L2 + sage: L2 = L.tensor_product(L, True); L2 Lattice of degree 4 and rank 4 over Integer Ring Standard basis Inner product matrix: @@ -1384,12 +1377,12 @@ def quadratic_form(self): EXAMPLES:: sage: L = IntegralLattice("A2") - sage: q = L.quadratic_form() - sage: q + sage: q = L.quadratic_form(); q Quadratic form in 2 variables over Integer Ring with coefficients: [ 2 -2 ] [ * 2 ] """ + from sage.quadratic_forms.quadratic_form import QuadraticForm return QuadraticForm(2 * self.gram_matrix()) @cached_method @@ -1456,8 +1449,8 @@ def LLL(self): sage: L = IntegralLattice('A2') sage: L.lll() == L True - sage: G = matrix(ZZ,3,[0,1,0, 1,0,0, 0,0,7]) - sage: V = matrix(ZZ,3,[-14,-15,-15, -4,1,16, -5,-5,-4]) + sage: G = matrix(ZZ, 3, [0,1,0, 1,0,0, 0,0,7]) + sage: V = matrix(ZZ, 3, [-14,-15,-15, -4,1,16, -5,-5,-4]) sage: L = IntegralLattice(V * G * V.T) sage: L.lll().gram_matrix() [0 0 1] @@ -1491,7 +1484,7 @@ def short_vectors(self, n, **kwargs): INPUT: - ``n`` -- an integer - - further key word arguments are passed on to + - further keyword arguments are passed on to :meth:`sage.quadratic_forms.short_vector_list_up_to_length`. OUTPUT: @@ -1512,6 +1505,7 @@ def short_vectors(self, n, **kwargs): e = 2 if m != 0: e = -2 + from sage.quadratic_forms.quadratic_form import QuadraticForm q = QuadraticForm(e * self.gram_matrix()) short = q.short_vector_list_up_to_length(n, *kwargs) return [[self(v * self.basis_matrix()) for v in L] for L in short] @@ -1538,8 +1532,7 @@ def twist(self, s, discard_basis=False): [-3 6 -3 0] [ 0 -3 6 -3] [ 0 0 -3 6] - sage: L = IntegralLattice(3,[[2,1,0],[0,1,1]]) - sage: L + sage: L = IntegralLattice(3, [[2,1,0], [0,1,1]]); L Lattice of degree 3 and rank 2 over Integer Ring Basis matrix: [2 1 0] @@ -1581,8 +1574,7 @@ def local_modification(M, G, p, check=True): - ``M`` -- a `\ZZ_p`-maximal lattice - - ``G`` -- the gram matrix of a lattice - isomorphic to `M` over `\QQ_p` + - ``G`` -- the gram matrix of a lattice isomorphic to `M` over `\QQ_p` - ``p`` -- a prime number diff --git a/src/sage/modules/torsion_quadratic_module.py b/src/sage/modules/torsion_quadratic_module.py index aba3df2211c..0f1a92d8c56 100644 --- a/src/sage/modules/torsion_quadratic_module.py +++ b/src/sage/modules/torsion_quadratic_module.py @@ -47,7 +47,7 @@ def TorsionQuadraticForm(q): EXAMPLES:: - sage: q1 = Matrix(QQ,2,[1,1/2,1/2,1]) + sage: q1 = Matrix(QQ, 2, [1,1/2,1/2,1]) sage: TorsionQuadraticForm(q1) Finite quadratic module over Integer Ring with invariants (2, 2) Gram matrix of the quadratic form with values in Q/2Z: @@ -57,7 +57,7 @@ def TorsionQuadraticForm(q): In the following example the quadratic form is degenerate. But the bilinear form is still non-degenerate:: - sage: q2 = diagonal_matrix(QQ,[1/4,1/3]) + sage: q2 = diagonal_matrix(QQ, [1/4,1/3]) sage: TorsionQuadraticForm(q2) Finite quadratic module over Integer Ring with invariants (12,) Gram matrix of the quadratic form with values in Q/Z: @@ -112,7 +112,7 @@ class TorsionQuadraticModuleElement(FGP_Element): sage: from sage.modules.torsion_quadratic_module import TorsionQuadraticModule sage: V = span([[1/2,1,1], [3/2,2,1], [0,0,1]], ZZ) sage: b = V.basis() - sage: W = V.span([2*b[0]+4*b[1], 9*b[0]+12*b[1], 4*b[2]]) + sage: W = V.span([2*b[0] + 4*b[1], 9*b[0] + 12*b[1], 4*b[2]]) sage: Q = TorsionQuadraticModule(V, W) sage: x = Q(b[0] - b[1]) sage: TestSuite(x).run() @@ -132,10 +132,9 @@ def _mul_(self, other): sage: V = (1/2)*ZZ^2; W = ZZ^2 sage: T = TorsionQuadraticModule(V, W) sage: g = T.gens() - sage: x = g[0] - sage: y = g[0] + g[1] - sage: x + sage: x = g[0]; x (1, 0) + sage: y = g[0] + g[1] sage: x*y 1/4 @@ -154,7 +153,7 @@ def _mul_(self, other): def quadratic_product(self): r""" - Compute the quadratic_product of ``self``. + Compute the quadratic product of ``self``. OUTPUT: @@ -190,7 +189,7 @@ class TorsionQuadraticModule(FGP_Module_class, CachedRepresentation): r""" Finite quotients with a bilinear and a quadratic form. - Let `V` be a symmetric FreeQuadraticModule and `W \subseteq V` a + Let `V` be a symmetric :class:`FreeQuadraticModule` and `W \subseteq V` a submodule of the same rank as `V`. The quotient `V / W` is a torsion quadratic module. It inherits a bilinear form `b` and a quadratic form `q`. @@ -218,8 +217,7 @@ class TorsionQuadraticModule(FGP_Module_class, CachedRepresentation): sage: from sage.modules.torsion_quadratic_module import TorsionQuadraticModule sage: V = FreeModule(ZZ, 3) - sage: T = TorsionQuadraticModule(V, 5*V) - sage: T + sage: T = TorsionQuadraticModule(V, 5*V); T Finite quadratic module over Integer Ring with invariants (5, 5, 5) Gram matrix of the quadratic form with values in Q/5Z: [1 0 0] @@ -306,8 +304,8 @@ def _repr_(self): EXAMPLES:: sage: from sage.modules.torsion_quadratic_module import TorsionQuadraticModule - sage: V = FreeModule(ZZ,3) - sage: T = TorsionQuadraticModule(V, 5*V,modulus=1) + sage: V = FreeModule(ZZ, 3) + sage: T = TorsionQuadraticModule(V, 5*V, modulus=1) sage: T Finite quadratic module over Integer Ring with invariants (5, 5, 5) Gram matrix of the quadratic form with values in Q/Z: @@ -344,13 +342,13 @@ def _module_constructor(self, V, W, check=False): sage: from sage.modules.torsion_quadratic_module import TorsionQuadraticModule sage: V = span([[1/2,1,1], [3/2,2,1], [0,0,1]], ZZ) sage: b = V.basis() - sage: W = V.span([2*b[0]+4*b[1], 9*b[0]+12*b[1], 4*b[2]]) + sage: W = V.span([2*b[0] + 4*b[1], 9*b[0] + 12*b[1], 4*b[2]]) sage: Q = TorsionQuadraticModule(V, W); Q Finite quadratic module over Integer Ring with invariants (4, 12) Gram matrix of the quadratic form with values in Q/(1/4)Z: [0 0] [0 0] - sage: Q._module_constructor(V,W) + sage: Q._module_constructor(V, W) Finite quadratic module over Integer Ring with invariants (4, 12) Gram matrix of the quadratic form with values in Q/(1/4)Z: [0 0] @@ -439,7 +437,7 @@ def brown_invariant(self): We require the quadratic form to be defined modulo `2 \ZZ`:: sage: from sage.modules.torsion_quadratic_module import TorsionQuadraticModule - sage: V = FreeQuadraticModule(ZZ,3,matrix.identity(3)) + sage: V = FreeQuadraticModule(ZZ, 3, matrix.identity(3)) sage: T = TorsionQuadraticModule((1/10)*V, V) sage: T.brown_invariant() Traceback (most recent call last): @@ -546,7 +544,7 @@ def genus(self, signature_pair): r""" Return the genus defined by ``self`` and the ``signature_pair``. - If no such genus exists, raise a ``ValueError``. + If no such genus exists, raise a :class:`ValueError`. REFERENCES: @@ -554,24 +552,24 @@ def genus(self, signature_pair): EXAMPLES:: - sage: L = IntegralLattice("D4").direct_sum(IntegralLattice("A2")) - sage: D = L.discriminant_group() - sage: genus = D.genus(L.signature_pair()) - sage: genus + sage: L = IntegralLattice("D4").direct_sum(IntegralLattice("A2")) # optional - sage.combinat + sage: D = L.discriminant_group() # optional - sage.combinat + sage: genus = D.genus(L.signature_pair()) # optional - sage.combinat sage.libs.pari + sage: genus # optional - sage.combinat sage.libs.pari Genus of None Signature: (6, 0) Genus symbol at 2: 1^4:2^-2 Genus symbol at 3: 1^-5 3^-1 - sage: genus == L.genus() + sage: genus == L.genus() # optional - sage.combinat sage.libs.pari True Let `H` be an even unimodular lattice of signature `(9, 1)`. Then `L = D_4 + A_2` is primitively embedded in `H`. We compute the discriminant form of the orthogonal complement of `L` in `H`:: - sage: DK = D.twist(-1) - sage: DK + sage: DK = D.twist(-1) # optional - sage.combinat sage.libs.pari + sage: DK # optional - sage.combinat sage.libs.pari Finite quadratic module over Integer Ring with invariants (2, 6) Gram matrix of the quadratic form with values in Q/2Z: [ 1 1/2] @@ -580,7 +578,7 @@ def genus(self, signature_pair): We know that `K` has signature `(5, 1)` and thus we can compute the genus of `K` as:: - sage: DK.genus((3,1)) + sage: DK.genus((3,1)) # optional - sage.combinat sage.libs.pari Genus of None Signature: (3, 1) @@ -592,7 +590,7 @@ def genus(self, signature_pair): sage: L = IntegralLattice(matrix.diagonal(range(1,5))) sage: D = L.discriminant_group() - sage: D.genus((4,0)) + sage: D.genus((4,0)) # optional - sage.libs.pari Genus of None Signature: (4, 0) @@ -601,20 +599,20 @@ def genus(self, signature_pair): TESTS:: - sage: L.genus() == D.genus((4,0)) + sage: L.genus() == D.genus((4,0)) # optional - sage.libs.pari True - sage: D.genus((1,0)) + sage: D.genus((1,0)) # optional - sage.libs.pari Traceback (most recent call last): ... ValueError: this discriminant form and signature do not define a genus A systematic test of lattices of small ranks and determinants:: - sage: from sage.quadratic_forms.genera.genus import genera - sage: signatures = [(1,0),(1,1),(1,2),(3,0),(0,4)] - sage: dets = range(1,33) - sage: genera = flatten([genera(s, d, even=False) for d in dets for s in signatures]) # long time - sage: all(g == g.discriminant_form().genus(g.signature_pair()) for g in genera) # long time + sage: from sage.quadratic_forms.genera.genus import genera # optional - sage.libs.pari + sage: signatures = [(1,0), (1,1), (1,2), (3,0), (0,4)] # optional - sage.libs.pari + sage: dets = range(1, 33) # optional - sage.libs.pari + sage: genera = flatten([genera(s, d, even=False) for d in dets for s in signatures]) # long time # optional - sage.libs.pari + sage: all(g == g.discriminant_form().genus(g.signature_pair()) for g in genera) # long time # optional - sage.libs.pari True """ from sage.quadratic_forms.genera.genus import (Genus_Symbol_p_adic_ring, @@ -752,12 +750,13 @@ def is_genus(self, signature_pair, even=True): INPUT: - - signature_pair -- a tuple of non negative integers ``(s_plus, s_minus)`` - - even -- bool (default: ``True``) + - ``signature_pair`` -- a tuple of non negative integers ``(s_plus, s_minus)`` + - ``even`` -- bool (default: ``True``) EXAMPLES:: - sage: L = IntegralLattice("D4").direct_sum(IntegralLattice(3 * Matrix(ZZ,2,[2,1,1,2]))) + sage: L3 = IntegralLattice(3 * Matrix(ZZ, 2, [2,1,1,2])) + sage: L = IntegralLattice("D4").direct_sum(L3) sage: D = L.discriminant_group() sage: D.is_genus((6,0)) True @@ -827,8 +826,8 @@ def orthogonal_group(self, gens=None, check=False): INPUT: - ``gens`` -- a list of generators, for instance square matrices, - something that acts on ``self``, or an automorphism - of the underlying abelian group + something that acts on ``self``, or an automorphism + of the underlying abelian group - ``check`` -- perform additional checks on the generators EXAMPLES: @@ -836,37 +835,37 @@ def orthogonal_group(self, gens=None, check=False): You can provide generators to obtain a subgroup of the full orthogonal group:: sage: D = TorsionQuadraticForm(matrix.identity(2)/2) - sage: f = matrix(2,[0,1,1,0]) - sage: D.orthogonal_group(gens=[f]).order() + sage: f = matrix(2, [0,1,1,0]) + sage: D.orthogonal_group(gens=[f]).order() # optional - sage.groups 2 If no generators are given a slow brute force approach is used to calculate the full orthogonal group:: sage: D = TorsionQuadraticForm(matrix.identity(3)/2) - sage: OD = D.orthogonal_group() - sage: OD.order() + sage: OD = D.orthogonal_group() # optional - sage.groups + sage: OD.order() # optional - sage.groups 6 - sage: fd = D.hom([D.1,D.0,D.2]) - sage: OD(fd) + sage: fd = D.hom([D.1, D.0, D.2]) + sage: OD(fd) # optional - sage.groups [0 1 0] [1 0 0] [0 0 1] We compute the kernel of the action of the orthogonal group of `L` on the discriminant group:: - sage: L = IntegralLattice('A4') - sage: O = L.orthogonal_group() - sage: D = L.discriminant_group() - sage: Obar = D.orthogonal_group(O.gens()) - sage: O.order() + sage: L = IntegralLattice('A4') # optional - sage.combinat + sage: O = L.orthogonal_group() # optional - sage.combinat sage.groups + sage: D = L.discriminant_group() # optional - sage.combinat sage.groups + sage: Obar = D.orthogonal_group(O.gens()) # optional - sage.combinat sage.groups + sage: O.order() # optional - sage.combinat sage.groups 240 - sage: Obar.order() + sage: Obar.order() # optional - sage.combinat sage.groups 2 - sage: phi = O.hom(Obar.gens()) - sage: phi.kernel().order() + sage: phi = O.hom(Obar.gens()) # optional - sage.combinat sage.groups + sage: phi.kernel().order() # optional - sage.combinat sage.groups 120 """ - from sage.groups.fqf_orthogonal import FqfOrthogonalGroup,_isom_fqf + from sage.groups.fqf_orthogonal import FqfOrthogonalGroup, _isom_fqf from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap ambient = AbelianGroupGap(self.invariants()).aut() @@ -956,7 +955,7 @@ def normal_form(self, partial=False): or `u p^n`. If `p = 2` is even, then the normal form consists of - 1 x 1 blocks of the form + `1 \times 1` blocks of the form .. MATH:: @@ -981,7 +980,7 @@ def normal_form(self, partial=False): INPUT: - - partial - bool (default: ``False``) return only a partial normal form + - ``partial`` - bool (default: ``False``) return only a partial normal form; it is not unique but still useful to extract invariants OUTPUT: @@ -990,13 +989,13 @@ def normal_form(self, partial=False): EXAMPLES:: - sage: L1=IntegralLattice(matrix([[-2,0,0],[0,1,0],[0,0,4]])) + sage: L1 = IntegralLattice(matrix([[-2,0,0], [0,1,0], [0,0,4]])) sage: L1.discriminant_group().normal_form() Finite quadratic module over Integer Ring with invariants (2, 4) Gram matrix of the quadratic form with values in Q/Z: [1/2 0] [ 0 1/4] - sage: L2=IntegralLattice(matrix([[-2,0,0],[0,1,0],[0,0,-4]])) + sage: L2 = IntegralLattice(matrix([[-2,0,0], [0,1,0], [0,0,-4]])) sage: L2.discriminant_group().normal_form() Finite quadratic module over Integer Ring with invariants (2, 4) Gram matrix of the quadratic form with values in Q/Z: @@ -1005,10 +1004,10 @@ def normal_form(self, partial=False): We check that :trac:`24864` is fixed:: - sage: L1=IntegralLattice(matrix([[-4,0,0],[0,4,0],[0,0,-2]])) - sage: AL1=L1.discriminant_group() - sage: L2=IntegralLattice(matrix([[-4,0,0],[0,-4,0],[0,0,2]])) - sage: AL2=L2.discriminant_group() + sage: L1 = IntegralLattice(matrix([[-4,0,0], [0,4,0], [0,0,-2]])) + sage: AL1 = L1.discriminant_group() + sage: L2 = IntegralLattice(matrix([[-4,0,0], [0,-4,0], [0,0,2]])) + sage: AL2 = L2.discriminant_group() sage: AL1.normal_form() Finite quadratic module over Integer Ring with invariants (2, 4, 4) Gram matrix of the quadratic form with values in Q/2Z: @@ -1025,11 +1024,10 @@ def normal_form(self, partial=False): Some exotic cases:: sage: from sage.modules.torsion_quadratic_module import TorsionQuadraticModule - sage: D4_gram = Matrix(ZZ,4,4,[2,0,0,-1,0,2,0,-1,0,0,2,-1,-1,-1,-1,2]) - sage: D4 = FreeQuadraticModule(ZZ,4,D4_gram) + sage: D4_gram = Matrix(ZZ, 4, 4,[2,0,0,-1, 0,2,0,-1, 0,0,2,-1, -1,-1,-1,2]) + sage: D4 = FreeQuadraticModule(ZZ, 4, D4_gram) sage: D4dual = D4.span(D4_gram.inverse()) - sage: T = TorsionQuadraticModule((1/6)*D4dual,D4) - sage: T + sage: T = TorsionQuadraticModule((1/6)*D4dual, D4); T Finite quadratic module over Integer Ring with invariants (6, 6, 12, 12) Gram matrix of the quadratic form with values in Q/(1/3)Z: [ 1/18 1/12 5/36 1/36] @@ -1129,8 +1127,7 @@ def primary_part(self, m): EXAMPLES:: sage: from sage.modules.torsion_quadratic_module import TorsionQuadraticModule - sage: T = TorsionQuadraticModule((1/6)*ZZ^3,ZZ^3) - sage: T + sage: T = TorsionQuadraticModule((1/6)*ZZ^3, ZZ^3); T Finite quadratic module over Integer Ring with invariants (6, 6, 6) Gram matrix of the quadratic form with values in Q/(1/3)Z: [1/36 0 0] @@ -1167,7 +1164,7 @@ def submodule_with_gens(self, gens): EXAMPLES:: sage: from sage.modules.torsion_quadratic_module import TorsionQuadraticModule - sage: V = FreeQuadraticModule(ZZ,3,matrix.identity(3)*10) + sage: V = FreeQuadraticModule(ZZ, 3, matrix.identity(3)*10) sage: T = TorsionQuadraticModule((1/10)*V, V) sage: g = T.gens() sage: new_gens = [2*g[0], 5*g[0]] @@ -1193,9 +1190,8 @@ def submodule_with_gens(self, gens): Test that things work without specified gens too:: sage: from sage.modules.torsion_quadratic_module import TorsionQuadraticModule - sage: V = FreeQuadraticModule(ZZ,3,matrix.identity(3)*5) - sage: T = TorsionQuadraticModule((1/5)*V, V) - sage: T + sage: V = FreeQuadraticModule(ZZ, 3, matrix.identity(3)*5) + sage: T = TorsionQuadraticModule((1/5)*V, V); T Finite quadratic module over Integer Ring with invariants (5, 5, 5) Gram matrix of the quadratic form with values in Q/Z: [1/5 0 0] @@ -1267,8 +1263,7 @@ def value_module(self): sage: A2 = Matrix(ZZ, 2, 2, [2,-1,-1,2]) sage: L = IntegralLattice(2*A2) - sage: D = L.discriminant_group() - sage: D + sage: D = L.discriminant_group(); D Finite quadratic module over Integer Ring with invariants (2, 6) Gram matrix of the quadratic form with values in Q/2Z: [ 1 1/2] @@ -1287,9 +1282,8 @@ def value_module_qf(self): EXAMPLES:: sage: A2 = Matrix(ZZ, 2, 2, [2,-1,-1,2]) - sage: L = IntegralLattice(2*A2) - sage: D = L.discriminant_group() - sage: D + sage: L = IntegralLattice(2 * A2) + sage: D = L.discriminant_group(); D Finite quadratic module over Integer Ring with invariants (2, 6) Gram matrix of the quadratic form with values in Q/2Z: [ 1 1/2] diff --git a/src/sage/quadratic_forms/binary_qf.py b/src/sage/quadratic_forms/binary_qf.py index eb185dbb32c..96247522baf 100755 --- a/src/sage/quadratic_forms/binary_qf.py +++ b/src/sage/quadratic_forms/binary_qf.py @@ -11,7 +11,7 @@ x^2 + 2*x*y + 3*y^2 sage: Q.discriminant() -8 - sage: Q.reduced_form() + sage: Q.reduced_form() # optional - sage.libs.pari x^2 + 2*y^2 sage: Q(1, 1) 6 @@ -51,9 +51,7 @@ # **************************************************************************** from functools import total_ordering -from sage.libs.pari.all import pari_gen, pari from sage.rings.integer_ring import ZZ -from sage.rings.number_field.number_field import is_fundamental_discriminant from sage.arith.misc import gcd from sage.structure.sage_object import SageObject from sage.matrix.matrix_space import MatrixSpace @@ -61,6 +59,12 @@ from sage.misc.cachefunc import cached_method +try: + from sage.libs.pari.all import pari_gen, pari +except ImportError: + pari_gen = () + + @total_ordering class BinaryQF(SageObject): r""" @@ -163,13 +167,13 @@ def _pari_init_(self): 2*x^2 + 3*x*y + 4*y^2 sage: f._pari_init_() 'Qfb(2,3,4)' - sage: pari(f) + sage: pari(f) # optional - sage.libs.pari Qfb(2, 3, 4) - sage: type(pari(f)) + sage: type(pari(f)) # optional - sage.libs.pari <... 'cypari2.gen.Gen'> - sage: gp(f) + sage: gp(f) # optional - sage.libs.pari Qfb(2, 3, 4) - sage: type(gp(f)) + sage: type(gp(f)) # optional - sage.libs.pari """ return 'Qfb(%s,%s,%s)' % (self._a, self._b, self._c) @@ -187,13 +191,13 @@ def __mul__(self, right): sage: R = BinaryQF_reduced_representatives(-23, primitive_only=False); R [x^2 + x*y + 6*y^2, 2*x^2 - x*y + 3*y^2, 2*x^2 + x*y + 3*y^2] - sage: R[0] * R[0] + sage: R[0] * R[0] # optional - sage.libs.pari x^2 + x*y + 6*y^2 - sage: R[1] * R[1] + sage: R[1] * R[1] # optional - sage.libs.pari 4*x^2 + 3*x*y + 2*y^2 - sage: (R[1] * R[1]).reduced_form() + sage: (R[1] * R[1]).reduced_form() # optional - sage.libs.pari 2*x^2 + x*y + 3*y^2 - sage: (R[1] * R[1] * R[1]).reduced_form() + sage: (R[1] * R[1] * R[1]).reduced_form() # optional - sage.libs.pari x^2 + x*y + 6*y^2 sage: q1 = BinaryQF(1, 1, 4) sage: M = Matrix(ZZ, [[1, 3], [0, 1]]) @@ -598,13 +602,13 @@ def has_fundamental_discriminant(self): sage: Q = BinaryQF([1, 0, 1]) sage: Q.discriminant() -4 - sage: Q.has_fundamental_discriminant() + sage: Q.has_fundamental_discriminant() # optional - sage.libs.pari True sage: Q = BinaryQF([2, 0, 2]) sage: Q.discriminant() -16 - sage: Q.has_fundamental_discriminant() + sage: Q.has_fundamental_discriminant() # optional - sage.libs.pari False """ return self.discriminant().is_fundamental_discriminant() @@ -813,17 +817,17 @@ def reduced_form(self, transformation=False, algorithm="default"): sage: a = BinaryQF([33, 11, 5]) sage: a.is_reduced() False - sage: b = a.reduced_form(); b + sage: b = a.reduced_form(); b # optional - sage.libs.pari 5*x^2 - x*y + 27*y^2 - sage: b.is_reduced() + sage: b.is_reduced() # optional - sage.libs.pari True sage: a = BinaryQF([15, 0, 15]) sage: a.is_reduced() True - sage: b = a.reduced_form(); b + sage: b = a.reduced_form(); b # optional - sage.libs.pari 15*x^2 + 15*y^2 - sage: b.is_reduced() + sage: b.is_reduced() # optional - sage.libs.pari True Examples of reducing indefinite forms:: @@ -831,26 +835,26 @@ def reduced_form(self, transformation=False, algorithm="default"): sage: f = BinaryQF(1, 0, -3) sage: f.is_reduced() False - sage: g = f.reduced_form(); g + sage: g = f.reduced_form(); g # optional - sage.libs.pari x^2 + 2*x*y - 2*y^2 - sage: g.is_reduced() + sage: g.is_reduced() # optional - sage.libs.pari True sage: q = BinaryQF(1, 0, -1) - sage: q.reduced_form() + sage: q.reduced_form() # optional - sage.libs.pari x^2 + 2*x*y - sage: BinaryQF(1, 9, 4).reduced_form(transformation=True) + sage: BinaryQF(1, 9, 4).reduced_form(transformation=True) # optional - sage.libs.pari ( [ 0 -1] 4*x^2 + 7*x*y - y^2, [ 1 2] ) - sage: BinaryQF(3, 7, -2).reduced_form(transformation=True) + sage: BinaryQF(3, 7, -2).reduced_form(transformation=True) # optional - sage.libs.pari ( [1 0] 3*x^2 + 7*x*y - 2*y^2, [0 1] ) - sage: BinaryQF(-6, 6, -1).reduced_form(transformation=True) + sage: BinaryQF(-6, 6, -1).reduced_form(transformation=True) # optional - sage.libs.pari ( [ 0 -1] -x^2 + 2*x*y + 2*y^2, [ 1 -4] @@ -860,7 +864,7 @@ def reduced_form(self, transformation=False, algorithm="default"): Check for :trac:`34229`:: - sage: BinaryQF([1,2,3]).reduced_form(transformation=True) + sage: BinaryQF([1,2,3]).reduced_form(transformation=True) # optional - sage.libs.pari ( [ 1 -1] x^2 + 2*y^2, [ 0 1] @@ -1039,30 +1043,30 @@ def cycle(self, proper=False): sage: Q = BinaryQF(1, 8, -3) sage: Q.cycle() [x^2 + 8*x*y - 3*y^2, - 3*x^2 + 4*x*y - 5*y^2, - 5*x^2 + 6*x*y - 2*y^2, - 2*x^2 + 6*x*y - 5*y^2, - 5*x^2 + 4*x*y - 3*y^2, - 3*x^2 + 8*x*y - y^2] - sage: Q.cycle(proper=True) - [x^2 + 8*x*y - 3*y^2, - -3*x^2 + 4*x*y + 5*y^2, + 3*x^2 + 4*x*y - 5*y^2, 5*x^2 + 6*x*y - 2*y^2, - -2*x^2 + 6*x*y + 5*y^2, + 2*x^2 + 6*x*y - 5*y^2, 5*x^2 + 4*x*y - 3*y^2, - -3*x^2 + 8*x*y + y^2] + 3*x^2 + 8*x*y - y^2] + sage: Q.cycle(proper=True) + [x^2 + 8*x*y - 3*y^2, + -3*x^2 + 4*x*y + 5*y^2, + 5*x^2 + 6*x*y - 2*y^2, + -2*x^2 + 6*x*y + 5*y^2, + 5*x^2 + 4*x*y - 3*y^2, + -3*x^2 + 8*x*y + y^2] sage: Q = BinaryQF(1, 7, -6) sage: Q.cycle() [x^2 + 7*x*y - 6*y^2, - 6*x^2 + 5*x*y - 2*y^2, - 2*x^2 + 7*x*y - 3*y^2, - 3*x^2 + 5*x*y - 4*y^2, - 4*x^2 + 3*x*y - 4*y^2, - 4*x^2 + 5*x*y - 3*y^2, - 3*x^2 + 7*x*y - 2*y^2, - 2*x^2 + 5*x*y - 6*y^2, - 6*x^2 + 7*x*y - y^2] + 6*x^2 + 5*x*y - 2*y^2, + 2*x^2 + 7*x*y - 3*y^2, + 3*x^2 + 5*x*y - 4*y^2, + 4*x^2 + 3*x*y - 4*y^2, + 4*x^2 + 5*x*y - 3*y^2, + 3*x^2 + 7*x*y - 2*y^2, + 2*x^2 + 5*x*y - 6*y^2, + 6*x^2 + 7*x*y - y^2] TESTS: @@ -1257,23 +1261,23 @@ def is_equivalent(self, other, proper=True): sage: Q3 = BinaryQF(4, 4, 15) sage: Q2 = BinaryQF(4, -4, 15) - sage: Q2.is_equivalent(Q3) + sage: Q2.is_equivalent(Q3) # optional - sage.libs.pari True sage: a = BinaryQF([33, 11, 5]) - sage: b = a.reduced_form(); b + sage: b = a.reduced_form(); b # optional - sage.libs.pari 5*x^2 - x*y + 27*y^2 - sage: a.is_equivalent(b) + sage: a.is_equivalent(b) # optional - sage.libs.pari True - sage: a.is_equivalent(BinaryQF((3, 4, 5))) + sage: a.is_equivalent(BinaryQF((3, 4, 5))) # optional - sage.libs.pari False Some indefinite examples:: sage: Q1 = BinaryQF(9, 8, -7) sage: Q2 = BinaryQF(9, -8, -7) - sage: Q1.is_equivalent(Q2, proper=True) + sage: Q1.is_equivalent(Q2, proper=True) # optional - sage.libs.pari False - sage: Q1.is_equivalent(Q2, proper=False) + sage: Q1.is_equivalent(Q2, proper=False) # optional - sage.libs.pari True TESTS: @@ -1282,11 +1286,11 @@ def is_equivalent(self, other, proper=True): sage: Q1 = BinaryQF(3, 4, -2) sage: Q2 = BinaryQF(-2, 4, 3) - sage: Q1.is_equivalent(Q2) == Q2.is_equivalent(Q1) + sage: Q1.is_equivalent(Q2) == Q2.is_equivalent(Q1) # optional - sage.libs.pari True - sage: Q1.is_equivalent(Q2, proper=False) == Q2.is_equivalent(Q1, proper=False) + sage: Q1.is_equivalent(Q2, proper=False) == Q2.is_equivalent(Q1, proper=False) # optional - sage.libs.pari True - sage: Q1.is_equivalent(Q2, proper=True) + sage: Q1.is_equivalent(Q2, proper=True) # optional - sage.libs.pari True We check that the first part of :trac:`29028` is fixed:: @@ -1294,22 +1298,22 @@ def is_equivalent(self, other, proper=True): sage: Q = BinaryQF(0, 2, 0) sage: Q.discriminant() 4 - sage: Q.is_equivalent(Q, proper=True) + sage: Q.is_equivalent(Q, proper=True) # optional - sage.libs.pari True - sage: Q.is_equivalent(Q, proper=False) + sage: Q.is_equivalent(Q, proper=False) # optional - sage.libs.pari True A test for rational forms:: sage: Q1 = BinaryQF(0, 4, 2) sage: Q2 = BinaryQF(2, 4, 0) - sage: Q1.is_equivalent(Q2, proper=False) + sage: Q1.is_equivalent(Q2, proper=False) # optional - sage.libs.pari True Test another part of :trac:`28989`:: sage: Q1, Q2 = BinaryQF(1, 1, -1), BinaryQF(-1, 1, 1) - sage: Q1.is_equivalent(Q2, proper=True) + sage: Q1.is_equivalent(Q2, proper=True) # optional - sage.libs.pari True """ if type(other) != type(self): @@ -1507,15 +1511,13 @@ def matrix_action_right(self, M): def small_prime_value(self, Bmax=1000): r""" - Returns a prime represented by this (primitive positive definite) binary form. + Return a prime represented by this (primitive positive definite) binary form. INPUT: - - ``Bmax`` -- a positive bound on the representing integers. - - OUTPUT: + - ``Bmax`` -- a positive bound on the representing integers - A prime number represented by the form. + OUTPUT: a prime number represented by the form .. NOTE:: @@ -1524,9 +1526,11 @@ def small_prime_value(self, Bmax=1000): EXAMPLES:: - sage: [Q.small_prime_value() for Q in BinaryQF_reduced_representatives(-23, primitive_only=True)] + sage: [Q.small_prime_value() # optional - sage.libs.pari + ....: for Q in BinaryQF_reduced_representatives(-23, primitive_only=True)] [23, 2, 2] - sage: [Q.small_prime_value() for Q in BinaryQF_reduced_representatives(-47, primitive_only=True)] + sage: [Q.small_prime_value() # optional - sage.libs.pari + ....: for Q in BinaryQF_reduced_representatives(-47, primitive_only=True)] [47, 2, 2, 3, 3] """ from sage.sets.set import Set @@ -1566,7 +1570,7 @@ def solve_integer(self, n, *, algorithm="general"): EXAMPLES:: sage: Q = BinaryQF([1, 0, 419]) - sage: Q.solve_integer(773187972) + sage: Q.solve_integer(773187972) # optional - sage.libs.pari (4919, 1337) If `Q` is of the form `[1,0,c]` as above and `n` is a prime or @@ -1586,14 +1590,14 @@ def solve_integer(self, n, *, algorithm="general"): :: - sage: Qs = BinaryQF_reduced_representatives(-23, primitive_only=True) - sage: Qs + sage: Qs = BinaryQF_reduced_representatives(-23, primitive_only=True) # optional - sage.libs.pari + sage: Qs # optional - sage.libs.pari [x^2 + x*y + 6*y^2, 2*x^2 - x*y + 3*y^2, 2*x^2 + x*y + 3*y^2] - sage: [Q.solve_integer(3) for Q in Qs] + sage: [Q.solve_integer(3) for Q in Qs] # optional - sage.libs.pari [None, (0, -1), (0, -1)] - sage: [Q.solve_integer(5) for Q in Qs] + sage: [Q.solve_integer(5) for Q in Qs] # optional - sage.libs.pari [None, None, None] - sage: [Q.solve_integer(6) for Q in Qs] + sage: [Q.solve_integer(6) for Q in Qs] # optional - sage.libs.pari [(1, -1), (1, -1), (-1, -1)] TESTS: @@ -1602,13 +1606,13 @@ def solve_integer(self, n, *, algorithm="general"): sage: Q = BinaryQF([randrange(-10^3, 10^3) for _ in 'abc']) sage: n = randrange(-10^9, 10^9) - sage: xy = Q.solve_integer(n) - sage: xy is None or Q(*xy) == n + sage: xy = Q.solve_integer(n) # optional - sage.libs.pari + sage: xy is None or Q(*xy) == n # optional - sage.libs.pari True Also when using the ``"cornacchia"`` algorithm:: - sage: abc = [1,0,randrange(1,10^3)] + sage: abc = [1, 0, randrange(1,10^3)] sage: Q = BinaryQF(abc) sage: n = random_prime(10^9) sage: if randrange(2): @@ -1630,14 +1634,14 @@ def solve_integer(self, n, *, algorithm="general"): sage: Q = Q.matrix_action_right(U) sage: Q.discriminant().is_square() True - sage: xy = Q.solve_integer(n) - sage: Q(*xy) == n + sage: xy = Q.solve_integer(n) # optional - sage.libs.pari + sage: Q(*xy) == n # optional - sage.libs.pari True Also test the `n=0` special case separately:: - sage: xy = Q.solve_integer(0) - sage: Q(*xy) + sage: xy = Q.solve_integer(0) # optional - sage.libs.pari + sage: Q(*xy) # optional - sage.libs.pari 0 """ n = ZZ(n) @@ -1730,10 +1734,11 @@ def BinaryQF_reduced_representatives(D, primitive_only=False, proper=True): [x^2 + 4*y^2, 2*x^2 + 2*y^2] sage: BinaryQF_reduced_representatives(-63) - [x^2 + x*y + 16*y^2, 2*x^2 - x*y + 8*y^2, 2*x^2 + x*y + 8*y^2, 3*x^2 + 3*x*y + 6*y^2, 4*x^2 + x*y + 4*y^2] + [x^2 + x*y + 16*y^2, 2*x^2 - x*y + 8*y^2, 2*x^2 + x*y + 8*y^2, + 3*x^2 + 3*x*y + 6*y^2, 4*x^2 + x*y + 4*y^2] The number of inequivalent reduced binary forms with a fixed negative - fundamental discriminant D is the class number of the quadratic field + fundamental discriminant `D` is the class number of the quadratic field `\QQ(\sqrt{D})`:: sage: len(BinaryQF_reduced_representatives(-13*4)) @@ -1742,9 +1747,9 @@ def BinaryQF_reduced_representatives(D, primitive_only=False, proper=True): 2 sage: p = next_prime(2^20); p 1048583 - sage: len(BinaryQF_reduced_representatives(-p)) + sage: len(BinaryQF_reduced_representatives(-p)) # optional - sage.libs.pari 689 - sage: QuadraticField(-p, 'a').class_number() + sage: QuadraticField(-p, 'a').class_number() # optional - sage.libs.pari sage.rings.number_field 689 sage: BinaryQF_reduced_representatives(-23*9) @@ -1757,7 +1762,7 @@ def BinaryQF_reduced_representatives(D, primitive_only=False, proper=True): 6*x^2 - 3*x*y + 9*y^2, 6*x^2 + 3*x*y + 9*y^2, 8*x^2 + 7*x*y + 8*y^2] - sage: BinaryQF_reduced_representatives(-23*9, primitive_only=True) + sage: BinaryQF_reduced_representatives(-23*9, primitive_only=True) # optional - sage.libs.pari [x^2 + x*y + 52*y^2, 2*x^2 - x*y + 26*y^2, 2*x^2 + x*y + 26*y^2, @@ -1769,7 +1774,7 @@ def BinaryQF_reduced_representatives(D, primitive_only=False, proper=True): sage: BinaryQF_reduced_representatives(73) [4*x^2 + 3*x*y - 4*y^2] - sage: BinaryQF_reduced_representatives(76, primitive_only=True) + sage: BinaryQF_reduced_representatives(76, primitive_only=True) # optional - sage.libs.pari [-3*x^2 + 4*x*y + 5*y^2, 3*x^2 + 4*x*y - 5*y^2] sage: BinaryQF_reduced_representatives(136) @@ -1784,9 +1789,9 @@ def BinaryQF_reduced_representatives(D, primitive_only=False, proper=True): sage: BinaryQF_reduced_representatives(148, proper=False, primitive_only=False) [x^2 + 12*x*y - y^2, 4*x^2 + 6*x*y - 7*y^2, 6*x^2 + 2*x*y - 6*y^2] - sage: BinaryQF_reduced_representatives(148, proper=False, primitive_only=True) + sage: BinaryQF_reduced_representatives(148, proper=False, primitive_only=True) # optional - sage.libs.pari [x^2 + 12*x*y - y^2, 4*x^2 + 6*x*y - 7*y^2] - sage: BinaryQF_reduced_representatives(148, proper=True, primitive_only=True) + sage: BinaryQF_reduced_representatives(148, proper=True, primitive_only=True) # optional - sage.libs.pari [-7*x^2 + 6*x*y + 4*y^2, x^2 + 12*x*y - y^2, 4*x^2 + 6*x*y - 7*y^2] sage: BinaryQF_reduced_representatives(148, proper=True, primitive_only=False) [-7*x^2 + 6*x*y + 4*y^2, @@ -1805,9 +1810,9 @@ def BinaryQF_reduced_representatives(D, primitive_only=False, proper=True): x^2 + 10*x*y, 2*x^2 + 10*x*y, 5*x^2 + 10*x*y] - sage: BinaryQF_reduced_representatives(10^2, proper=False, primitive_only=True) + sage: BinaryQF_reduced_representatives(10^2, proper=False, primitive_only=True) # optional - sage.libs.pari [-3*x^2 + 10*x*y, -x^2 + 10*x*y, x^2 + 10*x*y] - sage: BinaryQF_reduced_representatives(10^2, proper=True, primitive_only=True) + sage: BinaryQF_reduced_representatives(10^2, proper=True, primitive_only=True) # optional - sage.libs.pari [-3*x^2 + 10*x*y, -x^2 + 10*x*y, x^2 + 10*x*y, 3*x^2 + 10*x*y] sage: BinaryQF_reduced_representatives(10^2, proper=True, primitive_only=False) [-4*x^2 + 10*x*y, diff --git a/src/sage/quadratic_forms/constructions.py b/src/sage/quadratic_forms/constructions.py index b1b3dca6307..e21613de790 100644 --- a/src/sage/quadratic_forms/constructions.py +++ b/src/sage/quadratic_forms/constructions.py @@ -23,18 +23,16 @@ def BezoutianQuadraticForm(f, g): INPUT: - - `f`, `g` -- polynomials in `R[x]`, for some ring `R` + - ``f``, ``g`` -- polynomials in `R[x]`, for some ring `R` - OUTPUT: - - a quadratic form over `R` + OUTPUT: a quadratic form over `R` EXAMPLES:: sage: R = PolynomialRing(ZZ, 'x') sage: f = R([1,2,3]) sage: g = R([2,5]) - sage: Q = BezoutianQuadraticForm(f, g) ; Q + sage: Q = BezoutianQuadraticForm(f, g); Q # optional - sage.libs.singular Quadratic form in 2 variables over Integer Ring with coefficients: [ 1 -12 ] [ * -15 ] @@ -76,8 +74,8 @@ def HyperbolicPlane_quadratic_form(R, r=1): INPUT: - - `R`: a ring - - `n` (integer, default 1) number of copies + - ``R``: a ring + - ``n`` (integer, default 1) number of copies EXAMPLES:: diff --git a/src/sage/quadratic_forms/count_local_2.pyx b/src/sage/quadratic_forms/count_local_2.pyx index 3eb0f712cf1..7ffedf8d8d2 100644 --- a/src/sage/quadratic_forms/count_local_2.pyx +++ b/src/sage/quadratic_forms/count_local_2.pyx @@ -11,24 +11,23 @@ from sage.sets.set import Set def count_modp__by_gauss_sum(n, p, m, Qdet): - """ - Returns the number of solutions of Q(x) = m over the finite field - Z/pZ, where p is a prime number > 2 and Q is a non-degenerate - quadratic form of dimension n >= 1 and has Gram determinant Qdet. + r""" + Return the number of solutions of `Q(x) = m` over the finite field + `\ZZ/p\ZZ`, where `p` is a prime number > 2 and `Q` is a non-degenerate + quadratic form of dimension `n \geq 1` and has Gram determinant ``Qdet``. REFERENCE: - These are defined in Table 1 on p363 of Hanke's "Local - Densities..." paper. + + These are defined in Table 1 on p363 of Hanke's "Local Densities..." paper. INPUT: - - n -- an integer >= 1 - - p -- a prime number > 2 - - m -- an integer - - Qdet -- a integer which is non-zero mod p + - ``n`` -- an integer `\geq 1` + - ``p`` -- a prime number > 2 + - ``m`` -- an integer + - ``Qdet`` -- a integer which is non-zero mod `p` - OUTPUT: - an integer >= 0 + OUTPUT: an integer `\geq 0` EXAMPLES:: @@ -42,7 +41,9 @@ def count_modp__by_gauss_sum(n, p, m, Qdet): 12 sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1]) - sage: [Q.count_congruence_solutions(3, 1, m, None, None) == count_modp__by_gauss_sum(3, 3, m, 1) for m in range(3)] + sage: [Q.count_congruence_solutions(3, 1, m, None, None) + ....: == count_modp__by_gauss_sum(3, 3, m, 1) + ....: for m in range(3)] [True, True, True] @@ -54,7 +55,9 @@ def count_modp__by_gauss_sum(n, p, m, Qdet): 6 sage: Q = DiagonalQuadraticForm(ZZ, [1,1,2]) - sage: [Q.count_congruence_solutions(3, 1, m, None, None) == count_modp__by_gauss_sum(3, 3, m, 2) for m in range(3)] + sage: [Q.count_congruence_solutions(3, 1, m, None, None) + ....: == count_modp__by_gauss_sum(3, 3, m, 2) + ....: for m in range(3)] [True, True, True] @@ -161,10 +164,10 @@ def CountAllLocalTypesNaive(Q, p, k, m, zvec, nzvec): INPUT: - - `Q` -- quadratic form over `\ZZ` - - `p` -- prime number > 0 - - `k` -- an integer > 0 - - `m` -- an integer (depending only on mod `p^k`) + - ``Q`` -- quadratic form over `\ZZ` + - ``p`` -- prime number > 0 + - ``k`` -- an integer > 0 + - ``m`` -- an integer (depending only on mod `p^k`) - ``zvec``, ``nzvec`` -- a list of integers in ``range(Q.dim())``, or ``None`` OUTPUT: @@ -194,12 +197,12 @@ def CountAllLocalTypesNaive(Q, p, k, m, zvec, nzvec): cdef local_solution_type_cdef(Q, p, w, zvec, nzvec): """ - Internal routine to check if a given solution vector w (of Q(w) = - m mod p^k) is of a certain local type and satisfies certain - congruence conditions mod p. + Internal routine to check if a given solution vector `w` (of `Q(w) = + m` mod `p^k`) is of a certain local type and satisfies certain + congruence conditions mod `p`. - NOTE: No internal checking is done to test if p is a prime >=2, or - that Q has the same size as w. + NOTE: No internal checking is done to test if `p` is a prime >=2, or + that Q has the same size as `w`. """ cdef long i diff --git a/src/sage/quadratic_forms/extras.py b/src/sage/quadratic_forms/extras.py index e042d3c037f..a64e3518207 100644 --- a/src/sage/quadratic_forms/extras.py +++ b/src/sage/quadratic_forms/extras.py @@ -25,7 +25,7 @@ def is_triangular_number(n, return_value=False): - ``n`` - an integer - ``return_value`` - a boolean set to ``False`` by default. If set to - ``True`` the function returns a pair made of a boolean and the value ``v`` + ``True`` the function returns a pair made of a boolean and the value `v` such that `v(v+1)/2 = n`. EXAMPLES:: @@ -75,11 +75,11 @@ def is_triangular_number(n, return_value=False): def extend_to_primitive(A_input): - """ + r""" Given a matrix (resp. list of vectors), extend it to a square matrix (resp. list of vectors), such that its determinant is the gcd of its minors (i.e. extend the basis of a lattice to a - "maximal" one in Z^n). + "maximal" one in `\ZZ^n`). Author(s): Gonzalo Tornaria and Jonathan Hanke. @@ -101,7 +101,6 @@ def extend_to_primitive(A_input): sage: extend_to_primitive([vector([1,2,3])]) [(1, 2, 3), (0, 1, 1), (-1, 0, 0)] - """ # Deal with a list of vectors if not is_Matrix(A_input): @@ -145,14 +144,14 @@ def extend_to_primitive(A_input): def least_quadratic_nonresidue(p): - """ - Return the smallest positive integer quadratic non-residue in Z/pZ for primes p>2. + r""" + Return the smallest positive integer quadratic non-residue in `\ZZ/p\ZZ` for primes `p>2`. EXAMPLES:: sage: least_quadratic_nonresidue(5) 2 - sage: [least_quadratic_nonresidue(p) for p in prime_range(3,100)] + sage: [least_quadratic_nonresidue(p) for p in prime_range(3, 100)] # optional - sage.libs.pari [2, 2, 3, 2, 2, 3, 2, 5, 2, 3, 2, 3, 2, 5, 2, 2, 2, 2, 7, 5, 3, 2, 3, 5] TESTS: diff --git a/src/sage/quadratic_forms/genera/genus.py b/src/sage/quadratic_forms/genera/genus.py index 4ee20120e1c..f80c2ae7d40 100644 --- a/src/sage/quadratic_forms/genera/genus.py +++ b/src/sage/quadratic_forms/genera/genus.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.libs.pari r""" Genus @@ -29,15 +30,8 @@ from sage.rings.integer_ring import IntegerRing, ZZ from sage.rings.rational_field import RationalField, QQ from sage.rings.integer import Integer -from sage.interfaces.gp import gp -from sage.libs.pari import pari -from sage.rings.finite_rings.finite_field_constructor import FiniteField from copy import copy, deepcopy from sage.misc.verbose import verbose -from sage.functions.gamma import gamma -from sage.functions.transcendental import zeta -from sage.symbolic.constants import pi -from sage.symbolic.ring import SR from sage.quadratic_forms.special_values import quadratic_L_function__exact lazy_import('sage.quadratic_forms.genera.normal_form', '_min_nonsquare') lazy_import('sage.interfaces.magma', 'magma') @@ -127,6 +121,9 @@ def genera(sig_pair, determinant, max_scale=None, even=False): return genera +genera = staticmethod(genera) + + def _local_genera(p, rank, det_val, max_scale, even): r""" Return all `p`-adic genera with the given conditions. @@ -140,7 +137,7 @@ def _local_genera(p, rank, det_val, max_scale, even): - ``rank`` -- the rank of this genus - - ``det_val`` -- valuation of the determinant at p + - ``det_val`` -- valuation of the determinant at `p` - ``max_scale`` -- an integer the maximal scale of a jordan block @@ -333,7 +330,7 @@ def Genus(A, factored_determinant=None): - ``A`` -- a symmetric matrix with integer coefficients - - ``factored_determinant`` -- (default: ``None``) a factorization object + - ``factored_determinant`` -- (default: ``None``) a :class:`Factorization` object, the factored determinant of ``A`` OUTPUT: @@ -419,9 +416,7 @@ def is_GlobalGenus(G): - ``G`` -- :class:`GenusSymbol_global_ring` object - OUTPUT: - - - boolean + OUTPUT: boolean EXAMPLES:: @@ -430,12 +425,11 @@ def is_GlobalGenus(G): sage: G = Genus(A) sage: is_GlobalGenus(G) True - sage: G=Genus(matrix.diagonal([2, 2, 2, 2])) - sage: G._local_symbols[0]._symbol=[[0,2,3,0,0], [1,2,5,1,0]] + sage: G = Genus(matrix.diagonal([2, 2, 2, 2])) + sage: G._local_symbols[0]._symbol = [[0,2,3,0,0], [1,2,5,1,0]] sage: G._representative=None sage: is_GlobalGenus(G) False - """ D = G.determinant() r, s = G.signature_pair() @@ -475,9 +469,7 @@ def is_2_adic_genus(genus_symbol_quintuple_list): - ``genus_symbol_quintuple_list`` -- a quintuple of integers (with certain restrictions). - OUTPUT: - - boolean + OUTPUT: boolean EXAMPLES:: @@ -493,7 +485,8 @@ def is_2_adic_genus(genus_symbol_quintuple_list): sage: is_2_adic_genus(G3.symbol_tuple_list()) # This raises an error Traceback (most recent call last): ... - TypeError: The genus symbols are not quintuples, so it's not a genus symbol for the prime p=2. + TypeError: The genus symbols are not quintuples, + so it's not a genus symbol for the prime p=2. sage: A = Matrix(ZZ, 2, 2, [1,0,0,2]) sage: G2 = LocalGenusSymbol(A, 2) @@ -530,18 +523,16 @@ def canonical_2_adic_compartments(genus_symbol_quintuple_list): r""" Given a `2`-adic local symbol (as the underlying list of quintuples) this returns a list of lists of indices of the - genus_symbol_quintuple_list which are in the same compartment. A + ``genus_symbol_quintuple_list`` which are in the same compartment. A compartment is defined to be a maximal interval of Jordan components all (scaled) of type I (i.e. odd). INPUT: - ``genus_symbol_quintuple_list`` -- a quintuple of integers (with certain - restrictions). - - OUTPUT: + restrictions) - a list of lists of integers. + OUTPUT: a list of lists of integers EXAMPLES:: @@ -599,7 +590,7 @@ def canonical_2_adic_trains(genus_symbol_quintuple_list, compartments=None): r""" Given a `2`-adic local symbol (as the underlying list of quintuples) this returns a list of lists of indices of the - genus_symbol_quintuple_list which are in the same train. A train + ``genus_symbol_quintuple_list`` which are in the same train. A train is defined to be a maximal interval of Jordan components so that at least one of each adjacent pair (allowing zero-dimensional Jordan components) is (scaled) of type I (i.e. odd). @@ -613,9 +604,7 @@ def canonical_2_adic_trains(genus_symbol_quintuple_list, compartments=None): restrictions). - ``compartments`` -- this argument is deprecated - OUTPUT: - - a list of lists of distinct integers. + OUTPUT: a list of lists of distinct integers EXAMPLES:: @@ -646,7 +635,9 @@ def canonical_2_adic_trains(genus_symbol_quintuple_list, compartments=None): [[0, 2, 3, 0, 0]] sage: canonical_2_adic_trains(G2.symbol_tuple_list()) [[0]] - sage: symbol = [[0, 1, 1, 1, 1], [1, 2, -1, 0, 0], [2, 1, 1, 1, 1], [3, 1, 1, 1, 1], [4, 1, 1, 1, 1], [5, 2, -1, 0, 0], [7, 1, 1, 1, 1], [10, 1, 1, 1, 1], [11, 1, 1, 1, 1], [12, 1, 1, 1, 1]] + sage: symbol = [[0, 1, 1, 1, 1], [1, 2, -1, 0, 0], [2, 1, 1, 1, 1], + ....: [3, 1, 1, 1, 1], [4, 1, 1, 1, 1], [5, 2, -1, 0, 0], + ....: [7, 1, 1, 1, 1], [10, 1, 1, 1, 1], [11, 1, 1, 1, 1], [12, 1, 1, 1, 1]] sage: canonical_2_adic_trains(symbol) [[0, 1, 2, 3, 4, 5], [6], [7, 8, 9]] @@ -659,7 +650,6 @@ def canonical_2_adic_trains(genus_symbol_quintuple_list, compartments=None): .. NOTE:: See [CS1999]_, pp. 381-382 for definitions and examples. - """ if compartments is not None: from sage.misc.superseded import deprecation @@ -713,9 +703,7 @@ def canonical_2_adic_reduction(genus_symbol_quintuple_list): - ``compartments`` -- a list of lists of distinct integers (optional) - OUTPUT: - - a list of lists of distinct integers. + OUTPUT: a list of lists of distinct integers. EXAMPLES:: @@ -799,9 +787,7 @@ def basis_complement(B): - ``B`` -- matrix over a field in row echelon form - OUTPUT: - - a rectangular matrix over a field + OUTPUT: a rectangular matrix over a field EXAMPLES:: @@ -844,9 +830,7 @@ def signature_pair_of_matrix(A): - ``A`` -- symmetric matrix (assumed to be non-degenerate) - OUTPUT: - - - `(p, n)` -- a pair (tuple) of integers. + OUTPUT: `(p, n)` -- a pair (tuple) of integers. EXAMPLES:: @@ -902,9 +886,7 @@ def p_adic_symbol(A, p, val): divisor of `A` needed to obtain enough precision. Calculation is modulo `p` to the ``val+3``. - OUTPUT: - - a list of lists of integers + OUTPUT: a list of lists of integers EXAMPLES:: @@ -920,6 +902,9 @@ def p_adic_symbol(A, p, val): """ if p % 2 == 0: return two_adic_symbol(A, val) + + from sage.rings.finite_rings.finite_field_constructor import FiniteField + m0 = min([ c.valuation(p) for c in A.list() ]) q = p**m0 n = A.nrows() @@ -959,15 +944,13 @@ def is_even_matrix(A): Determines if the integral symmetric matrix `A` is even (i.e. represents only even numbers). If not, then it returns the index of an odd diagonal entry. If it is even, then we return the - index -1. + index `-1`. INPUT: - ``A`` -- symmetric integer matrix - OUTPUT: - - a pair of the form (boolean, integer) + OUTPUT: a pair of the form (boolean, integer) EXAMPLES:: @@ -1030,7 +1013,6 @@ def split_odd(A): Traceback (most recent call last): ... RuntimeError: The matrix A does not admit a non-even splitting. - """ n0 = A.nrows() if n0 == 1: @@ -1079,8 +1061,8 @@ def split_odd(A): def trace_diag_mod_8(A): r""" Return the trace of the diagonalised form of `A` of an integral - symmetric matrix which is diagonalizable `\mod 8`. (Note that since - the Jordan decomposition into blocks of size `<=` 2 is not unique + symmetric matrix which is diagonalizable mod `8`. (Note that since + the Jordan decomposition into blocks of size `\leq 2` is not unique here, this is not the same as saying that `A` is always diagonal in any `2`-adic Jordan decomposition!) @@ -1089,9 +1071,7 @@ def trace_diag_mod_8(A): - ``A`` -- symmetric matrix with coefficients in `\ZZ` which is odd in `\ZZ/2\ZZ` and has determinant not divisible by `8`. - OUTPUT: - - an integer + OUTPUT: an integer EXAMPLES:: @@ -1127,11 +1107,11 @@ def two_adic_symbol(A, val): The genus symbol of a component `2^m f` is of the form ``(m,n,s,d[,o])``, where - - m = valuation of the component - - n = dimension of f - - d = det(f) in {1,3,5,7} - - s = 0 (or 1) if even (or odd) - - o = oddity of f (= 0 if s = 0) in `Z/8Z` + - ``m`` = valuation of the component + - ``n`` = dimension of `f` + - ``d`` = det(`f`) in {1,3,5,7} + - ``s`` = 0 (or 1) if even (or odd) + - ``o`` = oddity of `f` (= 0 if s = 0) in `\ZZ/8\ZZ` INPUT: @@ -1151,6 +1131,8 @@ def two_adic_symbol(A, val): [[0, 2, 3, 1, 4], [1, 1, 1, 1, 1], [2, 1, 1, 1, 1]] """ + from sage.rings.finite_rings.finite_field_constructor import FiniteField + n = A.nrows() # deal with the empty matrix if n == 0: @@ -1219,13 +1201,13 @@ def two_adic_symbol(A, val): class Genus_Symbol_p_adic_ring(): r""" - Local genus symbol over a p-adic ring. + Local genus symbol over a `p`-adic ring. The genus symbol of a component `p^m A` for odd prime `= p` is of the form `(m,n,d)`, where - `m` = valuation of the component - - `n` = rank of A + - `n` = rank of `A` - `d = det(A) \in \{1,u\}` for a normalized quadratic non-residue `u`. The genus symbol of a component `2^m A` is of the form `(m, n, s, d, o)`, @@ -1235,13 +1217,14 @@ class Genus_Symbol_p_adic_ring(): - `n` = rank of `A` - `d` = det(A) in `\{1,3,5,7\}` - `s` = 0 (or 1) if even (or odd) - - `o` = oddity of `A` (= 0 if s = 0) in `Z/8Z` - = the trace of the diagonalization of `A` + - `o` = oddity of `A` (= 0 if s = 0) in `Z/8Z` = the trace of the diagonalization of `A` The genus symbol is a list of such symbols (ordered by `m`) for each of the Jordan blocks `A_1,...,A_t`. - Reference: [CS1999]_ Conway and Sloane 3rd edition, Chapter 15, Section 7. + REFERENCE: + + [CS1999]_ Conway and Sloane 3rd edition, Chapter 15, Section 7. .. WARNING:: @@ -1266,14 +1249,14 @@ class Genus_Symbol_p_adic_ring(): sage: p = 2 sage: s2 = p_adic_symbol(A, p, 2); s2 [[0, 2, 3, 1, 4], [1, 1, 1, 1, 1], [2, 1, 1, 1, 1]] - sage: G2 = Genus_Symbol_p_adic_ring(p,s2);G2 + sage: G2 = Genus_Symbol_p_adic_ring(p,s2); G2 Genus symbol at 2: [1^-2 2^1 4^1]_6 sage: A = diagonal_matrix(ZZ, [1, 2, 3, 4]) sage: p = 3 sage: s3 = p_adic_symbol(A, p, 1); s3 [[0, 3, -1], [1, 1, 1]] - sage: G3 = Genus_Symbol_p_adic_ring(p,s3);G3 + sage: G3 = Genus_Symbol_p_adic_ring(p,s3); G3 Genus symbol at 3: 1^-3 3^1 """ def __init__(self, prime, symbol, check = True): @@ -1313,9 +1296,7 @@ def __repr__(self): r""" String representation for the `p`-adic genus symbol - OUTPUT: - - a string + OUTPUT: a string EXAMPLES:: @@ -1450,11 +1431,9 @@ def __eq__(self, other): INPUT: - - other -- a :class:`Genus_Symbol_p_adic_ring` object + - ``other`` -- a :class:`Genus_Symbol_p_adic_ring` object - OUTPUT: - - boolean + OUTPUT: boolean EXAMPLES:: @@ -1488,11 +1467,9 @@ def __ne__(self, other): INPUT: - - other -- a :class:`Genus_Symbol_p_adic_ring` object - - OUTPUT: + - ``other`` -- a :class:`Genus_Symbol_p_adic_ring` object - boolean + OUTPUT: boolean EXAMPLES:: @@ -1535,8 +1512,8 @@ def automorphous_numbers(self): OUTPUT: - - a list of integers representing the square classes of generators of - the automorphous numbers + a list of integers representing the square classes of generators of + the automorphous numbers EXAMPLES: @@ -1545,13 +1522,12 @@ def automorphous_numbers(self): sage: A = matrix.diagonal([3, 16]) sage: G = Genus(A) - sage: sym2 = G.local_symbols()[0] - sage: sym2 + sage: sym2 = G.local_symbols()[0]; sym2 Genus symbol at 2: [1^-1]_3:[16^1]_1 sage: sym2.automorphous_numbers() [3, 5] - sage: A = matrix(ZZ,3,[2,1,0, 1,2,0, 0,0,18]) + sage: A = matrix(ZZ, 3, [2,1,0, 1,2,0, 0,0,18]) sage: G = Genus(A) sage: sym = G.local_symbols() sage: sym[0] @@ -1760,11 +1736,11 @@ def canonical_symbol(self): def gram_matrix(self, check=True): r""" - Return a gram matrix of a representative of this local genus. + Return a Gram matrix of a representative of this local genus. INPUT: - - check (default: ``True``) -- double check the result + - ``check`` (default: ``True``) -- double check the result EXAMPLES:: @@ -1932,9 +1908,7 @@ def prime(self): r""" Return the prime number `p` of this `p`-adic local symbol. - OUTPUT: - - - an integer + OUTPUT: an integer EXAMPLES:: @@ -1978,9 +1952,7 @@ def symbol_tuple_list(self): Return a copy of the underlying list of lists of integers defining the genus symbol. - OUTPUT: - - a list of lists of integers + OUTPUT: a list of lists of integers EXAMPLES:: @@ -2011,9 +1983,7 @@ def number_of_blocks(self): r""" Return the number of positive dimensional symbols/Jordan blocks. - OUTPUT: - - A non-negative integer + OUTPUT: a non-negative integer EXAMPLES:: @@ -2022,14 +1992,16 @@ def number_of_blocks(self): sage: A = DiagonalQuadraticForm(ZZ, [1, 2, 3, 4]).Hessian_matrix() sage: p = 2 - sage: G2 = Genus_Symbol_p_adic_ring(p, p_adic_symbol(A, p, 2)); G2.symbol_tuple_list() + sage: G2 = Genus_Symbol_p_adic_ring(p, p_adic_symbol(A, p, 2)) + sage: G2.symbol_tuple_list() [[1, 2, 3, 1, 4], [2, 1, 1, 1, 1], [3, 1, 1, 1, 1]] sage: G2.number_of_blocks() 3 sage: A = DiagonalQuadraticForm(ZZ, [1,2,3,4]).Hessian_matrix() sage: p = 3 - sage: G3 = Genus_Symbol_p_adic_ring(p, p_adic_symbol(A, p, 2)); G3.symbol_tuple_list() + sage: G3 = Genus_Symbol_p_adic_ring(p, p_adic_symbol(A, p, 2)) + sage: G3.symbol_tuple_list() [[0, 3, 1], [1, 1, -1]] sage: G3.number_of_blocks() 2 @@ -2043,9 +2015,7 @@ def determinant(self): integral symmetric matrix which generated this genus symbol as the Gram matrix of `Q`) associated to this local genus symbol. - OUTPUT: - - an integer + OUTPUT: an integer EXAMPLES:: @@ -2075,9 +2045,7 @@ def dimension(self): r""" Return the dimension of a quadratic form associated to this genus symbol. - OUTPUT: - - an non-negative integer + OUTPUT: a non-negative integer EXAMPLES:: @@ -2097,7 +2065,6 @@ def dimension(self): Genus symbol at 3: 1^3 3^-1 sage: G3.dimension() 4 - """ return sum([ s[1] for s in self._symbol ]) @@ -2163,8 +2130,8 @@ def direct_sum(self, other): def excess(self): r""" - Returns the p-excess of the quadratic form whose Hessian - matrix is the symmetric matrix A. When p = 2 the p-excess is + Returns the `p`-excess of the quadratic form whose Hessian + matrix is the symmetric matrix `A`. When `p = 2`, the `p`-excess is called the oddity. .. WARNING:: @@ -2177,9 +2144,7 @@ def excess(self): [CS1999]_ Conway and Sloane Book, 3rd edition, pp 370-371. - OUTPUT: - - an integer + OUTPUT: an integer EXAMPLES:: @@ -2245,9 +2210,7 @@ def scale(self): The scale of `(L,b)` is defined as the ideal `b(L,L)`. - OUTPUT: - - an integer + OUTPUT: an integer EXAMPLES:: @@ -2289,7 +2252,7 @@ def norm(self): def level(self): r""" - Return the maximal scale of a jordan component. + Return the maximal scale of a Jordan component. EXAMPLES:: @@ -2304,12 +2267,10 @@ def level(self): def trains(self): r""" Compute the indices for each of the trains in this local genus - symbol if it is associated to the prime p=2 (and raise an + symbol if it is associated to the prime `p=2` (and raise an error for all other primes). - OUTPUT: - - a list of non-negative integers + OUTPUT: a list of non-negative integers EXAMPLES:: @@ -2333,12 +2294,10 @@ def trains(self): def compartments(self): r""" Compute the indices for each of the compartments in this local genus - symbol if it is associated to the prime p=2 (and raise an + symbol if it is associated to the prime `p=2` (and raise an error for all other primes). - OUTPUT: - - a list of non-negative integers + OUTPUT: a list of non-negative integers EXAMPLES:: @@ -2370,11 +2329,11 @@ class GenusSymbol_global_ring(): - ``signature_pair`` -- a tuple of two non-negative integers - - ``local_symbols`` -- a list of :class:`Genus_Symbol_p_adic_ring`` instances + - ``local_symbols`` -- a list of :class:`Genus_Symbol_p_adic_ring` instances sorted by their primes - ``representative`` -- (default: ``None``) integer symmetric matrix; - the gram matrix of a representative of this genus + the Gram matrix of a representative of this genus - ``check`` -- (default: ``True``) a boolean; checks the input @@ -2395,7 +2354,7 @@ class GenusSymbol_global_ring(): .. SEEALSO:: - :func:`Genus` to create a :class:`GenusSymbol_global_ring` from the gram matrix directly. + :func:`Genus` to create a :class:`GenusSymbol_global_ring` from the Gram matrix directly. """ def __init__(self, signature_pair, local_symbols, representative=None, check=True): @@ -2436,9 +2395,7 @@ def __repr__(self): r""" Return a string representing the global genus symbol. - OUTPUT: - - a string + OUTPUT: a string EXAMPLES:: @@ -2506,9 +2463,7 @@ def __eq__(self, other): a :class:`GenusSymbol_global_ring` object - OUTPUT: - - boolean + OUTPUT: boolean EXAMPLES:: @@ -2558,9 +2513,7 @@ def __ne__(self, other): a ``GenusSymbol_global_ring`` object - OUTPUT: - - boolean + OUTPUT: boolean EXAMPLES:: @@ -2601,12 +2554,10 @@ def is_even(self): def signature_pair(self): r""" Return the signature pair `(p, n)` of the (non-degenerate) - global genus symbol, where p is the number of positive - eigenvalues and n is the number of negative eigenvalues. - - OUTPUT: + global genus symbol, where `p` is the number of positive + eigenvalues and `n` is the number of negative eigenvalues. - a pair of integers `(p, n)` each `>= 0` + OUTPUT: a pair of integers `(p, n)`, each `\geq 0` EXAMPLES:: @@ -2623,9 +2574,7 @@ def _proper_spinor_kernel(self): r""" Return the proper spinor kernel. - OUTPUT: - - A pair ``(A, K)`` where + OUTPUT: a pair `(A, K)` where .. MATH:: @@ -2665,9 +2614,7 @@ def _improper_spinor_kernel(self): r""" Return the improper spinor kernel. - OUTPUT: - - A pair ``(A, K)`` where + OUTPUT: a pair ``(A, K)`` where .. MATH:: @@ -2710,9 +2657,7 @@ def spinor_generators(self, proper): - ``proper`` -- boolean - OUTPUT: - - a list of primes not dividing the determinant + OUTPUT: a list of primes not dividing the determinant EXAMPLES:: @@ -2816,9 +2761,7 @@ def determinant(self): matrix is the Gram matrix giving rise to this global genus symbol. - OUTPUT: - - an integer + OUTPUT: an integer EXAMPLES:: @@ -2917,9 +2860,7 @@ def rational_representative(self): Return a representative of the rational bilinear form defined by this genus. - OUTPUT: - - A diagonal_matrix. + OUTPUT: a diagonal_matrix EXAMPLES:: @@ -2995,9 +2936,13 @@ def _compute_representative(self, LLL=True): L = local_modification(L, sym.gram_matrix(), p) L = L.gram_matrix().change_ring(ZZ) if LLL: + from sage.libs.pari import pari + sig = self.signature_pair_of_matrix() if sig[0] * sig[1] != 0: from sage.env import SAGE_EXTCODE + from sage.interfaces.gp import gp + m = pari(L) gp.read(SAGE_EXTCODE + "/pari/simon/qfsolve.gp") m = gp.eval('qflllgram_indefgoon(%s)'%m) @@ -3050,12 +2995,10 @@ def representatives(self, backend=None, algorithm=None): INPUT: - - ``backend`` -- (default:``None``) - - ``algorithm`` -- (default:``None``) - - OUTPUT: + - ``backend`` -- (default: ``None``) + - ``algorithm`` -- (default: ``None``) - - a list of gram matrices + OUTPUT: a list of Gram matrices EXAMPLES:: @@ -3218,10 +3161,14 @@ def _standard_mass(self): sage: A = matrix.diagonal(ZZ, [1, 1, 1, 1]) sage: GS = Genus(A) - sage: GS._standard_mass() + sage: GS._standard_mass() # optional - sage.symbolic 1/48 """ + from sage.symbolic.constants import pi + from sage.symbolic.ring import SR + from sage.functions.transcendental import zeta + from sage.functions.gamma import gamma n = self.dimension() if n % 2 == 0: s = n // 2 @@ -3261,15 +3208,13 @@ def mass(self, backend='sage'): - ``backend`` -- default: ``'sage'``, or ``'magma'`` - OUTPUT: - - a rational number + OUTPUT: a rational number EXAMPLES:: sage: from sage.quadratic_forms.genera.genus import genera sage: G = genera((8,0), 1, even=True)[0] - sage: G.mass() + sage: G.mass() # optional - sage.symbolic 1/696729600 sage: G.mass(backend='magma') # optional - magma 1/696729600 @@ -3329,7 +3274,7 @@ def level(self): r""" Return the level of this genus. - This is the denominator of the inverse gram matrix + This is the denominator of the inverse Gram matrix of a representative. EXAMPLES:: @@ -3348,9 +3293,7 @@ def scale(self): The scale of `(L,b)` is defined as the ideal `b(L,L)`. - OUTPUT: - - an integer + OUTPUT: an integer EXAMPLES:: @@ -3382,7 +3325,7 @@ def norm(self): def _gram_from_jordan_block(p, block, discr_form=False): r""" - Return the gram matrix of this jordan block. + Return the Gram matrix of this jordan block. This is a helper for :meth:`discriminant_form` and :meth:`gram_matrix`. No input checks. @@ -3394,7 +3337,7 @@ def _gram_from_jordan_block(p, block, discr_form=False): - ``block`` -- a list of 3 integers or 5 integers if `p` is `2` - ``discr_form`` -- bool (default: ``False``); if ``True`` invert the scales - to obtain a gram matrix for the discriminant form instead. + to obtain a Gram matrix for the discriminant form instead. EXAMPLES:: diff --git a/src/sage/quadratic_forms/genera/normal_form.py b/src/sage/quadratic_forms/genera/normal_form.py index 616cc5c516b..e072adff683 100644 --- a/src/sage/quadratic_forms/genera/normal_form.py +++ b/src/sage/quadratic_forms/genera/normal_form.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.libs.pari sage.rings.padics r""" Normal forms for `p`-adic quadratic and bilinear forms @@ -87,7 +88,6 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.rings.padics.factory import Zp from sage.rings.integer_ring import ZZ from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF from sage.matrix.constructor import Matrix @@ -180,7 +180,7 @@ def p_adic_normal_form(G, p, precision=None, partial=False, debug=False): - ``D`` -- the jordan matrix over `\QQ_p` - ``B`` -- invertible transformation matrix over `\ZZ_p`, - i.e, ``D = B * G * B^T`` + i.e., `D = B * G * B^T` EXAMPLES:: @@ -235,13 +235,15 @@ def p_adic_normal_form(G, p, precision=None, partial=False, debug=False): TESTS:: - sage: Z = Matrix(ZZ,0,[]) + sage: Z = Matrix(ZZ, 0, []) sage: p_adic_normal_form(Z, 3) ([], []) sage: Z = matrix.zero(10) sage: p_adic_normal_form(Z, 3)[0] == 0 True """ + from sage.rings.padics.factory import Zp + p = ZZ(p) # input checks!! G0, denom = G._clear_denom() @@ -361,9 +363,7 @@ def _get_small_block_indices(G): - ``G`` -- a block_diagonal matrix consisting of `1` by `1` and `2` by `2` blocks - OUTPUT: - - - a list of integers + OUTPUT: a list of integers EXAMPLES:: @@ -397,12 +397,10 @@ def _get_homogeneous_block_indices(G): INPUT: - - ``G`` -- a block diagonal matrix over the p-adics + - ``G`` -- a block diagonal matrix over the `p`-adics with blocks of size at most `2`. - OUTPUT: - - - a list of integers + OUTPUT: a list of integers EXAMPLES:: @@ -459,7 +457,7 @@ def _homogeneous_normal_form(G, w): EXAMPLES:: sage: from sage.quadratic_forms.genera.normal_form import _homogeneous_normal_form - sage: R = Zp(2, type = 'fixed-mod', print_mode='terse', show_prec=False) + sage: R = Zp(2, type='fixed-mod', print_mode='terse', show_prec=False) sage: U = Matrix(R, 2, [0,1,1,0]) sage: V = Matrix(R, 2, [2,1,1,2]) sage: W1 = Matrix(R, 1, [1]) @@ -657,7 +655,7 @@ def _jordan_2_adic(G): sage: from sage.quadratic_forms.genera.normal_form import _jordan_2_adic sage: R = Zp(2, prec=3, print_mode='terse', show_prec=False) - sage: A4 = Matrix(R,4,[2, -1, 0, 0, -1, 2, -1, 0, 0, -1, 2, -1, 0, 0, -1, 2]) + sage: A4 = Matrix(R, 4, [2, -1, 0, 0, -1, 2, -1, 0, 0, -1, 2, -1, 0, 0, -1, 2]) sage: A4 [2 7 0 0] [7 2 7 0] @@ -786,7 +784,7 @@ def _normalize(G, normal_odd=True): EXAMPLES:: sage: from sage.quadratic_forms.genera.normal_form import _normalize - sage: R = Zp(3, prec = 5, type = 'fixed-mod', print_mode='series', show_prec=False) + sage: R = Zp(3, prec=5, type='fixed-mod', print_mode='series', show_prec=False) sage: G = matrix.diagonal(R, [1,7,3,3*5,3,9,-9,27*13]) sage: D, B =_normalize(G) sage: D @@ -863,7 +861,7 @@ def _normalize_2x2(G): INPUT: ``G`` - a `2` by `2` matrix over `\ZZ_p` - with ``type = 'fixed-mod'`` of the form:: + with ``type='fixed-mod'`` of the form:: [2a b] [ b 2c] * 2^n @@ -882,14 +880,14 @@ def _normalize_2x2(G): EXAMPLES:: sage: from sage.quadratic_forms.genera.normal_form import _normalize_2x2 - sage: R = Zp(2, prec = 15, type = 'fixed-mod', print_mode='series', show_prec=False) + sage: R = Zp(2, prec=15, type='fixed-mod', print_mode='series', show_prec=False) sage: G = Matrix(R, 2, [-17*2,3,3,23*2]) sage: B =_normalize_2x2(G) sage: B * G * B.T [2 1] [1 2] - sage: G = Matrix(R,2,[-17*4,3,3,23*2]) + sage: G = Matrix(R, 2, [-17*4,3,3,23*2]) sage: B = _normalize_2x2(G) sage: B*G*B.T [0 1] @@ -1040,7 +1038,7 @@ def _partial_normal_form_of_block(G): EXAMPLES:: sage: from sage.quadratic_forms.genera.normal_form import _partial_normal_form_of_block - sage: R = Zp(2,prec=4, type = 'fixed-mod',print_mode='terse', show_prec=False) + sage: R = Zp(2, prec=4, type='fixed-mod', print_mode='terse', show_prec=False) sage: U = Matrix(R, 2, [0,1,1,0]) sage: V = Matrix(R, 2, [2,1,1,2]) sage: W1 = Matrix(R, 1, [1]) @@ -1136,13 +1134,13 @@ def _relations(G, n): EXAMPLES:: sage: from sage.quadratic_forms.genera.normal_form import _relations - sage: R = Zp(2, type = 'fixed-mod',print_mode='terse', show_prec=False) - sage: U = Matrix(R,2,[0,1,1,0]) - sage: V = Matrix(R,2,[2,1,1,2]) - sage: W1 = Matrix(R,1,[1]) - sage: W3 = Matrix(R,1,[3]) - sage: W5 = Matrix(R,1,[5]) - sage: W7 = Matrix(R,1,[7]) + sage: R = Zp(2, type='fixed-mod', print_mode='terse', show_prec=False) + sage: U = Matrix(R, 2, [0,1,1,0]) + sage: V = Matrix(R, 2, [2,1,1,2]) + sage: W1 = Matrix(R, 1, [1]) + sage: W3 = Matrix(R, 1, [3]) + sage: W5 = Matrix(R, 1, [5]) + sage: W7 = Matrix(R, 1, [7]) sage: G = Matrix.block_diagonal(W1,W1) sage: b = _relations(G,1) sage: b * G * b.T @@ -1396,13 +1394,13 @@ def _two_adic_normal_forms(G, partial=False): EXAMPLES:: sage: from sage.quadratic_forms.genera.normal_form import _two_adic_normal_forms - sage: R = Zp(2, type = 'fixed-mod', print_mode='terse', show_prec=False) - sage: U = Matrix(R,2,[0,1,1,0]) - sage: V = Matrix(R,2,[2,1,1,2]) - sage: W1 = Matrix(R,1,[1]) - sage: W3 = Matrix(R,1,[3]) - sage: W5 = Matrix(R,1,[5]) - sage: W7 = Matrix(R,1,[7]) + sage: R = Zp(2, type='fixed-mod', print_mode='terse', show_prec=False) + sage: U = Matrix(R, 2, [0,1,1,0]) + sage: V = Matrix(R, 2, [2,1,1,2]) + sage: W1 = Matrix(R, 1, [1]) + sage: W3 = Matrix(R, 1, [3]) + sage: W5 = Matrix(R, 1, [5]) + sage: W7 = Matrix(R, 1, [7]) sage: G = Matrix.block_diagonal([2*W1,2*W1,4*V]) sage: B = _two_adic_normal_forms(G)[1] sage: B * G * B.T diff --git a/src/sage/quadratic_forms/genera/spinor_genus.py b/src/sage/quadratic_forms/genera/spinor_genus.py index 8e77961b864..7e6afff21a0 100644 --- a/src/sage/quadratic_forms/genera/spinor_genus.py +++ b/src/sage/quadratic_forms/genera/spinor_genus.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.groups r""" Spinor genus computations. @@ -201,7 +202,7 @@ def delta(self, r, prime=None): OUTPUT: - If a prime `p` is given the method returns + If a prime `p` is given, the method returns `\Delta_p(r)` otherwise returns `\Delta(r)` where both are as defined by Conway-Sloane in diff --git a/src/sage/quadratic_forms/qfsolve.py b/src/sage/quadratic_forms/qfsolve.py index 82b22328818..f8d82f48cbb 100644 --- a/src/sage/quadratic_forms/qfsolve.py +++ b/src/sage/quadratic_forms/qfsolve.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.libs.pari """ Solving quadratic equations @@ -46,7 +47,7 @@ def qfsolve(G): ALGORITHM: - Uses PARI/GP function ``qfsolve``. + Uses PARI/GP function :pari:`qfsolve`. EXAMPLES:: @@ -81,23 +82,23 @@ def qfsolve(G): def qfparam(G, sol): r""" - Parametrizes the conic defined by the matrix ``G``. + Parametrize the conic defined by the matrix `G`. INPUT: - - ``G`` -- a `3 \times 3`-matrix over `\QQ`. + - ``G`` -- a `3 \times 3`-matrix over `\QQ` - - ``sol`` -- a triple of rational numbers providing a solution - to sol*G*sol^t = 0. + - ``sol`` -- a triple of rational numbers providing a solution + to `x\cdot G\cdot x^t = 0` OUTPUT: A triple of polynomials that parametrizes all solutions of - x*G*x^t = 0 up to scaling. + `x\cdot G\cdot x^t = 0` up to scaling. ALGORITHM: - Uses PARI/GP function ``qfparam``. + Uses PARI/GP function :pari:`qfparam`. EXAMPLES:: @@ -110,7 +111,8 @@ def qfparam(G, sol): sage: ret = qfparam(M, sol); ret (-12*t^2 - 1, 24*t, 24) sage: ret.parent() - Ambient free module of rank 3 over the principal ideal domain Univariate Polynomial Ring in t over Rational Field + Ambient free module of rank 3 over the principal ideal domain + Univariate Polynomial Ring in t over Rational Field """ R = QQ['t'] mat = G.__pari__().qfparam(sol) @@ -124,15 +126,13 @@ def solve(self, c=0): INPUT: - - ``c`` -- (default: 0) a rational number. + - ``c`` -- (default: 0) a rational number - OUTPUT: - - - A non-zero vector `x` satisfying ``self(x) == c``. + OUTPUT: A non-zero vector `x` satisfying ``self(x) == c``. ALGORITHM: - Uses PARI's qfsolve(). Algorithm described by Jeroen Demeyer; see comments on :trac:`19112` + Uses PARI's :pari:`qfsolve`. Algorithm described by Jeroen Demeyer; see comments on :trac:`19112` EXAMPLES:: diff --git a/src/sage/quadratic_forms/quadratic_form.py b/src/sage/quadratic_forms/quadratic_form.py index 7e58c48fb36..8d5bd96bc32 100644 --- a/src/sage/quadratic_forms/quadratic_form.py +++ b/src/sage/quadratic_forms/quadratic_form.py @@ -23,6 +23,7 @@ from sage.matrix.constructor import matrix from sage.matrix.matrix_space import MatrixSpace +from sage.misc.lazy_import import lazy_import from sage.structure.element import is_Matrix from sage.rings.integer_ring import IntegerRing, ZZ from sage.rings.ring import Ring @@ -37,45 +38,31 @@ from sage.rings.polynomial.polynomial_element import Polynomial from sage.rings.polynomial.multi_polynomial import MPolynomial from sage.modules.free_module_element import vector -from sage.quadratic_forms.genera.genus import genera from sage.quadratic_forms.quadratic_form__evaluate import QFEvaluateVector, QFEvaluateMatrix from sage.structure.sage_object import SageObject -from sage.combinat.integer_lists.invlex import IntegerListsLex -from sage.misc.superseded import deprecated_function_alias - - -def QuadraticForm__constructor(R, n=None, entries=None): - """ - Wrapper for the QuadraticForm class constructor. This is meant - for internal use within the QuadraticForm class code only. You - should instead directly call QuadraticForm(). - - EXAMPLES:: - - sage: from sage.quadratic_forms.quadratic_form import QuadraticForm__constructor - sage: QuadraticForm__constructor(ZZ, 3) # Makes a generic quadratic form over the integers - Quadratic form in 3 variables over Integer Ring with coefficients: - [ 0 0 0 ] - [ * 0 0 ] - [ * * 0 ] - - """ - return QuadraticForm(R, n, entries) +from sage.misc.superseded import deprecation, deprecated_function_alias def is_QuadraticForm(Q): """ - Determine if the object Q is an element of the QuadraticForm class. + Determine if the object ``Q`` is an element of the :class:`QuadraticForm` class. + + This function is deprecated. EXAMPLES:: sage: Q = QuadraticForm(ZZ, 2, [1,2,3]) sage: from sage.quadratic_forms.quadratic_form import is_QuadraticForm - sage: is_QuadraticForm(Q) ##random + sage: is_QuadraticForm(Q) + doctest:...: DeprecationWarning: the function is_QuadraticForm is deprecated; + use isinstance(x, sage.quadratic_forms.quadratic_form.QuadraticForm) instead... True - sage: is_QuadraticForm(2) ##random + sage: is_QuadraticForm(2) False """ + deprecation(35305, + "the function is_QuadraticForm is deprecated; use " + "isinstance(x, sage.quadratic_forms.quadratic_form.QuadraticForm) instead") return isinstance(Q, QuadraticForm) @@ -118,7 +105,7 @@ def quadratic_form_from_invariants(F, rk, det, P, sminus): Quadratic form in 2 variables over Rational Field with coefficients: [ 5 0 ] [ * -3 ] - sage: all(q.hasse_invariant(p)==-1 for p in P) + sage: all(q.hasse_invariant(p) == -1 for p in P) True TESTS: @@ -197,8 +184,8 @@ def quadratic_form_from_invariants(F, rk, det, P, sminus): class QuadraticForm(SageObject): r""" - The ``QuadraticForm`` class represents a quadratic form in n variables with - coefficients in the ring R. + The ``QuadraticForm`` class represents a quadratic form in `n` variables with + coefficients in the ring `R`. INPUT: @@ -206,25 +193,25 @@ class QuadraticForm(SageObject): #. ``QuadraticForm(R, n, entries)``, where - - `R` -- ring for which the quadratic form is defined - - `n` -- an integer >= 0 + - ``R`` -- ring for which the quadratic form is defined + - ``n`` -- an integer `\geq 0` - ``entries`` -- a list of `n(n+1)/2` coefficients of the quadratic form in `R` (given lexicographically, or equivalently, by rows of the matrix) #. ``QuadraticForm(p)``, where - - `p` -- a homogeneous polynomial of degree `2` + - ``p`` -- a homogeneous polynomial of degree `2` #. ``QuadraticForm(R, n)``, where - - `R` -- a ring - - `n` -- a symmetric `n \times n` matrix with even diagonal (relative to + - ``R`` -- a ring + - ``n`` -- a symmetric `n \times n` matrix with even diagonal (relative to `R`) #. ``QuadraticForm(R)``, where - - `R` -- a symmetric `n \times n` matrix with even diagonal (relative to + - ``R`` -- a symmetric `n \times n` matrix with even diagonal (relative to its base ring) If the keyword argument ``unsafe_initialize`` is True, then the subsequent @@ -235,14 +222,11 @@ class QuadraticForm(SageObject): - ``determinant`` - OUTPUT: - - quadratic form + OUTPUT: quadratic form EXAMPLES:: - sage: Q = QuadraticForm(ZZ, 3, [1,2,3,4,5,6]) - sage: Q + sage: Q = QuadraticForm(ZZ, 3, [1,2,3,4,5,6]); Q Quadratic form in 3 variables over Integer Ring with coefficients: [ 1 2 3 ] [ * 4 5 ] @@ -250,8 +234,7 @@ class QuadraticForm(SageObject): :: - sage: Q = QuadraticForm(QQ, 3, [1,2,3,4/3 ,5,6]) - sage: Q + sage: Q = QuadraticForm(QQ, 3, [1,2,3,4/3,5,6]); Q Quadratic form in 3 variables over Rational Field with coefficients: [ 1 2 3 ] [ * 4/3 5 ] @@ -263,8 +246,7 @@ class QuadraticForm(SageObject): :: - sage: Q = QuadraticForm(QQ, 7, range(28)) - sage: Q + sage: Q = QuadraticForm(QQ, 7, range(28)); Q Quadratic form in 7 variables over Rational Field with coefficients: [ 0 1 2 3 4 5 6 ] [ * 7 8 9 10 11 12 ] @@ -277,7 +259,7 @@ class QuadraticForm(SageObject): :: sage: Q = QuadraticForm(QQ, 2, range(1,4)) - sage: A = Matrix(ZZ,2,2,[-1,0,0,1]) + sage: A = Matrix(ZZ, 2, 2, [-1,0,0,1]) sage: Q(A) Quadratic form in 2 variables over Rational Field with coefficients: [ 1 -2 ] @@ -285,7 +267,7 @@ class QuadraticForm(SageObject): :: - sage: m = matrix(2,2,[1,2,3,4]) + sage: m = matrix(2, 2, [1,2,3,4]) sage: m + m.transpose() [2 5] [5 8] @@ -323,11 +305,12 @@ class QuadraticForm(SageObject): # --------------------------- # Routines to compute the p-adic local normal form - from sage.quadratic_forms.quadratic_form__local_normal_form import \ - find_entry_with_minimal_scale_at_prime, \ - local_normal_form, \ - jordan_blocks_by_scale_and_unimodular, \ - jordan_blocks_in_unimodular_list_by_scale_power + lazy_import("sage.quadratic_forms.quadratic_form__local_normal_form", [ + "find_entry_with_minimal_scale_at_prime", + "local_normal_form", + "jordan_blocks_by_scale_and_unimodular", + "jordan_blocks_in_unimodular_list_by_scale_power" + ]) # Routines to perform elementary variable substitutions from sage.quadratic_forms.quadratic_form__variable_substitutions import \ @@ -382,9 +365,10 @@ class QuadraticForm(SageObject): count_congruence_solutions__bad_type_II # Routines to be called by the user to compute local densities - from sage.quadratic_forms.quadratic_form__local_density_interfaces import \ - local_density, \ - local_primitive_density + lazy_import("sage.quadratic_forms.quadratic_form__local_density_interfaces", [ + "local_density", + "local_primitive_density" + ]) # Routines for computing with ternary forms from sage.quadratic_forms.quadratic_form__ternary_Tornaria import \ @@ -420,8 +404,9 @@ class QuadraticForm(SageObject): theta_by_cholesky # Routines to compute the product of all local densities - from sage.quadratic_forms.quadratic_form__siegel_product import \ - siegel_product + lazy_import("sage.quadratic_forms.quadratic_form__siegel_product", [ + "siegel_product" + ]) # Routines to compute p-neighbors from sage.quadratic_forms.quadratic_form__neighbors import \ @@ -439,46 +424,51 @@ class QuadraticForm(SageObject): minkowski_reduction, \ minkowski_reduction_for_4vars__SP # Wrappers for Conway-Sloane genus routines (in ./genera/) - from sage.quadratic_forms.quadratic_form__genus import \ - global_genus_symbol, \ - local_genus_symbol, \ - CS_genus_symbol_list + lazy_import("sage.quadratic_forms.quadratic_form__genus", [ + "global_genus_symbol", + "local_genus_symbol", + "CS_genus_symbol_list" + ]) # Routines to compute local masses for ZZ. - from sage.quadratic_forms.quadratic_form__mass import \ - shimura_mass__maximal, \ - GHY_mass__maximal - from sage.quadratic_forms.quadratic_form__mass__Siegel_densities import \ - mass__by_Siegel_densities, \ - Pall_mass_density_at_odd_prime, \ - Watson_mass_at_2, \ - Kitaoka_mass_at_2, \ - mass_at_two_by_counting_mod_power - from sage.quadratic_forms.quadratic_form__mass__Conway_Sloane_masses import \ - parity, \ - is_even, \ - is_odd, \ - conway_species_list_at_odd_prime, \ - conway_species_list_at_2, \ - conway_octane_of_this_unimodular_Jordan_block_at_2, \ - conway_diagonal_factor, \ - conway_cross_product_doubled_power, \ - conway_type_factor, \ - conway_p_mass, \ - conway_standard_p_mass, \ - conway_standard_mass, \ - conway_mass + lazy_import("sage.quadratic_forms.quadratic_form__mass", [ + "shimura_mass__maximal", + "GHY_mass__maximal" + ]) + lazy_import("sage.quadratic_forms.quadratic_form__mass__Siegel_densities", [ + "mass__by_Siegel_densities", + "Pall_mass_density_at_odd_prime", + "Watson_mass_at_2", + "Kitaoka_mass_at_2", + "mass_at_two_by_counting_mod_power" + ]) + lazy_import("sage.quadratic_forms.quadratic_form__mass__Conway_Sloane_masses", [ + "parity", + "is_even", + "is_odd", + "conway_species_list_at_odd_prime", + "conway_species_list_at_2", + "conway_octane_of_this_unimodular_Jordan_block_at_2", + "conway_diagonal_factor", + "conway_cross_product_doubled_power", + "conway_type_factor", + "conway_p_mass", + "conway_standard_p_mass", + "conway_standard_mass", + "conway_mass" # conway_generic_mass, \ # conway_p_mass_adjustment + ]) # Routines to check local representability of numbers - from sage.quadratic_forms.quadratic_form__local_representation_conditions import \ - local_representation_conditions, \ - is_locally_universal_at_prime, \ - is_locally_universal_at_all_primes, \ - is_locally_universal_at_all_places, \ - is_locally_represented_number_at_place, \ - is_locally_represented_number + lazy_import("sage.quadratic_forms.quadratic_form__local_representation_conditions", [ + "local_representation_conditions", + "is_locally_universal_at_prime", + "is_locally_universal_at_all_primes", + "is_locally_universal_at_all_places", + "is_locally_represented_number_at_place", + "is_locally_represented_number" + ]) # Routines to make a split local covering of the given quadratic form. from sage.quadratic_forms.quadratic_form__split_local_covering import \ @@ -488,15 +478,16 @@ class QuadraticForm(SageObject): split_local_cover # Routines to make automorphisms of the given quadratic form. - from sage.quadratic_forms.quadratic_form__automorphisms import \ - basis_of_short_vectors, \ - short_vector_list_up_to_length, \ - short_primitive_vector_list_up_to_length, \ - _compute_automorphisms, \ - automorphism_group, \ - automorphisms, \ - number_of_automorphisms, \ - set_number_of_automorphisms + lazy_import("sage.quadratic_forms.quadratic_form__automorphisms", [ + "basis_of_short_vectors", + "short_vector_list_up_to_length", + "short_primitive_vector_list_up_to_length", + "_compute_automorphisms", + "automorphism_group", + "automorphisms", + "number_of_automorphisms", + "set_number_of_automorphisms" + ]) # Routines to test the local and global equivalence/isometry of two quadratic forms. from sage.quadratic_forms.quadratic_form__equivalence_testing import \ @@ -506,7 +497,14 @@ class QuadraticForm(SageObject): is_rationally_isometric # Routines for solving equations of the form Q(x) = c. - from sage.quadratic_forms.qfsolve import solve + lazy_import("sage.quadratic_forms.qfsolve", [ + "solve" + ]) + + # Genus + lazy_import("sage.quadratic_forms.genera.genus", [ + "genera" + ]) def __init__(self, R, n=None, entries=None, unsafe_initialization=False, number_of_automorphisms=None, determinant=None): """ @@ -593,6 +591,8 @@ def __init__(self, R, n=None, entries=None, unsafe_initialization=False, number_ elif n == 1: exponents = [2] else: + from sage.combinat.integer_lists.invlex import IntegerListsLex + exponents = IntegerListsLex(2, length=n) for alpha in exponents: entries.append(p[alpha]) @@ -661,7 +661,7 @@ def __init__(self, R, n=None, entries=None, unsafe_initialization=False, number_ def list_external_initializations(self): """ Return a list of the fields which were set externally at - creation, and not created through the usual QuadraticForm + creation, and not created through the usual :class:`QuadraticForm` methods. These fields are as good as the external process that made them, and are thus not guaranteed to be correct. @@ -670,20 +670,23 @@ def list_external_initializations(self): sage: Q = QuadraticForm(ZZ, 2, [1,0,5]) sage: Q.list_external_initializations() [] - sage: T = Q.theta_series() - sage: Q.list_external_initializations() + sage: T = Q.theta_series() # optional - sage.libs.pari + sage: Q.list_external_initializations() # optional - sage.libs.pari [] - sage: Q = QuadraticForm(ZZ, 2, [1,0,5], unsafe_initialization=False, number_of_automorphisms=3, determinant=0) - sage: Q.list_external_initializations() + sage: Q = QuadraticForm(ZZ, 2, [1,0,5], unsafe_initialization=False, # optional - sage.libs.pari + ....: number_of_automorphisms=3, determinant=0) + sage: Q.list_external_initializations() # optional - sage.libs.pari [] :: - sage: Q = QuadraticForm(ZZ, 2, [1,0,5], unsafe_initialization=False, number_of_automorphisms=3, determinant=0) - sage: Q.list_external_initializations() + sage: Q = QuadraticForm(ZZ, 2, [1,0,5], unsafe_initialization=False, # optional - sage.libs.pari + ....: number_of_automorphisms=3, determinant=0) + sage: Q.list_external_initializations() # optional - sage.libs.pari [] - sage: Q = QuadraticForm(ZZ, 2, [1,0,5], unsafe_initialization=True, number_of_automorphisms=3, determinant=0) - sage: Q.list_external_initializations() + sage: Q = QuadraticForm(ZZ, 2, [1,0,5], unsafe_initialization=True, # optional - sage.libs.pari + ....: number_of_automorphisms=3, determinant=0) + sage: Q.list_external_initializations() # optional - sage.libs.pari ['number_of_automorphisms', 'determinant'] """ return deepcopy(self._external_initialization_list) @@ -695,7 +698,7 @@ def __pari__(self): EXAMPLES:: sage: Q = QuadraticForm(ZZ, 2, [1,0,5]) - sage: Q.__pari__() + sage: Q.__pari__() # optional - sage.libs.pari [2, 0; 0, 10] """ @@ -708,7 +711,7 @@ def _pari_init_(self): EXAMPLES:: sage: Q = QuadraticForm(ZZ, 2, [1,0,5]) - sage: Q._pari_init_() + sage: Q._pari_init_() # optional - sage.libs.pari 'Mat([2,0;0,10])' """ return self.matrix()._pari_init_() @@ -723,7 +726,6 @@ def _repr_(self): Quadratic form in 2 variables over Integer Ring with coefficients: [ 1 3 ] [ * 5 ] - """ n = self.dim() out_str = "Quadratic form in " + str(n) + " variables over " + str(self.base_ring()) + " with coefficients: \n" @@ -748,7 +750,6 @@ def _latex_(self): sage: Q = QuadraticForm(ZZ, 2, [2,3,5]) sage: Q._latex_() 'Quadratic form in 2 variables over Integer Ring with coefficients: \\newline\\left[ \\begin{array}{cc}2 & 3 & * & 5 & \\end{array} \\right]' - """ n = self.dim() out_str = "" @@ -767,8 +768,8 @@ def _latex_(self): return out_str def __getitem__(self, ij): - """ - Return the coefficient `a_{ij}` of `x_i * x_j`. + r""" + Return the coefficient `a_{ij}` of `x_i\cdot x_j`. EXAMPLES:: @@ -793,8 +794,8 @@ def __getitem__(self, ij): return self.__coeffs[i*self.__n - i*(i-1)//2 + j - i] def __setitem__(self, ij, coeff): - """ - Set the coefficient `a_{ij}` in front of `x_i * x_j`. + r""" + Set the coefficient `a_{ij}` in front of `x_i\cdot x_j`. EXAMPLES:: @@ -837,10 +838,10 @@ def __hash__(self): sage: Q1 = QuadraticForm(QQ, 2, [1,1,1]) sage: Q2 = QuadraticForm(QQ, 2, [1,1,1]) - sage: Q3 = QuadraticForm(QuadraticField(2), 2, [1,1,1]) + sage: Q3 = QuadraticForm(QuadraticField(2), 2, [1,1,1]) # optional - sage.rings.number_field sage: hash(Q1) == hash(Q2) True - sage: hash(Q1) == hash(Q3) + sage: hash(Q1) == hash(Q3) # optional - sage.rings.number_field False """ return hash(self.__base_ring) ^ hash(tuple(self.__coeffs)) @@ -878,8 +879,7 @@ def __add__(self, right): EXAMPLES:: - sage: Q = QuadraticForm(ZZ, 2, [1,4,10]) - sage: Q + sage: Q = QuadraticForm(ZZ, 2, [1,4,10]); Q Quadratic form in 2 variables over Integer Ring with coefficients: [ 1 4 ] [ * 10 ] @@ -916,12 +916,11 @@ def sum_by_coefficients_with(self, right): EXAMPLES:: - sage: Q = QuadraticForm(ZZ, 2, [1,4,10]) - sage: Q + sage: Q = QuadraticForm(ZZ, 2, [1,4,10]); Q Quadratic form in 2 variables over Integer Ring with coefficients: [ 1 4 ] [ * 10 ] - sage: Q+Q + sage: Q + Q Quadratic form in 4 variables over Integer Ring with coefficients: [ 1 4 0 0 ] [ * 10 0 0 ] @@ -969,15 +968,15 @@ def sum_by_coefficients_with(self, right): # ========================================================================================================================= def __call__(self, v): - """ - Evaluate this quadratic form Q on a vector or matrix of elements + r""" + Evaluate this quadratic form `Q` on a vector or matrix of elements coercible to the base ring of the quadratic form. If a vector - is given then the output will be the ring element Q(`v`), but if a - matrix is given then the output will be the quadratic form Q' + is given then the output will be the ring element `Q(v)`, but if a + matrix is given then the output will be the quadratic form `Q'` which in matrix notation is given by: .. MATH:: - Q' = v^t * Q * v. + Q' = v^t\cdot Q\cdot v. EXAMPLES: @@ -1084,12 +1083,13 @@ def __call__(self, v): def _is_even_symmetric_matrix_(self, A, R=None): """ - Tests if a matrix is symmetric, defined over R, and has even diagonal in R. + Tests if a matrix is symmetric, defined over `R`, and has even diagonal in `R`. INPUT: - A -- matrix - R -- ring + - ``A`` -- matrix + + - ``R`` -- ring EXAMPLES:: @@ -1147,8 +1147,8 @@ def _is_even_symmetric_matrix_(self, A, R=None): # ===================================================================================================== def matrix(self): - """ - Return the Hessian matrix A for which Q(X) = `(1/2) * X^t * A * X`. + r""" + Return the Hessian matrix `A` for which `Q(X) = (1/2) X^t\cdot A\cdot X`. EXAMPLES:: @@ -1162,13 +1162,12 @@ def matrix(self): return self.Hessian_matrix() def Hessian_matrix(self): - """ - Return the Hessian matrix A for which Q(X) = `(1/2) * X^t * A * X`. + r""" + Return the Hessian matrix `A` for which `Q(X) = (1/2) X^t\cdot A\cdot X`. EXAMPLES:: - sage: Q = QuadraticForm(QQ, 2, range(1,4)) - sage: Q + sage: Q = QuadraticForm(QQ, 2, range(1,4)); Q Quadratic form in 2 variables over Rational Field with coefficients: [ 1 2 ] [ * 3 ] @@ -1190,13 +1189,13 @@ def Hessian_matrix(self): return matrix(self.base_ring(), self.dim(), self.dim(), mat_entries) def Gram_matrix_rational(self): - """ - Return a (symmetric) Gram matrix A for the quadratic form Q, + r""" + Return a (symmetric) Gram matrix `A` for the quadratic form `Q`, meaning that .. MATH:: - Q(x) = x^t * A * x, + Q(x) = x^t\cdot A\cdot x, defined over the fraction field of the base ring. @@ -1215,16 +1214,16 @@ def Gram_matrix_rational(self): return (ZZ(1) / ZZ(2)) * self.matrix() def Gram_matrix(self): - """ - Return a (symmetric) Gram matrix A for the quadratic form Q, + r""" + Return a (symmetric) Gram matrix `A` for the quadratic form `Q`, meaning that .. MATH:: - Q(x) = x^t * A * x, + Q(x) = x^t\cdot A\cdot x, - defined over the base ring of Q. If this is not possible, - then a TypeError is raised. + defined over the base ring of `Q`. If this is not possible, + then a :class:`TypeError` is raised. EXAMPLES:: @@ -1252,7 +1251,7 @@ def Gram_matrix(self): raise TypeError("this form does not have an integral Gram matrix") def has_integral_Gram_matrix(self): - """ + r""" Return whether the quadratic form has an integral Gram matrix (with respect to its base ring). A warning is issued if the form is defined over a field, since in that case the return is trivially true. @@ -1304,17 +1303,15 @@ def gcd(self): def polynomial(self,names='x'): r""" - Return the polynomial in 'n' variables of the quadratic form in the ring 'R[names].' + Return the quadratic form as a polynomial in `n` variables. INPUT: - -'self' - a quadratic form over a commutative ring. - -'names' - the name of the variables. Digits will be appended to the name for each different canonical - variable e.g x1, x2, x3 etc. + - ``self`` - a quadratic form over a commutative ring - OUTPUT: + - ``names`` - specification of the names of the variables; see :func:`PolynomialRing` - The polynomial form of the quadratic form. + OUTPUT: The polynomial form of the quadratic form. EXAMPLES:: @@ -1324,17 +1321,19 @@ def polynomial(self,names='x'): :: - sage: F. = NumberField(x^2 - 5) - sage: Z = F.ring_of_integers() - sage: Q = QuadraticForm(Z,3,[2*a, 3*a, 0 , 1 - a, 0, 2*a + 4]) - sage: P = Q.polynomial(names='y'); P + sage: F. = NumberField(x^2 - 5) # optional - sage.rings.number_field + sage: Z = F.ring_of_integers() # optional - sage.rings.number_field + sage: Q = QuadraticForm(Z, 3, [2*a, 3*a, 0, 1 - a, 0, 2*a + 4]) # optional - sage.rings.number_field + sage: P = Q.polynomial(names='y'); P # optional - sage.rings.number_field 2*a*y0^2 + 3*a*y0*y1 + (-a + 1)*y1^2 + (2*a + 4)*y2^2 - sage: Q = QuadraticForm(F,4,[a, 3*a, 0, 1 - a, a - 3, 0, 2*a + 4, 4 + a, 0, 1]) - sage: Q.polynomial(names='z') - a*z0^2 + (3*a)*z0*z1 + (a - 3)*z1^2 + (a + 4)*z2^2 + (-a + 1)*z0*z3 + (2*a + 4)*z1*z3 + z3^2 - sage: B. = QuaternionAlgebra(F,-1,-1) - sage: Q = QuadraticForm(B, 3, [2*a, 3*a, i, 1 - a, 0, 2*a + 4]) - sage: Q.polynomial() + sage: Q = QuadraticForm(F, 4, # optional - sage.rings.number_field + ....: [a, 3*a, 0, 1 - a, a - 3, 0, 2*a + 4, 4 + a, 0, 1]) + sage: Q.polynomial(names='z') # optional - sage.rings.number_field + a*z0^2 + (3*a)*z0*z1 + (a - 3)*z1^2 + (a + 4)*z2^2 + + (-a + 1)*z0*z3 + (2*a + 4)*z1*z3 + z3^2 + sage: B. = QuaternionAlgebra(F,-1,-1) # optional - sage.rings.number_field + sage: Q = QuadraticForm(B, 3, [2*a, 3*a, i, 1 - a, 0, 2*a + 4]) # optional - sage.rings.number_field + sage: Q.polynomial() # optional - sage.rings.number_field Traceback (most recent call last): ... ValueError: Can only create polynomial rings over commutative rings. @@ -1397,7 +1396,7 @@ def from_polynomial(poly): def is_primitive(self): """ Determines if the given integer-valued form is primitive - (i.e. not an integer (>1) multiple of another integer-valued + (i.e. not an integer (`> 1`) multiple of another integer-valued quadratic form). EXAMPLES:: @@ -1413,8 +1412,8 @@ def is_primitive(self): return (self.gcd() == 1) def primitive(self): - """ - Return a primitive version of an integer-valued quadratic form, defined over `ZZ`. + r""" + Return a primitive version of an integer-valued quadratic form, defined over `\ZZ`. EXAMPLES:: @@ -1455,7 +1454,7 @@ def adjoint_primitive(self): def dim(self): """ - Gives the number of variables of the quadratic form. + Return the number of variables of the quadratic form. EXAMPLES:: @@ -1474,20 +1473,19 @@ def dim(self): def base_ring(self): """ - Gives the ring over which the quadratic form is defined. + Return the ring over which the quadratic form is defined. EXAMPLES:: sage: Q = QuadraticForm(ZZ, 2, [1,2,3]) sage: Q.base_ring() Integer Ring - """ return self.__base_ring def coefficients(self): - """ - Gives the matrix of upper triangular coefficients, + r""" + Return the matrix of upper triangular coefficients, by reading across the rows from the main diagonal. EXAMPLES:: @@ -1495,24 +1493,23 @@ def coefficients(self): sage: Q = QuadraticForm(ZZ, 2, [1,2,3]) sage: Q.coefficients() [1, 2, 3] - """ return self.__coeffs def det(self): - """ - Gives the determinant of the Gram matrix of 2*Q, or - equivalently the determinant of the Hessian matrix of Q. + r""" + Return the determinant of the Gram matrix of `2\cdot Q`, or + equivalently the determinant of the Hessian matrix of `Q`. - (Note: This is always defined over the same ring as the - quadratic form.) + .. NOTE: + + This is always defined over the same ring as the quadratic form. EXAMPLES:: sage: Q = QuadraticForm(ZZ, 2, [1,2,3]) sage: Q.det() 8 - """ try: return self.__det @@ -1528,45 +1525,46 @@ def det(self): return new_det def Gram_det(self): - """ - Gives the determinant of the Gram matrix of Q. + r""" + Return the determinant of the Gram matrix of `Q`. + + .. NOTE:: - (Note: This is defined over the fraction field of the ring of - the quadratic form, but is often not defined over the same - ring as the quadratic form.) + This is defined over the fraction field of the ring of + the quadratic form, but is often not defined over the same + ring as the quadratic form. EXAMPLES:: sage: Q = QuadraticForm(ZZ, 2, [1,2,3]) sage: Q.Gram_det() 2 - """ return self.det() / ZZ(2**self.dim()) def change_ring(self, R): """ Alters the quadratic form to have all coefficients - defined over the new base_ring R. Here R must be + defined over the new base ring `R`. Here `R` must be coercible to from the current base ring. - Note: This is preferable to performing an explicit - coercion through the base_ring() method, which does - not affect the individual coefficients. This is - particularly useful for performing fast modular - arithmetic evaluations. + .. NOTE:: + + This is preferable to performing an explicit + coercion through the :meth:`base_ring` method, which does + not affect the individual coefficients. This is + particularly useful for performing fast modular + arithmetic evaluations. INPUT: - - - R -- a ring - OUTPUT: - - quadratic form + - ``R`` -- a ring + + OUTPUT: quadratic form EXAMPLES:: - sage: Q = DiagonalQuadraticForm(ZZ,[1,1]); Q + sage: Q = DiagonalQuadraticForm(ZZ, [1,1]); Q Quadratic form in 2 variables over Integer Ring with coefficients: [ 1 0 ] [ * 1 ] @@ -1592,8 +1590,8 @@ def change_ring(self, R): def level(self): r""" Determines the level of the quadratic form over a PID, which is a - generator for the smallest ideal `N` of `R` such that N * (the matrix of - 2*Q)^(-1) is in R with diagonal in 2*R. + generator for the smallest ideal `N` of `R` such that `N\cdot (` the matrix of + `2*Q` `)^{(-1)}` is in `R` with diagonal in `2R`. Over `\ZZ` this returns a non-negative number. @@ -1607,13 +1605,13 @@ def level(self): sage: Q1 = QuadraticForm(QQ, 2, range(1,4)) sage: Q1.level() # random - UserWarning: Warning -- The level of a quadratic form over a field is always 1. Do you really want to do this?!? + UserWarning: Warning -- The level of a quadratic form over a field is always 1. + Do you really want to do this?!? 1 sage: Q = DiagonalQuadraticForm(ZZ, [1,3,5,7]) sage: Q.level() 420 - """ # Try to return the cached level try: @@ -1660,14 +1658,16 @@ def level(self): return lvl def level_ideal(self): - """ - Determines the level of the quadratic form (over R), which is the - smallest ideal N of R such that N * (the matrix of 2*Q)^(-1) is - in R with diagonal in 2*R. + r""" + Determine the level of the quadratic form (over `R`), which is the + smallest ideal `N` of `R` such that `N \cdot (` the matrix of `2Q` `)^{(-1)}` is + in `R` with diagonal in `2R`. (Caveat: This always returns the principal ideal when working over a field!) - WARNING: THIS ONLY WORKS OVER A PID RING OF INTEGERS FOR NOW! - (Waiting for Sage fractional ideal support.) + .. WARNING:: + + This only works over a PID ring of integers for now! + (Waiting for Sage fractional ideal support.) EXAMPLES:: @@ -1701,46 +1701,44 @@ def bilinear_map(self, v, w): INPUT: - `v, w` -- two vectors - - OUTPUT: + - ``v``, ``w`` -- two vectors - an element of the base ring `R`. + OUTPUT: an element of the base ring `R`. EXAMPLES: First, an example over `\ZZ`:: - sage: Q = QuadraticForm(ZZ,3,[1,4,0,1,4,1]) - sage: v = vector(ZZ,(1,2,0)) - sage: w = vector(ZZ,(0,1,1)) - sage: Q.bilinear_map(v,w) + sage: Q = QuadraticForm(ZZ, 3, [1,4,0,1,4,1]) + sage: v = vector(ZZ, (1,2,0)) + sage: w = vector(ZZ, (0,1,1)) + sage: Q.bilinear_map(v, w) 8 This also works over `\QQ`:: - sage: Q = QuadraticForm(QQ,2,[1/2,2,1]) - sage: v = vector(QQ,(1,1)) - sage: w = vector(QQ,(1/2,2)) - sage: Q.bilinear_map(v,w) + sage: Q = QuadraticForm(QQ, 2, [1/2,2,1]) + sage: v = vector(QQ, (1,1)) + sage: w = vector(QQ, (1/2,2)) + sage: Q.bilinear_map(v, w) 19/4 The vectors must have the correct length:: - sage: Q = DiagonalQuadraticForm(ZZ,[1,7,7]) + sage: Q = DiagonalQuadraticForm(ZZ, [1,7,7]) sage: v = vector((1,2)) sage: w = vector((1,1,1)) - sage: Q.bilinear_map(v,w) + sage: Q.bilinear_map(v, w) Traceback (most recent call last): ... TypeError: vectors must have length 3 This does not work if the characteristic is 2:: - sage: Q = DiagonalQuadraticForm(GF(2),[1,1,1]) - sage: v = vector((1,1,1)) - sage: w = vector((1,1,1)) - sage: Q.bilinear_map(v,w) + sage: Q = DiagonalQuadraticForm(GF(2), [1,1,1]) # optional - sage.rings.finite_rings + sage: v = vector((1,1,1)) # optional - sage.rings.finite_rings + sage: w = vector((1,1,1)) # optional - sage.rings.finite_rings + sage: Q.bilinear_map(v, w) # optional - sage.rings.finite_rings Traceback (most recent call last): ... TypeError: not defined for rings of characteristic 2 @@ -1751,8 +1749,6 @@ def bilinear_map(self, v, w): raise TypeError("not defined for rings of characteristic 2") return (self(v+w) - self(v) - self(w))/2 - genera = staticmethod(genera) - def DiagonalQuadraticForm(R, diag): """ @@ -1760,17 +1756,14 @@ def DiagonalQuadraticForm(R, diag): INPUT: - - `R` -- ring - - ``diag`` -- list/tuple of elements coercible to R - - OUTPUT: + - ``R`` -- ring + - ``diag`` -- list/tuple of elements coercible to `R` - quadratic form + OUTPUT: quadratic form EXAMPLES:: - sage: Q = DiagonalQuadraticForm(ZZ, [1,3,5,7]) - sage: Q + sage: Q = DiagonalQuadraticForm(ZZ, [1,3,5,7]); Q Quadratic form in 4 variables over Integer Ring with coefficients: [ 1 0 0 0 ] [ * 3 0 0 ] diff --git a/src/sage/quadratic_forms/quadratic_form__automorphisms.py b/src/sage/quadratic_forms/quadratic_form__automorphisms.py index 4e6453b34d3..d12fc95eb5c 100644 --- a/src/sage/quadratic_forms/quadratic_form__automorphisms.py +++ b/src/sage/quadratic_forms/quadratic_form__automorphisms.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.libs.pari """ Automorphisms of Quadratic Forms """ @@ -8,7 +9,6 @@ # https://www.gnu.org/licenses/ # **************************************************************************** from sage.misc.cachefunc import cached_method -from sage.libs.pari.all import pari from sage.matrix.constructor import Matrix from sage.rings.integer_ring import ZZ @@ -20,7 +20,7 @@ @cached_method def basis_of_short_vectors(self, show_lengths=False): r""" - Return a basis for `\ZZ^n` made of vectors with minimal lengths Q(`v`). + Return a basis for `\ZZ^n` made of vectors with minimal lengths `Q(v)`. OUTPUT: @@ -101,11 +101,11 @@ def basis_of_short_vectors(self, show_lengths=False): def short_vector_list_up_to_length(self, len_bound, up_to_sign_flag=False): """ Return a list of lists of short vectors `v`, sorted by length, with - Q(`v`) < len_bound. + `Q(v) <` ``len_bound``. INPUT: - - ``len_bound`` -- bound for the length of the vectors. + - ``len_bound`` -- bound for the length of the vectors - ``up_to_sign_flag`` -- (default: ``False``) if set to True, then only one of the vectors of the pair `[v, -v]` is listed. @@ -186,6 +186,8 @@ def short_vector_list_up_to_length(self, len_bound, up_to_sign_flag=False): raise ValueError("Quadratic form must be positive definite " "in order to enumerate short vectors") + from sage.libs.pari.all import pari + if len_bound <= 0: return [] @@ -224,8 +226,8 @@ def short_vector_list_up_to_length(self, len_bound, up_to_sign_flag=False): def short_primitive_vector_list_up_to_length(self, len_bound, up_to_sign_flag=False): r""" Return a list of lists of short primitive vectors `v`, sorted by length, with - Q(`v`) < len_bound. The list in output `[i]` indexes all vectors of - length `i`. If the up_to_sign_flag is set to ``True``, then only one of + `Q(v) <` ``len_bound``. The list in output `[i]` indexes all vectors of + length `i`. If the ``up_to_sign_flag`` is set to ``True``, then only one of the vectors of the pair `[v, -v]` is listed. .. NOTE:: @@ -374,13 +376,11 @@ def automorphisms(self): def number_of_automorphisms(self): - """ - Return the number of automorphisms (of det 1 and -1) of + r""" + Return the number of automorphisms (of det `1` and `-1`) of the quadratic form. - OUTPUT: - - an integer >= 2. + OUTPUT: an integer `\geq 2`. EXAMPLES:: @@ -404,13 +404,13 @@ def number_of_automorphisms(self): def set_number_of_automorphisms(self, num_autos): - """ + r""" Set the number of automorphisms to be the value given. No error checking is performed, to this may lead to erroneous results. The fact that this result was set externally is recorded in the internal list of external initializations, accessible by the - method list_external_initializations(). + method :meth:`list_external_initializations`. OUTPUT: None diff --git a/src/sage/quadratic_forms/quadratic_form__count_local_2.py b/src/sage/quadratic_forms/quadratic_form__count_local_2.py index 6b4eebd26fc..999da6428de 100644 --- a/src/sage/quadratic_forms/quadratic_form__count_local_2.py +++ b/src/sage/quadratic_forms/quadratic_form__count_local_2.py @@ -13,21 +13,21 @@ def count_congruence_solutions_as_vector(self, p, k, m, zvec, nzvec): - """ - Gives the number of integer solution vectors `x` satisfying the - congruence Q(`x`) `= m (mod p^k)` of each solution type (i.e. All, + r""" + Return the number of integer solution vectors `x` satisfying the + congruence `Q(x) = m` (mod `p^k`) of each solution type (i.e. All, Good, Zero, Bad, BadI, BadII) which satisfy the additional congruence conditions of having certain coefficients = 0 (mod `p`) and certain collections of coefficients not congruent to the zero vector (mod `p`). A solution vector `x` satisfies the additional congruence conditions - specified by zvec and nzvec (and therefore is counted) iff both of + specified by ``zvec`` and ``nzvec`` (and therefore is counted) iff both of the following conditions hold: - 1) `x[i] == 0 (mod p)` for all `i` in zvec + 1. `x_i = 0` (mod `p`) for all `i` in ``zvec`` - 2) `x[i] != 0 (mod p) for all i` in nzvec + 2. `x_i \neq 0` (mod `p`) for all `i` in ``nzvec`` REFERENCES: @@ -37,14 +37,14 @@ def count_congruence_solutions_as_vector(self, p, k, m, zvec, nzvec): INPUT: - - `p` -- prime number > 0 - - `k` -- an integer > 0 - - `m` -- an integer (depending only on mod `p^k`) - - zvec, nzvec -- a list of integers in range(self.dim()), or None + - ``p`` -- prime number > 0 + - ``k`` -- an integer > 0 + - ``m`` -- an integer (depending only on mod `p^k`) + - ``zvec``, ``nzvec`` -- lists of integers in ``range(self.dim())``, or ``None`` OUTPUT: - a list of six integers >= 0 representing the solution types: + a list of six integers `\geq 0` representing the solution types: [All, Good, Zero, Bad, BadI, BadII] @@ -73,156 +73,150 @@ def count_congruence_solutions_as_vector(self, p, k, m, zvec, nzvec): ##/////////////////////////////////////////// def count_congruence_solutions(self, p, k, m, zvec, nzvec): - """ - Counts all solutions of Q(`x`) `= m (mod p^k)` satisfying the + r""" + Count all solutions of `Q(x) = m` (mod `p^k`) satisfying the additional congruence conditions described in - QuadraticForm.count_congruence_solutions_as_vector(). + :meth:`QuadraticForm.count_congruence_solutions_as_vector`. INPUT: - `p` -- prime number > 0 + - ``p`` -- prime number > 0 - `k` -- an integer > 0 + - ``k`` -- an integer > 0 - `m` -- an integer (depending only on mod `p^k`) + - ``m`` -- an integer (depending only on mod `p^k`) - zvec, nzvec -- a list of integers in range(self.dim()), or None + - ``zvec``, ``nzvec`` -- lists of integers in ``range(self.dim())``, or ``None`` EXAMPLES:: sage: Q = DiagonalQuadraticForm(ZZ, [1,2,3]) sage: Q.count_congruence_solutions(3, 1, 0, None, None) 15 - """ return CountAllLocalTypesNaive(self, p, k, m, zvec, nzvec)[0] def count_congruence_solutions__good_type(self, p, k, m, zvec, nzvec): - """ - Counts the good-type solutions of Q(x) = m (mod p^k) satisfying the + r""" + Count the good-type solutions of `Q(x) = m` (mod `p^k`) satisfying the additional congruence conditions described in - QuadraticForm.count_congruence_solutions_as_vector(). + :meth:`QuadraticForm.count_congruence_solutions_as_vector`. INPUT: - `p` -- prime number > 0 + - ``p`` -- prime number > 0 - `k` -- an integer > 0 + - ``k`` -- an integer > 0 - `m` -- an integer (depending only on mod `p^k`) + - ``m`` -- an integer (depending only on mod `p^k`) - zvec, nzvec -- a list of integers up to dim(Q) + - ``zvec``, ``nzvec`` -- lists of integers up to dim(`Q`) EXAMPLES:: sage: Q = DiagonalQuadraticForm(ZZ, [1,2,3]) sage: Q.count_congruence_solutions__good_type(3, 1, 0, None, None) 12 - """ return CountAllLocalTypesNaive(self, p, k, m, zvec, nzvec)[1] def count_congruence_solutions__zero_type(self, p, k, m, zvec, nzvec): """ - Counts the zero-type solutions of Q(`x`) = `m (mod p^k)` satisfying the + Count the zero-type solutions of `Q(x) = m` (mod `p^k`) satisfying the additional congruence conditions described in - QuadraticForm.count_congruence_solutions_as_vector(). + :meth:`QuadraticForm.count_congruence_solutions_as_vector`. INPUT: - `p` -- prime number > 0 + - ``p`` -- prime number > 0 - `k` -- an integer > 0 + - ``k`` -- an integer > 0 - `m` -- an integer (depending only on mod `p^k`) + - ``m`` -- an integer (depending only on mod `p^k`) - zvec, nzvec -- a list of integers up to dim(Q) + - ``zvec``, ``nzvec`` -- lists of integers up to dim(`Q`) EXAMPLES:: sage: Q = DiagonalQuadraticForm(ZZ, [1,2,3]) sage: Q.count_congruence_solutions__zero_type(3, 1, 0, None, None) 1 - """ return CountAllLocalTypesNaive(self, p, k, m, zvec, nzvec)[2] def count_congruence_solutions__bad_type(self, p, k, m, zvec, nzvec): """ - Counts the bad-type solutions of Q(`x`) `= m (mod p^k)` satisfying the + Count the bad-type solutions of `Q(x) = m` (mod `p^k`) satisfying the additional congruence conditions described in - QuadraticForm.count_congruence_solutions_as_vector(). + :meth:`QuadraticForm.count_congruence_solutions_as_vector`. INPUT: - `p` -- prime number > 0 + - ``p`` -- prime number > 0 - `k` -- an integer > 0 + - ``k`` -- an integer > 0 - `m` -- an integer (depending only on mod `p^k`) + - ``m`` -- an integer (depending only on mod `p^k`) - zvec, nzvec -- a list of integers up to dim(Q) + - ``zvec``, ``nzvec`` -- lists of integers up to dim(`Q`) EXAMPLES:: sage: Q = DiagonalQuadraticForm(ZZ, [1,2,3]) sage: Q.count_congruence_solutions__bad_type(3, 1, 0, None, None) 2 - """ return CountAllLocalTypesNaive(self, p, k, m, zvec, nzvec)[3] def count_congruence_solutions__bad_type_I(self, p, k, m, zvec, nzvec): """ - Counts the bad-typeI solutions of Q(`x`) = `m (mod p^k)` satisfying + Count the bad-typeI solutions of `Q(x) = m` (mod `p^k`) satisfying the additional congruence conditions described in - QuadraticForm.count_congruence_solutions_as_vector(). + :meth:`QuadraticForm.count_congruence_solutions_as_vector`. INPUT: - `p` -- prime number > 0 + - ``p`` -- prime number > 0 - `k` -- an integer > 0 + - ``k`` -- an integer > 0 - `m` -- an integer (depending only on mod `p^k`) + - ``m`` -- an integer (depending only on mod `p^k`) - zvec, nzvec -- a list of integers up to dim(Q) + - ``zvec``, ``nzvec`` -- lists of integers up to dim(`Q`) EXAMPLES:: sage: Q = DiagonalQuadraticForm(ZZ, [1,2,3]) sage: Q.count_congruence_solutions__bad_type_I(3, 1, 0, None, None) 0 - """ return CountAllLocalTypesNaive(self, p, k, m, zvec, nzvec)[4] def count_congruence_solutions__bad_type_II(self, p, k, m, zvec, nzvec): """ - Counts the bad-typeII solutions of Q(`x`) `= m (mod p^k)` satisfying + Count the bad-typeII solutions of `Q(x) = m` (mod `p^k`) satisfying the additional congruence conditions described in - QuadraticForm.count_congruence_solutions_as_vector(). + :meth:`QuadraticForm.count_congruence_solutions_as_vector`. INPUT: - `p` -- prime number > 0 + - ``p`` -- prime number > 0 - `k` -- an integer > 0 + - ``k`` -- an integer > 0 - `m` -- an integer (depending only on mod `p^k`) + - ``m`` -- an integer (depending only on mod `p^k`) - zvec, nzvec -- a list of integers up to dim(Q) + - ``zvec``, ``nzvec`` -- lists of integers up to dim(`Q`) EXAMPLES:: sage: Q = DiagonalQuadraticForm(ZZ, [1,2,3]) sage: Q.count_congruence_solutions__bad_type_II(3, 1, 0, None, None) 2 - """ return CountAllLocalTypesNaive(self, p, k, m, zvec, nzvec)[5] diff --git a/src/sage/quadratic_forms/quadratic_form__equivalence_testing.py b/src/sage/quadratic_forms/quadratic_form__equivalence_testing.py index cac17f3e952..6196dde8558 100644 --- a/src/sage/quadratic_forms/quadratic_form__equivalence_testing.py +++ b/src/sage/quadratic_forms/quadratic_form__equivalence_testing.py @@ -11,7 +11,6 @@ legendre_symbol, prime_divisors, valuation) -from sage.quadratic_forms.quadratic_form import is_QuadraticForm from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ @@ -22,9 +21,9 @@ ############################################################################## def is_globally_equivalent_to(self, other, return_matrix=False): - """ + r""" Determine if the current quadratic form is equivalent to the - given form over ZZ. + given form over `\ZZ`. If ``return_matrix`` is True, then we return the transformation matrix `M` so that ``self(M) == other``. @@ -94,8 +93,10 @@ def is_globally_equivalent_to(self, other, return_matrix=False): sage: P.is_globally_equivalent_to(Q) False """ + from sage.quadratic_forms.quadratic_form import QuadraticForm + # Check that other is a QuadraticForm - if not is_QuadraticForm(other): + if not isinstance(other, QuadraticForm): raise TypeError("you must compare two quadratic forms, but the argument is not a quadratic form") # only for definite forms @@ -113,21 +114,19 @@ def is_globally_equivalent_to(self, other, return_matrix=False): def is_locally_equivalent_to(self, other, check_primes_only=False, force_jordan_equivalence_test=False): - """ - Determine if the current quadratic form (defined over ZZ) is + r""" + Determine if the current quadratic form (defined over `\ZZ`) is locally equivalent to the given form over the real numbers and the - `p`-adic integers for every prime p. + `p`-adic integers for every prime `p`. This works by comparing the local Jordan decompositions at every prime, and the dimension and signature at the real place. INPUT: - a QuadraticForm + - ``other`` -- a :class:`QuadraticForm` - OUTPUT: - - boolean + OUTPUT: boolean EXAMPLES:: @@ -137,7 +136,6 @@ def is_locally_equivalent_to(self, other, check_primes_only=False, force_jordan_ False sage: Q1.is_locally_equivalent_to(Q2) True - """ # TO IMPLEMENT: if self.det() == 0: @@ -175,16 +173,14 @@ def is_locally_equivalent_to(self, other, check_primes_only=False, force_jordan_ def has_equivalent_Jordan_decomposition_at_prime(self, other, p): """ - Determines if the given quadratic form has a Jordan decomposition - equivalent to that of self. + Determine if the given quadratic form has a Jordan decomposition + equivalent to that of ``self``. INPUT: - a QuadraticForm - - OUTPUT: + - ``other`` -- a :class:`QuadraticForm` - boolean + OUTPUT: boolean EXAMPLES:: @@ -193,19 +189,18 @@ def has_equivalent_Jordan_decomposition_at_prime(self, other, p): sage: Q3 = QuadraticForm(ZZ, 3, [1, 0, 0, 1, 0, 11]) sage: [Q1.level(), Q2.level(), Q3.level()] [44, 44, 44] - sage: Q1.has_equivalent_Jordan_decomposition_at_prime(Q2,2) + sage: Q1.has_equivalent_Jordan_decomposition_at_prime(Q2, 2) # optional - sage.libs.pari False - sage: Q1.has_equivalent_Jordan_decomposition_at_prime(Q2,11) + sage: Q1.has_equivalent_Jordan_decomposition_at_prime(Q2, 11) # optional - sage.libs.pari False - sage: Q1.has_equivalent_Jordan_decomposition_at_prime(Q3,2) + sage: Q1.has_equivalent_Jordan_decomposition_at_prime(Q3, 2) # optional - sage.libs.pari False - sage: Q1.has_equivalent_Jordan_decomposition_at_prime(Q3,11) + sage: Q1.has_equivalent_Jordan_decomposition_at_prime(Q3, 11) # optional - sage.libs.pari True - sage: Q2.has_equivalent_Jordan_decomposition_at_prime(Q3,2) + sage: Q2.has_equivalent_Jordan_decomposition_at_prime(Q3, 2) # optional - sage.libs.pari True - sage: Q2.has_equivalent_Jordan_decomposition_at_prime(Q3,11) + sage: Q2.has_equivalent_Jordan_decomposition_at_prime(Q3, 11) # optional - sage.libs.pari False - """ # Sanity Checks # if not isinstance(other, QuadraticForm): @@ -323,126 +318,130 @@ def is_rationally_isometric(self, other, return_matrix=False): sage: V = DiagonalQuadraticForm(QQ, [1, 1, 2]) sage: W = DiagonalQuadraticForm(QQ, [2, 2, 2]) - sage: V.is_rationally_isometric(W) + sage: V.is_rationally_isometric(W) # optional - sage.libs.pari True :: - sage: K. = NumberField(x^2-3) - sage: V = QuadraticForm(K, 4, [1, 0, 0, 0, 2*a, 0, 0, a, 0, 2]); V - Quadratic form in 4 variables over Number Field in a with defining polynomial x^2 - 3 with coefficients: + sage: K. = NumberField(x^2 - 3) # optional - sage.rings.number_field + sage: V = QuadraticForm(K, 4, [1, 0, 0, 0, 2*a, 0, 0, a, 0, 2]); V # optional - sage.rings.number_field + Quadratic form in 4 variables over Number Field in a + with defining polynomial x^2 - 3 with coefficients: [ 1 0 0 0 ] [ * 2*a 0 0 ] [ * * a 0 ] [ * * * 2 ] - sage: W = QuadraticForm(K, 4, [1, 2*a, 4, 6, 3, 10, 2, 1, 2, 5]); W - Quadratic form in 4 variables over Number Field in a with defining polynomial x^2 - 3 with coefficients: + sage: W = QuadraticForm(K, 4, [1, 2*a, 4, 6, 3, 10, 2, 1, 2, 5]); W # optional - sage.rings.number_field + Quadratic form in 4 variables over Number Field in a + with defining polynomial x^2 - 3 with coefficients: [ 1 2*a 4 6 ] [ * 3 10 2 ] [ * * 1 2 ] [ * * * 5 ] - sage: V.is_rationally_isometric(W) + sage: V.is_rationally_isometric(W) # optional - sage.rings.number_field False :: - sage: K. = NumberField(x^4 + 2*x + 6) - sage: V = DiagonalQuadraticForm(K, [a, 2, 3, 2, 1]); V - Quadratic form in 5 variables over Number Field in a with defining polynomial x^4 + 2*x + 6 with coefficients: + sage: K. = NumberField(x^4 + 2*x + 6) # optional - sage.rings.number_field + sage: V = DiagonalQuadraticForm(K, [a, 2, 3, 2, 1]); V # optional - sage.rings.number_field + Quadratic form in 5 variables over Number Field in a + with defining polynomial x^4 + 2*x + 6 with coefficients: [ a 0 0 0 0 ] [ * 2 0 0 0 ] [ * * 3 0 0 ] [ * * * 2 0 ] [ * * * * 1 ] - sage: W = DiagonalQuadraticForm(K, [a, a, a, 2, 1]); W - Quadratic form in 5 variables over Number Field in a with defining polynomial x^4 + 2*x + 6 with coefficients: + sage: W = DiagonalQuadraticForm(K, [a, a, a, 2, 1]); W # optional - sage.rings.number_field + Quadratic form in 5 variables over Number Field in a + with defining polynomial x^4 + 2*x + 6 with coefficients: [ a 0 0 0 0 ] [ * a 0 0 0 ] [ * * a 0 0 ] [ * * * 2 0 ] [ * * * * 1 ] - sage: V.is_rationally_isometric(W) + sage: V.is_rationally_isometric(W) # optional - sage.rings.number_field False :: - sage: K. = NumberField(x^2 - 3) - sage: V = DiagonalQuadraticForm(K, [-1, a, -2*a]) - sage: W = DiagonalQuadraticForm(K, [-1, -a, 2*a]) - sage: V.is_rationally_isometric(W) + sage: K. = NumberField(x^2 - 3) # optional - sage.rings.number_field + sage: V = DiagonalQuadraticForm(K, [-1, a, -2*a]) # optional - sage.rings.number_field + sage: W = DiagonalQuadraticForm(K, [-1, -a, 2*a]) # optional - sage.rings.number_field + sage: V.is_rationally_isometric(W) # optional - sage.rings.number_field True - sage: V = DiagonalQuadraticForm(QQ, [1, 1, 2]) - sage: W = DiagonalQuadraticForm(QQ, [2, 2, 2]) - sage: T = V.is_rationally_isometric(W, True); T + sage: V = DiagonalQuadraticForm(QQ, [1, 1, 2]) # optional - sage.rings.number_field + sage: W = DiagonalQuadraticForm(QQ, [2, 2, 2]) # optional - sage.rings.number_field + sage: T = V.is_rationally_isometric(W, True); T # optional - sage.rings.number_field [ 0 0 1] [-1/2 -1/2 0] [ 1/2 -1/2 0] - sage: V.Gram_matrix() == T.transpose() * W.Gram_matrix() * T + sage: V.Gram_matrix() == T.transpose() * W.Gram_matrix() * T # optional - sage.rings.number_field True - sage: T = W.is_rationally_isometric(V, True); T + sage: T = W.is_rationally_isometric(V, True); T # optional - sage.rings.number_field [ 0 -1 1] [ 0 -1 -1] [ 1 0 0] - sage: W.Gram_matrix() == T.T * V.Gram_matrix() * T + sage: W.Gram_matrix() == T.T * V.Gram_matrix() * T # optional - sage.rings.number_field True :: sage: L = QuadraticForm(QQ, 3, [2, 2, 0, 2, 2, 5]) sage: M = QuadraticForm(QQ, 3, [2, 2, 0, 3, 2, 3]) - sage: L.is_rationally_isometric(M, True) + sage: L.is_rationally_isometric(M, True) # optional - sage.libs.pari False :: sage: A = DiagonalQuadraticForm(QQ, [1, 5]) sage: B = QuadraticForm(QQ, 2, [1, 12, 81]) - sage: T = A.is_rationally_isometric(B, True); T + sage: T = A.is_rationally_isometric(B, True); T # optional - sage.libs.pari [ 1 -2] [ 0 1/3] - sage: A.Gram_matrix() == T.T * B.Gram_matrix() * T + sage: A.Gram_matrix() == T.T * B.Gram_matrix() * T # optional - sage.libs.pari True :: sage: C = DiagonalQuadraticForm(QQ, [1, 5, 9]) sage: D = DiagonalQuadraticForm(QQ, [6, 30, 1]) - sage: T = C.is_rationally_isometric(D, True); T + sage: T = C.is_rationally_isometric(D, True); T # optional - sage.libs.pari [ 0 -5/6 1/2] [ 0 1/6 1/2] [ -1 0 0] - sage: C.Gram_matrix() == T.T * D.Gram_matrix() * T + sage: C.Gram_matrix() == T.T * D.Gram_matrix() * T # optional - sage.libs.pari True :: sage: E = DiagonalQuadraticForm(QQ, [1, 1]) sage: F = QuadraticForm(QQ, 2, [17, 94, 130]) - sage: T = F.is_rationally_isometric(E, True); T + sage: T = F.is_rationally_isometric(E, True); T # optional - sage.libs.pari [ -4 -189/17] [ -1 -43/17] - sage: F.Gram_matrix() == T.T * E.Gram_matrix() * T + sage: F.Gram_matrix() == T.T * E.Gram_matrix() * T # optional - sage.libs.pari True TESTS:: - sage: K. = QuadraticField(3) - sage: V = DiagonalQuadraticForm(K, [1, 2]) - sage: W = DiagonalQuadraticForm(K, [1, 0]) - sage: V.is_rationally_isometric(W) + sage: K. = QuadraticField(3) # optional - sage.rings.number_field + sage: V = DiagonalQuadraticForm(K, [1, 2]) # optional - sage.rings.number_field + sage: W = DiagonalQuadraticForm(K, [1, 0]) # optional - sage.rings.number_field + sage: V.is_rationally_isometric(W) # optional - sage.rings.number_field Traceback (most recent call last): ... NotImplementedError: This only tests regular forms Forms must have the same base ring otherwise a `TypeError` is raised:: - sage: K1. = QuadraticField(5) - sage: K2. = QuadraticField(7) - sage: V = DiagonalQuadraticForm(K1, [1, a]) - sage: W = DiagonalQuadraticForm(K2, [1, b]) - sage: V.is_rationally_isometric(W) + sage: K1. = QuadraticField(5) # optional - sage.rings.number_field + sage: K2. = QuadraticField(7) # optional - sage.rings.number_field + sage: V = DiagonalQuadraticForm(K1, [1, a]) # optional - sage.rings.number_field + sage: W = DiagonalQuadraticForm(K2, [1, b]) # optional - sage.rings.number_field + sage: V.is_rationally_isometric(W) # optional - sage.rings.number_field Traceback (most recent call last): ... TypeError: forms must have the same base ring. @@ -456,18 +455,18 @@ def is_rationally_isometric(self, other, return_matrix=False): Forms whose determinants do not differ by a square in the base field are not isometric:: - sage: K. = NumberField(x^2-3) - sage: V = DiagonalQuadraticForm(K, [-1, a, -2*a]) - sage: W = DiagonalQuadraticForm(K, [-1, a, 2*a]) - sage: V.is_rationally_isometric(W) + sage: K. = NumberField(x^2 - 3) # optional - sage.rings.number_field + sage: V = DiagonalQuadraticForm(K, [-1, a, -2*a]) # optional - sage.rings.number_field + sage: W = DiagonalQuadraticForm(K, [-1, a, 2*a]) # optional - sage.rings.number_field + sage: V.is_rationally_isometric(W) # optional - sage.rings.number_field False :: - sage: K. = NumberField(x^5 - x + 2, 'a') - sage: Q = QuadraticForm(K, 3, [a, 1, 0, -a**2, -a**3, -1]) - sage: m = Q.matrix() - sage: for _ in range(5): + sage: K. = NumberField(x^5 - x + 2, 'a') # optional - sage.rings.number_field + sage: Q = QuadraticForm(K, 3, [a, 1, 0, -a**2, -a**3, -1]) # optional - sage.rings.number_field + sage: m = Q.matrix() # optional - sage.rings.number_field + sage: for _ in range(5): # optional - sage.rings.number_field ....: t = random_matrix(ZZ, 3, algorithm='unimodular') ....: m2 = t*m*t.transpose() ....: Q2 = QuadraticForm(K, 3, [m2[i,j] / (2 if i==j else 1) @@ -565,18 +564,18 @@ def _diagonal_isometry(V, W): sage: Q = DiagonalQuadraticForm(QQ, [1, 2, 4]) sage: F = DiagonalQuadraticForm(QQ, [2, 2, 2]) - sage: T = _diagonal_isometry(Q, F); T + sage: T = _diagonal_isometry(Q, F); T # optional - sage.libs.pari [ 0 1 0] [-1/2 0 1] [ 1/2 0 1] - sage: Q.Gram_matrix() == T.T * F.Gram_matrix() * T + sage: Q.Gram_matrix() == T.T * F.Gram_matrix() * T # optional - sage.libs.pari True - sage: T = _diagonal_isometry(F, Q); T + sage: T = _diagonal_isometry(F, Q); T # optional - sage.libs.pari [ 0 -1 -1] [ 1 0 0] [ 0 -1/2 1/2] - sage: F.Gram_matrix() == T.T * Q.Gram_matrix() * T + sage: F.Gram_matrix() == T.T * Q.Gram_matrix() * T # optional - sage.libs.pari True """ import copy diff --git a/src/sage/quadratic_forms/quadratic_form__evaluate.pyx b/src/sage/quadratic_forms/quadratic_form__evaluate.pyx index 1505e7bd115..f4dc35176a2 100644 --- a/src/sage/quadratic_forms/quadratic_form__evaluate.pyx +++ b/src/sage/quadratic_forms/quadratic_form__evaluate.pyx @@ -2,29 +2,29 @@ def QFEvaluateVector(Q, v): - """ - Evaluate this quadratic form Q on a vector or matrix of elements + r""" + Evaluate this quadratic form `Q` on a vector or matrix of elements coercible to the base ring of the quadratic form. If a vector - is given then the output will be the ring element Q(v), but if a - matrix is given then the output will be the quadratic form Q' + is given, then the output will be the ring element `Q(v)`, but if a + matrix is given, then the output will be the quadratic form `Q'` which in matrix notation is given by: .. MATH:: - Q' = v^t * Q * v. + Q' = v^t\cdot Q\cdot v. - Note: This is a Python wrapper for the fast evaluation routine - QFEvaluateVector_cdef(). This routine is for internal use and is - called more conveniently as Q(M). + .. NOTE:: - INPUT: + This is a Python wrapper for the fast evaluation routine + :func:`QFEvaluateVector_cdef`. This routine is for internal use and is + called more conveniently as ``Q(M)``. - - Q -- QuadraticForm over a base ring R - - v -- a tuple or list (or column matrix) of Q.dim() elements of R + INPUT: - OUTPUT: + - ``Q`` -- :class:`QuadraticForm` over a base ring `R` + - ``v`` -- a tuple or list (or column matrix) of ``Q.dim()`` elements of `R` - an element of R + OUTPUT: an element of `R` EXAMPLES:: @@ -39,16 +39,15 @@ def QFEvaluateVector(Q, v): 0 sage: QFEvaluateVector(Q, (1,0,1,0)) 9 - """ return QFEvaluateVector_cdef(Q, v) cdef QFEvaluateVector_cdef(Q, v): - """ - Routine to quickly evaluate a quadratic form Q on a vector v. See - the Python wrapper function QFEvaluate() above for details. + r""" + Routine to quickly evaluate a quadratic form `Q` on a vector `v`. See + the Python wrapper function :meth:`QFEvaluate` above for details. """ # If we are passed a matrix A, return the quadratic form Q(A(x)) @@ -66,27 +65,29 @@ cdef QFEvaluateVector_cdef(Q, v): def QFEvaluateMatrix(Q, M, Q2): - """ - Evaluate this quadratic form Q on a matrix M of elements coercible + r""" + Evaluate this quadratic form `Q` on a matrix `M` of elements coercible to the base ring of the quadratic form, which in matrix notation is given by: - Q2 = M^t * Q * M. + .. MATH:: - Note: This is a Python wrapper for the fast evaluation routine - QFEvaluateMatrix_cdef(). This routine is for internal use and is - called more conveniently as Q(M). The inclusion of Q2 as an - argument is to avoid having to create a QuadraticForm here, which - for now creates circular imports. + Q_2 = M^t\cdot Q\cdot M. - INPUT: + .. NOTE:: + + This is a Python wrapper for the fast evaluation routine + :func:`QFEvaluateMatrix_cdef`. This routine is for internal use and is + called more conveniently as ``Q(M)``. The inclusion of ``Q2`` as an + argument is to avoid having to create a :func:`QuadraticForm` here, which + for now creates circular imports. - - Q -- QuadraticForm over a base ring R - - M -- a Q.dim() x Q2.dim() matrix of elements of R + INPUT: - OUTPUT: + - ``Q`` -- :class:`QuadraticForm` over a base ring `R` + - ``M`` -- a ``Q.dim()`` `\times` ``Q2.dim()`` matrix of elements of `R` - - Q2 -- a QuadraticForm over R + OUTPUT: a :class:`QuadraticForm` over `R` EXAMPLES:: @@ -107,15 +108,14 @@ def QFEvaluateMatrix(Q, M, Q2): Quadratic form in 2 variables over Integer Ring with coefficients: [ 0 2 ] [ * 7 ] - """ return QFEvaluateMatrix_cdef(Q, M, Q2) cdef QFEvaluateMatrix_cdef(Q, M, Q2): - """ - Routine to quickly evaluate a quadratic form Q on a matrix M. See - the Python wrapper function QFEvaluateMatrix() above for details. + r""" + Routine to quickly evaluate a quadratic form `Q` on a matrix `M`. See + the Python wrapper function :func:`QFEvaluateMatrix` above for details. """ # Create the new quadratic form diff --git a/src/sage/quadratic_forms/quadratic_form__genus.py b/src/sage/quadratic_forms/quadratic_form__genus.py index 30bd73145f9..9f6371b5cdb 100644 --- a/src/sage/quadratic_forms/quadratic_form__genus.py +++ b/src/sage/quadratic_forms/quadratic_form__genus.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.libs.pari """ Local and Global Genus Symbols """ @@ -55,48 +56,47 @@ def local_genus_symbol(self, p): Return the Conway-Sloane genus symbol of 2 times a quadratic form defined over `\ZZ` at a prime number `p`. - This is defined (in the - Genus_Symbol_p_adic_ring() class in the quadratic_forms/genera - subfolder) to be a list of tuples (one for each Jordan component - p^m*A at p, where A is a unimodular symmetric matrix with - coefficients the p-adic integers) of the following form: + This is defined (in the class + :class:`~sage.quadratic_forms.genera.genus.Genus_Symbol_p_adic_ring`) + to be a list of tuples (one for each Jordan component + `p^m\cdot A` at `p`, where `A` is a unimodular symmetric matrix with + coefficients the `p`-adic integers) of the following form: - 1. If p>2 then return triples of the form [`m`, `n`, `d`] where + - If `p>2`, then return triples of the form [`m`, `n`, `d`] where - `m` = valuation of the component + - `m` = valuation of the component - `n` = rank of A + - `n` = rank of `A` - `d` = det(A) in {1,u} for normalized quadratic non-residue u. + - `d` = det(`A`) in {1, `u`} for normalized quadratic non-residue `u`. - 2. If p=2 then return quintuples of the form [`m`,`n`,`s`, `d`, `o`] where + - If `p=2`, then return quintuples of the form [`m`, `n`, `s`, `d`, `o`] where - `m` = valuation of the component + - `m` = valuation of the component - `n` = rank of A + - `n` = rank of `A` - `d` = det(A) in {1,3,5,7} + - `d` = det(`A`) in {1, 3, 5, 7} - `s` = 0 (or 1) if A is even (or odd) + - `s` = 0 (or 1) if `A` is even (or odd) - `o` = oddity of A (= 0 if s = 0) in Z/8Z - = the trace of the diagonalization of A + - `o` = oddity of `A` (= 0 if `s` = 0) in `\ZZ/8\ZZ` = the trace of the diagonalization of `A` .. NOTE:: - The Conway-Sloane convention for describing the prime 'p = -1' + The Conway-Sloane convention for describing the prime `p = -1` is not supported here, and neither is the convention for including the 'prime' Infinity. See note on p370 of Conway-Sloane (3rd ed) [CS1999]_ for a discussion of this convention. INPUT: - - `p` -- a prime number > 0 + - ``p`` -- a prime number > 0 OUTPUT: a Conway-Sloane genus symbol at `p`, which is an - instance of the Genus_Symbol_p_adic_ring class. + instance of the class :class:`~sage.quadratic_forms.genera.genus.Genus_Symbol_p_adic_ring`. EXAMPLES:: diff --git a/src/sage/quadratic_forms/quadratic_form__local_density_congruence.py b/src/sage/quadratic_forms/quadratic_form__local_density_congruence.py index bf09113ae73..0ab0050d046 100644 --- a/src/sage/quadratic_forms/quadratic_form__local_density_congruence.py +++ b/src/sage/quadratic_forms/quadratic_form__local_density_congruence.py @@ -17,9 +17,9 @@ def count_modp_solutions__by_Gauss_sum(self, p, m): - """ - Return the number of solutions of `Q(x) = m (mod p)` of a - non-degenerate quadratic form over the finite field `Z/pZ`, + r""" + Return the number of solutions of `Q(x) = m` (mod `p`) of a + non-degenerate quadratic form over the finite field `\ZZ/p\ZZ`, where `p` is a prime number > 2. .. NOTE:: @@ -32,11 +32,11 @@ def count_modp_solutions__by_Gauss_sum(self, p, m): INPUT: - - `p` -- a prime number > 2 + - ``p`` -- a prime number > 2 - - `m` -- an integer + - ``m`` -- an integer - OUTPUT: an integer >= 0 + OUTPUT: an integer `\geq 0` EXAMPLES:: @@ -55,29 +55,29 @@ def count_modp_solutions__by_Gauss_sum(self, p, m): def local_good_density_congruence_odd(self, p, m, Zvec, NZvec): """ - Find the Good-type local density of Q representing `m` at `p`. - (Assuming that `p` > 2 and Q is given in local diagonal form.) + Find the Good-type local density of `Q` representing `m` at `p`. + (Assuming that `p > 2` and `Q` is given in local diagonal form.) - The additional congruence condition arguments Zvec and NZvec can - be either a list of indices or None. Zvec = [] is equivalent to - Zvec = None which both impose no additional conditions, but NZvec - = [] returns no solutions always while NZvec = None imposes no + The additional congruence condition arguments ``Zvec`` and ``NZvec`` can + be either a list of indices or None. ``Zvec=[]`` is equivalent to + ``Zvec=None``, which both impose no additional conditions, but + ``NZvec=[]`` returns no solutions always while ``NZvec=None`` imposes no additional condition. .. TODO:: - Add type checking for Zvec, NZvec, and that Q is in local + Add type checking for ``Zvec``, ``NZvec``, and that `Q` is in local normal form. INPUT: - - Q -- quadratic form assumed to be diagonal and p-integral + - ``self`` -- quadratic form `Q`, assumed to be diagonal and `p`-integral - - `p` -- a prime number + - ``p`` -- a prime number - - `m` -- an integer + - ``m`` -- an integer - - Zvec, NZvec -- non-repeating lists of integers in range(self.dim()) or None + - ``Zvec``, ``NZvec`` -- non-repeating lists of integers in ``range(self.dim())`` or ``None`` OUTPUT: a rational number @@ -92,7 +92,6 @@ def local_good_density_congruence_odd(self, p, m, Zvec, NZvec): sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1,1]) sage: Q.local_good_density_congruence_odd(3, 1, None, None) 8/9 - """ n = self.dim() @@ -141,38 +140,40 @@ def local_good_density_congruence_odd(self, p, m, Zvec, NZvec): def local_good_density_congruence_even(self, m, Zvec, NZvec): - """ - Find the Good-type local density of Q representing `m` at `p=2`. - (Assuming Q is given in local diagonal form.) - - The additional congruence condition arguments Zvec and NZvec can - be either a list of indices or None. Zvec = [] is equivalent to - Zvec = None which both impose no additional conditions, but NZvec - = [] returns no solutions always while NZvec = None imposes no + r""" + Find the Good-type local density of `Q` representing `m` at `p=2`. + (Assuming `Q` is given in local diagonal form.) + + The additional congruence condition arguments ``Zvec`` and ``NZvec`` can + be either a list of indices or None. ``Zvec=[]`` is equivalent to + ``Zvec=None`` which both impose no additional conditions, but + ``NZvec=[]`` returns no solutions always while ``NZvec=None`` imposes no additional condition. - WARNING: Here the indices passed in Zvec and NZvec represent - indices of the solution vector `x` of Q(`x`) = `m (mod p^k)`, and *not* - the Jordan components of Q. They therefore are required (and - assumed) to include either all or none of the indices of a given - Jordan component of Q. This is only important when `p=2` since - otherwise all Jordan blocks are 1x1, and so there the indices and - Jordan blocks coincide. + .. WARNING:: + + Here the indices passed in ``Zvec`` and ``NZvec`` represent + indices of the solution vector `x` of `Q(x) = m` (mod `p^k`), and *not* + the Jordan components of `Q`. They therefore are required (and + assumed) to include either all or none of the indices of a given + Jordan component of `Q`. This is only important when `p=2` since + otherwise all Jordan blocks are `1 \times 1`, and so there the indices and + Jordan blocks coincide. .. TODO:: - Add type checking for Zvec, NZvec, and that Q is in local + Add type checking for ``Zvec`` and ``NZvec``, and that `Q` is in local normal form. INPUT: - - Q -- quadratic form assumed to be block diagonal and 2-integral + - ``self`` -- quadratic form `Q`, assumed to be block diagonal and 2-integral - - `p` -- a prime number + - ``p`` -- a prime number - - `m` -- an integer + - ``m`` -- an integer - - Zvec, NZvec -- non-repeating lists of integers in range(self.dim()) or None + - ``Zvec``, ``NZvec`` -- non-repeating lists of integers in ``range(self.dim())`` or ``None`` OUTPUT: a rational number @@ -207,9 +208,9 @@ def local_good_density_congruence_even(self, m, Zvec, NZvec): [ * 10 5 6 ] [ * * 15 8 ] [ * * * 20 ] - sage: Q.theta_series(20) + sage: Q.theta_series(20) # optional - sage.libs.pari 1 + 2*q^5 + 2*q^10 + 2*q^14 + 2*q^15 + 2*q^16 + 2*q^18 + O(q^20) - sage: Q.local_normal_form(2) + sage: Q.local_normal_form(2) # optional - sage.libs.pari sage.rings.padics Quadratic form in 4 variables over Integer Ring with coefficients: [ 0 1 0 0 ] [ * 0 0 0 ] @@ -221,7 +222,6 @@ def local_good_density_congruence_even(self, m, Zvec, NZvec): 1 sage: Q.local_good_density_congruence_even(5, None, None) 3/4 - """ n = self.dim() @@ -323,23 +323,23 @@ def local_good_density_congruence_even(self, m, Zvec, NZvec): def local_good_density_congruence(self, p, m, Zvec=None, NZvec=None): """ - Find the Good-type local density of Q representing `m` at `p`. - (Front end routine for parity specific routines for p.) + Find the Good-type local density of `Q` representing `m` at `p`. + (Front end routine for parity specific routines for `p`.) .. TODO:: - Add Documentation about the additional congruence - conditions Zvec and NZvec. + Add documentation about the additional congruence + conditions ``Zvec`` and ``NZvec``. INPUT: - - Q -- quadratic form assumed to be block diagonal and p-integral + - ``self`` -- quadratic form `Q`, assumed to be block diagonal and `p`-integral - - `p` -- a prime number + - ``p`` -- a prime number - - `m` -- an integer + - ``m`` -- an integer - - Zvec, NZvec -- non-repeating lists of integers in range(self.dim()) or None + - ``Zvec``, ``NZvec`` -- non-repeating lists of integers in ``range(self.dim())`` or ``None`` OUTPUT: a rational number @@ -399,18 +399,18 @@ def local_good_density_congruence(self, p, m, Zvec=None, NZvec=None): def local_zero_density_congruence(self, p, m, Zvec=None, NZvec=None): """ - Find the Zero-type local density of Q representing `m` at `p`, - allowing certain congruence conditions mod p. + Find the Zero-type local density of `Q` representing `m` at `p`, + allowing certain congruence conditions mod `p`. INPUT: - - Q -- quadratic form assumed to be block diagonal and `p`-integral + - ``self`` -- quadratic form `Q`, assumed to be block diagonal and `p`-integral - - `p` -- a prime number + - ``p`` -- a prime number - - `m` -- an integer + - ``m`` -- an integer - - Zvec, NZvec -- non-repeating lists of integers in range(self.dim()) or None + - ``Zvec``, ``NZvec`` -- non-repeating lists of integers in ``range(self.dim())`` or ``None`` OUTPUT: a rational number @@ -437,7 +437,6 @@ def local_zero_density_congruence(self, p, m, Zvec=None, NZvec=None): 0 sage: Q.local_zero_density_congruence(3, 9, None, None) 8/81 - """ # DIAGNOSTIC verbose(" In local_zero_density_congruence with ") @@ -473,18 +472,18 @@ def local_zero_density_congruence(self, p, m, Zvec=None, NZvec=None): def local_badI_density_congruence(self, p, m, Zvec=None, NZvec=None): """ - Find the Bad-type I local density of Q representing `m` at `p`. - (Assuming that p > 2 and Q is given in local diagonal form.) + Find the Bad-type I local density of `Q` representing `m` at `p`. + (Assuming that `p > 2` and `Q` is given in local diagonal form.) INPUT: - - Q -- quadratic form assumed to be block diagonal and `p`-integral + - ``self`` -- quadratic form `Q`, assumed to be block diagonal and `p`-integral - - `p` -- a prime number + - ``p`` -- a prime number - - `m` -- an integer + - ``m`` -- an integer - - Zvec, NZvec -- non-repeating lists of integers in range(self.dim()) or None + - ``Zvec``, ``NZvec`` -- non-repeating lists of integers in ``range(self.dim())`` or ``None`` OUTPUT: a rational number @@ -533,8 +532,6 @@ def local_badI_density_congruence(self, p, m, Zvec=None, NZvec=None): 0 sage: Q.local_badI_density_congruence(3, 18, None, None) 0 - - """ # DIAGNOSTIC verbose(" In local_badI_density_congruence with ") @@ -638,18 +635,18 @@ def local_badI_density_congruence(self, p, m, Zvec=None, NZvec=None): def local_badII_density_congruence(self, p, m, Zvec=None, NZvec=None): """ - Find the Bad-type II local density of Q representing `m` at `p`. - (Assuming that `p` > 2 and Q is given in local diagonal form.) + Find the Bad-type II local density of `Q` representing `m` at `p`. + (Assuming that `p > 2` and `Q` is given in local diagonal form.) INPUT: - - Q -- quadratic form assumed to be block diagonal and p-integral + - ``self`` -- quadratic form `Q`, assumed to be block diagonal and `p`-integral - - `p` -- a prime number + - ``p`` -- a prime number - - `m` -- an integer + - ``m`` -- an integer - - Zvec, NZvec -- non-repeating lists of integers in range(self.dim()) or None + - ``Zvec``, ``NZvec`` -- non-repeating lists of integers in ``range(self.dim())`` or ``None`` OUTPUT: a rational number @@ -684,7 +681,6 @@ def local_badII_density_congruence(self, p, m, Zvec=None, NZvec=None): 4/27 sage: Q.local_badII_density_congruence(3, 18, None, None) 4/9 - """ # DIAGNOSTIC verbose(" In local_badII_density_congruence with ") @@ -785,18 +781,18 @@ def local_badII_density_congruence(self, p, m, Zvec=None, NZvec=None): def local_bad_density_congruence(self, p, m, Zvec=None, NZvec=None): """ - Find the Bad-type local density of Q representing + Find the Bad-type local density of `Q` representing `m` at `p`, allowing certain congruence conditions mod `p`. INPUT: - - Q -- quadratic form assumed to be block diagonal and p-integral + - ``self`` -- quadratic form `Q`, assumed to be block diagonal and `p`-integral - - `p` -- a prime number + - ``p`` -- a prime number - - `m` -- an integer + - ``m`` -- an integer - - Zvec, NZvec -- non-repeating lists of integers in range(self.dim()) or None + - ``Zvec``, ``NZvec`` -- non-repeating lists of integers in ``range(self.dim())`` or ``None`` OUTPUT: a rational number @@ -833,7 +829,6 @@ def local_bad_density_congruence(self, p, m, Zvec=None, NZvec=None): 4/9 sage: Q.local_bad_density_congruence(3, 27, None, None) 8/27 - """ return self.local_badI_density_congruence(p, m, Zvec, NZvec) + self.local_badII_density_congruence(p, m, Zvec, NZvec) @@ -844,18 +839,18 @@ def local_bad_density_congruence(self, p, m, Zvec=None, NZvec=None): def local_density_congruence(self, p, m, Zvec=None, NZvec=None): """ - Find the local density of Q representing `m` at `p`, + Find the local density of `Q` representing `m` at `p`, allowing certain congruence conditions mod `p`. INPUT: - - Q -- quadratic form assumed to be block diagonal and p-integral + - ``self`` -- quadratic form `Q`, assumed to be block diagonal and `p`-integral - - `p` -- a prime number + - ``p`` -- a prime number - - `m` -- an integer + - ``m`` -- an integer - - Zvec, NZvec -- non-repeating lists of integers in range(self.dim()) or None + - ``Zvec``, ``NZvec`` -- non-repeating lists of integers in ``range(self.dim())`` or ``None`` OUTPUT: a rational number @@ -912,7 +907,7 @@ def local_density_congruence(self, p, m, Zvec=None, NZvec=None): def local_primitive_density_congruence(self, p, m, Zvec=None, NZvec=None): """ - Find the primitive local density of Q representing + Find the primitive local density of `Q` representing `m` at `p`, allowing certain congruence conditions mod `p`. .. NOTE:: @@ -921,13 +916,13 @@ def local_primitive_density_congruence(self, p, m, Zvec=None, NZvec=None): INPUT: - - Q -- quadratic form assumed to be block diagonal and p-integral + - ``self`` -- quadratic form `Q`, assumed to be block diagonal and `p`-integral - - `p` -- a prime number + - ``p`` -- a prime number - - `m` -- an integer + - ``m`` -- an integer - - Zvec, NZvec -- non-repeating lists of integers in range(self.dim()) or None + - ``Zvec``, ``NZvec`` -- non-repeating lists of integers in ``range(self.dim())`` or ``None`` OUTPUT: a rational number diff --git a/src/sage/quadratic_forms/quadratic_form__local_density_interfaces.py b/src/sage/quadratic_forms/quadratic_form__local_density_interfaces.py index 91a73f14283..4bfe7ebe6a7 100644 --- a/src/sage/quadratic_forms/quadratic_form__local_density_interfaces.py +++ b/src/sage/quadratic_forms/quadratic_form__local_density_interfaces.py @@ -20,12 +20,10 @@ def local_density(self, p, m): INPUT: - - `p` -- a prime number > 0 - - `m` -- an integer + - ``p`` -- a prime number > 0 + - ``m`` -- an integer - OUTPUT: - - a rational number + OUTPUT: a rational number EXAMPLES:: @@ -68,7 +66,7 @@ def local_density(self, p, m): def local_primitive_density(self, p, m): """ - Gives the local primitive density -- should be called by the user. =) + Return the local primitive density -- should be called by the user. =) NOTE: This screens for imprimitive forms, and puts the quadratic form in local normal form, which is a *requirement* of @@ -76,12 +74,10 @@ def local_primitive_density(self, p, m): INPUT: - `p` -- a prime number > 0 - `m` -- an integer - - OUTPUT: + - ``p`` -- a prime number > 0 + - ``m`` -- an integer - a rational number + OUTPUT: a rational number EXAMPLES:: @@ -96,7 +92,7 @@ def local_primitive_density(self, p, m): [ * 10 5 6 ] [ * * 15 8 ] [ * * * 20 ] - sage: Q.theta_series(20) + sage: Q.theta_series(20) # optional - sage.libs.pari 1 + 2*q^5 + 2*q^10 + 2*q^14 + 2*q^15 + 2*q^16 + 2*q^18 + O(q^20) sage: Q.local_normal_form(2) Quadratic form in 4 variables over Integer Ring with coefficients: @@ -114,7 +110,6 @@ def local_primitive_density(self, p, m): 3/4 sage: Q.local_density(2, 5) 3/4 - """ n = self.dim() if n == 0: diff --git a/src/sage/quadratic_forms/quadratic_form__local_field_invariants.py b/src/sage/quadratic_forms/quadratic_form__local_field_invariants.py index 7920578508c..bec86a5afef 100644 --- a/src/sage/quadratic_forms/quadratic_form__local_field_invariants.py +++ b/src/sage/quadratic_forms/quadratic_form__local_field_invariants.py @@ -24,12 +24,10 @@ from copy import deepcopy from sage.arith.misc import hilbert_symbol, prime_divisors -from sage.functions.all import sgn from sage.matrix.matrix_space import MatrixSpace from sage.misc.cachefunc import cached_method from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ -from sage.rings.real_mpfr import RR def rational_diagonal_form(self, return_matrix=False): @@ -42,15 +40,15 @@ def rational_diagonal_form(self, return_matrix=False): - ``return_matrix`` -- (boolean, default: False) also return the transformation matrix - OUTPUT: either ``D`` (if ``return_matrix`` is false) or ``(D,T)`` - (if ``return_matrix`` is true) where + OUTPUT: either the diagonal quadratic form `D` (if ``return_matrix`` is false) + or the pair `(D, T)` (if ``return_matrix`` is true) where - - ``D`` -- the diagonalized form of this quadratic form. + - `D` -- the diagonalized form of this quadratic form - - ``T`` -- transformation matrix. This is such that + - `T` -- transformation matrix. This is such that ``T.transpose() * self.matrix() * T`` gives ``D.matrix()``. - Both ``D`` and ``T`` are defined over the fraction field of the + Both `D` and `T` are defined over the fraction field of the base ring of the given form. EXAMPLES:: @@ -142,7 +140,8 @@ def rational_diagonal_form(self, return_matrix=False): ... TypeError sage: Q.rational_diagonal_form() - Quadratic form in 4 variables over Real Interval Field with 53 bits of precision with coefficients: + Quadratic form in 4 variables over Real Interval Field with 53 bits of precision + with coefficients: [ 5 0.?e-14 0.?e-13 0.?e-13 ] [ * -0.05000000000000? 0.?e-12 0.?e-12 ] [ * * 13.00000000000? 0.?e-10 ] @@ -188,14 +187,14 @@ def _rational_diagonal_form_and_transformation(self): the corresponding transformation matrix. This is over the fraction field of the base ring of the given quadratic form. - OUTPUT: a tuple ``(D,T)`` where + OUTPUT: a tuple `(D,T)` where - - ``D`` -- the diagonalized form of this quadratic form. + - `D` -- the diagonalized form of this quadratic form - - ``T`` -- transformation matrix. This is such that + - `T` -- transformation matrix. This is such that ``T.transpose() * self.matrix() * T`` gives ``D.matrix()``. - Both ``D`` and ``T`` are defined over the fraction field of the + Both `D` and `T` are defined over the fraction field of the base ring of the given form. EXAMPLES:: @@ -286,22 +285,16 @@ def _rational_diagonal_form_and_transformation(self): def signature_vector(self): - """ - Returns the triple `(p, n, z)` of integers where + r""" + Return the triple `(p, n, z)` of integers where - `p` = number of positive eigenvalues - `n` = number of negative eigenvalues - `z` = number of zero eigenvalues - for the symmetric matrix associated to Q. - - INPUT: - - (none) + for the symmetric matrix associated to `Q`. - OUTPUT: - - a triple of integers >= 0 + OUTPUT: a triple of integers `\geq 0` EXAMPLES:: @@ -344,19 +337,13 @@ def signature_vector(self): def signature(self): """ - Returns the signature of the quadratic form, defined as: + Return the signature of the quadratic form, defined as: - number of positive eigenvalues - number of negative eigenvalues + number of positive eigenvalues `-` number of negative eigenvalues of the matrix of the quadratic form. - INPUT: - - None - - OUTPUT: - - an integer + OUTPUT: an integer EXAMPLES:: @@ -388,8 +375,8 @@ def signature(self): def hasse_invariant(self, p): r""" - Computes the Hasse invariant at a prime `p` or at infinity, as given on p55 of - Cassels's book. If Q is diagonal with coefficients `a_i`, then the + Compute the Hasse invariant at a prime `p` or at infinity, as given on p55 of + Cassels's book. If `Q` is diagonal with coefficients `a_i`, then the (Cassels) Hasse invariant is given by .. MATH:: @@ -397,27 +384,25 @@ def hasse_invariant(self, p): c_p = \prod_{i < j} (a_i, a_j)_p where `(a,b)_p` is the Hilbert symbol at `p`. The underlying - quadratic form must be non-degenerate over `Q_p` for this to make + quadratic form must be non-degenerate over `\QQ_p` for this to make sense. .. WARNING:: This is different from the O'Meara Hasse invariant, which - allows `i <= j` in the product. That is given by the method - hasse_invariant__OMeara(p). + allows `i \leq j` in the product. That is given by the method + :meth:`hasse_invariant__OMeara`. .. NOTE:: - We should really rename this hasse_invariant__Cassels(), and - set hasse_invariant() as a front-end to it. + We should really rename this ``hasse_invariant__Cassels``, and + set :meth:`hasse_invariant` as a front-end to it. INPUT: - - `p` -- a prime number > 0 or `-1` for the infinite place + - ``p`` -- a prime number > 0 or `-1` for the infinite place - OUTPUT: - - 1 or -1 + OUTPUT: `1` or `-1` EXAMPLES:: @@ -426,32 +411,32 @@ def hasse_invariant(self, p): Quadratic form in 2 variables over Rational Field with coefficients: [ 1 0 ] [ * 2 ] - sage: [Q.hasse_invariant(p) for p in prime_range(20)] + sage: [Q.hasse_invariant(p) for p in prime_range(20)] # optional - sage.libs.pari [1, 1, 1, 1, 1, 1, 1, 1] - sage: [Q.hasse_invariant__OMeara(p) for p in prime_range(20)] + sage: [Q.hasse_invariant__OMeara(p) for p in prime_range(20)] # optional - sage.libs.pari [1, 1, 1, 1, 1, 1, 1, 1] :: sage: Q = DiagonalQuadraticForm(ZZ, [1,-1]) - sage: [Q.hasse_invariant(p) for p in prime_range(20)] + sage: [Q.hasse_invariant(p) for p in prime_range(20)] # optional - sage.libs.pari [1, 1, 1, 1, 1, 1, 1, 1] - sage: [Q.hasse_invariant__OMeara(p) for p in prime_range(20)] + sage: [Q.hasse_invariant__OMeara(p) for p in prime_range(20)] # optional - sage.libs.pari [-1, 1, 1, 1, 1, 1, 1, 1] :: sage: Q = DiagonalQuadraticForm(ZZ, [1,-1,5]) - sage: [Q.hasse_invariant(p) for p in prime_range(20)] + sage: [Q.hasse_invariant(p) for p in prime_range(20)] # optional - sage.libs.pari [1, 1, 1, 1, 1, 1, 1, 1] - sage: [Q.hasse_invariant__OMeara(p) for p in prime_range(20)] + sage: [Q.hasse_invariant__OMeara(p) for p in prime_range(20)] # optional - sage.libs.pari [-1, 1, 1, 1, 1, 1, 1, 1] :: - sage: K.=NumberField(x^2-23) - sage: Q=DiagonalQuadraticForm(K,[-a,a+2]) - sage: [Q.hasse_invariant(p) for p in K.primes_above(19)] + sage: K. = NumberField(x^2 - 23) # optional - sage.rings.number_field + sage: Q = DiagonalQuadraticForm(K, [-a, a + 2]) # optional - sage.rings.number_field + sage: [Q.hasse_invariant(p) for p in K.primes_above(19)] # optional - sage.rings.number_field [-1, 1] """ # TO DO: Need to deal with the case n=1 separately somewhere! @@ -480,12 +465,12 @@ def hasse_invariant__OMeara(self, p): Compute the O'Meara Hasse invariant at a prime `p`. This is defined on - p167 of O'Meara's book. If Q is diagonal with coefficients `a_i`, + p167 of O'Meara's book. If `Q` is diagonal with coefficients `a_i`, then the (Cassels) Hasse invariant is given by .. MATH:: - c_p = \prod_{i <= j} (a_i, a_j)_p + c_p = \prod_{i \leq j} (a_i, a_j)_p where `(a,b)_p` is the Hilbert symbol at `p`. @@ -497,11 +482,9 @@ def hasse_invariant__OMeara(self, p): INPUT: - - `p` -- a prime number > 0 or `-1` for the infinite place - - OUTPUT: + - ``p`` -- a prime number > 0 or `-1` for the infinite place - 1 or -1 + OUTPUT: `1` or `-1` EXAMPLES:: @@ -510,32 +493,32 @@ def hasse_invariant__OMeara(self, p): Quadratic form in 2 variables over Rational Field with coefficients: [ 1 0 ] [ * 2 ] - sage: [Q.hasse_invariant(p) for p in prime_range(20)] + sage: [Q.hasse_invariant(p) for p in prime_range(20)] # optional - sage.libs.pari [1, 1, 1, 1, 1, 1, 1, 1] - sage: [Q.hasse_invariant__OMeara(p) for p in prime_range(20)] + sage: [Q.hasse_invariant__OMeara(p) for p in prime_range(20)] # optional - sage.libs.pari [1, 1, 1, 1, 1, 1, 1, 1] :: sage: Q = DiagonalQuadraticForm(ZZ, [1,-1]) - sage: [Q.hasse_invariant(p) for p in prime_range(20)] + sage: [Q.hasse_invariant(p) for p in prime_range(20)] # optional - sage.libs.pari [1, 1, 1, 1, 1, 1, 1, 1] - sage: [Q.hasse_invariant__OMeara(p) for p in prime_range(20)] + sage: [Q.hasse_invariant__OMeara(p) for p in prime_range(20)] # optional - sage.libs.pari [-1, 1, 1, 1, 1, 1, 1, 1] :: sage: Q = DiagonalQuadraticForm(ZZ,[1,-1,-1]) - sage: [Q.hasse_invariant(p) for p in prime_range(20)] + sage: [Q.hasse_invariant(p) for p in prime_range(20)] # optional - sage.libs.pari [-1, 1, 1, 1, 1, 1, 1, 1] - sage: [Q.hasse_invariant__OMeara(p) for p in prime_range(20)] + sage: [Q.hasse_invariant__OMeara(p) for p in prime_range(20)] # optional - sage.libs.pari [-1, 1, 1, 1, 1, 1, 1, 1] :: - sage: K.=NumberField(x^2-23) - sage: Q = DiagonalQuadraticForm(K,[-a,a+2]) - sage: [Q.hasse_invariant__OMeara(p) for p in K.primes_above(19)] + sage: K. = NumberField(x^2 - 23) # optional - sage.rings.number_field + sage: Q = DiagonalQuadraticForm(K, [-a, a + 2]) # optional - sage.rings.number_field + sage: [Q.hasse_invariant__OMeara(p) for p in K.primes_above(19)] # optional - sage.rings.number_field [1, 1] """ # TO DO: Need to deal with the case n=1 separately somewhere! @@ -565,33 +548,31 @@ def is_hyperbolic(self, p): REFERENCES: - This criteria follows from Cassels's "Rational Quadratic Forms": + This criterion follows from Cassels's "Rational Quadratic Forms": - local invariants for hyperbolic plane (Lemma 2.4, p58) - direct sum formulas (Lemma 2.3, p58) INPUT: - - `p` -- a prime number > 0 or `-1` for the infinite place - - OUTPUT: + - ``p`` -- a prime number > 0 or `-1` for the infinite place - boolean + OUTPUT: boolean EXAMPLES:: sage: Q = DiagonalQuadraticForm(ZZ, [1,1]) - sage: Q.is_hyperbolic(-1) + sage: Q.is_hyperbolic(-1) # optional - sage.libs.pari False - sage: Q.is_hyperbolic(2) + sage: Q.is_hyperbolic(2) # optional - sage.libs.pari False - sage: Q.is_hyperbolic(3) + sage: Q.is_hyperbolic(3) # optional - sage.libs.pari False - sage: Q.is_hyperbolic(5) # Here -1 is a square, so it's true. + sage: Q.is_hyperbolic(5) # Here -1 is a square, so it's true. # optional - sage.libs.pari True - sage: Q.is_hyperbolic(7) + sage: Q.is_hyperbolic(7) # optional - sage.libs.pari False - sage: Q.is_hyperbolic(13) # Here -1 is a square, so it's true. + sage: Q.is_hyperbolic(13) # Here -1 is a square, so it's true. # optional - sage.libs.pari True """ # False for odd-dim'l forms @@ -620,44 +601,46 @@ def is_hyperbolic(self, p): def is_anisotropic(self, p): r""" - Check if the quadratic form is anisotropic over the p-adic numbers `\QQ_p` or `\RR`. + Check if the quadratic form is anisotropic over the `p`-adic numbers `\QQ_p` or `\RR`. INPUT: - - `p` -- a prime number > 0 or `-1` for the infinite place + - ``p`` -- a prime number > 0 or `-1` for the infinite place - OUTPUT: - - boolean + OUTPUT: boolean EXAMPLES:: sage: Q = DiagonalQuadraticForm(ZZ, [1,1]) - sage: Q.is_anisotropic(2) + sage: Q.is_anisotropic(2) # optional - sage.libs.pari True - sage: Q.is_anisotropic(3) + sage: Q.is_anisotropic(3) # optional - sage.libs.pari True - sage: Q.is_anisotropic(5) + sage: Q.is_anisotropic(5) # optional - sage.libs.pari False :: sage: Q = DiagonalQuadraticForm(ZZ, [1,-1]) - sage: Q.is_anisotropic(2) + sage: Q.is_anisotropic(2) # optional - sage.libs.pari False - sage: Q.is_anisotropic(3) + sage: Q.is_anisotropic(3) # optional - sage.libs.pari False - sage: Q.is_anisotropic(5) + sage: Q.is_anisotropic(5) # optional - sage.libs.pari False :: - sage: [DiagonalQuadraticForm(ZZ, [1, -least_quadratic_nonresidue(p)]).is_anisotropic(p) for p in prime_range(3, 30)] + sage: [DiagonalQuadraticForm(ZZ, # optional - sage.libs.pari + ....: [1, -least_quadratic_nonresidue(p)]).is_anisotropic(p) + ....: for p in prime_range(3, 30)] [True, True, True, True, True, True, True, True, True] :: - sage: [DiagonalQuadraticForm(ZZ, [1, -least_quadratic_nonresidue(p), p, -p*least_quadratic_nonresidue(p)]).is_anisotropic(p) for p in prime_range(3, 30)] + sage: [DiagonalQuadraticForm(ZZ, [1, -least_quadratic_nonresidue(p), # optional - sage.libs.pari + ....: p, -p*least_quadratic_nonresidue(p)]).is_anisotropic(p) + ....: for p in prime_range(3, 30)] [True, True, True, True, True, True, True, True, True] """ # TO DO: Should check that p is prime @@ -687,45 +670,47 @@ def is_anisotropic(self, p): def is_isotropic(self, p): - """ - Checks if Q is isotropic over the p-adic numbers `Q_p` or `RR`. + r""" + Checks if `Q` is isotropic over the `p`-adic numbers `\QQ_p` or `\RR`. INPUT: - - `p` -- a prime number > 0 or `-1` for the infinite place - - OUTPUT: + - ``p`` -- a prime number > 0 or `-1` for the infinite place - boolean + OUTPUT: boolean EXAMPLES:: sage: Q = DiagonalQuadraticForm(ZZ, [1,1]) - sage: Q.is_isotropic(2) + sage: Q.is_isotropic(2) # optional - sage.libs.pari False - sage: Q.is_isotropic(3) + sage: Q.is_isotropic(3) # optional - sage.libs.pari False - sage: Q.is_isotropic(5) + sage: Q.is_isotropic(5) # optional - sage.libs.pari True :: sage: Q = DiagonalQuadraticForm(ZZ, [1,-1]) - sage: Q.is_isotropic(2) + sage: Q.is_isotropic(2) # optional - sage.libs.pari True - sage: Q.is_isotropic(3) + sage: Q.is_isotropic(3) # optional - sage.libs.pari True - sage: Q.is_isotropic(5) + sage: Q.is_isotropic(5) # optional - sage.libs.pari True :: - sage: [DiagonalQuadraticForm(ZZ, [1, -least_quadratic_nonresidue(p)]).is_isotropic(p) for p in prime_range(3, 30)] + sage: [DiagonalQuadraticForm(ZZ, # optional - sage.libs.pari + ....: [1, -least_quadratic_nonresidue(p)]).is_isotropic(p) + ....: for p in prime_range(3, 30)] [False, False, False, False, False, False, False, False, False] :: - sage: [DiagonalQuadraticForm(ZZ, [1, -least_quadratic_nonresidue(p), p, -p*least_quadratic_nonresidue(p)]).is_isotropic(p) for p in prime_range(3, 30)] + sage: [DiagonalQuadraticForm(ZZ, [1, -least_quadratic_nonresidue(p), # optional - sage.libs.pari + ....: p, -p*least_quadratic_nonresidue(p)]).is_isotropic(p) + ....: for p in prime_range(3, 30)] [False, False, False, False, False, False, False, False, False] """ @@ -741,15 +726,15 @@ def anisotropic_primes(self): EXAMPLES:: sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1]) - sage: Q.anisotropic_primes() + sage: Q.anisotropic_primes() # optional - sage.libs.pari [2, -1] sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1,1]) - sage: Q.anisotropic_primes() + sage: Q.anisotropic_primes() # optional - sage.libs.pari [2, -1] sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1,1,1]) - sage: Q.anisotropic_primes() + sage: Q.anisotropic_primes() # optional - sage.libs.pari [-1] """ # Look at all prime divisors of 2 * Det(Q) to find the @@ -760,25 +745,23 @@ def anisotropic_primes(self): def compute_definiteness(self): """ - Computes whether the given quadratic form is positive-definite, + Compute whether the given quadratic form is positive-definite, negative-definite, indefinite, degenerate, or the zero form. - This caches one of the following strings in self.__definiteness_string: + This caches one of the following strings in ``self.__definiteness_string``: "pos_def", "neg_def", "indef", "zero", "degenerate". It is called - from all routines like: - - is_positive_definite(), is_negative_definite(), is_indefinite(), etc. + from all routines like: :meth:`is_positive_definite`, :meth:`is_negative_definite`, + :meth:`is_indefinite`, etc. - Note: A degenerate form is considered neither definite nor indefinite. - Note: The zero-dim'l form is considered both positive definite and negative definite. + .. NOTE:: - INPUT: + A degenerate form is considered neither definite nor indefinite. - QuadraticForm + .. NOTE: - OUTPUT: + The zero-dimensional form is considered both positive definite and negative definite. - boolean + OUTPUT: boolean EXAMPLES:: @@ -821,6 +804,8 @@ def compute_definiteness(self): """ # Sanity Check + from sage.rings.real_mpfr import RR + if not ((self.base_ring() == ZZ) or (self.base_ring() == QQ) or (self.base_ring() == RR)): raise NotImplementedError("we can only check definiteness over ZZ, QQ, and RR for now") @@ -853,15 +838,9 @@ def compute_definiteness_string_by_determinants(self): """ Compute the (positive) definiteness of a quadratic form by looking at the signs of all of its upper-left subdeterminants. See also - self.compute_definiteness() for more documentation. - - INPUT: - - None - - OUTPUT: + :meth:`compute_definiteness` for more documentation. - string describing the definiteness + OUTPUT: string describing the definiteness EXAMPLES:: @@ -894,9 +873,13 @@ def compute_definiteness_string_by_determinants(self): 'neg_def' """ # Sanity Check + from sage.rings.real_mpfr import RR + if not ((self.base_ring() == ZZ) or (self.base_ring() == QQ) or (self.base_ring() == RR)): raise NotImplementedError("we can only check definiteness over ZZ, QQ, and RR for now") + from sage.functions.all import sgn + # Some useful variables n = self.dim() M = self.matrix() @@ -931,16 +914,15 @@ def is_positive_definite(self): """ Determines if the given quadratic form is positive-definite. - Note: A degenerate form is considered neither definite nor indefinite. - Note: The zero-dim'l form is considered both positive definite and negative definite. + .. NOTE:: - INPUT: + A degenerate form is considered neither definite nor indefinite. - None + .. NOTE:: - OUTPUT: + The zero-dimensional form is considered both positive definite and negative definite. - boolean -- True or False + OUTPUT: boolean -- True or False EXAMPLES:: @@ -969,16 +951,15 @@ def is_negative_definite(self): """ Determines if the given quadratic form is negative-definite. - Note: A degenerate form is considered neither definite nor indefinite. - Note: The zero-dim'l form is considered both positive definite and negative definite. + .. NOTE:: - INPUT: + A degenerate form is considered neither definite nor indefinite. - None + .. NOTE:: - OUTPUT: + The zero-dimensional form is considered both positive definite and negative definite. - boolean -- True or False + OUTPUT: boolean -- True or False EXAMPLES:: @@ -1007,16 +988,15 @@ def is_indefinite(self): """ Determines if the given quadratic form is indefinite. - Note: A degenerate form is considered neither definite nor indefinite. - Note: The zero-dim'l form is not considered indefinite. + .. NOTE:: - INPUT: + A degenerate form is considered neither definite nor indefinite. - None + .. NOTE:: - OUTPUT: + The zero-dimensional form is not considered indefinite. - boolean -- True or False + OUTPUT: boolean -- True or False EXAMPLES:: @@ -1046,16 +1026,15 @@ def is_definite(self): """ Determines if the given quadratic form is (positive or negative) definite. - Note: A degenerate form is considered neither definite nor indefinite. - Note: The zero-dim'l form is considered indefinite. + .. NOTE:: - INPUT: + A degenerate form is considered neither definite nor indefinite. - None + .. NOTE:: - OUTPUT: + The zero-dimensional form is considered indefinite. - boolean -- True or False + OUTPUT: boolean -- True or False EXAMPLES:: diff --git a/src/sage/quadratic_forms/quadratic_form__local_normal_form.py b/src/sage/quadratic_forms/quadratic_form__local_normal_form.py index 775313004ba..cf7216e7a24 100644 --- a/src/sage/quadratic_forms/quadratic_form__local_normal_form.py +++ b/src/sage/quadratic_forms/quadratic_form__local_normal_form.py @@ -27,29 +27,29 @@ def find_entry_with_minimal_scale_at_prime(self, p): - """ + r""" Finds the entry of the quadratic form with minimal scale at the - prime p, preferring diagonal entries in case of a tie. (I.e. If - we write the quadratic form as a symmetric matrix M, then this - entry M[i,j] has the minimal valuation at the prime p.) + prime `p`, preferring diagonal entries in case of a tie. (I.e. If + we write the quadratic form as a symmetric matrix `M`, then this + entry ``M[i,j]`` has the minimal valuation at the prime `p`.) + + .. NOTE:: - Note: This answer is independent of the kind of matrix (Gram or - Hessian) associated to the form. + This answer is independent of the kind of matrix (Gram or + Hessian) associated to the form. INPUT: - `p` -- a prime number > 0 - - OUTPUT: + - ``p`` -- a prime number > 0 - a pair of integers >= 0 + OUTPUT: a pair of integers `\geq 0` EXAMPLES:: sage: Q = QuadraticForm(ZZ, 2, [6, 2, 20]); Q Quadratic form in 2 variables over Integer Ring with coefficients: - [ 6 2 ] - [ * 20 ] + [ 6 2 ] + [ * 20 ] sage: Q.find_entry_with_minimal_scale_at_prime(2) (0, 1) sage: Q.find_entry_with_minimal_scale_at_prime(3) @@ -85,18 +85,16 @@ def local_normal_form(self, p): Return a locally integrally equivalent quadratic form over the `p`-adic integers `\ZZ_p` which gives the Jordan decomposition. - The Jordan components are written as sums of blocks of size <= 2 + The Jordan components are written as sums of blocks of size `\leq 2` and are arranged by increasing scale, and then by increasing norm. - This is equivalent to saying that we put the 1x1 blocks before - the 2x2 blocks in each Jordan component. + This is equivalent to saying that we put the `1 \times 1` blocks before + the `2 \times 2` blocks in each Jordan component. INPUT: - - `p` -- a positive prime number. + - ``p`` -- a positive prime number - OUTPUT: - - a quadratic form over `\ZZ` + OUTPUT: a quadratic form over `\ZZ` .. WARNING:: @@ -107,20 +105,20 @@ def local_normal_form(self, p): sage: Q = QuadraticForm(ZZ, 2, [10,4,1]) sage: Q.local_normal_form(5) Quadratic form in 2 variables over Integer Ring with coefficients: - [ 1 0 ] - [ * 6 ] + [ 1 0 ] + [ * 6 ] :: sage: Q.local_normal_form(3) Quadratic form in 2 variables over Integer Ring with coefficients: - [ 10 0 ] - [ * 15 ] + [ 10 0 ] + [ * 15 ] sage: Q.local_normal_form(2) Quadratic form in 2 variables over Integer Ring with coefficients: - [ 1 0 ] - [ * 6 ] + [ 1 0 ] + [ * 6 ] """ # Sanity Checks if (self.base_ring() != IntegerRing()): @@ -239,7 +237,7 @@ def jordan_blocks_by_scale_and_unimodular(self, p, safe_flag=True): `p^{s_i}`-unimodular Jordan component which is further decomposed into block diagonals of block size `\le 2`. - For each `L_i` the 2x2 blocks are listed after the 1x1 blocks + For each `L_i` the `2 \times 2` blocks are listed after the `1 \times 1` blocks (which follows from the convention of the :meth:`local_normal_form` method). @@ -255,7 +253,7 @@ def jordan_blocks_by_scale_and_unimodular(self, p, safe_flag=True): INPUT: - - `p` -- a prime number > 0. + - ``p`` -- a prime number > 0 OUTPUT: @@ -274,25 +272,27 @@ def jordan_blocks_by_scale_and_unimodular(self, p, safe_flag=True): sage: Q = DiagonalQuadraticForm(ZZ, [1,9,5,7]) sage: Q.jordan_blocks_by_scale_and_unimodular(3) [(0, Quadratic form in 3 variables over Integer Ring with coefficients: - [ 1 0 0 ] - [ * 5 0 ] - [ * * 7 ]), (2, Quadratic form in 1 variables over Integer Ring with coefficients: - [ 1 ])] + [ 1 0 0 ] + [ * 5 0 ] + [ * * 7 ]), + (2, Quadratic form in 1 variables over Integer Ring with coefficients: + [ 1 ])] :: sage: Q2 = QuadraticForm(ZZ, 2, [1,1,1]) sage: Q2.jordan_blocks_by_scale_and_unimodular(2) [(-1, Quadratic form in 2 variables over Integer Ring with coefficients: - [ 2 2 ] - [ * 2 ])] + [ 2 2 ] + [ * 2 ])] sage: Q = Q2 + Q2.scale_by_factor(2) sage: Q.jordan_blocks_by_scale_and_unimodular(2) [(-1, Quadratic form in 2 variables over Integer Ring with coefficients: - [ 2 2 ] - [ * 2 ]), (0, Quadratic form in 2 variables over Integer Ring with coefficients: - [ 2 2 ] - [ * 2 ])] + [ 2 2 ] + [ * 2 ]), + (0, Quadratic form in 2 variables over Integer Ring with coefficients: + [ 2 2 ] + [ * 2 ])] """ # Try to use the cached result try: @@ -356,22 +356,20 @@ def jordan_blocks_by_scale_and_unimodular(self, p, safe_flag=True): def jordan_blocks_in_unimodular_list_by_scale_power(self, p): - """ - Returns a list of Jordan components, whose component at index i - should be scaled by the factor p^i. + r""" + Return a list of Jordan components, whose component at index `i` + should be scaled by the factor `p^i`. This is only defined for integer-valued quadratic forms - (i.e. forms with base_ring ZZ), and the indexing only works - correctly for p=2 when the form has an integer Gram matrix. + (i.e., forms with base ring `\ZZ`), and the indexing only works + correctly for `p=2` when the form has an integer Gram matrix. INPUT: - self -- a quadratic form over ZZ, which has integer Gram matrix if p == 2 - `p` -- a prime number > 0 - - OUTPUT: + - ``self`` -- a quadratic form over `\ZZ`, which has integer Gram matrix if `p = 2` + - ``p`` -- a prime number > 0 - a list of p-unimodular quadratic forms + OUTPUT: a list of `p`-unimodular quadratic forms EXAMPLES:: @@ -383,16 +381,19 @@ def jordan_blocks_in_unimodular_list_by_scale_power(self, p): sage: Q.scale_by_factor(2).jordan_blocks_in_unimodular_list_by_scale_power(2) [Quadratic form in 2 variables over Integer Ring with coefficients: - [ 0 2 ] - [ * 0 ], Quadratic form in 0 variables over Integer Ring with coefficients: - , Quadratic form in 1 variables over Integer Ring with coefficients: - [ 345 ]] + [ 0 2 ] + [ * 0 ], + Quadratic form in 0 variables over Integer Ring with coefficients: + , + Quadratic form in 1 variables over Integer Ring with coefficients: + [ 345 ]] sage: Q.jordan_blocks_in_unimodular_list_by_scale_power(3) [Quadratic form in 2 variables over Integer Ring with coefficients: - [ 2 0 ] - [ * 10 ], Quadratic form in 1 variables over Integer Ring with coefficients: - [ 2 ]] + [ 2 0 ] + [ * 10 ], + Quadratic form in 1 variables over Integer Ring with coefficients: + [ 2 ]] """ # Sanity Check if self.base_ring() != ZZ: diff --git a/src/sage/quadratic_forms/quadratic_form__local_representation_conditions.py b/src/sage/quadratic_forms/quadratic_form__local_representation_conditions.py index 661078d8788..ccff02a6368 100644 --- a/src/sage/quadratic_forms/quadratic_form__local_representation_conditions.py +++ b/src/sage/quadratic_forms/quadratic_form__local_representation_conditions.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.libs.pari sage.rings.number_field """ Local Representation Conditions """ @@ -67,8 +68,9 @@ class QuadraticFormLocalRepresentationConditions(): sage: Q2.is_locally_universal_at_all_primes() False sage: L = [m for m in range(-5, 25) if Q2.is_locally_represented_number(m)] - sage: L1 = [0] + [m for m in range(1,25) \ - if len([p for p in prime_factors(squarefree_part(ZZ(m))) if (p % 4) == 3]) % 2 == 0] + sage: L1 = [0] + [m for m in range(1, 25) + ....: if len([p for p in prime_factors(squarefree_part(ZZ(m))) + ....: if (p % 4) == 3]) % 2 == 0] sage: L == L1 True sage: L @@ -93,19 +95,19 @@ class QuadraticFormLocalRepresentationConditions(): [0] """ def __init__(self, Q): - """ - Takes a QuadraticForm and computes its local conditions (if - they do not already exist). The recompute_flag overrides the + r""" + Takes a :class:`QuadraticForm` and computes its local conditions (if + they do not already exist). The ``recompute_flag`` overrides the previously computed conditions if they exist, and stores the new conditions. INPUT: - - Q -- Quadratic form over ZZ + - ``Q`` -- Quadratic form over `\ZZ` OUTPUT: - a QuadraticFormLocalRepresentationConditions object + a :class:`QuadraticFormLocalRepresentationConditions` object EXAMPLES:: @@ -201,9 +203,7 @@ def __repr__(self) -> str: r""" Print the local conditions. - OUTPUT: - - string + OUTPUT: string .. TODO:: @@ -246,11 +246,9 @@ def __eq__(self, right) -> bool: INPUT: - - right -- a QuadraticFormLocalRepresentationConditions object - - OUTPUT: + - ``right`` -- a QuadraticFormLocalRepresentationConditions object - boolean + OUTPUT: boolean EXAMPLES:: @@ -293,11 +291,9 @@ def squareclass_vector(self, p) -> list: INPUT: - - `p` -- a positive prime number or "infinity" + - ``p`` -- a positive prime number or "infinity" - OUTPUT: - - a list of integers + OUTPUT: a list of integers EXAMPLES:: @@ -320,11 +316,9 @@ def local_conditions_vector_for_prime(self, p) -> list: INPUT: - - `p` -- a positive prime number. (Is 'infinity' allowed here?) - - OUTPUT: + - ``p`` -- a positive prime number. (Is 'infinity' allowed here?) - a list of integers + OUTPUT: a list of integers EXAMPLES:: @@ -371,16 +365,14 @@ def local_conditions_vector_for_prime(self, p) -> list: raise RuntimeError("the stored dimension should be a non-negative integer") def is_universal_at_prime(self, p) -> bool: - """ - Determine if the (integer-valued/rational) quadratic form represents all of `Z_p`. + r""" + Determine if the (integer-valued/rational) quadratic form represents all of `\ZZ_p`. INPUT: - - `p` -- a positive prime number or "infinity". + - ``p`` -- a positive prime number or "infinity" - OUTPUT: - - boolean + OUTPUT: boolean EXAMPLES:: @@ -418,12 +410,10 @@ def is_universal_at_prime(self, p) -> bool: return Zp_univ_flag def is_universal_at_all_finite_primes(self) -> bool: - """ - Determine if the quadratic form represents `Z_p` for all finite/non-archimedean primes. - - OUTPUT: + r""" + Determine if the quadratic form represents `\ZZ_p` for all finite/non-archimedean primes. - boolean + OUTPUT: boolean EXAMPLES:: @@ -451,13 +441,11 @@ def is_universal_at_all_finite_primes(self) -> bool: for p in self.exceptional_primes[1:]) def is_universal_at_all_places(self) -> bool: - """ - Determine if the quadratic form represents `Z_p` for all + r""" + Determine if the quadratic form represents `\ZZ_p` for all finite/non-archimedean primes, and represents all real numbers. - OUTPUT: - - boolean + OUTPUT: boolean EXAMPLES:: @@ -499,13 +487,11 @@ def is_locally_represented_at_place(self, m, p) -> bool: INPUT: - - `m` -- an integer - - - `p` -- a positive prime number or "infinity". + - ``m`` -- an integer - OUTPUT: + - ``p`` -- a positive prime number or "infinity" - boolean + OUTPUT: boolean EXAMPLES:: @@ -563,18 +549,16 @@ def is_locally_represented_at_place(self, m, p) -> bool: return local_vec[sqclass.index(s) + 1] <= (nu / 2) def is_locally_represented(self, m) -> bool: - """ + r""" Determine if the rational number `m` is locally represented by - the quadratic form (allowing vectors with coefficients in `Z_p` at all + the quadratic form (allowing vectors with coefficients in `\ZZ_p` at all places). INPUT: - - `m` -- an integer + - ``m`` -- an integer - OUTPUT: - - boolean + OUTPUT: boolean EXAMPLES:: @@ -624,51 +608,45 @@ def is_locally_represented(self, m) -> bool: def local_representation_conditions(self, recompute_flag=False, silent_flag=False): - """ + r""" .. WARNING:: - THIS ONLY WORKS CORRECTLY FOR FORMS IN >=3 VARIABLES, - WHICH ARE LOCALLY UNIVERSAL AT ALMOST ALL PRIMES! + This only works correctly for forms in >=3 variables, + which are locally universal at almost all primes! This class finds the local conditions for a number to be integrally represented by an integer-valued quadratic form. These conditions - are stored in "self.__local_representability_conditions" and + are stored in ``self.__local_representability_conditions`` and consist of a list of 9 element vectors, with one for each prime with a local obstruction (though only the first 5 are meaningful - unless `p=2` ). The first element is always the prime `p` where the + unless `p=2`). The first element is always the prime `p` where the local obstruction occurs, and the next 8 (or 4) entries represent - square-classes in the `p`-adic integers `Z_p`, and are labeled by the - `Q_p` square-classes `t*(Q_p)^2` with `t` given as follows: + square-classes in the `p`-adic integers `\ZZ_p`, and are labeled by the + `\QQ_p` square-classes `t\cdot (\QQ_p)^2` with `t` given as follows: - `p > 2` ==> [ * 1 u p u p * * * * ] + - for `p > 2`, ``[ * 1 u p u p * * * * ]``, - `p = 2` ==> [ * 1 3 5 7 2 6 10 14 ] + - for `p = 2`, ``[ * 1 3 5 7 2 6 10 14 ]``. The integer appearing in each place tells us how `p`-divisible a number needs to be in that square-class in order to be locally - represented by Q. A negative number indicates that the entire `Q_p` + represented by `Q`. A negative number indicates that the entire `\QQ_p` square-class is not represented, while a positive number `x` indicates - that `t*p^{(2*x)} (Z_p)^2` is locally represented but `t*p^{(2*(x-1))}` - `(Z_p)^2` is not. + that `t\cdot p^{(2\cdot x)} (\ZZ_p)^2` is locally represented but `t\cdot p^{(2\cdot (x-1))}` + `(\ZZ_p)^2` is not. - As an example, the vector - - [2 3 0 0 0 0 2 0 infinity] - - tells us that all positive integers are locally represented at p=2 + As an example, the vector ``[2 3 0 0 0 0 2 0 infinity]`` + tells us that all positive integers are locally represented at `p=2` except those of the forms: - `2^6 * u * r^2` with `u = 1 (mod 8)` - - `2^5 * u * r^2` with `u = 3 (mod 8)` + - `2^6\cdot u\cdot r^2` with `u = 1` (mod 8) - `2 * u * r^2` with `u = 7 (mod 8)` + - `2^5\cdot u\cdot r^2` with `u = 3` (mod 8) - At the real numbers, the vector which looks like + - `2\cdot u\cdot r^2` with `u = 7` (mod 8) - [infinity, 0, infinity, None, None, None, None, None, None] - - means that Q is negative definite (i.e. the 0 tells us all + At the real numbers, the vector which looks like ``[infinity, 0, infinity, None, None, None, None, None, None]`` + means that `Q` is negative definite (i.e., the 0 tells us all positive reals are represented). The real vector always appears, and is listed before the other ones. @@ -738,16 +716,14 @@ def local_representation_conditions(self, recompute_flag=False, silent_flag=Fals def is_locally_universal_at_prime(self, p) -> bool: - """ - Determine if the (integer-valued/rational) quadratic form represents all of `Z_p`. + r""" + Determine if the (integer-valued/rational) quadratic form represents all of `\ZZ_p`. INPUT: - - `p` -- a positive prime number or "infinity". + - ``p`` -- a positive prime number or "infinity" - OUTPUT: - - boolean + OUTPUT: boolean EXAMPLES:: @@ -784,12 +760,10 @@ def is_locally_universal_at_prime(self, p) -> bool: def is_locally_universal_at_all_primes(self) -> bool: - """ - Determine if the quadratic form represents `Z_p` for all finite/non-archimedean primes. - - OUTPUT: + r""" + Determine if the quadratic form represents `\ZZ_p` for all finite/non-archimedean primes. - boolean + OUTPUT: boolean EXAMPLES:: @@ -814,13 +788,11 @@ def is_locally_universal_at_all_primes(self) -> bool: def is_locally_universal_at_all_places(self) -> bool: - """ - Determine if the quadratic form represents `Z_p` for all + r""" + Determine if the quadratic form represents `\ZZ_p` for all finite/non-archimedean primes, and represents all real numbers. - OUTPUT: - - boolean + OUTPUT: boolean EXAMPLES:: @@ -851,13 +823,11 @@ def is_locally_represented_number_at_place(self, m, p) -> bool: INPUT: - - `m` -- an integer - - - `p` -- a prime number > 0 or 'infinity' + - ``m`` -- an integer - OUTPUT: + - ``p`` -- a prime number > 0 or 'infinity' - boolean + OUTPUT: boolean EXAMPLES:: @@ -898,11 +868,9 @@ def is_locally_represented_number(self, m) -> bool: INPUT: - - `m` -- an integer - - OUTPUT: + - ``m`` -- an integer - boolean + OUTPUT: boolean EXAMPLES:: diff --git a/src/sage/quadratic_forms/quadratic_form__mass.py b/src/sage/quadratic_forms/quadratic_form__mass.py index 8de97aaebc3..11b581b1dd7 100644 --- a/src/sage/quadratic_forms/quadratic_form__mass.py +++ b/src/sage/quadratic_forms/quadratic_form__mass.py @@ -55,7 +55,9 @@ def GHY_mass__maximal(self): Use the GHY formula to compute the mass of a (maximal?) quadratic lattice. This works for any number field. - Reference: See [GHY, Prop 7.4 and 7.5, p121] and [GY, Thrm 10.20, p25]. + REFERENCES: + + See [GHY, Prop 7.4 and 7.5, p121] and [GY, Thrm 10.20, p25]. OUTPUT: diff --git a/src/sage/quadratic_forms/quadratic_form__mass__Conway_Sloane_masses.py b/src/sage/quadratic_forms/quadratic_form__mass__Conway_Sloane_masses.py index 010ebd97b51..22e70881009 100644 --- a/src/sage/quadratic_forms/quadratic_form__mass__Conway_Sloane_masses.py +++ b/src/sage/quadratic_forms/quadratic_form__mass__Conway_Sloane_masses.py @@ -7,33 +7,31 @@ legendre_symbol, prime_divisors) from sage.misc.misc_c import prod -from sage.quadratic_forms.special_values import gamma__exact, zeta__exact, quadratic_L_function__exact from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ -from sage.symbolic.constants import pi def parity(self, allow_rescaling_flag=True): - """ + r""" Return the parity ("even" or "odd") of an integer-valued quadratic - form over `ZZ`, defined up to similitude/rescaling of the form so that + form over `\ZZ`, defined up to similitude/rescaling of the form so that its Jordan component of smallest scale is unimodular. After this rescaling, we say a form is even if it only represents even numbers, and odd if it represents some odd number. - If the 'allow_rescaling_flag' is set to False, then we require that - the quadratic form have a Gram matrix with coefficients in `ZZ`, and + If the ``allow_rescaling_flag`` is set to False, then we require that + the quadratic form have a Gram matrix with coefficients in `\ZZ`, and look at the unimodular Jordan block to determine its parity. This returns an error if the form is not integer-matrix, meaning that it has Jordan components at `p=2` which do not have an integer scale. - We determine the parity by looking for a 1x1 block in the 0-th + We determine the parity by looking for a `1 \times 1` block in the 0-th Jordan component, after a possible rescaling. INPUT: - self -- a quadratic form with base_ring `ZZ`, which we may - require to have integer Gram matrix. + - ``self`` -- a quadratic form with base ring `\ZZ`, which we may + require to have integer Gram matrix. OUTPUT: @@ -78,7 +76,6 @@ def parity(self, allow_rescaling_flag=True): [ * * 1 ] sage: Q.parity() 'odd' - """ # Deal with 0-dim'l forms if self.dim() == 0: @@ -114,11 +111,11 @@ def parity(self, allow_rescaling_flag=True): def is_even(self, allow_rescaling_flag=True): - """ - Returns true iff after rescaling by some appropriate factor, the - form represents no odd integers. For more details, see parity(). + r""" + Return true iff after rescaling by some appropriate factor, the + form represents no odd integers. For more details, see :meth:`parity`. - Requires that Q is defined over `ZZ`. + Requires that `Q` is defined over `\ZZ`. EXAMPLES:: @@ -134,11 +131,11 @@ def is_even(self, allow_rescaling_flag=True): def is_odd(self, allow_rescaling_flag=True): - """ - Returns true iff after rescaling by some appropriate factor, the - form represents some odd integers. For more details, see parity(). + r""" + Return true iff after rescaling by some appropriate factor, the + form represents some odd integers. For more details, see :meth:`parity`. - Requires that Q is defined over `ZZ`. + Requires that `Q` is defined over `\ZZ`. EXAMPLES:: @@ -154,25 +151,25 @@ def is_odd(self, allow_rescaling_flag=True): def conway_species_list_at_odd_prime(self, p): - """ - Returns an integer called the 'species' which determines the type - of the orthogonal group over the finite field `F_p`. + r""" + Return an integer called the 'species' which determines the type + of the orthogonal group over the finite field `\GF{p}`. This assumes that the given quadratic form is a unimodular Jordan block at an odd prime `p`. When the dimension is odd then this number is always positive, otherwise it may be positive or negative (or zero, but that is considered positive by convention). - Note: The species of a zero dim'l form is always 0+, so we - interpret the return value of zero as positive here! =) + .. NOTE: + + The species of a zero dimensional form is always 0+, so we + interpret the return value of zero as positive here! =) INPUT: - a positive prime number + - ``p`` -- a positive prime number - OUTPUT: - - a list of integers + OUTPUT: a list of integers EXAMPLES:: @@ -224,21 +221,21 @@ def conway_species_list_at_odd_prime(self, p): def conway_species_list_at_2(self): - """ - Returns an integer called the 'species' which determines the type - of the orthogonal group over the finite field `F_p`. + r""" + Return an integer called the 'species' which determines the type + of the orthogonal group over the finite field `\GF{p}`. This assumes that the given quadratic form is a unimodular Jordan block at an odd prime `p`. When the dimension is odd then this number is always positive, otherwise it may be positive or negative. - Note: The species of a zero dim'l form is always 0+, so we - interpret the return value of zero as positive here! =) + .. NOTE:: - OUTPUT: + The species of a zero dimensional form is always 0+, so we + interpret the return value of zero as positive here! =) - a list of integers + OUTPUT: a list of integers EXAMPLES:: @@ -309,21 +306,15 @@ def conway_species_list_at_2(self): def conway_octane_of_this_unimodular_Jordan_block_at_2(self): - """ + r""" Determines the 'octane' of this full unimodular Jordan block at - the prime `p=2`. This is an invariant defined `(mod 8)`, ad. + the prime `p=2`. This is an invariant defined (mod 8), ad. This assumes that the form is given as a block diagonal form with - unimodular blocks of size <= 2 and the 1x1 blocks are all in the upper + unimodular blocks of size `\leq 2` and the `1 \times 1` blocks are all in the upper leftmost position. - INPUT: - - none - - OUTPUT: - - an integer 0 <= x <= 7 + OUTPUT: an integer `0 \leq x \leq 7` EXAMPLES:: @@ -336,7 +327,6 @@ def conway_octane_of_this_unimodular_Jordan_block_at_2(self): sage: Q = DiagonalQuadraticForm(ZZ, [3,7,13]) sage: Q.conway_octane_of_this_unimodular_Jordan_block_at_2() 7 - """ # Deal with 'even' forms if self.parity() == "even": @@ -401,23 +391,20 @@ def conway_octane_of_this_unimodular_Jordan_block_at_2(self): def conway_diagonal_factor(self, p): - """ - Computes the diagonal factor of Conway's `p`-mass. + r""" + Compute the diagonal factor of Conway's `p`-mass. INPUT: - `p` -- a prime number > 0 - - OUTPUT: + - ``p`` -- a prime number > 0 - a rational number > 0 + OUTPUT: a rational number > 0 EXAMPLES:: sage: Q = DiagonalQuadraticForm(ZZ, range(1,6)) sage: Q.conway_diagonal_factor(3) 81/256 - """ # Get the species list at p if p == 2: @@ -442,17 +429,15 @@ def conway_diagonal_factor(self, p): def conway_cross_product_doubled_power(self, p): - """ - Computes twice the power of p which evaluates the 'cross product' + r""" + Compute twice the power of `p` which evaluates the 'cross product' term in Conway's mass formula. INPUT: - `p` -- a prime number > 0 + - ``p`` -- a prime number > 0 - OUTPUT: - - a rational number + OUTPUT: a rational number EXAMPLES:: @@ -480,23 +465,16 @@ def conway_cross_product_doubled_power(self, p): def conway_type_factor(self): - """ + r""" This is a special factor only present in the mass formula when `p=2`. - INPUT: - - none - - OUTPUT: - - a rational number + OUTPUT: a rational number EXAMPLES:: sage: Q = DiagonalQuadraticForm(ZZ, range(1,8)) sage: Q.conway_type_factor() 4 - """ jordan_list = self.jordan_blocks_in_unimodular_list_by_scale_power(2) n2 = sum([J.dim() for J in jordan_list if J.is_even()]) @@ -506,16 +484,14 @@ def conway_type_factor(self): def conway_p_mass(self, p): - """ - Computes Conway's `p`-mass. + r""" + Compute Conway's `p`-mass. INPUT: - `p` -- a prime number > 0 + - ``p`` -- a prime number > 0 - OUTPUT: - - a rational number > 0 + OUTPUT: a rational number > 0 EXAMPLES:: @@ -524,7 +500,6 @@ def conway_p_mass(self, p): 16/3 sage: Q.conway_p_mass(3) 729/256 - """ # Compute the first two factors of the p-mass p_mass = self.conway_diagonal_factor(p) * (p ** (self.conway_cross_product_doubled_power(p) / ZZ(2))) @@ -538,23 +513,20 @@ def conway_p_mass(self, p): def conway_standard_p_mass(self, p): - """ - Computes the standard (generic) Conway-Sloane `p`-mass. + r""" + Compute the standard (generic) Conway-Sloane `p`-mass. INPUT: - `p` -- a prime number > 0 - - OUTPUT: + - ``p`` -- a prime number > 0 - a rational number > 0 + OUTPUT: a rational number > 0 EXAMPLES:: sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1]) sage: Q.conway_standard_p_mass(2) 2/3 - """ # Some useful variables n = self.dim() @@ -576,30 +548,26 @@ def conway_standard_p_mass(self, p): def conway_standard_mass(self): - """ - Returns the infinite product of the standard mass factors. - - INPUT: - - none - - OUTPUT: + r""" + Return the infinite product of the standard mass factors. - a rational number > 0 + OUTPUT: a rational number > 0 EXAMPLES:: sage: Q = QuadraticForm(ZZ, 3, [2, -2, 0, 3, -5, 4]) - sage: Q.conway_standard_mass() + sage: Q.conway_standard_mass() # optional - sage.symbolic 1/6 :: sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1]) - sage: Q.conway_standard_mass() + sage: Q.conway_standard_mass() # optional - sage.symbolic 1/6 - """ + from sage.quadratic_forms.special_values import gamma__exact, zeta__exact, quadratic_L_function__exact + from sage.symbolic.constants import pi + n = self.dim() if n % 2 == 0: s = n // 2 @@ -618,29 +586,27 @@ def conway_standard_mass(self): def conway_mass(self): - """ + r""" Compute the mass by using the Conway-Sloane mass formula. - OUTPUT: - - a rational number > 0 + OUTPUT: a rational number > 0 EXAMPLES:: sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1]) - sage: Q.conway_mass() + sage: Q.conway_mass() # optional - sage.symbolic 1/48 sage: Q = DiagonalQuadraticForm(ZZ, [7,1,1]) - sage: Q.conway_mass() + sage: Q.conway_mass() # optional - sage.symbolic 3/16 sage: Q = QuadraticForm(ZZ, 3, [7, 2, 2, 2, 0, 2]) + DiagonalQuadraticForm(ZZ, [1]) - sage: Q.conway_mass() + sage: Q.conway_mass() # optional - sage.symbolic 3/32 - sage: Q = QuadraticForm(Matrix(ZZ,2,[2,1,1,2])) - sage: Q.conway_mass() + sage: Q = QuadraticForm(Matrix(ZZ, 2, [2,1,1,2])) + sage: Q.conway_mass() # optional - sage.symbolic 1/12 """ # Try to use the cached result diff --git a/src/sage/quadratic_forms/quadratic_form__mass__Siegel_densities.py b/src/sage/quadratic_forms/quadratic_form__mass__Siegel_densities.py index 16d18f12341..d0a668381b8 100644 --- a/src/sage/quadratic_forms/quadratic_form__mass__Siegel_densities.py +++ b/src/sage/quadratic_forms/quadratic_form__mass__Siegel_densities.py @@ -13,7 +13,6 @@ from copy import deepcopy from sage.arith.misc import kronecker, legendre_symbol, prime_divisors -from sage.functions.all import sgn from sage.matrix.matrix_space import MatrixSpace from sage.misc.functional import squarefree_part from sage.misc.misc_c import prod @@ -22,43 +21,47 @@ from sage.rings.finite_rings.integer_mod_ring import IntegerModRing from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ -from sage.symbolic.constants import pi def mass__by_Siegel_densities(self, odd_algorithm="Pall", even_algorithm="Watson"): """ - Gives the mass of transformations (det 1 and -1). + Return the mass of transformations (det 1 and -1). - WARNING: THIS IS BROKEN RIGHT NOW... =( + .. WARNING:: - Optional Arguments: + This is broken right now... - - When p > 2 -- odd_algorithm = "Pall" (only one choice for now) - - When p = 2 -- even_algorithm = "Kitaoka" or "Watson" + INPUT: + + - ``odd_algorithm`` -- algorithm to be used when `p>2`; ``"Pall"`` (only one choice for now) + - ``even_algorithm`` -- algorithm to be used when `p=2`; + either ``"Kitaoka"`` or ``"Watson"`` (the default) REFERENCES: - Nipp's Book "Tables of Quaternary Quadratic Forms". - - Papers of Pall (only for p>2) and Watson (for `p=2` -- tricky!). + - Papers of Pall (only for `p>2`) and Watson (for `p=2` -- tricky!). - Siegel, Milnor-Hussemoller, Conway-Sloane Paper IV, Kitoaka (all of which have problems...) EXAMPLES:: sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1,1]) - sage: m = Q.mass__by_Siegel_densities(); m + sage: m = Q.mass__by_Siegel_densities(); m # optional - sage.symbolic 1/384 - sage: m - (2^Q.dim() * factorial(Q.dim()))^(-1) + sage: m - (2^Q.dim() * factorial(Q.dim()))^(-1) # optional - sage.symbolic 0 :: sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1]) - sage: m = Q.mass__by_Siegel_densities(); m + sage: m = Q.mass__by_Siegel_densities(); m # optional - sage.symbolic 1/48 - sage: m - (2^Q.dim() * factorial(Q.dim()))^(-1) + sage: m - (2^Q.dim() * factorial(Q.dim()))^(-1) # optional - sage.symbolic 0 """ + from sage.symbolic.constants import pi + # Setup n = self.dim() s = (n-1) // 2 @@ -110,22 +113,20 @@ def mass__by_Siegel_densities(self, odd_algorithm="Pall", even_algorithm="Watson def Pall_mass_density_at_odd_prime(self, p): - """ - Returns the local representation density of a form (for - representing itself) defined over `ZZ`, at some prime `p>2`. + r""" + Return the local representation density of a form (for + representing itself) defined over `\ZZ`, at some prime `p>2`. REFERENCES: - Pall's article "The Weight of a Genus of Positive n-ary Quadratic Forms" - appearing in Proc. Symp. Pure Math. VIII (1965), pp95--105. + Pall's article "The Weight of a Genus of Positive n-ary Quadratic Forms" + appearing in Proc. Symp. Pure Math. VIII (1965), pp95--105. INPUT: - `p` -- a prime number > 2. - - OUTPUT: + - ``p`` -- a prime number > 2 - a rational number. + OUTPUT: a rational number. EXAMPLES:: @@ -171,25 +172,21 @@ def Pall_mass_density_at_odd_prime(self, p): def Watson_mass_at_2(self): """ - Returns the local mass of the quadratic form when `p=2`, according + Return the local mass of the quadratic form when `p=2`, according to Watson's Theorem 1 of "The 2-adic density of a quadratic form" in Mathematika 23 (1976), pp 94--106. - INPUT: - - none - - OUTPUT: - - a rational number + OUTPUT: a rational number EXAMPLES:: sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1]) - sage: Q.Watson_mass_at_2() # WARNING: WE NEED TO CHECK THIS CAREFULLY! + sage: Q.Watson_mass_at_2() # WARNING: WE NEED TO CHECK THIS CAREFULLY! # optional - sage.symbolic 384 """ + from sage.functions.all import sgn + # Make a 0-dim'l quadratic form (for initialization purposes) Null_Form = deepcopy(self) Null_Form.__init__(ZZ, 0) @@ -259,17 +256,11 @@ def Watson_mass_at_2(self): def Kitaoka_mass_at_2(self): """ - Returns the local mass of the quadratic form when `p=2`, according + Return the local mass of the quadratic form when `p=2`, according to Theorem 5.6.3 on pp108--9 of Kitaoka's Book "The Arithmetic of Quadratic Forms". - INPUT: - - none - - OUTPUT: - - a rational number > 0 + OUTPUT: a rational number > 0 EXAMPLES:: @@ -348,10 +339,12 @@ def Kitaoka_mass_at_2(self): def mass_at_two_by_counting_mod_power(self, k): - """ - Computes the local mass at `p=2` assuming that it's stable `(mod 2^k)`. + r""" + Compute the local mass at `p=2` assuming that it's stable (mod `2^k`). - Note: This is **way** too slow to be useful, even when k=1!!! + .. NOTE:: + + This is **way** too slow to be useful, even when `k=1`. .. TODO:: @@ -359,11 +352,9 @@ def mass_at_two_by_counting_mod_power(self, k): INPUT: - - k -- an integer >= 1 - - OUTPUT: + - ``k`` -- an integer `\geq 1` - a rational number + OUTPUT: a rational number EXAMPLES:: diff --git a/src/sage/quadratic_forms/quadratic_form__neighbors.py b/src/sage/quadratic_forms/quadratic_form__neighbors.py index 11065d861aa..4a490717863 100644 --- a/src/sage/quadratic_forms/quadratic_form__neighbors.py +++ b/src/sage/quadratic_forms/quadratic_form__neighbors.py @@ -4,7 +4,6 @@ from sage.modules.free_module_element import vector from sage.rings.integer_ring import ZZ -from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF from sage.rings.rational_field import QQ from copy import deepcopy from sage.matrix.constructor import matrix @@ -32,7 +31,7 @@ def find_primitive_p_divisible_vector__random(self, p): True sage: 5.divides(Q(v)) True - sage: Q = QuadraticForm(QQ,matrix.diagonal([1,1,1,1])) + sage: Q = QuadraticForm(QQ, matrix.diagonal([1,1,1,1])) sage: v = Q.find_primitive_p_divisible_vector__random(2) sage: Q(v) 2 @@ -60,14 +59,12 @@ def find_primitive_p_divisible_vector__next(self, p, v=None): value is `p`-divisible, where the last vector returned was `v`. For an initial call, no `v` needs to be passed. - Returns vectors whose last non-zero entry is normalized to 0 or 1 (so no + Return vectors whose last non-zero entry is normalized to 0 or 1 (so no lines are counted repeatedly). The ordering is by increasing the first non-normalized entry. If we have tested all (lines of) vectors, then return None. - OUTPUT: - - vector or None + OUTPUT: vector or None EXAMPLES:: @@ -77,7 +74,7 @@ def find_primitive_p_divisible_vector__next(self, p, v=None): sage: v = Q.find_primitive_p_divisible_vector__next(5, v); v (1, 0) sage: v = Q.find_primitive_p_divisible_vector__next(5, v); v - sage: Q = QuadraticForm(QQ,matrix.diagonal([1,1,1,1])) + sage: Q = QuadraticForm(QQ, matrix.diagonal([1,1,1,1])) sage: v = Q.find_primitive_p_divisible_vector__next(2) sage: Q(v) 2 @@ -147,14 +144,14 @@ def find_p_neighbor_from_vec(self, p, y): INPUT: - ``p`` -- a prime number - - ``y`` -- a vector with `q(y) \in p \ZZ`. - - ``odd`` -- (default=``False``) if `p=2` return also odd neighbors + - ``y`` -- a vector with `q(y) \in p \ZZ` + - ``odd`` -- (default: ``False``) if `p=2`, return also odd neighbors EXAMPLES:: - sage: Q = DiagonalQuadraticForm(ZZ,[1,1,1,1]) + sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1,1]) sage: v = vector([0,2,1,1]) - sage: X = Q.find_p_neighbor_from_vec(3,v); X + sage: X = Q.find_p_neighbor_from_vec(3, v); X # optional - sage.libs.pari Quadratic form in 4 variables over Integer Ring with coefficients: [ 1 0 0 0 ] [ * 1 4 4 ] @@ -163,11 +160,11 @@ def find_p_neighbor_from_vec(self, p, y): Since the base ring and the domain are not yet separate, for rational, half integral forms we just pretend - the base ring is `ZZ`:: + the base ring is `\ZZ`:: - sage: Q = QuadraticForm(QQ,matrix.diagonal([1,1,1,1])) + sage: Q = QuadraticForm(QQ, matrix.diagonal([1,1,1,1])) sage: v = vector([1,1,1,1]) - sage: Q.find_p_neighbor_from_vec(2,v) + sage: Q.find_p_neighbor_from_vec(2, v) # optional - sage.libs.pari Quadratic form in 4 variables over Rational Field with coefficients: [ 1/2 1 1 1 ] [ * 1 1 2 ] @@ -179,6 +176,9 @@ def find_p_neighbor_from_vec(self, p, y): raise ValueError("y=%s must be of square divisible by p=%s"%(y,p)) if self.base_ring() not in [ZZ, QQ]: raise NotImplementedError("the base ring of this form must be the integers or the rationals") + + from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF + n = self.dim() G = self.Hessian_matrix() R = self.base_ring() @@ -237,7 +237,7 @@ def neighbor_iteration(seeds, p, mass=None, max_classes=ZZ(10)**3, Return all classes in the `p`-neighbor graph of ``self``. Starting from the given seeds, this function successively - finds p-neighbors until no new quadratic form (class) is obtained. + finds `p`-neighbors until no new quadratic form (class) is obtained. INPUT: @@ -249,14 +249,12 @@ def neighbor_iteration(seeds, p, mass=None, max_classes=ZZ(10)**3, - ``max_classes`` -- (default: ``1000``) break the computation when ``max_classes`` are found - - ``algorithm`` -- (optional) one of 'orbits', 'random', 'exhaustion' + - ``algorithm`` -- (optional) one of ``'orbits'``, ``'random'``, ``'exhaustion'`` - ``max_random_trys`` -- (default: ``1000``) the maximum number of neighbors - computed for a single lattice + computed for a single lattice - OUTPUT: - - - a list of quadratic forms + OUTPUT: a list of quadratic forms EXAMPLES:: @@ -264,26 +262,29 @@ def neighbor_iteration(seeds, p, mass=None, max_classes=ZZ(10)**3, sage: Q = QuadraticForm(ZZ, 3, [1, 0, 0, 2, 1, 3]) sage: Q.det() 46 - sage: mass = Q.conway_mass() - sage: g1 = neighbor_iteration([Q],3, mass=mass, algorithm = 'random') # long time - sage: g2 = neighbor_iteration([Q],3, algorithm = 'exhaustion') # long time - sage: g3 = neighbor_iteration([Q],3, algorithm = 'orbits') - sage: mass == sum(1/q.number_of_automorphisms() for q in g1) # long time + sage: mass = Q.conway_mass() # optional - sage.symbolic + sage: g1 = neighbor_iteration([Q], 3, # long time # optional - sage.symbolic + ....: mass=mass, algorithm='random') + sage: g2 = neighbor_iteration([Q], 3, algorithm='exhaustion') # long time + sage: g3 = neighbor_iteration([Q], 3, algorithm='orbits') # optional - sage.libs.gap + sage: mass == sum(1/q.number_of_automorphisms() for q in g1) # long time # optional - sage.symbolic True - sage: mass == sum(1/q.number_of_automorphisms() for q in g2) # long time + sage: mass == sum(1/q.number_of_automorphisms() for q in g2) # long time # optional - sage.symbolic True - sage: mass == sum(1/q.number_of_automorphisms() for q in g3) + sage: mass == sum(1/q.number_of_automorphisms() for q in g3) # optional - sage.libs.gap sage.symbolic True TESTS:: sage: from sage.quadratic_forms.quadratic_form__neighbors import neighbor_iteration sage: Q = QuadraticForm(ZZ, 3, [1, 0, 0, 2, 1, 3]) - sage: g = neighbor_iteration([Q],3,mass=Q.conway_mass(),max_classes=2) + sage: g = neighbor_iteration([Q], 3, mass=Q.conway_mass(), max_classes=2) # optional - sage.symbolic ... - UserWarning: reached the maximum number of isometry classes=2. Increase the optional argument max_classes to obtain more. + UserWarning: reached the maximum number of isometry classes=2. + Increase the optional argument max_classes to obtain more. Warning: not all classes in the genus were found - sage: neighbor_iteration([Q], 3, mass=Q.conway_mass(), max_neighbors=0, algorithm='random') + sage: neighbor_iteration([Q], 3, # optional - sage.symbolic + ....: mass=Q.conway_mass(), max_neighbors=0, algorithm='random') Warning: not all classes in the genus were found [] """ @@ -362,15 +363,13 @@ def orbits_lines_mod_p(self, p): - ``p`` -- a prime number - OUTPUT: - - - a list of vectors over ``GF(p)`` + OUTPUT: a list of vectors over ``GF(p)`` EXAMPLES:: sage: from sage.quadratic_forms.quadratic_form__neighbors import orbits_lines_mod_p sage: Q = QuadraticForm(ZZ, 3, [1, 0, 0, 2, 1, 3]) - sage: Q.orbits_lines_mod_p(2) + sage: Q.orbits_lines_mod_p(2) # optional - sage.libs.gap sage.libs.pari [(0, 0, 1), (0, 1, 0), (0, 1, 1), @@ -380,6 +379,8 @@ def orbits_lines_mod_p(self, p): (1, 1, 1)] """ from sage.libs.gap.libgap import libgap + from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF + # careful the self.automorphism_group() acts from the left # but in gap we act from the right!! --> transpose gens = self.automorphism_group().gens() diff --git a/src/sage/quadratic_forms/quadratic_form__reduction_theory.py b/src/sage/quadratic_forms/quadratic_form__reduction_theory.py index 0035bbdf84f..03fab299d48 100644 --- a/src/sage/quadratic_forms/quadratic_form__reduction_theory.py +++ b/src/sage/quadratic_forms/quadratic_form__reduction_theory.py @@ -3,7 +3,8 @@ """ from copy import deepcopy from sage.matrix.constructor import matrix -from sage.functions.all import floor +from sage.misc.lazy_import import lazy_import +lazy_import("sage.functions.all", "floor") from sage.misc.mrange import mrange from sage.modules.free_module_element import vector from sage.rings.integer_ring import ZZ @@ -17,7 +18,7 @@ def reduced_binary_form1(self): EXAMPLES:: - sage: QuadraticForm(ZZ,2,[5,5,2]).reduced_binary_form1() + sage: QuadraticForm(ZZ, 2, [5,5,2]).reduced_binary_form1() # optional - sage.symbolic ( Quadratic form in 2 variables over Integer Ring with coefficients: [ 2 -1 ] @@ -79,7 +80,7 @@ def reduced_binary_form(self): EXAMPLES:: - sage: QuadraticForm(ZZ,2,[5,5,2]).reduced_binary_form() + sage: QuadraticForm(ZZ, 2, [5,5,2]).reduced_binary_form() # optional - sage.symbolic ( Quadratic form in 2 variables over Integer Ring with coefficients: [ 2 -1 ] @@ -133,28 +134,29 @@ def reduced_binary_form(self): def minkowski_reduction(self): - """ + r""" Find a Minkowski-reduced form equivalent to the given one. This means that .. MATH:: - Q(v_k) <= Q(s_1 * v_1 + ... + s_n * v_n) + Q(v_k) \leq Q(s_1\cdot v_1 + ... + s_n\cdot v_n) + + for all `s_i` where `\gcd(s_k, ... s_n) = 1`. - for all `s_i` where GCD`(s_k, ... s_n) = 1`. + .. NOTE:: - Note: When Q has dim <= 4 we can take all `s_i` in {1, 0, -1}. + When `Q` has dim `\leq 4` we can take all `s_i` in `\{1, 0, -1\}`. - References: + REFERENCES: - Schulze-Pillot's paper on "An algorithm for computing genera - of ternary and quaternary quadratic forms", p138. - Donaldson's 1979 paper "Minkowski Reduction of Integral - Matrices", p203. + - Schulze-Pillot's paper on "An algorithm for computing genera + of ternary and quaternary quadratic forms", p138. + - Donaldson's 1979 paper "Minkowski Reduction of Integral Matrices", p203. EXAMPLES:: - sage: Q = QuadraticForm(ZZ,4,[30, 17, 11, 12, 29, 25, 62, 64, 25, 110]) + sage: Q = QuadraticForm(ZZ, 4, [30, 17, 11, 12, 29, 25, 62, 64, 25, 110]) sage: Q Quadratic form in 4 variables over Integer Ring with coefficients: [ 30 17 11 12 ] @@ -262,26 +264,29 @@ def minkowski_reduction(self): def minkowski_reduction_for_4vars__SP(self): - """ + r""" Find a Minkowski-reduced form equivalent to the given one. This means that - Q(`v_k`) <= Q(`s_1 * v_1 + ... + s_n * v_n`) + .. MATH:: + + Q(v_k) \leq Q(s_1\cdot v_1 + ... + s_n\cdot v_n) for all `s_i` where GCD(`s_k, ... s_n`) = 1. - Note: When Q has dim <= 4 we can take all `s_i` in {1, 0, -1}. + .. NOTE:: + + When `Q` has dim `\leq 4`, we can take all `s_i` in `\{1, 0, -1\}`. - References: - Schulze-Pillot's paper on "An algorithm for computing genera - of ternary and quaternary quadratic forms", p138. - Donaldson's 1979 paper "Minkowski Reduction of Integral - Matrices", p203. + REFERENCES: + + - Schulze-Pillot's paper on "An algorithm for computing genera + of ternary and quaternary quadratic forms", p138. + - Donaldson's 1979 paper "Minkowski Reduction of Integral Matrices", p203. EXAMPLES:: - sage: Q = QuadraticForm(ZZ,4,[30,17,11,12,29,25,62,64,25,110]) - sage: Q + sage: Q = QuadraticForm(ZZ, 4, [30,17,11,12,29,25,62,64,25,110]); Q Quadratic form in 4 variables over Integer Ring with coefficients: [ 30 17 11 12 ] [ * 29 25 62 ] diff --git a/src/sage/quadratic_forms/quadratic_form__siegel_product.py b/src/sage/quadratic_forms/quadratic_form__siegel_product.py index b7426ecd1f3..1ac027a6331 100644 --- a/src/sage/quadratic_forms/quadratic_form__siegel_product.py +++ b/src/sage/quadratic_forms/quadratic_form__siegel_product.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.libs.pari """ Siegel Products """ @@ -33,7 +34,7 @@ def siegel_product(self, u): """ - Computes the infinite product of local densities of the quadratic + Compute the infinite product of local densities of the quadratic form for the number `u`. EXAMPLES:: diff --git a/src/sage/quadratic_forms/quadratic_form__split_local_covering.py b/src/sage/quadratic_forms/quadratic_form__split_local_covering.py index 5db7d266767..5991fb113c2 100644 --- a/src/sage/quadratic_forms/quadratic_form__split_local_covering.py +++ b/src/sage/quadratic_forms/quadratic_form__split_local_covering.py @@ -9,14 +9,13 @@ from copy import deepcopy from sage.quadratic_forms.extras import extend_to_primitive -from sage.quadratic_forms.quadratic_form import QuadraticForm__constructor, is_QuadraticForm import sage.rings.abc -from sage.rings.real_mpfr import RealField from sage.rings.real_double import RDF from sage.matrix.matrix_space import MatrixSpace from sage.matrix.constructor import matrix -from sage.functions.all import floor +from sage.misc.lazy_import import lazy_import +lazy_import("sage.functions.all", "floor") from sage.rings.integer_ring import ZZ from sage.arith.misc import GCD @@ -28,28 +27,26 @@ def cholesky_decomposition(self, bit_prec = 53): RESTRICTIONS: - Q must be given as a QuadraticForm defined over `\ZZ`, `\QQ`, or some + `Q` must be given as a :class:`QuadraticForm` defined over `\ZZ`, `\QQ`, or some real field. If it is over some real field, then an error is raised if the precision given is not less than the defined precision of the real field defining the quadratic form! REFERENCE: - From Cohen's "A Course in Computational Algebraic Number Theory" book, - p 103. + - Cohen's "A Course in Computational Algebraic Number Theory" book, p 103. INPUT: - ``bit_prec`` -- a natural number (default 53). + - ``bit_prec`` -- a natural number (default 53) - OUTPUT: + OUTPUT: an upper triangular real matrix of precision ``bit_prec``. - an upper triangular real matrix of precision ``bit_prec``. + .. TODO:: - TO DO: - If we only care about working over the real double field (RDF), then we - can use the ``cholesky()`` method present for square matrices over that. + If we only care about working over the real double field (``RDF``), then we + can use the method :meth:`cholesky` present for square matrices over that. .. note:: @@ -57,10 +54,8 @@ def cholesky_decomposition(self, bit_prec = 53): :: - ##///////////////////////////////////////////////////////////////////////////////////////////////// - ##/// Finds the Cholesky decomposition of a quadratic form -- as an upper-triangular matrix! - ##/// (It's assumed to be global, hence twice the form it refers to.) <-- Python revision asks: Is this true?!? =| - ##///////////////////////////////////////////////////////////////////////////////////////////////// + Finds the Cholesky decomposition of a quadratic form -- as an upper-triangular matrix! + (It's assumed to be global, hence twice the form it refers to.) <-- Python revision asks: Is this true?!? =| EXAMPLES:: @@ -87,6 +82,8 @@ def cholesky_decomposition(self, bit_prec = 53): if isinstance(self.base_ring(), sage.rings.abc.RealField) and (self.base_ring().prec() < bit_prec): raise RuntimeError("the precision requested is greater than that of the given quadratic form") + from sage.rings.real_mpfr import RealField + # 1. Initialization n = self.dim() R = RealField(bit_prec) @@ -115,27 +112,29 @@ def cholesky_decomposition(self, bit_prec = 53): def vectors_by_length(self, bound): - """ - Returns a list of short vectors together with their values. + r""" + Return a list of short vectors together with their values. This is a naive algorithm which uses the Cholesky decomposition, but does not use the LLL-reduction algorithm. INPUT: - bound -- an integer >= 0 + - ``bound`` -- an integer `\geq 0` OUTPUT: - A list L of length (bound + 1) whose entry L `[i]` is a list of - all vectors of length `i`. + - a list ``L`` of length (``bound`` + 1) whose entry ``L[i]`` is a list of + all vectors of length `i`. + + REFERENCES: - Reference: This is a slightly modified version of Cohn's Algorithm + This is a slightly modified version of Cohn's Algorithm 2.7.5 in "A Course in Computational Number Theory", with the increment step moved around and slightly re-indexed to allow clean looping. - .. NOTE:: + .. NOTE:: We could speed this up for very skew matrices by using LLL first, and then changing coordinates back, but for our purposes @@ -144,7 +143,7 @@ def vectors_by_length(self, bound): EXAMPLES:: sage: Q = DiagonalQuadraticForm(ZZ, [1,1]) - sage: Q.vectors_by_length(5) + sage: Q.vectors_by_length(5) # optional - sage.symbolic [[[0, 0]], [[0, -1], [-1, 0]], [[-1, -1], [1, -1]], @@ -155,7 +154,7 @@ def vectors_by_length(self, bound): :: sage: Q1 = DiagonalQuadraticForm(ZZ, [1,3,5,7]) - sage: Q1.vectors_by_length(5) + sage: Q1.vectors_by_length(5) # optional - sage.symbolic [[[0, 0, 0, 0]], [[-1, 0, 0, 0]], [], @@ -166,13 +165,13 @@ def vectors_by_length(self, bound): :: sage: Q = QuadraticForm(ZZ, 4, [1,1,1,1, 1,0,0, 1,0, 1]) - sage: list(map(len, Q.vectors_by_length(2))) + sage: list(map(len, Q.vectors_by_length(2))) # optional - sage.symbolic [1, 12, 12] :: sage: Q = QuadraticForm(ZZ, 4, [1,-1,-1,-1, 1,0,0, 4,-3, 4]) - sage: list(map(len, Q.vectors_by_length(3))) + sage: list(map(len, Q.vectors_by_length(3))) # optional - sage.symbolic [1, 3, 0, 3] """ # pari uses eps = 1e-6 ; nothing bad should happen if eps is too big @@ -263,25 +262,27 @@ def vectors_by_length(self, bound): def complementary_subform_to_vector(self, v): - """ - Finds the `(n-1)`-dim'l quadratic form orthogonal to the vector `v`. + r""" + Find the `(n-1)`-dimensional quadratic form orthogonal to the vector `v`. - Note: This is usually not a direct summand! + .. NOTE:: - Technical Notes: There is a minor difference in the cancellation - code here (form the C++ version) since the notation Q `[i,j]` indexes - coefficients of the quadratic polynomial here, not the symmetric - matrix. Also, it produces a better splitting now, for the full - lattice (as opposed to a sublattice in the C++ code) since we - now extend `v` to a unimodular matrix. + This is usually not a direct summand! - INPUT: + .. NOTE:: - `v` -- a list of self.dim() integers + There is a minor difference in the cancellation + code here (form the C++ version) since the notation ``Q[i,j]`` indexes + coefficients of the quadratic polynomial here, not the symmetric + matrix. Also, it produces a better splitting now, for the full + lattice (as opposed to a sublattice in the C++ code) since we + now extend `v` to a unimodular matrix. - OUTPUT: + INPUT: + + - ``v`` -- a list of ``self.dim()`` integers - a QuadraticForm over `ZZ` + OUTPUT: a :class:`QuadraticForm` over `\ZZ` EXAMPLES:: @@ -308,7 +309,6 @@ def complementary_subform_to_vector(self, v): [ 880 -480 -160 ] [ * 624 -96 ] [ * * 240 ] - """ n = self.dim() @@ -358,41 +358,36 @@ def complementary_subform_to_vector(self, v): def split_local_cover(self): - """ + r""" Tries to find subform of the given (positive definite quaternary) - quadratic form Q of the form + quadratic form `Q` of the form .. MATH:: - d*x^2 + T(y,z,w) + d\cdot x^2 + T(y,z,w) where `d > 0` is as small as possible. This is done by exhaustive search on small vectors, and then - comparing the local conditions of its sum with it's complementary - lattice and the original quadratic form Q. - - INPUT: + comparing the local conditions of its sum with its complementary + lattice and the original quadratic form `Q`. - none - - OUTPUT: - - a QuadraticForm over ZZ + OUTPUT: a :class:`QuadraticForm` over `\ZZ` EXAMPLES:: sage: Q1 = DiagonalQuadraticForm(ZZ, [7,5,3]) - sage: Q1.split_local_cover() + sage: Q1.split_local_cover() # optional - sage.symbolic Quadratic form in 3 variables over Integer Ring with coefficients: [ 3 0 0 ] [ * 5 0 ] [ * * 7 ] - """ + from sage.quadratic_forms.quadratic_form import QuadraticForm + # 0. If a split local cover already exists, then return it. if hasattr(self, "__split_local_cover"): - if is_QuadraticForm(self.__split_local_cover): # Here the computation has been done. + if isinstance(self.__split_local_cover, QuadraticForm): # Here the computation has been done. return self.__split_local_cover elif self.__split_local_cover in ZZ: # Here it indexes the values already tried! current_length = self.__split_local_cover + 1 @@ -410,7 +405,7 @@ def split_local_cover(self): # 2. Check if any of the primitive ones produce a split local cover for v in current_vectors: - Q = QuadraticForm__constructor(ZZ, 1, [current_length]) + self.complementary_subform_to_vector(v) + Q = QuadraticForm(ZZ, 1, [current_length]) + self.complementary_subform_to_vector(v) if Q.local_representation_conditions() == self.local_representation_conditions(): self.__split_local_cover = Q return Q diff --git a/src/sage/quadratic_forms/quadratic_form__ternary_Tornaria.py b/src/sage/quadratic_forms/quadratic_form__ternary_Tornaria.py index 8686b43ed76..9b8dfcecf7b 100644 --- a/src/sage/quadratic_forms/quadratic_form__ternary_Tornaria.py +++ b/src/sage/quadratic_forms/quadratic_form__ternary_Tornaria.py @@ -17,12 +17,10 @@ hilbert_symbol, kronecker as kronecker_symbol, prime_to_m_part) -from sage.libs.pari.all import pari from sage.misc.functional import is_odd from sage.misc.misc_c import prod from sage.modules.free_module import FreeModule from sage.modules.free_module_element import vector -from sage.quadratic_forms.quadratic_form import QuadraticForm__constructor as QuadraticForm from sage.rings.integer_ring import ZZ @@ -133,6 +131,8 @@ def adjoint(self): [ * * 8 ] """ + from sage.quadratic_forms.quadratic_form import QuadraticForm as QuadraticForm + if is_odd(self.dim()): return QuadraticForm(self.matrix().adjoint_classical() * 2) return QuadraticForm(self.matrix().adjoint_classical()) @@ -150,7 +150,7 @@ def antiadjoint(self): [ 1 0 -1 ] [ * 2 -1 ] [ * * 5 ] - sage: Q.antiadjoint() + sage: Q.antiadjoint() # optional - sage.symbolic Traceback (most recent call last): ... ValueError: not an adjoint @@ -174,7 +174,7 @@ def is_adjoint(self) -> bool: EXAMPLES:: sage: Q = QuadraticForm(ZZ, 3, [1, 0, -1, 2, -1, 5]) - sage: Q.is_adjoint() + sage: Q.is_adjoint() # optional - sage.symbolic False sage: Q.adjoint().is_adjoint() True @@ -187,7 +187,7 @@ def is_adjoint(self) -> bool: def reciprocal(self): - """ + r""" This gives the reciprocal quadratic form associated to the given form. This is defined as the multiple of the primitive adjoint with the same content as the given form. @@ -213,7 +213,7 @@ def reciprocal(self): def omega(self): - """ + r""" This is the content of the adjoint of the primitive associated quadratic form. Ref: See Dickson's "Studies in Number Theory". @@ -229,7 +229,7 @@ def omega(self): def delta(self): - """ + r""" This is the omega of the adjoint form, which is the same as the omega of the reciprocal form. @@ -243,14 +243,14 @@ def delta(self): def level__Tornaria(self): - """ + r""" Return the level of the quadratic form, defined as - level(B) for even dimension - level(B)/4 for odd dimension + - level(`B`) for even dimension, + - level(`B`)/4 for odd dimension, - where 2Q(`x`) `= x^t * B * x`. + where `2Q(x) = x^t\cdot B\cdot x`. This agrees with the usual level for even dimension... @@ -269,7 +269,7 @@ def level__Tornaria(self): def discrec(self): - """ + r""" Return the discriminant of the reciprocal form. EXAMPLES:: @@ -289,21 +289,21 @@ def discrec(self): def hasse_conductor(self): """ - This is the product of all primes where the Hasse invariant equals -1 + This is the product of all primes where the Hasse invariant equals `-1` EXAMPLES:: sage: Q = QuadraticForm(ZZ, 3, [1, 0, -1, 2, -1, 5]) - sage: Q.hasse_invariant(2) + sage: Q.hasse_invariant(2) # optional - sage.libs.pari -1 - sage: Q.hasse_invariant(37) + sage: Q.hasse_invariant(37) # optional - sage.libs.pari -1 - sage: Q.hasse_conductor() + sage: Q.hasse_conductor() # optional - sage.libs.pari 74 - sage: DiagonalQuadraticForm(ZZ, [1, 1, 1]).hasse_conductor() + sage: DiagonalQuadraticForm(ZZ, [1, 1, 1]).hasse_conductor() # optional - sage.libs.pari 1 - sage: QuadraticForm(ZZ, 3, [2, -2, 0, 2, 0, 5]).hasse_conductor() + sage: QuadraticForm(ZZ, 3, [2, -2, 0, 2, 0, 5]).hasse_conductor() # optional - sage.libs.pari 10 """ return prod([x[0] for x in factor(2 * self.level()) @@ -320,16 +320,16 @@ def clifford_invariant(self, p): EXAMPLES: - For hyperbolic spaces, the clifford invariant is +1:: + For hyperbolic spaces, the Clifford invariant is +1:: sage: H = QuadraticForm(ZZ, 2, [0, 1, 0]) - sage: H.clifford_invariant(2) + sage: H.clifford_invariant(2) # optional - sage.libs.pari 1 - sage: (H + H).clifford_invariant(2) + sage: (H + H).clifford_invariant(2) # optional - sage.libs.pari 1 - sage: (H + H + H).clifford_invariant(2) + sage: (H + H + H).clifford_invariant(2) # optional - sage.libs.pari 1 - sage: (H + H + H + H).clifford_invariant(2) + sage: (H + H + H + H).clifford_invariant(2) # optional - sage.libs.pari 1 """ n = self.dim() % 8 @@ -346,9 +346,9 @@ def clifford_invariant(self, p): def clifford_conductor(self): """ - This is the product of all primes where the Clifford invariant is -1 + This is the product of all primes where the Clifford invariant is `-1` - ..NOTE:: + .. NOTE:: For ternary forms, this is the discriminant of the quaternion algebra associated to the quadratic space @@ -357,28 +357,28 @@ def clifford_conductor(self): EXAMPLES:: sage: Q = QuadraticForm(ZZ, 3, [1, 0, -1, 2, -1, 5]) - sage: Q.clifford_invariant(2) + sage: Q.clifford_invariant(2) # optional - sage.libs.pari 1 - sage: Q.clifford_invariant(37) + sage: Q.clifford_invariant(37) # optional - sage.libs.pari -1 - sage: Q.clifford_conductor() + sage: Q.clifford_conductor() # optional - sage.libs.pari 37 - sage: DiagonalQuadraticForm(ZZ, [1, 1, 1]).clifford_conductor() + sage: DiagonalQuadraticForm(ZZ, [1, 1, 1]).clifford_conductor() # optional - sage.libs.pari 2 - sage: QuadraticForm(ZZ, 3, [2, -2, 0, 2, 0, 5]).clifford_conductor() + sage: QuadraticForm(ZZ, 3, [2, -2, 0, 2, 0, 5]).clifford_conductor() # optional - sage.libs.pari 30 - For hyperbolic spaces, the clifford conductor is 1:: + For hyperbolic spaces, the Clifford conductor is 1:: sage: H = QuadraticForm(ZZ, 2, [0, 1, 0]) - sage: H.clifford_conductor() + sage: H.clifford_conductor() # optional - sage.libs.pari 1 - sage: (H + H).clifford_conductor() + sage: (H + H).clifford_conductor() # optional - sage.libs.pari 1 - sage: (H + H + H).clifford_conductor() + sage: (H + H + H).clifford_conductor() # optional - sage.libs.pari 1 - sage: (H + H + H + H).clifford_conductor() + sage: (H + H + H + H).clifford_conductor() # optional - sage.libs.pari 1 """ return prod([x[0] for x in factor(2 * self.level()) @@ -389,7 +389,7 @@ def clifford_conductor(self): def basiclemma(self, M): """ - Find a number represented by self and coprime to M. + Find a number represented by self and coprime to `M`. EXAMPLES:: @@ -404,7 +404,7 @@ def basiclemma(self, M): def basiclemmavec(self, M): """ - Find a vector where the value of the quadratic form is coprime to M. + Find a vector where the value of the quadratic form is coprime to `M`. EXAMPLES:: @@ -450,7 +450,9 @@ def xi(self, p): Return the value of the genus characters Xi_p... which may be missing one character. We allow -1 as a prime. - Reference: Dickson's "Studies in the Theory of Numbers" + REFERENCES: + + Dickson's "Studies in the Theory of Numbers" EXAMPLES:: @@ -458,9 +460,10 @@ def xi(self, p): sage: Q2 = QuadraticForm(ZZ, 3, [2, -1, 0, 2, 0, 50]) sage: [Q1.omega(), Q2.omega()] [5, 5] - sage: [Q1.hasse_invariant(5), Q2.hasse_invariant(5)] # equivalent over Q_5 + sage: [Q1.hasse_invariant(5), # equivalent over Q_5 # optional - sage.libs.pari + ....: Q2.hasse_invariant(5)] [1, 1] - sage: [Q1.xi(5), Q2.xi(5)] # not equivalent over Z_5 + sage: [Q1.xi(5), Q2.xi(5)] # not equivalent over Z_5 # optional - sage.libs.pari [1, -1] """ if self.dim() == 2 and self.disc() % p: @@ -480,17 +483,18 @@ def xi_rec(self,p): sage: Q1 = QuadraticForm(ZZ, 3, [1, 1, 1, 14, 3, 14]) sage: Q2 = QuadraticForm(ZZ, 3, [2, -1, 0, 2, 0, 50]) - sage: [Q1.clifford_conductor(), Q2.clifford_conductor()] # equivalent over Q + sage: [Q1.clifford_conductor(), # equivalent over Q # optional - sage.libs.pari + ....: Q2.clifford_conductor()] [3, 3] - sage: Q1.is_locally_equivalent_to(Q2) # not in the same genus + sage: Q1.is_locally_equivalent_to(Q2) # not in the same genus # optional - sage.libs.pari False - sage: [Q1.delta(), Q2.delta()] + sage: [Q1.delta(), Q2.delta()] # optional - sage.libs.pari [480, 480] - sage: factor(480) + sage: factor(480) # optional - sage.libs.pari 2^5 * 3 * 5 - sage: list(map(Q1.xi_rec, [-1,2,3,5])) + sage: list(map(Q1.xi_rec, [-1,2,3,5])) # optional - sage.libs.pari [-1, -1, -1, 1] - sage: list(map(Q2.xi_rec, [-1,2,3,5])) + sage: list(map(Q2.xi_rec, [-1,2,3,5])) # optional - sage.libs.pari [-1, -1, -1, -1] """ return self.reciprocal().xi(p) @@ -498,7 +502,7 @@ def xi_rec(self,p): def lll(self): """ - Return an LLL-reduced form of Q (using Pari). + Return an LLL-reduced form of `Q` (using PARI). EXAMPLES:: @@ -521,10 +525,12 @@ def representation_number_list(self, B): EXAMPLES:: - sage: Q = DiagonalQuadraticForm(ZZ,[1,1,1,1,1,1,1,1]) - sage: Q.representation_number_list(10) + sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1,1,1,1,1,1]) + sage: Q.representation_number_list(10) # optional - sage.libs.pari [1, 16, 112, 448, 1136, 2016, 3136, 5504, 9328, 12112] """ + from sage.libs.pari.all import pari + ans = pari(1).concat(self.__pari__().qfrep(B - 1, 1) * 2) return ans.sage() @@ -538,7 +544,7 @@ def representation_vector_list(self, B, maxvectors=10**8): EXAMPLES:: sage: Q = DiagonalQuadraticForm(ZZ, [1, 1]) - sage: Q.representation_vector_list(10) + sage: Q.representation_vector_list(10) # optional - sage.libs.pari [[(0, 0)], [(0, 1), (0, -1), (1, 0), (-1, 0)], [(1, 1), (-1, -1), (1, -1), (-1, 1)], @@ -549,15 +555,15 @@ def representation_vector_list(self, B, maxvectors=10**8): [], [(2, 2), (-2, -2), (2, -2), (-2, 2)], [(0, 3), (0, -3), (3, 0), (-3, 0)]] - sage: list(map(len, _)) + sage: list(map(len, _)) # optional - sage.libs.pari [1, 4, 4, 0, 4, 8, 0, 0, 4, 4] - sage: Q.representation_number_list(10) + sage: Q.representation_number_list(10) # optional - sage.libs.pari [1, 4, 4, 0, 4, 8, 0, 0, 4, 4] TESTS:: - sage: R = QuadraticForm(ZZ,2,[-4,-3,0]) - sage: R.representation_vector_list(10) + sage: R = QuadraticForm(ZZ, 2, [-4,-3,0]) + sage: R.representation_vector_list(10) # optional - sage.libs.pari Traceback (most recent call last): ... PariError: domain error in minim0: form is not positive definite @@ -576,8 +582,8 @@ def representation_vector_list(self, B, maxvectors=10**8): # zeros def is_zero(self, v, p=0) -> bool: - """ - Determine if the vector v is on the conic Q(x) = 0 (mod p). + r""" + Determine if the vector `v` is on the conic `Q(x) = 0` (mod `p`). EXAMPLES:: @@ -597,7 +603,7 @@ def is_zero(self, v, p=0) -> bool: def is_zero_nonsingular(self, v, p=0) -> bool: """ - Determine if the vector `v` is on the conic Q(`x`) = 0 (mod `p`), + Determine if the vector `v` is on the conic `Q(x) = 0` (mod `p`), and that this point is non-singular point of the conic. EXAMPLES:: @@ -620,7 +626,7 @@ def is_zero_nonsingular(self, v, p=0) -> bool: def is_zero_singular(self, v, p=0) -> bool: """ - Determine if the vector `v` is on the conic Q(`x`) = 0 (mod `p`), + Determine if the vector `v` is on the conic `Q(x) = 0` (mod `p`), and that this point is singular point of the conic. EXAMPLES:: diff --git a/src/sage/quadratic_forms/quadratic_form__theta.py b/src/sage/quadratic_forms/quadratic_form__theta.py index 022084cc332..c706d7e4de5 100644 --- a/src/sage/quadratic_forms/quadratic_form__theta.py +++ b/src/sage/quadratic_forms/quadratic_form__theta.py @@ -11,35 +11,31 @@ """ from copy import deepcopy -from sage.rings.real_mpfr import RealField from sage.rings.power_series_ring import PowerSeriesRing from sage.rings.integer_ring import ZZ -from sage.functions.all import floor, ceil -from sage.misc.functional import sqrt -from sage.misc.misc import cputime def theta_series(self, Max=10, var_str='q', safe_flag=True): - """ + r""" Compute the theta series as a power series in the variable given - in var_str (which defaults to '`q`'), up to the specified precision - `O(q^max)`. + in ``var_str`` (which defaults to ``'q'``), up to the specified precision + `O(q^{Max})`. This uses the PARI/GP function :pari:`qfrep`, wrapped by the theta_by_pari() method. This caches the result for future computations. - The safe_flag allows us to select whether we want a copy of the + The ``safe_flag`` allows us to select whether we want a copy of the output, or the original output. It is only meaningful when a vector is returned, otherwise a copy is automatically made in - creating the power series. By default safe_flag = True, so we + creating the power series. By default ``safe_flag`` = True, so we return a copy of the cached information. If this is set to False, then the routine is much faster but the return values are vulnerable to being corrupted by the user. .. TODO:: - Allow the option Max='mod_form' to give enough coefficients + Allow the option ``Max='mod_form'`` to give enough coefficients to ensure we determine the theta series as a modular form. This is related to the Sturm bound, but we will need to be careful about this (particularly for half-integral weights!). @@ -47,11 +43,13 @@ def theta_series(self, Max=10, var_str='q', safe_flag=True): EXAMPLES:: sage: Q = DiagonalQuadraticForm(ZZ, [1,3,5,7]) - sage: Q.theta_series() + sage: Q.theta_series() # optional - sage.libs.pari 1 + 2*q + 2*q^3 + 6*q^4 + 2*q^5 + 4*q^6 + 6*q^7 + 8*q^8 + 14*q^9 + O(q^10) - sage: Q.theta_series(25) - 1 + 2*q + 2*q^3 + 6*q^4 + 2*q^5 + 4*q^6 + 6*q^7 + 8*q^8 + 14*q^9 + 4*q^10 + 12*q^11 + 18*q^12 + 12*q^13 + 12*q^14 + 8*q^15 + 34*q^16 + 12*q^17 + 8*q^18 + 32*q^19 + 10*q^20 + 28*q^21 + 16*q^23 + 44*q^24 + O(q^25) + sage: Q.theta_series(25) # optional - sage.libs.pari + 1 + 2*q + 2*q^3 + 6*q^4 + 2*q^5 + 4*q^6 + 6*q^7 + 8*q^8 + 14*q^9 + 4*q^10 + + 12*q^11 + 18*q^12 + 12*q^13 + 12*q^14 + 8*q^15 + 34*q^16 + 12*q^17 + 8*q^18 + + 32*q^19 + 10*q^20 + 28*q^21 + 16*q^23 + 44*q^24 + O(q^25) """ # Sanity Check: Max is an integer or an allowed string: @@ -73,38 +71,37 @@ def theta_series(self, Max=10, var_str='q', safe_flag=True): # ------------- Compute the theta function by using the PARI/GP routine qfrep ------------ def theta_by_pari(self, Max, var_str='q', safe_flag=True): - """ + r""" Use PARI/GP to compute the theta function as a power series (or - vector) up to the precision `O(q^Max)`. This also caches the result + vector) up to the precision `O(q^{Max})`. This also caches the result for future computations. - If var_str = '', then we return a vector `v` where `v[i]` counts the + If ``var_str`` = ``''``, then we return a vector `v` where ``v[i]`` counts the number of vectors of length `i`. - The safe_flag allows us to select whether we want a copy of the + The ``safe_flag`` allows us to select whether we want a copy of the output, or the original output. It is only meaningful when a vector is returned, otherwise a copy is automatically made in - creating the power series. By default safe_flag = True, so we + creating the power series. By default ``safe_flag=True``, so we return a copy of the cached information. If this is set to False, then the routine is much faster but the return values are vulnerable to being corrupted by the user. INPUT: - Max -- an integer >=0 - var_str -- a string + - ``Max`` -- an integer `\geq 0` + - ``var_str`` -- a string - OUTPUT: - - a power series or a vector + OUTPUT: a power series or a vector EXAMPLES:: sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1,1]) sage: Prec = 100 - sage: compute = Q.theta_by_pari(Prec, '') - sage: exact = [1] + [8 * sum([d for d in divisors(i) if d % 4 != 0]) for i in range(1, Prec)] - sage: compute == exact + sage: compute = Q.theta_by_pari(Prec, '') # optional - sage.libs.pari + sage: exact = [1] + [8 * sum([d for d in divisors(i) if d % 4 != 0]) # optional - sage.libs.pari + ....: for i in range(1, Prec)] + sage: compute == exact # optional - sage.libs.pari True """ @@ -147,8 +144,7 @@ def theta_by_cholesky(self, q_prec): REFERENCE: - From Cohen's "A Course in Computational Algebraic Number Theory" book, - p 102. + Cohen's "A Course in Computational Algebraic Number Theory" book, p 102. EXAMPLES:: @@ -156,8 +152,10 @@ def theta_by_cholesky(self, q_prec): sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1,1]) sage: Theta = Q.theta_by_cholesky(10) sage: Theta - 1 + 8*q + 24*q^2 + 32*q^3 + 24*q^4 + 48*q^5 + 96*q^6 + 64*q^7 + 24*q^8 + 104*q^9 + 144*q^10 - sage: Expected = [1] + [8*sum([d for d in divisors(n) if d%4 != 0]) for n in range(1,11)] + 1 + 8*q + 24*q^2 + 32*q^3 + 24*q^4 + 48*q^5 + 96*q^6 + + 64*q^7 + 24*q^8 + 104*q^9 + 144*q^10 + sage: Expected = [1] + [8*sum([d for d in divisors(n) if d%4 != 0]) + ....: for n in range(1, 11)] sage: Expected [1, 8, 24, 32, 24, 48, 96, 64, 24, 104, 144] sage: Theta.list() == Expected @@ -176,6 +174,10 @@ def theta_by_cholesky(self, q_prec): # RAISE AN ERROR -- This routine is deprecated! #raise NotImplementedError, "This routine is deprecated. Try theta_series(), which uses theta_by_pari()." + from sage.arith.misc import integer_ceil as ceil, integer_floor as floor + from sage.misc.functional import sqrt + from sage.rings.real_mpfr import RealField + n = self.dim() theta = [0 for i in range(q_prec+1)] PS = PowerSeriesRing(ZZ, 'q') @@ -269,11 +271,11 @@ def theta_by_cholesky(self, q_prec): def theta_series_degree_2(Q, prec): r""" - Compute the theta series of degree 2 for the quadratic form Q. + Compute the theta series of degree 2 for the quadratic form `Q`. INPUT: - - ``prec`` -- an integer. + - ``prec`` -- an integer OUTPUT: @@ -303,6 +305,9 @@ def theta_series_degree_2(Q, prec): - Raum, Ryan, Skoruppa, Tornaria, 'On Formal Siegel Modular Forms' (preprint) """ + from sage.arith.misc import integer_floor as floor + from sage.misc.functional import sqrt + from sage.misc.misc import cputime from sage.misc.verbose import verbose if Q.base_ring() != ZZ: diff --git a/src/sage/quadratic_forms/quadratic_form__variable_substitutions.py b/src/sage/quadratic_forms/quadratic_form__variable_substitutions.py index f84dc007c7f..cbcae91d9de 100644 --- a/src/sage/quadratic_forms/quadratic_form__variable_substitutions.py +++ b/src/sage/quadratic_forms/quadratic_form__variable_substitutions.py @@ -19,17 +19,17 @@ def swap_variables(self, r, s, in_place=False): - """ + r""" Switch the variables `x_r` and `x_s` in the quadratic form - (replacing the original form if the in_place flag is True). + (replacing the original form if the ``in_place`` flag is True). INPUT: - - `r`, `s` -- integers >= 0 + - ``r``, ``s`` -- integers `\geq 0` OUTPUT: - a QuadraticForm (by default, otherwise none) + a :class:`QuadraticForm` (by default, otherwise none) EXAMPLES:: @@ -41,7 +41,6 @@ def swap_variables(self, r, s, in_place=False): [ * * 8 9 ] [ * * * 10 ] - sage: Q.swap_variables(0,2) Quadratic form in 4 variables over Integer Ring with coefficients: [ 8 6 3 9 ] @@ -49,14 +48,12 @@ def swap_variables(self, r, s, in_place=False): [ * * 1 4 ] [ * * * 10 ] - sage: Q.swap_variables(0,2).swap_variables(0,2) Quadratic form in 4 variables over Integer Ring with coefficients: [ 1 2 3 4 ] [ * 5 6 7 ] [ * * 8 9 ] [ * * * 10 ] - """ if not in_place: Q = self.parent()(self.base_ring(), self.dim(), self.coefficients()) @@ -77,33 +74,30 @@ def swap_variables(self, r, s, in_place=False): def multiply_variable(self, c, i, in_place=False): - """ - Replace the variables `x_i` by `c*x_i` in the quadratic form - (replacing the original form if the in_place flag is True). + r""" + Replace the variables `x_i` by `c\cdot x_i` in the quadratic form + (replacing the original form if the ``in_place`` flag is True). - Here `c` must be an element of the base_ring defining the + Here `c` must be an element of the base ring defining the quadratic form. INPUT: - - `c` -- an element of Q.base_ring() + - ``c`` -- an element of ``self.base_ring()`` - - `i` -- an integer >= 0 + - ``i`` -- an integer `\geq 0` - OUTPUT: - - a QuadraticForm (by default, otherwise none) + OUTPUT: a :class:`QuadraticForm` (by default, otherwise none) EXAMPLES:: sage: Q = DiagonalQuadraticForm(ZZ, [1,9,5,7]) - sage: Q.multiply_variable(5,0) + sage: Q.multiply_variable(5, 0) Quadratic form in 4 variables over Integer Ring with coefficients: [ 25 0 0 0 ] [ * 9 0 0 ] [ * * 5 0 ] [ * * * 7 ] - """ if not in_place: Q = self.parent()(self.base_ring(), self.dim(), self.coefficients()) @@ -122,34 +116,33 @@ def multiply_variable(self, c, i, in_place=False): def divide_variable(self, c, i, in_place=False): - """ + r""" Replace the variables `x_i` by `(x_i)/c` in the quadratic form - (replacing the original form if the in_place flag is True). + (replacing the original form if the ``in_place`` flag is True). - Here `c` must be an element of the base_ring defining the + Here `c` must be an element of the base ring defining the quadratic form, and the division must be defined in the base ring. INPUT: - - `c` -- an element of Q.base_ring() + - ``c`` -- an element of ``self.base_ring()`` - - `i` -- an integer >= 0 + - ``i`` -- an integer `\geq 0` OUTPUT: - a QuadraticForm (by default, otherwise none) + a :class:`QuadraticForm` (by default, otherwise none) EXAMPLES:: sage: Q = DiagonalQuadraticForm(ZZ, [1,9,5,7]) - sage: Q.divide_variable(3,1) + sage: Q.divide_variable(3, 1) Quadratic form in 4 variables over Integer Ring with coefficients: [ 1 0 0 0 ] [ * 1 0 0 ] [ * * 5 0 ] [ * * * 7 ] - """ if not in_place: Q = self.parent()(self.base_ring(), self.dim(), self.coefficients()) @@ -177,11 +170,9 @@ def scale_by_factor(self, c, change_value_ring_flag=False): INPUT: - `c` -- a scalar in the fraction field of the value ring of the form. + - ``c`` -- a scalar in the fraction field of the value ring of the form - OUTPUT: - - A quadratic form of the same dimension + OUTPUT: a quadratic form of the same dimension EXAMPLES:: @@ -222,17 +213,15 @@ def scale_by_factor(self, c, change_value_ring_flag=False): def extract_variables(QF, var_indices): - """ + r""" Extract the variables (in order) whose indices are listed in ``var_indices``, to give a new quadratic form. INPUT: - ``var_indices`` -- a list of integers >= 0 + - ``var_indices`` -- a list of integers `\geq 0` - OUTPUT: - - a QuadraticForm + OUTPUT: a :class:`QuadraticForm` EXAMPLES:: @@ -255,24 +244,23 @@ def extract_variables(QF, var_indices): def elementary_substitution(self, c, i, j, in_place=False): # CHECK THIS!!! - """ - Perform the substitution `x_i --> x_i + c*x_j` (replacing the - original form if the in_place flag is True). + r""" + Perform the substitution `x_i \longmapsto x_i + c\cdot x_j` (replacing the + original form if the ``in_place`` flag is True). INPUT: - - `c` -- an element of Q.base_ring() + - ``c`` -- an element of ``self.base_ring()`` - - `i`, `j` -- integers >= 0 + - ``i``, ``j`` -- integers `\geq 0` OUTPUT: - a QuadraticForm (by default, otherwise none) + a :class:`QuadraticForm` (by default, otherwise none) EXAMPLES:: - sage: Q = QuadraticForm(ZZ, 4, range(1,11)) - sage: Q + sage: Q = QuadraticForm(ZZ, 4, range(1,11)); Q Quadratic form in 4 variables over Integer Ring with coefficients: [ 1 2 3 4 ] [ * 5 6 7 ] @@ -288,8 +276,7 @@ def elementary_substitution(self, c, i, j, in_place=False): # CHECK THIS!!! :: - sage: R = QuadraticForm(ZZ, 4, range(1,11)) - sage: R + sage: R = QuadraticForm(ZZ, 4, range(1,11)); R Quadratic form in 4 variables over Integer Ring with coefficients: [ 1 2 3 4 ] [ * 5 6 7 ] @@ -298,8 +285,7 @@ def elementary_substitution(self, c, i, j, in_place=False): # CHECK THIS!!! :: - sage: M = Matrix(ZZ, 4, 4, [1,0,0,1,0,1,0,0,0,0,1,0,0,0,0,1]) - sage: M + sage: M = Matrix(ZZ, 4, 4, [1,0,0,1, 0,1,0,0, 0,0,1,0, 0,0,0,1]); M [1 0 0 1] [0 1 0 0] [0 0 1 0] @@ -310,7 +296,6 @@ def elementary_substitution(self, c, i, j, in_place=False): # CHECK THIS!!! [ * 5 6 9 ] [ * * 8 12 ] [ * * * 15 ] - """ if not in_place: Q = self.parent()(self.base_ring(), self.dim(), self.coefficients()) @@ -332,25 +317,24 @@ def elementary_substitution(self, c, i, j, in_place=False): # CHECK THIS!!! def add_symmetric(self, c, i, j, in_place=False): - """ - Performs the substitution `x_j --> x_j + c*x_i`, which has the + r""" + Perform the substitution `x_j \longmapsto x_j + c\cdot x_i`, which has the effect (on associated matrices) of symmetrically adding - `c * j`-th row/column to the `i`-th row/column. + `c` times the `j`-th row/column to the `i`-th row/column. NOTE: This is meant for compatibility with previous code, which implemented a matrix model for this class. It is used - in the local_normal_form() method. - + in the method :meth:`local_normal_form`. INPUT: - - `c` -- an element of Q.base_ring() + - ``c`` -- an element of ``self.base_ring()`` - - `i`, `j` -- integers >= 0 + - ``i``, ``j`` -- integers `\geq 0` OUTPUT: - a QuadraticForm (by default, otherwise none) + a :class:`QuadraticForm` (by default, otherwise none) EXAMPLES:: @@ -367,7 +351,8 @@ def add_symmetric(self, c, i, j, in_place=False): sage: Q.add_symmetric(-3/2, 2, 0) # ERROR: -3/2 isn't in the base ring ZZ Traceback (most recent call last): ... - RuntimeError: this coefficient cannot be coerced to an element of the base ring for the quadratic form + RuntimeError: this coefficient cannot be coerced + to an element of the base ring for the quadratic form :: diff --git a/src/sage/quadratic_forms/random_quadraticform.py b/src/sage/quadratic_forms/random_quadraticform.py index 368de819740..aa6a069a8b5 100644 --- a/src/sage/quadratic_forms/random_quadraticform.py +++ b/src/sage/quadratic_forms/random_quadraticform.py @@ -23,14 +23,12 @@ def random_quadraticform(R, n, rand_arg_list=[]): INPUT: - - `R` -- a ring. - - `n` -- an integer `\ge 0` + - ``R`` -- a ring + - ``n`` -- an integer `\ge 0` - ``rand_arg_list`` -- a list of at most 3 arguments which can be taken by ``R.random_element()``. - OUTPUT: - - A quadratic form over the ring `R`. + OUTPUT: A quadratic form over the ring `R`. EXAMPLES:: @@ -134,9 +132,7 @@ def random_ternaryqf(rand_arg_list=[]): - ``rand_arg_list`` -- a list of at most 3 arguments which can be taken by ``R.random_element()``. - OUTPUT: - - A ternary quadratic form. + OUTPUT: A ternary quadratic form. EXAMPLES:: diff --git a/src/sage/quadratic_forms/special_values.py b/src/sage/quadratic_forms/special_values.py index 4d3ef49d437..8374ab845dd 100644 --- a/src/sage/quadratic_forms/special_values.py +++ b/src/sage/quadratic_forms/special_values.py @@ -13,13 +13,11 @@ factorial, fundamental_discriminant, kronecker as kronecker_symbol) -from sage.combinat.combinat import bernoulli_polynomial from sage.misc.functional import denominator from sage.rings.infinity import infinity from sage.rings.integer_ring import ZZ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.rational_field import QQ -from sage.symbolic.constants import pi, I # ---------------- The Gamma Function ------------------ @@ -40,22 +38,22 @@ def gamma__exact(n): sage: gamma__exact(1) 1 - sage: gamma__exact(1/2) + sage: gamma__exact(1/2) # optional - sage.symbolic sqrt(pi) - sage: gamma__exact(3/2) + sage: gamma__exact(3/2) # optional - sage.symbolic 1/2*sqrt(pi) - sage: gamma__exact(5/2) + sage: gamma__exact(5/2) # optional - sage.symbolic 3/4*sqrt(pi) - sage: gamma__exact(7/2) + sage: gamma__exact(7/2) # optional - sage.symbolic 15/8*sqrt(pi) - sage: gamma__exact(-1/2) + sage: gamma__exact(-1/2) # optional - sage.symbolic -2*sqrt(pi) - sage: gamma__exact(-3/2) + sage: gamma__exact(-3/2) # optional - sage.symbolic 4/3*sqrt(pi) - sage: gamma__exact(-5/2) + sage: gamma__exact(-5/2) # optional - sage.symbolic -8/15*sqrt(pi) - sage: gamma__exact(-7/2) + sage: gamma__exact(-7/2) # optional - sage.symbolic 16/105*sqrt(pi) TESTS:: @@ -65,15 +63,18 @@ def gamma__exact(n): ... TypeError: you must give an integer or half-integer argument """ - from sage.misc.functional import sqrt n = QQ(n) if denominator(n) == 1: if n <= 0: return infinity return factorial(n - 1) - elif denominator(n) == 2: + + if denominator(n) == 2: # now n = 1/2 + an integer + from sage.misc.functional import sqrt + from sage.symbolic.constants import pi + ans = QQ.one() while n != QQ((1, 2)): if n < 0: @@ -85,14 +86,14 @@ def gamma__exact(n): ans *= sqrt(pi) return ans - else: - raise TypeError("you must give an integer or half-integer argument") + + raise TypeError("you must give an integer or half-integer argument") # ------------- The Riemann Zeta Function -------------- def zeta__exact(n): r""" - Returns the exact value of the Riemann Zeta function + Return the exact value of the Riemann Zeta function The argument must be a critical value, namely either positive even or negative odd. @@ -118,12 +119,12 @@ def zeta__exact(n): Let us test the accuracy for positive special values:: - sage: all(abs(RR(zeta__exact(2*i))-zeta(RR(2*i))) < 10**(-28) for i in range(1,10)) + sage: all(abs(RR(zeta__exact(2*i)) - zeta(RR(2*i))) < 10**(-28) for i in range(1,10)) True TESTS:: - sage: zeta__exact(4) + sage: zeta__exact(4) # optional - sage.symbolic 1/90*pi^4 sage: zeta__exact(-3) 1/120 @@ -144,6 +145,8 @@ def zeta__exact(n): return bernoulli(1-n)/(n-1) elif n > 1: if (n % 2 == 0): + from sage.symbolic.constants import pi + return ZZ(-1)**(n//2 + 1) * ZZ(2)**(n-1) * pi**n * bernoulli(n) / factorial(n) else: raise TypeError("n must be a critical value (i.e. even > 0 or odd < 0)") @@ -163,18 +166,23 @@ def QuadraticBernoulliNumber(k, d): Let us create a list of some odd negative fundamental discriminants:: - sage: test_set = [d for d in srange(-163, -3, 4) if d.is_fundamental_discriminant()] + sage: test_set = [d for d in srange(-163, -3, 4) # optional - sage.libs.pari + ....: if d.is_fundamental_discriminant()] In general, we have `B_{1, \chi_d} = -2 h/w` for odd negative fundamental discriminants:: - sage: all(QuadraticBernoulliNumber(1, d) == -len(BinaryQF_reduced_representatives(d)) for d in test_set) + sage: all(QuadraticBernoulliNumber(1, d) # optional - sage.libs.pari + ....: == -len(BinaryQF_reduced_representatives(d)) + ....: for d in test_set) True REFERENCES: - [Iwa1972]_, pp 7-16. """ + from sage.combinat.combinat import bernoulli_polynomial + # Ensure the character is primitive d1 = fundamental_discriminant(d) f = abs(d1) @@ -189,25 +197,26 @@ def QuadraticBernoulliNumber(k, d): return total + def quadratic_L_function__exact(n, d): r""" - Returns the exact value of a quadratic twist of the Riemann Zeta function + Return the exact value of a quadratic twist of the Riemann Zeta function by `\chi_d(x) = \left(\frac{d}{x}\right)`. The input `n` must be a critical value. EXAMPLES:: - sage: quadratic_L_function__exact(1, -4) + sage: quadratic_L_function__exact(1, -4) # optional - sage.libs.pari sage.symbolic 1/4*pi - sage: quadratic_L_function__exact(-4, -4) + sage: quadratic_L_function__exact(-4, -4) # optional - sage.libs.pari 5/2 - sage: quadratic_L_function__exact(2, 1) + sage: quadratic_L_function__exact(2, 1) # optional - sage.libs.pari sage.symbolic 1/6*pi^2 TESTS:: - sage: quadratic_L_function__exact(2, -4) + sage: quadratic_L_function__exact(2, -4) # optional - sage.libs.pari Traceback (most recent call last): ... TypeError: n must be a critical value (i.e. odd > 0 or even <= 0) @@ -218,8 +227,6 @@ def quadratic_L_function__exact(n, d): - [IR1990]_ - [Was1997]_ """ - from sage.symbolic.ring import SR - from sage.misc.functional import sqrt if n <= 0: return QuadraticBernoulliNumber(1-n,d)/(n-1) elif n >= 1: @@ -231,6 +238,10 @@ def quadratic_L_function__exact(n, d): # Compute the positive special values (p17) if ((n - delta) % 2 == 0): + from sage.misc.functional import sqrt + from sage.symbolic.constants import I, pi + from sage.symbolic.ring import SR + f = abs(fundamental_discriminant(d)) if delta == 0: GS = sqrt(f) @@ -260,7 +271,9 @@ def quadratic_L_function__numerical(n, d, num_terms=1000): sage: RR = RealField(100) sage: for i in range(5): - ....: print("L({}, (-4/.)): {}".format(1+2*i, RR(quadratic_L_function__exact(1+2*i, -4)) - quadratic_L_function__numerical(RR(1+2*i),-4, 10000))) + ....: print("L({}, (-4/.)): {}".format(1+2*i, + ....: RR(quadratic_L_function__exact(1+2*i, -4)) + ....: - quadratic_L_function__numerical(RR(1+2*i), -4, 10000))) L(1, (-4/.)): 0.000049999999500000024999996962707 L(3, (-4/.)): 4.99999970000003...e-13 L(5, (-4/.)): 4.99999922759382...e-21 @@ -270,7 +283,7 @@ def quadratic_L_function__numerical(n, d, num_terms=1000): This procedure fails for negative special values, as the Dirichlet series does not converge here:: - sage: quadratic_L_function__numerical(-3,-4, 10000) + sage: quadratic_L_function__numerical(-3, -4, 10000) Traceback (most recent call last): ... ValueError: the Dirichlet series does not converge here @@ -279,8 +292,11 @@ def quadratic_L_function__numerical(n, d, num_terms=1000): value, to a given accuracy :: sage: for d in range(-20,0): # long time (2s on sage.math 2014) - ....: if abs(RR(quadratic_L_function__numerical(1, d, 10000) - quadratic_L_function__exact(1, d))) > 0.001: - ....: print("We have a problem at d = {}: exact = {}, numerical = {}".format(d, RR(quadratic_L_function__exact(1, d)), RR(quadratic_L_function__numerical(1, d)))) + ....: if abs(RR(quadratic_L_function__numerical(1, d, 10000) + ....: - quadratic_L_function__exact(1, d))) > 0.001: + ....: print("We have a problem at d = {}: exact = {}, numerical = {}".format(d, + ....: RR(quadratic_L_function__exact(1, d)), + ....: RR(quadratic_L_function__numerical(1, d)))) """ # Set the correct precision if it is given (for n). if isinstance(n.parent(), sage.rings.abc.RealField): diff --git a/src/sage/quadratic_forms/ternary.pyx b/src/sage/quadratic_forms/ternary.pyx index 727b31ce080..a0c86f7c7cb 100644 --- a/src/sage/quadratic_forms/ternary.pyx +++ b/src/sage/quadratic_forms/ternary.pyx @@ -23,15 +23,13 @@ from sage.rings.integer_ring import ZZ def red_mfact(a,b): """ - Auxiliary function for reduction that finds the reduction factor of a, b integers. + Auxiliary function for reduction that finds the reduction factor of integers `a`, `b`. INPUT: - - a, b integers + - ``a``, ``b`` -- integers - OUTPUT: - - Integer + OUTPUT: Integer EXAMPLES:: @@ -40,7 +38,6 @@ def red_mfact(a,b): 0 sage: red_mfact(-5, 100) 9 - """ if a: @@ -422,7 +419,7 @@ def _reduced_ternary_form_eisenstein_without_matrix(a1, a2, a3, a23, a13, a12): def primitivize(long long v0, long long v1, long long v2, p): """ - Given a 3-tuple v not singular mod p, it returns a primitive 3-tuple version of v mod p. + Given a 3-tuple `v` not singular mod `p`, return a primitive 3-tuple version of `v` mod `p`. EXAMPLES:: @@ -431,7 +428,6 @@ def primitivize(long long v0, long long v1, long long v2, p): (3, 2, 1) sage: primitivize(12, 13, 15, 5) (4, 1, 0) - """ if v2%p != 0: @@ -444,7 +440,7 @@ def primitivize(long long v0, long long v1, long long v2, p): def evaluate(a, b, c, r, s, t, v): """ - Function to evaluate the ternary quadratic form (a, b, c, r, s, t) in a 3-tuple v. + Function to evaluate the ternary quadratic form `(a, b, c, r, s, t)` in a 3-tuple `v`. EXAMPLES:: @@ -455,7 +451,6 @@ def evaluate(a, b, c, r, s, t, v): 1105 sage: evaluate(1, 2, 3, -1, 0, 0, v) 1105 - """ return a*v[0]**2+b*v[1]**2+c*v[2]**2+r*v[2]*v[1]+s*v[2]*v[0]+t*v[1]*v[0] @@ -497,18 +492,18 @@ def _find_zeros_mod_p_2(a, b, c, r, s, t): def pseudorandom_primitive_zero_mod_p(a, b, c, r, s, t, p): """ - Find a zero of the form (a, b, 1) of the ternary quadratic form given by the coefficients (a, b, c, r, s, t) - mod p, where p is a odd prime that doesn't divide the discriminant. + Find a zero of the form `(a, b, 1)` of the ternary quadratic form given by the coefficients `(a, b, c, r, s, t)` + mod `p`, where `p` is a odd prime that doesn't divide the discriminant. EXAMPLES:: sage: Q = TernaryQF([1, 2, 2, -1, 0, 0]) sage: p = 1009 sage: from sage.quadratic_forms.ternary import pseudorandom_primitive_zero_mod_p - sage: v = pseudorandom_primitive_zero_mod_p(1, 2, 2, -1, 0, 0, p) - sage: v[2] + sage: v = pseudorandom_primitive_zero_mod_p(1, 2, 2, -1, 0, 0, p) # optional - sage.libs.pari + sage: v[2] # optional - sage.libs.pari 1 - sage: Q(v)%p + sage: Q(v)%p # optional - sage.libs.pari 0 """ @@ -532,9 +527,9 @@ def pseudorandom_primitive_zero_mod_p(a, b, c, r, s, t, p): def _find_zeros_mod_p_odd(long long a, long long b, long long c, long long r, long long s, long long t, long long p, v): """ - Find the zeros mod p, where p is an odd prime, of a ternary quadratic form given by its coefficients and a given zero of the form v. + Find the zeros mod `p`, where `p` is an odd prime, of a ternary quadratic form given by its coefficients and a given zero of the form `v`. - The prime p does not divide the discriminant of the form. + The prime `p` does not divide the discriminant of the form. EXAMPLES:: @@ -605,7 +600,7 @@ def _find_zeros_mod_p(a, b, c, r, s, t, p): """ Find the zeros mod `p` of the ternary quadratic form. - The quadratic form is given by the coefficients (a, b, c, r, s, t), + The quadratic form is given by the coefficients `(a, b, c, r, s, t)`, and `p` is a prime that does not divide the discriminant of the form. EXAMPLES:: @@ -613,16 +608,16 @@ def _find_zeros_mod_p(a, b, c, r, s, t, p): sage: from sage.quadratic_forms.ternary import _find_zeros_mod_p sage: Q = TernaryQF([1, 2, 2, -1, 0, 0]) sage: p = 1009 - sage: zeros_1009 = _find_zeros_mod_p(1, 2, 2, -1, 0, 0, p) - sage: len(zeros_1009) + sage: zeros_1009 = _find_zeros_mod_p(1, 2, 2, -1, 0, 0, p) # optional - sage.libs.pari + sage: len(zeros_1009) # optional - sage.libs.pari 1010 - sage: zeros_1009.sort() - sage: zeros_1009[0] + sage: zeros_1009.sort() # optional - sage.libs.pari + sage: zeros_1009[0] # optional - sage.libs.pari (0, 32, 1) sage: Q((0, 32, 1)) 2018 - sage: zeros_2 = _find_zeros_mod_p(1, 2, 2, -1, 0, 0, 2) - sage: zeros_2 + sage: zeros_2 = _find_zeros_mod_p(1, 2, 2, -1, 0, 0, 2) # optional - sage.libs.pari + sage: zeros_2 # optional - sage.libs.pari [(0, 1, 0), (0, 0, 1), (1, 1, 1)] """ @@ -919,7 +914,7 @@ def _find_a_ternary_qf_by_level_disc(long long N, long long d): def extend(v): """ - Return the coefficients of a matrix M such that M has determinant gcd(v) and the first column is v. + Return the coefficients of a matrix `M` such that `M` has determinant gcd(`v`) and the first column is `v`. EXAMPLES:: @@ -975,9 +970,9 @@ def _find_p_neighbor_from_vec(a, b, c, r, s, t, p, v, mat = False): sage: Q.disc() 29 sage: v = (9, 7, 1) - sage: v in Q.find_zeros_mod_p(11) + sage: v in Q.find_zeros_mod_p(11) # optional - sage.libs.pari True - sage: q11, M = _find_p_neighbor_from_vec(1, 3, 3, -2, 0, -1, 11, v, mat = True) + sage: q11, M = _find_p_neighbor_from_vec(1, 3, 3, -2, 0, -1, 11, v, mat=True) sage: Q11 = TernaryQF(q11) sage: Q11 Ternary quadratic form with integer coefficients: diff --git a/src/sage/quadratic_forms/ternary_qf.py b/src/sage/quadratic_forms/ternary_qf.py index bb98b11cb30..ce74661ffdd 100644 --- a/src/sage/quadratic_forms/ternary_qf.py +++ b/src/sage/quadratic_forms/ternary_qf.py @@ -1,4 +1,4 @@ -""" +r""" Ternary quadratic form with integer coefficients AUTHOR: @@ -7,7 +7,7 @@ Based in code of Gonzalo Tornaria -The form `a*x^2 + b*y^2 + c*z^2 + r*yz + s*xz + t*xy` is stored as a tuple (a, b, c, r, s, t) of integers. +The form `a\cdot x^2 + b\cdot y^2 + c\cdot z^2 + r\cdot yz + s\cdot xz + t\cdot xy` is stored as a tuple ``(a, b, c, r, s, t)`` of integers. """ @@ -48,21 +48,20 @@ class TernaryQF(SageObject): - """ - The ``TernaryQF`` class represents a quadratic form in 3 variables with coefficients in Z. + r""" + The ``TernaryQF`` class represents a quadratic form in 3 variables with coefficients in `\ZZ`. INPUT: - - `v` -- a list or tuple of 6 entries: [a,b,c,r,s,t] + - ``v`` -- a list or tuple of 6 entries: ``[a,b,c,r,s,t]`` OUTPUT: - - the ternary quadratic form a*x^2 + b*y^2 + c*z^2 + r*y*z + s*x*z + t*x*y. + - the ternary quadratic form `a\cdot x^2 + b\cdot y^2 + c\cdot z^2 + r\cdot y\cdot z + s\cdot x\cdot z + t\cdot x\cdot y`. EXAMPLES:: - sage: Q = TernaryQF([1, 2, 3, 4, 5, 6]) - sage: Q + sage: Q = TernaryQF([1, 2, 3, 4, 5, 6]); Q Ternary quadratic form with integer coefficients: [1 2 3] [4 5 6] @@ -72,8 +71,6 @@ class TernaryQF(SageObject): [1 187 9] [-85 8 -31] sage: TestSuite(TernaryQF).run() - - """ __slots__ = ['_a', '_b', '_c', '_r', '_s', '_t', '_automorphisms', '_number_of_automorphisms'] @@ -82,17 +79,16 @@ class TernaryQF(SageObject): def __init__(self, v): r""" - Creates the ternary quadratic form `a*x^2 + b*y^2 + c*z^2 + r*y*z + s*x*z + t*x*y.` from the - tuple v=[a,b,c,r,s,t] over `\ZZ`. + Create the ternary quadratic form `a\cdot x^2 + b\cdot y^2 + c\cdot z^2 + r\cdot y\cdot z + s\cdot x\cdot z + t\cdot x\cdot y` from the + tuple ``v=[a,b,c,r,s,t]`` over `\ZZ`. INPUT: - - ``v`` -- 6-tuple of integers + - ``v`` -- 6-tuple of integers EXAMPLES:: - sage: Q = TernaryQF([1, 2, 3, 4, 5, 6]) - sage: Q + sage: Q = TernaryQF([1, 2, 3, 4, 5, 6]); Q Ternary quadratic form with integer coefficients: [1 2 3] [4 5 6] @@ -106,30 +102,31 @@ def __init__(self, v): self._number_of_automorphisms = None def coefficients(self): - """ - Return the list coefficients of the ternary quadratic form. + r""" + Return the list of coefficients of the ternary quadratic form. EXAMPLES:: - sage: Q = TernaryQF([1, 2, 3, 4, 5, 6]) - sage: Q + sage: Q = TernaryQF([1, 2, 3, 4, 5, 6]); Q Ternary quadratic form with integer coefficients: [1 2 3] [4 5 6] sage: Q.coefficients() (1, 2, 3, 4, 5, 6) - """ return self._a, self._b, self._c, self._r, self._s, self._t def coefficient(self, n): - """ - Return the n-th coefficient of the ternary quadratic form, with 0<=n<=5. + r""" + Return the `n`-th coefficient of the ternary quadratic form. + + INPUT: + + - ``n`` -- integer with `0 \leq n \leq 5`. EXAMPLES:: - sage: Q = TernaryQF([1, 2, 3, 4, 5, 6]) - sage: Q + sage: Q = TernaryQF([1, 2, 3, 4, 5, 6]); Q Ternary quadratic form with integer coefficients: [1 2 3] [4 5 6] @@ -141,28 +138,25 @@ def coefficient(self, n): return self.coefficients()[n] def polynomial(self, names='x,y,z'): - """ + r""" Return the polynomial associated to the ternary quadratic form. EXAMPLES:: - sage: Q = TernaryQF([1, 1, 0, 2, -3, -1]) - sage: Q + sage: Q = TernaryQF([1, 1, 0, 2, -3, -1]); Q Ternary quadratic form with integer coefficients: [1 1 0] [2 -3 -1] - sage: p = Q.polynomial() - sage: p + sage: p = Q.polynomial(); p x^2 - x*y + y^2 - 3*x*z + 2*y*z sage: p.parent() Multivariate Polynomial Ring in x, y, z over Integer Ring - """ (x,y,z) = polygens(ZZ,names) return self._a * x**2 + self._b* y**2 + self._c * z**2 + self._t * x*y + self._s * x*z + self._r * y*z def _repr_(self): - """ + r""" Display the quadratic form. EXAMPLES:: @@ -183,12 +177,20 @@ def _repr_(self): return rep def __call__(self, v): - """ - Evaluate this ternary quadratic form Q on a vector of 3 elements, or matrix of elements in Z, with 3 rows. If a vector is given then the output will be an integer Q(`v`), but if a matrix is given the output will be a ternary quadratic form if the matrix has 3 columns, or a quadratic form if not. The quadratic form in matrix notation will be: + r""" + Evaluate this ternary quadratic form `Q` on a vector of 3 elements, + or matrix of elements in Z, with 3 rows. + + OUTPUT: + + If a vector is given, then the output will be an integer `Q(v)`, + but if a matrix is given, the output will be a ternary quadratic form + if the matrix has 3 columns, or a quadratic form if not. + The quadratic form in matrix notation will be: .. MATH:: - Q' = v^t * Q * v. + Q' = v^t\cdot Q\cdot v. EXAMPLES:: @@ -231,14 +233,13 @@ def __call__(self, v): raise TypeError("presently we can only evaluate a quadratic form on a list, tuple, vector or matrix") def quadratic_form(self): - """ - Return the object QuadraticForm with the same coefficients as Q over ZZ. + r""" + Return a :class:`QuadraticForm` with the same coefficients as ``self`` over `\ZZ`. EXAMPLES:: sage: Q = TernaryQF([1, 2, 3, 1, 1, 1]) - sage: QF1 = Q.quadratic_form() - sage: QF1 + sage: QF1 = Q.quadratic_form(); QF1 Quadratic form in 3 variables over Integer Ring with coefficients: [ 1 1 1 ] [ * 2 1 ] @@ -250,25 +251,23 @@ def quadratic_form(self): return QuadraticForm(ZZ, 3, [self._a, self._t, self._s, self._b, self._r, self._c]) def matrix(self): - """ + r""" Return the Hessian matrix associated to the ternary quadratic form. - That is, if Q is a ternary quadratic form, Q(x,y,z) = a*x^2 + b*y^2 + c*z^2 + r*y*z + s*x*z + t*x*y, - then the Hessian matrix associated to Q is + That is, if `Q` is a ternary quadratic form, `Q(x,y,z) = a\cdot x^2 + b\cdot y^2 + c\cdot z^2 + r\cdot y\cdot z + s\cdot x\cdot z + t\cdot x\cdot y`, + then the Hessian matrix associated to `Q` is :: - [2*a t s] - [t 2*b r] - [s r 2*c] + [2\cdot a t s] + [t 2\cdot b r] + [s r 2\cdot c] EXAMPLES:: - sage: Q = TernaryQF([1,1,2,0,-1,4]) - sage: Q + sage: Q = TernaryQF([1,1,2,0,-1,4]); Q Ternary quadratic form with integer coefficients: [1 1 2] [0 -1 4] - sage: M = Q.matrix() - sage: M + sage: M = Q.matrix(); M [ 2 4 -1] [ 4 2 0] [-1 0 4] @@ -282,7 +281,7 @@ def matrix(self): return M def disc(self): - """ + r""" Return the discriminant of the ternary quadratic form, this is the determinant of the matrix divided by 2. EXAMPLES:: @@ -417,8 +416,7 @@ def __neg__(self): EXAMPLES:: - sage: Q = TernaryQF([1, 1, 2, -2, 0, -1]) - sage: Q + sage: Q = TernaryQF([1, 1, 2, -2, 0, -1]); Q Ternary quadratic form with integer coefficients: [1 1 2] [-2 0 -1] @@ -427,7 +425,7 @@ def __neg__(self): [-1 -1 -2] [2 0 1] sage: Q = TernaryQF([0, 0, 0, 0, 0, 0]) - sage: Q==-Q + sage: Q == -Q True """ return TernaryQF([-a for a in self.coefficients()]) @@ -481,7 +479,12 @@ def primitive(self): def scale_by_factor(self, k): """ - Scale the values of the ternary quadratic form by the number c, if c times the content of the ternary quadratic form is an integer it returns a ternary quadratic form, otherwise returns a quadratic form of dimension 3. + Scale the values of the ternary quadratic form by the number ``k``. + + OUTPUT: + + If ``k`` times the content of the ternary quadratic form is an integer, return a ternary quadratic form; + otherwise, return a quadratic form of dimension 3. EXAMPLES:: @@ -548,15 +551,14 @@ def reciprocal_reduced(self): EXAMPLES:: sage: Q = TernaryQF([1, 1, 3, 0, -1, 0]) - sage: Qrr = Q.reciprocal_reduced() - sage: Qrr + sage: Qrr = Q.reciprocal_reduced(); Qrr Ternary quadratic form with integer coefficients: [4 11 12] [0 -4 0] sage: Q.is_eisenstein_reduced() True sage: Qr = Q.reciprocal() - sage: Qr.reduced_form_eisenstein(matrix = False) == Qrr + sage: Qr.reduced_form_eisenstein(matrix=False) == Qrr True """ return self.reciprocal().reduced_form_eisenstein(matrix=False) @@ -690,7 +692,7 @@ def level(self): return 4 * self.disc() // self.divisor() def is_eisenstein_reduced(self) -> bool: - """ + r""" Determine if the ternary quadratic form is Eisenstein reduced. That is, if we have a ternary quadratic form: @@ -701,16 +703,14 @@ def is_eisenstein_reduced(self) -> bool: then - :: - - 1- a<=b<=c; - 2- r, s, and t are all positive or all nonpositive; - 3- a>=|t|; a>=|s|; b>=|r|; - 4- a+b+r+s+t>=0; - 5- a=t implies s<=2*r; a=s implies t<=2*r; b=r implies t<=2*s; - 6- a=-t implies s=0; a=-s implies t=0; b=-r implies t=0; - 7- a+b+r+s+t=0 implies 2*a+2*s+t<=0; - 8- a=b implies |r|<=|s|; b=c implies |s|<=|t|. + 1. `a \leq b \leq c`; + 2. `r`, `s`, and `t` are all positive or all nonpositive; + 3. `a \geq |t|`; `a \geq |s|`; `b \geq |r|`; + 4. `a+b+r+s+t \geq 0`; + 5. `a=t` implies `s \leq 2\cdot r`; `a=s` implies `t \leq 2\cdot r`; `b=r` implies `t \leq 2\cdot s`; + 6. `a=-t` implies `s=0`; `a=-s` implies `t=0`; `b=-r` implies `t=0`; + 7. `a+b+r+s+t = 0` implies `2\cdot a+2\cdot s+t \leq 0`; + 8. `a=b` implies `|r| \leq |s|`; `b=c` implies `|s| \leq |t|`. EXAMPLES:: @@ -766,7 +766,7 @@ def is_eisenstein_reduced(self) -> bool: return True def reduced_form_eisenstein(self, matrix=True): - """ + r""" Return the Eisenstein reduced form equivalent to the given positive ternary quadratic form, which is unique. @@ -803,8 +803,8 @@ def reduced_form_eisenstein(self, matrix=True): def pseudorandom_primitive_zero_mod_p(self, p): """ - Return a tuple of the form v = (a, b, 1) such that is a zero of the given ternary quadratic - positive definite form modulo an odd prime p, where p doesn't divides the discriminant of the form. + Return a tuple of the form `v = (a, b, 1)` such that is a zero of the given ternary quadratic + positive definite form modulo an odd prime `p`, where `p` doesn't divides the discriminant of the form. EXAMPLES:: @@ -815,10 +815,10 @@ def pseudorandom_primitive_zero_mod_p(self, p): (1, 2, 1) sage: Q((1, 2, 1)) 15 - sage: v = Q.pseudorandom_primitive_zero_mod_p(1009) - sage: Q(v) % 1009 + sage: v = Q.pseudorandom_primitive_zero_mod_p(1009) # optional - sage.libs.pari + sage: Q(v) % 1009 # optional - sage.libs.pari 0 - sage: v[2] + sage: v[2] # optional - sage.libs.pari 1 """ [a,b,c,r,s,t] = self.coefficients() @@ -840,7 +840,7 @@ def pseudorandom_primitive_zero_mod_p(self, p): def find_zeros_mod_p(self, p): """ - Find the zeros of the given ternary quadratic positive definite form modulo a prime p, where p doesn't divides the discriminant of the form. + Find the zeros of the given ternary quadratic positive definite form modulo a prime `p`, where `p` doesn't divide the discriminant of the form. EXAMPLES:: @@ -851,13 +851,11 @@ def find_zeros_mod_p(self, p): 3 * 13 * 19 sage: Q.find_zeros_mod_p(2) [(1, 0, 0), (1, 1, 0), (0, 0, 1)] - sage: zeros_17 = Q.find_zeros_mod_p(17) - sage: len(zeros_17) + sage: zeros_17 = Q.find_zeros_mod_p(17) # optional - sage.libs.pari + sage: len(zeros_17) # optional - sage.libs.pari 18 - sage: [Q(v)%17 for v in zeros_17] + sage: [Q(v)%17 for v in zeros_17] # optional - sage.libs.pari [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] - - """ if p==2: @@ -871,38 +869,39 @@ def find_zeros_mod_p(self, p): return _find_zeros_mod_p_odd(a, b, c, r, s, t, p, v) def find_p_neighbor_from_vec(self, p, v, mat=False): - """ - Finds the reduced equivalent of the p-neighbor of this ternary quadratic form associated to a given - vector v satisfying: + r""" + Finds the reduced equivalent of the `p`-neighbor of this ternary quadratic form associated to a given + vector `v` satisfying: + + 1. `Q(v) = 0` (mod `p`) - 1. Q(v) = 0 mod p + 2. `v` is a non-singular point of the conic `Q(v) = 0` (mod `p`). - 2. v is a non-singular point of the conic Q(v) = 0 mod p. + REFERENCES: - Reference: Gonzalo Tornaria's Thesis, Thrm 3.5, p34. + Gonzalo Tornaria's Thesis, Thrm 3.5, p34. EXAMPLES:: - sage: Q = TernaryQF([1, 3, 3, -2, 0, -1]) - sage: Q + sage: Q = TernaryQF([1, 3, 3, -2, 0, -1]); Q Ternary quadratic form with integer coefficients: [1 3 3] [-2 0 -1] sage: Q.disc() 29 sage: v = (9, 7, 1) - sage: v in Q.find_zeros_mod_p(11) + sage: v in Q.find_zeros_mod_p(11) # optional - sage.libs.pari True - sage: Q11, M = Q.find_p_neighbor_from_vec(11, v, mat = True) - sage: Q11 + sage: Q11, M = Q.find_p_neighbor_from_vec(11, v, mat=True) # optional - sage.libs.pari + sage: Q11 # optional - sage.libs.pari Ternary quadratic form with integer coefficients: [1 2 4] [-1 -1 0] - sage: M + sage: M # optional - sage.libs.pari [ -1 -5/11 7/11] [ 0 -10/11 3/11] [ 0 -3/11 13/11] - sage: Q(M) == Q11 + sage: Q(M) == Q11 # optional - sage.libs.pari True """ if mat: @@ -914,8 +913,8 @@ def find_p_neighbor_from_vec(self, p, v, mat=False): def find_p_neighbors(self, p, mat=False): """ - Find a list with all the reduced equivalent of the p-neighbors of this ternary quadratic form, given by the zeros mod p of the form. - See find_p_neighbor_from_vec for more information. + Find a list with all the reduced equivalent of the `p`-neighbors of this ternary quadratic form, given by the zeros mod `p` of the form. + See :meth:`find_p_neighbor_from_vec` for more information. EXAMPLES:: @@ -924,16 +923,16 @@ def find_p_neighbors(self, p, mat=False): Ternary quadratic form with integer coefficients: [1 3 3] [-2 0 -1] - sage: neig = Q0.find_p_neighbors(5) - sage: len(neig) + sage: neig = Q0.find_p_neighbors(5) # optional - sage.libs.pari + sage: len(neig) # optional - sage.libs.pari 6 sage: Q1 = TernaryQF([1, 1, 10, 1, 1, 1]) sage: Q2 = TernaryQF([1, 2, 4, -1, -1, 0]) - sage: neig.count(Q0) + sage: neig.count(Q0) # optional - sage.libs.pari 2 - sage: neig.count(Q1) + sage: neig.count(Q1) # optional - sage.libs.pari 1 - sage: neig.count(Q2) + sage: neig.count(Q2) # optional - sage.libs.pari 3 """ @@ -943,7 +942,7 @@ def find_p_neighbors(self, p, mat=False): def basic_lemma(self, p): """ - Finds a number represented by self and coprime to the prime p. + Find a number represented by ``self`` and coprime to the prime `p`. EXAMPLES:: @@ -957,9 +956,11 @@ def basic_lemma(self, p): def xi(self, p): """ Return the value of the genus characters Xi_p... which may be - missing one character. We allow -1 as a prime. + missing one character. We allow `-1` as a prime. - Reference: Dickson's "Studies in the Theory of Numbers" + REFERENCES: + + Dickson's "Studies in the Theory of Numbers" EXAMPLES:: @@ -1006,12 +1007,12 @@ def xi_rec(self, p): def symmetry(self, v): """ - Return A the automorphism of the ternary quadratic form such that: + Return `A`, the automorphism of the ternary quadratic form such that: - - A*v = -v. - - A*u = 0, if u is orthogonal to v. + - `Av = -v`, + - `Au = 0`, if `u` is orthogonal to `v`, - where v is a given vector. + where `v` is a given vector. EXAMPLES:: @@ -1036,15 +1037,15 @@ def symmetry(self, v): True sage: M*v2 == v2 True - - """ return identity_matrix(3) - v.column()*matrix(v)*self.matrix()/self(v) def automorphism_symmetries(self, A): """ - Given the automorphism A, returns two vectors v1, v2 if A is not the identity. Such that the product of the symmetries of the ternary quadratic form given by the two vectors is A. + Given the automorphism `A`, if `A` is the identity, return the empty list. + Otherwise, return a list of two vectors `v_1`, `v_2` such that the product of + the symmetries of the ternary quadratic form given by the two vectors is `A`. EXAMPLES:: @@ -1069,7 +1070,6 @@ def automorphism_symmetries(self, A): True sage: Q.automorphism_symmetries(identity_matrix(ZZ,3)) [] - """ if A == identity_matrix(3): @@ -1088,7 +1088,7 @@ def automorphism_symmetries(self, A): def automorphism_spin_norm(self, A): """ - Return the spin norm of the automorphism A. + Return the spin norm of the automorphism `A`. EXAMPLES:: @@ -1700,8 +1700,7 @@ def automorphisms(self, slow=True): EXAMPLES:: sage: Q = TernaryQF([1, 1, 7, 0, 0, 0]) - sage: auts = Q.automorphisms() - sage: auts + sage: auts = Q.automorphisms(); auts [ [-1 0 0] [-1 0 0] [ 0 -1 0] [ 0 -1 0] [ 0 1 0] [ 0 1 0] [ 0 -1 0] [ 0 1 0] [-1 0 0] [ 1 0 0] [-1 0 0] [ 1 0 0] @@ -1713,14 +1712,14 @@ def automorphisms(self, slow=True): sage: all(Q == Q(A) for A in auts) True sage: Q = TernaryQF([3, 4, 5, 3, 3, 2]) - sage: Q.automorphisms(slow = False) + sage: Q.automorphisms(slow=False) [ [1 0 0] [0 1 0] [0 0 1] ] sage: Q = TernaryQF([4, 2, 4, 3, -4, -5]) - sage: auts = Q.automorphisms(slow = False) + sage: auts = Q.automorphisms(slow=False) sage: auts [ [1 0 0] [ 2 -1 -1] @@ -1769,7 +1768,7 @@ def _number_of_automorphisms_reduced(self): sage: Q = TernaryQF([1, 1, 7, 0, 0, 0]) sage: Q._number_of_automorphisms_reduced() 8 - sage: len(Q.automorphisms(slow = False)) + sage: len(Q.automorphisms(slow=False)) 8 sage: Q = TernaryQF([3, 4, 5, 3, 3, 2]) sage: Q._number_of_automorphisms_reduced() @@ -1947,8 +1946,7 @@ def number_of_automorphisms(self, slow=True): sage: A = matrix(ZZ, 3, [0, 1, 0, -1, 5, 0, -8, -1, 1]) sage: A.det() 1 - sage: Q1 = Q(A) - sage: Q1 + sage: Q1 = Q(A); Q1 Ternary quadratic form with integer coefficients: [449 33 7] [-14 -112 102] @@ -1957,7 +1955,7 @@ def number_of_automorphisms(self, slow=True): sage: Q = TernaryQF([-19, -7, -6, -12, 20, 23]) sage: Q.is_negative_definite() True - sage: Q.number_of_automorphisms(slow = False) + sage: Q.number_of_automorphisms(slow=False) 24 """ if not self.is_definite(): @@ -1979,9 +1977,9 @@ def number_of_automorphisms(self, slow=True): def find_all_ternary_qf_by_level_disc(N, d): """ - Find the coefficients of all the reduced ternary quadratic forms given its discriminant d and level N. + Find the coefficients of all the reduced ternary quadratic forms given its discriminant `d` and level `N`. - If N|4d and d|N^2, then it may be some forms with that discriminant and level. + If `N|4d` and `d|N^2`, then it may be some forms with that discriminant and level. EXAMPLES:: @@ -2016,13 +2014,12 @@ def find_all_ternary_qf_by_level_disc(N, d): def find_a_ternary_qf_by_level_disc(N, d): """ - Find a reduced ternary quadratic form given its discriminant d and level N. - If N|4d and d|N^2, then it may be a form with that discriminant and level. + Find a reduced ternary quadratic form given its discriminant `d` and level `N`. + If `N|4d` and `d|N^2`, then it may be a form with that discriminant and level. EXAMPLES:: - sage: Q1 = find_a_ternary_qf_by_level_disc(44, 11) - sage: Q1 + sage: Q1 = find_a_ternary_qf_by_level_disc(44, 11); Q1 Ternary quadratic form with integer coefficients: [1 1 3] [0 -1 0] diff --git a/src/sage/rings/cfinite_sequence.py b/src/sage/rings/cfinite_sequence.py index 8681fc3f263..2c109271b5b 100644 --- a/src/sage/rings/cfinite_sequence.py +++ b/src/sage/rings/cfinite_sequence.py @@ -1233,7 +1233,7 @@ def guess(self, sequence, algorithm='sage'): return CFiniteSequence(num / den) else: from sage.matrix.constructor import matrix - from sage.functions.other import ceil + from sage.arith.misc import integer_ceil as ceil from numpy import trim_zeros seq = sequence[:] while seq and sequence[-1] == 0: diff --git a/src/sage/rings/invariants/reconstruction.py b/src/sage/rings/invariants/reconstruction.py index bde5c307ee4..99941d306b8 100644 --- a/src/sage/rings/invariants/reconstruction.py +++ b/src/sage/rings/invariants/reconstruction.py @@ -262,7 +262,7 @@ def binary_quintic_coefficients_from_invariants(invariants, K=None, invariant_ch N = K(2)**-1 * (A*C-B**2) R2 = -K(2)**-1 * (A*N**2-2*B*M*N+C*M**2) scale = [1,1,1,1,1,1] - from sage.functions.all import binomial + from sage.arith.misc import binomial from sage.misc.functional import sqrt if len(invariants) == 3: if R2.is_square(): diff --git a/src/sage/rings/padics/padic_generic_element.pyx b/src/sage/rings/padics/padic_generic_element.pyx index 09fd404df21..12c88f7186e 100644 --- a/src/sage/rings/padics/padic_generic_element.pyx +++ b/src/sage/rings/padics/padic_generic_element.pyx @@ -4085,7 +4085,7 @@ cdef class pAdicGenericElement(LocalGenericElement): ValueError: Polylogarithm only implemented for n at least 2. """ from sage.rings.power_series_ring import PowerSeriesRing - from sage.functions.other import ceil,floor + from sage.arith.misc import integer_ceil as ceil, integer_floor as floor from sage.rings.padics.factory import Qp from sage.misc.verbose import verbose @@ -4227,7 +4227,7 @@ cdef class pAdicGenericElement(LocalGenericElement): from sage.rings.power_series_ring import PowerSeriesRing from sage.rings.padics.factory import Qp from sage.misc.verbose import verbose - from sage.functions.other import ceil,floor + from sage.arith.misc import integer_ceil as ceil, integer_floor as floor from sage.rings.infinity import PlusInfinity if self.parent().absolute_degree() != 1: @@ -4376,7 +4376,8 @@ def _AHE_coefficients(p, N, prec): """ from sage.rings.padics.factory import ZpFM - from sage.functions.other import floor + from sage.arith.misc import integer_floor as floor + if N < p: internal_prec = prec else: @@ -4437,7 +4438,8 @@ def _findprec(c_1, c_2, c_3, p): See Remark 7.11 of [BdJ2008]_. """ - from sage.functions.other import ceil + from sage.arith.misc import integer_ceil as ceil + k = Integer(max(ceil(c_2/c_1), 2)) while True: if c_1*k - c_2*k.log(p).n() > c_3: @@ -4457,7 +4459,7 @@ def _compute_g(p, n, prec, terms): O(7^3)*v^2 + (1 + O(7^3))*v + O(7^3) """ from sage.rings.power_series_ring import PowerSeriesRing - from sage.functions.other import ceil + from sage.arith.misc import integer_ceil as ceil from sage.rings.padics.factory import Qp # Compute the sequence of power series g diff --git a/src/sage/rings/polynomial/polynomial_gf2x.pyx b/src/sage/rings/polynomial/polynomial_gf2x.pyx index 284e319be99..97b565e9cd0 100644 --- a/src/sage/rings/polynomial/polynomial_gf2x.pyx +++ b/src/sage/rings/polynomial/polynomial_gf2x.pyx @@ -145,7 +145,7 @@ cdef class Polynomial_GF2X(Polynomial_template): from sage.misc.misc import cputime from sage.misc.verbose import verbose - from sage.functions.all import ceil + from sage.arith.misc import integer_ceil as ceil from sage.matrix.constructor import Matrix from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF diff --git a/src/sage/schemes/plane_conics/constructor.py b/src/sage/schemes/plane_conics/constructor.py index c84e0ef5b2b..0a73422519c 100644 --- a/src/sage/schemes/plane_conics/constructor.py +++ b/src/sage/schemes/plane_conics/constructor.py @@ -26,7 +26,6 @@ from sage.matrix.constructor import Matrix from sage.modules.free_module_element import vector -from sage.quadratic_forms.quadratic_form import is_QuadraticForm from sage.rings.ring import IntegralDomain from sage.rings.rational_field import is_RationalField from sage.rings.finite_rings.finite_field_base import FiniteField @@ -198,7 +197,10 @@ def Conic(base_field, F=None, names=None, unique=True): F[3] * y**2 + F[4] * y * z + F[5] * z**2) raise TypeError("F (=%s) must be a sequence of 3 or 6" "coefficients" % F) - if is_QuadraticForm(F): + + from sage.quadratic_forms.quadratic_form import QuadraticForm + + if isinstance(F, QuadraticForm): F = F.matrix() if is_Matrix(F) and F.is_square() and F.ncols() == 3: if names is None: