diff --git a/src/sage/combinat/species/recursive_species.py b/src/sage/combinat/species/recursive_species.py index a361bdfad20..d3c669e2162 100644 --- a/src/sage/combinat/species/recursive_species.py +++ b/src/sage/combinat/species/recursive_species.py @@ -401,6 +401,15 @@ def define(self, x): [1, 2, 3, 5, 8, 13, 21, 34, 55, 89] sage: F.isotype_generating_series()[0:10] [1, 2, 3, 5, 8, 13, 21, 34, 55, 89] + + Check that issues :trac:`35071` is fixed:: + + sage: X = species.SingletonSpecies() + sage: E = species.SetSpecies(max=3) + sage: B = species.CombinatorialSpecies(min=1) + sage: B.define(X*E(B)) + sage: B.generating_series() + z + z^2 + 3/2*z^3 + 5/2*z^4 + 9/2*z^5 + 17/2*z^6 + 133/8*z^7 + O(z^8) """ if not isinstance(x, GenericCombinatorialSpecies): raise TypeError("x must be a combinatorial species") diff --git a/src/sage/data_structures/stream.py b/src/sage/data_structures/stream.py index 4bffa84bfc9..35c72bcedca 100644 --- a/src/sage/data_structures/stream.py +++ b/src/sage/data_structures/stream.py @@ -157,43 +157,83 @@ def _approximate_order(self): """ raise NotImplementedError - def __ne__(self, other): - """ - Return whether ``self`` and ``other`` are known to be different. - - The default is to always return ``False`` as it usually - cannot be decided whether they are equal. - - INPUT: - - - ``other`` -- a stream + def __bool__(self): + r""" + Return ``True`` if ``self`` is not known to be zero. EXAMPLES:: sage: from sage.data_structures.stream import Stream sage: CS = Stream(1) - sage: CS != CS - False - sage: CS != Stream(-2) - False - + sage: bool(CS) + True """ - return False + return True - def is_nonzero(self): + def _cache_iterator(self): r""" - Return ``True`` if and only if this stream is known - to be nonzero. + Iterate over the known ``(degree, coefficient)``-pairs. + """ + raise NotImplementedError - The default implementation is ``False``. + def __ne__(self, other): + """ + Return ``True`` if ``self`` and ``other`` are known to be different. + + This can be decided only if we have already encountered a + coefficient which is different in ``self`` and ``other``. + + INPUT: + + - ``other`` -- a stream EXAMPLES:: - sage: from sage.data_structures.stream import Stream - sage: CS = Stream(1) - sage: CS.is_nonzero() + sage: from sage.data_structures.stream import Stream_exact, Stream_zero, Stream_function + sage: s1 = Stream_exact([0, 1]) + sage: s1 != Stream_exact([1]) + True + sage: s1 != Stream_zero() + True + sage: s2 = Stream_function(lambda n: 2 if n else 0, True, 0) + sage: s1 != s2 False + sage: s2[1] + 2 + sage: s1 != s2 + True + """ + if isinstance(self, Stream_zero): + # bool(other) is True if we do not know that other is zero + # other.is_nonzero() is True if we know that other is non-zero + return other.is_nonzero() + if isinstance(other, Stream_zero): + return self.is_nonzero() + if isinstance(self, Stream_exact) and isinstance(other, Stream_exact): + return not self == other + # In the remaining cases we only know finitely many + # coefficients of at least one of the streams + ao_f = self._approximate_order + ao_g = other._approximate_order + if ao_g < ao_f: + f, g = other, self + ao_f, ao_g = ao_g, ao_f + else: + f, g = self, other + if f._true_order and ao_f < ao_g: + return True + f_iter = f._cache_iterator() + g_iter = g._cache_iterator() + f_deg, f_val = next(f_iter, (None, None)) + g_deg, g_val = next(g_iter, (None, None)) + while f_deg is not None and g_deg is not None: + if f_deg == g_deg and f_val != g_val: + return True + elif f_deg < g_deg: + f_deg, f_val = next(f_iter, (None, None)) + else: + g_deg, g_val = next(g_iter, (None, None)) return False @@ -251,6 +291,15 @@ def is_nonzero(self): return any(self._cache.values()) return any(self._cache) + def _cache_iterator(self): + r""" + Iterate over the known ``(degree, coefficient)``-pairs. + """ + if self._is_sparse: + yield from self._cache.items() # does python guarantee that they are sorted? + elif self._true_order: + yield from enumerate(self._cache, self._approximate_order) + def __getstate__(self): """ Build the dictionary for pickling ``self``. @@ -454,107 +503,6 @@ def order(self): n += 1 return n - def __ne__(self, other): - """ - Return whether ``self`` and ``other`` are known to be different. - - Only the elements in the caches are considered. - - INPUT: - - - ``other`` -- a stream - - EXAMPLES:: - - sage: from sage.data_structures.stream import Stream_function - sage: f = Stream_function(lambda n: n, True, 0) - sage: g = Stream_function(lambda n: n^2, True, 0) - sage: f != g - False - sage: f[1], g[1] - (1, 1) - sage: f != g - False - sage: f[3], g[4] - (3, 16) - sage: f != g - False - sage: f[2], g[2] - (2, 4) - sage: f != g - True - - Checking the dense implementation:: - - sage: f = Stream_function(lambda n: n if n > 0 else 0, False, -3) - sage: g = Stream_function(lambda n: n^2, False, 0) - sage: f != g - False - sage: g != f - False - sage: _ = f[1], g[1] - sage: f != g - False - sage: g != f - False - sage: _ = f[2], g[2] - sage: f != g - True - sage: g != f - True - - sage: f = Stream_function(lambda n: n if n > 0 else 0, False, -3) - sage: g = Stream_function(lambda n: n^2, False, 0) - sage: _ = f[5], g[1] - sage: f != g - False - sage: g != f - False - sage: _ = g[2] - sage: f != g - True - sage: g != f - True - - sage: f = Stream_function(lambda n: n if n > 0 else 0, False, -3) - sage: g = Stream_function(lambda n: n^2, False, 0) - sage: _ = g[5], f[1] - sage: f != g - False - sage: g != f - False - sage: _ = f[2] - sage: f != g - True - sage: g != f - True - - """ - # TODO: more cases, in particular mixed implementations, - # could be detected - if not isinstance(other, Stream_inexact): - return False - - if self._is_sparse and other._is_sparse: - for i in self._cache: - if i in other._cache and other._cache[i] != self._cache[i]: - return True - - elif not self._is_sparse and not other._is_sparse: - if ((self._true_order - and other._approximate_order > self._approximate_order) - or (other._true_order - and self._approximate_order > other._approximate_order)): - return True - - if not self._true_order or not other._true_order: - return False - - if any(i != j for i, j in zip(self._cache, other._cache)): - return True - - return False - class Stream_exact(Stream): r""" @@ -754,6 +702,31 @@ def __hash__(self): """ return hash((self._initial_coefficients, self._degree, self._constant)) + def _cache_iterator(self): + r""" + Iterate over the known ``(degree, coefficient)``-pairs. + """ + i = self._approximate_order + while True: + yield i, self[i] + i += 1 + + def is_nonzero(self): + r""" + Return ``True`` if and only if this stream is known + to be nonzero. + + An assumption of this class is that it is nonzero. + + EXAMPLES:: + + sage: from sage.data_structures.stream import Stream_exact + sage: g = Stream_exact([0, 1]) + sage: g.is_nonzero() + True + """ + return True + def __eq__(self, other): """ Return whether ``self`` and ``other`` are known to be equal. @@ -798,81 +771,6 @@ def __eq__(self, other): and self._initial_coefficients == other._initial_coefficients and self._constant == other._constant) - def __ne__(self, other): - """ - Return whether ``self`` and ``other`` are known to be different. - - The argument ``other`` may be exact or inexact, but is - assumed to be non-zero. - - INPUT: - - - ``other`` -- a stream - - EXAMPLES:: - - sage: from sage.data_structures.stream import Stream_exact - sage: s = Stream_exact([2], order=-1, degree=2, constant=1) - sage: t = Stream_exact([0, 2, 0], 1, 2, -2) - sage: s != t - False - sage: s = Stream_exact([2], constant=1) - sage: t = Stream_exact([2], order=-1, constant=1) - sage: s != t - True - - When it is not known, then both equality and inequality - return ``False``:: - - sage: from sage.data_structures.stream import Stream_function - sage: f = Stream_function(lambda n: 2 if n == 0 else 1, False, 0) - sage: s == f - False - sage: s != f - False - sage: [s[i] for i in range(-3, 5)] - [0, 0, 0, 2, 1, 1, 1, 1] - sage: [f[i] for i in range(-3, 5)] - [0, 0, 0, 2, 1, 1, 1, 1] - - """ - if isinstance(other, type(self)): - return (self._degree != other._degree - or self._approximate_order != other._approximate_order - or self._initial_coefficients != other._initial_coefficients - or self._constant != other._constant) - # if other is not exact, we can at least compare with the - # elements in its cache - if other._is_sparse: - for i in other._cache: - if self[i] != other._cache[i]: - return True - else: - if other._true_order: - return any(self[i] != c - for i, c in enumerate(other._cache, - other._approximate_order)) - if other._approximate_order > self._approximate_order: - return True - - return False - - def is_nonzero(self): - r""" - Return ``True`` if and only if this stream is known - to be nonzero. - - An assumption of this class is that it is nonzero. - - EXAMPLES:: - - sage: from sage.data_structures.stream import Stream_exact - sage: s = Stream_exact([2], order=-1, degree=2, constant=1) - sage: s.is_nonzero() - True - """ - return True - def _polynomial_part(self, R): """ Return the initial part of ``self`` as a Laurent polynomial in ``R``. @@ -1039,6 +937,23 @@ def iterate_coefficients(self): yield self._target[n] n += 1 + def is_nonzero(self): + r""" + Return ``True`` if and only if this stream is known + to be nonzero. + + An assumption of this class is that it is nonzero. + + EXAMPLES:: + + sage: from sage.data_structures.stream import Stream_uninitialized + sage: g = Stream_uninitialized(0) + sage: g.is_nonzero() + True + """ + if self._target is None: + return True + return super().is_nonzero() class Stream_unary(Stream_inexact): r""" @@ -1356,6 +1271,19 @@ def __hash__(self): """ return 0 + def __bool__(self): + r""" + Return ``True`` if ``self`` is not known to be zero. + + EXAMPLES:: + + sage: from sage.data_structures.stream import Stream_zero + sage: CS = Stream_zero() + sage: bool(CS) + False + """ + return False + ##################################################################### # Binary operations @@ -1572,6 +1500,14 @@ def is_nonzero(self): return self._left.is_nonzero() and self._right.is_nonzero() +class Stream_cauchy_mul_commutative(Stream_cauchy_mul, Stream_binaryCommutative): + """ + Operator for multiplication of two coefficient streams using the + Cauchy product for commutative multiplication of coefficients. + """ + pass + + class Stream_dirichlet_convolve(Stream_binary): r""" Operator for the Dirichlet convolution of two streams. @@ -2179,6 +2115,11 @@ class Stream_scalar(Stream_inexact): Base class for operators multiplying a coefficient stream by a scalar. + INPUT: + + - ``series`` -- a :class:`Stream` + - ``scalar`` -- a non-zero, non-one scalar + .. TODO:: This does not inherit from :class:`Stream_unary`, because of @@ -2292,7 +2233,7 @@ class Stream_rmul(Stream_scalar): INPUT: - ``series`` -- a :class:`Stream` - - ``scalar`` -- a scalar + - ``scalar`` -- a non-zero, non-one scalar EXAMPLES:: @@ -2333,7 +2274,7 @@ class Stream_lmul(Stream_scalar): INPUT: - ``series`` -- a :class:`Stream` - - ``scalar`` -- a scalar + - ``scalar`` -- a non-zero, non-one scalar EXAMPLES:: @@ -2602,6 +2543,11 @@ class Stream_map_coefficients(Stream_inexact): - ``series`` -- a :class:`Stream` - ``function`` -- a function that modifies the elements of the stream + .. WARNING:: + + We assume for equality that ``function`` is a function in the + mathematical sense. + EXAMPLES:: sage: from sage.data_structures.stream import (Stream_map_coefficients, Stream_function) @@ -2715,7 +2661,8 @@ def __eq__(self, other): class Stream_shift(Stream): """ - Operator for shifting a nonzero, nonexact stream. + Operator for shifting a nonexact stream which is not known to + be zero. Instances of this class share the cache with its input stream. @@ -2723,6 +2670,7 @@ class Stream_shift(Stream): - ``series`` -- a :class:`Stream` - ``shift`` -- an integer + """ def __init__(self, series, shift): """ @@ -2832,15 +2780,13 @@ def is_nonzero(self): Return ``True`` if and only if this stream is known to be nonzero. - An assumption of this class is that it is nonzero. - EXAMPLES:: - sage: from sage.data_structures.stream import (Stream_cauchy_invert, Stream_function) - sage: f = Stream_function(lambda n: n^2, False, 1) - sage: g = Stream_cauchy_invert(f) + sage: from sage.data_structures.stream import Stream_shift, Stream_function + sage: f = Stream_function(lambda n: 0, False, 1) + sage: g = Stream_shift(f, 3) sage: g.is_nonzero() - True + False """ return self._series.is_nonzero() @@ -3096,7 +3042,7 @@ def is_nonzero(self): class Stream_derivative(Stream_inexact): """ - Operator for taking derivatives of a stream. + Operator for taking derivatives of a non-exact stream. INPUT: @@ -3219,4 +3165,5 @@ def is_nonzero(self): sage: Stream_derivative(f, 2, True).is_nonzero() # it might be nice if this gave False True """ + # since self._series is not exact, this is correct return self._series.is_nonzero() diff --git a/src/sage/rings/lazy_series.py b/src/sage/rings/lazy_series.py index 8b0b8aa1dff..f127d99d687 100644 --- a/src/sage/rings/lazy_series.py +++ b/src/sage/rings/lazy_series.py @@ -195,6 +195,19 @@ sage: s = SymmetricFunctions(GF(2)).s() sage: L = LazySymmetricFunctions(s) sage: check(L, lambda n: sum(k*s(la) for k, la in enumerate(Partitions(n))), valuation=0) + +Check that we can invert matrices:: + + sage: L. = LazyLaurentSeriesRing(QQ) + sage: a11 = 1 + L(lambda n: 1 if not n else 0, valuation=0) + sage: a12 = 1 + L(lambda n: 1 if n == 1 else 0, valuation=0) + sage: a21 = 1 + L(lambda n: 1 if n == 2 else 0, valuation=0) + sage: a22 = 1 + L(lambda n: 1 if n == 3 else 0, valuation=0) + sage: m = matrix([[a11, a12], [a21, a22]]) + sage: m.inverse() + [ 1 + z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + O(z^7) -1 - 2*z - 3*z^2 - 4*z^3 - 5*z^4 - 6*z^5 - 7*z^6 + O(z^7)] + [ -1 - z - 3*z^2 - 3*z^3 - 5*z^4 - 5*z^5 - 7*z^6 + O(z^7) 2 + 2*z + 4*z^2 + 4*z^3 + 6*z^4 + 6*z^5 + 8*z^6 + O(z^7)] + """ # **************************************************************************** @@ -219,6 +232,7 @@ from sage.combinat.partition import Partition, Partitions from sage.misc.derivative import derivative_parse from sage.categories.integral_domains import IntegralDomains +from sage.categories.rings import Rings from sage.rings.infinity import infinity from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ @@ -228,6 +242,7 @@ from sage.data_structures.stream import ( Stream_add, Stream_cauchy_mul, + Stream_cauchy_mul_commutative, Stream_sub, Stream_cauchy_compose, Stream_lmul, @@ -897,12 +912,12 @@ def _richcmp_(self, other, op): Compare ``self`` with ``other`` with respect to the comparison operator ``op``. - Equality is verified if the corresponding coefficients of both series - can be checked for equality without computing coefficients - indefinitely. Otherwise an exception is raised to declare that - equality is not decidable. - - Inequality is not defined for lazy Laurent series. + Equality is verified if the corresponding coefficients of + both series can be checked for equality without computing + coefficients indefinitely. This is the case if ``self`` and + ``other`` are trivially equal, either by construction, or + because they are known to have only finitely many + coefficients. INPUT: @@ -941,43 +956,22 @@ def _richcmp_(self, other, op): """ if op is op_EQ: - if isinstance(self._coeff_stream, Stream_zero): - if isinstance(other._coeff_stream, Stream_zero): - return True - if other._coeff_stream.is_nonzero(): - return False - elif isinstance(other._coeff_stream, Stream_zero): - if self._coeff_stream.is_nonzero(): - return False - elif isinstance(self._coeff_stream, Stream_exact): - if isinstance(other._coeff_stream, Stream_exact): - return self._coeff_stream == other._coeff_stream - if self._coeff_stream != other._coeff_stream: - return False - elif isinstance(other._coeff_stream, Stream_exact): - if other._coeff_stream != self._coeff_stream: - return False - else: - # both streams are inexact, perhaps they are equal by - # construction - if self._coeff_stream == other._coeff_stream: - return True - # perhaps their caches are different - if self._coeff_stream != other._coeff_stream: - return False - - # undecidable otherwise + # they may be trivially equal + if self._coeff_stream == other._coeff_stream: + return True + # they may be trivially different + if self._coeff_stream != other._coeff_stream: + return False prec = self.parent().options['halting_precision'] if prec is None: raise ValueError("undecidable") - # at least one of the approximate orders is not infinity + # otherwise we check the first prec coefficients m = min(self._coeff_stream._approximate_order, other._coeff_stream._approximate_order) return all(self[i] == other[i] for i in range(m, m + prec)) if op is op_NE: return not (self == other) - return False def __hash__(self): @@ -998,11 +992,7 @@ def __hash__(self): def __bool__(self): """ - Test whether ``self`` is not zero. - - An uninitialized series returns ``True`` as it is considered - as a formal variable, such as a generator of a polynomial - ring. + Return ``True`` if ``self`` is not known to be zero. TESTS:: @@ -1021,7 +1011,7 @@ def __bool__(self): sage: bool(M) Traceback (most recent call last): ... - ValueError: undecidable as lazy Laurent series + ValueError: undecidable sage: M[15] 1 sage: bool(M) @@ -1033,7 +1023,7 @@ def __bool__(self): sage: bool(M) Traceback (most recent call last): ... - ValueError: undecidable as lazy Laurent series + ValueError: undecidable sage: M[15] 1 sage: bool(M) @@ -1060,35 +1050,11 @@ def __bool__(self): True sage: g.define(1 + z*g) sage: bool(g) - True + Traceback (most recent call last): + ... + ValueError: undecidable """ - if isinstance(self._coeff_stream, Stream_zero): - return False - if isinstance(self._coeff_stream, Stream_exact): - return True - if isinstance(self._coeff_stream, Stream_uninitialized): - if self._coeff_stream._target is None: - return True - if isinstance(self._coeff_stream._target, Stream_zero): - return False - if isinstance(self._coeff_stream._target, Stream_exact): - return True - if self._coeff_stream._is_sparse: - cache = self._coeff_stream._cache - if any(cache[a] for a in cache): - return True - else: - if any(a for a in self._coeff_stream._cache): - return True - - v = self._coeff_stream._approximate_order - if self[v]: - return True - - prec = self.parent().options['halting_precision'] - if prec is None: - raise ValueError("undecidable as lazy Laurent series") - return any(self[i] for i in range(v, v + prec)) + return not (self == self.parent().zero()) def define(self, s): r""" @@ -1110,7 +1076,7 @@ def define(self, s): sage: binomial(2000, 1000) / C[1000] 1001 - The Catalan numbers but with a valuation 1:: + The Catalan numbers but with a valuation `1`:: sage: B = L.undefined(valuation=1) sage: B.define(z + B^2) @@ -1864,7 +1830,7 @@ def _acted_upon_(self, scalar, self_on_left): order=v, constant=c, degree=coeff_stream._degree)) - if self_on_left or R.is_commutative(): + if self_on_left or R in Rings().Commutative(): return P.element_class(P, Stream_lmul(coeff_stream, scalar, P.is_sparse())) return P.element_class(P, Stream_rmul(coeff_stream, scalar, @@ -2822,6 +2788,9 @@ def _mul_(self, other): and right.order() == 0 and not right._constant): return self # right == 1 + if ((isinstance(left, Stream_cauchy_invert) and left._series == right) + or (isinstance(right, Stream_cauchy_invert) and right._series == left)): + return P.one() # The product is exact if and only if both factors are exact # and one of the factors has eventually 0 coefficients: # (p + a x^d/(1-x))(q + b x^e/(1-x)) @@ -2867,7 +2836,11 @@ def _mul_(self, other): constant=c) return P.element_class(P, coeff_stream) - return P.element_class(P, Stream_cauchy_mul(left, right, P.is_sparse())) + if P in Rings().Commutative(): + coeff_stream = Stream_cauchy_mul_commutative(left, right, P.is_sparse()) + else: + coeff_stream = Stream_cauchy_mul(left, right, P.is_sparse()) + return P.element_class(P, coeff_stream) def __pow__(self, n): r""" @@ -3000,7 +2973,7 @@ def __invert__(self): sage: g = L([2], valuation=-1, constant=1); g 2*x^-1 + 1 + x + x^2 + O(x^3) sage: g * g^-1 - 1 + O(x^7) + 1 sage: L. = LazyPowerSeriesRing(QQ) sage: ~(x + x^2) @@ -3163,7 +3136,7 @@ def _div_(self, other): return self # self is right - if left is right: + if left == right: return P.one() if (P._minimal_valuation is not None @@ -3238,7 +3211,11 @@ def _div_(self, other): # P._minimal_valuation is zero, because we allow division by # series of positive valuation right_inverse = Stream_cauchy_invert(right) - return P.element_class(P, Stream_cauchy_mul(left, right_inverse, P.is_sparse())) + if P in Rings().Commutative(): + coeff_stream = Stream_cauchy_mul_commutative(left, right_inverse, P.is_sparse()) + else: + coeff_stream = Stream_cauchy_mul(left, right_inverse, P.is_sparse()) + return P.element_class(P, coeff_stream) def _floordiv_(self, other): @@ -3330,7 +3307,10 @@ def exp(self): d_self = Stream_function(lambda n: (n + 1) * coeff_stream[n + 1], False, 0) f = P.undefined(valuation=0) - d_self_f = Stream_cauchy_mul(d_self, f._coeff_stream, False) + if P in Rings().Commutative(): + d_self_f = Stream_cauchy_mul_commutative(d_self, f._coeff_stream, False) + else: + d_self_f = Stream_cauchy_mul(d_self, f._coeff_stream, False) int_d_self_f = Stream_function(lambda n: d_self_f[n-1] / R(n) if n else R.one(), False, 0) f._coeff_stream._target = int_d_self_f @@ -3379,9 +3359,15 @@ def log(self): # multivariate power series d_self = Stream_function(lambda n: (n + 1) * coeff_stream[n + 1], P.is_sparse(), 0) - d_self_quo_self = Stream_cauchy_mul(d_self, - Stream_cauchy_invert(coeff_stream), - P.is_sparse()) + coeff_stream_inverse = Stream_cauchy_invert(coeff_stream) + if P in Rings().Commutative(): + d_self_quo_self = Stream_cauchy_mul_commutative(d_self, + coeff_stream_inverse, + P.is_sparse()) + else: + d_self_quo_self = Stream_cauchy_mul(d_self, + coeff_stream_inverse, + P.is_sparse()) int_d_self_quo_self = Stream_function(lambda n: d_self_quo_self[n-1] / R(n), P.is_sparse(), 1) return P.element_class(P, int_d_self_quo_self) @@ -4662,6 +4648,16 @@ def __call__(self, *g, check=True): sage: g.define((z - (f - z)(g))) sage: g z - z^2 + 2*z^3 - 6*z^4 + 20*z^5 - 70*z^6 + 256*z^7 + O(z^8) + + Check that issue :trac:`35071` is fixed:: + + sage: L. = LazyPowerSeriesRing(QQ) + sage: f = z^2 + sage: g = L.undefined(valuation=1) + sage: g.define(z*f(f(g))) + sage: g + O(z^8) + """ fP = parent(self) if len(g) != fP._arity: diff --git a/src/sage/rings/lazy_series_ring.py b/src/sage/rings/lazy_series_ring.py index 9f942c93251..841dd34b5a8 100644 --- a/src/sage/rings/lazy_series_ring.py +++ b/src/sage/rings/lazy_series_ring.py @@ -664,8 +664,8 @@ class options(GlobalOptions): description='the number of coefficients to display for nonzero constant series', checker=lambda x: x in ZZ and x > 0) halting_precision = dict(default=None, - description='the number of coefficients, beginning with the approximate valuation, to check in equality tests', - checker=lambda x: x is None or x in ZZ and x > 0) + description='the number of coefficients, beginning with the approximate valuation, to check in equality tests', + checker=lambda x: x is None or x in ZZ and x > 0) @cached_method def one(self): @@ -2262,10 +2262,10 @@ def __init__(self, basis, sparse=True, category=None): if basis not in GradedAlgebrasWithBasis: raise ValueError("basis should be in GradedAlgebrasWithBasis") self._arity = 1 - category = Algebras(base_ring.category()) - if base_ring in IntegralDomains(): + category = Algebras(basis.category()) + if basis in IntegralDomains(): category &= IntegralDomains() - elif base_ring in Rings().Commutative(): + elif basis in Rings().Commutative(): category = category.Commutative() if base_ring.is_zero():