From 27c60d767b60ba132ed942eb5113009ee624e5ab Mon Sep 17 00:00:00 2001 From: Enrique Artal Date: Wed, 20 Sep 2023 16:17:12 +0200 Subject: [PATCH 01/45] add is_noetherian and divides, for univariate --- src/sage/rings/polynomial/laurent_polynomial.pyx | 6 ++++++ src/sage/rings/polynomial/laurent_polynomial_ring_base.py | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/sage/rings/polynomial/laurent_polynomial.pyx b/src/sage/rings/polynomial/laurent_polynomial.pyx index cd79996eed7..61ba3870357 100644 --- a/src/sage/rings/polynomial/laurent_polynomial.pyx +++ b/src/sage/rings/polynomial/laurent_polynomial.pyx @@ -1969,3 +1969,9 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): 0 """ return self.__u[-self.__n] + + def divides(self, other): + R = self.parent().polynomial_ring() + p = R(self.polynomial_construction()[0]) + q = R(other.polynomial_construction()[0]) + return p.divides(q) diff --git a/src/sage/rings/polynomial/laurent_polynomial_ring_base.py b/src/sage/rings/polynomial/laurent_polynomial_ring_base.py index 0c9022c492c..f160502d43f 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_ring_base.py +++ b/src/sage/rings/polynomial/laurent_polynomial_ring_base.py @@ -166,7 +166,7 @@ def is_noetherian(self): ... NotImplementedError """ - raise NotImplementedError + return self.base_ring().is_noetherian() def construction(self): """ From e4e3ced9931b4f1a34f4dbf55da90fc55b8e08bd Mon Sep 17 00:00:00 2001 From: Enrique Artal Date: Wed, 20 Sep 2023 23:17:32 +0200 Subject: [PATCH 02/45] . --- .../polynomial/laurent_polynomial_mpair.pyx | 53 +++++++++++++++---- 1 file changed, 44 insertions(+), 9 deletions(-) diff --git a/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx b/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx index 5db2df9dbbd..2e846ed7a53 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx +++ b/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx @@ -113,16 +113,16 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial): if isinstance(k, tuple): k = ETuple(k) D[k] = x_k - self._mon = self._mon.emin(k) # point-wise min of _mon and k + self._mon = self._mon.emin(k) # point-wise min of _mon and k else: x = D - if not self._mon.is_constant(): # factor out _mon + if not self._mon.is_constant(): # factor out _mon x = {k.esub(self._mon): x_k for k, x_k in x.iteritems()} elif (isinstance(x, LaurentPolynomial_mpair) and parent.variable_names() == x.parent().variable_names()): self._mon = (x)._mon x = (x)._poly - else: # since x should coerce into parent, _mon should be (0,...,0) + else: # since x should coerce into parent, _mon should be (0,...,0) self._mon = ETuple({}, int(parent.ngens())) self._poly = parent._R(x) CommutativeAlgebraElement.__init__(self, parent) @@ -275,7 +275,7 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial): self._mon = ETuple({}, int(self._parent.ngens())) return - #cdef dict D = self._poly._mpoly_dict_recursive( + # cdef dict D = self._poly._mpoly_dict_recursive( # self._parent.variable_names(), # self._parent.base_ring() # ) @@ -310,7 +310,7 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial): sage: a.dict() # indirect doctest {(0, 0): 3, (2, -1): 1} """ - #cdef dict D = self._poly._mpoly_dict_recursive(self._parent.variable_names(), + # cdef dict D = self._poly._mpoly_dict_recursive(self._parent.variable_names(), # self._parent.base_ring()) cdef dict D = self._poly.dict() cdef dict DD @@ -1236,7 +1236,7 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial): """ if kwds: f = self.subs(**kwds) - if x: # More than 1 non-keyword argument + if x: # More than 1 non-keyword argument return f(*x) else: return f @@ -1251,7 +1251,7 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial): raise TypeError("number of arguments does not match the number" " of generators in parent") - #Check to make sure that we aren't dividing by zero + # Check to make sure that we aren't dividing by zero cdef Py_ssize_t m for m in range(l): if x[m] == 0: @@ -1514,11 +1514,40 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial): x = 'x' i = 0 - #construct ring if none + # construct ring if none if R is None: R = LaurentPolynomialRing(self.base_ring(), x) - return R({m[i]: c for m,c in self.dict().iteritems()}) + return R({m[i]: c for m, c in self.dict().iteritems()}) + + def monomial_reduction(self): + """ + Factor ``self`` into a polynomial and a monomial. + + OUTPUT: + + A tuple ``(p, v)`` where ``p`` is the underlying polynomial and ``v`` + is a monomial. + + EXAMPLES:: + + sage: R. = LaurentPolynomialRing(QQ) + sage: f = y / x + x^2 / y + 3 * x^4 * y^-2 + sage: f.monomial_reduction() + (3*x^5 + x^3*y + y^3, 1/(x*y^2)) + sage: f = y * x + x^2 / y + 3 * x^4 * y^-2 + sage: f.monomial_reduction() + (3*x^3 + y^3 + x*y, x/y^2) + sage: x.monomial_reduction() + (1, x) + sage: (y^-1).monomial_reduction() + (1, 1/y) + """ + self._normalize() + ring = self._parent._R + g = ring.gens() + mon = ring.prod(g[i] ** j for i, j in enumerate(self._mon)) + return (self._poly, mon) def factor(self): """ @@ -1825,3 +1854,9 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial): if new_ring is not None: return new_ring(ans) return ans + + def divides(self, other): + R = self.parent().polynomial_ring() + p = R(self.monomial_reduction()[0]) + q = R(other.monomial_reduction()[0]) + return p.divides(q) From df7ed6f7836a303a62c38bf105e06faadd144edf Mon Sep 17 00:00:00 2001 From: Enrique Artal Date: Wed, 20 Sep 2023 23:33:56 +0200 Subject: [PATCH 03/45] divides --- src/sage/rings/polynomial/laurent_polynomial.pyx | 2 ++ src/sage/rings/polynomial/laurent_polynomial_mpair.pyx | 2 ++ src/sage/rings/polynomial/laurent_polynomial_ring.py | 5 +++-- src/sage/rings/polynomial/laurent_polynomial_ring_base.py | 4 +--- 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/sage/rings/polynomial/laurent_polynomial.pyx b/src/sage/rings/polynomial/laurent_polynomial.pyx index 61ba3870357..ff043140e48 100644 --- a/src/sage/rings/polynomial/laurent_polynomial.pyx +++ b/src/sage/rings/polynomial/laurent_polynomial.pyx @@ -1972,6 +1972,8 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): def divides(self, other): R = self.parent().polynomial_ring() + if not R.base_ring().is_integral_domain(): + raise NotImplementedError("divisibility test only implemented for polynomials over an integral domain") p = R(self.polynomial_construction()[0]) q = R(other.polynomial_construction()[0]) return p.divides(q) diff --git a/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx b/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx index 2e846ed7a53..fe199d281e3 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx +++ b/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx @@ -1857,6 +1857,8 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial): def divides(self, other): R = self.parent().polynomial_ring() + if not R.base_ring().is_integral_domain(): + raise NotImplementedError("divisibility test only implemented for polynomials over an integral domain") p = R(self.monomial_reduction()[0]) q = R(other.monomial_reduction()[0]) return p.divides(q) diff --git a/src/sage/rings/polynomial/laurent_polynomial_ring.py b/src/sage/rings/polynomial/laurent_polynomial_ring.py index ac40e815724..fcd7c90f2f6 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_ring.py +++ b/src/sage/rings/polynomial/laurent_polynomial_ring.py @@ -442,9 +442,10 @@ def __init__(self, R): TESTS:: - sage: TestSuite(LaurentPolynomialRing(Zmod(4), 'y')).run() + # sage: TestSuite(LaurentPolynomialRing(Zmod(4), 'y')).run() sage: TestSuite(LaurentPolynomialRing(ZZ, 'u')).run() - sage: TestSuite(LaurentPolynomialRing(Zmod(4)['T'], 'u')).run() + + # sage: TestSuite(LaurentPolynomialRing(Zmod(4)['T'], 'u')).run() """ if R.ngens() != 1: raise ValueError("must be 1 generator") diff --git a/src/sage/rings/polynomial/laurent_polynomial_ring_base.py b/src/sage/rings/polynomial/laurent_polynomial_ring_base.py index f160502d43f..c10cbb219b0 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_ring_base.py +++ b/src/sage/rings/polynomial/laurent_polynomial_ring_base.py @@ -162,9 +162,7 @@ def is_noetherian(self): EXAMPLES:: sage: LaurentPolynomialRing(QQ, 2, 'x').is_noetherian() - Traceback (most recent call last): - ... - NotImplementedError + True """ return self.base_ring().is_noetherian() From 28530fb0a6ea28eb99290ebda0ed9c13ab177587 Mon Sep 17 00:00:00 2001 From: Enrique Artal Date: Thu, 21 Sep 2023 16:18:20 +0200 Subject: [PATCH 04/45] avoid non integral domains --- .../rings/polynomial/laurent_polynomial.pyx | 3 +- .../polynomial/laurent_polynomial_ideal.py | 32 +++++++++++-------- .../polynomial/laurent_polynomial_ring.py | 5 ++- 3 files changed, 22 insertions(+), 18 deletions(-) diff --git a/src/sage/rings/polynomial/laurent_polynomial.pyx b/src/sage/rings/polynomial/laurent_polynomial.pyx index ff043140e48..b134b63ac5e 100644 --- a/src/sage/rings/polynomial/laurent_polynomial.pyx +++ b/src/sage/rings/polynomial/laurent_polynomial.pyx @@ -1970,10 +1970,9 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): """ return self.__u[-self.__n] + @coerce_binop def divides(self, other): R = self.parent().polynomial_ring() - if not R.base_ring().is_integral_domain(): - raise NotImplementedError("divisibility test only implemented for polynomials over an integral domain") p = R(self.polynomial_construction()[0]) q = R(other.polynomial_construction()[0]) return p.divides(q) diff --git a/src/sage/rings/polynomial/laurent_polynomial_ideal.py b/src/sage/rings/polynomial/laurent_polynomial_ideal.py index aa18314e523..be0e109738d 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_ideal.py +++ b/src/sage/rings/polynomial/laurent_polynomial_ideal.py @@ -24,6 +24,7 @@ from sage.rings.ideal import Ideal_generic from sage.structure.richcmp import op_EQ, op_NE, op_LT, op_LE, op_GT, op_GE +from sage.arith.misc import GCD class LaurentPolynomialIdeal( Ideal_generic ): def __init__(self, ring, gens, coerce=True, hint=None): @@ -399,31 +400,36 @@ def polynomial_ideal(self, saturate=True): Ideal (x + 3*y) of Multivariate Polynomial Ring in x, y over Rational Field """ - if self._poly_ideal is not None and (self._saturated or not saturate): - return self._poly_ideal P = self.ring() Q = self._poly_ring + if len(P.gens()) == 1: + a = [Q(p.polynomial_construction()[0]) for p in self.gens()] + if P.is_integral_domain(): + a = GCD(a) + return Q.ideal(a) + if self._poly_ideal is not None and (self._saturated or not saturate): + return self._poly_ideal gens = self.gens() if len(gens) == 0: - I = Q.ideal([]) - self._poly_ideal = I - self._hint = I + id = Q.ideal([]) + self._poly_ideal = id + self._hint = id self._saturated = True - return I + return id l2 = [f.__reduce__()[1][0] for f in gens] hint = self._hint l2 += list(hint.groebner_basis()) - I = Q.ideal(l2) + id = Q.ideal(l2) if not saturate: - self._poly_ideal = I - self._hint = I + self._poly_ideal = id + self._hint = id return Q.ideal(l2) n = P.ngens() - I = I.saturation(Q.ideal([Q.monomial(*((1,) * n))]))[0] - self._poly_ideal = I - self._hint = I + id = id.saturation(Q.ideal([Q.monomial(*((1,) * n))]))[0] + self._poly_ideal = id + self._hint = id self._saturated = True - return I + return id def groebner_basis(self, saturate=True): """ diff --git a/src/sage/rings/polynomial/laurent_polynomial_ring.py b/src/sage/rings/polynomial/laurent_polynomial_ring.py index fcd7c90f2f6..22d97975cd6 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_ring.py +++ b/src/sage/rings/polynomial/laurent_polynomial_ring.py @@ -442,10 +442,9 @@ def __init__(self, R): TESTS:: - # sage: TestSuite(LaurentPolynomialRing(Zmod(4), 'y')).run() + sage: TestSuite(LaurentPolynomialRing(Zmod(2), 'y')).run() sage: TestSuite(LaurentPolynomialRing(ZZ, 'u')).run() - - # sage: TestSuite(LaurentPolynomialRing(Zmod(4)['T'], 'u')).run() + sage: TestSuite(LaurentPolynomialRing(Zmod(2)['T'], 'u')).run() """ if R.ngens() != 1: raise ValueError("must be 1 generator") From fe8dbac479c135371f9d2825978a0264ce36b7cf Mon Sep 17 00:00:00 2001 From: Enrique Artal Date: Fri, 22 Sep 2023 09:04:24 +0200 Subject: [PATCH 05/45] typo in __contains__ --- src/sage/rings/polynomial/laurent_polynomial_ideal.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/polynomial/laurent_polynomial_ideal.py b/src/sage/rings/polynomial/laurent_polynomial_ideal.py index be0e109738d..b9ead02ea3e 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_ideal.py +++ b/src/sage/rings/polynomial/laurent_polynomial_ideal.py @@ -197,7 +197,7 @@ def __contains__(self, f): if not f or f in self.gens(): return True f = self.ring()(f) - g = f.__reduce__()[1][0] + g = f.__reduce__()[1][1] return (g in self.polynomial_ideal()) # Operations on ideals From e79852927082127fd5c39fe03348877eee0b3367 Mon Sep 17 00:00:00 2001 From: Enrique Artal Date: Fri, 22 Sep 2023 18:18:24 +0200 Subject: [PATCH 06/45] reduction of matrices of Laurent polynomials --- src/sage/matrix/matrix_mpolynomial_dense.pyx | 22 ++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/sage/matrix/matrix_mpolynomial_dense.pyx b/src/sage/matrix/matrix_mpolynomial_dense.pyx index d8819bdc7cc..4679f1c72a7 100644 --- a/src/sage/matrix/matrix_mpolynomial_dense.pyx +++ b/src/sage/matrix/matrix_mpolynomial_dense.pyx @@ -21,6 +21,7 @@ from sage.matrix.matrix_generic_dense cimport Matrix_generic_dense from sage.matrix.matrix2 cimport Matrix from sage.rings.polynomial.multi_polynomial_libsingular cimport MPolynomialRing_libsingular +from sage.rings.polynomial.laurent_polynomial_ring_base import LaurentPolynomialRing_generic from sage.rings.polynomial.polynomial_singular_interface import can_convert_to_singular from sage.libs.singular.function import singular_function @@ -554,3 +555,24 @@ cdef class Matrix_mpolynomial_dense(Matrix_generic_dense): self.cache('det', d) return d + + def laurent_matrix_reduction(self): + R = self._base_ring + n_rows, n_cols = self.dimensions() + mat_l = identity_matrix(R, n_rows) + mat_r = identity_matrix(R, n_cols) + if not isinstance(R, LaurentPolynomialRing_generic): + return mat_l, self, mat_r + res = self + for j, rw in enumerate(self.rows()): + for t in R.gens(): + n = min(mon.degree(t) for a in rw for cf, mon in a) + res.rescale_row(j, t ** -n) + mat_l.rescale_col(j, t ** n) + for j, cl in enumerate(self.columns()): + for t in R.gens(): + n = min(mon.degree(t) for a in cl for cf, mon in a) + res.rescale_col(j, t ** -n) + mat_r.rescale_row(j, t ** n) + res = res.change_ring(R.polynomial_ring()) + return mat_l, res, mat_r From 97bd76c4f3e6057faa84c47da56ce7fafe8c37f1 Mon Sep 17 00:00:00 2001 From: Enrique Artal Date: Fri, 22 Sep 2023 18:23:10 +0200 Subject: [PATCH 07/45] import identity --- src/sage/matrix/matrix_mpolynomial_dense.pyx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sage/matrix/matrix_mpolynomial_dense.pyx b/src/sage/matrix/matrix_mpolynomial_dense.pyx index 4679f1c72a7..ad8e8bceba3 100644 --- a/src/sage/matrix/matrix_mpolynomial_dense.pyx +++ b/src/sage/matrix/matrix_mpolynomial_dense.pyx @@ -19,6 +19,7 @@ AUTHOR: #***************************************************************************** from sage.matrix.matrix_generic_dense cimport Matrix_generic_dense from sage.matrix.matrix2 cimport Matrix +from sage.matrix.constructor import identity_matrix from sage.rings.polynomial.multi_polynomial_libsingular cimport MPolynomialRing_libsingular from sage.rings.polynomial.laurent_polynomial_ring_base import LaurentPolynomialRing_generic From 2888c7bdf8613dca8ff6cc71808bff9492815387 Mon Sep 17 00:00:00 2001 From: Enrique Artal Date: Sat, 23 Sep 2023 01:29:29 +0200 Subject: [PATCH 08/45] doctests --- src/sage/matrix/matrix_mpolynomial_dense.pyx | 76 ++-- .../rings/polynomial/laurent_polynomial.pyx | 58 ++- .../polynomial/laurent_polynomial_ideal.py | 35 +- .../polynomial/laurent_polynomial_mpair.pyx | 10 +- .../polynomial/laurent_polynomial_ring.py | 6 +- .../laurent_polynomial_ring_base.py | 5 +- .../rings/polynomial/laurent_reduction.py | 50 +++ .../rings/polynomial/polynomial_element.pyx | 344 +++++++++--------- 8 files changed, 328 insertions(+), 256 deletions(-) create mode 100644 src/sage/rings/polynomial/laurent_reduction.py diff --git a/src/sage/matrix/matrix_mpolynomial_dense.pyx b/src/sage/matrix/matrix_mpolynomial_dense.pyx index ad8e8bceba3..0a7ba60db75 100644 --- a/src/sage/matrix/matrix_mpolynomial_dense.pyx +++ b/src/sage/matrix/matrix_mpolynomial_dense.pyx @@ -9,20 +9,18 @@ AUTHOR: * Martin Albrecht """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2013 Martin Albrecht # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. # https://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.matrix.matrix_generic_dense cimport Matrix_generic_dense from sage.matrix.matrix2 cimport Matrix -from sage.matrix.constructor import identity_matrix from sage.rings.polynomial.multi_polynomial_libsingular cimport MPolynomialRing_libsingular -from sage.rings.polynomial.laurent_polynomial_ring_base import LaurentPolynomialRing_generic from sage.rings.polynomial.polynomial_singular_interface import can_convert_to_singular from sage.libs.singular.function import singular_function @@ -101,7 +99,8 @@ cdef class Matrix_mpolynomial_dense(Matrix_generic_dense): [ 0 -x + y] """ x = self.fetch('echelon_form_'+algorithm) - if x is not None: return x + if x is not None: + return x if algorithm == "frac": E = self.matrix_over_field() @@ -116,8 +115,8 @@ cdef class Matrix_mpolynomial_dense(Matrix_generic_dense): if algorithm == "frac": self.cache('pivots', E.pivots()) elif algorithm == "bareiss": - l = E.swapped_columns() - self.cache('pivots', tuple(sorted(l))) + l1 = E.swapped_columns() + self.cache('pivots', tuple(sorted(l1))) elif algorithm == "row_reduction": pass @@ -154,7 +153,7 @@ cdef class Matrix_mpolynomial_dense(Matrix_generic_dense): x = self.fetch('pivots') if x is None: - raise RuntimeError("BUG: matrix pivots should have been set but weren't, matrix parent = '%s'"%self.parent()) + raise RuntimeError("BUG: matrix pivots should have been set but weren't, matrix parent = '%s'" % self.parent()) return x def echelonize(self, algorithm='row_reduction', **kwds): @@ -262,7 +261,7 @@ cdef class Matrix_mpolynomial_dense(Matrix_generic_dense): self.clear_cache() singular_bareiss = singular_function("bareiss") - E, l = singular_bareiss(self.T) + E, ln = singular_bareiss(self.T) m = len(E) n = len(E[0]) @@ -277,33 +276,33 @@ cdef class Matrix_mpolynomial_dense(Matrix_generic_dense): self.set_unsafe(r, c, R._zero_element) from sage.rings.integer_ring import ZZ - l = [ZZ(e-1) for e in l] + ln = [ZZ(e-1) for e in ln] - self.cache('in_echelon_form_bareiss',True) + self.cache('in_echelon_form_bareiss', True) self.cache('rank', len(E)) self.cache('pivots', tuple(range(len(E)))) - self.cache('swapped_columns', tuple(l)) + self.cache('swapped_columns', tuple(ln)) elif can_convert_to_singular(self.base_ring()): self.check_mutability() self.clear_cache() - E,l = self.T._singular_().bareiss()._sage_(self.base_ring()) + E, ln = self.T._singular_().bareiss()._sage_(self.base_ring()) # clear matrix for r from 0 <= r < self._nrows: for c from 0 <= c < self._ncols: - self.set_unsafe(r,c,R._zero_element) + self.set_unsafe(r, c, R._zero_element) for r from 0 <= r < E.nrows(): for c from 0 <= c < E.ncols(): - self.set_unsafe(c,r, E[r,c]) + self.set_unsafe(c, r, E[r, c]) - self.cache('in_echelon_form_bareiss',True) + self.cache('in_echelon_form_bareiss', True) self.cache('rank', E.nrows()) self.cache('pivots', tuple(range(E.nrows()))) - self.cache('swapped_columns', l) + self.cache('swapped_columns', ln) else: @@ -387,14 +386,14 @@ cdef class Matrix_mpolynomial_dense(Matrix_generic_dense): if x is not None: return # already known to be in echelon form - nr,nc = self.nrows(),self.ncols() + nr, nc = self.nrows(), self.ncols() F = self.base_ring().base_ring() - cdef Matrix d = matrix(F,nr,nc) + cdef Matrix d = matrix(F, nr, nc) start_row = 0 for r from 0 <= r < nr: for c from 0 <= c < nc: - p = self.get_unsafe(r,c) + p = self.get_unsafe(r, c) if p.is_constant(): d.set_unsafe(r, c, p.constant_coefficient()) @@ -404,25 +403,25 @@ cdef class Matrix_mpolynomial_dense(Matrix_generic_dense): if d.get_unsafe(rc, c): r = rc break - if r!=-1: - a_inverse = ~self.get_unsafe(r,c) - self.rescale_row_c(r, a_inverse , c) + if r != -1: + a_inverse = ~self.get_unsafe(r, c) + self.rescale_row_c(r, a_inverse, c) self.swap_rows_c(r, start_row) for i from 0 <= i < nr: if i != start_row: - minus_b = -self.get_unsafe(i,c) + minus_b = -self.get_unsafe(i, c) self.add_multiple_of_row(i, start_row, minus_b, 0) - start_row +=1 + start_row += 1 d = d._parent(0) for i from start_row <= i < nr: for j from c+1 <= j < nc: - if self.get_unsafe(i,j).is_constant(): - d.set_unsafe(i,j, self.get_unsafe(i,j).constant_coefficient()) + if self.get_unsafe(i, j).is_constant(): + d.set_unsafe(i, j, self.get_unsafe(i, j).constant_coefficient()) - self.cache('in_echelon_form_row_reduction',True) + self.cache('in_echelon_form_row_reduction', True) def swapped_columns(self): """ @@ -556,24 +555,3 @@ cdef class Matrix_mpolynomial_dense(Matrix_generic_dense): self.cache('det', d) return d - - def laurent_matrix_reduction(self): - R = self._base_ring - n_rows, n_cols = self.dimensions() - mat_l = identity_matrix(R, n_rows) - mat_r = identity_matrix(R, n_cols) - if not isinstance(R, LaurentPolynomialRing_generic): - return mat_l, self, mat_r - res = self - for j, rw in enumerate(self.rows()): - for t in R.gens(): - n = min(mon.degree(t) for a in rw for cf, mon in a) - res.rescale_row(j, t ** -n) - mat_l.rescale_col(j, t ** n) - for j, cl in enumerate(self.columns()): - for t in R.gens(): - n = min(mon.degree(t) for a in cl for cf, mon in a) - res.rescale_col(j, t ** -n) - mat_r.rescale_row(j, t ** n) - res = res.change_ring(R.polynomial_ring()) - return mat_l, res, mat_r diff --git a/src/sage/rings/polynomial/laurent_polynomial.pyx b/src/sage/rings/polynomial/laurent_polynomial.pyx index b134b63ac5e..917943f5619 100644 --- a/src/sage/rings/polynomial/laurent_polynomial.pyx +++ b/src/sage/rings/polynomial/laurent_polynomial.pyx @@ -592,11 +592,11 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): elif e == 0: var = "" else: - var = "*{}^{}".format(X,e) - s += "{}{}".format(x,var) + var = "*{}^{}".format(X, e) + s += "{}{}".format(x, var) first = False s = s.replace(" + -", " - ") - s = s.replace(" 1*"," ") + s = s.replace(" 1*", " ") s = s.replace(" -1*", " -") return s[1:] @@ -701,7 +701,7 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): # degrees cdef long result = 0 cdef long result_mon - cdef int i,j + cdef int i, j cdef long var_hash_name = hash(self.__u._parent._names[0]) for i in range(self.__u.degree()+1): result_mon = hash(self.__u[i]) @@ -913,11 +913,11 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): j = i - self.__n if j >= 0: self.__u._unsafe_mutate(j, value) - else: # off to the left + else: # off to the left if value != 0: self.__n = self.__n + j R = self._parent.base_ring() - coeffs = [value] + [R.zero() for _ in range(1,-j)] + self.__u.list() + coeffs = [value] + [R.zero() for _ in range(1, -j)] + self.__u.list() self.__u = self.__u._parent(coeffs) self._normalize() @@ -1282,7 +1282,7 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): Fraction Field of Univariate Polynomial Ring in t over Rational Field """ cdef LaurentPolynomial_univariate ret - if self.__u.is_constant(): # this has a single term c*x^n + if self.__u.is_constant(): # this has a single term c*x^n ret = self._new_c() if self.__u.is_unit(): ret.__u = self.__u.inverse_of_unit() @@ -1599,7 +1599,6 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): """ return self.__n == 0 and self.__u.is_constant() - def is_square(self, root=False): r""" Return whether this Laurent polynomial is a square. @@ -1846,10 +1845,10 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): cdef list a = self.__u.list(copy=False) if n < 0: - v = [a[i]/(n+i+1) for i in range(min(-1-n,len(a)))] + [0] + v = [a[i] / (n + i + 1) for i in range(min(-1 - n, len(a)))] + [0] else: v = [] - v += [a[i]/(n+i+1) for i in range(max(-n,0), len(a))] + v += [a[i] / (n + i + 1) for i in range(max(-n, 0), len(a))] try: u = self._parent._R(v) except TypeError: @@ -1888,7 +1887,7 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): """ if kwds: f = self.subs(**kwds) - if x: # If there are non-keyword arguments + if x: # If there are non-keyword arguments return f(*x) else: return f @@ -1972,6 +1971,43 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): @coerce_binop def divides(self, other): + r""" + Return ``True`` if ``self`` divides ``other``. + + This method is only implemented for Laurent polynomials over an integral domain. + + EXAMPLES:: + + sage: R. = LaurentPolynomialRing(ZZ) + sage: (2*x**-1 + 1).divides(4*x**-2 - 1) + True + sage: (2*x + 1).divides(4*x**2 + 1) + False + sage: (2*x + x**-1).divides(R(0)) + True + sage: R(0).divides(2*x ** -1 + 1) + False + sage: R(0).divides(R(0)) + True + sage: R. = LaurentPolynomialRing(Zmod(6)) + sage: p = 4*x + 3*x^-1 + sage: q = 5*x^2 + x + 2*x^-2 + sage: p.divides(q) + Traceback (most recent call last): + ... + NotImplementedError: divisibility test only implemented for Laurent polynomials over an integral domain + + + sage: R. = GF(2)[] + sage: S. = LaurentPolynomialRing(R) + sage: p = (x+y+1) * z**-1 + x*y + sage: q = (y^2-x^2) * z**-2 + z + x-y + sage: p.divides(q), p.divides(p*q) # needs sage.libs.singular + (False, True) + """ + if not self.base_ring().is_integral_domain(): + raise NotImplementedError("divisibility test only implemented for Laurent polynomials over an integral domain") + R = self.parent().polynomial_ring() p = R(self.polynomial_construction()[0]) q = R(other.polynomial_construction()[0]) diff --git a/src/sage/rings/polynomial/laurent_polynomial_ideal.py b/src/sage/rings/polynomial/laurent_polynomial_ideal.py index b9ead02ea3e..fbfa99fd8ac 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_ideal.py +++ b/src/sage/rings/polynomial/laurent_polynomial_ideal.py @@ -26,7 +26,8 @@ from sage.structure.richcmp import op_EQ, op_NE, op_LT, op_LE, op_GT, op_GE from sage.arith.misc import GCD -class LaurentPolynomialIdeal( Ideal_generic ): + +class LaurentPolynomialIdeal(Ideal_generic): def __init__(self, ring, gens, coerce=True, hint=None): r""" Create an ideal in a Laurent polynomial ring. @@ -92,7 +93,7 @@ def __init__(self, ring, gens, coerce=True, hint=None): """ Ideal_generic.__init__(self, ring, gens, coerce=coerce) self._poly_ring = ring.polynomial_ring() - self._poly_ideal = None # Create only as needed + self._poly_ideal = None # Create only as needed self._saturated = False if hint is None: self._hint = self._poly_ring.zero_ideal() @@ -167,11 +168,11 @@ def _richcmp_(self, right_r, op): True """ if op in (op_EQ, op_NE): - if set(self.gens()) == set(right_r.gens()): # Early abort + if set(self.gens()) == set(right_r.gens()): # Early abort return (op == op_EQ) return ((self.polynomial_ideal() == right_r.polynomial_ideal()) == (op == op_EQ)) elif op == op_LE: - if all(f in right_r.gens() for f in self.gens()): # Early abort + if all(f in right_r.gens() for f in self.gens()): # Early abort return True return self.polynomial_ideal(saturate=False) <= right_r.polynomial_ideal() elif op == op_GE: @@ -298,10 +299,10 @@ def apply_coeff_map(self, f, new_base_ring=None, forward_hint=True): else: R = ring.change_ring(new_base_ring) if forward_hint: - apply_to_hint = lambda x,f=f: x.map_coefficients(f) + apply_to_hint = lambda x, f=f: x.map_coefficients(f) else: apply_to_hint = None - return self.apply_map(lambda x,f=f: + return self.apply_map(lambda x, f=f: x.map_coefficients(f, new_base_ring=new_base_ring), new_ring=R, apply_to_hint=apply_to_hint) @@ -443,8 +444,8 @@ def groebner_basis(self, saturate=True): sage: (I + J).groebner_basis() (x - 1, y + 1) """ - l = self.polynomial_ideal(saturate=saturate).groebner_basis() - return tuple(self.ring()(x) for x in l) + gb = self.polynomial_ideal(saturate=saturate).groebner_basis() + return tuple(self.ring()(x) for x in gb) def is_one(self): """ @@ -476,10 +477,10 @@ def is_binomial(self, groebner_basis=False): True """ if groebner_basis: - l = self.groebner_basis() + gb = self.groebner_basis() else: - l = self.gens() - return all(not f or f.number_of_terms() == 2 for f in l) + gb = self.gens() + return all(not f or f.number_of_terms() == 2 for f in gb) def associated_primes(self): """ @@ -499,9 +500,9 @@ def associated_primes(self): Ideal (z^2 - y, y*z + 2, y^2 + 2*z) of Multivariate Laurent Polynomial Ring in x, y, z over Rational Field) """ - l = self.polynomial_ideal(saturate=False).associated_primes() - l2 = [self.ring().ideal(I.gens(), hint=I) for I in l] - return tuple(I for I in l2 if not I.is_one()) + ap = self.polynomial_ideal(saturate=False).associated_primes() + ap2 = [self.ring().ideal(id.gens(), hint=id) for Iid in ap] + return tuple(id for id in ap2 if not id.is_one()) def minimal_associated_primes(self, saturate=False): """ @@ -521,9 +522,9 @@ def minimal_associated_primes(self, saturate=False): Ideal (z^3 + 2, -z^2 + y) of Multivariate Laurent Polynomial Ring in x, y, z over Rational Field) """ - l = self.polynomial_ideal(saturate=saturate).minimal_associated_primes() - l2 = [self.ring().ideal(I.gens(), hint=I) for I in l] - return tuple(I for I in l2 if not I.is_one()) + ap = self.polynomial_ideal(saturate=saturate).minimal_associated_primes() + ap2 = [self.ring().ideal(id.gens(), hint=id) for id in ap] + return tuple(id for id in ap2 if not id.is_one()) def radical(self): """ diff --git a/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx b/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx index fe199d281e3..efab709fd44 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx +++ b/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx @@ -1241,19 +1241,19 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial): else: return f - cdef int l = len(x) + cdef int ln = len(x) - if l == 1 and isinstance(x[0], (tuple, list)): + if ln == 1 and isinstance(x[0], (tuple, list)): x = x[0] - l = len(x) + ln = len(x) - if l != self._parent.ngens(): + if ln != self._parent.ngens(): raise TypeError("number of arguments does not match the number" " of generators in parent") # Check to make sure that we aren't dividing by zero cdef Py_ssize_t m - for m in range(l): + for m in range(ln): if x[m] == 0: if self.has_inverse_of(m): raise ZeroDivisionError diff --git a/src/sage/rings/polynomial/laurent_polynomial_ring.py b/src/sage/rings/polynomial/laurent_polynomial_ring.py index 22d97975cd6..38f9f7a8ebb 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_ring.py +++ b/src/sage/rings/polynomial/laurent_polynomial_ring.py @@ -327,8 +327,8 @@ def extract(T, indices): if not all(r == 0 for r in extract(K, remaining)): raise SplitDictError('split not possible') G = extract(K, group_by) - I = extract(K, indices) - result.setdefault(G, dict()).update({I: V}) + In = extract(K, indices) + result.setdefault(G, dict()).update({In: V}) if not group_by: return result.popitem()[1] else: @@ -755,7 +755,7 @@ def _element_constructor_(self, x, mon=None): P = parent(x) if P is self.polynomial_ring(): from sage.rings.polynomial.polydict import ETuple - return self.element_class( self, x, mon=ETuple({}, int(self.ngens())) ) + return self.element_class(self, x, mon=ETuple({}, int(self.ngens()))) elif isinstance(x, Expression): return x.laurent_polynomial(ring=self) diff --git a/src/sage/rings/polynomial/laurent_polynomial_ring_base.py b/src/sage/rings/polynomial/laurent_polynomial_ring_base.py index c10cbb219b0..95ea676e0d3 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_ring_base.py +++ b/src/sage/rings/polynomial/laurent_polynomial_ring_base.py @@ -278,8 +278,7 @@ def _coerce_map_from_(self, R): f = self._coerce_map_via([self._R], R) if f is not None: return f - if (isinstance(R, LaurentPolynomialRing_generic) - and self._R.has_coerce_map_from(R._R)): + if isinstance(R, LaurentPolynomialRing_generic) and self._R.has_coerce_map_from(R._R): return self._generic_coerce_map(R) def __eq__(self, right): @@ -480,7 +479,7 @@ def krull_dimension(self): """ raise NotImplementedError - def random_element(self, low_degree=-2, high_degree=2, terms=5, choose_degree=False,*args, **kwds): + def random_element(self, low_degree=-2, high_degree=2, terms=5, choose_degree=False, *args, **kwds): """ EXAMPLES:: diff --git a/src/sage/rings/polynomial/laurent_reduction.py b/src/sage/rings/polynomial/laurent_reduction.py new file mode 100644 index 00000000000..c26b667b492 --- /dev/null +++ b/src/sage/rings/polynomial/laurent_reduction.py @@ -0,0 +1,50 @@ +from sage.matrix.constructor import identity_matrix +from sage.rings.polynomial.laurent_polynomial_ring_base import LaurentPolynomialRing_generic + + +def laurent_matrix_reduction(A): + """ + From a matrix `A` of Laurent polynomials, apply elementary operations + to obtain a matrix `P` of polynomials such that the variables do not divide + no column and no row. + + OUTPUT: Three matrices `L`, `P`, `R` such that `A = L P R`, where `L` and + `R` are diagonal with monomial entries. + + EXAMPLES: + + sage: from sage.rings.polynomial.laurent_reduction import laurent_matrix_reduction + sage: R. = LaurentPolynomialRing(QQ) + sage: L = [1/3*x^-1*y - 6*x^-2*y^2 - 1/2*x^-2*y, 1/5*x + 1/2*y + 1/6] + sage: L += [1/2 - 5*x^-1*y - 2*x^-1, -1/3*y^-2 - 4*x^-1*y^-1 + 11*x^-1*y^-2] + sage: A = matrix(R, 2, L) + sage: lf, P, rg = laurent_matrix_reduction(A) + sage: lf + [ x^-2 0] + [ 0 x^-1*y^-2] + sage: P + [ 1/3*x - 6*y - 1/2 1/5*x^3 + 1/2*x^2*y + 1/6*x^2] + [ 1/2*x*y - 5*y^2 - 2*y -1/3*x - 4*y + 11] + sage: rg + [y 0] + [0 1] + """ + R = A.base_ring() + n_rows, n_cols = A.dimensions() + mat_l = identity_matrix(R, n_rows) + mat_r = identity_matrix(R, n_cols) + if not isinstance(R, LaurentPolynomialRing_generic): + return mat_l, A, mat_r + res = A + for j, rw in enumerate(A.rows()): + for t in R.gens(): + n = min(mon.degree(t) for a in rw for cf, mon in a) + res.rescale_row(j, t ** -n) + mat_l.rescale_col(j, t ** n) + for j, cl in enumerate(A.columns()): + for t in R.gens(): + n = min(mon.degree(t) for a in cl for cf, mon in a) + res.rescale_col(j, t ** -n) + mat_r.rescale_row(j, t ** n) + res = res.change_ring(R.polynomial_ring()) + return mat_l, res, mat_r diff --git a/src/sage/rings/polynomial/polynomial_element.pyx b/src/sage/rings/polynomial/polynomial_element.pyx index c5a1129aecf..06b5ab0eb43 100644 --- a/src/sage/rings/polynomial/polynomial_element.pyx +++ b/src/sage/rings/polynomial/polynomial_element.pyx @@ -213,7 +213,7 @@ cdef class Polynomial(CommutativePolynomial): .. automethod:: _mul_trunc_ """ - def __init__(self, parent, is_gen = False, construct=False): + def __init__(self, parent, is_gen=False, construct=False): """ The following examples illustrate creation of elements of polynomial rings, and some basic arithmetic. @@ -357,7 +357,7 @@ cdef class Polynomial(CommutativePolynomial): from sage.plot.all import plot, point if R.characteristic() == 0: if xmin is None and xmax is None: - (xmin, xmax) = (-1,1) + (xmin, xmax) = (-1, 1) elif xmin is None or xmax is None: raise AttributeError("must give both plot endpoints") return plot(self.__call__, (xmin, xmax), *args, **kwds) @@ -365,10 +365,10 @@ cdef class Polynomial(CommutativePolynomial): if R.is_finite(): v = list(R) v.sort() - w = dict([(v[i],i) for i in range(len(v))]) + w = dict([(v[i], i) for i in range(len(v))]) z = [(i, w[self(v[i])]) for i in range(len(v))] return point(z, *args, **kwds) - raise NotImplementedError("plotting of polynomials over %s not implemented"%R) + raise NotImplementedError("plotting of polynomials over %s not implemented" % R) cpdef _lmul_(self, Element left): """ @@ -832,7 +832,7 @@ cdef class Polynomial(CommutativePolynomial): # is more permissive about its arguments than we are. top = top(*args, **kwds) except TypeError: - if args: # bwd compat: nonsense *keyword* arguments are okay + if args: # bwd compat: nonsense *keyword* arguments are okay raise TypeError("Wrong number of arguments") else: eval_coeffs = True @@ -912,7 +912,7 @@ cdef class Polynomial(CommutativePolynomial): d = pol.degree() if d <= 0 or (isinstance(a, Element) and R.is_exact() and a.is_zero()): - return cst # with the right parent thanks to the above coercion + return cst # with the right parent thanks to the above coercion elif pol._parent is R and a.is_gen(): return pol elif hasattr(a, "_evaluate_polynomial"): @@ -1078,18 +1078,18 @@ cdef class Polynomial(CommutativePolynomial): cdef Py_ssize_t d2 = pol.degree() # Special case constant polynomials - if d1 == -1: # self is the 0 polynomial + if d1 == -1: # self is the 0 polynomial if d2 == -1: - return rich_to_bool(op, 0) # both polynomials are 0 + return rich_to_bool(op, 0) # both polynomials are 0 elif d2 == 0: return richcmp(self._parent._base.zero(), pol.get_unsafe(0), op) - return rich_to_bool_sgn(op, -1) # we have d2 > 0 - elif d1 == 0: # self is a nonzero constant + return rich_to_bool_sgn(op, -1) # we have d2 > 0 + elif d1 == 0: # self is a nonzero constant if d2 == -1: return richcmp(self.get_unsafe(0), pol._parent._base.zero(), op) elif d2 == 0: return richcmp(self.get_unsafe(0), pol.get_unsafe(0), op) - return rich_to_bool_sgn(op, -1) # we have d2 > d1 == 0 + return rich_to_bool_sgn(op, -1) # we have d2 > d1 == 0 # For different degrees, compare the degree if d1 != d2: @@ -1272,12 +1272,12 @@ cdef class Polynomial(CommutativePolynomial): TypeError: unhashable type: 'sage.rings.padics.qadic_flint_CR.qAdicCappedRelativeElement' """ - cdef long result = 0 # store it in a c-int and just let the overflowing additions wrap + cdef long result = 0 # store it in a c-int and just let the overflowing additions wrap cdef long result_mon cdef long c_hash cdef long var_name_hash cdef int i - for i from 0<= i <= self.degree(): + for i from 0 <= i <= self.degree(): if i == 1: # we delay the hashing until now to not waste it on a constant poly var_name_hash = hash(self._parent._names[0]) @@ -1331,7 +1331,7 @@ cdef class Polynomial(CommutativePolynomial): a = im_gens[0] d = self.degree() if d == -1: - return codomain.zero() # Special case: 0 should always coerce to 0 + return codomain.zero() # Special case: 0 should always coerce to 0 if base_map is None: base_map = codomain.coerce_map_from(self.base_ring()) result = base_map(self.get_unsafe(d)) @@ -1661,9 +1661,9 @@ cdef class Polynomial(CommutativePolynomial): for i in range(n+1): for j in range(n-1): M[i+j, j+n] = m[i] - v = vector(R, [R.one()] + [R.zero()]*(2*n-2)) # the constant polynomial 1 + v = vector(R, [R.one()] + [R.zero()]*(2*n-2)) # the constant polynomial 1 if M.is_invertible(): - x = M.solve_right(v) # there has to be a better way to solve + x = M.solve_right(v) # there has to be a better way to solve return a.parent()(list(x)[0:n]) else: raise ValueError("Impossible inverse modulo") @@ -1846,7 +1846,7 @@ cdef class Polynomial(CommutativePolynomial): This is the default implementation that does the multiplication and then truncate! There are custom implementations in several subclasses: - - :meth:`on dense polynomial over integers (via FLINT) ` + - :meth:`on dense polynomial over integers (via FLINT) ` - :meth:`on dense polynomial over Z/nZ (via FLINT) ` @@ -1961,7 +1961,7 @@ cdef class Polynomial(CommutativePolynomial): """ if self.degree() < 0: raise ValueError("square-free decomposition not defined for zero polynomial") - if hasattr(self.base_ring(),'_squarefree_decomposition_univariate_polynomial'): + if hasattr(self.base_ring(), '_squarefree_decomposition_univariate_polynomial'): return self.base_ring()._squarefree_decomposition_univariate_polynomial(self) raise NotImplementedError("square-free decomposition not implemented for this polynomial") @@ -2188,11 +2188,11 @@ cdef class Polynomial(CommutativePolynomial): raise ValueError("ring must be an extension of the base ring") if not (ring.is_field() and ring.is_finite()): raise NotImplementedError - allowed_deg_mult = Integer(ring.factored_order()[0][1]) # generally it will be the quotient of this by the degree of the base ring. + allowed_deg_mult = Integer(ring.factored_order()[0][1]) # generally it will be the quotient of this by the degree of the base ring. if degree is None: x = self._parent.gen() if allowed_deg_mult == 1: - xq = pow(x,q,self) + xq = pow(x, q, self) self = self.gcd(xq-x) degree = -1 if self.degree() == 0: @@ -2210,7 +2210,7 @@ cdef class Polynomial(CommutativePolynomial): break while d < allowed_deg_mult: d = d+1 - xq = pow(xq,q,self) + xq = pow(xq, q, self) if d.divides(allowed_deg_mult): break A = self.gcd(xq-x) @@ -2234,8 +2234,8 @@ cdef class Polynomial(CommutativePolynomial): break while True: # we waste a little effort here in computing the xq again. - d = d+1 - xq = pow(xq,q,self) + d = d + 1 + xq = pow(xq, q, self) if allowed_deg_mult.divides(d): break A = self.gcd(xq-x) @@ -2257,7 +2257,7 @@ cdef class Polynomial(CommutativePolynomial): raise ValueError("no roots D %s" % self) break d = d+1 - xq = pow(xq,q,self) + xq = pow(xq, q, self) if d == degree: break A = self.gcd(xq-x) @@ -2273,13 +2273,13 @@ cdef class Polynomial(CommutativePolynomial): if degree == 1: ring = self.base_ring() else: - ring = self.base_ring().extension(degree) # this won't work yet. + ring = self.base_ring().extension(degree) # this won't work yet. # now self has only roots of degree ``degree``. # for now, we only implement the Cantor-Zassenhaus split k = self.degree() // degree if k == 1: try: - return self.roots(ring, multiplicities=False)[0] # is there something better to do here? + return self.roots(ring, multiplicities=False)[0] # is there something better to do here? except IndexError: raise ValueError("no roots F %s" % self) if q % 2 == 0: @@ -2289,8 +2289,8 @@ cdef class Polynomial(CommutativePolynomial): continue T = T.monic() C = T - for i in range(degree-1): - C = T + pow(C,q,self) + for i in range(degree - 1): + C = T + pow(C, q, self) h = self.gcd(C) hd = h.degree() if hd != 0 and hd != self.degree(): @@ -2536,7 +2536,7 @@ cdef class Polynomial(CommutativePolynomial): else: v = [R.zero()]*right + [R.one()] return self.parent()(v, check=False) - if right > 20: # no gain below + if right > 20: # no gain below try: p = self.parent().characteristic() except (AttributeError, NotImplementedError): @@ -2557,7 +2557,7 @@ cdef class Polynomial(CommutativePolynomial): q, r = q.quo_rem(p) if r != 0: if sparse: - tmp = self.parent()({e*k : d[k]**e for k in d}) + tmp = self.parent()({e * k: d[k] ** e for k in d}) else: tmp = [0] * (e * len(c) - e + 1) for i in range(len(c)): @@ -2728,19 +2728,19 @@ cdef class Polynomial(CommutativePolynomial): if y.find("-") == 0: y = y[1:] if not atomic_repr and n > 0 and (y.find("+") != -1 or y.find("-") != -1): - x = "(%s)"%x + x = "(%s)" % x if n > 1: - var = "*%s^%s"%(name,n) - elif n==1: - var = "*%s"%name + var = "*%s^%s" % (name, n) + elif n == 1: + var = "*%s" % name else: var = "" sbuf.write(x) sbuf.write(var) s = sbuf.getvalue() s = s.replace(" + -", " - ") - s = re.sub(r' 1(\.0+)?\*',' ', s) - s = re.sub(r' -1(\.0+)?\*',' -', s) + s = re.sub(r' 1(\.0+)?\*', ' ', s) + s = re.sub(r' -1(\.0+)?\*', ' -', s) if s == " ": return "0" return s[1:] @@ -2813,7 +2813,7 @@ cdef class Polynomial(CommutativePolynomial): x = "\\left(%s\\right)" % x if n > 1: var = "|%s^{%s}" % (name, n) - elif n==1: + elif n == 1: var = "|%s" % name else: var = "" @@ -3150,12 +3150,12 @@ cdef class Polynomial(CommutativePolynomial): - Didier Deshommes (2006-05-25) """ - return self._parent(polynomial_fateman._mul_fateman_mul(self,right)) + return self._parent(polynomial_fateman._mul_fateman_mul(self, right)) @cython.boundscheck(False) @cython.wraparound(False) @cython.overflowcheck(False) - def _mul_karatsuba(self, right, K_threshold = None): + def _mul_karatsuba(self, right, K_threshold=None): r""" Compute the product of two polynomials using the Karatsuba divide and conquer multiplication algorithm. This is only used over a @@ -3328,8 +3328,8 @@ cdef class Polynomial(CommutativePolynomial): if n <= K_threshold or m <= K_threshold: return self._new_generic(do_schoolbook_product(f, g, -1)) if n == m: - return self._new_generic(do_karatsuba(f,g, K_threshold, 0, 0, n)) - return self._new_generic(do_karatsuba_different_size(f,g, K_threshold)) + return self._new_generic(do_karatsuba(f, g, K_threshold, 0, 0, n)) + return self._new_generic(do_karatsuba_different_size(f, g, K_threshold)) @cython.boundscheck(False) @cython.wraparound(False) @@ -3487,7 +3487,7 @@ cdef class Polynomial(CommutativePolynomial): if var not in variables: x = base_ring(self) if base_ring else self const_ix = ETuple((0,)*len(variables)) - return { const_ix: x } + return {const_ix: x} cdef tuple prev_variables = variables[:variables.index(var)] const_ix = ETuple((0,)*len(prev_variables)) @@ -3509,7 +3509,7 @@ cdef class Polynomial(CommutativePolynomial): cdef dict D = {} cdef tuple leftovers = (0,) * (len(variables) - len(prev_variables) - 1) for k in range(len(mpolys)): - for i,a in mpolys[k].iteritems(): + for i, a in mpolys[k].iteritems(): j = ETuple((k,) + leftovers) D[i + j] = a @@ -3680,7 +3680,7 @@ cdef class Polynomial(CommutativePolynomial): for y in x: d = d.lcm(y.denominator()) return d - except(AttributeError): + except (AttributeError): return self.base_ring().one() def numerator(self): @@ -3951,7 +3951,7 @@ cdef class Polynomial(CommutativePolynomial): """ return [self.diff()] - def integral(self,var=None): + def integral(self, var=None): """ Return the integral of this polynomial. @@ -4571,39 +4571,39 @@ cdef class Polynomial(CommutativePolynomial): # PARI for smaller degree over other rings besides Z, and use # NTL in general. # A remark from Bill Hart (2007-09-25) about the above observation: - ## NTL uses the Berlekamp-Zassenhaus method with van Hoeij's improvements. - ## But so does Magma since about Jul 2001. - ## - ## But here's the kicker. PARI also uses this algorithm. Even Maple uses - ## it! - ## - ## NTL's LLL algorithms are extremely well developed (van Hoeij uses - ## LLL). There is also a possible speed difference in whether one uses - ## quadratic convergence or not in the Hensel lift. But the right choice - ## is not always what one thinks. - ## - ## But more than likely NTL is just better for large problems because - ## Victor Shoup was very careful with the choice of strategies and - ## parameters he used. Paul Zimmerman supplied him with a pile of - ## polynomials to factor for comparison purposes and these seem to have - ## been used to tune the algorithm for a wide range of inputs, including - ## cases that van Hoeij's algorithm doesn't usually like. - ## - ## If you have a bound on the coefficients of the factors, one can surely - ## do better than a generic implementation, but probably not much better - ## if there are many factors. - ## - - ## HUGE TODO, refactor the code below here such that this method will - ## have as only the following code - ## - ## R = self.parent().base_ring() - ## return R._factor_univariate_polynomial(self) - ## - ## in this way we can move the specific logic of factoring to the - ## self.parent().base_ring() and get rid of all the ugly - ## is_SomeType(R) checks and get way nicer structured code - ## 200 lines of spaghetti code is just way to much! + # # NTL uses the Berlekamp-Zassenhaus method with van Hoeij's improvements. + # # But so does Magma since about Jul 2001. + # # + # # But here's the kicker. PARI also uses this algorithm. Even Maple uses + # # it! + # # + # # NTL's LLL algorithms are extremely well developed (van Hoeij uses + # # LLL). There is also a possible speed difference in whether one uses + # # quadratic convergence or not in the Hensel lift. But the right choice + # # is not always what one thinks. + # # + # # But more than likely NTL is just better for large problems because + # # Victor Shoup was very careful with the choice of strategies and + # # parameters he used. Paul Zimmerman supplied him with a pile of + # # polynomials to factor for comparison purposes and these seem to have + # # been used to tune the algorithm for a wide range of inputs, including + # # cases that van Hoeij's algorithm doesn't usually like. + # # + # # If you have a bound on the coefficients of the factors, one can surely + # # do better than a generic implementation, but probably not much better + # # if there are many factors. + # # + + # # HUGE TODO, refactor the code below here such that this method will + # # have as only the following code + # # + # # R = self.parent().base_ring() + # # return R._factor_univariate_polynomial(self) + # # + # # in this way we can move the specific logic of factoring to the + # # self.parent().base_ring() and get rid of all the ugly + # # is_SomeType(R) checks and get way nicer structured code + # # 200 lines of spaghetti code is just way to much! if self.degree() < 0: raise ArithmeticError("factorization of {!r} is not defined".format(self)) @@ -4617,7 +4617,7 @@ cdef class Polynomial(CommutativePolynomial): try: F = flatten(self).factor(**kwargs) unflatten = flatten.section() - return Factorization(((unflatten(f),m) for (f,m) in F), unit = F.unit()) + return Factorization(((unflatten(f), m) for (f, m) in F), unit=F.unit()) except NotImplementedError: pass @@ -4650,7 +4650,7 @@ cdef class Polynomial(CommutativePolynomial): # This was copied from the general multivariate implementation try: if R.is_finite(): - if R.characteristic() > 1<<29: + if R.characteristic() > 1 << 29: raise NotImplementedError("Factorization of multivariate polynomials over prime fields with characteristic > 2^29 is not implemented.") P = self._parent @@ -4658,8 +4658,8 @@ cdef class Polynomial(CommutativePolynomial): S = self._singular_().factorize() factors = S[1] exponents = S[2] - v = sorted([( P(factors[i+1]), - sage.rings.integer.Integer(exponents[i+1])) + v = sorted([(P(factors[i + 1]), + sage.rings.integer.Integer(exponents[i + 1])) for i in range(len(factors))]) unit = P.one() for i in range(len(v)): @@ -4936,7 +4936,7 @@ cdef class Polynomial(CommutativePolynomial): raise NotImplementedError("splitting_field() is only implemented over number fields and finite fields") - def pseudo_quo_rem(self,other): + def pseudo_quo_rem(self, other): r""" Compute the pseudo-division of two polynomials. @@ -4996,7 +4996,7 @@ cdef class Polynomial(CommutativePolynomial): e -= 1 q = d**e - return (q*Q,q*R) + return (q * Q, q * R) @coerce_binop def gcd(self, other): @@ -5089,7 +5089,7 @@ cdef class Polynomial(CommutativePolynomial): try: doit = self._parent._base._gcd_univariate_polynomial except AttributeError: - raise NotImplementedError("%s does not provide a gcd implementation for univariate polynomials"%self._parent._base) + raise NotImplementedError("%s does not provide a gcd implementation for univariate polynomials" % self._parent._base) else: return doit(self, other) @@ -5462,7 +5462,7 @@ cdef class Polynomial(CommutativePolynomial): return R.fraction_field()[self._parent.variable_name()].quotient(self, names) - def sylvester_matrix(self, right, variable = None): + def sylvester_matrix(self, right, variable=None): """ Return the Sylvester matrix of ``self`` and ``right``. @@ -5588,10 +5588,10 @@ cdef class Polynomial(CommutativePolynomial): # sylvester_matrix() in multi_polynomial.pyx. if self._parent != right.parent(): - a, b = coercion_model.canonical_coercion(self,right) + a, b = coercion_model.canonical_coercion(self, right) variable = a.parent()(self.variables()[0]) - #We add the variable to cover the case that right is a multivariate - #polynomial + # We add the variable to cover the case that right is a multivariate + # polynomial return a.sylvester_matrix(b, variable) if variable: @@ -6446,13 +6446,18 @@ cdef class Polynomial(CommutativePolynomial): e = self.exponents() c = self.coefficients() - if len(e) == 0: return [] + if len(e) == 0: + return [] if len(e) == 1: - if e[0] == 0: return [] - else: return [(infinity.infinity, e[0])] + if e[0] == 0: + return [] + else: + return [(infinity.infinity, e[0])] - if e[0] == 0: slopes = [] - else: slopes = [(infinity.infinity, e[0])] + if e[0] == 0: + slopes = [] + else: + slopes = [(infinity.infinity, e[0])] points = [(e[0], c[0].valuation(p)), (e[1], c[1].valuation(p))] slopes.append((-(c[1].valuation(p)-c[0].valuation(p))/(e[1] - e[0]), e[1]-e[0])) @@ -6463,8 +6468,8 @@ cdef class Polynomial(CommutativePolynomial): slopes = slopes[:-1] points = points[:-1] s = -(v-points[-1][1])/(e[i]-points[-1][0]) - slopes.append((s,e[i]-points[-1][0])) - points.append((e[i],v)) + slopes.append((s, e[i] - points[-1][0])) + points.append((e[i], v)) return slopes @@ -6508,7 +6513,7 @@ cdef class Polynomial(CommutativePolynomial): if m != n or p[n] != q[n]: continue alpha = (q[n-1] - p[n-1])/(n*p[n]) - if alpha.is_integer(): # ZZ() might work for non-integers... + if alpha.is_integer(): # ZZ() might work for non-integers... alpha = ZZ(alpha) else: continue @@ -7178,7 +7183,7 @@ cdef class Polynomial(CommutativePolynomial): if Sf is not QQ or (d1 <= N and d2 <= N): algorithm = "resultant" else: - c = d1*sum(bool(p1[i]) for i in range(d1 + 1))*\ + c = d1*sum(bool(p1[i]) for i in range(d1 + 1)) * \ d2*sum(bool(p2[i]) for i in range(d2 + 1)) if c <= N**4: algorithm = "resultant" @@ -7591,8 +7596,7 @@ cdef class Polynomial(CommutativePolynomial): return self # return 0 n = self.degree() base_ring = self._parent.base_ring() - if (is_MPolynomialRing(base_ring) or - is_PowerSeriesRing(base_ring)): + if (is_MPolynomialRing(base_ring) or is_PowerSeriesRing(base_ring)): # It is often cheaper to compute discriminant of simple # multivariate polynomial and substitute the real # coefficients into that result (see #16014). @@ -7601,13 +7605,13 @@ cdef class Polynomial(CommutativePolynomial): k = d.degree() r = n % 4 - u = -1 # (-1)**(n*(n-1)/2) + u = -1 # (-1)**(n*(n-1)/2) if r == 0 or r == 1: u = 1 try: an = self.get_coeff_c(n)**(n - k - 2) except ZeroDivisionError: - assert(n-k-2 == -1) + assert (n-k-2 == -1) # Rather than dividing the resultant by the leading coefficient, # we alter the Sylvester matrix (see #11782). mat = self.sylvester_matrix(d) @@ -7656,14 +7660,14 @@ cdef class Polynomial(CommutativePolynomial): if degree is not None: d = degree if d != degree: - raise ValueError("degree argument must be a non-negative integer, got %s"%(degree)) + raise ValueError("degree argument must be a non-negative integer, got %s" % (degree)) if len(v) < degree+1: v.reverse() v = [self.base_ring().zero()]*(degree+1-len(v)) + v elif len(v) > degree+1: v = v[:degree+1] v.reverse() - else: # len(v) == degree + 1 + else: # len(v) == degree + 1 v.reverse() else: v.reverse() @@ -8418,9 +8422,9 @@ cdef class Polynomial(CommutativePolynomial): sage.rings.abc.RealDoubleField, sage.rings.abc.ComplexDoubleField)) output_fp = isinstance(L, (sage.rings.abc.RealField, - sage.rings.abc.ComplexField, - sage.rings.abc.RealDoubleField, - sage.rings.abc.ComplexDoubleField)) + sage.rings.abc.ComplexField, + sage.rings.abc.RealDoubleField, + sage.rings.abc.ComplexDoubleField)) input_complex = isinstance(K, (sage.rings.abc.ComplexField, sage.rings.abc.ComplexDoubleField)) output_complex = isinstance(L, (sage.rings.abc.ComplexField, sage.rings.abc.ComplexDoubleField)) input_gaussian = (isinstance(K, sage.rings.abc.NumberField_quadratic) @@ -8503,20 +8507,20 @@ cdef class Polynomial(CommutativePolynomial): from sage.symbolic.constants import I coeffs = self.list() D = coeffs[1]*coeffs[1] - 4*coeffs[0]*coeffs[2] - l = None + l0 = None if D > 0: - l = [((-coeffs[1]-sqrt(D))/2/coeffs[2], 1), - ((-coeffs[1]+sqrt(D))/2/coeffs[2], 1)] + l0 = [((-coeffs[1] - sqrt(D)) / 2 / coeffs[2], 1), + ((-coeffs[1] + sqrt(D)) / 2 / coeffs[2], 1)] elif D < 0: - l = [((-coeffs[1]-I*sqrt(-D))/2/coeffs[2], 1), - ((-coeffs[1]+I*sqrt(-D))/2/coeffs[2], 1)] + l0 = [((-coeffs[1] - I * sqrt(-D)) / 2 / coeffs[2], 1), + ((-coeffs[1] + I * sqrt(-D)) / 2 / coeffs[2], 1)] elif D == 0: - l = [(-coeffs[1]/2/coeffs[2], 2)] - if l: + l0 = [(-coeffs[1] / 2 / coeffs[2], 2)] + if l0: if multiplicities: - return l + return l0 else: - return [val for val,m in l] + return [val for val, m in l0] from sage.symbolic.ring import SR vname = 'do_not_use_this_name_in_a_polynomial_coefficient' var = SR(vname) @@ -8534,7 +8538,7 @@ cdef class Polynomial(CommutativePolynomial): # and complex root isolation and for p-adic factorization if (is_IntegerRing(K) or is_RationalField(K) or isinstance(K, sage.rings.abc.AlgebraicRealField)) and \ - isinstance(L, (sage.rings.abc.AlgebraicRealField, sage.rings.abc.RealIntervalField)): + isinstance(L, (sage.rings.abc.AlgebraicRealField, sage.rings.abc.RealIntervalField)): from sage.rings.polynomial.real_roots import real_roots @@ -8564,7 +8568,7 @@ cdef class Polynomial(CommutativePolynomial): if (is_IntegerRing(K) or is_RationalField(K) or isinstance(K, sage.rings.abc.AlgebraicField_common) or input_gaussian) and \ - isinstance(L, (sage.rings.abc.ComplexIntervalField, sage.rings.abc.AlgebraicField_common)): + isinstance(L, (sage.rings.abc.ComplexIntervalField, sage.rings.abc.AlgebraicField_common)): from sage.rings.polynomial.complex_roots import complex_roots @@ -8682,7 +8686,7 @@ cdef class Polynomial(CommutativePolynomial): pass else: if multiplicities: - seq.append((rt,fac[1])) + seq.append((rt, fac[1])) else: seq.append(rt) return seq @@ -9088,7 +9092,7 @@ cdef class Polynomial(CommutativePolynomial): coeffs = [] m = Q.degree() // 2 for i in reversed(range(m + 1)): - coeffs.insert(0, Q[2*i]) # Note: degree of Q may be less than 2*i + coeffs.insert(0, Q[2*i]) # Note: degree of Q may be less than 2*i Q = (Q % (x**2 + q)**i) // x return S(coeffs), cofactor, q @@ -9294,7 +9298,7 @@ cdef class Polynomial(CommutativePolynomial): if hasattr(self.base_ring(), '_xgcd_univariate_polynomial'): return self.base_ring()._xgcd_univariate_polynomial(self, other) else: - raise NotImplementedError("%s does not provide an xgcd implementation for univariate polynomials"%self.base_ring()) + raise NotImplementedError("%s does not provide an xgcd implementation for univariate polynomials" % self.base_ring()) def rational_reconstruction(self, m, n_deg=None, d_deg=None): r""" @@ -9459,9 +9463,9 @@ cdef class Polynomial(CommutativePolynomial): sF = Pf(self) mF = Pf(m) n, d = sF.rational_reconstruction(mF, n_deg, d_deg) - l = lcm([n.denominator(), d.denominator()]) - n *= l - d *= l + lc = lcm([n.denominator(), d.denominator()]) + n *= lc + d *= lc return P(n), P(d) # n and d are unique if m.degree() > (n.degree() + d.degree()) @@ -9472,9 +9476,9 @@ cdef class Polynomial(CommutativePolynomial): if n_deg < 0 or d_deg < 0: raise ValueError("the degree bounds " - "n_deg and d_deg should be positive") + "n_deg and d_deg should be positive") - #XGCD until degree the degree of t1 surpasses the degree of n + # XGCD until degree the degree of t1 surpasses the degree of n s0 = P(0) t0 = P(1) s1 = P(m) @@ -9583,15 +9587,15 @@ cdef class Polynomial(CommutativePolynomial): _p = self._parent.coerce(p) elif p is infinity.infinity: return -self.degree() - elif is_Ideal(p) and p.ring() is self._parent: # eventually need to handle fractional ideals in the fraction field - if self._parent.base_ring().is_field(): # common case + elif is_Ideal(p) and p.ring() is self._parent: # eventually need to handle fractional ideals in the fraction field + if self._parent.base_ring().is_field(): # common case _p = p.gen() else: raise NotImplementedError else: from sage.rings.fraction_field import is_FractionField if is_FractionField(p.parent()) and self._parent.has_coerce_map_from(p.parent().ring()): - _p = self._parent.coerce(p.parent().ring()(p)) # here we require that p be integral. + _p = self._parent.coerce(p.parent().ring()(p)) # here we require that p be integral. else: raise TypeError("The polynomial, p, must have the same parent as self.") @@ -10846,13 +10850,13 @@ cdef class Polynomial(CommutativePolynomial): elif n == 1 or self.is_zero() or self.is_one(): return self elif self.degree() % n: - raise ValueError("not a %s power"%Integer(n).ordinal_str()) - elif self.get_unsafe(0).is_zero(): # We know that self is not 0, so it must have degree >= 0 + raise ValueError("not a %s power" % Integer(n).ordinal_str()) + elif self.get_unsafe(0).is_zero(): # We know that self is not 0, so it must have degree >= 0 # p = x^k q # p^(1/n) = x^(k/n) q^(1/n) i = self.valuation() - if i%n: - raise ValueError("not a %s power"%Integer(n).ordinal_str()) + if i % n: + raise ValueError("not a %s power" % Integer(n).ordinal_str()) return (self >> i).nth_root(n) << (i // n) if self.get_unsafe(0).is_one(): @@ -10871,7 +10875,7 @@ cdef class Polynomial(CommutativePolynomial): if q**n == p: return S(q) else: - raise ValueError("not a %s power"%Integer(n).ordinal_str()) + raise ValueError("not a %s power" % Integer(n).ordinal_str()) def _nth_root_series(self, long n, long prec, start=None): r""" @@ -10964,12 +10968,12 @@ cdef class Polynomial(CommutativePolynomial): raise ValueError("n (={}) must be positive".format(m)) elif m.is_one() or self.is_zero() or self.is_one(): return self - elif self.get_unsafe(0).is_zero(): # we know that self is not zero, so the degree >= 0 + elif self.get_unsafe(0).is_zero(): # we know that self is not zero, so the degree >= 0 # p = x^i q # p^(1/m) = x^(i/m) q^(1/m) i = self.valuation() if i % m: - raise ValueError("not a %s power"%m.ordinal_str()) + raise ValueError("not a %s power" % m.ordinal_str()) return (self >> i)._nth_root_series(m, prec - i // m) << (i // m) else: c = R.characteristic() @@ -10981,7 +10985,7 @@ cdef class Polynomial(CommutativePolynomial): for i in range(self.degree()+1): if self.get_unsafe(i): if i % cc: - raise ValueError("not a %s power"%m.ordinal_str()) + raise ValueError("not a %s power" % m.ordinal_str()) ans[i//cc] = self.get_unsafe(i).nth_root(cc) p = self._parent(ans) m = m // cc @@ -11077,12 +11081,16 @@ cdef class Polynomial(CommutativePolynomial): if not self.base_ring().is_integral_domain(): raise NotImplementedError("divisibility test only implemented for polynomials over an integral domain") - if p.is_zero(): return True # everything divides 0 - if self.is_zero(): return False # 0 only divides 0 + if p.is_zero(): + return True # everything divides 0 + if self.is_zero(): + return False # 0 only divides 0 try: - if self.is_unit(): return True # units divide everything + if self.is_unit(): + return True # units divide everything except NotImplementedError: - if self.is_one(): return True # if is_unit is not implemented + if self.is_one(): + return True # if is_unit is not implemented if self.degree() > p.degree(): return False @@ -11134,10 +11142,9 @@ cdef class Polynomial(CommutativePolynomial): raise ValueError("either the dictionary or the specialization must be provided") else: from sage.rings.polynomial.flatten import SpecializationMorphism - phi = SpecializationMorphism(self._parent,D) + phi = SpecializationMorphism(self._parent, D) return phi(self) - def _log_series(self, long n): r""" Return the power series expansion of logarithm of this polynomial, @@ -11335,10 +11342,10 @@ cdef list do_schoolbook_product(list x, list y, Py_ssize_t deg): return y elif d1 == 0: c = x[0] - return [c*a for a in y[:deg]] # beware of noncommutative rings + return [c * a for a in y[:deg]] # beware of noncommutative rings elif d2 == 0: c = y[0] - return [a*c for a in x[:deg]] # beware of noncommutative rings + return [a * c for a in x[:deg]] # beware of noncommutative rings coeffs = [None]*deg for k in range(deg): start = 0 if k <= d2 else k-d2 # max(0, k-d2) @@ -11384,10 +11391,10 @@ cdef list do_karatsuba_different_size(list left, list right, Py_ssize_t K_thresh return [] if n == 1: c = left[0] - return [c*a for a in right] + return [c * a for a in right] if m == 1: c = right[0] - return [a*c for a in left] # beware of noncommutative rings + return [a * c for a in left] # beware of noncommutative rings if n <= K_threshold or m <= K_threshold: return do_schoolbook_product(left, right, -1) if n == m: @@ -11434,7 +11441,7 @@ cdef list do_karatsuba_different_size(list left, list right, Py_ssize_t K_thresh @cython.boundscheck(False) @cython.wraparound(False) @cython.overflowcheck(False) -cdef list do_karatsuba(list left, list right, Py_ssize_t K_threshold,Py_ssize_t start_l, Py_ssize_t start_r,Py_ssize_t num_elts): +cdef list do_karatsuba(list left, list right, Py_ssize_t K_threshold, Py_ssize_t start_l, Py_ssize_t start_r, Py_ssize_t num_elts): """ Core routine for Karatsuba multiplication. This function works for two polynomials of the same degree. @@ -11489,8 +11496,8 @@ cdef list do_karatsuba(list left, list right, Py_ssize_t K_threshold,Py_ssize_t d = right[start_r] c = right[start_r+1] return [b*d, a*d+b*c, a*c] - return do_schoolbook_product(left[start_l:start_l+num_elts], - right[start_r:start_r+num_elts], -1) + return do_schoolbook_product(left[start_l:start_l + num_elts], + right[start_r:start_r + num_elts], -1) if num_elts == 2: # beware of noncommutative rings b = left[start_l] @@ -11524,7 +11531,7 @@ cdef list do_karatsuba(list left, list right, Py_ssize_t K_threshold,Py_ssize_t bd[e+i] = bd[e+i] + tt1[i] bd.append(tt1[e-1]) for i from 0 <= i < lenac -e: - ac[i] = ac[i] + tt1[e+i] + ac[i] = ac[i] + tt1[e + i] return bd + ac @@ -11603,10 +11610,10 @@ cdef class Polynomial_generic_dense(Polynomial): check = 0 elif not isinstance(x, (list, tuple)): # We trust that the element constructors do not send x=0 -# if x: + # if x: x = [x] # constant polynomials -# else: -# x = [] # zero polynomial + # else: + # x = [] # zero polynomial if check: self._coeffs = [R(z, **kwds) for z in x] self._normalize() @@ -11639,9 +11646,9 @@ cdef class Polynomial_generic_dense(Polynomial): Univariate Polynomial Ring in x over Univariate Polynomial Ring in y over Rational Field """ if a: - return self._new_c([a],P) + return self._new_c([a], P) else: - return self._new_c([],P) + return self._new_c([], P) def __reduce__(self): """ @@ -11710,7 +11717,7 @@ cdef class Polynomial_generic_dense(Polynomial): for i in range(ell): v[i+d] = c * x[i] cdef Polynomial_generic_dense res = self._new_c(v, self._parent) - #if not v[len(v)-1]: + # if not v[len(v)-1]: # "normalize" checks this anyway... res._normalize() return res @@ -11853,7 +11860,7 @@ cdef class Polynomial_generic_dense(Polynomial): 2*y*x^3 + (y + 3)*x^2 + (-2*y + 1)*x + 1 """ cdef Polynomial_generic_dense res - cdef Py_ssize_t check=0, i, min + cdef Py_ssize_t check = 0, i, min x = (self)._coeffs y = (right)._coeffs if len(x) > len(y): @@ -11874,7 +11881,7 @@ cdef class Polynomial_generic_dense(Polynomial): cpdef _sub_(self, right): cdef Polynomial_generic_dense res - cdef Py_ssize_t check=0, i, min + cdef Py_ssize_t check = 0, i, min x = (self)._coeffs y = (right)._coeffs if len(x) > len(y): @@ -11900,7 +11907,7 @@ cdef class Polynomial_generic_dense(Polynomial): c = (self._coeffs[0])._parent.coerce(c) v = [c * a for a in self._coeffs] cdef Polynomial_generic_dense res = self._new_c(v, self._parent) - #if not v[len(v)-1]: + # if not v[len(v)-1]: # "normalize" checks this anyway... res._normalize() return res @@ -11912,7 +11919,7 @@ cdef class Polynomial_generic_dense(Polynomial): c = (self._coeffs[0])._parent.coerce(c) v = [a * c for a in self._coeffs] cdef Polynomial_generic_dense res = self._new_c(v, self._parent) - #if not v[len(v)-1]: + # if not v[len(v)-1]: # "normalize" checks this anyway... res._normalize() return res @@ -12121,7 +12128,7 @@ cdef class Polynomial_generic_dense(Polynomial): quo.append(q) quo.reverse() - return self._new_c(quo,self._parent), self._new_c(x,self._parent)._inplace_truncate(n-1) + return self._new_c(quo, self._parent), self._new_c(x, self._parent)._inplace_truncate(n-1) cpdef Polynomial truncate(self, long n): r""" @@ -12150,10 +12157,10 @@ cdef class Polynomial_generic_dense(Polynomial): sage: type(f) """ - l = len(self._coeffs) - if n > l: - n = l - while n > 0 and not self._coeffs[n-1]: + ln = len(self._coeffs) + if n > ln: + n = ln + while n > 0 and not self._coeffs[n - 1]: n -= 1 return self._new_c(self._coeffs[:n], self._parent) @@ -12164,6 +12171,7 @@ cdef class Polynomial_generic_dense(Polynomial): self._coeffs = self._coeffs[:n] return self + def make_generic_polynomial(parent, coeffs): return parent(coeffs) @@ -12205,7 +12213,7 @@ def universal_discriminant(n): pr1 = PolynomialRing(ZZ, n + 1, 'a') pr2 = PolynomialRing(pr1, 'x') p = pr2(list(pr1.gens())) - return (1 - (n&2))*p.resultant(p.derivative())//pr1.gen(n) + return (1 - (n & 2)) * p.resultant(p.derivative()) // pr1.gen(n) cpdef Polynomial generic_power_trunc(Polynomial p, Integer n, long prec): @@ -12301,7 +12309,7 @@ cpdef list _dict_to_list(dict x, zero): return [] n = max(x.keys()) cdef list v - if isinstance(n, tuple): # a mpoly dict + if isinstance(n, tuple): # a mpoly dict n = n[0] v = [zero] * (n+1) for i, z in x.iteritems(): From 9817b917c41f44feb02fc1971d3a4d91e62f64fe Mon Sep 17 00:00:00 2001 From: Enrique Artal Date: Sat, 23 Sep 2023 09:45:52 +0200 Subject: [PATCH 09/45] homogeneize __reduce__ for uni- and multi-variate Laurent polynomials --- src/sage/rings/polynomial/laurent_polynomial.pyx | 2 +- src/sage/rings/polynomial/laurent_polynomial_ideal.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/rings/polynomial/laurent_polynomial.pyx b/src/sage/rings/polynomial/laurent_polynomial.pyx index 917943f5619..6d3168f4995 100644 --- a/src/sage/rings/polynomial/laurent_polynomial.pyx +++ b/src/sage/rings/polynomial/laurent_polynomial.pyx @@ -379,7 +379,7 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): sage: loads(dumps(elt)) == elt True """ - return LaurentPolynomial_univariate, (self._parent, self.__u, self.__n) + return LaurentPolynomial_univariate, (self.__u, self.__n) # eliminate first term in the tuple for the previous definition def _polynomial_(self, R): r""" diff --git a/src/sage/rings/polynomial/laurent_polynomial_ideal.py b/src/sage/rings/polynomial/laurent_polynomial_ideal.py index fbfa99fd8ac..c36c52957cd 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_ideal.py +++ b/src/sage/rings/polynomial/laurent_polynomial_ideal.py @@ -198,7 +198,7 @@ def __contains__(self, f): if not f or f in self.gens(): return True f = self.ring()(f) - g = f.__reduce__()[1][1] + g = f.__reduce__()[1][0] return (g in self.polynomial_ideal()) # Operations on ideals @@ -501,7 +501,7 @@ def associated_primes(self): Multivariate Laurent Polynomial Ring in x, y, z over Rational Field) """ ap = self.polynomial_ideal(saturate=False).associated_primes() - ap2 = [self.ring().ideal(id.gens(), hint=id) for Iid in ap] + ap2 = [self.ring().ideal(id.gens(), hint=id) for id in ap] return tuple(id for id in ap2 if not id.is_one()) def minimal_associated_primes(self, saturate=False): From 5591d6cd8d41856327619fd68d894dc4933e155f Mon Sep 17 00:00:00 2001 From: Enrique Artal Date: Sat, 23 Sep 2023 11:08:00 +0200 Subject: [PATCH 10/45] style --- src/sage/matrix/matrix2.pyx | 731 +++++++++--------- .../rings/polynomial/laurent_polynomial.pyx | 14 +- .../polynomial/laurent_polynomial_ring.py | 5 + 3 files changed, 386 insertions(+), 364 deletions(-) diff --git a/src/sage/matrix/matrix2.pyx b/src/sage/matrix/matrix2.pyx index 1e871d9e553..d438453318f 100644 --- a/src/sage/matrix/matrix2.pyx +++ b/src/sage/matrix/matrix2.pyx @@ -206,10 +206,10 @@ cdef class Matrix(Matrix1): from sage.matrix.constructor import matrix if self.is_sparse(): return matrix({ij: self[ij].subs(*args, **kwds) for ij in self.nonzero_positions()}, - nrows=self._nrows, ncols=self._ncols, sparse=True) + nrows=self._nrows, ncols=self._ncols, sparse=True) else: return matrix([a.subs(*args, **kwds) for a in self.list()], - nrows=self._nrows, ncols=self._ncols, sparse=False) + nrows=self._nrows, ncols=self._ncols, sparse=False) def solve_left(self, B, check=True): """ @@ -887,8 +887,8 @@ cdef class Matrix(Matrix1): # Elements of SR "remember" whether or not they are exact. # If every element in the system is exact, we can probably # still check the solution over the inexact ring SR. - check = (check and all( e.is_exact() - for e in self.list() + B.list() )) + check = (check and all(e.is_exact() + for e in self.list() + B.list())) else: check = (check and K.is_exact()) @@ -972,7 +972,7 @@ cdef class Matrix(Matrix1): raise NotFullRankError D = self.augment(B) D.echelonize() - return D.matrix_from_columns(range(self.ncols(),D.ncols())) + return D.matrix_from_columns(range(self.ncols(), D.ncols())) def pivot_rows(self): """ @@ -1072,8 +1072,8 @@ cdef class Matrix(Matrix1): for row from 0 <= row < self._nrows: tmp = [] for c in cols: -# if c<0 or c >= self._ncols: -# raise IndexError("matrix column index out of range") + # if c<0 or c >= self._ncols: + # raise IndexError("matrix column index out of range") tmp.append(self.get_unsafe(row, c)) pr = pr * sum(tmp) return pr @@ -1170,7 +1170,10 @@ cdef class Matrix(Matrix1): sage: A.elementwise_product(vector(ZZ, [1,2,3,4])) Traceback (most recent call last): ... - TypeError: no common canonical parent for objects with parents: 'Full MatrixSpace of 5 by 10 dense matrices over Integer Ring' and 'Ambient free module of rank 4 over the principal ideal domain Integer Ring' + TypeError: no common canonical parent for objects with parents: + 'Full MatrixSpace of 5 by 10 dense matrices over Integer Ring' + and 'Ambient free module of rank 4 over the principal ideal + domain Integer Ring' sage: A = matrix(2, 2, range(4)) sage: A.elementwise_product(polygen(parent(A))) @@ -1185,7 +1188,11 @@ cdef class Matrix(Matrix1): sage: A.elementwise_product(B) Traceback (most recent call last): ... - TypeError: no common canonical parent for objects with parents: 'Full MatrixSpace of 5 by 10 dense matrices over Integer Ring' and 'Full MatrixSpace of 10 by 5 dense matrices over Integer Ring' + TypeError: no common canonical parent + for objects with parents: 'Full MatrixSpace of + 5 by 10 dense matrices over Integer Ring' and + 'Full MatrixSpace of 10 by 5 dense matrices over + Integer Ring' Some pairs of rings do not have a common parent where multiplication makes sense. This will raise an error. :: @@ -1383,7 +1390,7 @@ cdef class Matrix(Matrix1): m = self._nrows n = self._ncols if not m <= n: - raise ValueError("must have m <= n, but m (=%s) and n (=%s)"%(m,n)) + raise ValueError("must have m <= n, but m (=%s) and n (=%s)" % (m, n)) for r from 1 <= r < m+1: lst = _choose(n, r) @@ -1504,8 +1511,8 @@ cdef class Matrix(Matrix1): return R.zero() pm = 0 - for cols in _choose(n,k): - for rows in _choose(m,k): + for cols in _choose(n, k): + for rows in _choose(m, k): pm = pm + self.matrix_from_rows_and_columns(rows, cols).permanent() return pm @@ -1814,14 +1821,14 @@ cdef class Matrix(Matrix1): ....: if v != [1, 16, 78, 128, 53]: ....: print("ERROR with algorithm={} use_complement=False".format(algorithm)) """ - cdef Py_ssize_t i,j + cdef Py_ssize_t i, j cdef unsigned int num_ones cdef int m = self._nrows cdef int n = self._ncols cdef int mn = min(m, n) cdef Matrix B zero = self.base_ring().zero() - one = self.base_ring().one() + one = self.base_ring().one() if algorithm is None: algorithm = "ButeraPernici" @@ -1835,7 +1842,7 @@ cdef class Matrix(Matrix1): num_ones = 1 for i in range(m): for j in range(n): - x = self.get_unsafe(i,j) + x = self.get_unsafe(i, j) if x != zero: if x != one: z2 = False @@ -1847,7 +1854,7 @@ cdef class Matrix(Matrix1): break if not z2 and (complement or algorithm == "Godsil"): - raise ValueError("coefficients must be zero or one, but we have '{}' in position ({},{}).".format(x,i,j)) + raise ValueError("coefficients must be zero or one, but we have '{}' in position ({},{}).".format(x, i, j)) if use_complement is None: use_complement = z2 and num_ones > 0.55 * m * n @@ -1861,7 +1868,7 @@ cdef class Matrix(Matrix1): complement = not complement elif algorithm == "Ryser": - b = [self.permanental_minor(k,algorithm="Ryser") + b = [self.permanental_minor(k, algorithm="Ryser") for k in range(mn + 1)] elif algorithm == "ButeraPernici": @@ -1950,9 +1957,9 @@ cdef class Matrix(Matrix1): all_rows = range(self.nrows()) all_cols = range(self.ncols()) m = [] - for rows in Combinations(all_rows,k): - for cols in Combinations(all_cols,k): - m.append(self.matrix_from_rows_and_columns(rows,cols).determinant()) + for rows in Combinations(all_rows, k): + for cols in Combinations(all_cols, k): + m.append(self.matrix_from_rows_and_columns(rows, cols).determinant()) return m def det(self, *args, **kwds): @@ -2110,13 +2117,13 @@ cdef class Matrix(Matrix1): if n == 0: d = R.one() elif n == 1: - d = self.get_unsafe(0,0) + d = self.get_unsafe(0, 0) elif n == 2: - d = self.get_unsafe(0,0)*self.get_unsafe(1,1) - self.get_unsafe(1,0)*self.get_unsafe(0,1) + d = self.get_unsafe(0, 0)*self.get_unsafe(1, 1) - self.get_unsafe(1, 0)*self.get_unsafe(0, 1) elif n == 3: - d = self.get_unsafe(0,0) * (self.get_unsafe(1,1)*self.get_unsafe(2,2) - self.get_unsafe(1,2)*self.get_unsafe(2,1)) \ - - self.get_unsafe(1,0) * (self.get_unsafe(0,1)*self.get_unsafe(2,2) - self.get_unsafe(0,2)*self.get_unsafe(2,1)) \ - + self.get_unsafe(2,0) * (self.get_unsafe(0,1)*self.get_unsafe(1,2) - self.get_unsafe(0,2)*self.get_unsafe(1,1)) + d = self.get_unsafe(0, 0) * (self.get_unsafe(1, 1)*self.get_unsafe(2, 2) - self.get_unsafe(1, 2)*self.get_unsafe(2, 1)) \ + - self.get_unsafe(1, 0) * (self.get_unsafe(0, 1)*self.get_unsafe(2, 2) - self.get_unsafe(0, 2)*self.get_unsafe(2, 1)) \ + + self.get_unsafe(2, 0) * (self.get_unsafe(0, 1)*self.get_unsafe(1, 2) - self.get_unsafe(0, 2)*self.get_unsafe(1, 1)) self.cache('det', d) return d @@ -2130,7 +2137,7 @@ cdef class Matrix(Matrix1): d = R(self.__pari__().matdet()) else: # Lift to ZZ and compute there. - d = R(self.apply_map(lambda x : x.lift_centered()).det()) + d = R(self.apply_map(lambda x: x.lift_centered()).det()) self.cache('det', d) return d @@ -2186,18 +2193,18 @@ cdef class Matrix(Matrix1): """ cdef Py_ssize_t n, i if level == 2: - return self.get_unsafe(0,0) * self.get_unsafe(1,1) - self.get_unsafe(0,1) * self.get_unsafe(1,0) + return self.get_unsafe(0, 0) * self.get_unsafe(1, 1) - self.get_unsafe(0, 1) * self.get_unsafe(1, 0) else: level -= 1 - d = self.get_unsafe(level,level) * self._det_by_minors(level) + d = self.get_unsafe(level, level) * self._det_by_minors(level) # on each iteration, row i will be missing in the first (level) rows # swapping is much faster than taking submatrices for i from level > i >= 0: self.swap_rows(level, i) if (level - i) % 2: - d -= self.get_unsafe(level,level) * self._det_by_minors(level) + d -= self.get_unsafe(level, level) * self._det_by_minors(level) else: - d += self.get_unsafe(level,level) * self._det_by_minors(level) + d += self.get_unsafe(level, level) * self._det_by_minors(level) # undo all our permutations to get us back to where we started for i from 0 <= i < level: self.swap_rows(level, i) @@ -2648,7 +2655,7 @@ cdef class Matrix(Matrix1): """ M = self.parent().change_ring(phi.codomain()) if self.is_sparse(): - values = {(i,j): phi(z) for (i,j),z in self.dict()} + values = {(i, j): phi(z) for (i, j), z in self.dict()} else: values = [phi(z) for z in self.list()] image = M(values) @@ -2757,7 +2764,7 @@ cdef class Matrix(Matrix1): return self.dense_matrix() if self.is_sparse(): - values = {(i,j): phi(v) for (i,j),v in self.dict().iteritems()} + values = {(i, j): phi(v) for (i, j), v in self.dict().iteritems()} if R is None: R = sage.structure.sequence.Sequence(values.values()).universe() else: @@ -2775,7 +2782,7 @@ cdef class Matrix(Matrix1): else: from sage.matrix.matrix_space import MatrixSpace M = MatrixSpace(R, self._nrows, - self._ncols, sparse=sparse) + self._ncols, sparse=sparse) image = M(values) if self._subdivisions is not None: image.subdivide(*self.subdivisions()) @@ -2886,7 +2893,7 @@ cdef class Matrix(Matrix1): # At least check that the minimal polynomial kills the matrix tester.assertTrue(self.minpoly().subs(x=self).is_zero()) - def charpoly(self, var = 'x', algorithm = None): + def charpoly(self, var='x', algorithm=None): r""" Returns the characteristic polynomial of self, as a polynomial over the base ring. @@ -3081,7 +3088,7 @@ cdef class Matrix(Matrix1): self.cache('charpoly', f) return f - def _charpoly_df(self, var = 'x'): + def _charpoly_df(self, var='x'): r""" Computes the characteristic polynomial of ``self`` without divisions. @@ -3169,10 +3176,10 @@ cdef class Matrix(Matrix1): # Extract parameters # - cdef Matrix M = self - n = M._ncols - R = M._base_ring - S = PolynomialRing(R, var) + cdef Matrix M = self + n = M._ncols + R = M._base_ring + S = PolynomialRing(R, var) # Corner cases # N.B. We already tested for M to be square, hence we do not need to @@ -3197,11 +3204,11 @@ cdef class Matrix(Matrix1): from sage.matrix.constructor import matrix F = [R.zero()] * n - cdef Matrix a = matrix(R, n-1, n) + cdef Matrix a = matrix(R, n - 1, n) A = [R.zero()] * n F[0] = - M.get_unsafe(0, 0) - for t in range(1,n): + for t in range(1, n): # Set a(1, t) to be M(<=t, t) # @@ -3372,7 +3379,7 @@ cdef class Matrix(Matrix1): [] """ n = min(self.nrows(), self.ncols()) - return [self[i,i] for i in range(n)] + return [self[i, i] for i in range(n)] def trace(self): """ @@ -3409,7 +3416,7 @@ cdef class Matrix(Matrix1): cdef object s s = R(0) for i from 0 <= i < self._nrows: - s = s + self.get_unsafe(i,i) + s = s + self.get_unsafe(i, i) return s def trace_of_product(self, Matrix other): @@ -3467,11 +3474,11 @@ cdef class Matrix(Matrix1): H = self.change_ring(K) H.hessenbergize() except TypeError as msg: - raise TypeError("%s\nHessenberg form only possible for matrices over a field"%msg) + raise TypeError("%s\nHessenberg form only possible for matrices over a field" % msg) else: H = self.__copy__() H.hessenbergize() - #end if + # end if self.cache('hessenberg_form', H) return H @@ -3515,7 +3522,7 @@ cdef class Matrix(Matrix1): cdef Py_ssize_t i, j, m, n, r n = self._nrows - tm = verbose("Computing Hessenberg Normal Form of %sx%s matrix"%(n,n)) + tm = verbose("Computing Hessenberg Normal Form of %sx%s matrix" % (n, n)) if not self.is_square(): raise TypeError("self must be square") @@ -3542,20 +3549,20 @@ cdef class Matrix(Matrix1): if i != -1: # Found a nonzero entry in column m-1 that is strictly below row m # Now set i to be the first nonzero position >= m in column m-1 - if not self.get_is_zero_unsafe(m,m-1): + if not self.get_is_zero_unsafe(m, m - 1): i = m - t = self.get_unsafe(i,m-1) + t = self.get_unsafe(i, m - 1) t_inv = None if i > m: - self.swap_rows_c(i,m) + self.swap_rows_c(i, m) # We must do the corresponding column swap to # maintain the characteristic polynomial (which is # an invariant of Hessenberg form) - self.swap_columns_c(i,m) + self.swap_columns_c(i, m) # Now the nonzero entry in position (m,m-1) is t. # Use t to clear the entries in column m-1 below m. for j from m+1 <= j < n: - x = self.get_unsafe(j, m-1) + x = self.get_unsafe(j, m - 1) if x != zero: if t_inv is None: t_inv = one / t @@ -3566,7 +3573,7 @@ cdef class Matrix(Matrix1): # column m, and we're only worried about column m-1 right now. # Add u*column_j to column_m. self.add_multiple_of_column_c(m, j, u, 0) - verbose("Finished Hessenberg Normal Form of %sx%s matrix"%(n,n),tm) + verbose("Finished Hessenberg Normal Form of %sx%s matrix" % (n, n), tm) def _charpoly_hessenberg(self, var): """ @@ -3617,9 +3624,9 @@ cdef class Matrix(Matrix1): n = self._nrows cdef Matrix c - c = H.new_matrix(nrows=n+1,ncols=n+1) # the 0 matrix + c = H.new_matrix(nrows=n + 1, ncols=n + 1) # the 0 matrix one = H._coerce_element(1) - c.set_unsafe(0,0,one) + c.set_unsafe(0, 0, one) for m from 1 <= m <= n: # Set the m-th row of c to (x - H[m-1,m-1])*c[m-1] = x*c[m-1] - H[m-1,m-1]*c[m-1] @@ -3627,20 +3634,21 @@ cdef class Matrix(Matrix1): # shifted to the right by one. We then add # -H[m-1,m-1]*c[m-1] to the resulting m-th row. for i from 1 <= i <= n: - c.set_unsafe(m, i, c.get_unsafe(m-1,i-1)) - c.add_multiple_of_row_c(m, m-1, -H.get_unsafe(m-1, m-1), 0) + c.set_unsafe(m, i, c.get_unsafe(m - 1, i - 1)) + c.add_multiple_of_row_c(m, m-1, -H.get_unsafe(m - 1, m - 1), 0) t = one for i from 1 <= i < m: - t = t * H.get_unsafe(m-i,m-i-1) + t = t * H.get_unsafe(m - i, m - i - 1) # Set the m-th row of c to c[m] - t*H[m-i-1,m-1]*c[m-i-1] - c.add_multiple_of_row_c(m, m-i-1, - t*H.get_unsafe(m-i-1,m-1), 0) + c.add_multiple_of_row_c(m, m - i - 1, -t * H.get_unsafe(m - i - 1, m - 1), 0) # The answer is now the n-th row of c. v = PyList_New(n+1) # this is really sort of v = []..." for i from 0 <= i <= n: # Finally, set v[i] = c[n,i] - o = c.get_unsafe(n,i) - Py_INCREF(o); PyList_SET_ITEM(v, i, o) + o = c.get_unsafe(n, i) + Py_INCREF(o) + PyList_SET_ITEM(v, i, o) R = self._base_ring[var] # polynomial ring over the base ring return R(v) @@ -3758,12 +3766,12 @@ cdef class Matrix(Matrix1): [0 0 1] """ from sage.matrix.matrix_space import MatrixSpace - tm = verbose("computing right kernel matrix over a number field for %sx%s matrix" % (self.nrows(), self.ncols()),level=1) + tm = verbose("computing right kernel matrix over a number field for %sx%s matrix" % (self.nrows(), self.ncols()), level=1) basis = self.__pari__().matker() # Coerce PARI representations into the number field R = self.base_ring() basis = [[R(x) for x in row] for row in basis] - verbose("done computing right kernel matrix over a number field for %sx%s matrix" % (self.nrows(), self.ncols()),level=1,t=tm) + verbose("done computing right kernel matrix over a number field for %sx%s matrix" % (self.nrows(), self.ncols()), level=1, t=tm) return 'pivot-pari-numberfield', MatrixSpace(R, len(basis), ncols=self._ncols)(basis) def _right_kernel_matrix_over_field(self, *args, **kwds): @@ -3817,7 +3825,7 @@ cdef class Matrix(Matrix1): [0 0 1] """ from sage.matrix.matrix_space import MatrixSpace - tm = verbose("computing right kernel matrix over an arbitrary field for %sx%s matrix" % (self.nrows(), self.ncols()),level=1) + tm = verbose("computing right kernel matrix over an arbitrary field for %sx%s matrix" % (self.nrows(), self.ncols()), level=1) E = self.echelon_form(*args, **kwds) pivots = E.pivots() pivots_set = set(pivots) @@ -3846,7 +3854,7 @@ cdef class Matrix(Matrix1): basis.append(v) M = MS(basis, coerce=False) tm = verbose("done computing right kernel matrix over an arbitrary field for %sx%s matrix" - % (self.nrows(), self.ncols()),level=1,t=tm) + % (self.nrows(), self.ncols()), level=1, t=tm) return 'pivot-generic', M def _right_kernel_matrix_over_domain(self): @@ -3910,7 +3918,7 @@ cdef class Matrix(Matrix1): cdef Py_ssize_t i, nrows = self._nrows for i in range(self._ncols): if i >= nrows or d[i, i] == 0: - basis.append( v.column(i) ) + basis.append(v.column(i)) verbose("done computing right kernel matrix over a domain for %sx%s matrix" % (self.nrows(), self.ncols()), level=1, t=tm) return 'computed-smith-form', self.new_matrix(nrows=len(basis), ncols=self._ncols, entries=basis) @@ -4501,7 +4509,7 @@ cdef class Matrix(Matrix1): if algorithm is None: algorithm = 'default' elif algorithm not in ['default', 'generic', 'flint', 'pari', 'padic', 'pluq']: - raise ValueError("matrix kernel algorithm '%s' not recognized" % algorithm ) + raise ValueError("matrix kernel algorithm '%s' not recognized" % algorithm) elif algorithm == 'padic' and not (is_IntegerRing(R) or is_RationalField(R)): raise ValueError("'padic' matrix kernel algorithm only available over the rationals and the integers, not over %s" % R) elif algorithm == 'flint' and not (is_IntegerRing(R) or is_RationalField(R)): @@ -4518,7 +4526,7 @@ cdef class Matrix(Matrix1): if basis is None: basis = 'default' elif basis not in ['default', 'computed', 'echelon', 'pivot', 'LLL']: - raise ValueError("matrix kernel basis format '%s' not recognized" % basis ) + raise ValueError("matrix kernel basis format '%s' not recognized" % basis) elif basis == 'pivot' and R not in _Fields: raise ValueError('pivot basis only available over a field, not over %s' % R) elif basis == 'LLL' and not is_IntegerRing(R): @@ -4552,7 +4560,8 @@ cdef class Matrix(Matrix1): # Third: generic first, if requested explicitly # then try specialized class methods, and finally # delegate to ad-hoc methods in greater generality - M = None; format = '' + M = None + format = '' if algorithm == 'generic': format, M = self._right_kernel_matrix_over_field() @@ -4582,7 +4591,7 @@ cdef class Matrix(Matrix1): # zero columns as well. (eg PARI?) This could be fixed at the source # with a careful study of the phenomenon. Start by commenting out # the following and running doctests in sage/matrix - if M.nrows()==0 and M.ncols()!=self.ncols(): + if M.nrows() == 0 and M.ncols() != self.ncols(): M = M.new_matrix(nrows=0, ncols=self.ncols()) # Convert basis to requested type and return the matrix @@ -5145,10 +5154,10 @@ cdef class Matrix(Matrix1): if K is not None: return K - tm = verbose("computing left kernel for %sx%s matrix" % (self.nrows(), self.ncols()),level=1) + tm = verbose("computing left kernel for %sx%s matrix" % (self.nrows(), self.ncols()), level=1) K = self.transpose().right_kernel(*args, **kwds) self.cache('left_kernel', K) - verbose("done computing left kernel for %sx%s matrix" % (self.nrows(), self.ncols()),level=1,t=tm) + verbose("done computing left kernel for %sx%s matrix" % (self.nrows(), self.ncols()), level=1, t=tm) return K kernel = left_kernel @@ -5520,15 +5529,15 @@ cdef class Matrix(Matrix1): False) ] """ if algorithm == 'kernel' or self.base_ring() not in _Fields: - return self._decomposition_using_kernels(is_diagonalizable = is_diagonalizable, dual=dual) + return self._decomposition_using_kernels(is_diagonalizable=is_diagonalizable, dual=dual) elif algorithm == 'spin': - X = self._decomposition_spin_generic(is_diagonalizable = is_diagonalizable) + X = self._decomposition_spin_generic(is_diagonalizable=is_diagonalizable) if dual: - Y = self.transpose()._decomposition_spin_generic(is_diagonalizable = is_diagonalizable) + Y = self.transpose()._decomposition_spin_generic(is_diagonalizable=is_diagonalizable) return X, Y return X else: - raise ValueError("no algorithm '%s'"%algorithm) + raise ValueError("no algorithm '%s'" % algorithm) def _decomposition_spin_generic(self, is_diagonalizable=False): r""" @@ -5558,13 +5567,13 @@ cdef class Matrix(Matrix1): if len(F) == 1: V = self.base_ring()**self.nrows() - return decomp_seq([(V,F[0][1]==1)]) + return decomp_seq([(V, F[0][1] == 1)]) V = self.base_ring()**self.nrows() v = V.random_element() num_iterates = max([0] + [f.degree() - g.degree() for g, _ in F if g.degree() > 1]) + 1 - S = [ ] + S = [] F.sort() for i in range(len(F)): @@ -5574,11 +5583,11 @@ cdef class Matrix(Matrix1): # Just use kernel -- much easier. B = self.__copy__() for k from 0 <= k < self.nrows(): - B[k,k] += g[0] + B[k, k] += g[0] if m > 1 and not is_diagonalizable: B = B**m W = B.kernel() - E.append((W, m==1)) + E.append((W, m == 1)) continue # General case, i.e., deg(g) > 1: @@ -5591,40 +5600,40 @@ cdef class Matrix(Matrix1): v = h.list() while len(S) < tries: - t = verbose('%s-spinning %s-th random vector'%(num_iterates, len(S)), level=2, caller_name='generic spin decomp') + t = verbose('%s-spinning %s-th random vector' % (num_iterates, len(S)), level=2, caller_name='generic spin decomp') S.append(self.iterates(V.random_element(), num_iterates)) verbose('done spinning', level=2, t=t, caller_name='generic spin decomp') for j in range(0 if W is None else W.nrows() // g.degree(), len(S)): # Compute one element of the kernel of g(A)**m. - t = verbose('compute element of kernel of g(A), for g of degree %s'%g.degree(),level=2, + t = verbose('compute element of kernel of g(A), for g of degree %s' % g.degree(), level=2, caller_name='generic spin decomp') w = S[j].linear_combination_of_rows(h.list()) - t = verbose('done computing element of kernel of g(A)', t=t,level=2, caller_name='generic spin decomp') + t = verbose('done computing element of kernel of g(A)', t=t, level=2, caller_name='generic spin decomp') # Get the rest of the kernel. - t = verbose('fill out rest of kernel',level=2, caller_name='generic spin decomp') + t = verbose('fill out rest of kernel', level=2, caller_name='generic spin decomp') if W is None: W = self.iterates(w, g.degree()) else: W = W.stack(self.iterates(w, g.degree())) - t = verbose('finished filling out more of kernel',level=2, t=t, caller_name='generic spin decomp') + t = verbose('finished filling out more of kernel', level=2, t=t, caller_name='generic spin decomp') if W.rank() == m * g.degree(): t = verbose('now computing row space', level=2, caller_name='generic spin decomp') W.echelonize() - E.append((W.row_space(), m==1)) - verbose('computed row space', level=2,t=t, caller_name='generic spin decomp') + E.append((W.row_space(), m == 1)) + verbose('computed row space', level=2, t=t, caller_name='generic spin decomp') break else: - verbose('we have not yet generated all the kernel (rank so far=%s, target rank=%s)'%( + verbose('we have not yet generated all the kernel (rank so far=%s, target rank=%s)' % ( W.rank(), m*g.degree()), level=2, caller_name='generic spin decomp') tries += 1 if tries > 1000*m: # avoid an insanely long infinite loop raise RuntimeError("likely bug in decomposition") # end if - #end while - #end for + # end while + # end for return E def _decomposition_using_kernels(self, is_diagonalizable=False, dual=False): @@ -5648,30 +5657,30 @@ cdef class Matrix(Matrix1): V = self.column_ambient_module() m = F[0][1] if dual: - return decomp_seq([(V, m==1)]), decomp_seq([(V, m==1)]) + return decomp_seq([(V, m == 1)]), decomp_seq([(V, m == 1)]) else: - return decomp_seq([(V, m==1)]) + return decomp_seq([(V, m == 1)]) F.sort() for g, m in f.factor(): - t = verbose('decomposition -- Computing g(self) for an irreducible factor g of degree %s'%g.degree(),level=2) + t = verbose('decomposition -- Computing g(self) for an irreducible factor g of degree %s' % g.degree(), level=2) if is_diagonalizable: B = g(self) else: B = g(self) - t2 = verbose('decomposition -- raising g(self) to the power %s'%m,level=2) + t2 = verbose('decomposition -- raising g(self) to the power %s' % m, level=2) B = B ** m - verbose('done powering',t2) + verbose('done powering', t2) t = verbose('decomposition -- done computing g(self)', level=2, t=t) - E.append((B.kernel(), m==1)) + E.append((B.kernel(), m == 1)) t = verbose('decomposition -- time to compute kernel', level=2, t=t) if dual: - Edual.append((B.transpose().kernel(), m==1)) + Edual.append((B.transpose().kernel(), m == 1)) verbose('decomposition -- time to compute dual kernel', level=2, t=t) if dual: return E, Edual return E - def decomposition_of_subspace(self, M, check_restrict = True, **kwds): + def decomposition_of_subspace(self, M, check_restrict=True, **kwds): """ Suppose the right action of self on M leaves M invariant. Return the decomposition of M as a list of pairs (W, is_irred) where @@ -5747,7 +5756,7 @@ cdef class Matrix(Matrix1): if not self.is_square(): raise ArithmeticError("self must be a square matrix") if M.base_ring() != self.base_ring(): - raise ArithmeticError("base rings must be the same, but self is over %s and module is over %s"%( + raise ArithmeticError("base rings must be the same, but self is over %s and module is over %s" % ( self.base_ring(), M.base_ring())) if M.degree() != self.ncols(): raise ArithmeticError("M must be a subspace of an %s-dimensional space" % self.ncols()) @@ -5755,16 +5764,18 @@ cdef class Matrix(Matrix1): time = verbose(t=0) # 1. Restrict - B = self.restrict(M, check = check_restrict) + B = self.restrict(M, check=check_restrict) time0 = verbose("decompose restriction -- ", time) # 2. Decompose restriction D = B.decomposition(**kwds) - sum_dim = sum([A.dimension() for A,_ in D]) + sum_dim = sum([A.dimension() for A, _ in D]) assert sum_dim == M.dimension(), \ "bug in decomposition; " + \ - "the sum of the dimensions (=%s) of the factors must equal the dimension (%s) of the acted on space:\nFactors found: %s\nSpace: %s"%(sum_dim, M.dimension(), D, M) + "the sum of the dimensions (=%s) of the factors must equal" + \ + "the dimension (%s) of the acted on space:\nFactors found:" + \ + "%s\nSpace: %s" % (sum_dim, M.dimension(), D, M) # 3. Lift decomposition to subspaces of ambient vector space. # Each basis vector for an element of D defines a linear @@ -5834,7 +5845,7 @@ cdef class Matrix(Matrix1): """ if not isinstance(V, sage.modules.free_module.FreeModule_generic): raise TypeError("V must be a free module") - #if V.base_ring() != self.base_ring(): + # if V.base_ring() != self.base_ring(): # raise ValueError("matrix and module must have the same base ring, but matrix is over %s and module is over %s"%(self.base_ring(), V.base_ring())) if V.degree() != self.nrows(): raise IndexError("degree of V (=%s) must equal number of rows of self (=%s)" % (V.degree(), self.nrows())) @@ -6016,7 +6027,8 @@ cdef class Matrix(Matrix1): sage: t.charpoly() # needs sage.libs.pari x^3 - 12*x^2 - 18*x """ - i = int(i); t=int(t) + i = int(i) + t = int(t) if self.nrows() != self.ncols(): raise ArithmeticError("self must be a square matrix") n = self.nrows() @@ -6421,7 +6433,7 @@ cdef class Matrix(Matrix1): if algebraic_multiplicity: return x else: - return Sequence([(e[0],e[1]) for e in x], cr=True, check=False) + return Sequence([(e[0], e[1]) for e in x], cr=True, check=False) # Possible improvements: # algorithm for dual_eigenvector in sage/modular/hecke/module.py @@ -6433,7 +6445,7 @@ cdef class Matrix(Matrix1): G = self.fcp() # factored characteristic polynomial V = [] - i = -1 # variable name index, increments for each eigenvalue + i = -1 # variable name index, increments for each eigenvalue for h, e in G: i = i + 1 if h.degree() == 1: @@ -6445,7 +6457,7 @@ cdef class Matrix(Matrix1): W = A.kernel() V.append((alpha, W.ambient_module().span_of_basis(W.basis()), e)) else: - F = h.root_field('{0}{1}'.format(var,i)) + F = h.root_field('{0}{1}'.format(var, i)) alpha = F.gen(0) A = self.change_ring(F) - alpha W = A.kernel() @@ -6469,7 +6481,7 @@ cdef class Matrix(Matrix1): if algebraic_multiplicity: return V else: - return Sequence([(e[0],e[1]) for e in V], cr=True, check=False) + return Sequence([(e[0], e[1]) for e in V], cr=True, check=False) left_eigenspaces = eigenspaces_left @@ -6673,7 +6685,7 @@ cdef class Matrix(Matrix1): if algebraic_multiplicity: return x else: - return Sequence([(e[0],e[1]) for e in x], cr=True, check=False) + return Sequence([(e[0], e[1]) for e in x], cr=True, check=False) V = self.transpose().eigenspaces_left(format=format, var=var, algebraic_multiplicity=True) @@ -6681,7 +6693,7 @@ cdef class Matrix(Matrix1): if algebraic_multiplicity: return V else: - return Sequence([(e[0],e[1]) for e in V], cr=True, check=False) + return Sequence([(e[0], e[1]) for e in V], cr=True, check=False) right_eigenspaces = eigenspaces_right @@ -6794,7 +6806,7 @@ cdef class Matrix(Matrix1): warn("Using generic algorithm for an inexact ring, which will probably give incorrect results due to numerical precision issues.") if not extend: - return Sequence(r for r,m in self.charpoly().roots() for _ in range(m)) + return Sequence(r for r, m in self.charpoly().roots() for _ in range(m)) # now we need to find a natural algebraic closure for the base ring K = self.base_ring() @@ -6814,7 +6826,7 @@ cdef class Matrix(Matrix1): if f.degree() == 1: res.extend([-f.constant_coefficient()]*e) else: - for r,ee in f.change_ring(A).roots(): + for r, ee in f.change_ring(A).roots(): res.extend([r]*(e*ee)) eigenvalues = Sequence(res) @@ -6925,7 +6937,7 @@ cdef class Matrix(Matrix1): V = [] from sage.categories.homset import hom eigenspaces = self.eigenspaces_left(format='galois', algebraic_multiplicity=True) - evec_list=[] + evec_list = [] n = self._nrows evec_eval_list = [] F = self.base_ring().fraction_field() @@ -6947,7 +6959,7 @@ cdef class Matrix(Matrix1): m = hom(eigval.parent(), e.parent(), e) space = (e.parent())**n evec_list = [(space)([m(i) for i in v]) for v in eigbasis] - evec_eval_list.append( (e, evec_list, eigmult)) + evec_eval_list.append((e, evec_list, eigmult)) return evec_eval_list @@ -7229,7 +7241,7 @@ cdef class Matrix(Matrix1): "failed to compute eigenvectors for eigenvalue %s, " "check eigenvectors_left() for partial results" % e[0]) P = matrix(rows) - return D,P + return D, P left_eigenmatrix = eigenmatrix_left @@ -7397,9 +7409,9 @@ cdef class Matrix(Matrix1): True """ - D,P = self.transpose().eigenmatrix_left(None if other is None - else other.transpose()) - return D,P.transpose() + D, P = self.transpose().eigenmatrix_left(None if other is None + else other.transpose()) + return D, P.transpose() right_eigenmatrix = eigenmatrix_right @@ -7615,7 +7627,7 @@ cdef class Matrix(Matrix1): d = self.dense_matrix().echelon_form(**kwds) for c from 0 <= c < self.ncols(): for r from 0 <= r < self.nrows(): - self.set_unsafe(r, c, d.get_unsafe(r,c)) + self.set_unsafe(r, c, d.get_unsafe(r, c)) self.clear_cache() self.cache('pivots', d.pivots()) self.cache('in_echelon_form', True) @@ -7623,11 +7635,11 @@ cdef class Matrix(Matrix1): try: a, d, p = self._echelon_form_PID() except TypeError as msg: - raise NotImplementedError("%s\nechelon form over %s not yet implemented"%(msg, self.base_ring())) + raise NotImplementedError("%s\nechelon form over %s not yet implemented" % (msg, self.base_ring())) for c from 0 <= c < self.ncols(): for r from 0 <= r < self.nrows(): - self.set_unsafe(r, c, d.get_unsafe(r,c)) + self.set_unsafe(r, c, d.get_unsafe(r, c)) self.clear_cache() self.cache('pivots', tuple(p)) self.cache('in_echelon_form', True) @@ -7827,7 +7839,7 @@ cdef class Matrix(Matrix1): kwds['algorithm'] = algorithm return self._echelonize_ring(**kwds) except ArithmeticError as msg: - raise NotImplementedError("%s\nEchelon form not implemented over '%s'."%(msg,basring)) + raise NotImplementedError("%s\nEchelon form not implemented over '%s'." % (msg, basring)) def echelon_form(self, algorithm="default", cutoff=0, **kwds): r""" @@ -7922,7 +7934,7 @@ cdef class Matrix(Matrix1): if algorithm == 'default': v = E.echelonize(cutoff=cutoff, **kwds) else: - v = E.echelonize(algorithm = algorithm, cutoff=cutoff, **kwds) + v = E.echelonize(algorithm=algorithm, cutoff=cutoff, **kwds) E.set_immutable() # so we can cache the echelon form. self.cache('echelon_form', E) if v is not None: @@ -8068,7 +8080,7 @@ cdef class Matrix(Matrix1): if self.fetch('in_echelon_form'): return self.fetch('pivots') - tm = verbose('generic in-place Gauss elimination on %s x %s matrix using %s algorithm'%(self._nrows, self._ncols, algorithm)) + tm = verbose('generic in-place Gauss elimination on %s x %s matrix using %s algorithm' % (self._nrows, self._ncols, algorithm)) self.check_mutability() cdef Matrix A @@ -8124,21 +8136,21 @@ cdef class Matrix(Matrix1): if algorithm == 'partial_pivoting': for r in range(start_row, nr): - abs_val = A.get_unsafe(r,c).abs() + abs_val = A.get_unsafe(r, c).abs() if abs_val > max_abs_val: max_abs_val = abs_val best_r = r elif algorithm == 'scaled_partial_pivoting': for r in range(start_row, nr): if scale_factors[r]: - abs_val = A.get_unsafe(r,c).abs() / scale_factors[r] + abs_val = A.get_unsafe(r, c).abs() / scale_factors[r] if abs_val > max_abs_val: max_abs_val = abs_val best_r = r - else: # algorithm == 'scaled_partial_pivoting_valuation': + else: # algorithm == 'scaled_partial_pivoting_valuation': for r in range(start_row, nr): if scale_factors[r] is not None: - abs_val = scale_factors[r] - A.get_unsafe(r,c).valuation() + abs_val = scale_factors[r] - A.get_unsafe(r, c).valuation() if max_abs_val is None or abs_val > max_abs_val: max_abs_val = abs_val best_r = r @@ -8481,7 +8493,7 @@ cdef class Matrix(Matrix1): permutations.append( (PermutationGroupElement([p(1 + i) for i in range(nrows)]), PermutationGroupElement([p(1 + nrows + i) - nrows for i in range(ncols)]) - )) + )) return permutations def permutation_normal_form(self, check=False): @@ -8588,14 +8600,14 @@ cdef class Matrix(Matrix1): # Sort each row with respect to S for the first matrix in X = MS X = copy(MS) SM = [sorted([(S[j], X[0][k][j]) for j in range(ncols)], reverse=True) - for k in range(l, nrows)] + for k in range(l, nrows)] SM = [[k[1] for k in s] for s in SM] # and pick the maximal row b = max(SM) # Find all rows equal to the maximal (potential new cases) m = [[j for j in range(nrows - l) if SM[j] == b]] - w = 0 # keeps track of how many entries we have removed from MS + w = 0 # keeps track of how many entries we have removed from MS # Let us find the maximal row in each of the entries in X = MS for i in range(1, len(X)): SN = [sorted([(S[j], X[i][k][j]) for j in range(ncols)], reverse=True) @@ -8731,7 +8743,7 @@ cdef class Matrix(Matrix1): truth, perm = N_B.is_isomorphic(M_B, certificate=True, edge_labels=True) from sage.groups.perm_gps.constructor import PermutationGroupElement if perm: - s = sorted(perm.items(), key=lambda x:x[0]) + s = sorted(perm.items(), key=lambda x: x[0]) row_perms = [value for k, value in s if k <= nrows] col_perms = [value - nrows for k, value in s if k > nrows] perm = (PermutationGroupElement(row_perms), PermutationGroupElement(col_perms)) @@ -8782,16 +8794,15 @@ cdef class Matrix(Matrix1): output = self.new_matrix(self._nrows, right._ncols) # The following used to be a little faster, but meanwhile # the previous line is faster. - #if self.is_sparse(): + # if self.is_sparse(): # output = self.matrix_space(self._nrows, right._ncols, sparse = True)(0) - #else: + # else: # output = self.matrix_space(self._nrows, right._ncols, sparse = False).zero_matrix().__copy__() - self_window = self.matrix_window() - right_window = right.matrix_window() + self_window = self.matrix_window() + right_window = right.matrix_window() output_window = output.matrix_window() - from . import strassen strassen.strassen_window_multiply(output_window, self_window, right_window, cutoff) return output @@ -8813,7 +8824,7 @@ cdef class Matrix(Matrix1): [ 0 0 0 0] [ 0 0 0 0] """ - tm = verbose('strassen echelon of %s x %s matrix'%(self._nrows, self._ncols)) + tm = verbose('strassen echelon of %s x %s matrix' % (self._nrows, self._ncols)) self.check_mutability() @@ -8836,8 +8847,8 @@ cdef class Matrix(Matrix1): verbose('done with strassen', tm) cpdef matrix_window(self, Py_ssize_t row=0, Py_ssize_t col=0, - Py_ssize_t nrows=-1, Py_ssize_t ncols=-1, - bint check=1): + Py_ssize_t nrows=-1, Py_ssize_t ncols=-1, + bint check=1): """ Return the requested matrix window. @@ -9091,7 +9102,7 @@ cdef class Matrix(Matrix1): """ if self._subdivisions is None: self._subdivisions = ([0, self._nrows], [0, self._ncols]) - key = "subdivision %s %s"%(i,j) + key = "subdivision %s %s" % (i, j) sd = self.fetch(key) if sd is None: sd = self[self._subdivisions[0][i]:self._subdivisions[0][i+1], @@ -9137,13 +9148,13 @@ cdef class Matrix(Matrix1): """ if self._subdivisions is None: if not i and not j: - return self[x,y] + return self[x, y] else: - raise IndexError("No such submatrix %s, %s"%(i,j)) + raise IndexError("No such submatrix %s, %s" % (i, j)) if x >= self._subdivisions[0][i+1]-self._subdivisions[0][i] or \ y >= self._subdivisions[1][j+1]-self._subdivisions[1][j]: - raise IndexError("Submatrix %s,%s has no entry %s,%s"%(i,j, x, y)) - return self[self._subdivisions[0][i] + x , self._subdivisions[1][j] + y] + raise IndexError("Submatrix %s,%s has no entry %s,%s" % (i, j, x, y)) + return self[self._subdivisions[0][i] + x, self._subdivisions[1][j] + y] def _subdivide_on_augment(self, left, right): r""" @@ -9454,7 +9465,7 @@ cdef class Matrix(Matrix1): for i from 0 <= i < self._nrows: for j from 0 <= j < self._ncols: self.set_unsafe(i, j, R._random_nonzero_element(*args, - **kwds)) + **kwds)) else: num = int(self._nrows * self._ncols * density) for i from 0 <= i < num: @@ -9494,7 +9505,7 @@ cdef class Matrix(Matrix1): """ return self.is_scalar(self.base_ring().one()) - def is_scalar(self, a = None): + def is_scalar(self, a=None): """ Return True if this matrix is a scalar matrix. @@ -9529,13 +9540,13 @@ cdef class Matrix(Matrix1): if a is None: if self._nrows == 0: return True - a = self.get_unsafe(0,0) + a = self.get_unsafe(0, 0) else: a = self.base_ring()(a) for i in range(self._nrows): for j in range(self._ncols): if i != j: - if not self.get_unsafe(i,j).is_zero(): + if not self.get_unsafe(i, j).is_zero(): return False else: if self.get_unsafe(i, i) != a: @@ -9572,7 +9583,7 @@ cdef class Matrix(Matrix1): for i in range(self._nrows): for j in range(self._ncols): if i != j: - if not self.get_unsafe(i,j).is_zero(): + if not self.get_unsafe(i, j).is_zero(): return False return True @@ -9682,7 +9693,7 @@ cdef class Matrix(Matrix1): P = self.transpose() * self # Orthogonal return P.is_scalar(1) - def is_bistochastic(self, normalized = True): + def is_bistochastic(self, normalized=True): r""" Returns ``True`` if this matrix is bistochastic. @@ -9845,12 +9856,12 @@ cdef class Matrix(Matrix1): cdef Matrix left = self*CT cdef Matrix right = CT*self - cdef Py_ssize_t i,j + cdef Py_ssize_t i, j normal = True # two products are Hermitian, need only check lower triangle for i from 0 <= i < self._nrows: for j from 0 <= j <= i: - if left.get_unsafe(i,j) != right.get_unsafe(i,j): + if left.get_unsafe(i, j) != right.get_unsafe(i, j): normal = False break if not normal: @@ -9967,11 +9978,11 @@ cdef class Matrix(Matrix1): ir = mc ic = mr b = 1.0 - elif max(mr,mc) > maxsize: + elif max(mr, mc) > maxsize: maxsize = float(maxsize) - ir = int(mc * maxsize/max(mr,mc)) - ic = int(mr * maxsize/max(mr,mc)) - b = max(mr,mc)/maxsize + ir = int(mc * maxsize / max(mr, mc)) + ic = int(mr * maxsize / max(mr, mc)) + b = max(mr, mc) / maxsize else: ir = mc ic = mr @@ -9988,7 +9999,7 @@ cdef class Matrix(Matrix1): for _x in range(bi): for _y in range(bi): if not self.get_unsafe((x*b + _x), (y*b + _y)).is_zero(): - v -= 1 #increase darkness + v -= 1 # increase darkness v = (v * fct + 0.5) pixel[y, x] = (v, v, v) return img @@ -10024,7 +10035,7 @@ cdef class Matrix(Matrix1): sage: a.density() 0 """ - cdef int x,y,k + cdef int x, y, k k = 0 nr = self.nrows() nc = self.ncols() @@ -10032,8 +10043,8 @@ cdef class Matrix(Matrix1): return 0 for x from 0 <= x < nr: for y from 0 <= y < nc: - if not self.get_unsafe(x,y).is_zero(): - k+=1 + if not self.get_unsafe(x, y).is_zero(): + k += 1 return QQ(k)/QQ(nr*nc) def inverse(self): @@ -10253,13 +10264,13 @@ cdef class Matrix(Matrix1): This is all left to the method `adjugate`. """ - n = self._ncols + n = self._ncols if self._nrows != n: raise ValueError("self must be a square matrix") A = self.charpoly().shift(-1)(self) - return A if n%2 else -A + return A if n % 2 else -A def QR(self, full=True): r""" @@ -10529,16 +10540,16 @@ cdef class Matrix(Matrix1): scale = sqrt(hip) q = (1/scale)*v Q.append(q) - R[row,i] = scale - for j in range(i+1, n): - R[row,j] = q.hermitian_inner_product(V[j]) - V[j] = V[j] - R[row,j]*q + R[row, i] = scale + for j in range(i + 1, n): + R[row, j] = q.hermitian_inner_product(V[j]) + V[j] = V[j] - R[row, j] * q row = row + 1 except TypeError: raise TypeError('QR decomposition unable to compute square roots in %s' % F) # complete to full orthonormal basis, or reduce to truncated R if full: - Qt = matrix(Q) # as rows here + Qt = matrix(Q) # as rows here if Qt.nrows() == 0: Qt = zero_matrix(F, 0, m) orthogonal = Qt.right_kernel().basis_matrix().transpose() @@ -10687,12 +10698,12 @@ cdef class Matrix(Matrix1): zero = F(0) Bstar = [] R = zero_matrix(F, n) - nnz = 0 # number non-zero rows in R, or number of nonzero vectors in Bstar + nnz = 0 # number non-zero rows in R, or number of nonzero vectors in Bstar for i in range(n): ortho = B[i] for j in range(nnz): - R[j,i] = Bstar[j].hermitian_inner_product(B[i])/Bstar[j].hermitian_inner_product(Bstar[j]) - ortho = ortho - R[j,i]*Bstar[j] + R[j, i] = Bstar[j].hermitian_inner_product(B[i]) / Bstar[j].hermitian_inner_product(Bstar[j]) + ortho = ortho - R[j, i] * Bstar[j] if ortho.hermitian_inner_product(ortho) != zero: Bstar.append(ortho) R[nnz, i] = 1 @@ -11028,7 +11039,8 @@ cdef class Matrix(Matrix1): R = self.base_ring() if isinstance(R, (sage.rings.abc.RealDoubleField, sage.rings.abc.ComplexDoubleField)): Q, R = self.transpose().QR() - m = R.nrows(); n = R.ncols() + m = R.nrows() + n = R.ncols() if m > n: Q = Q[0:m, 0:n] R = R[0:n, 0:n] @@ -11465,7 +11477,7 @@ cdef class Matrix(Matrix1): blocks = [] for eval, mult in evals: if mult == 1: - blocks.append((eval,1)) + blocks.append((eval, 1)) else: B = A - diagonal_matrix([eval]*n, sparse=sparse) C = B @@ -11494,7 +11506,7 @@ cdef class Matrix(Matrix1): # a Jordan chain for each, adding the chain (a sequence of # vectors) to the entry for the eigenvalue (which is a list). jordan_chains = {} - for eval,_ in evals: + for eval, _ in evals: jordan_chains[eval] = [] # Let B be the matrix `A - eval Id`. @@ -11532,9 +11544,9 @@ cdef class Matrix(Matrix1): # Now ``jordan_chains`` has all the columns of the transformation # matrix; we just need to put them in the right order. jordan_basis = [] - for eval,size in blocks: + for eval, size in blocks: # Find a block with the right size - for index,chain in enumerate(jordan_chains[eval]): + for index, chain in enumerate(jordan_chains[eval]): if len(chain) == size: jordan_basis += jordan_chains[eval].pop(index) break @@ -12592,7 +12604,7 @@ cdef class Matrix(Matrix1): R = self.base_ring() if not is_Vector(v): raise TypeError('first input should be a vector, not {0}'.format(v)) - if not (var is None or isinstance(var, str)): + if not (var is None or isinstance(var, str)): generator = False try: generator = var.is_gen() @@ -12911,7 +12923,7 @@ cdef class Matrix(Matrix1): True """ - cdef Matrix C # output matrix + cdef Matrix C # output matrix C = self.fetch('cholesky') if C is not None: return C @@ -12933,7 +12945,7 @@ cdef class Matrix(Matrix1): cdef Matrix L # block_ldlt() results cdef list d # block_ldlt() results try: - _,L,d = self._block_ldlt(True) + _, L, d = self._block_ldlt(True) except ValueError: # If the matrix was positive-definite, that would # have worked. @@ -12946,7 +12958,7 @@ cdef class Matrix(Matrix1): cdef bint extend = False for X in d: # The X are guaranteed to be one-by-one blocks. - x = X[0,0] + x = X[0, 0] if x <= zero: raise ValueError("matrix is not positive definite") @@ -12973,7 +12985,7 @@ cdef class Matrix(Matrix1): from sage.rings.qqbar import AA try: C = L.change_ring(AA) - except ValueError: # cannot coerce... + except ValueError: # cannot coerce... C = L.change_ring(F_ac) else: C = L.__copy__() @@ -12981,11 +12993,11 @@ cdef class Matrix(Matrix1): # Overwrite the (strict) upper-triangular part of "C", since a # priori it contains junk after _block_ldlt(). zero = C.base_ring().zero() - cdef Py_ssize_t i, j # loop indices + cdef Py_ssize_t i, j # loop indices for i in range(n): C.rescale_col_c(i, splits[i], 0) - for j in range(i+1,n): - C.set_unsafe(i,j,zero) + for j in range(i + 1, n): + C.set_unsafe(i, j, zero) C.set_immutable() self.cache('cholesky', C) return C @@ -13105,7 +13117,7 @@ cdef class Matrix(Matrix1): sage: actual == expected True """ - P,L,D = self.block_ldlt() + P, L, D = self.block_ldlt() # The default "echelonize" inverse() method works just fine for # triangular matrices. @@ -13558,24 +13570,24 @@ cdef class Matrix(Matrix1): # abs() necessary to convert zero to the # correct type for comparisons (Issue #12208) max_entry = abs(zero) - for i in range(k,m): - entry = abs(M.get_unsafe(i,k)) + for i in range(k, m): + entry = abs(M.get_unsafe(i, k)) if entry > max_entry: max_location = i max_entry = entry else: - for i in range(k,m): - if M.get_unsafe(i,k) != zero: + for i in range(k, m): + if M.get_unsafe(i, k) != zero: max_location = i break if max_location != -1: perm[k], perm[max_location] = perm[max_location], perm[k] M.swap_rows(k, max_location) for j in range(k+1, m): - scale = -M.get_unsafe(j,k)/M.get_unsafe(k,k) - M.set_unsafe(j,k, -scale) - for p in range(k+1,n): - M.set_unsafe(j,p, M.get_unsafe(j,p) + scale*M.get_unsafe(k,p)) + scale = -M.get_unsafe(j, k) / M.get_unsafe(k, k) + M.set_unsafe(j, k, -scale) + for p in range(k + 1, n): + M.set_unsafe(j, p, M.get_unsafe(j, p) + scale * M.get_unsafe(k, p)) perm = tuple(perm) M.set_immutable() compact = (perm, M) @@ -13594,11 +13606,11 @@ cdef class Matrix(Matrix1): perm = [perm[i]+1 for i in range(m)] P = sage.combinat.permutation.Permutation(perm).to_matrix() P = P.change_ring(F) - L = M.matrix_space(m,m).identity_matrix().__copy__() + L = M.matrix_space(m, m).identity_matrix().__copy__() for i in range(1, m): - for k in range(min(i,d)): - L[i,k] = M[i,k] - M[i,k] = zero + for k in range(min(i, d)): + L[i, k] = M[i, k] + M[i, k] = zero return P, L, M def _indefinite_factorization(self, algorithm, check=True): @@ -13840,16 +13852,16 @@ cdef class Matrix(Matrix1): t = L.get_unsafe(i, j) if conjugate: for k in range(j): - t -= L.get_unsafe(k,i)*L.get_unsafe(j,k).conjugate() + t -= L.get_unsafe(k, i) * L.get_unsafe(j, k).conjugate() else: for k in range(j): - t -= L.get_unsafe(k,i)*L.get_unsafe(j,k) + t -= L.get_unsafe(k, i) * L.get_unsafe(j, k) if i == j: if not t: - self.cache(cache_string, (False,i+1)) - return (False, i+1) + self.cache(cache_string, (False, i + 1)) + return (False, i + 1) d.append(t) - d_inv.append(one/t) + d_inv.append(one / t) L.set_unsafe(i, i, one) else: L.set_unsafe(j, i, t) @@ -14065,7 +14077,7 @@ cdef class Matrix(Matrix1): if result is not None: return result - cdef Py_ssize_t i, j, k # loop indices + cdef Py_ssize_t i, j, k # loop indices cdef Py_ssize_t r # another row/column index # We need to construct 1x1 and 2x2 matrices to stick in d. @@ -14089,7 +14101,7 @@ cdef class Matrix(Matrix1): # at the end of the function, not as its columns are computed. ring = self.base_ring().fraction_field() - cdef Matrix A # A copy of the input matrix + cdef Matrix A # A copy of the input matrix if self.base_ring() == ring: A = self.__copy__() else: @@ -14127,7 +14139,7 @@ cdef class Matrix(Matrix1): cdef list d = [] # And the parent of those diagonal blocks that are 1x1... - one_by_one_space = A.matrix_space(1,1) + one_by_one_space = A.matrix_space(1, 1) # The case n == 0 is *almost* handled by skipping the # forthcoming loop entirely. However, we must stick a trivial @@ -14143,7 +14155,7 @@ cdef class Matrix(Matrix1): # where we're storing the next iterate. So our indices are # always "k" greater than those of Higham or B&K. - A_kk = A.get_unsafe(k,k) + A_kk = A.get_unsafe(k, k) if k == (n-1): # Handle this trivial case manually, since otherwise the @@ -14151,7 +14163,7 @@ cdef class Matrix(Matrix1): # meaningless. The corresponding entry of "L" will be # fixed later (since it's an on-diagonal element, it gets # set to one eventually). - d.append( one_by_one_space(A_kk) ) + d.append(one_by_one_space(A_kk)) k += 1 continue @@ -14161,8 +14173,8 @@ cdef class Matrix(Matrix1): # It's a back door that lets us escape with only the standard non-block # non-pivoting LDL^T factorization. This allows us to implement e.g. # indefinite_factorization() in terms of this method. - d.append( one_by_one_space(A_kk) ) - _block_ldlt_pivot1x1(A,k) + d.append(one_by_one_space(A_kk)) + _block_ldlt_pivot1x1(A, k) k += 1 continue except ZeroDivisionError: @@ -14177,8 +14189,8 @@ cdef class Matrix(Matrix1): # Note: omega_1 is defined as a C double, but the abs() # below would make a complex number approximate anyway. omega_1 = 0 - for i in range(k+1,n): - a_ik_abs = A.get_unsafe(i,k).abs() + for i in range(k + 1, n): + a_ik_abs = A.get_unsafe(i, k).abs() if a_ik_abs > omega_1: omega_1 = a_ik_abs # We record the index "r" that corresponds to @@ -14198,7 +14210,7 @@ cdef class Matrix(Matrix1): # the 1x1 pivot "a" in the top-left position. The entry "a" # will be adjusted to "1" later on to ensure that "L" is # (block) unit-lower-triangular. - d.append( one_by_one_space(A_kk) ) + d.append(one_by_one_space(A_kk)) k += 1 continue @@ -14210,8 +14222,8 @@ cdef class Matrix(Matrix1): # otherwise. We are performing a 1x1 pivot, but the # rows/columns are already where we want them, so nothing # needs to be permuted. - d.append( one_by_one_space(A_kk) ) - _block_ldlt_pivot1x1(A,k) + d.append(one_by_one_space(A_kk)) + _block_ldlt_pivot1x1(A, k) k += 1 continue @@ -14225,27 +14237,30 @@ cdef class Matrix(Matrix1): # Note: omega_r is defined as a C double, but the abs() # below would make a complex number approximate anyway. omega_r = 0 - for j in range(k,r): - a_rj_abs = A.get_unsafe(r,j).abs() + for j in range(k, r): + a_rj_abs = A.get_unsafe(r, j).abs() if a_rj_abs > omega_r: omega_r = a_rj_abs if A_kk.abs()*omega_r >= alpha*(omega_1**2): # Step (2) in Higham or Step (4) in B&K. - d.append( one_by_one_space(A_kk) ) - _block_ldlt_pivot1x1(A,k) + d.append(one_by_one_space(A_kk)) + _block_ldlt_pivot1x1(A, k) k += 1 continue - A_rr = A.get_unsafe(r,r) + A_rr = A.get_unsafe(r, r) if A_rr.abs() > alpha*omega_r: # This is Step (3) in Higham or Step (5) in B&K. Still # a 1x1 pivot, but this time we need to swap # rows/columns k and r. - d.append( one_by_one_space(A_rr) ) - A.swap_columns_c(k,r); A.swap_rows_c(k,r) - p_k = p[k]; p[k] = p[r]; p[r] = p_k - _block_ldlt_pivot1x1(A,k) + d.append(one_by_one_space(A_rr)) + A.swap_columns_c(k, r) + A.swap_rows_c(k, r) + p_k = p[k] + p[k] = p[r] + p[r] = p_k + _block_ldlt_pivot1x1(A, k) k += 1 continue @@ -14253,16 +14268,19 @@ cdef class Matrix(Matrix1): # or Step (6) in B&K, where we perform a 2x2 pivot. See # pivot1x1() for an explanation of why it's OK to permute # the entries of "L" here as well. - A.swap_columns_c(k+1,r); A.swap_rows_c(k+1,r) - p_k = p[k+1]; p[k+1] = p[r]; p[r] = p_k + A.swap_columns_c(k + 1, r) + A.swap_rows_c(k + 1, r) + p_k = p[k + 1] + p[k + 1] = p[r] + p[r] = p_k # The top-left 2x2 submatrix (starting at position k,k) is # now our pivot. - E = A[k:k+2,k:k+2] + E = A[k: k + 2, k: k + 2] d.append(E) - C = A[k+2:n,k:k+2] - B = A[k+2:,k+2:] + C = A[k + 2: n, k: k + 2] + B = A[k + 2:, k+2:] # We don't actually need the inverse of E, what we really need # is C*E.inverse(), and that can be found by setting @@ -14279,10 +14297,10 @@ cdef class Matrix(Matrix1): # Compute the Schur complement that we'll work on during # the following iteration, and store it back in the lower- # right-hand corner of "A". - for i in range(n-k-2): - for j in range(i+1): - A.set_unsafe(k+2+i, k+2+j, schur_complement[i,j]) - A.set_unsafe(k+2+j, k+2+i, schur_complement[j,i]) + for i in range(n - k - 2): + for j in range(i + 1): + A.set_unsafe(k + 2 + i, k + 2 + j, schur_complement[i, j]) + A.set_unsafe(k + 2 + j, k + 2 + i, schur_complement[j, i]) # The on- and above-diagonal entries of "L" will be fixed # later, so we only need to worry about the lower-left entry @@ -14293,8 +14311,7 @@ cdef class Matrix(Matrix1): for j in range(2): # Store the new (k and (k+1)st) columns of "L" within # the lower-left-hand corner of "A". - A.set_unsafe(k+i+2, k+j, CE_inverse[i,j]) - + A.set_unsafe(k+i+2, k+j, CE_inverse[i, j]) k += 2 @@ -14303,7 +14320,7 @@ cdef class Matrix(Matrix1): # correctness. A.set_unsafe(i, i, one) - result = (p,A,d) + result = (p, A, d) self.cache(cache_string, result) return result @@ -14608,12 +14625,12 @@ cdef class Matrix(Matrix1): """ cdef Py_ssize_t n # size of the matrices - cdef Py_ssize_t i, j # loop indices - cdef Matrix P,L,D # output matrices + cdef Py_ssize_t i, j # loop indices + cdef Matrix P, L, D # output matrices - p,L,d = self._block_ldlt(classical) + p, L, d = self._block_ldlt(classical) MS = L.matrix_space() - P = MS.matrix(lambda i,j: p[j] == i) + P = MS.matrix(lambda i, j: p[j] == i) # Warning: when n == 0, this works, but returns a matrix # whose (nonexistent) entries are in ZZ rather than in @@ -14626,11 +14643,10 @@ cdef class Matrix(Matrix1): n = L._nrows zero = MS.base_ring().zero() for i in range(n): - for j in range(i+1,n): - L.set_unsafe(i,j,zero) - - return (P,L,D) + for j in range(i + 1, n): + L.set_unsafe(i, j, zero) + return (P, L, D) cdef bint _is_positive_definite_or_semidefinite(self, bint semi) except -1: """ @@ -14640,7 +14656,7 @@ cdef class Matrix(Matrix1): code. The boolean ``semi`` argument exists only to change "greater than zero" into "greater than or equal to zero." """ - from sage.rings.real_lazy import RLF,CLF + from sage.rings.real_lazy import RLF, CLF R = self.base_ring() @@ -14660,10 +14676,10 @@ cdef class Matrix(Matrix1): return False if self._nrows == 0: - return True # vacuously + return True # vacuously cdef list d - _,_,d = self._block_ldlt(False) + _, _, d = self._block_ldlt(False) # Check each 1x1 block for a nonpositive (negative) entry. If # we don't find any, the matrix is positive-(semi)definite. The @@ -14673,8 +14689,7 @@ cdef class Matrix(Matrix1): if semi: op = operator.ge - return all(d_i.nrows() == 1 and op(d_i[0,0], 0) for d_i in d) - + return all(d_i.nrows() == 1 and op(d_i[0, 0], 0) for d_i in d) def is_positive_semidefinite(self): r""" @@ -14986,7 +15001,7 @@ cdef class Matrix(Matrix1): result = self._is_positive_definite_or_semidefinite(False) if certificate: from sage.misc.superseded import deprecation - msg = "the 'certificate' argument is deprecated; if you " + msg = "the 'certificate' argument is deprecated; if you " msg += "need the corresponding factorization, you can " msg += "simply compute it yourself (the results are cached)" deprecation(31619, msg) @@ -14994,7 +15009,7 @@ cdef class Matrix(Matrix1): d = None if result: from sage.modules.free_module_element import vector - _,L,D = self.block_ldlt() + _, L, D = self.block_ldlt() d = vector(D.base_ring(), D.diagonal()) return (result, L, d) else: @@ -15075,7 +15090,7 @@ cdef class Matrix(Matrix1): m2 = hadamard_row_bound_mpfr(A) return min(m1, m2) - def find(self,f, indices=False): + def find(self, f, indices=False): r""" Find elements in this matrix satisfying the constraints in the function `f`. The function is evaluated on each element of @@ -15141,7 +15156,7 @@ cdef class Matrix(Matrix1): True """ from sage.matrix.matrix_space import MatrixSpace - cdef Py_ssize_t size,i,j + cdef Py_ssize_t size, i, j cdef object M if not indices: @@ -15150,20 +15165,20 @@ cdef class Matrix(Matrix1): M = PyList_New(0) for i from 0 <= i < size: - PyList_Append(M,f(PyList_GET_ITEM(L,i))) + PyList_Append(M, f(PyList_GET_ITEM(L, i))) from sage.rings.finite_rings.integer_mod_ring import IntegerModRing return MatrixSpace(IntegerModRing(2), - nrows=self._nrows,ncols=self._ncols).matrix(M) + nrows=self._nrows, ncols=self._ncols).matrix(M) else: # return matrix along with indices in a dictionary d = {} for i from 0 <= i < self._nrows: for j from 0 <= j < self._ncols: - if f(self.get_unsafe(i,j)): - d[(i,j)] = self.get_unsafe(i,j) + if f(self.get_unsafe(i, j)): + d[(i, j)] = self.get_unsafe(i, j) return d @@ -15654,7 +15669,7 @@ cdef class Matrix(Matrix1): """ d = self.smith_form(transformation=False) r = min(self.nrows(), self.ncols()) - return [d[i,i] for i in range(r)] + return [d[i, i] for i in range(r)] def smith_form(self, transformation=True, integral=None, exact=True): r""" @@ -15878,20 +15893,20 @@ cdef class Matrix(Matrix1): raise NotImplementedError("Smith form over non-exact rings not implemented at present") # first clear the first row and column - u,t,v = _smith_onestep(self) + u, t, v = _smith_onestep(self) # now recurse: t now has a nonzero entry at 0,0 and zero entries in the rest # of the 0th row and column, so we apply smith_form to the smaller submatrix - mm = t.submatrix(1,1) + mm = t.submatrix(1, 1) if transformation: dd, uu, vv = mm.smith_form(transformation=True) else: dd = mm.smith_form(transformation=False) mone = self.new_matrix(1, 1, [1]) - d = dd.new_matrix(1,1,[t[0,0]]).block_sum(dd) + d = dd.new_matrix(1, 1, [t[0, 0]]).block_sum(dd) if transformation: - u = uu.new_matrix(1,1,[1]).block_sum(uu) * u - v = v * vv.new_matrix(1,1,[1]).block_sum(vv) + u = uu.new_matrix(1, 1, [1]).block_sum(uu) * u + v = v * vv.new_matrix(1, 1, [1]).block_sum(vv) dp, up, vp = _smith_diag(d, transformation=transformation) if integral is False: dp = dp.change_ring(R) @@ -15972,36 +15987,37 @@ cdef class Matrix(Matrix1): pivot_cols = [] while j < n: k = i - while k < m and A.get_unsafe(k,j).is_zero(): # first nonzero entry + while k < m and A.get_unsafe(k, j).is_zero(): # first nonzero entry k += 1 if k < m: l = k + 1 while l < m: - while l < m and A.get_unsafe(l,j).is_zero(): # nonzero entry below + while l < m and A.get_unsafe(l, j).is_zero(): # nonzero entry below l += 1 - if l >= m: break + if l >= m: + break - a = A.get_unsafe(k,j) - b = A.get_unsafe(l,j) - d,p,q = a.xgcd(b) # p * a + q * b = d = gcd(a,b) + a = A.get_unsafe(k, j) + b = A.get_unsafe(l, j) + d, p, q = a.xgcd(b) # p * a + q * b = d = gcd(a,b) e = a // d f = b // d - for c in range(j,n): - Akc = A.get_unsafe(k,c) - Alc = A.get_unsafe(l,c) + for c in range(j, n): + Akc = A.get_unsafe(k, c) + Alc = A.get_unsafe(l, c) A.set_unsafe(k, c, p * Akc + q * Alc) A.set_unsafe(l, c, (-f) * Akc + e * Alc) if transformation: for c in range(m): - Ukc = U.get_unsafe(k,c) - Ulc = U.get_unsafe(l,c) + Ukc = U.get_unsafe(k, c) + Ulc = U.get_unsafe(l, c) U.set_unsafe(k, c, p * Ukc + q * Ulc) U.set_unsafe(l, c, (-f) * Ukc + e * Ulc) if i != k: - A.swap_rows_c(i,k) + A.swap_rows_c(i, k) if transformation: - U.swap_rows_c(i,k) + U.swap_rows_c(i, k) pivot_cols.append(j) i += 1 j += 1 @@ -16009,26 +16025,26 @@ cdef class Matrix(Matrix1): # reduce entries above pivots for i in range(len(pivot_cols)): j = pivot_cols[i] - pivot = A.get_unsafe(i,j) + pivot = A.get_unsafe(i, j) # possibly normalize the pivot if normalization: coeff = normalization(pivot) - for c in range(j,n): - A.set_unsafe(i, c, A.get_unsafe(i,c) * coeff) + for c in range(j, n): + A.set_unsafe(i, c, A.get_unsafe(i, c) * coeff) if transformation: for c in range(m): - U.set_unsafe(i, c, U.get_unsafe(i,c) * coeff) + U.set_unsafe(i, c, U.get_unsafe(i, c) * coeff) - pivot = A.get_unsafe(i,j) + pivot = A.get_unsafe(i, j) for k in range(i): - q = - (A.get_unsafe(k,j) // pivot) + q = - (A.get_unsafe(k, j) // pivot) if not q.is_zero(): - for c in range(j,n): - A.set_unsafe(k, c, A.get_unsafe(k,c) + q * A.get_unsafe(i,c)) + for c in range(j, n): + A.set_unsafe(k, c, A.get_unsafe(k, c) + q * A.get_unsafe(i, c)) if transformation: for c in range(m): - U.set_unsafe(k, c, U.get_unsafe(k,c) + q * U.get_unsafe(i,c)) + U.set_unsafe(k, c, U.get_unsafe(k, c) + q * U.get_unsafe(i, c)) if transformation: return U @@ -16173,25 +16189,25 @@ cdef class Matrix(Matrix1): return self.new_matrix(self.nrows(), self.nrows(), 1), self, [] else: return self.new_matrix(self.nrows(), self.nrows(), 1), self, [ - self.nonzero_positions_in_row(0)[0] ] + self.nonzero_positions_in_row(0)[0]] R = self.base_ring() # data type checks on R if not R.is_integral_domain(): raise TypeError("Generic echelon form only defined over " - "integral domains") + "integral domains") if not R.is_exact(): raise NotImplementedError("Echelon form over generic non-exact " - "rings not implemented at present") + "rings not implemented at present") left_mat, a = _generic_clear_column(self) assert left_mat * self == a - if a[0,0] != 0: + if a[0, 0] != 0: aa = a.submatrix(1, 1) s, t, pivs = aa._echelon_form_PID() - left_mat = s.new_matrix(1,1,[1]).block_sum(s) * left_mat + left_mat = s.new_matrix(1, 1, [1]).block_sum(s) * left_mat a = left_mat * self pivs = [0] + [x + 1 for x in pivs] @@ -16209,12 +16225,12 @@ cdef class Matrix(Matrix1): I = ideal_or_fractional(R, y) s = a[0][pivs[i]] t = I.small_residue(s) - v = R( (s-t) / y) + v = R((s-t) / y) left_mat.add_multiple_of_row(0, i, -v) a.add_multiple_of_row(0, i, -v) assert left_mat * self == a - except AttributeError: # on I.small_residue + except AttributeError: # on I.small_residue pass return left_mat, a, pivs @@ -16321,7 +16337,7 @@ cdef class Matrix(Matrix1): cdef list corners = [] # zero or one in corner of off-diagonal blocks if basis: from sage.matrix.constructor import identity_matrix - U = identity_matrix(R, n) # transformation matrix + U = identity_matrix(R, n) # transformation matrix # parity switch, True iff working on transpose # if False, mimic row operations only on U # if True, mimic column operations only on U @@ -16334,7 +16350,7 @@ cdef class Matrix(Matrix1): while zigging: # zigging means we are building a block nonzero = -1 for i in range(c+1, n): - if Z.get_unsafe(i,c): + if Z.get_unsafe(i, c): nonzero = i break zigging = (nonzero != -1) @@ -16378,7 +16394,7 @@ cdef class Matrix(Matrix1): # (inclusive), use it to clear entries to the right # but first record polynomial for block just built # this is the full monic polynomial, with correct coefficients - p = [-Z.get_unsafe(i,c) for i in range(s,c+1)] + p = [-Z.get_unsafe(i, c) for i in range(s, c + 1)] p.append(one) polys.append(p) @@ -16394,7 +16410,7 @@ cdef class Matrix(Matrix1): # Effectively: Z.add_multiple_of_row(i, j, scale) for k in range(c+1, n): # Z[i,k] = Z[i,k] + scale*Z[j,k] - Z.set_unsafe(i, k, Z.get_unsafe(i,k)+scale*Z.get_unsafe(j,k)) + Z.set_unsafe(i, k, Z.get_unsafe(i, k) + scale * Z.get_unsafe(j, k)) if basis: if trans: U.add_multiple_of_column(j, i, -scale) @@ -17161,7 +17177,7 @@ cdef class Matrix(Matrix1): companions.append(companion_matrix(poly, format=format)) return block_diagonal_matrix(companions, subdivide=subdivide) - def is_positive_operator_on(self,K1,K2=None): + def is_positive_operator_on(self, K1, K2=None): r""" Determine if this matrix is a positive operator on a cone. @@ -17595,7 +17611,7 @@ cdef class Matrix(Matrix1): """ return (-self).is_cross_positive_on(K) - def is_lyapunov_like_on(self,K): + def is_lyapunov_like_on(self, K): r""" Determine if this matrix is Lyapunov-like on a cone. @@ -17965,35 +17981,35 @@ def _smith_diag(d, transformation=True): else: left = right = None for i in range(n): - I = ideal_or_fractional(R, dp[i,i]) + I = ideal_or_fractional(R, dp[i, i]) if I == ideal_or_fractional(R, 1): - if dp[i,i] != 1: + if dp[i, i] != 1: if transformation: - left.add_multiple_of_row(i,i,R(R(1)/(dp[i,i])) - 1) - dp[i,i] = R(1) + left.add_multiple_of_row(i, i, R(R(1) / (dp[i, i])) - 1) + dp[i, i] = R(1) continue - for j in range(i+1,n): - if dp[j,j] not in I: - t = ideal_or_fractional(R, [dp[i,i], dp[j,j]]).gens_reduced() + for j in range(i + 1, n): + if dp[j, j] not in I: + t = ideal_or_fractional(R, [dp[i, i], dp[j, j]]).gens_reduced() if len(t) > 1: raise ArithmeticError t = t[0] # find lambda, mu such that lambda*d[i,i] + mu*d[j,j] = t - lamb = R(dp[i,i]/t).inverse_mod( ideal_or_fractional(R, dp[j,j]/t)) - mu = R((t - lamb*dp[i,i]) / dp[j,j]) + lamb = R(dp[i, i] / t).inverse_mod(ideal_or_fractional(R, dp[j, j] / t)) + mu = R((t - lamb * dp[i, i]) / dp[j, j]) newlmat = dp.new_matrix(dp.nrows(), dp.nrows(), 1) - newlmat[i,i] = lamb - newlmat[i,j] = 1 - newlmat[j,i] = R(-dp[j,j]*mu/t) - newlmat[j,j] = R(dp[i,i]/t) + newlmat[i, i] = lamb + newlmat[i, j] = 1 + newlmat[j, i] = R(-dp[j, j] * mu / t) + newlmat[j, j] = R(dp[i, i] / t) newrmat = dp.new_matrix(dp.ncols(), dp.ncols(), 1) - newrmat[i,i] = 1 - newrmat[i,j] = R(-dp[j,j]/t) - newrmat[j,i] = mu - newrmat[j,j] = R(lamb*dp[i,i] / t) + newrmat[i, i] = 1 + newrmat[i, j] = R(-dp[j, j] / t) + newrmat[j, i] = mu + newrmat[j, j] = R(lamb * dp[i, i] / t) if transformation: left = newlmat*left @@ -18039,13 +18055,13 @@ def _generic_clear_column(m): k = 0 while a[k, 0] == 0: k += 1 - if k == a.nrows(): # first column is zero + if k == a.nrows(): # first column is zero return left_mat, a # k is now first row such that a[k, 0] is nonzero - left_mat[0,0] = 0 - left_mat[k,k] = 0 - left_mat[0,k] = 1 - left_mat[k,0] = -1 + left_mat[0, 0] = 0 + left_mat[k, k] = 0 + left_mat[0, k] = 1 + left_mat[k, 0] = -1 a = left_mat*a if left_mat * m != a: raise ArithmeticError("Something went wrong") @@ -18059,15 +18075,15 @@ def _generic_clear_column(m): # [e,f] # is invertible over R - I = ideal_or_fractional(R, a[0, 0]) # need to make sure we change this when a[0,0] changes + I = ideal_or_fractional(R, a[0, 0]) # need to make sure we change this when a[0,0] changes for k in range(1, a.nrows()): - if a[k,0] not in I: + if a[k, 0] not in I: try: - v = ideal_or_fractional(R, a[0,0], a[k,0]).gens_reduced() + v = ideal_or_fractional(R, a[0, 0], a[k, 0]).gens_reduced() except Exception as msg: - raise ArithmeticError("%s\nCan't create ideal on %s and %s" % (msg, a[0,0], a[k,0])) + raise ArithmeticError("%s\nCan't create ideal on %s and %s" % (msg, a[0, 0], a[k, 0])) if len(v) > 1: - raise ArithmeticError("Ideal %s not principal" % ideal_or_fractional(R, a[0,0], a[k,0])) + raise ArithmeticError("Ideal %s not principal" % ideal_or_fractional(R, a[0, 0], a[k, 0])) B = v[0] # now we find c,d, using the fact that c * (a_{0,0}/B) - d * @@ -18076,40 +18092,40 @@ def _generic_clear_column(m): # need to handle carefully the case when a_{k,0}/B is a unit, i.e. a_{k,0} divides # a_{0,0}. - c = R(a[0,0] / B).inverse_mod(ideal_or_fractional(R, a[k,0] / B)) - d = R( (c*a[0,0] - B)/(a[k,0]) ) + c = R(a[0, 0] / B).inverse_mod(ideal_or_fractional(R, a[k, 0] / B)) + d = R((c*a[0, 0] - B)/(a[k, 0])) # sanity check - if c*a[0,0] - d*a[k,0] != B: + if c*a[0, 0] - d*a[k, 0] != B: raise ArithmeticError # now we find e,f such that e*d + c*f = 1 in the same way if c != 0: - e = d.inverse_mod( ideal_or_fractional(R, c) ) + e = d.inverse_mod(ideal_or_fractional(R, c)) f = R((1 - d*e)/c) else: - e = R(-a[k,0]/B) # here d is a unit and this is just 1/d + e = R(-a[k, 0] / B) # here d is a unit and this is just 1/d f = R(1) if e*d + c*f != 1: raise ArithmeticError newlmat = left_mat.parent()(1) - newlmat[0,0] = c - newlmat[0,k] = -d - newlmat[k,0] = e - newlmat[k,k] = f + newlmat[0, 0] = c + newlmat[0, k] = -d + newlmat[k, 0] = e + newlmat[k, k] = f if newlmat.det() != 1: raise ArithmeticError a = newlmat*a - I = ideal_or_fractional(R, a[0,0]) + I = ideal_or_fractional(R, a[0, 0]) left_mat = newlmat*left_mat if left_mat * m != a: raise ArithmeticError # now everything in column 0 is divisible by the pivot - for i in range(1,a.nrows()): - s = R( a[i, 0]/a[0, 0]) - a.add_multiple_of_row(i, 0, -s ) + for i in range(1, a.nrows()): + s = R(a[i, 0] / a[0, 0]) + a.add_multiple_of_row(i, 0, -s) left_mat.add_multiple_of_row(i, 0, -s) if left_mat * m != a: raise ArithmeticError @@ -18147,11 +18163,12 @@ def _smith_onestep(m): # preparation: if column 0 is zero, swap it with the first nonzero column j = 0 - while a.column(j) == 0: j += 1 + while a.column(j) == 0: + j += 1 if j > 0: - right_mat[0,0] = right_mat[j,j] = 0 - right_mat[0,j] = 1 - right_mat[j,0] = -1 + right_mat[0, 0] = right_mat[j, j] = 0 + right_mat[0, j] = 1 + right_mat[j, 0] = -1 a = a*right_mat if m * right_mat != a: raise ArithmeticError @@ -18162,15 +18179,15 @@ def _smith_onestep(m): # test if everything to the right of the pivot in row 0 is good as well isdone = True for jj in range(j+1, a.ncols()): - if a[0,jj] != 0: + if a[0, jj] != 0: isdone = False # if not we recurse -- algorithm must terminate if R is Noetherian. if not isdone: - s,t,u = _smith_onestep(a.transpose()) + s, t, u = _smith_onestep(a.transpose()) left_mat = u.transpose() * left_mat a = t.transpose() - right_mat = right_mat* s.transpose() + right_mat = right_mat * s.transpose() return left_mat, a, right_mat @@ -18445,7 +18462,7 @@ def _matrix_power_symbolic(A, n): # Jordan block Jk, its dimension nk, the eigenvalue m Jk = J.subdivision(k, k) nk = Jk.ncols() - mk = Jk[0,0] + mk = Jk[0, 0] # First row of block Mk; its entries are of the form # D^i(f) / i! with f = x^n and D = differentiation wrt x @@ -18492,28 +18509,28 @@ cdef inline bint _block_ldlt_pivot1x1(Matrix A, Py_ssize_t k) except 1: to return zero/one so that ``1`` can be used to indicate that a python exception occurred. """ - cdef Py_ssize_t i,j # dumy loop indices + cdef Py_ssize_t i, j # dumy loop indices cdef Py_ssize_t n = A._nrows - pivot = A.get_unsafe(k,k) + pivot = A.get_unsafe(k, k) # Compute the Schur complement that we'll work on during # the following iteration, and store it back in the lower- # right-hand corner of "A". - for i in range(n-k-1): - for j in range(i+1): - A.set_unsafe(k+1+i, - k+1+j, - ( A.get_unsafe(k+1+i,k+1+j) - - A.get_unsafe(k+1+i,k)*A.get_unsafe(k,k+1+j)/pivot )) - A.set_unsafe(k+1+j, - k+1+i, - A.get_unsafe(k+1+i,k+1+j).conjugate()) + for i in range(n - k - 1): + for j in range(i + 1): + A.set_unsafe(k + 1 + i, + k + 1 + j, + (A.get_unsafe(k + 1 + i, k + 1 + j) - + A.get_unsafe(k + 1 + i, k) * A.get_unsafe(k, k + 1 + j) / pivot)) + A.set_unsafe(k + 1 + j, + k + 1 + i, + A.get_unsafe(k + 1 + i, k + 1 + j).conjugate()) for i in range(n-k-1): # Store the new (kth) column of "L" within the lower- # left-hand corner of "A". - A.set_unsafe(k+i+1, + A.set_unsafe(k + i + 1, k, - A.get_unsafe(k+i+1,k)/ pivot) + A.get_unsafe(k + i + 1, k) / pivot) return 0 diff --git a/src/sage/rings/polynomial/laurent_polynomial.pyx b/src/sage/rings/polynomial/laurent_polynomial.pyx index 6d3168f4995..aba931ad022 100644 --- a/src/sage/rings/polynomial/laurent_polynomial.pyx +++ b/src/sage/rings/polynomial/laurent_polynomial.pyx @@ -359,7 +359,7 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): elif (not isinstance(f, Polynomial)) or (parent is not f.parent()): if isinstance(f, dict): v = min(f) if f else 0 - f = {i-v: c for i,c in f.items()} + f = {i-v: c for i, c in f.items()} n += v f = parent._R(f) @@ -653,19 +653,19 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): elif e == 0: var = "" elif e > 0: - var = "|{}^{{{}}}".format(X,e) + var = "|{}^{{{}}}".format(X, e) if e >= 0: - s += "{}{}".format(x,var) - else: # negative e + s += "{}{}".format(x, var) + else: # negative e if e == -1: s += "\\frac{{{}}}{{{}}}".format(x, X) else: - s += "\\frac{{{}}}{{{}^{{{}}}}}".format(x, X,-e) + s += "\\frac{{{}}}{{{}^{{{}}}}}".format(x, X, -e) first = False s = s.replace(" + -", " - ") - s = s.replace(" 1|"," ") + s = s.replace(" 1|", " ") s = s.replace(" -1|", " -") - s = s.replace("|","") + s = s.replace("|", "") return s[1:] diff --git a/src/sage/rings/polynomial/laurent_polynomial_ring.py b/src/sage/rings/polynomial/laurent_polynomial_ring.py index 38f9f7a8ebb..4cf0880880e 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_ring.py +++ b/src/sage/rings/polynomial/laurent_polynomial_ring.py @@ -77,6 +77,8 @@ def is_LaurentPolynomialRing(R): _cache = {} + + def LaurentPolynomialRing(base_ring, *args, **kwds): r""" Return the globally unique univariate or multivariate Laurent polynomial @@ -252,6 +254,7 @@ def LaurentPolynomialRing(base_ring, *args, **kwds): _cache[R] = P return P + def _split_dict_(D, indices, group_by=None): r""" Split the dictionary ``D`` by ``indices`` and ``group_by``. @@ -334,6 +337,7 @@ def extract(T, indices): else: return result + def _split_laurent_polynomial_dict_(P, M, d): r""" Helper function for splitting a multivariate Laurent polynomial @@ -395,6 +399,7 @@ def value(d, R): pass return sum(P({k: 1}) * value(v, P) for k, v in D.items()).dict() + def from_fraction_field(L, x): r""" Helper function to construct a Laurent polynomial from an element of its From 040d9ec01d60e15d99b4726a2fbdd71cb7f2e127 Mon Sep 17 00:00:00 2001 From: Enrique Artal Date: Sat, 23 Sep 2023 22:00:00 +0200 Subject: [PATCH 11/45] change __reduce__ again to avoid further errors --- src/sage/rings/polynomial/laurent_polynomial.pyx | 2 +- src/sage/rings/polynomial/laurent_polynomial_ideal.py | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/polynomial/laurent_polynomial.pyx b/src/sage/rings/polynomial/laurent_polynomial.pyx index aba931ad022..9a042d526d8 100644 --- a/src/sage/rings/polynomial/laurent_polynomial.pyx +++ b/src/sage/rings/polynomial/laurent_polynomial.pyx @@ -379,7 +379,7 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): sage: loads(dumps(elt)) == elt True """ - return LaurentPolynomial_univariate, (self.__u, self.__n) # eliminate first term in the tuple for the previous definition + return LaurentPolynomial_univariate, (self._parent, self.__u, self.__n) def _polynomial_(self, R): r""" diff --git a/src/sage/rings/polynomial/laurent_polynomial_ideal.py b/src/sage/rings/polynomial/laurent_polynomial_ideal.py index c36c52957cd..b193569d3fa 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_ideal.py +++ b/src/sage/rings/polynomial/laurent_polynomial_ideal.py @@ -198,7 +198,10 @@ def __contains__(self, f): if not f or f in self.gens(): return True f = self.ring()(f) - g = f.__reduce__()[1][0] + if self.ring().ngens() > 1: + g = f.__reduce__()[1][0] + else: + g = f.__reduce__()[1][1] return (g in self.polynomial_ideal()) # Operations on ideals From fdcfe1c7eb12fa1c2a79eaabed65ee83cdceb491 Mon Sep 17 00:00:00 2001 From: Enrique Artal Date: Mon, 25 Sep 2023 09:17:46 +0200 Subject: [PATCH 12/45] merge --- src/sage/matrix/matrix2.pyx | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/sage/matrix/matrix2.pyx b/src/sage/matrix/matrix2.pyx index 060f6620f87..3e5115ec5dd 100644 --- a/src/sage/matrix/matrix2.pyx +++ b/src/sage/matrix/matrix2.pyx @@ -8078,11 +8078,7 @@ cdef class Matrix(Matrix1): if self.fetch('in_echelon_form'): return self.fetch('pivots') -<<<<<<< HEAD - tm = verbose('generic in-place Gauss elimination on %s x %s matrix using %s algorithm' % (self._nrows, self._ncols, algorithm)) -======= _ = verbose('generic in-place Gauss elimination on %s x %s matrix using %s algorithm' % (self._nrows, self._ncols, algorithm)) ->>>>>>> develop self.check_mutability() cdef Matrix A From 04f314a01427dbbfa87c76a77884dc79046cb1e0 Mon Sep 17 00:00:00 2001 From: Enrique Artal Date: Mon, 25 Sep 2023 09:20:37 +0200 Subject: [PATCH 13/45] merge --- src/sage/matrix/matrix2.pyx | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/sage/matrix/matrix2.pyx b/src/sage/matrix/matrix2.pyx index 060f6620f87..3e5115ec5dd 100644 --- a/src/sage/matrix/matrix2.pyx +++ b/src/sage/matrix/matrix2.pyx @@ -8078,11 +8078,7 @@ cdef class Matrix(Matrix1): if self.fetch('in_echelon_form'): return self.fetch('pivots') -<<<<<<< HEAD - tm = verbose('generic in-place Gauss elimination on %s x %s matrix using %s algorithm' % (self._nrows, self._ncols, algorithm)) -======= _ = verbose('generic in-place Gauss elimination on %s x %s matrix using %s algorithm' % (self._nrows, self._ncols, algorithm)) ->>>>>>> develop self.check_mutability() cdef Matrix A From 905d0420cc6d20fbb81a1876642268fc362ac996 Mon Sep 17 00:00:00 2001 From: Enrique Artal Date: Thu, 28 Sep 2023 15:26:34 +0200 Subject: [PATCH 14/45] class of matrices of Laurent mpolynomials --- .../matrix_laurent_mpolynomial_dense.pyx} | 0 src/sage/matrix/matrix_mpolynomial_dense.pyx | 52 ++++++++++++++++++- src/sage/matrix/matrix_space.py | 27 ++++++---- 3 files changed, 68 insertions(+), 11 deletions(-) rename src/sage/{rings/polynomial/laurent_reduction.py => matrix/matrix_laurent_mpolynomial_dense.pyx} (100%) diff --git a/src/sage/rings/polynomial/laurent_reduction.py b/src/sage/matrix/matrix_laurent_mpolynomial_dense.pyx similarity index 100% rename from src/sage/rings/polynomial/laurent_reduction.py rename to src/sage/matrix/matrix_laurent_mpolynomial_dense.pyx diff --git a/src/sage/matrix/matrix_mpolynomial_dense.pyx b/src/sage/matrix/matrix_mpolynomial_dense.pyx index e20c662cc0e..57f80149e88 100644 --- a/src/sage/matrix/matrix_mpolynomial_dense.pyx +++ b/src/sage/matrix/matrix_mpolynomial_dense.pyx @@ -20,6 +20,8 @@ AUTHOR: from sage.matrix.matrix_generic_dense cimport Matrix_generic_dense from sage.matrix.matrix2 cimport Matrix +from sage.matrix.constructor import identity_matrix +from sage.rings.polynomial.laurent_polynomial_ring_base import LaurentPolynomialRing_generic from sage.rings.polynomial.multi_polynomial_libsingular cimport MPolynomialRing_libsingular from sage.rings.polynomial.polynomial_singular_interface import can_convert_to_singular @@ -500,7 +502,7 @@ cdef class Matrix_mpolynomial_dense(Matrix_generic_dense): N = self.__copy__() for j in range(self.ncols()): if j != ncoef: - N.add_multiple_of_column(j, ncoef, -R(self[nrow,j] / coef)) + N.add_multiple_of_column(j, ncoef, -R(self[nrow, j] / coef)) return N.fitting_ideal(i) for (ncolumn, column) in enumerate(self.columns()): if not column: @@ -619,3 +621,51 @@ cdef class Matrix_mpolynomial_dense(Matrix_generic_dense): self.cache('det', d) return d + +cdef class Matrix_laurent_mpolynomial_dense(Matrix_generic_dense): + """ + Dense matrix over a multivariate polynomial ring over a field. + """ + def laurent_matrix_reduction(self): + """ + From a matrix `self` of Laurent polynomials, apply elementary operations + to obtain a matrix `P` of polynomials such that the variables do not divide + no column and no row. + + OUTPUT: Three matrices `L`, `P`, `R` such that `self = L P R`, where `L` and + `R` are diagonal with monomial entries. + + EXAMPLES: + + sage: R. = LaurentPolynomialRing(QQ) + sage: L = [1/3*x^-1*y - 6*x^-2*y^2 - 1/2*x^-2*y, 1/5*x + 1/2*y + 1/6] + sage: L += [1/2 - 5*x^-1*y - 2*x^-1, -1/3*y^-2 - 4*x^-1*y^-1 + 11*x^-1*y^-2] + sage: A = matrix(R, 2, L) + sage: lf, P, rg = A.laurent_matrix_reduction() + sage: lf + [ x^-2 0] + [ 0 x^-1*y^-2] + sage: P + [ 1/3*x - 6*y - 1/2 1/5*x^3 + 1/2*x^2*y + 1/6*x^2] + [ 1/2*x*y - 5*y^2 - 2*y -1/3*x - 4*y + 11] + sage: rg + [y 0] + [0 1] + """ + R = self.base_ring() + n_rows, n_cols = self.dimensions() + mat_l = identity_matrix(R, n_rows) + mat_r = identity_matrix(R, n_cols) + res = self + for j, rw in enumerate(self.rows()): + for t in R.gens(): + n = min(mon.degree(t) for a in rw for cf, mon in a) + res.rescale_row(j, t ** -n) + mat_l.rescale_col(j, t ** n) + for j, cl in enumerate(self.columns()): + for t in R.gens(): + n = min(mon.degree(t) for a in cl for cf, mon in a) + res.rescale_col(j, t ** -n) + mat_r.rescale_row(j, t ** n) + res = res.change_ring(R.polynomial_ring()) + return mat_l, res, mat_r diff --git a/src/sage/matrix/matrix_space.py b/src/sage/matrix/matrix_space.py index 6aab58352be..31e2ce46224 100644 --- a/src/sage/matrix/matrix_space.py +++ b/src/sage/matrix/matrix_space.py @@ -306,6 +306,13 @@ def get_matrix_class(R, nrows, ncols, sparse, implementation): pass else: return matrix_mpolynomial_dense.Matrix_mpolynomial_dense + elif isinstance(R, sage.rings.polynomial.laurent_polynomial_ring.LaurentPolynomialRing_mpair) and R.base_ring() in _Fields: + try: + from . import matrix_mpolynomial_dense + except ImportError: + pass + else: + return matrix_mpolynomial_dense.Matrix_laurent_mpolynomial_dense # The fallback from sage.matrix.matrix_generic_dense import Matrix_generic_dense @@ -795,7 +802,7 @@ def transposed(self): Full MatrixSpace of 3 by 2 dense matrices over Integer Ring """ return MatrixSpace(self._base, self.__ncols, self.__nrows, - self.__is_sparse, self.Element) + self.__is_sparse, self.Element) @lazy_attribute def _copy_zero(self): @@ -2179,7 +2186,7 @@ def row_space(self): return self.__row_space except AttributeError: self.__row_space = sage.modules.free_module.FreeModule(self.base_ring(), - self.ncols(), sparse=self.is_sparse()) + self.ncols(), sparse=self.is_sparse()) return self.__row_space def column_space(self): @@ -2197,7 +2204,7 @@ def column_space(self): return self.__column_space except AttributeError: self.__column_space = sage.modules.free_module.FreeModule(self.base_ring(), self.nrows(), - sparse=self.is_sparse()) + sparse=self.is_sparse()) return self.__column_space def random_element(self, density=None, *args, **kwds): @@ -2255,10 +2262,10 @@ def random_element(self, density=None, *args, **kwds): Z = self.zero_matrix().__copy__() if density is None: Z.randomize(density=float(1), nonzero=kwds.pop('nonzero', False), - *args, **kwds) + *args, **kwds) else: Z.randomize(density=density, nonzero=kwds.pop('nonzero', True), - *args, **kwds) + *args, **kwds) return Z def _an_element_(self): @@ -2582,13 +2589,13 @@ def _MatrixSpace_ZZ_2x2(): register_unpickle_override('sage.matrix.matrix_modn_dense', - 'Matrix_modn_dense', Matrix_modn_dense_double) + 'Matrix_modn_dense', Matrix_modn_dense_double) register_unpickle_override('sage.matrix.matrix_integer_2x2', - 'Matrix_integer_2x2', Matrix_integer_dense) + 'Matrix_integer_2x2', Matrix_integer_dense) register_unpickle_override('sage.matrix.matrix_integer_2x2', - 'MatrixSpace_ZZ_2x2_class', MatrixSpace) + 'MatrixSpace_ZZ_2x2_class', MatrixSpace) register_unpickle_override('sage.matrix.matrix_integer_2x2', - 'MatrixSpace_ZZ_2x2', _MatrixSpace_ZZ_2x2) + 'MatrixSpace_ZZ_2x2', _MatrixSpace_ZZ_2x2) lazy_import('sage.matrix.matrix_gf2e_dense', 'unpickle_matrix_gf2e_dense_v0') register_unpickle_override('sage.matrix.matrix_mod2e_dense', - 'unpickle_matrix_mod2e_dense_v0', unpickle_matrix_gf2e_dense_v0) + 'unpickle_matrix_mod2e_dense_v0', unpickle_matrix_gf2e_dense_v0) From df401b2140d657bc778124266c2eb9a98dedf1ee Mon Sep 17 00:00:00 2001 From: Enrique Artal Date: Thu, 28 Sep 2023 17:52:27 +0200 Subject: [PATCH 15/45] use fitting_ideals for characteristic varieties --- src/sage/groups/finitely_presented.py | 98 +++++++++++++------- src/sage/matrix/matrix_mpolynomial_dense.pyx | 46 +++++++++ 2 files changed, 108 insertions(+), 36 deletions(-) diff --git a/src/sage/groups/finitely_presented.py b/src/sage/groups/finitely_presented.py index 96d03e90c83..c96ea32c0da 100644 --- a/src/sage/groups/finitely_presented.py +++ b/src/sage/groups/finitely_presented.py @@ -145,6 +145,7 @@ from sage.sets.set import Set from sage.structure.unique_representation import UniqueRepresentation + class GroupMorphismWithGensImages(SetMorphism): r""" Class used for morphisms from finitely presented groups to @@ -1549,12 +1550,12 @@ def sorted_presentation(self): C = [rel] for j in range(len(rel) - 1): C.append(rel[j + 1:] + rel[:j + 1]) - C1 = [tuple(-j for j in reversed(l)) for l in C] + C1 = [tuple(-j for j in reversed(l1)) for l1 in C] C += C1 C.sort() L1.append(C[0]) L1.sort() - return F/L1 + return F / L1 def epimorphisms(self, H): r""" @@ -1762,65 +1763,90 @@ def characteristic_varieties(self, ring=QQ, matrix_ideal=None, groebner=False): OUTPUT: If ``groebner`` is ``False`` a list of ideals defining the characteristic varieties. - If it is ``True``, a list of lists for Gröbner bases for each ideal. + If it is ``True``, a list of lists for Gröbner bases for the ideal of each irreducible + component. EXAMPLES:: sage: L = [2*(i, j) + 2* (-i, -j) for i, j in ((1, 2), (2, 3), (3, 1))] sage: G = FreeGroup(3) / L sage: G.characteristic_varieties(groebner=True) - [[(f1 - 1, f2 - 1, f3 - 1), - (f1 + 1, f2 - 1, f3 - 1), - (f1 - 1, f2 - 1, f3 + 1), - (f3^2 + 1, f1 - f3, f2 - f3), - (f1 - 1, f2 + 1, f3 - 1)], - [(f1 - 1, f2 - 1, f3 - 1), + {0: [(0,)], + 1: [(f1 - 1, f2 - 1, f3 - 1), (f1*f3 + 1, f2 - 1), (f1*f2 + 1, f3 - 1), (f2*f3 + 1, f1 - 1), (f2*f3 + 1, f1 - f2), (f2*f3 + 1, f1 - f3), - (f1*f3 + 1, f2 - f3)]] + (f1*f3 + 1, f2 - f3)], + 2: [(f1 - 1, f2 - 1, f3 + 1), + (f3^2 + 1, f1 - f3, f2 - f3), + (f1 - 1, f2 - 1, f3 - 1), + (f1 - 1, f2 + 1, f3 - 1), + (f1 + 1, f2 - 1, f3 - 1)], + 3: [(f1 - 1, f2 - 1, f3 - 1)]} sage: G = FreeGroup(2)/[2*(1,2,-1,-2)] sage: G.characteristic_varieties() - [Ideal (-2*f2 + 2, 2*f1 - 2) of Multivariate Laurent Polynomial Ring in f1, f2 over Rational Field] + {0: Ideal (0, 0) of Multivariate Laurent Polynomial Ring in f1, f2 over Rational Field, + 1: Ideal (0, -2*f2 + 2, 2*f1 - 2) of Multivariate Laurent Polynomial Ring in f1, f2 over Rational Field, + 2: Ideal (f1 - 1, f2 - 1) of Multivariate Laurent Polynomial Ring in f1, f2 over Rational Field} sage: G.characteristic_varieties(ring=ZZ) - [Ideal (-2*f2 + 2, 2*f1 - 2) of Multivariate Laurent Polynomial Ring in f1, f2 over Integer Ring] + {0: Ideal (0, 0) of Multivariate Laurent Polynomial Ring in f1, f2 over Integer Ring, + 1: Ideal (0, -2*f2 + 2, 2*f1 - 2) of Multivariate Laurent Polynomial Ring in f1, f2 over Integer Ring, + 2: Ideal (f1 - 1, f2 - 1) of Multivariate Laurent Polynomial Ring in f1, f2 over Integer Ring} sage: G = FreeGroup(2)/[(1,2,1,-2,-1,-2)] sage: G.characteristic_varieties() - [Ideal (1 - f2 + f2^2, -1 + f2 - f2^2) of Univariate Laurent Polynomial Ring in f2 over Rational Field] + {0: Ideal (0, 0) of Univariate Laurent Polynomial Ring in f2 over Rational Field, + 1: Ideal (-1 + 2*f2 - 2*f2^2 + f2^3, 1 - 2*f2 + 2*f2^2 - f2^3) of Univariate Laurent Polynomial Ring in f2 over Rational Field, + 2: Ideal (0, 1) of Univariate Laurent Polynomial Ring in f2 over Rational Field} sage: G.characteristic_varieties(groebner=True) - [[1 - f2 + f2^2]] + {0: [0], 1: [-1 + f2, 1 - f2 + f2^2], 2: [1]} """ - A, ideal = self.abelian_alexander_matrix(ring=ring, simplified=True) + A, rels = self.abelian_alexander_matrix(ring=ring, simplified=True) R = A.base_ring() - res = [] + eval_1 = {x: ring(1) for x in R.gens()} + A_scalar = A.apply_map(lambda p: p.subs(eval_1)) + n = A.ncols() + n1 = n - A_scalar.rank() + ideal_1 = R.ideal([x - 1 for x in R.gens()]) S = R.polynomial_ring() - ideal = [S(elt) for elt in ideal] - for j in range(1, A.ncols()): - L = [p.monomial_reduction()[0] for p in A.minors(j)] - J = R.ideal(L + ideal) - res.append(J) - if not groebner or not R.base_ring().is_field(): + K = R.base_ring() + id_rels = R.ideal(rels) + res = dict() + for j in range(n + 1): + if R.ngens() != 1: + J = id_rels + A.fitting_ideal(j) + elif R.ngens() == 1: + J = R.ideal(id_rels.gens() + A.fitting_ideal(j).gens()) + if j <= n1: + J1 = K.ideal([K(p.subs(eval_1)) for p in J.gens()]) + if J1: + J *= ideal_1 + res[j] = J + if not groebner or not ring.is_field(): return res if R.ngens() == 1: - res0 = [gcd(S(p) for p in J.gens()) for J in res] - res1 = [] - for p in res0: - if p == 0: - res1.append([R(0)]) + res = {j: gcd(S(p) for p in res[j].gens()) for j in range(n + 1)} + char_var = dict() + for j in range(n + 1): + if res[j] == 0: + char_var[j] = [R(0)] else: - fct = [q[0] for q in R(p).factor()] + fct = [q[0] for q in R(res[j]).factor()] if fct: - res1.append(fct) - return res1 - res1 = [] - for J in res: - LJ = J.minimal_associated_primes() + char_var[j] = fct + else: + char_var[j] = [R(1)] + return char_var + char_var = dict() + for j in range(n + 1): + LJ = res[j].minimal_associated_primes() fct = [id.groebner_basis() for id in LJ] - if fct != [(S.one(),)]: - res1.append(fct) - return res1 + if fct != [(S.one(), )]: + char_var[j] = fct + else: + char_var[j] = [R(1)] + return char_var def rewriting_system(self): """ diff --git a/src/sage/matrix/matrix_mpolynomial_dense.pyx b/src/sage/matrix/matrix_mpolynomial_dense.pyx index 57f80149e88..d3f22015465 100644 --- a/src/sage/matrix/matrix_mpolynomial_dense.pyx +++ b/src/sage/matrix/matrix_mpolynomial_dense.pyx @@ -669,3 +669,49 @@ cdef class Matrix_laurent_mpolynomial_dense(Matrix_generic_dense): mat_r.rescale_row(j, t ** n) res = res.change_ring(R.polynomial_ring()) return mat_l, res, mat_r + + def _fitting_ideal(self, i): + r""" + Return the `i`-th Fitting ideal of the matrix. This is the ideal generated + by the `n - i` minors, where `n` is the number of columns. + + INPUT: + + ``i`` -- an integer + + OUTPUT: + + An ideal on the base ring. + + EXAMPLES:: + + sage: R. = LaurentPolynomialRing(QQ) + sage: M = matrix(R, [[2*x^-1-z, 0, y-z^-2, 0], [0, z - y^-1, z - x, 0],[z - y, x^-2 - y, 0, z]]) + sage: M + [-z + 2*x^-1 0 y - z^-2 0] + [ 0 z - y^-1 -x + z 0] + [ -y + z -y + x^-2 0 z] + sage: M.fitting_ideal(0) + Ideal (0) of Multivariate Laurent Polynomial Ring in x, y, z over Rational Field + sage: M.fitting_ideal(1) == M._fitting_ideal(1) + True + sage: M.fitting_ideal(1).groebner_basis() + (x^4 - 2*x^3*y - x*z^3 - 4*x^2*y + 8*x*y^2 + 4*x*y*z + 2*z^2 - 8*y, + x*y*z^2 - x*z - 2*y*z + 2, + x^2*z - x*z^2 - 2*x + 2*z, + y^2*z + 1/4*x^2 - 1/2*x*y - 1/4*x*z - y + 1/2) + sage: M.fitting_ideal(2).groebner_basis() + (1,) + sage: M.fitting_ideal(3).groebner_basis() + (1,) + sage: M.fitting_ideal(4).groebner_basis() + (1,) + sage: [R.ideal(M.minors(i)) == M._fitting_ideal(4 - i) for i in range(5)] + [True, True, True, True, True] + + """ + R = self.base_ring() + S = R.polynomial_ring() + A = self.laurent_matrix_reduction()[1].change_ring(S) + J = A._fitting_ideal(i) + return J.change_ring(R) From 68a94e5fd3f168718044d11e5610894a7af2a86e Mon Sep 17 00:00:00 2001 From: Enrique Artal Date: Thu, 28 Sep 2023 22:07:32 +0200 Subject: [PATCH 16/45] adding xgcd, etc, for laurent polynomials in one variable --- src/sage/groups/finitely_presented.py | 6 +- src/sage/matrix/matrix2.pyx | 14 +-- src/sage/matrix/matrix_mpolynomial_dense.pyx | 6 +- .../rings/polynomial/laurent_polynomial.pyx | 113 ++++++++++++++++++ .../polynomial/laurent_polynomial_ideal.py | 10 ++ 5 files changed, 135 insertions(+), 14 deletions(-) diff --git a/src/sage/groups/finitely_presented.py b/src/sage/groups/finitely_presented.py index c96ea32c0da..d2192bdcbbd 100644 --- a/src/sage/groups/finitely_presented.py +++ b/src/sage/groups/finitely_presented.py @@ -1814,10 +1814,8 @@ def characteristic_varieties(self, ring=QQ, matrix_ideal=None, groebner=False): id_rels = R.ideal(rels) res = dict() for j in range(n + 1): - if R.ngens() != 1: - J = id_rels + A.fitting_ideal(j) - elif R.ngens() == 1: - J = R.ideal(id_rels.gens() + A.fitting_ideal(j).gens()) + # J = id_rels + A.fitting_ideal(j) + J = R.ideal(id_rels.gens() + A.fitting_ideal(j).gens()) if j <= n1: J1 = K.ideal([K(p.subs(eval_1)) for p in J.gens()]) if J1: diff --git a/src/sage/matrix/matrix2.pyx b/src/sage/matrix/matrix2.pyx index 09a90f0c2a1..a872e2264a2 100644 --- a/src/sage/matrix/matrix2.pyx +++ b/src/sage/matrix/matrix2.pyx @@ -15902,7 +15902,7 @@ cdef class Matrix(Matrix1): dd, uu, vv = mm.smith_form(transformation=True) else: dd = mm.smith_form(transformation=False) - d = dd.new_matrix(1,1,[t[0,0]]).block_sum(dd) + d = dd.new_matrix(1, 1, [t[0, 0]]).block_sum(dd) if transformation: u = uu.new_matrix(1, 1, [1]).block_sum(uu) * u v = v * vv.new_matrix(1, 1, [1]).block_sum(vv) @@ -18121,9 +18121,9 @@ def _smith_diag(d, transformation=True): else: left = right = None for i in range(n): - I = ideal_or_fractional(R, dp[i, i]) + I0 = ideal_or_fractional(R, dp[i, i]) - if I == ideal_or_fractional(R, 1): + if I0 == ideal_or_fractional(R, 1): if dp[i, i] != 1: if transformation: left.add_multiple_of_row(i, i, R(R(1) / (dp[i, i])) - 1) @@ -18131,7 +18131,7 @@ def _smith_diag(d, transformation=True): continue for j in range(i + 1, n): - if dp[j, j] not in I: + if dp[j, j] not in I0: t = ideal_or_fractional(R, [dp[i, i], dp[j, j]]).gens_reduced() if len(t) > 1: raise ArithmeticError @@ -18215,9 +18215,9 @@ def _generic_clear_column(m): # [e,f] # is invertible over R - I = ideal_or_fractional(R, a[0, 0]) # need to make sure we change this when a[0,0] changes + I0 = ideal_or_fractional(R, a[0, 0]) # need to make sure we change this when a[0,0] changes for k in range(1, a.nrows()): - if a[k, 0] not in I: + if a[k, 0] not in I0: try: v = ideal_or_fractional(R, a[0, 0], a[k, 0]).gens_reduced() except Exception as msg: @@ -18257,7 +18257,7 @@ def _generic_clear_column(m): if newlmat.det() != 1: raise ArithmeticError a = newlmat*a - I = ideal_or_fractional(R, a[0, 0]) + I0 = ideal_or_fractional(R, a[0, 0]) left_mat = newlmat*left_mat if left_mat * m != a: raise ArithmeticError diff --git a/src/sage/matrix/matrix_mpolynomial_dense.pyx b/src/sage/matrix/matrix_mpolynomial_dense.pyx index d3f22015465..840be75c387 100644 --- a/src/sage/matrix/matrix_mpolynomial_dense.pyx +++ b/src/sage/matrix/matrix_mpolynomial_dense.pyx @@ -656,13 +656,13 @@ cdef class Matrix_laurent_mpolynomial_dense(Matrix_generic_dense): n_rows, n_cols = self.dimensions() mat_l = identity_matrix(R, n_rows) mat_r = identity_matrix(R, n_cols) - res = self - for j, rw in enumerate(self.rows()): + res = self.__copy__() + for j, rw in enumerate(res.rows()): for t in R.gens(): n = min(mon.degree(t) for a in rw for cf, mon in a) res.rescale_row(j, t ** -n) mat_l.rescale_col(j, t ** n) - for j, cl in enumerate(self.columns()): + for j, cl in enumerate(res.columns()): for t in R.gens(): n = min(mon.degree(t) for a in cl for cf, mon in a) res.rescale_col(j, t ** -n) diff --git a/src/sage/rings/polynomial/laurent_polynomial.pyx b/src/sage/rings/polynomial/laurent_polynomial.pyx index 5f563725296..bfb9e4ddd57 100644 --- a/src/sage/rings/polynomial/laurent_polynomial.pyx +++ b/src/sage/rings/polynomial/laurent_polynomial.pyx @@ -1316,6 +1316,119 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): return ~self raise ArithmeticError("element is not a unit") + def xgcd(self, other): + R = self.parent() + S = R.polynomial_ring() + f, df = self.monomial_reduction() + g, dg = other.monomial_reduction() + h, p, q = f.xgcd(g) + return R(h), p / df, q / dg + + def inverse_mod(a, m): + """ + Invert the polynomial ``a`` with respect to ``m``, or raise a :class:`ValueError` + if no such inverse exists. + + The parameter ``m`` may be either a single polynomial or an ideal + (for consistency with :meth:`inverse_mod` in other rings). + + EXAMPLES:: + + sage: S. = LaurentPolynomialRing(QQ) + sage: f = inverse_mod(t^2 + 1, t^3 + 1); f + -1/2*t^2 - 1/2*t + 1/2 + sage: f * (t^2 + 1) % (t^3 + 1) + 1 + sage: f = t.inverse_mod((t + 1)^7); f + -t^6 - 7*t^5 - 21*t^4 - 35*t^3 - 35*t^2 - 21*t - 7 + sage: (f * t) + (t + 1)^7 + 1 + sage: t.inverse_mod(S.ideal((t + 1)^7)) == f + True + + This also works over inexact rings, but note that due to rounding + error the product may not always exactly equal the constant + polynomial 1 and have extra terms with coefficients close to zero. :: + + sage: # needs sage.modules + sage: R. = RDF[] + sage: epsilon = RDF(1).ulp()*50 # Allow an error of up to 50 ulp + sage: f = inverse_mod(x^2 + 1, x^5 + x + 1); f # abs tol 1e-14 + 0.4*x^4 - 0.2*x^3 - 0.4*x^2 + 0.2*x + 0.8 + sage: poly = f * (x^2 + 1) % (x^5 + x + 1) + sage: # Remove noisy zero terms: + sage: parent(poly)([0.0 if abs(c) <= epsilon else c + ....: for c in poly.coefficients(sparse=False)]) + 1.0 + sage: f = inverse_mod(x^3 - x + 1, x - 2); f + 0.14285714285714285 + sage: f * (x^3 - x + 1) % (x - 2) + 1.0 + sage: g = 5*x^3 + x - 7; m = x^4 - 12*x + 13; f = inverse_mod(g, m); f + -0.0319636125...*x^3 - 0.0383269759...*x^2 - 0.0463050900...*x + 0.346479687... + sage: poly = f*g % m + sage: # Remove noisy zero terms: + sage: parent(poly)([0.0 if abs(c) <= epsilon else c # abs tol 1e-14 + ....: for c in poly.coefficients(sparse=False)]) + 1.0000000000000004 + + ALGORITHM: Solve the system `as + mt = 1`, returning `s` as the inverse + of `a` mod `m`. + + Uses the Euclidean algorithm for exact rings, and solves a linear + system for the coefficients of `s` and `t` for inexact rings (as the + Euclidean algorithm may not converge in that case). + """ + from sage.rings.ideal import is_Ideal + if is_Ideal(m): + v = m.gens_reduced() + if len(v) > 1: + raise NotImplementedError("Don't know how to invert modulo non-principal ideal %s" % m) + m = v[0] + if m.degree() == 1 and m[1].is_unit(): + # a(x) mod (x-r) = a(r) + r = -m[0] + if not m[1].is_one(): + r *= m.base_ring()(~m[1]) + u = a(r) + if u.is_unit(): + return a.parent()(~u) + if a.parent().is_exact(): + # use xgcd + g, s, _ = a.xgcd(m) + if g == 1: + return s + elif g.is_unit(): + return g.inverse_of_unit() * s + else: + raise ValueError("Impossible inverse modulo") + else: + # xgcd may not converge for inexact rings. + # Instead solve for the coefficients of + # s (degree n-1) and t (degree n-2) in + # as + mt = 1 + # as a linear system. + from sage.matrix.constructor import matrix + from sage.modules.free_module_element import vector + a %= m + n = m.degree() + R = a.parent().base_ring() + M = matrix(R, 2*n-1) + # a_i s_j x^{i+j} terms + for i in range(n): + for j in range(n): + M[i+j, j] = a[i] + # m_i t_j x^{i+j} terms + for i in range(n+1): + for j in range(n-1): + M[i+j, j+n] = m[i] + v = vector(R, [R.one()] + [R.zero()]*(2*n-2)) # the constant polynomial 1 + if M.is_invertible(): + x = M.solve_right(v) # there has to be a better way to solve + return a.parent()(list(x)[0:n]) + else: + raise ValueError("Impossible inverse modulo") + def _fraction_pair(self): """ Return one representation of ``self`` as a pair diff --git a/src/sage/rings/polynomial/laurent_polynomial_ideal.py b/src/sage/rings/polynomial/laurent_polynomial_ideal.py index b193569d3fa..991a3fa589c 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_ideal.py +++ b/src/sage/rings/polynomial/laurent_polynomial_ideal.py @@ -204,6 +204,16 @@ def __contains__(self, f): g = f.__reduce__()[1][1] return (g in self.polynomial_ideal()) + def gens_reduced(self): + R = self.ring() + if R.ngens() > 1 or not R.base_ring().is_field(): + return self.gens() + gns = self.gens() + res = R(0) + for p in gns: + res = res.gcd(p) + return (res, ) + # Operations on ideals def change_ring(self, R, hint=None): From 8da8781f109e97e87885c0a05c55e5a6d2fef45e Mon Sep 17 00:00:00 2001 From: Enrique Artal Date: Thu, 28 Sep 2023 23:34:10 +0200 Subject: [PATCH 17/45] cut characteristic varieties when the total ideal is reached --- src/sage/groups/finitely_presented.py | 34 ++-- .../matrix_laurent_mpolynomial_dense.pyx | 168 +++++++++++++----- src/sage/matrix/matrix_mpolynomial_dense.pyx | 96 ---------- src/sage/matrix/matrix_space.py | 4 +- .../rings/polynomial/laurent_polynomial.pyx | 95 +++------- 5 files changed, 169 insertions(+), 228 deletions(-) diff --git a/src/sage/groups/finitely_presented.py b/src/sage/groups/finitely_presented.py index d2192bdcbbd..391cefc336c 100644 --- a/src/sage/groups/finitely_presented.py +++ b/src/sage/groups/finitely_presented.py @@ -1784,21 +1784,25 @@ def characteristic_varieties(self, ring=QQ, matrix_ideal=None, groebner=False): (f1 - 1, f2 - 1, f3 - 1), (f1 - 1, f2 + 1, f3 - 1), (f1 + 1, f2 - 1, f3 - 1)], - 3: [(f1 - 1, f2 - 1, f3 - 1)]} + 3: [(f1 - 1, f2 - 1, f3 - 1)], + 4: []} sage: G = FreeGroup(2)/[2*(1,2,-1,-2)] sage: G.characteristic_varieties() {0: Ideal (0, 0) of Multivariate Laurent Polynomial Ring in f1, f2 over Rational Field, 1: Ideal (0, -2*f2 + 2, 2*f1 - 2) of Multivariate Laurent Polynomial Ring in f1, f2 over Rational Field, - 2: Ideal (f1 - 1, f2 - 1) of Multivariate Laurent Polynomial Ring in f1, f2 over Rational Field} + 2: Ideal (f1 - 1, f2 - 1) of Multivariate Laurent Polynomial Ring in f1, f2 over Rational Field, + 3: Ideal (0, 1) of Multivariate Laurent Polynomial Ring in f1, f2 over Rational Field} sage: G.characteristic_varieties(ring=ZZ) {0: Ideal (0, 0) of Multivariate Laurent Polynomial Ring in f1, f2 over Integer Ring, 1: Ideal (0, -2*f2 + 2, 2*f1 - 2) of Multivariate Laurent Polynomial Ring in f1, f2 over Integer Ring, - 2: Ideal (f1 - 1, f2 - 1) of Multivariate Laurent Polynomial Ring in f1, f2 over Integer Ring} + 2: Ideal (f1 - 1, f2 - 1) of Multivariate Laurent Polynomial Ring in f1, f2 over Integer Ring, + 3: Ideal (0, 1) of Multivariate Laurent Polynomial Ring in f1, f2 over Integer Ring} sage: G = FreeGroup(2)/[(1,2,1,-2,-1,-2)] sage: G.characteristic_varieties() {0: Ideal (0, 0) of Univariate Laurent Polynomial Ring in f2 over Rational Field, 1: Ideal (-1 + 2*f2 - 2*f2^2 + f2^3, 1 - 2*f2 + 2*f2^2 - f2^3) of Univariate Laurent Polynomial Ring in f2 over Rational Field, - 2: Ideal (0, 1) of Univariate Laurent Polynomial Ring in f2 over Rational Field} + 2: Ideal (0, 1) of Univariate Laurent Polynomial Ring in f2 over Rational Field, + 3: Ideal (0, 1) of Univariate Laurent Polynomial Ring in f2 over Rational Field} sage: G.characteristic_varieties(groebner=True) {0: [0], 1: [-1 + f2, 1 - f2 + f2^2], 2: [1]} """ @@ -1813,7 +1817,7 @@ def characteristic_varieties(self, ring=QQ, matrix_ideal=None, groebner=False): K = R.base_ring() id_rels = R.ideal(rels) res = dict() - for j in range(n + 1): + for j in range(n + 2): # J = id_rels + A.fitting_ideal(j) J = R.ideal(id_rels.gens() + A.fitting_ideal(j).gens()) if j <= n1: @@ -1824,9 +1828,11 @@ def characteristic_varieties(self, ring=QQ, matrix_ideal=None, groebner=False): if not groebner or not ring.is_field(): return res if R.ngens() == 1: - res = {j: gcd(S(p) for p in res[j].gens()) for j in range(n + 1)} + res = {j: gcd(S(p) for p in res[j].gens()) for j in range(n + 2)} char_var = dict() - for j in range(n + 1): + strict = True + j = 0 + while strict and j <= n + 1: if res[j] == 0: char_var[j] = [R(0)] else: @@ -1835,15 +1841,19 @@ def characteristic_varieties(self, ring=QQ, matrix_ideal=None, groebner=False): char_var[j] = fct else: char_var[j] = [R(1)] + strict = False + j += 1 return char_var char_var = dict() - for j in range(n + 1): + strict = True + j = 0 + while strict and j <= n + 1: LJ = res[j].minimal_associated_primes() fct = [id.groebner_basis() for id in LJ] - if fct != [(S.one(), )]: - char_var[j] = fct - else: - char_var[j] = [R(1)] + char_var[j] = fct + if not fct: + strict = False + j += 1 return char_var def rewriting_system(self): diff --git a/src/sage/matrix/matrix_laurent_mpolynomial_dense.pyx b/src/sage/matrix/matrix_laurent_mpolynomial_dense.pyx index c26b667b492..769608b3ce1 100644 --- a/src/sage/matrix/matrix_laurent_mpolynomial_dense.pyx +++ b/src/sage/matrix/matrix_laurent_mpolynomial_dense.pyx @@ -1,50 +1,128 @@ +""" +Dense matrices over multivariate polynomials over fields + +This implementation inherits from Matrix_generic_dense, i.e. it is not +optimized for speed only some methods were added. + +AUTHOR: + +* Martin Albrecht +""" + +# ***************************************************************************** +# Copyright (C) 2013 Martin Albrecht +# +# Distributed under the terms of the GNU General Public License (GPL) +# as published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# https://www.gnu.org/licenses/ +# ***************************************************************************** +from sage.matrix.matrix_generic_dense cimport Matrix_generic_dense + +# from sage.matrix.matrix2 cimport Matrix +# +# from sage.matrix.constructor import identity_matrix +# from sage.rings.polynomial.laurent_polynomial_ring_base import LaurentPolynomialRing_generic +# from sage.rings.polynomial.multi_polynomial_libsingular cimport MPolynomialRing_libsingular +# from sage.rings.polynomial.polynomial_singular_interface import can_convert_to_singular +# +# from sage.libs.singular.function import singular_function, lib +# +# from cysignals.signals cimport sig_on, sig_off + from sage.matrix.constructor import identity_matrix from sage.rings.polynomial.laurent_polynomial_ring_base import LaurentPolynomialRing_generic - -def laurent_matrix_reduction(A): +cdef class Matrix_laurent_mpolynomial_dense(Matrix_generic_dense): """ - From a matrix `A` of Laurent polynomials, apply elementary operations - to obtain a matrix `P` of polynomials such that the variables do not divide - no column and no row. - - OUTPUT: Three matrices `L`, `P`, `R` such that `A = L P R`, where `L` and - `R` are diagonal with monomial entries. - - EXAMPLES: - - sage: from sage.rings.polynomial.laurent_reduction import laurent_matrix_reduction - sage: R. = LaurentPolynomialRing(QQ) - sage: L = [1/3*x^-1*y - 6*x^-2*y^2 - 1/2*x^-2*y, 1/5*x + 1/2*y + 1/6] - sage: L += [1/2 - 5*x^-1*y - 2*x^-1, -1/3*y^-2 - 4*x^-1*y^-1 + 11*x^-1*y^-2] - sage: A = matrix(R, 2, L) - sage: lf, P, rg = laurent_matrix_reduction(A) - sage: lf - [ x^-2 0] - [ 0 x^-1*y^-2] - sage: P - [ 1/3*x - 6*y - 1/2 1/5*x^3 + 1/2*x^2*y + 1/6*x^2] - [ 1/2*x*y - 5*y^2 - 2*y -1/3*x - 4*y + 11] - sage: rg - [y 0] - [0 1] + Dense matrix over a multivariate polynomial ring over a field. """ - R = A.base_ring() - n_rows, n_cols = A.dimensions() - mat_l = identity_matrix(R, n_rows) - mat_r = identity_matrix(R, n_cols) - if not isinstance(R, LaurentPolynomialRing_generic): - return mat_l, A, mat_r - res = A - for j, rw in enumerate(A.rows()): - for t in R.gens(): - n = min(mon.degree(t) for a in rw for cf, mon in a) - res.rescale_row(j, t ** -n) - mat_l.rescale_col(j, t ** n) - for j, cl in enumerate(A.columns()): - for t in R.gens(): - n = min(mon.degree(t) for a in cl for cf, mon in a) - res.rescale_col(j, t ** -n) - mat_r.rescale_row(j, t ** n) - res = res.change_ring(R.polynomial_ring()) - return mat_l, res, mat_r + def laurent_matrix_reduction(self): + """ + From a matrix `self` of Laurent polynomials, apply elementary operations + to obtain a matrix `P` of polynomials such that the variables do not divide + no column and no row. + + OUTPUT: Three matrices `L`, `P`, `R` such that `self = L P R`, where `L` and + `R` are diagonal with monomial entries. + + EXAMPLES: + + sage: R. = LaurentPolynomialRing(QQ) + sage: L = [1/3*x^-1*y - 6*x^-2*y^2 - 1/2*x^-2*y, 1/5*x + 1/2*y + 1/6] + sage: L += [1/2 - 5*x^-1*y - 2*x^-1, -1/3*y^-2 - 4*x^-1*y^-1 + 11*x^-1*y^-2] + sage: A = matrix(R, 2, L) + sage: lf, P, rg = A.laurent_matrix_reduction() + sage: lf + [ x^-2 0] + [ 0 x^-1*y^-2] + sage: P + [ 1/3*x - 6*y - 1/2 1/5*x^3 + 1/2*x^2*y + 1/6*x^2] + [ 1/2*x*y - 5*y^2 - 2*y -1/3*x - 4*y + 11] + sage: rg + [y 0] + [0 1] + """ + R = self.base_ring() + n_rows, n_cols = self.dimensions() + mat_l = identity_matrix(R, n_rows) + mat_r = identity_matrix(R, n_cols) + res = self.__copy__() + for j, rw in enumerate(res.rows()): + for t in R.gens(): + n = min(mon.degree(t) for a in rw for cf, mon in a) + res.rescale_row(j, t ** -n) + mat_l.rescale_col(j, t ** n) + for j, cl in enumerate(res.columns()): + for t in R.gens(): + n = min(mon.degree(t) for a in cl for cf, mon in a) + res.rescale_col(j, t ** -n) + mat_r.rescale_row(j, t ** n) + res = res.change_ring(R.polynomial_ring()) + return mat_l, res, mat_r + + def _fitting_ideal(self, i): + r""" + Return the `i`-th Fitting ideal of the matrix. This is the ideal generated + by the `n - i` minors, where `n` is the number of columns. + + INPUT: + + ``i`` -- an integer + + OUTPUT: + + An ideal on the base ring. + + EXAMPLES:: + + sage: R. = LaurentPolynomialRing(QQ) + sage: M = matrix(R, [[2*x^-1-z, 0, y-z^-2, 0], [0, z - y^-1, z - x, 0],[z - y, x^-2 - y, 0, z]]) + sage: M + [-z + 2*x^-1 0 y - z^-2 0] + [ 0 z - y^-1 -x + z 0] + [ -y + z -y + x^-2 0 z] + sage: M.fitting_ideal(0) + Ideal (0) of Multivariate Laurent Polynomial Ring in x, y, z over Rational Field + sage: M.fitting_ideal(1) == M._fitting_ideal(1) + True + sage: M.fitting_ideal(1).groebner_basis() + (x^4 - 2*x^3*y - x*z^3 - 4*x^2*y + 8*x*y^2 + 4*x*y*z + 2*z^2 - 8*y, + x*y*z^2 - x*z - 2*y*z + 2, + x^2*z - x*z^2 - 2*x + 2*z, + y^2*z + 1/4*x^2 - 1/2*x*y - 1/4*x*z - y + 1/2) + sage: M.fitting_ideal(2).groebner_basis() + (1,) + sage: M.fitting_ideal(3).groebner_basis() + (1,) + sage: M.fitting_ideal(4).groebner_basis() + (1,) + sage: [R.ideal(M.minors(i)) == M._fitting_ideal(4 - i) for i in range(5)] + [True, True, True, True, True] + + """ + R = self.base_ring() + S = R.polynomial_ring() + A = self.laurent_matrix_reduction()[1].change_ring(S) + J = A._fitting_ideal(i) + return J.change_ring(R) diff --git a/src/sage/matrix/matrix_mpolynomial_dense.pyx b/src/sage/matrix/matrix_mpolynomial_dense.pyx index 840be75c387..589b5b33331 100644 --- a/src/sage/matrix/matrix_mpolynomial_dense.pyx +++ b/src/sage/matrix/matrix_mpolynomial_dense.pyx @@ -20,8 +20,6 @@ AUTHOR: from sage.matrix.matrix_generic_dense cimport Matrix_generic_dense from sage.matrix.matrix2 cimport Matrix -from sage.matrix.constructor import identity_matrix -from sage.rings.polynomial.laurent_polynomial_ring_base import LaurentPolynomialRing_generic from sage.rings.polynomial.multi_polynomial_libsingular cimport MPolynomialRing_libsingular from sage.rings.polynomial.polynomial_singular_interface import can_convert_to_singular @@ -621,97 +619,3 @@ cdef class Matrix_mpolynomial_dense(Matrix_generic_dense): self.cache('det', d) return d - -cdef class Matrix_laurent_mpolynomial_dense(Matrix_generic_dense): - """ - Dense matrix over a multivariate polynomial ring over a field. - """ - def laurent_matrix_reduction(self): - """ - From a matrix `self` of Laurent polynomials, apply elementary operations - to obtain a matrix `P` of polynomials such that the variables do not divide - no column and no row. - - OUTPUT: Three matrices `L`, `P`, `R` such that `self = L P R`, where `L` and - `R` are diagonal with monomial entries. - - EXAMPLES: - - sage: R. = LaurentPolynomialRing(QQ) - sage: L = [1/3*x^-1*y - 6*x^-2*y^2 - 1/2*x^-2*y, 1/5*x + 1/2*y + 1/6] - sage: L += [1/2 - 5*x^-1*y - 2*x^-1, -1/3*y^-2 - 4*x^-1*y^-1 + 11*x^-1*y^-2] - sage: A = matrix(R, 2, L) - sage: lf, P, rg = A.laurent_matrix_reduction() - sage: lf - [ x^-2 0] - [ 0 x^-1*y^-2] - sage: P - [ 1/3*x - 6*y - 1/2 1/5*x^3 + 1/2*x^2*y + 1/6*x^2] - [ 1/2*x*y - 5*y^2 - 2*y -1/3*x - 4*y + 11] - sage: rg - [y 0] - [0 1] - """ - R = self.base_ring() - n_rows, n_cols = self.dimensions() - mat_l = identity_matrix(R, n_rows) - mat_r = identity_matrix(R, n_cols) - res = self.__copy__() - for j, rw in enumerate(res.rows()): - for t in R.gens(): - n = min(mon.degree(t) for a in rw for cf, mon in a) - res.rescale_row(j, t ** -n) - mat_l.rescale_col(j, t ** n) - for j, cl in enumerate(res.columns()): - for t in R.gens(): - n = min(mon.degree(t) for a in cl for cf, mon in a) - res.rescale_col(j, t ** -n) - mat_r.rescale_row(j, t ** n) - res = res.change_ring(R.polynomial_ring()) - return mat_l, res, mat_r - - def _fitting_ideal(self, i): - r""" - Return the `i`-th Fitting ideal of the matrix. This is the ideal generated - by the `n - i` minors, where `n` is the number of columns. - - INPUT: - - ``i`` -- an integer - - OUTPUT: - - An ideal on the base ring. - - EXAMPLES:: - - sage: R. = LaurentPolynomialRing(QQ) - sage: M = matrix(R, [[2*x^-1-z, 0, y-z^-2, 0], [0, z - y^-1, z - x, 0],[z - y, x^-2 - y, 0, z]]) - sage: M - [-z + 2*x^-1 0 y - z^-2 0] - [ 0 z - y^-1 -x + z 0] - [ -y + z -y + x^-2 0 z] - sage: M.fitting_ideal(0) - Ideal (0) of Multivariate Laurent Polynomial Ring in x, y, z over Rational Field - sage: M.fitting_ideal(1) == M._fitting_ideal(1) - True - sage: M.fitting_ideal(1).groebner_basis() - (x^4 - 2*x^3*y - x*z^3 - 4*x^2*y + 8*x*y^2 + 4*x*y*z + 2*z^2 - 8*y, - x*y*z^2 - x*z - 2*y*z + 2, - x^2*z - x*z^2 - 2*x + 2*z, - y^2*z + 1/4*x^2 - 1/2*x*y - 1/4*x*z - y + 1/2) - sage: M.fitting_ideal(2).groebner_basis() - (1,) - sage: M.fitting_ideal(3).groebner_basis() - (1,) - sage: M.fitting_ideal(4).groebner_basis() - (1,) - sage: [R.ideal(M.minors(i)) == M._fitting_ideal(4 - i) for i in range(5)] - [True, True, True, True, True] - - """ - R = self.base_ring() - S = R.polynomial_ring() - A = self.laurent_matrix_reduction()[1].change_ring(S) - J = A._fitting_ideal(i) - return J.change_ring(R) diff --git a/src/sage/matrix/matrix_space.py b/src/sage/matrix/matrix_space.py index 31e2ce46224..04ab6b138a2 100644 --- a/src/sage/matrix/matrix_space.py +++ b/src/sage/matrix/matrix_space.py @@ -308,11 +308,11 @@ def get_matrix_class(R, nrows, ncols, sparse, implementation): return matrix_mpolynomial_dense.Matrix_mpolynomial_dense elif isinstance(R, sage.rings.polynomial.laurent_polynomial_ring.LaurentPolynomialRing_mpair) and R.base_ring() in _Fields: try: - from . import matrix_mpolynomial_dense + from . import matrix_laurent_mpolynomial_dense except ImportError: pass else: - return matrix_mpolynomial_dense.Matrix_laurent_mpolynomial_dense + return matrix_laurent_mpolynomial_dense.Matrix_laurent_mpolynomial_dense # The fallback from sage.matrix.matrix_generic_dense import Matrix_generic_dense diff --git a/src/sage/rings/polynomial/laurent_polynomial.pyx b/src/sage/rings/polynomial/laurent_polynomial.pyx index bfb9e4ddd57..d4dff8b1361 100644 --- a/src/sage/rings/polynomial/laurent_polynomial.pyx +++ b/src/sage/rings/polynomial/laurent_polynomial.pyx @@ -1317,7 +1317,18 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): raise ArithmeticError("element is not a unit") def xgcd(self, other): + """ + Extended `gcd` for univariate Laurent polynomial rings over a field. + + EXAMPLES:: + + sage: S. = LaurentPolynomialRing(QQ) + sage: (t^-2 + 1).xgcd(t^-3 + 1) + (1, 1/2*t^2 - 1/2*t^3 - 1/2*t^4, 1/2*t^3 + 1/2*t^4) + """ R = self.parent() + if not R.is_exact() or not R.base_ring().is_field: + raise NotImplementedError("Not implemented") S = R.polynomial_ring() f, df = self.monomial_reduction() g, dg = other.monomial_reduction() @@ -1335,49 +1346,13 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): EXAMPLES:: sage: S. = LaurentPolynomialRing(QQ) - sage: f = inverse_mod(t^2 + 1, t^3 + 1); f - -1/2*t^2 - 1/2*t + 1/2 - sage: f * (t^2 + 1) % (t^3 + 1) - 1 - sage: f = t.inverse_mod((t + 1)^7); f - -t^6 - 7*t^5 - 21*t^4 - 35*t^3 - 35*t^2 - 21*t - 7 - sage: (f * t) + (t + 1)^7 + sage: f = inverse_mod(t^-2 + 1, t^-3 + 1); f + 1/2*t^2 - 1/2*t^3 - 1/2*t^4 + sage: f * (t^-2 + 1) + (1/2*t^4 + 1/2*t^3) * (t^-3 + 1) 1 - sage: t.inverse_mod(S.ideal((t + 1)^7)) == f - True - - This also works over inexact rings, but note that due to rounding - error the product may not always exactly equal the constant - polynomial 1 and have extra terms with coefficients close to zero. :: - - sage: # needs sage.modules - sage: R. = RDF[] - sage: epsilon = RDF(1).ulp()*50 # Allow an error of up to 50 ulp - sage: f = inverse_mod(x^2 + 1, x^5 + x + 1); f # abs tol 1e-14 - 0.4*x^4 - 0.2*x^3 - 0.4*x^2 + 0.2*x + 0.8 - sage: poly = f * (x^2 + 1) % (x^5 + x + 1) - sage: # Remove noisy zero terms: - sage: parent(poly)([0.0 if abs(c) <= epsilon else c - ....: for c in poly.coefficients(sparse=False)]) - 1.0 - sage: f = inverse_mod(x^3 - x + 1, x - 2); f - 0.14285714285714285 - sage: f * (x^3 - x + 1) % (x - 2) - 1.0 - sage: g = 5*x^3 + x - 7; m = x^4 - 12*x + 13; f = inverse_mod(g, m); f - -0.0319636125...*x^3 - 0.0383269759...*x^2 - 0.0463050900...*x + 0.346479687... - sage: poly = f*g % m - sage: # Remove noisy zero terms: - sage: parent(poly)([0.0 if abs(c) <= epsilon else c # abs tol 1e-14 - ....: for c in poly.coefficients(sparse=False)]) - 1.0000000000000004 ALGORITHM: Solve the system `as + mt = 1`, returning `s` as the inverse of `a` mod `m`. - - Uses the Euclidean algorithm for exact rings, and solves a linear - system for the coefficients of `s` and `t` for inexact rings (as the - Euclidean algorithm may not converge in that case). """ from sage.rings.ideal import is_Ideal if is_Ideal(m): @@ -1393,41 +1368,15 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): u = a(r) if u.is_unit(): return a.parent()(~u) - if a.parent().is_exact(): - # use xgcd - g, s, _ = a.xgcd(m) - if g == 1: - return s - elif g.is_unit(): - return g.inverse_of_unit() * s - else: - raise ValueError("Impossible inverse modulo") + if not a.parent().is_exact(): + raise NotImplementedError("Not implemented") + g, s, _ = a.xgcd(m) + if g == 1: + return s + elif g.is_unit(): + return g.inverse_of_unit() * s else: - # xgcd may not converge for inexact rings. - # Instead solve for the coefficients of - # s (degree n-1) and t (degree n-2) in - # as + mt = 1 - # as a linear system. - from sage.matrix.constructor import matrix - from sage.modules.free_module_element import vector - a %= m - n = m.degree() - R = a.parent().base_ring() - M = matrix(R, 2*n-1) - # a_i s_j x^{i+j} terms - for i in range(n): - for j in range(n): - M[i+j, j] = a[i] - # m_i t_j x^{i+j} terms - for i in range(n+1): - for j in range(n-1): - M[i+j, j+n] = m[i] - v = vector(R, [R.one()] + [R.zero()]*(2*n-2)) # the constant polynomial 1 - if M.is_invertible(): - x = M.solve_right(v) # there has to be a better way to solve - return a.parent()(list(x)[0:n]) - else: - raise ValueError("Impossible inverse modulo") + raise ValueError("Impossible inverse modulo") def _fraction_pair(self): """ From 1153822b0e99841d74bf629ba51ec5d32ddd5d92 Mon Sep 17 00:00:00 2001 From: Enrique Artal Date: Thu, 28 Sep 2023 23:41:51 +0200 Subject: [PATCH 18/45] trailing spaces --- src/sage/matrix/matrix_laurent_mpolynomial_dense.pyx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/matrix/matrix_laurent_mpolynomial_dense.pyx b/src/sage/matrix/matrix_laurent_mpolynomial_dense.pyx index 769608b3ce1..4a5d3b1ea2a 100644 --- a/src/sage/matrix/matrix_laurent_mpolynomial_dense.pyx +++ b/src/sage/matrix/matrix_laurent_mpolynomial_dense.pyx @@ -20,14 +20,14 @@ AUTHOR: from sage.matrix.matrix_generic_dense cimport Matrix_generic_dense # from sage.matrix.matrix2 cimport Matrix -# +# # from sage.matrix.constructor import identity_matrix # from sage.rings.polynomial.laurent_polynomial_ring_base import LaurentPolynomialRing_generic # from sage.rings.polynomial.multi_polynomial_libsingular cimport MPolynomialRing_libsingular # from sage.rings.polynomial.polynomial_singular_interface import can_convert_to_singular -# +# # from sage.libs.singular.function import singular_function, lib -# +# # from cysignals.signals cimport sig_on, sig_off from sage.matrix.constructor import identity_matrix From cbcc182b07a5f1664826aee23bf8e9712d5eec57 Mon Sep 17 00:00:00 2001 From: Enrique Artal Date: Fri, 29 Sep 2023 12:16:03 +0200 Subject: [PATCH 19/45] redefine gens_reduced and more doctests --- src/sage/groups/finitely_presented.py | 63 +++++++++---------- .../matrix_laurent_mpolynomial_dense.pyx | 4 +- .../polynomial/laurent_polynomial_ideal.py | 9 +-- 3 files changed, 35 insertions(+), 41 deletions(-) diff --git a/src/sage/groups/finitely_presented.py b/src/sage/groups/finitely_presented.py index 391cefc336c..2552cc0940c 100644 --- a/src/sage/groups/finitely_presented.py +++ b/src/sage/groups/finitely_presented.py @@ -1762,9 +1762,10 @@ def characteristic_varieties(self, ring=QQ, matrix_ideal=None, groebner=False): OUTPUT: - If ``groebner`` is ``False`` a list of ideals defining the characteristic varieties. - If it is ``True``, a list of lists for Gröbner bases for the ideal of each irreducible - component. + A dictionary with keys the indices of the varieties. If ``groebner`` is ``False`` + the values are the ideals defining the characteristic varieties. + If it is ``True``, lists for Gröbner bases for the ideal of each irreducible + component, stopping when the first time a characteristic variety is empty. EXAMPLES:: @@ -1772,39 +1773,37 @@ def characteristic_varieties(self, ring=QQ, matrix_ideal=None, groebner=False): sage: G = FreeGroup(3) / L sage: G.characteristic_varieties(groebner=True) {0: [(0,)], - 1: [(f1 - 1, f2 - 1, f3 - 1), - (f1*f3 + 1, f2 - 1), - (f1*f2 + 1, f3 - 1), - (f2*f3 + 1, f1 - 1), - (f2*f3 + 1, f1 - f2), - (f2*f3 + 1, f1 - f3), - (f1*f3 + 1, f2 - f3)], - 2: [(f1 - 1, f2 - 1, f3 + 1), - (f3^2 + 1, f1 - f3, f2 - f3), - (f1 - 1, f2 - 1, f3 - 1), - (f1 - 1, f2 + 1, f3 - 1), - (f1 + 1, f2 - 1, f3 - 1)], - 3: [(f1 - 1, f2 - 1, f3 - 1)], - 4: []} + 1: [(f1 - 1, f2 - 1, f3 - 1), (f1*f3 + 1, f2 - 1), (f1*f2 + 1, f3 - 1), (f2*f3 + 1, f1 - 1), + (f2*f3 + 1, f1 - f2), (f2*f3 + 1, f1 - f3), (f1*f3 + 1, f2 - f3)], + 2: [(f1 - 1, f2 - 1, f3 - 1), (f1 + 1, f2 - 1, f3 - 1), (f1 - 1, f2 - 1, f3 + 1), + (f3^2 + 1, f1 - f3, f2 - f3), (f1 - 1, f2 + 1, f3 - 1)], + 3: [(f1 - 1, f2 - 1, f3 - 1)], + 4: []} sage: G = FreeGroup(2)/[2*(1,2,-1,-2)] sage: G.characteristic_varieties() - {0: Ideal (0, 0) of Multivariate Laurent Polynomial Ring in f1, f2 over Rational Field, - 1: Ideal (0, -2*f2 + 2, 2*f1 - 2) of Multivariate Laurent Polynomial Ring in f1, f2 over Rational Field, - 2: Ideal (f1 - 1, f2 - 1) of Multivariate Laurent Polynomial Ring in f1, f2 over Rational Field, - 3: Ideal (0, 1) of Multivariate Laurent Polynomial Ring in f1, f2 over Rational Field} + {0: Ideal (0) of Multivariate Laurent Polynomial Ring in f1, f2 over Rational Field, + 1: Ideal (f2 - 1, f1 - 1) of Multivariate Laurent Polynomial Ring in f1, f2 over Rational Field, + 2: Ideal (f2 - 1, f1 - 1) of Multivariate Laurent Polynomial Ring in f1, f2 over Rational Field, + 3: Ideal (1) of Multivariate Laurent Polynomial Ring in f1, f2 over Rational Field} sage: G.characteristic_varieties(ring=ZZ) - {0: Ideal (0, 0) of Multivariate Laurent Polynomial Ring in f1, f2 over Integer Ring, - 1: Ideal (0, -2*f2 + 2, 2*f1 - 2) of Multivariate Laurent Polynomial Ring in f1, f2 over Integer Ring, - 2: Ideal (f1 - 1, f2 - 1) of Multivariate Laurent Polynomial Ring in f1, f2 over Integer Ring, - 3: Ideal (0, 1) of Multivariate Laurent Polynomial Ring in f1, f2 over Integer Ring} + {0: Ideal (0) of Multivariate Laurent Polynomial Ring in f1, f2 over Integer Ring, + 1: Ideal (2*f2 - 2, 2*f1 - 2) of Multivariate Laurent Polynomial Ring in f1, f2 over Integer Ring, + 2: Ideal (f2 - 1, f1 - 1) of Multivariate Laurent Polynomial Ring in f1, f2 over Integer Ring, + 3: Ideal (1) of Multivariate Laurent Polynomial Ring in f1, f2 over Integer Ring} sage: G = FreeGroup(2)/[(1,2,1,-2,-1,-2)] sage: G.characteristic_varieties() - {0: Ideal (0, 0) of Univariate Laurent Polynomial Ring in f2 over Rational Field, - 1: Ideal (-1 + 2*f2 - 2*f2^2 + f2^3, 1 - 2*f2 + 2*f2^2 - f2^3) of Univariate Laurent Polynomial Ring in f2 over Rational Field, - 2: Ideal (0, 1) of Univariate Laurent Polynomial Ring in f2 over Rational Field, - 3: Ideal (0, 1) of Univariate Laurent Polynomial Ring in f2 over Rational Field} + {0: Ideal (0) of Univariate Laurent Polynomial Ring in f2 over Rational Field, + 1: Ideal (-1 + 2*f2 - 2*f2^2 + f2^3) of Univariate Laurent Polynomial Ring in f2 over Rational Field, + 2: Ideal (1) of Univariate Laurent Polynomial Ring in f2 over Rational Field, + 3: Ideal (1) of Univariate Laurent Polynomial Ring in f2 over Rational Field} sage: G.characteristic_varieties(groebner=True) - {0: [0], 1: [-1 + f2, 1 - f2 + f2^2], 2: [1]} + {0: [0], 1: [-1 + f2, 1 - f2 + f2^2], 2: []} + sage: G = FreeGroup(2)/[3 * (1, ), 2 * (2, )] + sage: G.characteristic_varieties(groebner=True) + {0: [-1 + F1, 1 + F1, 1 - F1 + F1^2, 1 + F1 + F1^2], 1: [1 - F1 + F1^2], 2: []} + sage: G = FreeGroup(2)/[2 * (2, )] + sage: G.characteristic_varieties(groebner=True) + {0: [(f1 + 1,), (f1 - 1,)], 1: [(f1 + 1,), (f1 - 1, f2 - 1)], 2: []} """ A, rels = self.abelian_alexander_matrix(ring=ring, simplified=True) R = A.base_ring() @@ -1824,7 +1823,7 @@ def characteristic_varieties(self, ring=QQ, matrix_ideal=None, groebner=False): J1 = K.ideal([K(p.subs(eval_1)) for p in J.gens()]) if J1: J *= ideal_1 - res[j] = J + res[j] = R.ideal(J.gens_reduced()) if not groebner or not ring.is_field(): return res if R.ngens() == 1: @@ -1840,7 +1839,7 @@ def characteristic_varieties(self, ring=QQ, matrix_ideal=None, groebner=False): if fct: char_var[j] = fct else: - char_var[j] = [R(1)] + char_var[j] = [] strict = False j += 1 return char_var diff --git a/src/sage/matrix/matrix_laurent_mpolynomial_dense.pyx b/src/sage/matrix/matrix_laurent_mpolynomial_dense.pyx index 4a5d3b1ea2a..3f0c1e968f2 100644 --- a/src/sage/matrix/matrix_laurent_mpolynomial_dense.pyx +++ b/src/sage/matrix/matrix_laurent_mpolynomial_dense.pyx @@ -6,11 +6,11 @@ optimized for speed only some methods were added. AUTHOR: -* Martin Albrecht +* Enrique Artal """ # ***************************************************************************** -# Copyright (C) 2013 Martin Albrecht +# Copyright (C) 2023 Enrique Artal # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of diff --git a/src/sage/rings/polynomial/laurent_polynomial_ideal.py b/src/sage/rings/polynomial/laurent_polynomial_ideal.py index 991a3fa589c..5c938466e1c 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_ideal.py +++ b/src/sage/rings/polynomial/laurent_polynomial_ideal.py @@ -206,13 +206,8 @@ def __contains__(self, f): def gens_reduced(self): R = self.ring() - if R.ngens() > 1 or not R.base_ring().is_field(): - return self.gens() - gns = self.gens() - res = R(0) - for p in gns: - res = res.gcd(p) - return (res, ) + J = self.polynomial_ideal() + return tuple(R(p) for p in J.gens()) # Operations on ideals From fbb77c49de41e3d94404ea6861f0d2bab932175d Mon Sep 17 00:00:00 2001 From: Enrique Artal Date: Fri, 29 Sep 2023 15:47:12 +0200 Subject: [PATCH 20/45] sum of ideals --- src/sage/groups/finitely_presented.py | 4 ++-- src/sage/rings/polynomial/laurent_polynomial_ideal.py | 9 +++++---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/sage/groups/finitely_presented.py b/src/sage/groups/finitely_presented.py index 2552cc0940c..5b16bd3a7aa 100644 --- a/src/sage/groups/finitely_presented.py +++ b/src/sage/groups/finitely_presented.py @@ -1817,8 +1817,8 @@ def characteristic_varieties(self, ring=QQ, matrix_ideal=None, groebner=False): id_rels = R.ideal(rels) res = dict() for j in range(n + 2): - # J = id_rels + A.fitting_ideal(j) - J = R.ideal(id_rels.gens() + A.fitting_ideal(j).gens()) + J = id_rels + A.fitting_ideal(j) + # J = R.ideal(id_rels.gens() + A.fitting_ideal(j).gens()) if j <= n1: J1 = K.ideal([K(p.subs(eval_1)) for p in J.gens()]) if J1: diff --git a/src/sage/rings/polynomial/laurent_polynomial_ideal.py b/src/sage/rings/polynomial/laurent_polynomial_ideal.py index 5c938466e1c..d8af3c8685d 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_ideal.py +++ b/src/sage/rings/polynomial/laurent_polynomial_ideal.py @@ -95,10 +95,11 @@ def __init__(self, ring, gens, coerce=True, hint=None): self._poly_ring = ring.polynomial_ring() self._poly_ideal = None # Create only as needed self._saturated = False - if hint is None: - self._hint = self._poly_ring.zero_ideal() - else: - self._hint = hint.change_ring(self._poly_ring) + self._hint = self._poly_ring.ideal([f._fraction_pair()[0] for f in self.gens()]) + # if hint is None: + # self._hint = self._poly_ring.zero_ideal() + # else: + # self._hint = hint.change_ring(self._poly_ring) def set_hint(self, hint): """ From 56734816a8ba6e0784b23bca3b59ab5735ce9ef7 Mon Sep 17 00:00:00 2001 From: Enrique Artal Date: Sat, 30 Sep 2023 10:22:53 +0200 Subject: [PATCH 21/45] change hint definition --- src/sage/rings/polynomial/laurent_polynomial_ideal.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/rings/polynomial/laurent_polynomial_ideal.py b/src/sage/rings/polynomial/laurent_polynomial_ideal.py index d8af3c8685d..bea4b8bb76a 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_ideal.py +++ b/src/sage/rings/polynomial/laurent_polynomial_ideal.py @@ -95,7 +95,7 @@ def __init__(self, ring, gens, coerce=True, hint=None): self._poly_ring = ring.polynomial_ring() self._poly_ideal = None # Create only as needed self._saturated = False - self._hint = self._poly_ring.ideal([f._fraction_pair()[0] for f in self.gens()]) + self._hint = self._poly_ring.ideal([f.monomial_reduction()[0] for f in self.gens()]) # if hint is None: # self._hint = self._poly_ring.zero_ideal() # else: @@ -115,7 +115,7 @@ def set_hint(self, hint): sage: P. = LaurentPolynomialRing(QQ, 3) sage: I = P.ideal([x^2*y + 3*x*y^2]) sage: I.hint() - Ideal (0) of Multivariate Polynomial Ring in x, y, z over Rational Field + Ideal (x + 3*y) of Multivariate Polynomial Ring in x, y, z over Rational Field sage: I.set_hint(P.polynomial_ring().ideal([x + 3*y])) sage: I.hint() Ideal (x + 3*y) of Multivariate Polynomial Ring in x, y, z over Rational Field @@ -136,7 +136,7 @@ def hint(self): sage: P. = LaurentPolynomialRing(QQ, 3) sage: I = P.ideal([x^2*y + 3*x*y^2]) sage: I.hint() - Ideal (0) of Multivariate Polynomial Ring in x, y, z over Rational Field + Ideal (x + 3*y) of Multivariate Polynomial Ring in x, y, z over Rational Field """ return self._hint From 9e9185cac2e9790e683d62f61d1d5506ef42b926 Mon Sep 17 00:00:00 2001 From: Enrique Artal Date: Sun, 1 Oct 2023 10:40:41 +0200 Subject: [PATCH 22/45] undo format changes for finitely_presented.py --- src/sage/groups/finitely_presented.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/groups/finitely_presented.py b/src/sage/groups/finitely_presented.py index 5b16bd3a7aa..a961df9a4c5 100644 --- a/src/sage/groups/finitely_presented.py +++ b/src/sage/groups/finitely_presented.py @@ -1550,12 +1550,12 @@ def sorted_presentation(self): C = [rel] for j in range(len(rel) - 1): C.append(rel[j + 1:] + rel[:j + 1]) - C1 = [tuple(-j for j in reversed(l1)) for l1 in C] + C1 = [tuple(-j for j in reversed(l)) for l in C] C += C1 C.sort() L1.append(C[0]) L1.sort() - return F / L1 + return F/L1 def epimorphisms(self, H): r""" From b498b59c637d094bff24eb0036d1cfaf7985f91b Mon Sep 17 00:00:00 2001 From: Enrique Artal Date: Sun, 1 Oct 2023 10:49:39 +0200 Subject: [PATCH 23/45] undo format changes for matrix2.pyx --- src/sage/matrix/matrix2.pyx | 731 ++++++++++++++++++------------------ 1 file changed, 357 insertions(+), 374 deletions(-) diff --git a/src/sage/matrix/matrix2.pyx b/src/sage/matrix/matrix2.pyx index a872e2264a2..86aca6e00d8 100644 --- a/src/sage/matrix/matrix2.pyx +++ b/src/sage/matrix/matrix2.pyx @@ -209,10 +209,10 @@ cdef class Matrix(Matrix1): from sage.matrix.constructor import matrix if self.is_sparse(): return matrix({ij: self[ij].subs(*args, **kwds) for ij in self.nonzero_positions()}, - nrows=self._nrows, ncols=self._ncols, sparse=True) + nrows=self._nrows, ncols=self._ncols, sparse=True) else: return matrix([a.subs(*args, **kwds) for a in self.list()], - nrows=self._nrows, ncols=self._ncols, sparse=False) + nrows=self._nrows, ncols=self._ncols, sparse=False) def solve_left(self, B, check=True): """ @@ -890,8 +890,8 @@ cdef class Matrix(Matrix1): # Elements of SR "remember" whether or not they are exact. # If every element in the system is exact, we can probably # still check the solution over the inexact ring SR. - check = (check and all(e.is_exact() - for e in self.list() + B.list())) + check = (check and all( e.is_exact() + for e in self.list() + B.list() )) else: check = (check and K.is_exact()) @@ -975,7 +975,7 @@ cdef class Matrix(Matrix1): raise NotFullRankError D = self.augment(B) D.echelonize() - return D.matrix_from_columns(range(self.ncols(), D.ncols())) + return D.matrix_from_columns(range(self.ncols(),D.ncols())) def pivot_rows(self): """ @@ -1075,8 +1075,8 @@ cdef class Matrix(Matrix1): for row from 0 <= row < self._nrows: tmp = [] for c in cols: - # if c<0 or c >= self._ncols: - # raise IndexError("matrix column index out of range") +# if c<0 or c >= self._ncols: +# raise IndexError("matrix column index out of range") tmp.append(self.get_unsafe(row, c)) pr = pr * sum(tmp) return pr @@ -1173,10 +1173,7 @@ cdef class Matrix(Matrix1): sage: A.elementwise_product(vector(ZZ, [1,2,3,4])) Traceback (most recent call last): ... - TypeError: no common canonical parent for objects with parents: - 'Full MatrixSpace of 5 by 10 dense matrices over Integer Ring' - and 'Ambient free module of rank 4 over the principal ideal - domain Integer Ring' + TypeError: no common canonical parent for objects with parents: 'Full MatrixSpace of 5 by 10 dense matrices over Integer Ring' and 'Ambient free module of rank 4 over the principal ideal domain Integer Ring' sage: A = matrix(2, 2, range(4)) sage: A.elementwise_product(polygen(parent(A))) @@ -1191,11 +1188,7 @@ cdef class Matrix(Matrix1): sage: A.elementwise_product(B) Traceback (most recent call last): ... - TypeError: no common canonical parent - for objects with parents: 'Full MatrixSpace of - 5 by 10 dense matrices over Integer Ring' and - 'Full MatrixSpace of 10 by 5 dense matrices over - Integer Ring' + TypeError: no common canonical parent for objects with parents: 'Full MatrixSpace of 5 by 10 dense matrices over Integer Ring' and 'Full MatrixSpace of 10 by 5 dense matrices over Integer Ring' Some pairs of rings do not have a common parent where multiplication makes sense. This will raise an error. :: @@ -1393,7 +1386,7 @@ cdef class Matrix(Matrix1): m = self._nrows n = self._ncols if not m <= n: - raise ValueError("must have m <= n, but m (=%s) and n (=%s)" % (m, n)) + raise ValueError("must have m <= n, but m (=%s) and n (=%s)"%(m,n)) for r from 1 <= r < m+1: lst = _choose(n, r) @@ -1514,8 +1507,8 @@ cdef class Matrix(Matrix1): return R.zero() pm = 0 - for cols in _choose(n, k): - for rows in _choose(m, k): + for cols in _choose(n,k): + for rows in _choose(m,k): pm = pm + self.matrix_from_rows_and_columns(rows, cols).permanent() return pm @@ -1824,14 +1817,14 @@ cdef class Matrix(Matrix1): ....: if v != [1, 16, 78, 128, 53]: ....: print("ERROR with algorithm={} use_complement=False".format(algorithm)) """ - cdef Py_ssize_t i, j + cdef Py_ssize_t i,j cdef unsigned int num_ones cdef int m = self._nrows cdef int n = self._ncols cdef int mn = min(m, n) cdef Matrix B zero = self.base_ring().zero() - one = self.base_ring().one() + one = self.base_ring().one() if algorithm is None: algorithm = "ButeraPernici" @@ -1845,7 +1838,7 @@ cdef class Matrix(Matrix1): num_ones = 1 for i in range(m): for j in range(n): - x = self.get_unsafe(i, j) + x = self.get_unsafe(i,j) if x != zero: if x != one: z2 = False @@ -1857,7 +1850,7 @@ cdef class Matrix(Matrix1): break if not z2 and (complement or algorithm == "Godsil"): - raise ValueError("coefficients must be zero or one, but we have '{}' in position ({},{}).".format(x, i, j)) + raise ValueError("coefficients must be zero or one, but we have '{}' in position ({},{}).".format(x,i,j)) if use_complement is None: use_complement = z2 and num_ones > 0.55 * m * n @@ -1871,7 +1864,7 @@ cdef class Matrix(Matrix1): complement = not complement elif algorithm == "Ryser": - b = [self.permanental_minor(k, algorithm="Ryser") + b = [self.permanental_minor(k,algorithm="Ryser") for k in range(mn + 1)] elif algorithm == "ButeraPernici": @@ -1960,9 +1953,9 @@ cdef class Matrix(Matrix1): all_rows = range(self.nrows()) all_cols = range(self.ncols()) m = [] - for rows in Combinations(all_rows, k): - for cols in Combinations(all_cols, k): - m.append(self.matrix_from_rows_and_columns(rows, cols).determinant()) + for rows in Combinations(all_rows,k): + for cols in Combinations(all_cols,k): + m.append(self.matrix_from_rows_and_columns(rows,cols).determinant()) return m def det(self, *args, **kwds): @@ -2120,13 +2113,13 @@ cdef class Matrix(Matrix1): if n == 0: d = R.one() elif n == 1: - d = self.get_unsafe(0, 0) + d = self.get_unsafe(0,0) elif n == 2: - d = self.get_unsafe(0, 0)*self.get_unsafe(1, 1) - self.get_unsafe(1, 0)*self.get_unsafe(0, 1) + d = self.get_unsafe(0,0)*self.get_unsafe(1,1) - self.get_unsafe(1,0)*self.get_unsafe(0,1) elif n == 3: - d = self.get_unsafe(0, 0) * (self.get_unsafe(1, 1)*self.get_unsafe(2, 2) - self.get_unsafe(1, 2)*self.get_unsafe(2, 1)) \ - - self.get_unsafe(1, 0) * (self.get_unsafe(0, 1)*self.get_unsafe(2, 2) - self.get_unsafe(0, 2)*self.get_unsafe(2, 1)) \ - + self.get_unsafe(2, 0) * (self.get_unsafe(0, 1)*self.get_unsafe(1, 2) - self.get_unsafe(0, 2)*self.get_unsafe(1, 1)) + d = self.get_unsafe(0,0) * (self.get_unsafe(1,1)*self.get_unsafe(2,2) - self.get_unsafe(1,2)*self.get_unsafe(2,1)) \ + - self.get_unsafe(1,0) * (self.get_unsafe(0,1)*self.get_unsafe(2,2) - self.get_unsafe(0,2)*self.get_unsafe(2,1)) \ + + self.get_unsafe(2,0) * (self.get_unsafe(0,1)*self.get_unsafe(1,2) - self.get_unsafe(0,2)*self.get_unsafe(1,1)) self.cache('det', d) return d @@ -2140,7 +2133,7 @@ cdef class Matrix(Matrix1): d = R(self.__pari__().matdet()) else: # Lift to ZZ and compute there. - d = R(self.apply_map(lambda x: x.lift_centered()).det()) + d = R(self.apply_map(lambda x : x.lift_centered()).det()) self.cache('det', d) return d @@ -2196,18 +2189,18 @@ cdef class Matrix(Matrix1): """ cdef Py_ssize_t i if level == 2: - return self.get_unsafe(0, 0) * self.get_unsafe(1, 1) - self.get_unsafe(0, 1) * self.get_unsafe(1, 0) + return self.get_unsafe(0,0) * self.get_unsafe(1,1) - self.get_unsafe(0,1) * self.get_unsafe(1,0) else: level -= 1 - d = self.get_unsafe(level, level) * self._det_by_minors(level) + d = self.get_unsafe(level,level) * self._det_by_minors(level) # on each iteration, row i will be missing in the first (level) rows # swapping is much faster than taking submatrices for i from level > i >= 0: self.swap_rows(level, i) if (level - i) % 2: - d -= self.get_unsafe(level, level) * self._det_by_minors(level) + d -= self.get_unsafe(level,level) * self._det_by_minors(level) else: - d += self.get_unsafe(level, level) * self._det_by_minors(level) + d += self.get_unsafe(level,level) * self._det_by_minors(level) # undo all our permutations to get us back to where we started for i from 0 <= i < level: self.swap_rows(level, i) @@ -2658,7 +2651,7 @@ cdef class Matrix(Matrix1): """ M = self.parent().change_ring(phi.codomain()) if self.is_sparse(): - values = {(i, j): phi(z) for (i, j), z in self.dict()} + values = {(i,j): phi(z) for (i,j),z in self.dict()} else: values = [phi(z) for z in self.list()] image = M(values) @@ -2767,7 +2760,7 @@ cdef class Matrix(Matrix1): return self.dense_matrix() if self.is_sparse(): - values = {(i, j): phi(v) for (i, j), v in self.dict().iteritems()} + values = {(i,j): phi(v) for (i,j),v in self.dict().iteritems()} if R is None: R = sage.structure.sequence.Sequence(values.values()).universe() else: @@ -2785,7 +2778,7 @@ cdef class Matrix(Matrix1): else: from sage.matrix.matrix_space import MatrixSpace M = MatrixSpace(R, self._nrows, - self._ncols, sparse=sparse) + self._ncols, sparse=sparse) image = M(values) if self._subdivisions is not None: image.subdivide(*self.subdivisions()) @@ -2896,7 +2889,7 @@ cdef class Matrix(Matrix1): # At least check that the minimal polynomial kills the matrix tester.assertTrue(self.minpoly().subs(x=self).is_zero()) - def charpoly(self, var='x', algorithm=None): + def charpoly(self, var = 'x', algorithm = None): r""" Returns the characteristic polynomial of self, as a polynomial over the base ring. @@ -3091,7 +3084,7 @@ cdef class Matrix(Matrix1): self.cache('charpoly', f) return f - def _charpoly_df(self, var='x'): + def _charpoly_df(self, var = 'x'): r""" Computes the characteristic polynomial of ``self`` without divisions. @@ -3179,10 +3172,10 @@ cdef class Matrix(Matrix1): # Extract parameters # - cdef Matrix M = self - n = M._ncols - R = M._base_ring - S = PolynomialRing(R, var) + cdef Matrix M = self + n = M._ncols + R = M._base_ring + S = PolynomialRing(R, var) # Corner cases # N.B. We already tested for M to be square, hence we do not need to @@ -3207,11 +3200,11 @@ cdef class Matrix(Matrix1): from sage.matrix.constructor import matrix F = [R.zero()] * n - cdef Matrix a = matrix(R, n - 1, n) + cdef Matrix a = matrix(R, n-1, n) A = [R.zero()] * n F[0] = - M.get_unsafe(0, 0) - for t in range(1, n): + for t in range(1,n): # Set a(1, t) to be M(<=t, t) # @@ -3381,7 +3374,7 @@ cdef class Matrix(Matrix1): [] """ n = min(self.nrows(), self.ncols()) - return [self[i, i] for i in range(n)] + return [self[i,i] for i in range(n)] def trace(self): """ @@ -3418,7 +3411,7 @@ cdef class Matrix(Matrix1): cdef object s s = R(0) for i from 0 <= i < self._nrows: - s = s + self.get_unsafe(i, i) + s = s + self.get_unsafe(i,i) return s def trace_of_product(self, Matrix other): @@ -3476,11 +3469,11 @@ cdef class Matrix(Matrix1): H = self.change_ring(K) H.hessenbergize() except TypeError as msg: - raise TypeError("%s\nHessenberg form only possible for matrices over a field" % msg) + raise TypeError("%s\nHessenberg form only possible for matrices over a field"%msg) else: H = self.__copy__() H.hessenbergize() - # end if + #end if self.cache('hessenberg_form', H) return H @@ -3524,7 +3517,7 @@ cdef class Matrix(Matrix1): cdef Py_ssize_t i, j, m, n, r n = self._nrows - tm = verbose("Computing Hessenberg Normal Form of %sx%s matrix" % (n, n)) + tm = verbose("Computing Hessenberg Normal Form of %sx%s matrix"%(n,n)) if not self.is_square(): raise TypeError("self must be square") @@ -3551,20 +3544,20 @@ cdef class Matrix(Matrix1): if i != -1: # Found a nonzero entry in column m-1 that is strictly below row m # Now set i to be the first nonzero position >= m in column m-1 - if not self.get_is_zero_unsafe(m, m - 1): + if not self.get_is_zero_unsafe(m,m-1): i = m - t = self.get_unsafe(i, m - 1) + t = self.get_unsafe(i,m-1) t_inv = None if i > m: - self.swap_rows_c(i, m) + self.swap_rows_c(i,m) # We must do the corresponding column swap to # maintain the characteristic polynomial (which is # an invariant of Hessenberg form) - self.swap_columns_c(i, m) + self.swap_columns_c(i,m) # Now the nonzero entry in position (m,m-1) is t. # Use t to clear the entries in column m-1 below m. for j from m+1 <= j < n: - x = self.get_unsafe(j, m - 1) + x = self.get_unsafe(j, m-1) if x != zero: if t_inv is None: t_inv = one / t @@ -3575,7 +3568,7 @@ cdef class Matrix(Matrix1): # column m, and we're only worried about column m-1 right now. # Add u*column_j to column_m. self.add_multiple_of_column_c(m, j, u, 0) - verbose("Finished Hessenberg Normal Form of %sx%s matrix" % (n, n), tm) + verbose("Finished Hessenberg Normal Form of %sx%s matrix"%(n,n),tm) def _charpoly_hessenberg(self, var): """ @@ -3626,9 +3619,9 @@ cdef class Matrix(Matrix1): n = self._nrows cdef Matrix c - c = H.new_matrix(nrows=n + 1, ncols=n + 1) # the 0 matrix + c = H.new_matrix(nrows=n+1,ncols=n+1) # the 0 matrix one = H._coerce_element(1) - c.set_unsafe(0, 0, one) + c.set_unsafe(0,0,one) for m from 1 <= m <= n: # Set the m-th row of c to (x - H[m-1,m-1])*c[m-1] = x*c[m-1] - H[m-1,m-1]*c[m-1] @@ -3636,21 +3629,20 @@ cdef class Matrix(Matrix1): # shifted to the right by one. We then add # -H[m-1,m-1]*c[m-1] to the resulting m-th row. for i from 1 <= i <= n: - c.set_unsafe(m, i, c.get_unsafe(m - 1, i - 1)) - c.add_multiple_of_row_c(m, m-1, -H.get_unsafe(m - 1, m - 1), 0) + c.set_unsafe(m, i, c.get_unsafe(m-1,i-1)) + c.add_multiple_of_row_c(m, m-1, -H.get_unsafe(m-1, m-1), 0) t = one for i from 1 <= i < m: - t = t * H.get_unsafe(m - i, m - i - 1) + t = t * H.get_unsafe(m-i,m-i-1) # Set the m-th row of c to c[m] - t*H[m-i-1,m-1]*c[m-i-1] - c.add_multiple_of_row_c(m, m - i - 1, -t * H.get_unsafe(m - i - 1, m - 1), 0) + c.add_multiple_of_row_c(m, m-i-1, - t*H.get_unsafe(m-i-1,m-1), 0) # The answer is now the n-th row of c. v = PyList_New(n+1) # this is really sort of v = []..." for i from 0 <= i <= n: # Finally, set v[i] = c[n,i] - o = c.get_unsafe(n, i) - Py_INCREF(o) - PyList_SET_ITEM(v, i, o) + o = c.get_unsafe(n,i) + Py_INCREF(o); PyList_SET_ITEM(v, i, o) R = self._base_ring[var] # polynomial ring over the base ring return R(v) @@ -3768,12 +3760,12 @@ cdef class Matrix(Matrix1): [0 0 1] """ from sage.matrix.matrix_space import MatrixSpace - tm = verbose("computing right kernel matrix over a number field for %sx%s matrix" % (self.nrows(), self.ncols()), level=1) + tm = verbose("computing right kernel matrix over a number field for %sx%s matrix" % (self.nrows(), self.ncols()),level=1) basis = self.__pari__().matker() # Coerce PARI representations into the number field R = self.base_ring() basis = [[R(x) for x in row] for row in basis] - verbose("done computing right kernel matrix over a number field for %sx%s matrix" % (self.nrows(), self.ncols()), level=1, t=tm) + verbose("done computing right kernel matrix over a number field for %sx%s matrix" % (self.nrows(), self.ncols()),level=1,t=tm) return 'pivot-pari-numberfield', MatrixSpace(R, len(basis), ncols=self._ncols)(basis) def _right_kernel_matrix_over_field(self, *args, **kwds): @@ -3827,7 +3819,7 @@ cdef class Matrix(Matrix1): [0 0 1] """ from sage.matrix.matrix_space import MatrixSpace - tm = verbose("computing right kernel matrix over an arbitrary field for %sx%s matrix" % (self.nrows(), self.ncols()), level=1) + tm = verbose("computing right kernel matrix over an arbitrary field for %sx%s matrix" % (self.nrows(), self.ncols()),level=1) E = self.echelon_form(*args, **kwds) pivots = E.pivots() pivots_set = set(pivots) @@ -3856,7 +3848,7 @@ cdef class Matrix(Matrix1): basis.append(v) M = MS(basis, coerce=False) tm = verbose("done computing right kernel matrix over an arbitrary field for %sx%s matrix" - % (self.nrows(), self.ncols()), level=1, t=tm) + % (self.nrows(), self.ncols()),level=1,t=tm) return 'pivot-generic', M def _right_kernel_matrix_over_domain(self): @@ -3920,7 +3912,7 @@ cdef class Matrix(Matrix1): cdef Py_ssize_t i, nrows = self._nrows for i in range(self._ncols): if i >= nrows or d[i, i] == 0: - basis.append(v.column(i)) + basis.append( v.column(i) ) verbose("done computing right kernel matrix over a domain for %sx%s matrix" % (self.nrows(), self.ncols()), level=1, t=tm) return 'computed-smith-form', self.new_matrix(nrows=len(basis), ncols=self._ncols, entries=basis) @@ -4511,7 +4503,7 @@ cdef class Matrix(Matrix1): if algorithm is None: algorithm = 'default' elif algorithm not in ['default', 'generic', 'flint', 'pari', 'padic', 'pluq']: - raise ValueError("matrix kernel algorithm '%s' not recognized" % algorithm) + raise ValueError("matrix kernel algorithm '%s' not recognized" % algorithm ) elif algorithm == 'padic' and not (is_IntegerRing(R) or is_RationalField(R)): raise ValueError("'padic' matrix kernel algorithm only available over the rationals and the integers, not over %s" % R) elif algorithm == 'flint' and not (is_IntegerRing(R) or is_RationalField(R)): @@ -4528,7 +4520,7 @@ cdef class Matrix(Matrix1): if basis is None: basis = 'default' elif basis not in ['default', 'computed', 'echelon', 'pivot', 'LLL']: - raise ValueError("matrix kernel basis format '%s' not recognized" % basis) + raise ValueError("matrix kernel basis format '%s' not recognized" % basis ) elif basis == 'pivot' and R not in _Fields: raise ValueError('pivot basis only available over a field, not over %s' % R) elif basis == 'LLL' and not is_IntegerRing(R): @@ -4562,8 +4554,7 @@ cdef class Matrix(Matrix1): # Third: generic first, if requested explicitly # then try specialized class methods, and finally # delegate to ad-hoc methods in greater generality - M = None - format = '' + M = None; format = '' if algorithm == 'generic': format, M = self._right_kernel_matrix_over_field() @@ -4593,7 +4584,7 @@ cdef class Matrix(Matrix1): # zero columns as well. (eg PARI?) This could be fixed at the source # with a careful study of the phenomenon. Start by commenting out # the following and running doctests in sage/matrix - if M.nrows() == 0 and M.ncols() != self.ncols(): + if M.nrows()==0 and M.ncols()!=self.ncols(): M = M.new_matrix(nrows=0, ncols=self.ncols()) # Convert basis to requested type and return the matrix @@ -5156,10 +5147,10 @@ cdef class Matrix(Matrix1): if K is not None: return K - tm = verbose("computing left kernel for %sx%s matrix" % (self.nrows(), self.ncols()), level=1) + tm = verbose("computing left kernel for %sx%s matrix" % (self.nrows(), self.ncols()),level=1) K = self.transpose().right_kernel(*args, **kwds) self.cache('left_kernel', K) - verbose("done computing left kernel for %sx%s matrix" % (self.nrows(), self.ncols()), level=1, t=tm) + verbose("done computing left kernel for %sx%s matrix" % (self.nrows(), self.ncols()),level=1,t=tm) return K kernel = left_kernel @@ -5531,15 +5522,15 @@ cdef class Matrix(Matrix1): False) ] """ if algorithm == 'kernel' or self.base_ring() not in _Fields: - return self._decomposition_using_kernels(is_diagonalizable=is_diagonalizable, dual=dual) + return self._decomposition_using_kernels(is_diagonalizable = is_diagonalizable, dual=dual) elif algorithm == 'spin': - X = self._decomposition_spin_generic(is_diagonalizable=is_diagonalizable) + X = self._decomposition_spin_generic(is_diagonalizable = is_diagonalizable) if dual: - Y = self.transpose()._decomposition_spin_generic(is_diagonalizable=is_diagonalizable) + Y = self.transpose()._decomposition_spin_generic(is_diagonalizable = is_diagonalizable) return X, Y return X else: - raise ValueError("no algorithm '%s'" % algorithm) + raise ValueError("no algorithm '%s'"%algorithm) def _decomposition_spin_generic(self, is_diagonalizable=False): r""" @@ -5569,13 +5560,13 @@ cdef class Matrix(Matrix1): if len(F) == 1: V = self.base_ring()**self.nrows() - return decomp_seq([(V, F[0][1] == 1)]) + return decomp_seq([(V,F[0][1]==1)]) V = self.base_ring()**self.nrows() v = V.random_element() num_iterates = max([0] + [f.degree() - g.degree() for g, _ in F if g.degree() > 1]) + 1 - S = [] + S = [ ] F.sort() for i in range(len(F)): @@ -5585,11 +5576,11 @@ cdef class Matrix(Matrix1): # Just use kernel -- much easier. B = self.__copy__() for k from 0 <= k < self.nrows(): - B[k, k] += g[0] + B[k,k] += g[0] if m > 1 and not is_diagonalizable: B = B**m W = B.kernel() - E.append((W, m == 1)) + E.append((W, m==1)) continue # General case, i.e., deg(g) > 1: @@ -5602,40 +5593,40 @@ cdef class Matrix(Matrix1): v = h.list() while len(S) < tries: - t = verbose('%s-spinning %s-th random vector' % (num_iterates, len(S)), level=2, caller_name='generic spin decomp') + t = verbose('%s-spinning %s-th random vector'%(num_iterates, len(S)), level=2, caller_name='generic spin decomp') S.append(self.iterates(V.random_element(), num_iterates)) verbose('done spinning', level=2, t=t, caller_name='generic spin decomp') for j in range(0 if W is None else W.nrows() // g.degree(), len(S)): # Compute one element of the kernel of g(A)**m. - t = verbose('compute element of kernel of g(A), for g of degree %s' % g.degree(), level=2, + t = verbose('compute element of kernel of g(A), for g of degree %s'%g.degree(),level=2, caller_name='generic spin decomp') w = S[j].linear_combination_of_rows(h.list()) - t = verbose('done computing element of kernel of g(A)', t=t, level=2, caller_name='generic spin decomp') + t = verbose('done computing element of kernel of g(A)', t=t,level=2, caller_name='generic spin decomp') # Get the rest of the kernel. - t = verbose('fill out rest of kernel', level=2, caller_name='generic spin decomp') + t = verbose('fill out rest of kernel',level=2, caller_name='generic spin decomp') if W is None: W = self.iterates(w, g.degree()) else: W = W.stack(self.iterates(w, g.degree())) - t = verbose('finished filling out more of kernel', level=2, t=t, caller_name='generic spin decomp') + t = verbose('finished filling out more of kernel',level=2, t=t, caller_name='generic spin decomp') if W.rank() == m * g.degree(): t = verbose('now computing row space', level=2, caller_name='generic spin decomp') W.echelonize() - E.append((W.row_space(), m == 1)) - verbose('computed row space', level=2, t=t, caller_name='generic spin decomp') + E.append((W.row_space(), m==1)) + verbose('computed row space', level=2,t=t, caller_name='generic spin decomp') break else: - verbose('we have not yet generated all the kernel (rank so far=%s, target rank=%s)' % ( + verbose('we have not yet generated all the kernel (rank so far=%s, target rank=%s)'%( W.rank(), m*g.degree()), level=2, caller_name='generic spin decomp') tries += 1 if tries > 1000*m: # avoid an insanely long infinite loop raise RuntimeError("likely bug in decomposition") # end if - # end while - # end for + #end while + #end for return E def _decomposition_using_kernels(self, is_diagonalizable=False, dual=False): @@ -5659,30 +5650,30 @@ cdef class Matrix(Matrix1): V = self.column_ambient_module() m = F[0][1] if dual: - return decomp_seq([(V, m == 1)]), decomp_seq([(V, m == 1)]) + return decomp_seq([(V, m==1)]), decomp_seq([(V, m==1)]) else: - return decomp_seq([(V, m == 1)]) + return decomp_seq([(V, m==1)]) F.sort() for g, m in f.factor(): - t = verbose('decomposition -- Computing g(self) for an irreducible factor g of degree %s' % g.degree(), level=2) + t = verbose('decomposition -- Computing g(self) for an irreducible factor g of degree %s'%g.degree(),level=2) if is_diagonalizable: B = g(self) else: B = g(self) - t2 = verbose('decomposition -- raising g(self) to the power %s' % m, level=2) + t2 = verbose('decomposition -- raising g(self) to the power %s'%m,level=2) B = B ** m - verbose('done powering', t2) + verbose('done powering',t2) t = verbose('decomposition -- done computing g(self)', level=2, t=t) - E.append((B.kernel(), m == 1)) + E.append((B.kernel(), m==1)) t = verbose('decomposition -- time to compute kernel', level=2, t=t) if dual: - Edual.append((B.transpose().kernel(), m == 1)) + Edual.append((B.transpose().kernel(), m==1)) verbose('decomposition -- time to compute dual kernel', level=2, t=t) if dual: return E, Edual return E - def decomposition_of_subspace(self, M, check_restrict=True, **kwds): + def decomposition_of_subspace(self, M, check_restrict = True, **kwds): """ Suppose the right action of self on M leaves M invariant. Return the decomposition of M as a list of pairs (W, is_irred) where @@ -5758,7 +5749,7 @@ cdef class Matrix(Matrix1): if not self.is_square(): raise ArithmeticError("self must be a square matrix") if M.base_ring() != self.base_ring(): - raise ArithmeticError("base rings must be the same, but self is over %s and module is over %s" % ( + raise ArithmeticError("base rings must be the same, but self is over %s and module is over %s"%( self.base_ring(), M.base_ring())) if M.degree() != self.ncols(): raise ArithmeticError("M must be a subspace of an %s-dimensional space" % self.ncols()) @@ -5766,18 +5757,16 @@ cdef class Matrix(Matrix1): time = verbose(t=0) # 1. Restrict - B = self.restrict(M, check=check_restrict) + B = self.restrict(M, check = check_restrict) time0 = verbose("decompose restriction -- ", time) # 2. Decompose restriction D = B.decomposition(**kwds) - sum_dim = sum([A.dimension() for A, _ in D]) + sum_dim = sum([A.dimension() for A,_ in D]) assert sum_dim == M.dimension(), \ "bug in decomposition; " + \ - "the sum of the dimensions (=%s) of the factors must equal" + \ - "the dimension (%s) of the acted on space:\nFactors found:" + \ - "%s\nSpace: %s" % (sum_dim, M.dimension(), D, M) + "the sum of the dimensions (=%s) of the factors must equal the dimension (%s) of the acted on space:\nFactors found: %s\nSpace: %s"%(sum_dim, M.dimension(), D, M) # 3. Lift decomposition to subspaces of ambient vector space. # Each basis vector for an element of D defines a linear @@ -5847,7 +5836,7 @@ cdef class Matrix(Matrix1): """ if not isinstance(V, sage.modules.free_module.FreeModule_generic): raise TypeError("V must be a free module") - # if V.base_ring() != self.base_ring(): + #if V.base_ring() != self.base_ring(): # raise ValueError("matrix and module must have the same base ring, but matrix is over %s and module is over %s"%(self.base_ring(), V.base_ring())) if V.degree() != self.nrows(): raise IndexError("degree of V (=%s) must equal number of rows of self (=%s)" % (V.degree(), self.nrows())) @@ -6029,8 +6018,7 @@ cdef class Matrix(Matrix1): sage: t.charpoly() # needs sage.libs.pari x^3 - 12*x^2 - 18*x """ - i = int(i) - t = int(t) + i = int(i); t=int(t) if self.nrows() != self.ncols(): raise ArithmeticError("self must be a square matrix") n = self.nrows() @@ -6435,7 +6423,7 @@ cdef class Matrix(Matrix1): if algebraic_multiplicity: return x else: - return Sequence([(e[0], e[1]) for e in x], cr=True, check=False) + return Sequence([(e[0],e[1]) for e in x], cr=True, check=False) # Possible improvements: # algorithm for dual_eigenvector in sage/modular/hecke/module.py @@ -6447,7 +6435,7 @@ cdef class Matrix(Matrix1): G = self.fcp() # factored characteristic polynomial V = [] - i = -1 # variable name index, increments for each eigenvalue + i = -1 # variable name index, increments for each eigenvalue for h, e in G: i = i + 1 if h.degree() == 1: @@ -6459,7 +6447,7 @@ cdef class Matrix(Matrix1): W = A.kernel() V.append((alpha, W.ambient_module().span_of_basis(W.basis()), e)) else: - F = h.root_field('{0}{1}'.format(var, i)) + F = h.root_field('{0}{1}'.format(var,i)) alpha = F.gen(0) A = self.change_ring(F) - alpha W = A.kernel() @@ -6483,7 +6471,7 @@ cdef class Matrix(Matrix1): if algebraic_multiplicity: return V else: - return Sequence([(e[0], e[1]) for e in V], cr=True, check=False) + return Sequence([(e[0],e[1]) for e in V], cr=True, check=False) left_eigenspaces = eigenspaces_left @@ -6687,7 +6675,7 @@ cdef class Matrix(Matrix1): if algebraic_multiplicity: return x else: - return Sequence([(e[0], e[1]) for e in x], cr=True, check=False) + return Sequence([(e[0],e[1]) for e in x], cr=True, check=False) V = self.transpose().eigenspaces_left(format=format, var=var, algebraic_multiplicity=True) @@ -6695,7 +6683,7 @@ cdef class Matrix(Matrix1): if algebraic_multiplicity: return V else: - return Sequence([(e[0], e[1]) for e in V], cr=True, check=False) + return Sequence([(e[0],e[1]) for e in V], cr=True, check=False) right_eigenspaces = eigenspaces_right @@ -6808,7 +6796,7 @@ cdef class Matrix(Matrix1): warn("Using generic algorithm for an inexact ring, which will probably give incorrect results due to numerical precision issues.") if not extend: - return Sequence(r for r, m in self.charpoly().roots() for _ in range(m)) + return Sequence(r for r,m in self.charpoly().roots() for _ in range(m)) # now we need to find a natural algebraic closure for the base ring K = self.base_ring() @@ -6828,7 +6816,7 @@ cdef class Matrix(Matrix1): if f.degree() == 1: res.extend([-f.constant_coefficient()]*e) else: - for r, ee in f.change_ring(A).roots(): + for r,ee in f.change_ring(A).roots(): res.extend([r]*(e*ee)) eigenvalues = Sequence(res) @@ -6938,7 +6926,7 @@ cdef class Matrix(Matrix1): from sage.categories.homset import hom eigenspaces = self.eigenspaces_left(format='galois', algebraic_multiplicity=True) - evec_list = [] + evec_list=[] n = self._nrows evec_eval_list = [] F = self.base_ring().fraction_field() @@ -6960,7 +6948,7 @@ cdef class Matrix(Matrix1): m = hom(eigval.parent(), e.parent(), e) space = (e.parent())**n evec_list = [(space)([m(i) for i in v]) for v in eigbasis] - evec_eval_list.append((e, evec_list, eigmult)) + evec_eval_list.append( (e, evec_list, eigmult)) return evec_eval_list @@ -7242,7 +7230,7 @@ cdef class Matrix(Matrix1): "failed to compute eigenvectors for eigenvalue %s, " "check eigenvectors_left() for partial results" % e[0]) P = matrix(rows) - return D, P + return D,P left_eigenmatrix = eigenmatrix_left @@ -7410,9 +7398,9 @@ cdef class Matrix(Matrix1): True """ - D, P = self.transpose().eigenmatrix_left(None if other is None - else other.transpose()) - return D, P.transpose() + D,P = self.transpose().eigenmatrix_left(None if other is None + else other.transpose()) + return D,P.transpose() right_eigenmatrix = eigenmatrix_right @@ -7628,7 +7616,7 @@ cdef class Matrix(Matrix1): d = self.dense_matrix().echelon_form(**kwds) for c from 0 <= c < self.ncols(): for r from 0 <= r < self.nrows(): - self.set_unsafe(r, c, d.get_unsafe(r, c)) + self.set_unsafe(r, c, d.get_unsafe(r,c)) self.clear_cache() self.cache('pivots', d.pivots()) self.cache('in_echelon_form', True) @@ -7636,11 +7624,11 @@ cdef class Matrix(Matrix1): try: a, d, p = self._echelon_form_PID() except TypeError as msg: - raise NotImplementedError("%s\nechelon form over %s not yet implemented" % (msg, self.base_ring())) + raise NotImplementedError("%s\nechelon form over %s not yet implemented"%(msg, self.base_ring())) for c from 0 <= c < self.ncols(): for r from 0 <= r < self.nrows(): - self.set_unsafe(r, c, d.get_unsafe(r, c)) + self.set_unsafe(r, c, d.get_unsafe(r,c)) self.clear_cache() self.cache('pivots', tuple(p)) self.cache('in_echelon_form', True) @@ -7840,7 +7828,7 @@ cdef class Matrix(Matrix1): kwds['algorithm'] = algorithm return self._echelonize_ring(**kwds) except ArithmeticError as msg: - raise NotImplementedError("%s\nEchelon form not implemented over '%s'." % (msg, basring)) + raise NotImplementedError("%s\nEchelon form not implemented over '%s'."%(msg,basring)) def echelon_form(self, algorithm="default", cutoff=0, **kwds): r""" @@ -7935,7 +7923,7 @@ cdef class Matrix(Matrix1): if algorithm == 'default': v = E.echelonize(cutoff=cutoff, **kwds) else: - v = E.echelonize(algorithm=algorithm, cutoff=cutoff, **kwds) + v = E.echelonize(algorithm = algorithm, cutoff=cutoff, **kwds) E.set_immutable() # so we can cache the echelon form. self.cache('echelon_form', E) if v is not None: @@ -8137,21 +8125,21 @@ cdef class Matrix(Matrix1): if algorithm == 'partial_pivoting': for r in range(start_row, nr): - abs_val = A.get_unsafe(r, c).abs() + abs_val = A.get_unsafe(r,c).abs() if abs_val > max_abs_val: max_abs_val = abs_val best_r = r elif algorithm == 'scaled_partial_pivoting': for r in range(start_row, nr): if scale_factors[r]: - abs_val = A.get_unsafe(r, c).abs() / scale_factors[r] + abs_val = A.get_unsafe(r,c).abs() / scale_factors[r] if abs_val > max_abs_val: max_abs_val = abs_val best_r = r - else: # algorithm == 'scaled_partial_pivoting_valuation': + else: # algorithm == 'scaled_partial_pivoting_valuation': for r in range(start_row, nr): if scale_factors[r] is not None: - abs_val = scale_factors[r] - A.get_unsafe(r, c).valuation() + abs_val = scale_factors[r] - A.get_unsafe(r,c).valuation() if max_abs_val is None or abs_val > max_abs_val: max_abs_val = abs_val best_r = r @@ -8493,7 +8481,7 @@ cdef class Matrix(Matrix1): permutations.append( (PermutationGroupElement([p(1 + i) for i in range(nrows)]), PermutationGroupElement([p(1 + nrows + i) - nrows for i in range(ncols)]) - )) + )) return permutations def permutation_normal_form(self, check=False): @@ -8600,14 +8588,14 @@ cdef class Matrix(Matrix1): # Sort each row with respect to S for the first matrix in X = MS X = copy(MS) SM = [sorted([(S[j], X[0][k][j]) for j in range(ncols)], reverse=True) - for k in range(l, nrows)] + for k in range(l, nrows)] SM = [[k[1] for k in s] for s in SM] # and pick the maximal row b = max(SM) # Find all rows equal to the maximal (potential new cases) m = [[j for j in range(nrows - l) if SM[j] == b]] - w = 0 # keeps track of how many entries we have removed from MS + w = 0 # keeps track of how many entries we have removed from MS # Let us find the maximal row in each of the entries in X = MS for i in range(1, len(X)): SN = [sorted([(S[j], X[i][k][j]) for j in range(ncols)], reverse=True) @@ -8743,7 +8731,7 @@ cdef class Matrix(Matrix1): truth, perm = N_B.is_isomorphic(M_B, certificate=True, edge_labels=True) from sage.groups.perm_gps.constructor import PermutationGroupElement if perm: - s = sorted(perm.items(), key=lambda x: x[0]) + s = sorted(perm.items(), key=lambda x:x[0]) row_perms = [value for k, value in s if k <= nrows] col_perms = [value - nrows for k, value in s if k > nrows] perm = (PermutationGroupElement(row_perms), PermutationGroupElement(col_perms)) @@ -8794,15 +8782,16 @@ cdef class Matrix(Matrix1): output = self.new_matrix(self._nrows, right._ncols) # The following used to be a little faster, but meanwhile # the previous line is faster. - # if self.is_sparse(): + #if self.is_sparse(): # output = self.matrix_space(self._nrows, right._ncols, sparse = True)(0) - # else: + #else: # output = self.matrix_space(self._nrows, right._ncols, sparse = False).zero_matrix().__copy__() - self_window = self.matrix_window() - right_window = right.matrix_window() + self_window = self.matrix_window() + right_window = right.matrix_window() output_window = output.matrix_window() + from . import strassen strassen.strassen_window_multiply(output_window, self_window, right_window, cutoff) return output @@ -8824,7 +8813,7 @@ cdef class Matrix(Matrix1): [ 0 0 0 0] [ 0 0 0 0] """ - tm = verbose('strassen echelon of %s x %s matrix' % (self._nrows, self._ncols)) + tm = verbose('strassen echelon of %s x %s matrix'%(self._nrows, self._ncols)) self.check_mutability() @@ -8847,8 +8836,8 @@ cdef class Matrix(Matrix1): verbose('done with strassen', tm) cpdef matrix_window(self, Py_ssize_t row=0, Py_ssize_t col=0, - Py_ssize_t nrows=-1, Py_ssize_t ncols=-1, - bint check=1): + Py_ssize_t nrows=-1, Py_ssize_t ncols=-1, + bint check=1): """ Return the requested matrix window. @@ -9102,7 +9091,7 @@ cdef class Matrix(Matrix1): """ if self._subdivisions is None: self._subdivisions = ([0, self._nrows], [0, self._ncols]) - key = "subdivision %s %s" % (i, j) + key = "subdivision %s %s"%(i,j) sd = self.fetch(key) if sd is None: sd = self[self._subdivisions[0][i]:self._subdivisions[0][i+1], @@ -9148,13 +9137,13 @@ cdef class Matrix(Matrix1): """ if self._subdivisions is None: if not i and not j: - return self[x, y] + return self[x,y] else: - raise IndexError("No such submatrix %s, %s" % (i, j)) + raise IndexError("No such submatrix %s, %s"%(i,j)) if x >= self._subdivisions[0][i+1]-self._subdivisions[0][i] or \ y >= self._subdivisions[1][j+1]-self._subdivisions[1][j]: - raise IndexError("Submatrix %s,%s has no entry %s,%s" % (i, j, x, y)) - return self[self._subdivisions[0][i] + x, self._subdivisions[1][j] + y] + raise IndexError("Submatrix %s,%s has no entry %s,%s"%(i,j, x, y)) + return self[self._subdivisions[0][i] + x , self._subdivisions[1][j] + y] def _subdivide_on_augment(self, left, right): r""" @@ -9465,7 +9454,7 @@ cdef class Matrix(Matrix1): for i from 0 <= i < self._nrows: for j from 0 <= j < self._ncols: self.set_unsafe(i, j, R._random_nonzero_element(*args, - **kwds)) + **kwds)) else: num = int(self._nrows * self._ncols * density) for i from 0 <= i < num: @@ -9505,7 +9494,7 @@ cdef class Matrix(Matrix1): """ return self.is_scalar(self.base_ring().one()) - def is_scalar(self, a=None): + def is_scalar(self, a = None): """ Return True if this matrix is a scalar matrix. @@ -9540,13 +9529,13 @@ cdef class Matrix(Matrix1): if a is None: if self._nrows == 0: return True - a = self.get_unsafe(0, 0) + a = self.get_unsafe(0,0) else: a = self.base_ring()(a) for i in range(self._nrows): for j in range(self._ncols): if i != j: - if not self.get_unsafe(i, j).is_zero(): + if not self.get_unsafe(i,j).is_zero(): return False else: if self.get_unsafe(i, i) != a: @@ -9583,7 +9572,7 @@ cdef class Matrix(Matrix1): for i in range(self._nrows): for j in range(self._ncols): if i != j: - if not self.get_unsafe(i, j).is_zero(): + if not self.get_unsafe(i,j).is_zero(): return False return True @@ -9693,7 +9682,7 @@ cdef class Matrix(Matrix1): P = self.transpose() * self # Orthogonal return P.is_scalar(1) - def is_bistochastic(self, normalized=True): + def is_bistochastic(self, normalized = True): r""" Returns ``True`` if this matrix is bistochastic. @@ -9856,12 +9845,12 @@ cdef class Matrix(Matrix1): cdef Matrix left = self*CT cdef Matrix right = CT*self - cdef Py_ssize_t i, j + cdef Py_ssize_t i,j normal = True # two products are Hermitian, need only check lower triangle for i from 0 <= i < self._nrows: for j from 0 <= j <= i: - if left.get_unsafe(i, j) != right.get_unsafe(i, j): + if left.get_unsafe(i,j) != right.get_unsafe(i,j): normal = False break if not normal: @@ -9978,11 +9967,11 @@ cdef class Matrix(Matrix1): ir = mc ic = mr b = 1.0 - elif max(mr, mc) > maxsize: + elif max(mr,mc) > maxsize: maxsize = float(maxsize) - ir = int(mc * maxsize / max(mr, mc)) - ic = int(mr * maxsize / max(mr, mc)) - b = max(mr, mc) / maxsize + ir = int(mc * maxsize/max(mr,mc)) + ic = int(mr * maxsize/max(mr,mc)) + b = max(mr,mc)/maxsize else: ir = mc ic = mr @@ -9999,7 +9988,7 @@ cdef class Matrix(Matrix1): for _x in range(bi): for _y in range(bi): if not self.get_unsafe((x*b + _x), (y*b + _y)).is_zero(): - v -= 1 # increase darkness + v -= 1 #increase darkness v = (v * fct + 0.5) pixel[y, x] = (v, v, v) return img @@ -10035,7 +10024,7 @@ cdef class Matrix(Matrix1): sage: a.density() 0 """ - cdef int x, y, k + cdef int x,y,k k = 0 nr = self.nrows() nc = self.ncols() @@ -10043,8 +10032,8 @@ cdef class Matrix(Matrix1): return 0 for x from 0 <= x < nr: for y from 0 <= y < nc: - if not self.get_unsafe(x, y).is_zero(): - k += 1 + if not self.get_unsafe(x,y).is_zero(): + k+=1 return QQ(k)/QQ(nr*nc) def inverse(self): @@ -10264,13 +10253,13 @@ cdef class Matrix(Matrix1): This is all left to the method `adjugate`. """ - n = self._ncols + n = self._ncols if self._nrows != n: raise ValueError("self must be a square matrix") A = self.charpoly().shift(-1)(self) - return A if n % 2 else -A + return A if n%2 else -A def QR(self, full=True): r""" @@ -10540,16 +10529,16 @@ cdef class Matrix(Matrix1): scale = sqrt(hip) q = (1/scale)*v Q.append(q) - R[row, i] = scale - for j in range(i + 1, n): - R[row, j] = q.hermitian_inner_product(V[j]) - V[j] = V[j] - R[row, j] * q + R[row,i] = scale + for j in range(i+1, n): + R[row,j] = q.hermitian_inner_product(V[j]) + V[j] = V[j] - R[row,j]*q row = row + 1 except TypeError: raise TypeError('QR decomposition unable to compute square roots in %s' % F) # complete to full orthonormal basis, or reduce to truncated R if full: - Qt = matrix(Q) # as rows here + Qt = matrix(Q) # as rows here if Qt.nrows() == 0: Qt = zero_matrix(F, 0, m) orthogonal = Qt.right_kernel().basis_matrix().transpose() @@ -10698,12 +10687,12 @@ cdef class Matrix(Matrix1): zero = F(0) Bstar = [] R = zero_matrix(F, n) - nnz = 0 # number non-zero rows in R, or number of nonzero vectors in Bstar + nnz = 0 # number non-zero rows in R, or number of nonzero vectors in Bstar for i in range(n): ortho = B[i] for j in range(nnz): - R[j, i] = Bstar[j].hermitian_inner_product(B[i]) / Bstar[j].hermitian_inner_product(Bstar[j]) - ortho = ortho - R[j, i] * Bstar[j] + R[j,i] = Bstar[j].hermitian_inner_product(B[i])/Bstar[j].hermitian_inner_product(Bstar[j]) + ortho = ortho - R[j,i]*Bstar[j] if ortho.hermitian_inner_product(ortho) != zero: Bstar.append(ortho) R[nnz, i] = 1 @@ -11039,8 +11028,7 @@ cdef class Matrix(Matrix1): R = self.base_ring() if isinstance(R, (sage.rings.abc.RealDoubleField, sage.rings.abc.ComplexDoubleField)): Q, R = self.transpose().QR() - m = R.nrows() - n = R.ncols() + m = R.nrows(); n = R.ncols() if m > n: Q = Q[0:m, 0:n] R = R[0:n, 0:n] @@ -11477,7 +11465,7 @@ cdef class Matrix(Matrix1): blocks = [] for eval, mult in evals: if mult == 1: - blocks.append((eval, 1)) + blocks.append((eval,1)) else: B = A - diagonal_matrix([eval]*n, sparse=sparse) C = B @@ -11506,7 +11494,7 @@ cdef class Matrix(Matrix1): # a Jordan chain for each, adding the chain (a sequence of # vectors) to the entry for the eigenvalue (which is a list). jordan_chains = {} - for eval, _ in evals: + for eval,_ in evals: jordan_chains[eval] = [] # Let B be the matrix `A - eval Id`. @@ -11544,9 +11532,9 @@ cdef class Matrix(Matrix1): # Now ``jordan_chains`` has all the columns of the transformation # matrix; we just need to put them in the right order. jordan_basis = [] - for eval, size in blocks: + for eval,size in blocks: # Find a block with the right size - for index, chain in enumerate(jordan_chains[eval]): + for index,chain in enumerate(jordan_chains[eval]): if len(chain) == size: jordan_basis += jordan_chains[eval].pop(index) break @@ -12604,7 +12592,7 @@ cdef class Matrix(Matrix1): R = self.base_ring() if not is_Vector(v): raise TypeError('first input should be a vector, not {0}'.format(v)) - if not (var is None or isinstance(var, str)): + if not (var is None or isinstance(var, str)): generator = False try: generator = var.is_gen() @@ -12923,7 +12911,7 @@ cdef class Matrix(Matrix1): True """ - cdef Matrix C # output matrix + cdef Matrix C # output matrix C = self.fetch('cholesky') if C is not None: return C @@ -12945,7 +12933,7 @@ cdef class Matrix(Matrix1): cdef Matrix L # block_ldlt() results cdef list d # block_ldlt() results try: - _, L, d = self._block_ldlt(True) + _,L,d = self._block_ldlt(True) except ValueError: # If the matrix was positive-definite, that would # have worked. @@ -12958,7 +12946,7 @@ cdef class Matrix(Matrix1): cdef bint extend = False for X in d: # The X are guaranteed to be one-by-one blocks. - x = X[0, 0] + x = X[0,0] if x <= zero: raise ValueError("matrix is not positive definite") @@ -12985,7 +12973,7 @@ cdef class Matrix(Matrix1): from sage.rings.qqbar import AA try: C = L.change_ring(AA) - except ValueError: # cannot coerce... + except ValueError: # cannot coerce... C = L.change_ring(F_ac) else: C = L.__copy__() @@ -12993,11 +12981,11 @@ cdef class Matrix(Matrix1): # Overwrite the (strict) upper-triangular part of "C", since a # priori it contains junk after _block_ldlt(). zero = C.base_ring().zero() - cdef Py_ssize_t i, j # loop indices + cdef Py_ssize_t i, j # loop indices for i in range(n): C.rescale_col_c(i, splits[i], 0) - for j in range(i + 1, n): - C.set_unsafe(i, j, zero) + for j in range(i+1,n): + C.set_unsafe(i,j,zero) C.set_immutable() self.cache('cholesky', C) return C @@ -13117,7 +13105,7 @@ cdef class Matrix(Matrix1): sage: actual == expected True """ - P, L, D = self.block_ldlt() + P,L,D = self.block_ldlt() # The default "echelonize" inverse() method works just fine for # triangular matrices. @@ -13570,24 +13558,24 @@ cdef class Matrix(Matrix1): # abs() necessary to convert zero to the # correct type for comparisons (Issue #12208) max_entry = abs(zero) - for i in range(k, m): - entry = abs(M.get_unsafe(i, k)) + for i in range(k,m): + entry = abs(M.get_unsafe(i,k)) if entry > max_entry: max_location = i max_entry = entry else: - for i in range(k, m): - if M.get_unsafe(i, k) != zero: + for i in range(k,m): + if M.get_unsafe(i,k) != zero: max_location = i break if max_location != -1: perm[k], perm[max_location] = perm[max_location], perm[k] M.swap_rows(k, max_location) for j in range(k+1, m): - scale = -M.get_unsafe(j, k) / M.get_unsafe(k, k) - M.set_unsafe(j, k, -scale) - for p in range(k + 1, n): - M.set_unsafe(j, p, M.get_unsafe(j, p) + scale * M.get_unsafe(k, p)) + scale = -M.get_unsafe(j,k)/M.get_unsafe(k,k) + M.set_unsafe(j,k, -scale) + for p in range(k+1,n): + M.set_unsafe(j,p, M.get_unsafe(j,p) + scale*M.get_unsafe(k,p)) perm = tuple(perm) M.set_immutable() compact = (perm, M) @@ -13606,11 +13594,11 @@ cdef class Matrix(Matrix1): perm = [perm[i]+1 for i in range(m)] P = sage.combinat.permutation.Permutation(perm).to_matrix() P = P.change_ring(F) - L = M.matrix_space(m, m).identity_matrix().__copy__() + L = M.matrix_space(m,m).identity_matrix().__copy__() for i in range(1, m): - for k in range(min(i, d)): - L[i, k] = M[i, k] - M[i, k] = zero + for k in range(min(i,d)): + L[i,k] = M[i,k] + M[i,k] = zero return P, L, M def _indefinite_factorization(self, algorithm, check=True): @@ -13852,16 +13840,16 @@ cdef class Matrix(Matrix1): t = L.get_unsafe(i, j) if conjugate: for k in range(j): - t -= L.get_unsafe(k, i) * L.get_unsafe(j, k).conjugate() + t -= L.get_unsafe(k,i)*L.get_unsafe(j,k).conjugate() else: for k in range(j): - t -= L.get_unsafe(k, i) * L.get_unsafe(j, k) + t -= L.get_unsafe(k,i)*L.get_unsafe(j,k) if i == j: if not t: - self.cache(cache_string, (False, i + 1)) - return (False, i + 1) + self.cache(cache_string, (False,i+1)) + return (False, i+1) d.append(t) - d_inv.append(one / t) + d_inv.append(one/t) L.set_unsafe(i, i, one) else: L.set_unsafe(j, i, t) @@ -14077,7 +14065,7 @@ cdef class Matrix(Matrix1): if result is not None: return result - cdef Py_ssize_t i, j, k # loop indices + cdef Py_ssize_t i, j, k # loop indices cdef Py_ssize_t r # another row/column index # We need to construct 1x1 and 2x2 matrices to stick in d. @@ -14101,7 +14089,7 @@ cdef class Matrix(Matrix1): # at the end of the function, not as its columns are computed. ring = self.base_ring().fraction_field() - cdef Matrix A # A copy of the input matrix + cdef Matrix A # A copy of the input matrix if self.base_ring() == ring: A = self.__copy__() else: @@ -14139,7 +14127,7 @@ cdef class Matrix(Matrix1): cdef list d = [] # And the parent of those diagonal blocks that are 1x1... - one_by_one_space = A.matrix_space(1, 1) + one_by_one_space = A.matrix_space(1,1) # The case n == 0 is *almost* handled by skipping the # forthcoming loop entirely. However, we must stick a trivial @@ -14155,7 +14143,7 @@ cdef class Matrix(Matrix1): # where we're storing the next iterate. So our indices are # always "k" greater than those of Higham or B&K. - A_kk = A.get_unsafe(k, k) + A_kk = A.get_unsafe(k,k) if k == (n-1): # Handle this trivial case manually, since otherwise the @@ -14163,7 +14151,7 @@ cdef class Matrix(Matrix1): # meaningless. The corresponding entry of "L" will be # fixed later (since it's an on-diagonal element, it gets # set to one eventually). - d.append(one_by_one_space(A_kk)) + d.append( one_by_one_space(A_kk) ) k += 1 continue @@ -14173,8 +14161,8 @@ cdef class Matrix(Matrix1): # It's a back door that lets us escape with only the standard non-block # non-pivoting LDL^T factorization. This allows us to implement e.g. # indefinite_factorization() in terms of this method. - d.append(one_by_one_space(A_kk)) - _block_ldlt_pivot1x1(A, k) + d.append( one_by_one_space(A_kk) ) + _block_ldlt_pivot1x1(A,k) k += 1 continue except ZeroDivisionError: @@ -14189,8 +14177,8 @@ cdef class Matrix(Matrix1): # Note: omega_1 is defined as a C double, but the abs() # below would make a complex number approximate anyway. omega_1 = 0 - for i in range(k + 1, n): - a_ik_abs = A.get_unsafe(i, k).abs() + for i in range(k+1,n): + a_ik_abs = A.get_unsafe(i,k).abs() if a_ik_abs > omega_1: omega_1 = a_ik_abs # We record the index "r" that corresponds to @@ -14210,7 +14198,7 @@ cdef class Matrix(Matrix1): # the 1x1 pivot "a" in the top-left position. The entry "a" # will be adjusted to "1" later on to ensure that "L" is # (block) unit-lower-triangular. - d.append(one_by_one_space(A_kk)) + d.append( one_by_one_space(A_kk) ) k += 1 continue @@ -14222,8 +14210,8 @@ cdef class Matrix(Matrix1): # otherwise. We are performing a 1x1 pivot, but the # rows/columns are already where we want them, so nothing # needs to be permuted. - d.append(one_by_one_space(A_kk)) - _block_ldlt_pivot1x1(A, k) + d.append( one_by_one_space(A_kk) ) + _block_ldlt_pivot1x1(A,k) k += 1 continue @@ -14237,30 +14225,27 @@ cdef class Matrix(Matrix1): # Note: omega_r is defined as a C double, but the abs() # below would make a complex number approximate anyway. omega_r = 0 - for j in range(k, r): - a_rj_abs = A.get_unsafe(r, j).abs() + for j in range(k,r): + a_rj_abs = A.get_unsafe(r,j).abs() if a_rj_abs > omega_r: omega_r = a_rj_abs if A_kk.abs()*omega_r >= alpha*(omega_1**2): # Step (2) in Higham or Step (4) in B&K. - d.append(one_by_one_space(A_kk)) - _block_ldlt_pivot1x1(A, k) + d.append( one_by_one_space(A_kk) ) + _block_ldlt_pivot1x1(A,k) k += 1 continue - A_rr = A.get_unsafe(r, r) + A_rr = A.get_unsafe(r,r) if A_rr.abs() > alpha*omega_r: # This is Step (3) in Higham or Step (5) in B&K. Still # a 1x1 pivot, but this time we need to swap # rows/columns k and r. - d.append(one_by_one_space(A_rr)) - A.swap_columns_c(k, r) - A.swap_rows_c(k, r) - p_k = p[k] - p[k] = p[r] - p[r] = p_k - _block_ldlt_pivot1x1(A, k) + d.append( one_by_one_space(A_rr) ) + A.swap_columns_c(k,r); A.swap_rows_c(k,r) + p_k = p[k]; p[k] = p[r]; p[r] = p_k + _block_ldlt_pivot1x1(A,k) k += 1 continue @@ -14268,19 +14253,16 @@ cdef class Matrix(Matrix1): # or Step (6) in B&K, where we perform a 2x2 pivot. See # pivot1x1() for an explanation of why it's OK to permute # the entries of "L" here as well. - A.swap_columns_c(k + 1, r) - A.swap_rows_c(k + 1, r) - p_k = p[k + 1] - p[k + 1] = p[r] - p[r] = p_k + A.swap_columns_c(k+1,r); A.swap_rows_c(k+1,r) + p_k = p[k+1]; p[k+1] = p[r]; p[r] = p_k # The top-left 2x2 submatrix (starting at position k,k) is # now our pivot. - E = A[k: k + 2, k: k + 2] + E = A[k:k+2,k:k+2] d.append(E) - C = A[k + 2: n, k: k + 2] - B = A[k + 2:, k+2:] + C = A[k+2:n,k:k+2] + B = A[k+2:,k+2:] # We don't actually need the inverse of E, what we really need # is C*E.inverse(), and that can be found by setting @@ -14297,10 +14279,10 @@ cdef class Matrix(Matrix1): # Compute the Schur complement that we'll work on during # the following iteration, and store it back in the lower- # right-hand corner of "A". - for i in range(n - k - 2): - for j in range(i + 1): - A.set_unsafe(k + 2 + i, k + 2 + j, schur_complement[i, j]) - A.set_unsafe(k + 2 + j, k + 2 + i, schur_complement[j, i]) + for i in range(n-k-2): + for j in range(i+1): + A.set_unsafe(k+2+i, k+2+j, schur_complement[i,j]) + A.set_unsafe(k+2+j, k+2+i, schur_complement[j,i]) # The on- and above-diagonal entries of "L" will be fixed # later, so we only need to worry about the lower-left entry @@ -14311,7 +14293,8 @@ cdef class Matrix(Matrix1): for j in range(2): # Store the new (k and (k+1)st) columns of "L" within # the lower-left-hand corner of "A". - A.set_unsafe(k+i+2, k+j, CE_inverse[i, j]) + A.set_unsafe(k+i+2, k+j, CE_inverse[i,j]) + k += 2 @@ -14320,7 +14303,7 @@ cdef class Matrix(Matrix1): # correctness. A.set_unsafe(i, i, one) - result = (p, A, d) + result = (p,A,d) self.cache(cache_string, result) return result @@ -14625,12 +14608,12 @@ cdef class Matrix(Matrix1): """ cdef Py_ssize_t n # size of the matrices - cdef Py_ssize_t i, j # loop indices - cdef Matrix P, L, D # output matrices + cdef Py_ssize_t i, j # loop indices + cdef Matrix P,L,D # output matrices - p, L, d = self._block_ldlt(classical) + p,L,d = self._block_ldlt(classical) MS = L.matrix_space() - P = MS.matrix(lambda i, j: p[j] == i) + P = MS.matrix(lambda i,j: p[j] == i) # Warning: when n == 0, this works, but returns a matrix # whose (nonexistent) entries are in ZZ rather than in @@ -14643,10 +14626,11 @@ cdef class Matrix(Matrix1): n = L._nrows zero = MS.base_ring().zero() for i in range(n): - for j in range(i + 1, n): - L.set_unsafe(i, j, zero) + for j in range(i+1,n): + L.set_unsafe(i,j,zero) + + return (P,L,D) - return (P, L, D) cdef bint _is_positive_definite_or_semidefinite(self, bint semi) except -1: """ @@ -14656,7 +14640,7 @@ cdef class Matrix(Matrix1): code. The boolean ``semi`` argument exists only to change "greater than zero" into "greater than or equal to zero." """ - from sage.rings.real_lazy import RLF, CLF + from sage.rings.real_lazy import RLF,CLF R = self.base_ring() @@ -14676,10 +14660,10 @@ cdef class Matrix(Matrix1): return False if self._nrows == 0: - return True # vacuously + return True # vacuously cdef list d - _, _, d = self._block_ldlt(False) + _,_,d = self._block_ldlt(False) # Check each 1x1 block for a nonpositive (negative) entry. If # we don't find any, the matrix is positive-(semi)definite. The @@ -14689,7 +14673,8 @@ cdef class Matrix(Matrix1): if semi: op = operator.ge - return all(d_i.nrows() == 1 and op(d_i[0, 0], 0) for d_i in d) + return all(d_i.nrows() == 1 and op(d_i[0,0], 0) for d_i in d) + def is_positive_semidefinite(self): r""" @@ -15001,7 +14986,7 @@ cdef class Matrix(Matrix1): result = self._is_positive_definite_or_semidefinite(False) if certificate: from sage.misc.superseded import deprecation - msg = "the 'certificate' argument is deprecated; if you " + msg = "the 'certificate' argument is deprecated; if you " msg += "need the corresponding factorization, you can " msg += "simply compute it yourself (the results are cached)" deprecation(31619, msg) @@ -15009,7 +14994,7 @@ cdef class Matrix(Matrix1): d = None if result: from sage.modules.free_module_element import vector - _, L, D = self.block_ldlt() + _,L,D = self.block_ldlt() d = vector(D.base_ring(), D.diagonal()) return (result, L, d) else: @@ -15090,7 +15075,7 @@ cdef class Matrix(Matrix1): m2 = hadamard_row_bound_mpfr(A) return min(m1, m2) - def find(self, f, indices=False): + def find(self,f, indices=False): r""" Find elements in this matrix satisfying the constraints in the function `f`. The function is evaluated on each element of @@ -15156,7 +15141,7 @@ cdef class Matrix(Matrix1): True """ from sage.matrix.matrix_space import MatrixSpace - cdef Py_ssize_t size, i, j + cdef Py_ssize_t size,i,j cdef object M if not indices: @@ -15165,20 +15150,20 @@ cdef class Matrix(Matrix1): M = PyList_New(0) for i from 0 <= i < size: - PyList_Append(M, f(PyList_GET_ITEM(L, i))) + PyList_Append(M,f(PyList_GET_ITEM(L,i))) from sage.rings.finite_rings.integer_mod_ring import IntegerModRing return MatrixSpace(IntegerModRing(2), - nrows=self._nrows, ncols=self._ncols).matrix(M) + nrows=self._nrows,ncols=self._ncols).matrix(M) else: # return matrix along with indices in a dictionary d = {} for i from 0 <= i < self._nrows: for j from 0 <= j < self._ncols: - if f(self.get_unsafe(i, j)): - d[(i, j)] = self.get_unsafe(i, j) + if f(self.get_unsafe(i,j)): + d[(i,j)] = self.get_unsafe(i,j) return d @@ -15669,7 +15654,7 @@ cdef class Matrix(Matrix1): """ d = self.smith_form(transformation=False) r = min(self.nrows(), self.ncols()) - return [d[i, i] for i in range(r)] + return [d[i,i] for i in range(r)] def smith_form(self, transformation=True, integral=None, exact=True): r""" @@ -15893,19 +15878,19 @@ cdef class Matrix(Matrix1): raise NotImplementedError("Smith form over non-exact rings not implemented at present") # first clear the first row and column - u, t, v = _smith_onestep(self) + u,t,v = _smith_onestep(self) # now recurse: t now has a nonzero entry at 0,0 and zero entries in the rest # of the 0th row and column, so we apply smith_form to the smaller submatrix - mm = t.submatrix(1, 1) + mm = t.submatrix(1,1) if transformation: dd, uu, vv = mm.smith_form(transformation=True) else: dd = mm.smith_form(transformation=False) - d = dd.new_matrix(1, 1, [t[0, 0]]).block_sum(dd) + d = dd.new_matrix(1,1,[t[0,0]]).block_sum(dd) if transformation: - u = uu.new_matrix(1, 1, [1]).block_sum(uu) * u - v = v * vv.new_matrix(1, 1, [1]).block_sum(vv) + u = uu.new_matrix(1,1,[1]).block_sum(uu) * u + v = v * vv.new_matrix(1,1,[1]).block_sum(vv) dp, up, vp = _smith_diag(d, transformation=transformation) if integral is False: dp = dp.change_ring(R) @@ -16128,37 +16113,36 @@ cdef class Matrix(Matrix1): pivot_cols = [] while j < n: k = i - while k < m and A.get_unsafe(k, j).is_zero(): # first nonzero entry + while k < m and A.get_unsafe(k,j).is_zero(): # first nonzero entry k += 1 if k < m: l = k + 1 while l < m: - while l < m and A.get_unsafe(l, j).is_zero(): # nonzero entry below + while l < m and A.get_unsafe(l,j).is_zero(): # nonzero entry below l += 1 - if l >= m: - break + if l >= m: break - a = A.get_unsafe(k, j) - b = A.get_unsafe(l, j) - d, p, q = a.xgcd(b) # p * a + q * b = d = gcd(a,b) + a = A.get_unsafe(k,j) + b = A.get_unsafe(l,j) + d,p,q = a.xgcd(b) # p * a + q * b = d = gcd(a,b) e = a // d f = b // d - for c in range(j, n): - Akc = A.get_unsafe(k, c) - Alc = A.get_unsafe(l, c) + for c in range(j,n): + Akc = A.get_unsafe(k,c) + Alc = A.get_unsafe(l,c) A.set_unsafe(k, c, p * Akc + q * Alc) A.set_unsafe(l, c, (-f) * Akc + e * Alc) if transformation: for c in range(m): - Ukc = U.get_unsafe(k, c) - Ulc = U.get_unsafe(l, c) + Ukc = U.get_unsafe(k,c) + Ulc = U.get_unsafe(l,c) U.set_unsafe(k, c, p * Ukc + q * Ulc) U.set_unsafe(l, c, (-f) * Ukc + e * Ulc) if i != k: - A.swap_rows_c(i, k) + A.swap_rows_c(i,k) if transformation: - U.swap_rows_c(i, k) + U.swap_rows_c(i,k) pivot_cols.append(j) i += 1 j += 1 @@ -16166,26 +16150,26 @@ cdef class Matrix(Matrix1): # reduce entries above pivots for i in range(len(pivot_cols)): j = pivot_cols[i] - pivot = A.get_unsafe(i, j) + pivot = A.get_unsafe(i,j) # possibly normalize the pivot if normalization: coeff = normalization(pivot) - for c in range(j, n): - A.set_unsafe(i, c, A.get_unsafe(i, c) * coeff) + for c in range(j,n): + A.set_unsafe(i, c, A.get_unsafe(i,c) * coeff) if transformation: for c in range(m): - U.set_unsafe(i, c, U.get_unsafe(i, c) * coeff) + U.set_unsafe(i, c, U.get_unsafe(i,c) * coeff) - pivot = A.get_unsafe(i, j) + pivot = A.get_unsafe(i,j) for k in range(i): - q = - (A.get_unsafe(k, j) // pivot) + q = - (A.get_unsafe(k,j) // pivot) if not q.is_zero(): - for c in range(j, n): - A.set_unsafe(k, c, A.get_unsafe(k, c) + q * A.get_unsafe(i, c)) + for c in range(j,n): + A.set_unsafe(k, c, A.get_unsafe(k,c) + q * A.get_unsafe(i,c)) if transformation: for c in range(m): - U.set_unsafe(k, c, U.get_unsafe(k, c) + q * U.get_unsafe(i, c)) + U.set_unsafe(k, c, U.get_unsafe(k,c) + q * U.get_unsafe(i,c)) if transformation: return U @@ -16329,25 +16313,25 @@ cdef class Matrix(Matrix1): return self.new_matrix(self.nrows(), self.nrows(), 1), self, [] else: return self.new_matrix(self.nrows(), self.nrows(), 1), self, [ - self.nonzero_positions_in_row(0)[0]] + self.nonzero_positions_in_row(0)[0] ] R = self.base_ring() # data type checks on R if not R.is_integral_domain(): raise TypeError("Generic echelon form only defined over " - "integral domains") + "integral domains") if not R.is_exact(): raise NotImplementedError("Echelon form over generic non-exact " - "rings not implemented at present") + "rings not implemented at present") left_mat, a = _generic_clear_column(self) assert left_mat * self == a - if a[0, 0] != 0: + if a[0,0] != 0: aa = a.submatrix(1, 1) s, t, pivs = aa._echelon_form_PID() - left_mat = s.new_matrix(1, 1, [1]).block_sum(s) * left_mat + left_mat = s.new_matrix(1,1,[1]).block_sum(s) * left_mat a = left_mat * self pivs = [0] + [x + 1 for x in pivs] @@ -16365,12 +16349,12 @@ cdef class Matrix(Matrix1): I = ideal_or_fractional(R, y) s = a[0][pivs[i]] t = I.small_residue(s) - v = R((s-t) / y) + v = R( (s-t) / y) left_mat.add_multiple_of_row(0, i, -v) a.add_multiple_of_row(0, i, -v) assert left_mat * self == a - except AttributeError: # on I.small_residue + except AttributeError: # on I.small_residue pass return left_mat, a, pivs @@ -16477,7 +16461,7 @@ cdef class Matrix(Matrix1): cdef list corners = [] # zero or one in corner of off-diagonal blocks if basis: from sage.matrix.constructor import identity_matrix - U = identity_matrix(R, n) # transformation matrix + U = identity_matrix(R, n) # transformation matrix # parity switch, True iff working on transpose # if False, mimic row operations only on U # if True, mimic column operations only on U @@ -16490,7 +16474,7 @@ cdef class Matrix(Matrix1): while zigging: # zigging means we are building a block nonzero = -1 for i in range(c+1, n): - if Z.get_unsafe(i, c): + if Z.get_unsafe(i,c): nonzero = i break zigging = (nonzero != -1) @@ -16534,7 +16518,7 @@ cdef class Matrix(Matrix1): # (inclusive), use it to clear entries to the right # but first record polynomial for block just built # this is the full monic polynomial, with correct coefficients - p = [-Z.get_unsafe(i, c) for i in range(s, c + 1)] + p = [-Z.get_unsafe(i,c) for i in range(s,c+1)] p.append(one) polys.append(p) @@ -16550,7 +16534,7 @@ cdef class Matrix(Matrix1): # Effectively: Z.add_multiple_of_row(i, j, scale) for k in range(c+1, n): # Z[i,k] = Z[i,k] + scale*Z[j,k] - Z.set_unsafe(i, k, Z.get_unsafe(i, k) + scale * Z.get_unsafe(j, k)) + Z.set_unsafe(i, k, Z.get_unsafe(i,k)+scale*Z.get_unsafe(j,k)) if basis: if trans: U.add_multiple_of_column(j, i, -scale) @@ -17317,7 +17301,7 @@ cdef class Matrix(Matrix1): companions.append(companion_matrix(poly, format=format)) return block_diagonal_matrix(companions, subdivide=subdivide) - def is_positive_operator_on(self, K1, K2=None): + def is_positive_operator_on(self,K1,K2=None): r""" Determine if this matrix is a positive operator on a cone. @@ -17751,7 +17735,7 @@ cdef class Matrix(Matrix1): """ return (-self).is_cross_positive_on(K) - def is_lyapunov_like_on(self, K): + def is_lyapunov_like_on(self,K): r""" Determine if this matrix is Lyapunov-like on a cone. @@ -18121,35 +18105,35 @@ def _smith_diag(d, transformation=True): else: left = right = None for i in range(n): - I0 = ideal_or_fractional(R, dp[i, i]) + I = ideal_or_fractional(R, dp[i,i]) - if I0 == ideal_or_fractional(R, 1): - if dp[i, i] != 1: + if I == ideal_or_fractional(R, 1): + if dp[i,i] != 1: if transformation: - left.add_multiple_of_row(i, i, R(R(1) / (dp[i, i])) - 1) - dp[i, i] = R(1) + left.add_multiple_of_row(i,i,R(R(1)/(dp[i,i])) - 1) + dp[i,i] = R(1) continue - for j in range(i + 1, n): - if dp[j, j] not in I0: - t = ideal_or_fractional(R, [dp[i, i], dp[j, j]]).gens_reduced() + for j in range(i+1,n): + if dp[j,j] not in I: + t = ideal_or_fractional(R, [dp[i,i], dp[j,j]]).gens_reduced() if len(t) > 1: raise ArithmeticError t = t[0] # find lambda, mu such that lambda*d[i,i] + mu*d[j,j] = t - lamb = R(dp[i, i] / t).inverse_mod(ideal_or_fractional(R, dp[j, j] / t)) - mu = R((t - lamb * dp[i, i]) / dp[j, j]) + lamb = R(dp[i,i]/t).inverse_mod( ideal_or_fractional(R, dp[j,j]/t)) + mu = R((t - lamb*dp[i,i]) / dp[j,j]) newlmat = dp.new_matrix(dp.nrows(), dp.nrows(), 1) - newlmat[i, i] = lamb - newlmat[i, j] = 1 - newlmat[j, i] = R(-dp[j, j] * mu / t) - newlmat[j, j] = R(dp[i, i] / t) + newlmat[i,i] = lamb + newlmat[i,j] = 1 + newlmat[j,i] = R(-dp[j,j]*mu/t) + newlmat[j,j] = R(dp[i,i]/t) newrmat = dp.new_matrix(dp.ncols(), dp.ncols(), 1) - newrmat[i, i] = 1 - newrmat[i, j] = R(-dp[j, j] / t) - newrmat[j, i] = mu - newrmat[j, j] = R(lamb * dp[i, i] / t) + newrmat[i,i] = 1 + newrmat[i,j] = R(-dp[j,j]/t) + newrmat[j,i] = mu + newrmat[j,j] = R(lamb*dp[i,i] / t) if transformation: left = newlmat*left @@ -18195,13 +18179,13 @@ def _generic_clear_column(m): k = 0 while a[k, 0] == 0: k += 1 - if k == a.nrows(): # first column is zero + if k == a.nrows(): # first column is zero return left_mat, a # k is now first row such that a[k, 0] is nonzero - left_mat[0, 0] = 0 - left_mat[k, k] = 0 - left_mat[0, k] = 1 - left_mat[k, 0] = -1 + left_mat[0,0] = 0 + left_mat[k,k] = 0 + left_mat[0,k] = 1 + left_mat[k,0] = -1 a = left_mat*a if left_mat * m != a: raise ArithmeticError("Something went wrong") @@ -18215,15 +18199,15 @@ def _generic_clear_column(m): # [e,f] # is invertible over R - I0 = ideal_or_fractional(R, a[0, 0]) # need to make sure we change this when a[0,0] changes + I = ideal_or_fractional(R, a[0, 0]) # need to make sure we change this when a[0,0] changes for k in range(1, a.nrows()): - if a[k, 0] not in I0: + if a[k,0] not in I: try: - v = ideal_or_fractional(R, a[0, 0], a[k, 0]).gens_reduced() + v = ideal_or_fractional(R, a[0,0], a[k,0]).gens_reduced() except Exception as msg: - raise ArithmeticError("%s\nCan't create ideal on %s and %s" % (msg, a[0, 0], a[k, 0])) + raise ArithmeticError("%s\nCan't create ideal on %s and %s" % (msg, a[0,0], a[k,0])) if len(v) > 1: - raise ArithmeticError("Ideal %s not principal" % ideal_or_fractional(R, a[0, 0], a[k, 0])) + raise ArithmeticError("Ideal %s not principal" % ideal_or_fractional(R, a[0,0], a[k,0])) B = v[0] # now we find c,d, using the fact that c * (a_{0,0}/B) - d * @@ -18232,40 +18216,40 @@ def _generic_clear_column(m): # need to handle carefully the case when a_{k,0}/B is a unit, i.e. a_{k,0} divides # a_{0,0}. - c = R(a[0, 0] / B).inverse_mod(ideal_or_fractional(R, a[k, 0] / B)) - d = R((c*a[0, 0] - B)/(a[k, 0])) + c = R(a[0,0] / B).inverse_mod(ideal_or_fractional(R, a[k,0] / B)) + d = R( (c*a[0,0] - B)/(a[k,0]) ) # sanity check - if c*a[0, 0] - d*a[k, 0] != B: + if c*a[0,0] - d*a[k,0] != B: raise ArithmeticError # now we find e,f such that e*d + c*f = 1 in the same way if c != 0: - e = d.inverse_mod(ideal_or_fractional(R, c)) + e = d.inverse_mod( ideal_or_fractional(R, c) ) f = R((1 - d*e)/c) else: - e = R(-a[k, 0] / B) # here d is a unit and this is just 1/d + e = R(-a[k,0]/B) # here d is a unit and this is just 1/d f = R(1) if e*d + c*f != 1: raise ArithmeticError newlmat = left_mat.parent()(1) - newlmat[0, 0] = c - newlmat[0, k] = -d - newlmat[k, 0] = e - newlmat[k, k] = f + newlmat[0,0] = c + newlmat[0,k] = -d + newlmat[k,0] = e + newlmat[k,k] = f if newlmat.det() != 1: raise ArithmeticError a = newlmat*a - I0 = ideal_or_fractional(R, a[0, 0]) + I = ideal_or_fractional(R, a[0,0]) left_mat = newlmat*left_mat if left_mat * m != a: raise ArithmeticError # now everything in column 0 is divisible by the pivot - for i in range(1, a.nrows()): - s = R(a[i, 0] / a[0, 0]) - a.add_multiple_of_row(i, 0, -s) + for i in range(1,a.nrows()): + s = R( a[i, 0]/a[0, 0]) + a.add_multiple_of_row(i, 0, -s ) left_mat.add_multiple_of_row(i, 0, -s) if left_mat * m != a: raise ArithmeticError @@ -18303,12 +18287,11 @@ def _smith_onestep(m): # preparation: if column 0 is zero, swap it with the first nonzero column j = 0 - while a.column(j) == 0: - j += 1 + while a.column(j) == 0: j += 1 if j > 0: - right_mat[0, 0] = right_mat[j, j] = 0 - right_mat[0, j] = 1 - right_mat[j, 0] = -1 + right_mat[0,0] = right_mat[j,j] = 0 + right_mat[0,j] = 1 + right_mat[j,0] = -1 a = a*right_mat if m * right_mat != a: raise ArithmeticError @@ -18319,15 +18302,15 @@ def _smith_onestep(m): # test if everything to the right of the pivot in row 0 is good as well isdone = True for jj in range(j+1, a.ncols()): - if a[0, jj] != 0: + if a[0,jj] != 0: isdone = False # if not we recurse -- algorithm must terminate if R is Noetherian. if not isdone: - s, t, u = _smith_onestep(a.transpose()) + s,t,u = _smith_onestep(a.transpose()) left_mat = u.transpose() * left_mat a = t.transpose() - right_mat = right_mat * s.transpose() + right_mat = right_mat* s.transpose() return left_mat, a, right_mat @@ -18602,7 +18585,7 @@ def _matrix_power_symbolic(A, n): # Jordan block Jk, its dimension nk, the eigenvalue m Jk = J.subdivision(k, k) nk = Jk.ncols() - mk = Jk[0, 0] + mk = Jk[0,0] # First row of block Mk; its entries are of the form # D^i(f) / i! with f = x^n and D = differentiation wrt x @@ -18649,28 +18632,28 @@ cdef inline bint _block_ldlt_pivot1x1(Matrix A, Py_ssize_t k) except 1: to return zero/one so that ``1`` can be used to indicate that a python exception occurred. """ - cdef Py_ssize_t i, j # dumy loop indices + cdef Py_ssize_t i,j # dumy loop indices cdef Py_ssize_t n = A._nrows - pivot = A.get_unsafe(k, k) + pivot = A.get_unsafe(k,k) # Compute the Schur complement that we'll work on during # the following iteration, and store it back in the lower- # right-hand corner of "A". - for i in range(n - k - 1): - for j in range(i + 1): - A.set_unsafe(k + 1 + i, - k + 1 + j, - (A.get_unsafe(k + 1 + i, k + 1 + j) - - A.get_unsafe(k + 1 + i, k) * A.get_unsafe(k, k + 1 + j) / pivot)) - A.set_unsafe(k + 1 + j, - k + 1 + i, - A.get_unsafe(k + 1 + i, k + 1 + j).conjugate()) + for i in range(n-k-1): + for j in range(i+1): + A.set_unsafe(k+1+i, + k+1+j, + ( A.get_unsafe(k+1+i,k+1+j) - + A.get_unsafe(k+1+i,k)*A.get_unsafe(k,k+1+j)/pivot )) + A.set_unsafe(k+1+j, + k+1+i, + A.get_unsafe(k+1+i,k+1+j).conjugate()) for i in range(n-k-1): # Store the new (kth) column of "L" within the lower- # left-hand corner of "A". - A.set_unsafe(k + i + 1, + A.set_unsafe(k+i+1, k, - A.get_unsafe(k + i + 1, k) / pivot) + A.get_unsafe(k+i+1,k)/ pivot) return 0 From d22015ca69e5bfff517a129c0c3df639ab060efd Mon Sep 17 00:00:00 2001 From: Enrique Artal Date: Sun, 1 Oct 2023 10:52:33 +0200 Subject: [PATCH 24/45] undo format changes for matrix_mpolynomial_dense.pyx --- src/sage/matrix/matrix_mpolynomial_dense.pyx | 55 ++++++++++---------- 1 file changed, 27 insertions(+), 28 deletions(-) diff --git a/src/sage/matrix/matrix_mpolynomial_dense.pyx b/src/sage/matrix/matrix_mpolynomial_dense.pyx index 589b5b33331..e3de9bbdb57 100644 --- a/src/sage/matrix/matrix_mpolynomial_dense.pyx +++ b/src/sage/matrix/matrix_mpolynomial_dense.pyx @@ -9,14 +9,14 @@ AUTHOR: * Martin Albrecht """ -# ***************************************************************************** +#***************************************************************************** # Copyright (C) 2013 Martin Albrecht # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. # https://www.gnu.org/licenses/ -# ***************************************************************************** +#***************************************************************************** from sage.matrix.matrix_generic_dense cimport Matrix_generic_dense from sage.matrix.matrix2 cimport Matrix @@ -101,8 +101,7 @@ cdef class Matrix_mpolynomial_dense(Matrix_generic_dense): [ 0 -x + y] """ x = self.fetch('echelon_form_'+algorithm) - if x is not None: - return x + if x is not None: return x if algorithm == "frac": E = self.matrix_over_field() @@ -117,8 +116,8 @@ cdef class Matrix_mpolynomial_dense(Matrix_generic_dense): if algorithm == "frac": self.cache('pivots', E.pivots()) elif algorithm == "bareiss": - l1 = E.swapped_columns() - self.cache('pivots', tuple(sorted(l1))) + l = E.swapped_columns() + self.cache('pivots', tuple(sorted(l))) elif algorithm == "row_reduction": pass @@ -155,7 +154,7 @@ cdef class Matrix_mpolynomial_dense(Matrix_generic_dense): x = self.fetch('pivots') if x is None: - raise RuntimeError("BUG: matrix pivots should have been set but weren't, matrix parent = '%s'" % self.parent()) + raise RuntimeError("BUG: matrix pivots should have been set but weren't, matrix parent = '%s'"%self.parent()) return x def echelonize(self, algorithm='row_reduction', **kwds): @@ -263,7 +262,7 @@ cdef class Matrix_mpolynomial_dense(Matrix_generic_dense): self.clear_cache() singular_bareiss = singular_function("bareiss") - E, ln = singular_bareiss(self.T) + E, l = singular_bareiss(self.T) m = len(E) n = len(E[0]) @@ -278,33 +277,33 @@ cdef class Matrix_mpolynomial_dense(Matrix_generic_dense): self.set_unsafe(r, c, R._zero_element) from sage.rings.integer_ring import ZZ - ln = [ZZ(e-1) for e in ln] + l = [ZZ(e-1) for e in l] - self.cache('in_echelon_form_bareiss', True) + self.cache('in_echelon_form_bareiss',True) self.cache('rank', len(E)) self.cache('pivots', tuple(range(len(E)))) - self.cache('swapped_columns', tuple(ln)) + self.cache('swapped_columns', tuple(l)) elif can_convert_to_singular(self.base_ring()): self.check_mutability() self.clear_cache() - E, ln = self.T._singular_().bareiss()._sage_(self.base_ring()) + E,l = self.T._singular_().bareiss()._sage_(self.base_ring()) # clear matrix for r from 0 <= r < self._nrows: for c from 0 <= c < self._ncols: - self.set_unsafe(r, c, R._zero_element) + self.set_unsafe(r,c,R._zero_element) for r from 0 <= r < E.nrows(): for c from 0 <= c < E.ncols(): - self.set_unsafe(c, r, E[r, c]) + self.set_unsafe(c,r, E[r,c]) - self.cache('in_echelon_form_bareiss', True) + self.cache('in_echelon_form_bareiss',True) self.cache('rank', E.nrows()) self.cache('pivots', tuple(range(E.nrows()))) - self.cache('swapped_columns', ln) + self.cache('swapped_columns', l) else: @@ -388,14 +387,14 @@ cdef class Matrix_mpolynomial_dense(Matrix_generic_dense): if x is not None: return # already known to be in echelon form - nr, nc = self.nrows(), self.ncols() + nr,nc = self.nrows(),self.ncols() F = self.base_ring().base_ring() - cdef Matrix d = matrix(F, nr, nc) + cdef Matrix d = matrix(F,nr,nc) start_row = 0 for r from 0 <= r < nr: for c from 0 <= c < nc: - p = self.get_unsafe(r, c) + p = self.get_unsafe(r,c) if p.is_constant(): d.set_unsafe(r, c, p.constant_coefficient()) @@ -405,25 +404,25 @@ cdef class Matrix_mpolynomial_dense(Matrix_generic_dense): if d.get_unsafe(rc, c): r = rc break - if r != -1: - a_inverse = ~self.get_unsafe(r, c) - self.rescale_row_c(r, a_inverse, c) + if r!=-1: + a_inverse = ~self.get_unsafe(r,c) + self.rescale_row_c(r, a_inverse , c) self.swap_rows_c(r, start_row) for i from 0 <= i < nr: if i != start_row: - minus_b = -self.get_unsafe(i, c) + minus_b = -self.get_unsafe(i,c) self.add_multiple_of_row(i, start_row, minus_b, 0) - start_row += 1 + start_row +=1 d = d._parent(0) for i from start_row <= i < nr: for j from c+1 <= j < nc: - if self.get_unsafe(i, j).is_constant(): - d.set_unsafe(i, j, self.get_unsafe(i, j).constant_coefficient()) + if self.get_unsafe(i,j).is_constant(): + d.set_unsafe(i,j, self.get_unsafe(i,j).constant_coefficient()) - self.cache('in_echelon_form_row_reduction', True) + self.cache('in_echelon_form_row_reduction',True) def swapped_columns(self): """ @@ -500,7 +499,7 @@ cdef class Matrix_mpolynomial_dense(Matrix_generic_dense): N = self.__copy__() for j in range(self.ncols()): if j != ncoef: - N.add_multiple_of_column(j, ncoef, -R(self[nrow, j] / coef)) + N.add_multiple_of_column(j, ncoef, -R(self[nrow,j] / coef)) return N.fitting_ideal(i) for (ncolumn, column) in enumerate(self.columns()): if not column: From 53c99d2044076ce5c459e395f2fb562c6890a58a Mon Sep 17 00:00:00 2001 From: Enrique Artal Date: Sun, 1 Oct 2023 10:55:46 +0200 Subject: [PATCH 25/45] undo format changes for matrix_mpolynomial_dense.pyx and laurent_polynomial.pyx --- .../rings/polynomial/laurent_polynomial.pyx | 35 ++++++++++--------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/src/sage/rings/polynomial/laurent_polynomial.pyx b/src/sage/rings/polynomial/laurent_polynomial.pyx index d4dff8b1361..f0ccb4e2ce0 100644 --- a/src/sage/rings/polynomial/laurent_polynomial.pyx +++ b/src/sage/rings/polynomial/laurent_polynomial.pyx @@ -359,7 +359,7 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): elif (not isinstance(f, Polynomial)) or (parent is not f.parent()): if isinstance(f, dict): v = min(f) if f else 0 - f = {i-v: c for i, c in f.items()} + f = {i-v: c for i,c in f.items()} n += v f = parent._R(f) @@ -592,11 +592,11 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): elif e == 0: var = "" else: - var = "*{}^{}".format(X, e) - s += "{}{}".format(x, var) + var = "*{}^{}".format(X,e) + s += "{}{}".format(x,var) first = False s = s.replace(" + -", " - ") - s = s.replace(" 1*", " ") + s = s.replace(" 1*"," ") s = s.replace(" -1*", " -") return s[1:] @@ -653,19 +653,19 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): elif e == 0: var = "" elif e > 0: - var = "|{}^{{{}}}".format(X, e) + var = "|{}^{{{}}}".format(X,e) if e >= 0: - s += "{}{}".format(x, var) - else: # negative e + s += "{}{}".format(x,var) + else: # negative e if e == -1: s += "\\frac{{{}}}{{{}}}".format(x, X) else: - s += "\\frac{{{}}}{{{}^{{{}}}}}".format(x, X, -e) + s += "\\frac{{{}}}{{{}^{{{}}}}}".format(x, X,-e) first = False s = s.replace(" + -", " - ") - s = s.replace(" 1|", " ") + s = s.replace(" 1|"," ") s = s.replace(" -1|", " -") - s = s.replace("|", "") + s = s.replace("|","") return s[1:] @@ -701,7 +701,7 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): # degrees cdef long result = 0 cdef long result_mon - cdef int i, j + cdef int i,j cdef long var_hash_name = hash(self.__u._parent._names[0]) for i in range(self.__u.degree()+1): result_mon = hash(self.__u[i]) @@ -913,11 +913,11 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): j = i - self.__n if j >= 0: self.__u._unsafe_mutate(j, value) - else: # off to the left + else: # off to the left if value != 0: self.__n = self.__n + j R = self._parent.base_ring() - coeffs = [value] + [R.zero() for _ in range(1, -j)] + self.__u.list() + coeffs = [value] + [R.zero() for _ in range(1,-j)] + self.__u.list() self.__u = self.__u._parent(coeffs) self._normalize() @@ -1282,7 +1282,7 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): Fraction Field of Univariate Polynomial Ring in t over Rational Field """ cdef LaurentPolynomial_univariate ret - if self.__u.is_constant(): # this has a single term c*x^n + if self.__u.is_constant(): # this has a single term c*x^n ret = self._new_c() if self.__u.is_unit(): ret.__u = self.__u.inverse_of_unit() @@ -1680,6 +1680,7 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): """ return self.__n == 0 and self.__u.is_constant() + def is_square(self, root=False): r""" Return whether this Laurent polynomial is a square. @@ -1926,10 +1927,10 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): cdef list a = self.__u.list(copy=False) if n < 0: - v = [a[i] / (n + i + 1) for i in range(min(-1 - n, len(a)))] + [0] + v = [a[i]/(n+i+1) for i in range(min(-1-n,len(a)))] + [0] else: v = [] - v += [a[i] / (n + i + 1) for i in range(max(-n, 0), len(a))] + v += [a[i]/(n+i+1) for i in range(max(-n,0), len(a))] try: u = self._parent._R(v) except TypeError: @@ -1968,7 +1969,7 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): """ if kwds: f = self.subs(**kwds) - if x: # If there are non-keyword arguments + if x: # If there are non-keyword arguments return f(*x) else: return f From e5664d71849e6a367144ca9836c06510a6584307 Mon Sep 17 00:00:00 2001 From: Enrique Artal Date: Sun, 1 Oct 2023 10:59:37 +0200 Subject: [PATCH 26/45] undo format changes for laurent_polynomial_ideal.py --- .../polynomial/laurent_polynomial_ideal.py | 49 +++++++++---------- 1 file changed, 24 insertions(+), 25 deletions(-) diff --git a/src/sage/rings/polynomial/laurent_polynomial_ideal.py b/src/sage/rings/polynomial/laurent_polynomial_ideal.py index bea4b8bb76a..81bc095c382 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_ideal.py +++ b/src/sage/rings/polynomial/laurent_polynomial_ideal.py @@ -26,8 +26,7 @@ from sage.structure.richcmp import op_EQ, op_NE, op_LT, op_LE, op_GT, op_GE from sage.arith.misc import GCD - -class LaurentPolynomialIdeal(Ideal_generic): +class LaurentPolynomialIdeal( Ideal_generic ): def __init__(self, ring, gens, coerce=True, hint=None): r""" Create an ideal in a Laurent polynomial ring. @@ -93,7 +92,7 @@ def __init__(self, ring, gens, coerce=True, hint=None): """ Ideal_generic.__init__(self, ring, gens, coerce=coerce) self._poly_ring = ring.polynomial_ring() - self._poly_ideal = None # Create only as needed + self._poly_ideal = None # Create only as needed self._saturated = False self._hint = self._poly_ring.ideal([f.monomial_reduction()[0] for f in self.gens()]) # if hint is None: @@ -169,11 +168,11 @@ def _richcmp_(self, right_r, op): True """ if op in (op_EQ, op_NE): - if set(self.gens()) == set(right_r.gens()): # Early abort + if set(self.gens()) == set(right_r.gens()): # Early abort return (op == op_EQ) return ((self.polynomial_ideal() == right_r.polynomial_ideal()) == (op == op_EQ)) elif op == op_LE: - if all(f in right_r.gens() for f in self.gens()): # Early abort + if all(f in right_r.gens() for f in self.gens()): # Early abort return True return self.polynomial_ideal(saturate=False) <= right_r.polynomial_ideal() elif op == op_GE: @@ -308,10 +307,10 @@ def apply_coeff_map(self, f, new_base_ring=None, forward_hint=True): else: R = ring.change_ring(new_base_ring) if forward_hint: - apply_to_hint = lambda x, f=f: x.map_coefficients(f) + apply_to_hint = lambda x,f=f: x.map_coefficients(f) else: apply_to_hint = None - return self.apply_map(lambda x, f=f: + return self.apply_map(lambda x,f=f: x.map_coefficients(f, new_base_ring=new_base_ring), new_ring=R, apply_to_hint=apply_to_hint) @@ -429,17 +428,17 @@ def polynomial_ideal(self, saturate=True): l2 = [f.__reduce__()[1][0] for f in gens] hint = self._hint l2 += list(hint.groebner_basis()) - id = Q.ideal(l2) + I = Q.ideal(l2) if not saturate: - self._poly_ideal = id - self._hint = id + self._poly_ideal = I + self._hint = I return Q.ideal(l2) n = P.ngens() - id = id.saturation(Q.ideal([Q.monomial(*((1,) * n))]))[0] - self._poly_ideal = id - self._hint = id + I = I.saturation(Q.ideal([Q.monomial(*((1,) * n))]))[0] + self._poly_ideal = I + self._hint = I self._saturated = True - return id + return I def groebner_basis(self, saturate=True): """ @@ -453,8 +452,8 @@ def groebner_basis(self, saturate=True): sage: (I + J).groebner_basis() (x - 1, y + 1) """ - gb = self.polynomial_ideal(saturate=saturate).groebner_basis() - return tuple(self.ring()(x) for x in gb) + l = self.polynomial_ideal(saturate=saturate).groebner_basis() + return tuple(self.ring()(x) for x in l) def is_one(self): """ @@ -486,10 +485,10 @@ def is_binomial(self, groebner_basis=False): True """ if groebner_basis: - gb = self.groebner_basis() + l = self.groebner_basis() else: - gb = self.gens() - return all(not f or f.number_of_terms() == 2 for f in gb) + l = self.gens() + return all(not f or f.number_of_terms() == 2 for f in l) def associated_primes(self): """ @@ -509,9 +508,9 @@ def associated_primes(self): Ideal (z^2 - y, y*z + 2, y^2 + 2*z) of Multivariate Laurent Polynomial Ring in x, y, z over Rational Field) """ - ap = self.polynomial_ideal(saturate=False).associated_primes() - ap2 = [self.ring().ideal(id.gens(), hint=id) for id in ap] - return tuple(id for id in ap2 if not id.is_one()) + l = self.polynomial_ideal(saturate=False).associated_primes() + l2 = [self.ring().ideal(I.gens(), hint=I) for I in l] + return tuple(I for I in l2 if not I.is_one()) def minimal_associated_primes(self, saturate=False): """ @@ -531,9 +530,9 @@ def minimal_associated_primes(self, saturate=False): Ideal (z^3 + 2, -z^2 + y) of Multivariate Laurent Polynomial Ring in x, y, z over Rational Field) """ - ap = self.polynomial_ideal(saturate=saturate).minimal_associated_primes() - ap2 = [self.ring().ideal(id.gens(), hint=id) for id in ap] - return tuple(id for id in ap2 if not id.is_one()) + l = self.polynomial_ideal(saturate=saturate).minimal_associated_primes() + l2 = [self.ring().ideal(I.gens(), hint=I) for I in l] + return tuple(I for I in l2 if not I.is_one()) def radical(self): """ From 7285ecc55919324e6fb31c15500844b4cd6009fc Mon Sep 17 00:00:00 2001 From: Enrique Artal Date: Sun, 1 Oct 2023 11:00:54 +0200 Subject: [PATCH 27/45] undo format changes for laurent_polynomial_mpair.pyx --- src/sage/rings/polynomial/laurent_polynomial_mpair.pyx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx b/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx index efab709fd44..fe199d281e3 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx +++ b/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx @@ -1241,19 +1241,19 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial): else: return f - cdef int ln = len(x) + cdef int l = len(x) - if ln == 1 and isinstance(x[0], (tuple, list)): + if l == 1 and isinstance(x[0], (tuple, list)): x = x[0] - ln = len(x) + l = len(x) - if ln != self._parent.ngens(): + if l != self._parent.ngens(): raise TypeError("number of arguments does not match the number" " of generators in parent") # Check to make sure that we aren't dividing by zero cdef Py_ssize_t m - for m in range(ln): + for m in range(l): if x[m] == 0: if self.has_inverse_of(m): raise ZeroDivisionError From 61ea6e89a36e01741228e05a5f5d47e4395f64db Mon Sep 17 00:00:00 2001 From: Enrique Artal Date: Sun, 1 Oct 2023 11:02:27 +0200 Subject: [PATCH 28/45] undo format changes for laurent_polynomial_ring.py --- src/sage/rings/polynomial/laurent_polynomial_ring.py | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/sage/rings/polynomial/laurent_polynomial_ring.py b/src/sage/rings/polynomial/laurent_polynomial_ring.py index 4cf0880880e..22d97975cd6 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_ring.py +++ b/src/sage/rings/polynomial/laurent_polynomial_ring.py @@ -77,8 +77,6 @@ def is_LaurentPolynomialRing(R): _cache = {} - - def LaurentPolynomialRing(base_ring, *args, **kwds): r""" Return the globally unique univariate or multivariate Laurent polynomial @@ -254,7 +252,6 @@ def LaurentPolynomialRing(base_ring, *args, **kwds): _cache[R] = P return P - def _split_dict_(D, indices, group_by=None): r""" Split the dictionary ``D`` by ``indices`` and ``group_by``. @@ -330,14 +327,13 @@ def extract(T, indices): if not all(r == 0 for r in extract(K, remaining)): raise SplitDictError('split not possible') G = extract(K, group_by) - In = extract(K, indices) - result.setdefault(G, dict()).update({In: V}) + I = extract(K, indices) + result.setdefault(G, dict()).update({I: V}) if not group_by: return result.popitem()[1] else: return result - def _split_laurent_polynomial_dict_(P, M, d): r""" Helper function for splitting a multivariate Laurent polynomial @@ -399,7 +395,6 @@ def value(d, R): pass return sum(P({k: 1}) * value(v, P) for k, v in D.items()).dict() - def from_fraction_field(L, x): r""" Helper function to construct a Laurent polynomial from an element of its @@ -760,7 +755,7 @@ def _element_constructor_(self, x, mon=None): P = parent(x) if P is self.polynomial_ring(): from sage.rings.polynomial.polydict import ETuple - return self.element_class(self, x, mon=ETuple({}, int(self.ngens()))) + return self.element_class( self, x, mon=ETuple({}, int(self.ngens())) ) elif isinstance(x, Expression): return x.laurent_polynomial(ring=self) From 16ce3c760dc7c12a72d9b3ac1dc2a33b19631c87 Mon Sep 17 00:00:00 2001 From: Enrique Artal Date: Sun, 1 Oct 2023 11:03:57 +0200 Subject: [PATCH 29/45] undo format changes for laurent_polynomial_ring_base.py --- src/sage/rings/polynomial/laurent_polynomial_ring_base.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/polynomial/laurent_polynomial_ring_base.py b/src/sage/rings/polynomial/laurent_polynomial_ring_base.py index 95ea676e0d3..c10cbb219b0 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_ring_base.py +++ b/src/sage/rings/polynomial/laurent_polynomial_ring_base.py @@ -278,7 +278,8 @@ def _coerce_map_from_(self, R): f = self._coerce_map_via([self._R], R) if f is not None: return f - if isinstance(R, LaurentPolynomialRing_generic) and self._R.has_coerce_map_from(R._R): + if (isinstance(R, LaurentPolynomialRing_generic) + and self._R.has_coerce_map_from(R._R)): return self._generic_coerce_map(R) def __eq__(self, right): @@ -479,7 +480,7 @@ def krull_dimension(self): """ raise NotImplementedError - def random_element(self, low_degree=-2, high_degree=2, terms=5, choose_degree=False, *args, **kwds): + def random_element(self, low_degree=-2, high_degree=2, terms=5, choose_degree=False,*args, **kwds): """ EXAMPLES:: From 7bfdabf63b36743b5f43f646dc30681f7c5da921 Mon Sep 17 00:00:00 2001 From: Enrique Artal Date: Sun, 1 Oct 2023 11:09:55 +0200 Subject: [PATCH 30/45] undo format changes for polynomial_element.pyx --- .../rings/polynomial/polynomial_element.pyx | 344 +++++++++--------- 1 file changed, 168 insertions(+), 176 deletions(-) diff --git a/src/sage/rings/polynomial/polynomial_element.pyx b/src/sage/rings/polynomial/polynomial_element.pyx index 06b5ab0eb43..c5a1129aecf 100644 --- a/src/sage/rings/polynomial/polynomial_element.pyx +++ b/src/sage/rings/polynomial/polynomial_element.pyx @@ -213,7 +213,7 @@ cdef class Polynomial(CommutativePolynomial): .. automethod:: _mul_trunc_ """ - def __init__(self, parent, is_gen=False, construct=False): + def __init__(self, parent, is_gen = False, construct=False): """ The following examples illustrate creation of elements of polynomial rings, and some basic arithmetic. @@ -357,7 +357,7 @@ cdef class Polynomial(CommutativePolynomial): from sage.plot.all import plot, point if R.characteristic() == 0: if xmin is None and xmax is None: - (xmin, xmax) = (-1, 1) + (xmin, xmax) = (-1,1) elif xmin is None or xmax is None: raise AttributeError("must give both plot endpoints") return plot(self.__call__, (xmin, xmax), *args, **kwds) @@ -365,10 +365,10 @@ cdef class Polynomial(CommutativePolynomial): if R.is_finite(): v = list(R) v.sort() - w = dict([(v[i], i) for i in range(len(v))]) + w = dict([(v[i],i) for i in range(len(v))]) z = [(i, w[self(v[i])]) for i in range(len(v))] return point(z, *args, **kwds) - raise NotImplementedError("plotting of polynomials over %s not implemented" % R) + raise NotImplementedError("plotting of polynomials over %s not implemented"%R) cpdef _lmul_(self, Element left): """ @@ -832,7 +832,7 @@ cdef class Polynomial(CommutativePolynomial): # is more permissive about its arguments than we are. top = top(*args, **kwds) except TypeError: - if args: # bwd compat: nonsense *keyword* arguments are okay + if args: # bwd compat: nonsense *keyword* arguments are okay raise TypeError("Wrong number of arguments") else: eval_coeffs = True @@ -912,7 +912,7 @@ cdef class Polynomial(CommutativePolynomial): d = pol.degree() if d <= 0 or (isinstance(a, Element) and R.is_exact() and a.is_zero()): - return cst # with the right parent thanks to the above coercion + return cst # with the right parent thanks to the above coercion elif pol._parent is R and a.is_gen(): return pol elif hasattr(a, "_evaluate_polynomial"): @@ -1078,18 +1078,18 @@ cdef class Polynomial(CommutativePolynomial): cdef Py_ssize_t d2 = pol.degree() # Special case constant polynomials - if d1 == -1: # self is the 0 polynomial + if d1 == -1: # self is the 0 polynomial if d2 == -1: - return rich_to_bool(op, 0) # both polynomials are 0 + return rich_to_bool(op, 0) # both polynomials are 0 elif d2 == 0: return richcmp(self._parent._base.zero(), pol.get_unsafe(0), op) - return rich_to_bool_sgn(op, -1) # we have d2 > 0 - elif d1 == 0: # self is a nonzero constant + return rich_to_bool_sgn(op, -1) # we have d2 > 0 + elif d1 == 0: # self is a nonzero constant if d2 == -1: return richcmp(self.get_unsafe(0), pol._parent._base.zero(), op) elif d2 == 0: return richcmp(self.get_unsafe(0), pol.get_unsafe(0), op) - return rich_to_bool_sgn(op, -1) # we have d2 > d1 == 0 + return rich_to_bool_sgn(op, -1) # we have d2 > d1 == 0 # For different degrees, compare the degree if d1 != d2: @@ -1272,12 +1272,12 @@ cdef class Polynomial(CommutativePolynomial): TypeError: unhashable type: 'sage.rings.padics.qadic_flint_CR.qAdicCappedRelativeElement' """ - cdef long result = 0 # store it in a c-int and just let the overflowing additions wrap + cdef long result = 0 # store it in a c-int and just let the overflowing additions wrap cdef long result_mon cdef long c_hash cdef long var_name_hash cdef int i - for i from 0 <= i <= self.degree(): + for i from 0<= i <= self.degree(): if i == 1: # we delay the hashing until now to not waste it on a constant poly var_name_hash = hash(self._parent._names[0]) @@ -1331,7 +1331,7 @@ cdef class Polynomial(CommutativePolynomial): a = im_gens[0] d = self.degree() if d == -1: - return codomain.zero() # Special case: 0 should always coerce to 0 + return codomain.zero() # Special case: 0 should always coerce to 0 if base_map is None: base_map = codomain.coerce_map_from(self.base_ring()) result = base_map(self.get_unsafe(d)) @@ -1661,9 +1661,9 @@ cdef class Polynomial(CommutativePolynomial): for i in range(n+1): for j in range(n-1): M[i+j, j+n] = m[i] - v = vector(R, [R.one()] + [R.zero()]*(2*n-2)) # the constant polynomial 1 + v = vector(R, [R.one()] + [R.zero()]*(2*n-2)) # the constant polynomial 1 if M.is_invertible(): - x = M.solve_right(v) # there has to be a better way to solve + x = M.solve_right(v) # there has to be a better way to solve return a.parent()(list(x)[0:n]) else: raise ValueError("Impossible inverse modulo") @@ -1846,7 +1846,7 @@ cdef class Polynomial(CommutativePolynomial): This is the default implementation that does the multiplication and then truncate! There are custom implementations in several subclasses: - - :meth:`on dense polynomial over integers (via FLINT) ` + - :meth:`on dense polynomial over integers (via FLINT) ` - :meth:`on dense polynomial over Z/nZ (via FLINT) ` @@ -1961,7 +1961,7 @@ cdef class Polynomial(CommutativePolynomial): """ if self.degree() < 0: raise ValueError("square-free decomposition not defined for zero polynomial") - if hasattr(self.base_ring(), '_squarefree_decomposition_univariate_polynomial'): + if hasattr(self.base_ring(),'_squarefree_decomposition_univariate_polynomial'): return self.base_ring()._squarefree_decomposition_univariate_polynomial(self) raise NotImplementedError("square-free decomposition not implemented for this polynomial") @@ -2188,11 +2188,11 @@ cdef class Polynomial(CommutativePolynomial): raise ValueError("ring must be an extension of the base ring") if not (ring.is_field() and ring.is_finite()): raise NotImplementedError - allowed_deg_mult = Integer(ring.factored_order()[0][1]) # generally it will be the quotient of this by the degree of the base ring. + allowed_deg_mult = Integer(ring.factored_order()[0][1]) # generally it will be the quotient of this by the degree of the base ring. if degree is None: x = self._parent.gen() if allowed_deg_mult == 1: - xq = pow(x, q, self) + xq = pow(x,q,self) self = self.gcd(xq-x) degree = -1 if self.degree() == 0: @@ -2210,7 +2210,7 @@ cdef class Polynomial(CommutativePolynomial): break while d < allowed_deg_mult: d = d+1 - xq = pow(xq, q, self) + xq = pow(xq,q,self) if d.divides(allowed_deg_mult): break A = self.gcd(xq-x) @@ -2234,8 +2234,8 @@ cdef class Polynomial(CommutativePolynomial): break while True: # we waste a little effort here in computing the xq again. - d = d + 1 - xq = pow(xq, q, self) + d = d+1 + xq = pow(xq,q,self) if allowed_deg_mult.divides(d): break A = self.gcd(xq-x) @@ -2257,7 +2257,7 @@ cdef class Polynomial(CommutativePolynomial): raise ValueError("no roots D %s" % self) break d = d+1 - xq = pow(xq, q, self) + xq = pow(xq,q,self) if d == degree: break A = self.gcd(xq-x) @@ -2273,13 +2273,13 @@ cdef class Polynomial(CommutativePolynomial): if degree == 1: ring = self.base_ring() else: - ring = self.base_ring().extension(degree) # this won't work yet. + ring = self.base_ring().extension(degree) # this won't work yet. # now self has only roots of degree ``degree``. # for now, we only implement the Cantor-Zassenhaus split k = self.degree() // degree if k == 1: try: - return self.roots(ring, multiplicities=False)[0] # is there something better to do here? + return self.roots(ring, multiplicities=False)[0] # is there something better to do here? except IndexError: raise ValueError("no roots F %s" % self) if q % 2 == 0: @@ -2289,8 +2289,8 @@ cdef class Polynomial(CommutativePolynomial): continue T = T.monic() C = T - for i in range(degree - 1): - C = T + pow(C, q, self) + for i in range(degree-1): + C = T + pow(C,q,self) h = self.gcd(C) hd = h.degree() if hd != 0 and hd != self.degree(): @@ -2536,7 +2536,7 @@ cdef class Polynomial(CommutativePolynomial): else: v = [R.zero()]*right + [R.one()] return self.parent()(v, check=False) - if right > 20: # no gain below + if right > 20: # no gain below try: p = self.parent().characteristic() except (AttributeError, NotImplementedError): @@ -2557,7 +2557,7 @@ cdef class Polynomial(CommutativePolynomial): q, r = q.quo_rem(p) if r != 0: if sparse: - tmp = self.parent()({e * k: d[k] ** e for k in d}) + tmp = self.parent()({e*k : d[k]**e for k in d}) else: tmp = [0] * (e * len(c) - e + 1) for i in range(len(c)): @@ -2728,19 +2728,19 @@ cdef class Polynomial(CommutativePolynomial): if y.find("-") == 0: y = y[1:] if not atomic_repr and n > 0 and (y.find("+") != -1 or y.find("-") != -1): - x = "(%s)" % x + x = "(%s)"%x if n > 1: - var = "*%s^%s" % (name, n) - elif n == 1: - var = "*%s" % name + var = "*%s^%s"%(name,n) + elif n==1: + var = "*%s"%name else: var = "" sbuf.write(x) sbuf.write(var) s = sbuf.getvalue() s = s.replace(" + -", " - ") - s = re.sub(r' 1(\.0+)?\*', ' ', s) - s = re.sub(r' -1(\.0+)?\*', ' -', s) + s = re.sub(r' 1(\.0+)?\*',' ', s) + s = re.sub(r' -1(\.0+)?\*',' -', s) if s == " ": return "0" return s[1:] @@ -2813,7 +2813,7 @@ cdef class Polynomial(CommutativePolynomial): x = "\\left(%s\\right)" % x if n > 1: var = "|%s^{%s}" % (name, n) - elif n == 1: + elif n==1: var = "|%s" % name else: var = "" @@ -3150,12 +3150,12 @@ cdef class Polynomial(CommutativePolynomial): - Didier Deshommes (2006-05-25) """ - return self._parent(polynomial_fateman._mul_fateman_mul(self, right)) + return self._parent(polynomial_fateman._mul_fateman_mul(self,right)) @cython.boundscheck(False) @cython.wraparound(False) @cython.overflowcheck(False) - def _mul_karatsuba(self, right, K_threshold=None): + def _mul_karatsuba(self, right, K_threshold = None): r""" Compute the product of two polynomials using the Karatsuba divide and conquer multiplication algorithm. This is only used over a @@ -3328,8 +3328,8 @@ cdef class Polynomial(CommutativePolynomial): if n <= K_threshold or m <= K_threshold: return self._new_generic(do_schoolbook_product(f, g, -1)) if n == m: - return self._new_generic(do_karatsuba(f, g, K_threshold, 0, 0, n)) - return self._new_generic(do_karatsuba_different_size(f, g, K_threshold)) + return self._new_generic(do_karatsuba(f,g, K_threshold, 0, 0, n)) + return self._new_generic(do_karatsuba_different_size(f,g, K_threshold)) @cython.boundscheck(False) @cython.wraparound(False) @@ -3487,7 +3487,7 @@ cdef class Polynomial(CommutativePolynomial): if var not in variables: x = base_ring(self) if base_ring else self const_ix = ETuple((0,)*len(variables)) - return {const_ix: x} + return { const_ix: x } cdef tuple prev_variables = variables[:variables.index(var)] const_ix = ETuple((0,)*len(prev_variables)) @@ -3509,7 +3509,7 @@ cdef class Polynomial(CommutativePolynomial): cdef dict D = {} cdef tuple leftovers = (0,) * (len(variables) - len(prev_variables) - 1) for k in range(len(mpolys)): - for i, a in mpolys[k].iteritems(): + for i,a in mpolys[k].iteritems(): j = ETuple((k,) + leftovers) D[i + j] = a @@ -3680,7 +3680,7 @@ cdef class Polynomial(CommutativePolynomial): for y in x: d = d.lcm(y.denominator()) return d - except (AttributeError): + except(AttributeError): return self.base_ring().one() def numerator(self): @@ -3951,7 +3951,7 @@ cdef class Polynomial(CommutativePolynomial): """ return [self.diff()] - def integral(self, var=None): + def integral(self,var=None): """ Return the integral of this polynomial. @@ -4571,39 +4571,39 @@ cdef class Polynomial(CommutativePolynomial): # PARI for smaller degree over other rings besides Z, and use # NTL in general. # A remark from Bill Hart (2007-09-25) about the above observation: - # # NTL uses the Berlekamp-Zassenhaus method with van Hoeij's improvements. - # # But so does Magma since about Jul 2001. - # # - # # But here's the kicker. PARI also uses this algorithm. Even Maple uses - # # it! - # # - # # NTL's LLL algorithms are extremely well developed (van Hoeij uses - # # LLL). There is also a possible speed difference in whether one uses - # # quadratic convergence or not in the Hensel lift. But the right choice - # # is not always what one thinks. - # # - # # But more than likely NTL is just better for large problems because - # # Victor Shoup was very careful with the choice of strategies and - # # parameters he used. Paul Zimmerman supplied him with a pile of - # # polynomials to factor for comparison purposes and these seem to have - # # been used to tune the algorithm for a wide range of inputs, including - # # cases that van Hoeij's algorithm doesn't usually like. - # # - # # If you have a bound on the coefficients of the factors, one can surely - # # do better than a generic implementation, but probably not much better - # # if there are many factors. - # # - - # # HUGE TODO, refactor the code below here such that this method will - # # have as only the following code - # # - # # R = self.parent().base_ring() - # # return R._factor_univariate_polynomial(self) - # # - # # in this way we can move the specific logic of factoring to the - # # self.parent().base_ring() and get rid of all the ugly - # # is_SomeType(R) checks and get way nicer structured code - # # 200 lines of spaghetti code is just way to much! + ## NTL uses the Berlekamp-Zassenhaus method with van Hoeij's improvements. + ## But so does Magma since about Jul 2001. + ## + ## But here's the kicker. PARI also uses this algorithm. Even Maple uses + ## it! + ## + ## NTL's LLL algorithms are extremely well developed (van Hoeij uses + ## LLL). There is also a possible speed difference in whether one uses + ## quadratic convergence or not in the Hensel lift. But the right choice + ## is not always what one thinks. + ## + ## But more than likely NTL is just better for large problems because + ## Victor Shoup was very careful with the choice of strategies and + ## parameters he used. Paul Zimmerman supplied him with a pile of + ## polynomials to factor for comparison purposes and these seem to have + ## been used to tune the algorithm for a wide range of inputs, including + ## cases that van Hoeij's algorithm doesn't usually like. + ## + ## If you have a bound on the coefficients of the factors, one can surely + ## do better than a generic implementation, but probably not much better + ## if there are many factors. + ## + + ## HUGE TODO, refactor the code below here such that this method will + ## have as only the following code + ## + ## R = self.parent().base_ring() + ## return R._factor_univariate_polynomial(self) + ## + ## in this way we can move the specific logic of factoring to the + ## self.parent().base_ring() and get rid of all the ugly + ## is_SomeType(R) checks and get way nicer structured code + ## 200 lines of spaghetti code is just way to much! if self.degree() < 0: raise ArithmeticError("factorization of {!r} is not defined".format(self)) @@ -4617,7 +4617,7 @@ cdef class Polynomial(CommutativePolynomial): try: F = flatten(self).factor(**kwargs) unflatten = flatten.section() - return Factorization(((unflatten(f), m) for (f, m) in F), unit=F.unit()) + return Factorization(((unflatten(f),m) for (f,m) in F), unit = F.unit()) except NotImplementedError: pass @@ -4650,7 +4650,7 @@ cdef class Polynomial(CommutativePolynomial): # This was copied from the general multivariate implementation try: if R.is_finite(): - if R.characteristic() > 1 << 29: + if R.characteristic() > 1<<29: raise NotImplementedError("Factorization of multivariate polynomials over prime fields with characteristic > 2^29 is not implemented.") P = self._parent @@ -4658,8 +4658,8 @@ cdef class Polynomial(CommutativePolynomial): S = self._singular_().factorize() factors = S[1] exponents = S[2] - v = sorted([(P(factors[i + 1]), - sage.rings.integer.Integer(exponents[i + 1])) + v = sorted([( P(factors[i+1]), + sage.rings.integer.Integer(exponents[i+1])) for i in range(len(factors))]) unit = P.one() for i in range(len(v)): @@ -4936,7 +4936,7 @@ cdef class Polynomial(CommutativePolynomial): raise NotImplementedError("splitting_field() is only implemented over number fields and finite fields") - def pseudo_quo_rem(self, other): + def pseudo_quo_rem(self,other): r""" Compute the pseudo-division of two polynomials. @@ -4996,7 +4996,7 @@ cdef class Polynomial(CommutativePolynomial): e -= 1 q = d**e - return (q * Q, q * R) + return (q*Q,q*R) @coerce_binop def gcd(self, other): @@ -5089,7 +5089,7 @@ cdef class Polynomial(CommutativePolynomial): try: doit = self._parent._base._gcd_univariate_polynomial except AttributeError: - raise NotImplementedError("%s does not provide a gcd implementation for univariate polynomials" % self._parent._base) + raise NotImplementedError("%s does not provide a gcd implementation for univariate polynomials"%self._parent._base) else: return doit(self, other) @@ -5462,7 +5462,7 @@ cdef class Polynomial(CommutativePolynomial): return R.fraction_field()[self._parent.variable_name()].quotient(self, names) - def sylvester_matrix(self, right, variable=None): + def sylvester_matrix(self, right, variable = None): """ Return the Sylvester matrix of ``self`` and ``right``. @@ -5588,10 +5588,10 @@ cdef class Polynomial(CommutativePolynomial): # sylvester_matrix() in multi_polynomial.pyx. if self._parent != right.parent(): - a, b = coercion_model.canonical_coercion(self, right) + a, b = coercion_model.canonical_coercion(self,right) variable = a.parent()(self.variables()[0]) - # We add the variable to cover the case that right is a multivariate - # polynomial + #We add the variable to cover the case that right is a multivariate + #polynomial return a.sylvester_matrix(b, variable) if variable: @@ -6446,18 +6446,13 @@ cdef class Polynomial(CommutativePolynomial): e = self.exponents() c = self.coefficients() - if len(e) == 0: - return [] + if len(e) == 0: return [] if len(e) == 1: - if e[0] == 0: - return [] - else: - return [(infinity.infinity, e[0])] + if e[0] == 0: return [] + else: return [(infinity.infinity, e[0])] - if e[0] == 0: - slopes = [] - else: - slopes = [(infinity.infinity, e[0])] + if e[0] == 0: slopes = [] + else: slopes = [(infinity.infinity, e[0])] points = [(e[0], c[0].valuation(p)), (e[1], c[1].valuation(p))] slopes.append((-(c[1].valuation(p)-c[0].valuation(p))/(e[1] - e[0]), e[1]-e[0])) @@ -6468,8 +6463,8 @@ cdef class Polynomial(CommutativePolynomial): slopes = slopes[:-1] points = points[:-1] s = -(v-points[-1][1])/(e[i]-points[-1][0]) - slopes.append((s, e[i] - points[-1][0])) - points.append((e[i], v)) + slopes.append((s,e[i]-points[-1][0])) + points.append((e[i],v)) return slopes @@ -6513,7 +6508,7 @@ cdef class Polynomial(CommutativePolynomial): if m != n or p[n] != q[n]: continue alpha = (q[n-1] - p[n-1])/(n*p[n]) - if alpha.is_integer(): # ZZ() might work for non-integers... + if alpha.is_integer(): # ZZ() might work for non-integers... alpha = ZZ(alpha) else: continue @@ -7183,7 +7178,7 @@ cdef class Polynomial(CommutativePolynomial): if Sf is not QQ or (d1 <= N and d2 <= N): algorithm = "resultant" else: - c = d1*sum(bool(p1[i]) for i in range(d1 + 1)) * \ + c = d1*sum(bool(p1[i]) for i in range(d1 + 1))*\ d2*sum(bool(p2[i]) for i in range(d2 + 1)) if c <= N**4: algorithm = "resultant" @@ -7596,7 +7591,8 @@ cdef class Polynomial(CommutativePolynomial): return self # return 0 n = self.degree() base_ring = self._parent.base_ring() - if (is_MPolynomialRing(base_ring) or is_PowerSeriesRing(base_ring)): + if (is_MPolynomialRing(base_ring) or + is_PowerSeriesRing(base_ring)): # It is often cheaper to compute discriminant of simple # multivariate polynomial and substitute the real # coefficients into that result (see #16014). @@ -7605,13 +7601,13 @@ cdef class Polynomial(CommutativePolynomial): k = d.degree() r = n % 4 - u = -1 # (-1)**(n*(n-1)/2) + u = -1 # (-1)**(n*(n-1)/2) if r == 0 or r == 1: u = 1 try: an = self.get_coeff_c(n)**(n - k - 2) except ZeroDivisionError: - assert (n-k-2 == -1) + assert(n-k-2 == -1) # Rather than dividing the resultant by the leading coefficient, # we alter the Sylvester matrix (see #11782). mat = self.sylvester_matrix(d) @@ -7660,14 +7656,14 @@ cdef class Polynomial(CommutativePolynomial): if degree is not None: d = degree if d != degree: - raise ValueError("degree argument must be a non-negative integer, got %s" % (degree)) + raise ValueError("degree argument must be a non-negative integer, got %s"%(degree)) if len(v) < degree+1: v.reverse() v = [self.base_ring().zero()]*(degree+1-len(v)) + v elif len(v) > degree+1: v = v[:degree+1] v.reverse() - else: # len(v) == degree + 1 + else: # len(v) == degree + 1 v.reverse() else: v.reverse() @@ -8422,9 +8418,9 @@ cdef class Polynomial(CommutativePolynomial): sage.rings.abc.RealDoubleField, sage.rings.abc.ComplexDoubleField)) output_fp = isinstance(L, (sage.rings.abc.RealField, - sage.rings.abc.ComplexField, - sage.rings.abc.RealDoubleField, - sage.rings.abc.ComplexDoubleField)) + sage.rings.abc.ComplexField, + sage.rings.abc.RealDoubleField, + sage.rings.abc.ComplexDoubleField)) input_complex = isinstance(K, (sage.rings.abc.ComplexField, sage.rings.abc.ComplexDoubleField)) output_complex = isinstance(L, (sage.rings.abc.ComplexField, sage.rings.abc.ComplexDoubleField)) input_gaussian = (isinstance(K, sage.rings.abc.NumberField_quadratic) @@ -8507,20 +8503,20 @@ cdef class Polynomial(CommutativePolynomial): from sage.symbolic.constants import I coeffs = self.list() D = coeffs[1]*coeffs[1] - 4*coeffs[0]*coeffs[2] - l0 = None + l = None if D > 0: - l0 = [((-coeffs[1] - sqrt(D)) / 2 / coeffs[2], 1), - ((-coeffs[1] + sqrt(D)) / 2 / coeffs[2], 1)] + l = [((-coeffs[1]-sqrt(D))/2/coeffs[2], 1), + ((-coeffs[1]+sqrt(D))/2/coeffs[2], 1)] elif D < 0: - l0 = [((-coeffs[1] - I * sqrt(-D)) / 2 / coeffs[2], 1), - ((-coeffs[1] + I * sqrt(-D)) / 2 / coeffs[2], 1)] + l = [((-coeffs[1]-I*sqrt(-D))/2/coeffs[2], 1), + ((-coeffs[1]+I*sqrt(-D))/2/coeffs[2], 1)] elif D == 0: - l0 = [(-coeffs[1] / 2 / coeffs[2], 2)] - if l0: + l = [(-coeffs[1]/2/coeffs[2], 2)] + if l: if multiplicities: - return l0 + return l else: - return [val for val, m in l0] + return [val for val,m in l] from sage.symbolic.ring import SR vname = 'do_not_use_this_name_in_a_polynomial_coefficient' var = SR(vname) @@ -8538,7 +8534,7 @@ cdef class Polynomial(CommutativePolynomial): # and complex root isolation and for p-adic factorization if (is_IntegerRing(K) or is_RationalField(K) or isinstance(K, sage.rings.abc.AlgebraicRealField)) and \ - isinstance(L, (sage.rings.abc.AlgebraicRealField, sage.rings.abc.RealIntervalField)): + isinstance(L, (sage.rings.abc.AlgebraicRealField, sage.rings.abc.RealIntervalField)): from sage.rings.polynomial.real_roots import real_roots @@ -8568,7 +8564,7 @@ cdef class Polynomial(CommutativePolynomial): if (is_IntegerRing(K) or is_RationalField(K) or isinstance(K, sage.rings.abc.AlgebraicField_common) or input_gaussian) and \ - isinstance(L, (sage.rings.abc.ComplexIntervalField, sage.rings.abc.AlgebraicField_common)): + isinstance(L, (sage.rings.abc.ComplexIntervalField, sage.rings.abc.AlgebraicField_common)): from sage.rings.polynomial.complex_roots import complex_roots @@ -8686,7 +8682,7 @@ cdef class Polynomial(CommutativePolynomial): pass else: if multiplicities: - seq.append((rt, fac[1])) + seq.append((rt,fac[1])) else: seq.append(rt) return seq @@ -9092,7 +9088,7 @@ cdef class Polynomial(CommutativePolynomial): coeffs = [] m = Q.degree() // 2 for i in reversed(range(m + 1)): - coeffs.insert(0, Q[2*i]) # Note: degree of Q may be less than 2*i + coeffs.insert(0, Q[2*i]) # Note: degree of Q may be less than 2*i Q = (Q % (x**2 + q)**i) // x return S(coeffs), cofactor, q @@ -9298,7 +9294,7 @@ cdef class Polynomial(CommutativePolynomial): if hasattr(self.base_ring(), '_xgcd_univariate_polynomial'): return self.base_ring()._xgcd_univariate_polynomial(self, other) else: - raise NotImplementedError("%s does not provide an xgcd implementation for univariate polynomials" % self.base_ring()) + raise NotImplementedError("%s does not provide an xgcd implementation for univariate polynomials"%self.base_ring()) def rational_reconstruction(self, m, n_deg=None, d_deg=None): r""" @@ -9463,9 +9459,9 @@ cdef class Polynomial(CommutativePolynomial): sF = Pf(self) mF = Pf(m) n, d = sF.rational_reconstruction(mF, n_deg, d_deg) - lc = lcm([n.denominator(), d.denominator()]) - n *= lc - d *= lc + l = lcm([n.denominator(), d.denominator()]) + n *= l + d *= l return P(n), P(d) # n and d are unique if m.degree() > (n.degree() + d.degree()) @@ -9476,9 +9472,9 @@ cdef class Polynomial(CommutativePolynomial): if n_deg < 0 or d_deg < 0: raise ValueError("the degree bounds " - "n_deg and d_deg should be positive") + "n_deg and d_deg should be positive") - # XGCD until degree the degree of t1 surpasses the degree of n + #XGCD until degree the degree of t1 surpasses the degree of n s0 = P(0) t0 = P(1) s1 = P(m) @@ -9587,15 +9583,15 @@ cdef class Polynomial(CommutativePolynomial): _p = self._parent.coerce(p) elif p is infinity.infinity: return -self.degree() - elif is_Ideal(p) and p.ring() is self._parent: # eventually need to handle fractional ideals in the fraction field - if self._parent.base_ring().is_field(): # common case + elif is_Ideal(p) and p.ring() is self._parent: # eventually need to handle fractional ideals in the fraction field + if self._parent.base_ring().is_field(): # common case _p = p.gen() else: raise NotImplementedError else: from sage.rings.fraction_field import is_FractionField if is_FractionField(p.parent()) and self._parent.has_coerce_map_from(p.parent().ring()): - _p = self._parent.coerce(p.parent().ring()(p)) # here we require that p be integral. + _p = self._parent.coerce(p.parent().ring()(p)) # here we require that p be integral. else: raise TypeError("The polynomial, p, must have the same parent as self.") @@ -10850,13 +10846,13 @@ cdef class Polynomial(CommutativePolynomial): elif n == 1 or self.is_zero() or self.is_one(): return self elif self.degree() % n: - raise ValueError("not a %s power" % Integer(n).ordinal_str()) - elif self.get_unsafe(0).is_zero(): # We know that self is not 0, so it must have degree >= 0 + raise ValueError("not a %s power"%Integer(n).ordinal_str()) + elif self.get_unsafe(0).is_zero(): # We know that self is not 0, so it must have degree >= 0 # p = x^k q # p^(1/n) = x^(k/n) q^(1/n) i = self.valuation() - if i % n: - raise ValueError("not a %s power" % Integer(n).ordinal_str()) + if i%n: + raise ValueError("not a %s power"%Integer(n).ordinal_str()) return (self >> i).nth_root(n) << (i // n) if self.get_unsafe(0).is_one(): @@ -10875,7 +10871,7 @@ cdef class Polynomial(CommutativePolynomial): if q**n == p: return S(q) else: - raise ValueError("not a %s power" % Integer(n).ordinal_str()) + raise ValueError("not a %s power"%Integer(n).ordinal_str()) def _nth_root_series(self, long n, long prec, start=None): r""" @@ -10968,12 +10964,12 @@ cdef class Polynomial(CommutativePolynomial): raise ValueError("n (={}) must be positive".format(m)) elif m.is_one() or self.is_zero() or self.is_one(): return self - elif self.get_unsafe(0).is_zero(): # we know that self is not zero, so the degree >= 0 + elif self.get_unsafe(0).is_zero(): # we know that self is not zero, so the degree >= 0 # p = x^i q # p^(1/m) = x^(i/m) q^(1/m) i = self.valuation() if i % m: - raise ValueError("not a %s power" % m.ordinal_str()) + raise ValueError("not a %s power"%m.ordinal_str()) return (self >> i)._nth_root_series(m, prec - i // m) << (i // m) else: c = R.characteristic() @@ -10985,7 +10981,7 @@ cdef class Polynomial(CommutativePolynomial): for i in range(self.degree()+1): if self.get_unsafe(i): if i % cc: - raise ValueError("not a %s power" % m.ordinal_str()) + raise ValueError("not a %s power"%m.ordinal_str()) ans[i//cc] = self.get_unsafe(i).nth_root(cc) p = self._parent(ans) m = m // cc @@ -11081,16 +11077,12 @@ cdef class Polynomial(CommutativePolynomial): if not self.base_ring().is_integral_domain(): raise NotImplementedError("divisibility test only implemented for polynomials over an integral domain") - if p.is_zero(): - return True # everything divides 0 - if self.is_zero(): - return False # 0 only divides 0 + if p.is_zero(): return True # everything divides 0 + if self.is_zero(): return False # 0 only divides 0 try: - if self.is_unit(): - return True # units divide everything + if self.is_unit(): return True # units divide everything except NotImplementedError: - if self.is_one(): - return True # if is_unit is not implemented + if self.is_one(): return True # if is_unit is not implemented if self.degree() > p.degree(): return False @@ -11142,9 +11134,10 @@ cdef class Polynomial(CommutativePolynomial): raise ValueError("either the dictionary or the specialization must be provided") else: from sage.rings.polynomial.flatten import SpecializationMorphism - phi = SpecializationMorphism(self._parent, D) + phi = SpecializationMorphism(self._parent,D) return phi(self) + def _log_series(self, long n): r""" Return the power series expansion of logarithm of this polynomial, @@ -11342,10 +11335,10 @@ cdef list do_schoolbook_product(list x, list y, Py_ssize_t deg): return y elif d1 == 0: c = x[0] - return [c * a for a in y[:deg]] # beware of noncommutative rings + return [c*a for a in y[:deg]] # beware of noncommutative rings elif d2 == 0: c = y[0] - return [a * c for a in x[:deg]] # beware of noncommutative rings + return [a*c for a in x[:deg]] # beware of noncommutative rings coeffs = [None]*deg for k in range(deg): start = 0 if k <= d2 else k-d2 # max(0, k-d2) @@ -11391,10 +11384,10 @@ cdef list do_karatsuba_different_size(list left, list right, Py_ssize_t K_thresh return [] if n == 1: c = left[0] - return [c * a for a in right] + return [c*a for a in right] if m == 1: c = right[0] - return [a * c for a in left] # beware of noncommutative rings + return [a*c for a in left] # beware of noncommutative rings if n <= K_threshold or m <= K_threshold: return do_schoolbook_product(left, right, -1) if n == m: @@ -11441,7 +11434,7 @@ cdef list do_karatsuba_different_size(list left, list right, Py_ssize_t K_thresh @cython.boundscheck(False) @cython.wraparound(False) @cython.overflowcheck(False) -cdef list do_karatsuba(list left, list right, Py_ssize_t K_threshold, Py_ssize_t start_l, Py_ssize_t start_r, Py_ssize_t num_elts): +cdef list do_karatsuba(list left, list right, Py_ssize_t K_threshold,Py_ssize_t start_l, Py_ssize_t start_r,Py_ssize_t num_elts): """ Core routine for Karatsuba multiplication. This function works for two polynomials of the same degree. @@ -11496,8 +11489,8 @@ cdef list do_karatsuba(list left, list right, Py_ssize_t K_threshold, Py_ssize_t d = right[start_r] c = right[start_r+1] return [b*d, a*d+b*c, a*c] - return do_schoolbook_product(left[start_l:start_l + num_elts], - right[start_r:start_r + num_elts], -1) + return do_schoolbook_product(left[start_l:start_l+num_elts], + right[start_r:start_r+num_elts], -1) if num_elts == 2: # beware of noncommutative rings b = left[start_l] @@ -11531,7 +11524,7 @@ cdef list do_karatsuba(list left, list right, Py_ssize_t K_threshold, Py_ssize_t bd[e+i] = bd[e+i] + tt1[i] bd.append(tt1[e-1]) for i from 0 <= i < lenac -e: - ac[i] = ac[i] + tt1[e + i] + ac[i] = ac[i] + tt1[e+i] return bd + ac @@ -11610,10 +11603,10 @@ cdef class Polynomial_generic_dense(Polynomial): check = 0 elif not isinstance(x, (list, tuple)): # We trust that the element constructors do not send x=0 - # if x: +# if x: x = [x] # constant polynomials - # else: - # x = [] # zero polynomial +# else: +# x = [] # zero polynomial if check: self._coeffs = [R(z, **kwds) for z in x] self._normalize() @@ -11646,9 +11639,9 @@ cdef class Polynomial_generic_dense(Polynomial): Univariate Polynomial Ring in x over Univariate Polynomial Ring in y over Rational Field """ if a: - return self._new_c([a], P) + return self._new_c([a],P) else: - return self._new_c([], P) + return self._new_c([],P) def __reduce__(self): """ @@ -11717,7 +11710,7 @@ cdef class Polynomial_generic_dense(Polynomial): for i in range(ell): v[i+d] = c * x[i] cdef Polynomial_generic_dense res = self._new_c(v, self._parent) - # if not v[len(v)-1]: + #if not v[len(v)-1]: # "normalize" checks this anyway... res._normalize() return res @@ -11860,7 +11853,7 @@ cdef class Polynomial_generic_dense(Polynomial): 2*y*x^3 + (y + 3)*x^2 + (-2*y + 1)*x + 1 """ cdef Polynomial_generic_dense res - cdef Py_ssize_t check = 0, i, min + cdef Py_ssize_t check=0, i, min x = (self)._coeffs y = (right)._coeffs if len(x) > len(y): @@ -11881,7 +11874,7 @@ cdef class Polynomial_generic_dense(Polynomial): cpdef _sub_(self, right): cdef Polynomial_generic_dense res - cdef Py_ssize_t check = 0, i, min + cdef Py_ssize_t check=0, i, min x = (self)._coeffs y = (right)._coeffs if len(x) > len(y): @@ -11907,7 +11900,7 @@ cdef class Polynomial_generic_dense(Polynomial): c = (self._coeffs[0])._parent.coerce(c) v = [c * a for a in self._coeffs] cdef Polynomial_generic_dense res = self._new_c(v, self._parent) - # if not v[len(v)-1]: + #if not v[len(v)-1]: # "normalize" checks this anyway... res._normalize() return res @@ -11919,7 +11912,7 @@ cdef class Polynomial_generic_dense(Polynomial): c = (self._coeffs[0])._parent.coerce(c) v = [a * c for a in self._coeffs] cdef Polynomial_generic_dense res = self._new_c(v, self._parent) - # if not v[len(v)-1]: + #if not v[len(v)-1]: # "normalize" checks this anyway... res._normalize() return res @@ -12128,7 +12121,7 @@ cdef class Polynomial_generic_dense(Polynomial): quo.append(q) quo.reverse() - return self._new_c(quo, self._parent), self._new_c(x, self._parent)._inplace_truncate(n-1) + return self._new_c(quo,self._parent), self._new_c(x,self._parent)._inplace_truncate(n-1) cpdef Polynomial truncate(self, long n): r""" @@ -12157,10 +12150,10 @@ cdef class Polynomial_generic_dense(Polynomial): sage: type(f) """ - ln = len(self._coeffs) - if n > ln: - n = ln - while n > 0 and not self._coeffs[n - 1]: + l = len(self._coeffs) + if n > l: + n = l + while n > 0 and not self._coeffs[n-1]: n -= 1 return self._new_c(self._coeffs[:n], self._parent) @@ -12171,7 +12164,6 @@ cdef class Polynomial_generic_dense(Polynomial): self._coeffs = self._coeffs[:n] return self - def make_generic_polynomial(parent, coeffs): return parent(coeffs) @@ -12213,7 +12205,7 @@ def universal_discriminant(n): pr1 = PolynomialRing(ZZ, n + 1, 'a') pr2 = PolynomialRing(pr1, 'x') p = pr2(list(pr1.gens())) - return (1 - (n & 2)) * p.resultant(p.derivative()) // pr1.gen(n) + return (1 - (n&2))*p.resultant(p.derivative())//pr1.gen(n) cpdef Polynomial generic_power_trunc(Polynomial p, Integer n, long prec): @@ -12309,7 +12301,7 @@ cpdef list _dict_to_list(dict x, zero): return [] n = max(x.keys()) cdef list v - if isinstance(n, tuple): # a mpoly dict + if isinstance(n, tuple): # a mpoly dict n = n[0] v = [zero] * (n+1) for i, z in x.iteritems(): From 5f215beed284d864663931cd95bdd067918c832c Mon Sep 17 00:00:00 2001 From: Enrique Artal Date: Sun, 1 Oct 2023 11:32:17 +0200 Subject: [PATCH 31/45] undo format changes for matrix_space.py --- src/sage/matrix/matrix_space.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/sage/matrix/matrix_space.py b/src/sage/matrix/matrix_space.py index 04ab6b138a2..905b6fcc779 100644 --- a/src/sage/matrix/matrix_space.py +++ b/src/sage/matrix/matrix_space.py @@ -802,7 +802,7 @@ def transposed(self): Full MatrixSpace of 3 by 2 dense matrices over Integer Ring """ return MatrixSpace(self._base, self.__ncols, self.__nrows, - self.__is_sparse, self.Element) + self.__is_sparse, self.Element) @lazy_attribute def _copy_zero(self): @@ -2186,7 +2186,7 @@ def row_space(self): return self.__row_space except AttributeError: self.__row_space = sage.modules.free_module.FreeModule(self.base_ring(), - self.ncols(), sparse=self.is_sparse()) + self.ncols(), sparse=self.is_sparse()) return self.__row_space def column_space(self): @@ -2204,7 +2204,7 @@ def column_space(self): return self.__column_space except AttributeError: self.__column_space = sage.modules.free_module.FreeModule(self.base_ring(), self.nrows(), - sparse=self.is_sparse()) + sparse=self.is_sparse()) return self.__column_space def random_element(self, density=None, *args, **kwds): @@ -2262,10 +2262,10 @@ def random_element(self, density=None, *args, **kwds): Z = self.zero_matrix().__copy__() if density is None: Z.randomize(density=float(1), nonzero=kwds.pop('nonzero', False), - *args, **kwds) + *args, **kwds) else: Z.randomize(density=density, nonzero=kwds.pop('nonzero', True), - *args, **kwds) + *args, **kwds) return Z def _an_element_(self): @@ -2589,13 +2589,13 @@ def _MatrixSpace_ZZ_2x2(): register_unpickle_override('sage.matrix.matrix_modn_dense', - 'Matrix_modn_dense', Matrix_modn_dense_double) + 'Matrix_modn_dense', Matrix_modn_dense_double) register_unpickle_override('sage.matrix.matrix_integer_2x2', - 'Matrix_integer_2x2', Matrix_integer_dense) + 'Matrix_integer_2x2', Matrix_integer_dense) register_unpickle_override('sage.matrix.matrix_integer_2x2', - 'MatrixSpace_ZZ_2x2_class', MatrixSpace) + 'MatrixSpace_ZZ_2x2_class', MatrixSpace) register_unpickle_override('sage.matrix.matrix_integer_2x2', - 'MatrixSpace_ZZ_2x2', _MatrixSpace_ZZ_2x2) + 'MatrixSpace_ZZ_2x2', _MatrixSpace_ZZ_2x2) lazy_import('sage.matrix.matrix_gf2e_dense', 'unpickle_matrix_gf2e_dense_v0') register_unpickle_override('sage.matrix.matrix_mod2e_dense', - 'unpickle_matrix_mod2e_dense_v0', unpickle_matrix_gf2e_dense_v0) + 'unpickle_matrix_mod2e_dense_v0', unpickle_matrix_gf2e_dense_v0) From 2a244659f345684656ac77fdee70f70adc45b33d Mon Sep 17 00:00:00 2001 From: Enrique Artal Date: Mon, 9 Oct 2023 20:07:00 -0600 Subject: [PATCH 32/45] after first review --- .../matrix_laurent_mpolynomial_dense.pyx | 7 ++----- .../rings/polynomial/laurent_polynomial.pyx | 21 ++++++++++++------- .../polynomial/laurent_polynomial_ideal.py | 10 +++++++++ .../polynomial/laurent_polynomial_mpair.pyx | 7 ++++++- 4 files changed, 31 insertions(+), 14 deletions(-) diff --git a/src/sage/matrix/matrix_laurent_mpolynomial_dense.pyx b/src/sage/matrix/matrix_laurent_mpolynomial_dense.pyx index 3f0c1e968f2..31ccba6c5d7 100644 --- a/src/sage/matrix/matrix_laurent_mpolynomial_dense.pyx +++ b/src/sage/matrix/matrix_laurent_mpolynomial_dense.pyx @@ -1,12 +1,9 @@ """ -Dense matrices over multivariate polynomials over fields - -This implementation inherits from Matrix_generic_dense, i.e. it is not -optimized for speed only some methods were added. +Dense matrices over multivariate polynomials over fields. AUTHOR: -* Enrique Artal +- Enrique Artal (2023-??): initial version """ # ***************************************************************************** diff --git a/src/sage/rings/polynomial/laurent_polynomial.pyx b/src/sage/rings/polynomial/laurent_polynomial.pyx index f0ccb4e2ce0..c69859d443c 100644 --- a/src/sage/rings/polynomial/laurent_polynomial.pyx +++ b/src/sage/rings/polynomial/laurent_polynomial.pyx @@ -1325,10 +1325,17 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): sage: S. = LaurentPolynomialRing(QQ) sage: (t^-2 + 1).xgcd(t^-3 + 1) (1, 1/2*t^2 - 1/2*t^3 - 1/2*t^4, 1/2*t^3 + 1/2*t^4) + sage: R. = LaurentPolynomialRing(ZZ) + sage: f = 2*x^-2 - x^-1 + 4 + x + 139*x^2 - 5*x^3 + sage: g = -2 - x + 5*x^2 + 4*x^3 - x^4 + x^5 + sage: f.xgcd(g) + Traceback (most recent call last): + ... + NotImplementedError: only implemented when the base ring is an exact field """ R = self.parent() - if not R.is_exact() or not R.base_ring().is_field: - raise NotImplementedError("Not implemented") + if not R.is_exact() or not R.base_ring().is_field(): + raise NotImplementedError("only implemented when the base ring is an exact field") S = R.polynomial_ring() f, df = self.monomial_reduction() g, dg = other.monomial_reduction() @@ -1369,14 +1376,13 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): if u.is_unit(): return a.parent()(~u) if not a.parent().is_exact(): - raise NotImplementedError("Not implemented") + raise NotImplementedError("only implemented when the base ring is exact") g, s, _ = a.xgcd(m) if g == 1: return s elif g.is_unit(): return g.inverse_of_unit() * s - else: - raise ValueError("Impossible inverse modulo") + raise ValueError("impossible inverse modulo") def _fraction_pair(self): """ @@ -2079,7 +2085,6 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): ... NotImplementedError: divisibility test only implemented for Laurent polynomials over an integral domain - sage: R. = GF(2)[] sage: S. = LaurentPolynomialRing(R) sage: p = (x+y+1) * z**-1 + x*y @@ -2087,10 +2092,10 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): sage: p.divides(q), p.divides(p*q) # needs sage.libs.singular (False, True) """ - if not self.base_ring().is_integral_domain(): + if not self._parent.base_ring().is_integral_domain(): raise NotImplementedError("divisibility test only implemented for Laurent polynomials over an integral domain") - R = self.parent().polynomial_ring() + R = self._parent.polynomial_ring() p = R(self.polynomial_construction()[0]) q = R(other.polynomial_construction()[0]) return p.divides(q) diff --git a/src/sage/rings/polynomial/laurent_polynomial_ideal.py b/src/sage/rings/polynomial/laurent_polynomial_ideal.py index 81bc095c382..b3b1d391eb4 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_ideal.py +++ b/src/sage/rings/polynomial/laurent_polynomial_ideal.py @@ -205,6 +205,16 @@ def __contains__(self, f): return (g in self.polynomial_ideal()) def gens_reduced(self): + """ + A reduced system of generators. + + EXAMPLES:: + + sage: P. = LaurentPolynomialRing(QQ) + sage: J = P.ideal([x^2 - y^-2, x * y^3 + 2 * y^2+ y]) + sage: J.gens_reduced() + (x + 6*y + 5, 3*y^2 + 4*y + 1) + """ R = self.ring() J = self.polynomial_ideal() return tuple(R(p) for p in J.gens()) diff --git a/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx b/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx index fe199d281e3..e8b919b437e 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx +++ b/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx @@ -1856,9 +1856,14 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial): return ans def divides(self, other): - R = self.parent().polynomial_ring() + """ + Check if `self` divides `other` + """ + R = self._parent.polynomial_ring() if not R.base_ring().is_integral_domain(): raise NotImplementedError("divisibility test only implemented for polynomials over an integral domain") + if other.parent() != R: + return None p = R(self.monomial_reduction()[0]) q = R(other.monomial_reduction()[0]) return p.divides(q) From cc813a04bbc5501525ebdd8825c91fe9a7b9cab0 Mon Sep 17 00:00:00 2001 From: Enrique Artal Date: Tue, 10 Oct 2023 09:47:51 -0600 Subject: [PATCH 33/45] changes in divides --- src/sage/rings/polynomial/laurent_polynomial.pyx | 5 +---- .../rings/polynomial/laurent_polynomial_ideal.py | 2 +- .../polynomial/laurent_polynomial_mpair.pyx | 16 ++++++++++++---- 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/sage/rings/polynomial/laurent_polynomial.pyx b/src/sage/rings/polynomial/laurent_polynomial.pyx index c69859d443c..fba83a5ff42 100644 --- a/src/sage/rings/polynomial/laurent_polynomial.pyx +++ b/src/sage/rings/polynomial/laurent_polynomial.pyx @@ -2083,7 +2083,7 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): sage: p.divides(q) Traceback (most recent call last): ... - NotImplementedError: divisibility test only implemented for Laurent polynomials over an integral domain + NotImplementedError: divisibility test only implemented for polynomials over an integral domain sage: R. = GF(2)[] sage: S. = LaurentPolynomialRing(R) @@ -2092,9 +2092,6 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): sage: p.divides(q), p.divides(p*q) # needs sage.libs.singular (False, True) """ - if not self._parent.base_ring().is_integral_domain(): - raise NotImplementedError("divisibility test only implemented for Laurent polynomials over an integral domain") - R = self._parent.polynomial_ring() p = R(self.polynomial_construction()[0]) q = R(other.polynomial_construction()[0]) diff --git a/src/sage/rings/polynomial/laurent_polynomial_ideal.py b/src/sage/rings/polynomial/laurent_polynomial_ideal.py index b3b1d391eb4..0d5a6ad38ce 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_ideal.py +++ b/src/sage/rings/polynomial/laurent_polynomial_ideal.py @@ -92,7 +92,7 @@ def __init__(self, ring, gens, coerce=True, hint=None): """ Ideal_generic.__init__(self, ring, gens, coerce=coerce) self._poly_ring = ring.polynomial_ring() - self._poly_ideal = None # Create only as needed + self._poly_ideal = None # Create only as needed self._saturated = False self._hint = self._poly_ring.ideal([f.monomial_reduction()[0] for f in self.gens()]) # if hint is None: diff --git a/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx b/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx index e8b919b437e..fe7c0bdd787 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx +++ b/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx @@ -1858,12 +1858,20 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial): def divides(self, other): """ Check if `self` divides `other` + + EXAMPLES:: + + sage: R. = LaurentPolynomialRing(QQ) + sage: f1 = x^-2*y^3 - 9 - 1/14*x^-1*y - 1/3*x^-1 + sage: h = 3*x^-1 - 3*x^-2*y - 1/2*x^-3*y^2 - x^-3*y + x^-3 + sage: f2 = f1 * h + sage: f3 = f2 + x * y + sage: f1.divides(f2) + True + sage: f1.divides(f3) + False """ R = self._parent.polynomial_ring() - if not R.base_ring().is_integral_domain(): - raise NotImplementedError("divisibility test only implemented for polynomials over an integral domain") - if other.parent() != R: - return None p = R(self.monomial_reduction()[0]) q = R(other.monomial_reduction()[0]) return p.divides(q) From d68f6a5625fb661c12475099ef0f2c3155be19ce Mon Sep 17 00:00:00 2001 From: Enrique Artal Date: Fri, 13 Oct 2023 07:51:57 -0600 Subject: [PATCH 34/45] trick to solve the hint issue --- src/sage/rings/polynomial/ideal.py | 15 +++++++++++++++ src/sage/rings/polynomial/laurent_polynomial.pyx | 9 --------- .../rings/polynomial/laurent_polynomial_ideal.py | 10 +++++----- 3 files changed, 20 insertions(+), 14 deletions(-) diff --git a/src/sage/rings/polynomial/ideal.py b/src/sage/rings/polynomial/ideal.py index 1ab86736d5b..e61b6de3f39 100644 --- a/src/sage/rings/polynomial/ideal.py +++ b/src/sage/rings/polynomial/ideal.py @@ -85,3 +85,18 @@ def groebner_basis(self, algorithm=None): gb = self.gens_reduced() from sage.rings.polynomial.multi_polynomial_sequence import PolynomialSequence_generic return PolynomialSequence_generic([gb], self.ring(), immutable=True) + + def change_ring(self, R): + """ + Coerce an ideal into a new ring. + + EXAMPLES:: + + sage: P. = LaurentPolynomialRing(QQ, 2) + sage: I = P.ideal([x + y]) + sage: Q. = LaurentPolynomialRing(QQ, 3) + sage: I.change_ring(Q) + Ideal (x + y) of Multivariate Laurent Polynomial Ring in x, y, z + over Rational Field + """ + return R.ideal(self.gens()) diff --git a/src/sage/rings/polynomial/laurent_polynomial.pyx b/src/sage/rings/polynomial/laurent_polynomial.pyx index fba83a5ff42..748a07f7270 100644 --- a/src/sage/rings/polynomial/laurent_polynomial.pyx +++ b/src/sage/rings/polynomial/laurent_polynomial.pyx @@ -1325,17 +1325,8 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): sage: S. = LaurentPolynomialRing(QQ) sage: (t^-2 + 1).xgcd(t^-3 + 1) (1, 1/2*t^2 - 1/2*t^3 - 1/2*t^4, 1/2*t^3 + 1/2*t^4) - sage: R. = LaurentPolynomialRing(ZZ) - sage: f = 2*x^-2 - x^-1 + 4 + x + 139*x^2 - 5*x^3 - sage: g = -2 - x + 5*x^2 + 4*x^3 - x^4 + x^5 - sage: f.xgcd(g) - Traceback (most recent call last): - ... - NotImplementedError: only implemented when the base ring is an exact field """ R = self.parent() - if not R.is_exact() or not R.base_ring().is_field(): - raise NotImplementedError("only implemented when the base ring is an exact field") S = R.polynomial_ring() f, df = self.monomial_reduction() g, dg = other.monomial_reduction() diff --git a/src/sage/rings/polynomial/laurent_polynomial_ideal.py b/src/sage/rings/polynomial/laurent_polynomial_ideal.py index 0d5a6ad38ce..7b3b3a12ad3 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_ideal.py +++ b/src/sage/rings/polynomial/laurent_polynomial_ideal.py @@ -94,11 +94,11 @@ def __init__(self, ring, gens, coerce=True, hint=None): self._poly_ring = ring.polynomial_ring() self._poly_ideal = None # Create only as needed self._saturated = False - self._hint = self._poly_ring.ideal([f.monomial_reduction()[0] for f in self.gens()]) - # if hint is None: - # self._hint = self._poly_ring.zero_ideal() - # else: - # self._hint = hint.change_ring(self._poly_ring) + # self._hint = self._poly_ring.ideal([f.monomial_reduction()[0] for f in self.gens()]) + if hint is None: + self._hint = self._poly_ring.zero_ideal() + else: + self._hint = hint.change_ring(self._poly_ring) def set_hint(self, hint): """ From fe045a2a5eceb4f73dd53e20097d60b56697aba1 Mon Sep 17 00:00:00 2001 From: Enrique Artal Date: Mon, 16 Oct 2023 16:09:22 +0200 Subject: [PATCH 35/45] descripion of Laurent matrix class --- src/sage/matrix/matrix_laurent_mpolynomial_dense.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/matrix/matrix_laurent_mpolynomial_dense.pyx b/src/sage/matrix/matrix_laurent_mpolynomial_dense.pyx index 31ccba6c5d7..3794854e222 100644 --- a/src/sage/matrix/matrix_laurent_mpolynomial_dense.pyx +++ b/src/sage/matrix/matrix_laurent_mpolynomial_dense.pyx @@ -32,7 +32,7 @@ from sage.rings.polynomial.laurent_polynomial_ring_base import LaurentPolynomial cdef class Matrix_laurent_mpolynomial_dense(Matrix_generic_dense): """ - Dense matrix over a multivariate polynomial ring over a field. + Dense matrix over a Laurent multivariate polynomial ring over a field. """ def laurent_matrix_reduction(self): """ From 59e7c09eb75e8ca578e2ff56106cf6c1eba6b571 Mon Sep 17 00:00:00 2001 From: Enrique Artal Date: Tue, 17 Oct 2023 17:58:56 +0200 Subject: [PATCH 36/45] tests polynomial ideal --- src/sage/rings/polynomial/laurent_polynomial_ideal.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/polynomial/laurent_polynomial_ideal.py b/src/sage/rings/polynomial/laurent_polynomial_ideal.py index 7b3b3a12ad3..c556e1a7205 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_ideal.py +++ b/src/sage/rings/polynomial/laurent_polynomial_ideal.py @@ -114,7 +114,7 @@ def set_hint(self, hint): sage: P. = LaurentPolynomialRing(QQ, 3) sage: I = P.ideal([x^2*y + 3*x*y^2]) sage: I.hint() - Ideal (x + 3*y) of Multivariate Polynomial Ring in x, y, z over Rational Field + Ideal (0) of Multivariate Polynomial Ring in x, y, z over Rational Field sage: I.set_hint(P.polynomial_ring().ideal([x + 3*y])) sage: I.hint() Ideal (x + 3*y) of Multivariate Polynomial Ring in x, y, z over Rational Field @@ -135,7 +135,7 @@ def hint(self): sage: P. = LaurentPolynomialRing(QQ, 3) sage: I = P.ideal([x^2*y + 3*x*y^2]) sage: I.hint() - Ideal (x + 3*y) of Multivariate Polynomial Ring in x, y, z over Rational Field + Ideal (0) of Multivariate Polynomial Ring in x, y, z over Rational Field """ return self._hint From 01977ca18e1a818c73a0014f7568094891212f75 Mon Sep 17 00:00:00 2001 From: Enrique Artal Date: Mon, 23 Oct 2023 09:08:51 +0200 Subject: [PATCH 37/45] changes from revision october 23rd --- .../matrix/matrix_laurent_mpolynomial_dense.pxd | 6 ++++++ .../matrix/matrix_laurent_mpolynomial_dense.pyx | 17 ++++------------- .../rings/polynomial/laurent_polynomial.pyx | 12 ++++-------- .../polynomial/laurent_polynomial_ideal.py | 6 +++--- .../polynomial/laurent_polynomial_mpair.pyx | 5 ++++- 5 files changed, 21 insertions(+), 25 deletions(-) create mode 100644 src/sage/matrix/matrix_laurent_mpolynomial_dense.pxd diff --git a/src/sage/matrix/matrix_laurent_mpolynomial_dense.pxd b/src/sage/matrix/matrix_laurent_mpolynomial_dense.pxd new file mode 100644 index 00000000000..4679933c7f5 --- /dev/null +++ b/src/sage/matrix/matrix_laurent_mpolynomial_dense.pxd @@ -0,0 +1,6 @@ +from sage.matrix.matrix_generic_dense cimport Matrix_generic_dense + +from sage.libs.singular.decl cimport ideal + +cdef class Matrix_Laurent_mpolynomial_dense(Matrix_generic_dense): + pass diff --git a/src/sage/matrix/matrix_laurent_mpolynomial_dense.pyx b/src/sage/matrix/matrix_laurent_mpolynomial_dense.pyx index 3794854e222..775f6318bac 100644 --- a/src/sage/matrix/matrix_laurent_mpolynomial_dense.pyx +++ b/src/sage/matrix/matrix_laurent_mpolynomial_dense.pyx @@ -16,17 +16,6 @@ AUTHOR: # ***************************************************************************** from sage.matrix.matrix_generic_dense cimport Matrix_generic_dense -# from sage.matrix.matrix2 cimport Matrix -# -# from sage.matrix.constructor import identity_matrix -# from sage.rings.polynomial.laurent_polynomial_ring_base import LaurentPolynomialRing_generic -# from sage.rings.polynomial.multi_polynomial_libsingular cimport MPolynomialRing_libsingular -# from sage.rings.polynomial.polynomial_singular_interface import can_convert_to_singular -# -# from sage.libs.singular.function import singular_function, lib -# -# from cysignals.signals cimport sig_on, sig_off - from sage.matrix.constructor import identity_matrix from sage.rings.polynomial.laurent_polynomial_ring_base import LaurentPolynomialRing_generic @@ -40,8 +29,10 @@ cdef class Matrix_laurent_mpolynomial_dense(Matrix_generic_dense): to obtain a matrix `P` of polynomials such that the variables do not divide no column and no row. - OUTPUT: Three matrices `L`, `P`, `R` such that `self = L P R`, where `L` and - `R` are diagonal with monomial entries. + OUTPUT: + + Three matrices `L`, `P`, `R` such that ``self` equals `L P R`, where `L` and + `R` are diagonal with monomial entries. EXAMPLES: diff --git a/src/sage/rings/polynomial/laurent_polynomial.pyx b/src/sage/rings/polynomial/laurent_polynomial.pyx index 748a07f7270..91619cdfd69 100644 --- a/src/sage/rings/polynomial/laurent_polynomial.pyx +++ b/src/sage/rings/polynomial/laurent_polynomial.pyx @@ -1341,6 +1341,9 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): The parameter ``m`` may be either a single polynomial or an ideal (for consistency with :meth:`inverse_mod` in other rings). + ALGORITHM: Solve the system `as + mt = 1`, returning `s` as the inverse + of `a` mod `m`. + EXAMPLES:: sage: S. = LaurentPolynomialRing(QQ) @@ -1348,15 +1351,12 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): 1/2*t^2 - 1/2*t^3 - 1/2*t^4 sage: f * (t^-2 + 1) + (1/2*t^4 + 1/2*t^3) * (t^-3 + 1) 1 - - ALGORITHM: Solve the system `as + mt = 1`, returning `s` as the inverse - of `a` mod `m`. """ from sage.rings.ideal import is_Ideal if is_Ideal(m): v = m.gens_reduced() if len(v) > 1: - raise NotImplementedError("Don't know how to invert modulo non-principal ideal %s" % m) + raise NotImplementedError("only inversion modulo principal ideals implemented") m = v[0] if m.degree() == 1 and m[1].is_unit(): # a(x) mod (x-r) = a(r) @@ -1366,8 +1366,6 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): u = a(r) if u.is_unit(): return a.parent()(~u) - if not a.parent().is_exact(): - raise NotImplementedError("only implemented when the base ring is exact") g, s, _ = a.xgcd(m) if g == 1: return s @@ -2053,8 +2051,6 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): r""" Return ``True`` if ``self`` divides ``other``. - This method is only implemented for Laurent polynomials over an integral domain. - EXAMPLES:: sage: R. = LaurentPolynomialRing(ZZ) diff --git a/src/sage/rings/polynomial/laurent_polynomial_ideal.py b/src/sage/rings/polynomial/laurent_polynomial_ideal.py index c556e1a7205..1b836305af1 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_ideal.py +++ b/src/sage/rings/polynomial/laurent_polynomial_ideal.py @@ -206,7 +206,7 @@ def __contains__(self, f): def gens_reduced(self): """ - A reduced system of generators. + A reduced system of generators. EXAMPLES:: @@ -217,7 +217,7 @@ def gens_reduced(self): """ R = self.ring() J = self.polynomial_ideal() - return tuple(R(p) for p in J.gens()) + return tuple([R(p) for p in J.gens()]) # Operations on ideals @@ -423,7 +423,7 @@ def polynomial_ideal(self, saturate=True): Q = self._poly_ring if len(P.gens()) == 1: a = [Q(p.polynomial_construction()[0]) for p in self.gens()] - if P.is_integral_domain(): + if P.base_ring().is_field(): a = GCD(a) return Q.ideal(a) if self._poly_ideal is not None and (self._saturated or not saturate): diff --git a/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx b/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx index fe7c0bdd787..27c31754d8f 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx +++ b/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx @@ -1855,9 +1855,10 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial): return new_ring(ans) return ans + @coerce_binop def divides(self, other): """ - Check if `self` divides `other` + Check if ``self`` divides ``other`` EXAMPLES:: @@ -1870,6 +1871,8 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial): True sage: f1.divides(f3) False + sage: f1.divides(3) + False """ R = self._parent.polynomial_ring() p = R(self.monomial_reduction()[0]) From 314c4bb23283b0b9a155db6e2e4d41f7e0396f4c Mon Sep 17 00:00:00 2001 From: Enrique Artal Date: Mon, 23 Oct 2023 11:50:19 +0200 Subject: [PATCH 38/45] change position of conditional in divides --- .../polynomial/laurent_polynomial_ring.py | 1 + .../rings/polynomial/polynomial_element.pyx | 18 +++++++++++------- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/sage/rings/polynomial/laurent_polynomial_ring.py b/src/sage/rings/polynomial/laurent_polynomial_ring.py index 22d97975cd6..fdc04260001 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_ring.py +++ b/src/sage/rings/polynomial/laurent_polynomial_ring.py @@ -443,6 +443,7 @@ def __init__(self, R): TESTS:: sage: TestSuite(LaurentPolynomialRing(Zmod(2), 'y')).run() + sage: TestSuite(LaurentPolynomialRing(Zmod(4), 'y')).run() sage: TestSuite(LaurentPolynomialRing(ZZ, 'u')).run() sage: TestSuite(LaurentPolynomialRing(Zmod(2)['T'], 'u')).run() """ diff --git a/src/sage/rings/polynomial/polynomial_element.pyx b/src/sage/rings/polynomial/polynomial_element.pyx index a5b7f937cfe..7e006973db3 100644 --- a/src/sage/rings/polynomial/polynomial_element.pyx +++ b/src/sage/rings/polynomial/polynomial_element.pyx @@ -11074,15 +11074,19 @@ cdef class Polynomial(CommutativePolynomial): sage: p.divides(q), p.divides(p*q) # needs sage.libs.singular (False, True) """ - if not self.base_ring().is_integral_domain(): - raise NotImplementedError("divisibility test only implemented for polynomials over an integral domain") - - if p.is_zero(): return True # everything divides 0 - if self.is_zero(): return False # 0 only divides 0 + if p.is_zero(): + return True # everything divides 0 + if self.is_zero(): + return False # 0 only divides 0 try: - if self.is_unit(): return True # units divide everything + if self.is_unit(): + return True # units divide everything except NotImplementedError: - if self.is_one(): return True # if is_unit is not implemented + if self.is_one(): + return True # if is_unit is not implemented + + if not self.base_ring().is_integral_domain(): + raise NotImplementedError("divisibility test only implemented for polynomials over an integral domain") if self.degree() > p.degree(): return False From 72a36de551a5d05841c6e025a76e2e54bdff6821 Mon Sep 17 00:00:00 2001 From: Enrique Artal Date: Tue, 24 Oct 2023 14:37:14 +0200 Subject: [PATCH 39/45] revision october 24th --- .../matrix_laurent_mpolynomial_dense.pxd | 2 -- .../matrix_laurent_mpolynomial_dense.pyx | 2 -- .../rings/polynomial/laurent_polynomial.pyx | 9 +++----- .../polynomial/laurent_polynomial_ideal.py | 22 ++++++++++++++++--- .../polynomial/laurent_polynomial_mpair.pyx | 5 ++--- .../polynomial/laurent_polynomial_ring.py | 1 + 6 files changed, 25 insertions(+), 16 deletions(-) diff --git a/src/sage/matrix/matrix_laurent_mpolynomial_dense.pxd b/src/sage/matrix/matrix_laurent_mpolynomial_dense.pxd index 4679933c7f5..2a1170d0bc5 100644 --- a/src/sage/matrix/matrix_laurent_mpolynomial_dense.pxd +++ b/src/sage/matrix/matrix_laurent_mpolynomial_dense.pxd @@ -1,6 +1,4 @@ from sage.matrix.matrix_generic_dense cimport Matrix_generic_dense -from sage.libs.singular.decl cimport ideal - cdef class Matrix_Laurent_mpolynomial_dense(Matrix_generic_dense): pass diff --git a/src/sage/matrix/matrix_laurent_mpolynomial_dense.pyx b/src/sage/matrix/matrix_laurent_mpolynomial_dense.pyx index 775f6318bac..1f345a68ba6 100644 --- a/src/sage/matrix/matrix_laurent_mpolynomial_dense.pyx +++ b/src/sage/matrix/matrix_laurent_mpolynomial_dense.pyx @@ -14,8 +14,6 @@ AUTHOR: # the License, or (at your option) any later version. # https://www.gnu.org/licenses/ # ***************************************************************************** -from sage.matrix.matrix_generic_dense cimport Matrix_generic_dense - from sage.matrix.constructor import identity_matrix from sage.rings.polynomial.laurent_polynomial_ring_base import LaurentPolynomialRing_generic diff --git a/src/sage/rings/polynomial/laurent_polynomial.pyx b/src/sage/rings/polynomial/laurent_polynomial.pyx index 91619cdfd69..1e04abe3bf5 100644 --- a/src/sage/rings/polynomial/laurent_polynomial.pyx +++ b/src/sage/rings/polynomial/laurent_polynomial.pyx @@ -2068,9 +2068,7 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): sage: p = 4*x + 3*x^-1 sage: q = 5*x^2 + x + 2*x^-2 sage: p.divides(q) - Traceback (most recent call last): - ... - NotImplementedError: divisibility test only implemented for polynomials over an integral domain + False sage: R. = GF(2)[] sage: S. = LaurentPolynomialRing(R) @@ -2079,7 +2077,6 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): sage: p.divides(q), p.divides(p*q) # needs sage.libs.singular (False, True) """ - R = self._parent.polynomial_ring() - p = R(self.polynomial_construction()[0]) - q = R(other.polynomial_construction()[0]) + p = self.polynomial_construction()[0] + q = other.polynomial_construction()[0] return p.divides(q) diff --git a/src/sage/rings/polynomial/laurent_polynomial_ideal.py b/src/sage/rings/polynomial/laurent_polynomial_ideal.py index 1b836305af1..43f9bca511c 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_ideal.py +++ b/src/sage/rings/polynomial/laurent_polynomial_ideal.py @@ -94,7 +94,6 @@ def __init__(self, ring, gens, coerce=True, hint=None): self._poly_ring = ring.polynomial_ring() self._poly_ideal = None # Create only as needed self._saturated = False - # self._hint = self._poly_ring.ideal([f.monomial_reduction()[0] for f in self.gens()]) if hint is None: self._hint = self._poly_ring.zero_ideal() else: @@ -194,6 +193,14 @@ def __contains__(self, f): sage: I = P.ideal([x^2*y + 3*x*y^2]) sage: x + 3*y in I True + sage: I.gen(0).__reduce__() + (Multivariate Laurent Polynomial Ring in x, y over Rational Field, + (x^2*y + 3*x*y^2, (0, 0))) + sage: P. = LaurentPolynomialRing(QQ, 1) + sage: I = P.ideal([x^2 + 3*x]) + sage: I.gen(0).__reduce__() # Check the differences of __reduce__ for distinct Laurent polynomial rings + (Multivariate Laurent Polynomial Ring in x over Rational Field, + (x^2 + 3*x, (0,))) """ if not f or f in self.gens(): return True @@ -416,8 +423,17 @@ def polynomial_ideal(self, saturate=True): sage: P. = LaurentPolynomialRing(QQ, 2) sage: I = P.ideal([x^2*y + 3*x*y^2]) sage: I.polynomial_ideal() - Ideal (x + 3*y) of Multivariate Polynomial Ring in x, y - over Rational Field + Ideal (x + 3*y) of Multivariate Polynomial Ring in x, y over Rational Field + sage: P. = LaurentPolynomialRing(QQ) + sage: J = P.ideal(t^2 - t^-1) + sage: J.polynomial_ideal() + Principal ideal (t^3 - 1) of Univariate Polynomial Ring in t over Rational Field + sage: J = P.ideal([t^2 - t^-1, t + t^-1]) + sage: J.polynomial_ideal() + Principal ideal (1) of Univariate Polynomial Ring in t over Rational Field + sage: J = P.ideal([t^2 - t^-1, t - t^-1]) + sage: J.polynomial_ideal() + Principal ideal (t - 1) of Univariate Polynomial Ring in t over Rational Field """ P = self.ring() Q = self._poly_ring diff --git a/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx b/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx index 27c31754d8f..470c3b4ecc3 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx +++ b/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx @@ -1874,7 +1874,6 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial): sage: f1.divides(3) False """ - R = self._parent.polynomial_ring() - p = R(self.monomial_reduction()[0]) - q = R(other.monomial_reduction()[0]) + p = self.monomial_reduction()[0] + q = other.monomial_reduction()[0] return p.divides(q) diff --git a/src/sage/rings/polynomial/laurent_polynomial_ring.py b/src/sage/rings/polynomial/laurent_polynomial_ring.py index fdc04260001..812a4b3a351 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_ring.py +++ b/src/sage/rings/polynomial/laurent_polynomial_ring.py @@ -446,6 +446,7 @@ def __init__(self, R): sage: TestSuite(LaurentPolynomialRing(Zmod(4), 'y')).run() sage: TestSuite(LaurentPolynomialRing(ZZ, 'u')).run() sage: TestSuite(LaurentPolynomialRing(Zmod(2)['T'], 'u')).run() + sage: TestSuite(LaurentPolynomialRing(Zmod(4)['T'], 'u')).run() """ if R.ngens() != 1: raise ValueError("must be 1 generator") From 146508ebf4b48566127b1e92260b292d184c98bc Mon Sep 17 00:00:00 2001 From: Enrique Artal Date: Tue, 24 Oct 2023 22:57:38 +0200 Subject: [PATCH 40/45] forgot to push polynomial_element.pyx --- .../rings/polynomial/polynomial_element.pyx | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/src/sage/rings/polynomial/polynomial_element.pyx b/src/sage/rings/polynomial/polynomial_element.pyx index 7e006973db3..e6fc136df5e 100644 --- a/src/sage/rings/polynomial/polynomial_element.pyx +++ b/src/sage/rings/polynomial/polynomial_element.pyx @@ -11047,10 +11047,10 @@ cdef class Polynomial(CommutativePolynomial): sage: R. = Zmod(6)[] sage: p = 4*x + 3 sage: q = 5*x**2 + x + 2 + sage: q.divides(p) + False sage: p.divides(q) - Traceback (most recent call last): - ... - NotImplementedError: divisibility test only implemented for polynomials over an integral domain + False TESTS:: @@ -11073,6 +11073,13 @@ cdef class Polynomial(CommutativePolynomial): sage: q = (y^2-x^2) * z^2 + z + x-y sage: p.divides(q), p.divides(p*q) # needs sage.libs.singular (False, True) + sage: R. = Zmod(6)[] + sage: p = 4*x + 3 + sage: q = 2*x**2 + x + 2 + sage: p.divides(q) + Traceback (most recent call last): + ... + NotImplementedError: divisibility test only implemented for polynomials over an integral domain unless obvious non divisibility of leading terms """ if p.is_zero(): return True # everything divides 0 @@ -11085,19 +11092,19 @@ cdef class Polynomial(CommutativePolynomial): if self.is_one(): return True # if is_unit is not implemented - if not self.base_ring().is_integral_domain(): - raise NotImplementedError("divisibility test only implemented for polynomials over an integral domain") - if self.degree() > p.degree(): return False if not self.leading_coefficient().divides(p.leading_coefficient()): return False + if not self.base_ring().is_integral_domain(): + raise NotImplementedError("divisibility test only implemented for polynomials over an integral domain unless obvious non divisibility of leading terms") + try: return (p % self).is_zero() # if quo_rem is defined except ArithmeticError: - return False # if division is not exact + return False def specialization(self, D=None, phi=None): r""" From d1e90b9cf38582b6e79e640b3b568292c6f2bd19 Mon Sep 17 00:00:00 2001 From: Enrique Artal Date: Thu, 2 Nov 2023 08:24:55 +0100 Subject: [PATCH 41/45] more doctests --- .../rings/polynomial/laurent_polynomial_ideal.py | 12 +++++++++--- .../rings/polynomial/laurent_polynomial_mpair.pyx | 2 +- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/sage/rings/polynomial/laurent_polynomial_ideal.py b/src/sage/rings/polynomial/laurent_polynomial_ideal.py index 43f9bca511c..4cf7b8b3414 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_ideal.py +++ b/src/sage/rings/polynomial/laurent_polynomial_ideal.py @@ -193,14 +193,20 @@ def __contains__(self, f): sage: I = P.ideal([x^2*y + 3*x*y^2]) sage: x + 3*y in I True + sage: P.__contains__(x + 3*y) + True sage: I.gen(0).__reduce__() (Multivariate Laurent Polynomial Ring in x, y over Rational Field, (x^2*y + 3*x*y^2, (0, 0))) - sage: P. = LaurentPolynomialRing(QQ, 1) + sage: P. = LaurentPolynomialRing(QQ) sage: I = P.ideal([x^2 + 3*x]) + sage: 1 + 3*x^-1 in I + True + sage: P.__contains__(1 + 3*x^-1) + True sage: I.gen(0).__reduce__() # Check the differences of __reduce__ for distinct Laurent polynomial rings - (Multivariate Laurent Polynomial Ring in x over Rational Field, - (x^2 + 3*x, (0,))) + (, + (Univariate Laurent Polynomial Ring in x over Rational Field, x + 3, 1)) """ if not f or f in self.gens(): return True diff --git a/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx b/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx index 3b2ebf177ea..9cf123b5a52 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx +++ b/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx @@ -1858,7 +1858,7 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial): @coerce_binop def divides(self, other): """ - Check if ``self`` divides ``other`` + Check if ``self`` divides ``other``. EXAMPLES:: From 4ef28839c726a495332aca4d254a6c5925a58ee6 Mon Sep 17 00:00:00 2001 From: Enrique Artal Date: Thu, 2 Nov 2023 17:16:46 +0100 Subject: [PATCH 42/45] doctests for change_ring in ideal_py and __contains_ in laurent_polynomial_ideal --- src/sage/rings/polynomial/ideal.py | 10 +++---- .../polynomial/laurent_polynomial_ideal.py | 26 ++++++++----------- 2 files changed, 15 insertions(+), 21 deletions(-) diff --git a/src/sage/rings/polynomial/ideal.py b/src/sage/rings/polynomial/ideal.py index e61b6de3f39..9719c81ba41 100644 --- a/src/sage/rings/polynomial/ideal.py +++ b/src/sage/rings/polynomial/ideal.py @@ -92,11 +92,9 @@ def change_ring(self, R): EXAMPLES:: - sage: P. = LaurentPolynomialRing(QQ, 2) - sage: I = P.ideal([x + y]) - sage: Q. = LaurentPolynomialRing(QQ, 3) - sage: I.change_ring(Q) - Ideal (x + y) of Multivariate Laurent Polynomial Ring in x, y, z - over Rational Field + sage: R. = QQ[] + sage: I = R.ideal([q^2+q-1]) + sage: I.change_ring(RR['q']) + Principal ideal (q^2 + q - 1.00000000000000) of Univariate Polynomial Ring in q over Real Field with 53 bits of precision """ return R.ideal(self.gens()) diff --git a/src/sage/rings/polynomial/laurent_polynomial_ideal.py b/src/sage/rings/polynomial/laurent_polynomial_ideal.py index 4cf7b8b3414..924ce7ed7d3 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_ideal.py +++ b/src/sage/rings/polynomial/laurent_polynomial_ideal.py @@ -23,6 +23,7 @@ # **************************************************************************** from sage.rings.ideal import Ideal_generic +from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing_univariate from sage.structure.richcmp import op_EQ, op_NE, op_LT, op_LE, op_GT, op_GE from sage.arith.misc import GCD @@ -193,28 +194,23 @@ def __contains__(self, f): sage: I = P.ideal([x^2*y + 3*x*y^2]) sage: x + 3*y in I True - sage: P.__contains__(x + 3*y) - True - sage: I.gen(0).__reduce__() - (Multivariate Laurent Polynomial Ring in x, y over Rational Field, - (x^2*y + 3*x*y^2, (0, 0))) + + We test that these changes allow to use this method in the inivariate case. + + TESTS:: + sage: P. = LaurentPolynomialRing(QQ) sage: I = P.ideal([x^2 + 3*x]) sage: 1 + 3*x^-1 in I True - sage: P.__contains__(1 + 3*x^-1) - True - sage: I.gen(0).__reduce__() # Check the differences of __reduce__ for distinct Laurent polynomial rings - (, - (Univariate Laurent Polynomial Ring in x over Rational Field, x + 3, 1)) """ if not f or f in self.gens(): return True f = self.ring()(f) - if self.ring().ngens() > 1: - g = f.__reduce__()[1][0] - else: + if isinstance(self.ring(), LaurentPolynomialRing_univariate): g = f.__reduce__()[1][1] + else: + g = f.__reduce__()[1][0] return (g in self.polynomial_ideal()) def gens_reduced(self): @@ -356,7 +352,7 @@ def toric_coordinate_change(self, M, forward_hint=True): """ if forward_hint: R = self.ring() - apply_to_hint = lambda x, M=M, R=R: R(x).toric_coordinate_change(M).__reduce__()[1][0] + apply_to_hint = lambda x, M=M, R=R: R(x).toric_coordinate_change(M).monomial_reduction()[0] else: apply_to_hint = None return self.apply_map(lambda x, M=M: x.toric_coordinate_change(M), @@ -443,7 +439,7 @@ def polynomial_ideal(self, saturate=True): """ P = self.ring() Q = self._poly_ring - if len(P.gens()) == 1: + if isinstance(self.ring(), LaurentPolynomialRing_univariate): a = [Q(p.polynomial_construction()[0]) for p in self.gens()] if P.base_ring().is_field(): a = GCD(a) From 7030a05215a9178259241cae21ece3288e1acbc3 Mon Sep 17 00:00:00 2001 From: Enrique Artal Date: Thu, 2 Nov 2023 19:05:01 +0100 Subject: [PATCH 43/45] change in monomial_reduction --- src/sage/rings/polynomial/laurent_polynomial_mpair.pyx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx b/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx index 9cf123b5a52..c0fd659591f 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx +++ b/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx @@ -1534,17 +1534,17 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial): sage: R. = LaurentPolynomialRing(QQ) sage: f = y / x + x^2 / y + 3 * x^4 * y^-2 sage: f.monomial_reduction() - (3*x^5 + x^3*y + y^3, 1/(x*y^2)) + (3*x^5 + x^3*y + y^3, x^-1*y^-2) sage: f = y * x + x^2 / y + 3 * x^4 * y^-2 sage: f.monomial_reduction() - (3*x^3 + y^3 + x*y, x/y^2) + (3*x^3 + y^3 + x*y, x*y^-2) sage: x.monomial_reduction() (1, x) sage: (y^-1).monomial_reduction() - (1, 1/y) + (1, y^-1) """ self._normalize() - ring = self._parent._R + ring = self._parent g = ring.gens() mon = ring.prod(g[i] ** j for i, j in enumerate(self._mon)) return (self._poly, mon) From 650e0606748e57db9773a0f3e8201082771aae5d Mon Sep 17 00:00:00 2001 From: Enrique Artal Date: Fri, 3 Nov 2023 11:52:18 +0100 Subject: [PATCH 44/45] some cases missing in characteristic varieties --- src/sage/groups/finitely_presented.py | 35 +++++++++++++++++++++------ 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/src/sage/groups/finitely_presented.py b/src/sage/groups/finitely_presented.py index a961df9a4c5..a351e544ce7 100644 --- a/src/sage/groups/finitely_presented.py +++ b/src/sage/groups/finitely_presented.py @@ -1703,12 +1703,18 @@ def abelian_alexander_matrix(self, ring=QQ, simplified=True): sage: g = FreeGroup(1) / [] sage: g.abelian_alexander_matrix() ([], []) + sage: g.abelian_alexander_matrix()[0].base_ring() + Univariate Laurent Polynomial Ring in f1 over Rational Field sage: g = FreeGroup(0) / [] - sage: g.abelian_alexander_matrix() - ([], []) + sage: A, ideal = g.abelian_alexander_matrix(); A + [] + sage: A.base_ring() + Rational Field """ ab, R, ideal, images = self.abelianization_to_algebra(ring=ring) A = self.alexander_matrix(im_gens=images) + if A.base_ring() != R: + A = A.change_ring(R) if simplified: n, m = A.dimensions() if n == 0 or m == 0: @@ -1794,8 +1800,7 @@ def characteristic_varieties(self, ring=QQ, matrix_ideal=None, groebner=False): sage: G.characteristic_varieties() {0: Ideal (0) of Univariate Laurent Polynomial Ring in f2 over Rational Field, 1: Ideal (-1 + 2*f2 - 2*f2^2 + f2^3) of Univariate Laurent Polynomial Ring in f2 over Rational Field, - 2: Ideal (1) of Univariate Laurent Polynomial Ring in f2 over Rational Field, - 3: Ideal (1) of Univariate Laurent Polynomial Ring in f2 over Rational Field} + 2: Ideal (1) of Univariate Laurent Polynomial Ring in f2 over Rational Field} sage: G.characteristic_varieties(groebner=True) {0: [0], 1: [-1 + f2, 1 - f2 + f2^2], 2: []} sage: G = FreeGroup(2)/[3 * (1, ), 2 * (2, )] @@ -1804,7 +1809,17 @@ def characteristic_varieties(self, ring=QQ, matrix_ideal=None, groebner=False): sage: G = FreeGroup(2)/[2 * (2, )] sage: G.characteristic_varieties(groebner=True) {0: [(f1 + 1,), (f1 - 1,)], 1: [(f1 + 1,), (f1 - 1, f2 - 1)], 2: []} + sage: G = (FreeGroup(0) / []) + sage: G.characteristic_varieties() + {0: Principal ideal (0) of Rational Field, + 1: Principal ideal (1) of Rational Field} + sage: G.characteristic_varieties(groebner=True) + {0: [(0,)], 1: [(1,)]} """ + if self.ngens() == 0: + if groebner: + return {j: [(ring(j),)] for j in (0, 1)} + return {j: ring.ideal(j) for j in (0, 1)} A, rels = self.abelian_alexander_matrix(ring=ring, simplified=True) R = A.base_ring() eval_1 = {x: ring(1) for x in R.gens()} @@ -1816,7 +1831,8 @@ def characteristic_varieties(self, ring=QQ, matrix_ideal=None, groebner=False): K = R.base_ring() id_rels = R.ideal(rels) res = dict() - for j in range(n + 2): + bound = n + 1 + for j in range(bound + 1): J = id_rels + A.fitting_ideal(j) # J = R.ideal(id_rels.gens() + A.fitting_ideal(j).gens()) if j <= n1: @@ -1824,14 +1840,17 @@ def characteristic_varieties(self, ring=QQ, matrix_ideal=None, groebner=False): if J1: J *= ideal_1 res[j] = R.ideal(J.gens_reduced()) + if R(1) in res[j].gens(): + bound = j + break if not groebner or not ring.is_field(): return res if R.ngens() == 1: - res = {j: gcd(S(p) for p in res[j].gens()) for j in range(n + 2)} + res = {j: gcd(S(p) for p in res[j].gens()) for j in range(bound + 1)} char_var = dict() strict = True j = 0 - while strict and j <= n + 1: + while strict and j <= bound: if res[j] == 0: char_var[j] = [R(0)] else: @@ -1846,7 +1865,7 @@ def characteristic_varieties(self, ring=QQ, matrix_ideal=None, groebner=False): char_var = dict() strict = True j = 0 - while strict and j <= n + 1: + while strict and j <= bound: LJ = res[j].minimal_associated_primes() fct = [id.groebner_basis() for id in LJ] char_var[j] = fct From d3767f0b4b99da2f74c6ef1703234f598929870c Mon Sep 17 00:00:00 2001 From: Enrique Artal Date: Tue, 7 Nov 2023 10:40:41 +0100 Subject: [PATCH 45/45] corrections from review --- src/sage/rings/polynomial/laurent_polynomial_ideal.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/sage/rings/polynomial/laurent_polynomial_ideal.py b/src/sage/rings/polynomial/laurent_polynomial_ideal.py index 924ce7ed7d3..d569dc06101 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_ideal.py +++ b/src/sage/rings/polynomial/laurent_polynomial_ideal.py @@ -195,9 +195,7 @@ def __contains__(self, f): sage: x + 3*y in I True - We test that these changes allow to use this method in the inivariate case. - - TESTS:: + This also works in the univariate case:: sage: P. = LaurentPolynomialRing(QQ) sage: I = P.ideal([x^2 + 3*x]) @@ -215,7 +213,7 @@ def __contains__(self, f): def gens_reduced(self): """ - A reduced system of generators. + Return a reduced system of generators. EXAMPLES::