Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

make FreeAlgebra graded and provide is_unit and __invert__ #37199

Merged
merged 6 commits into from
Feb 13, 2024

Conversation

mantepse
Copy link
Collaborator

The final goal is to allow computations in the completion in the free algebra, that is,

sage: A.<x,y> = FreeAlgebra(ZZ)
sage: L = A.completion()
sage: ~L(1 - x - y^2)
1 + x + (x^2+y^2) + (x^3+x*y^2+y^2*x) + (x^4+x^2*y^2+x*y^2*x+y^2*x^2+y^4) + (x^5+x^3*y^2+x^2*y^2*x+x*y^2*x^2+x*y^4+y^2*x^3+y^2*x*y^2+y^4*x) + (x^6+x^4*y^2+x^3*y^2*x+x^2*y^2*x^2+x^2*y^4+x*y^2*x^3+x*y^2*x*y^2+x*y^4*x+y^2*x^4+y^2*x^2*y^2+y^2*x*y^2*x+y^4*x^2+y^6) + O^7

@mantepse
Copy link
Collaborator Author

There is still a small bug:

sage: A.<x,y> = FreeAlgebra(QQ)
sage: 1/A(2)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[29], line 1
----> 1 Integer(1)/A(Integer(2))

File ~/sage-trac/src/sage/rings/integer.pyx:2033, in sage.rings.integer.Integer.__truediv__()
   2031         return y
   2032 
-> 2033     return coercion_model.bin_op(left, right, operator.truediv)
   2034 
   2035 cpdef _div_(self, right) noexcept:

File ~/sage-trac/src/sage/structure/coerce.pyx:1234, in sage.structure.coerce.CoercionModel.bin_op()
   1232     self._record_exception()
   1233 else:
-> 1234     return PyObject_CallObject(op, xy)
   1235 
   1236 if op is mul:

File ~/sage-trac/src/sage/modules/with_basis/indexed_element.pyx:980, in sage.modules.with_basis.indexed_element.IndexedFreeModuleElement.__truediv__()
    978                           for k, c in D.items()})
    979 
--> 980 x_inv = B(x) ** -1
    981 return type(self)(F, scal(x_inv, D))
    982 

File ~/sage-trac/src/sage/structure/parent.pyx:901, in sage.structure.parent.Parent.__call__()
    899 if mor is not None:
    900     if no_extra_args:
--> 901         return mor._call_(x)
    902     else:
    903         return mor._call_with_args(x, args, kwds)

File ~/sage-trac/src/sage/structure/coerce_maps.pyx:163, in sage.structure.coerce_maps.DefaultConvertMap_unique._call_()
    161             print(type(C), C)
    162             print(type(C._element_constructor), C._element_constructor)
--> 163         raise
    164 
    165 cpdef Element _call_with_args(self, x, args=(), kwds={}) noexcept:

File ~/sage-trac/src/sage/structure/coerce_maps.pyx:158, in sage.structure.coerce_maps.DefaultConvertMap_unique._call_()
    156 cdef Parent C = self._codomain
    157 try:
--> 158     return C._element_constructor(x)
    159 except Exception:
    160     if print_warnings:

File ~/sage-trac/src/sage/rings/rational.pyx:547, in sage.rings.rational.Rational.__init__()
    545     """
    546     if x is not None:
--> 547         self.__set_value(x, base)
    548 
    549 def __reduce__(self):

File ~/sage-trac/src/sage/rings/rational.pyx:692, in sage.rings.rational.Rational._Rational__set_value()
    690 
    691         else:
--> 692             raise TypeError("unable to convert {!r} to a rational".format(x))
    693 
    694     cdef void set_from_mpq(Rational self, mpq_t value) noexcept:

TypeError: unable to convert 2 to a rational

@tscrim
Copy link
Collaborator

tscrim commented Jan 31, 2024

While I generally would like this, there is a small issue of morphisms to a non-graded algebra. This is analogous to why polynomial rings aren't graded by default. Although evaluations are typically not performed on a free algebra, they still define valid morphism. Just something to keep in mind at this point.

IMO, that is not a bug. We don't have a fraction field for the free algebra. (Of course, the error message doesn't express this point.) However, we could do a bit better with inverting elements in the base ring. Although I would say the thing that should work is inverse_of_unit() since inverting elements is suppose to return an element in a field where the division generically makes sense (e.g., 4 / 2 or (x^2 + x) / (x + 1) in QQ['x']). (There are some exceptions to this, such as Laurent polynomials, as the benefits outweigh the consistency break.)

@tscrim
Copy link
Collaborator

tscrim commented Jan 31, 2024

Having the degrees as input to indicate grading is desired is a great idea! Would it be a lot of trouble to allow an integer as input (which is applied to all generators)? This is mostly meant as a shorthand convenience.

We should apply that to polynomial rings as well...

@tscrim
Copy link
Collaborator

tscrim commented Jan 31, 2024

Closes #34406

Copy link
Collaborator

@tscrim tscrim left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you. Just a few other things. I will probably do a followup generalizing this to allow more general grading groups.

sage: ~A(1 + x)
Traceback (most recent call last):
...
ZeroDivisionError: element is not invertible
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this is the correct type of error. It should either be an ArithmeticError or ValueError to match other parts of Sage. Admittedly, we don't seem to be very consistent about this...

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that ValueError is not very precise. Anyway, just tell me which one you like best. It might actually make sense to unify in a followup ticket (with an awful amount of deprecation?)

  • 21 ValueError('{} is not invertible')
  • 11 ZeroDivisionError("element is not invertible")
  • 10 TypeError('the A-basis is defined only when 2 is invertible')
  • 8 ArithmeticError("self must be invertible to have a multiplicative order")
  • 2 RuntimeError("morphism is not invertible")
  • 2 NotImplementedError("matrix must be invertible")
grep -r --include=*.{py,pyx} --color -nH --null -e "Error(.*invertible" *
algebras/clifford_algebra.py\01093:            raise ValueError('{} is not invertible')
algebras/quatalg/quaternion_algebra.py\0269:            raise ValueError("2 is not invertible in %s" % K)
algebras/quatalg/quaternion_algebra.py\0271:            raise ValueError("defining elements of quaternion algebra (%s, %s) are not invertible in %s"
algebras/free_algebra_element.py\0253:        raise ZeroDivisionError("element is not invertible")
algebras/jordan_algebra.py\01182:            raise ValueError("2 must be invertible")
algebras/iwahori_hecke_algebra.py\01424:                raise ValueError("%s and %s must be invertible" % (A._q1, A._q2))
algebras/iwahori_hecke_algebra.py\02512:                raise TypeError('the A-basis is defined only when 2 is invertible')
algebras/iwahori_hecke_algebra.py\02644:                raise TypeError('the B-basis is defined only when 2 is invertible')
algebras/finite_dimensional_algebras/finite_dimensional_algebra_element.pyx\0596:            raise ZeroDivisionError("element is not invertible")
algebras/askey_wilson.py\0238:            raise ValueError("q={} is not invertible in {}".format(q, R))
arith/misc.py\03913:                raise ZeroDivisionError("factorial({}) not invertible in {}".format(m, P))
categories/finite_dimensional_modules_with_basis.py\0733:                raise RuntimeError("morphism is not invertible")
categories/commutative_rings.py\0352:                    raise ValueError("%s is not invertible in %s" % (q,self))
combinat/root_system/root_lattice_realizations.py\01479:                raise TypeError("The Cartan matrix is not invertible")
combinat/posets/incidence_algebras.py\0424:                raise ValueError("element is not invertible")
combinat/regular_sequence.py\01904:                raise RuntimeError('no invertible submatrix found')
crypto/classical_cipher.py\0238:            raise ValueError("Argument\n\n%s\n\nmust be an invertible cipher." % self)
crypto/classical.py\01509:            raise ValueError("Argument:\n\n%s\n\nis not invertible." % (A))
dynamics/arithmetic_dynamics/projective_ds.py\01963:            raise TypeError("matrix must be invertible and size dimension + 1")
geometry/hyperbolic_space/hyperbolic_isometry.py\01093:    raise TypeError("A must be an invertible 2x2 matrix over the"
groups/affine_gps/affine_group.py\0262:            raise TypeError('A must be invertible')
groups/matrix_gps/matrix_group.py\0150:            raise TypeError('matrix is not invertible')
groups/matrix_gps/finitely_generated.py\0292:        raise ValueError('each generator must be an invertible matrix')
manifolds/chart.py\03561:            raise ValueError("the change of coordinates is not invertible " +
matrix/matrix0.pyx\04983:            raise ArithmeticError("self must be invertible to have a multiplicative order")
matrix/matrix0.pyx\05868:                raise ArithmeticError("non-invertible matrix")
matrix/matrix_integer_dense.pyx\04131:            raise ArithmeticError("non-invertible matrix")
modular/btquotients/btquotient.py\0561:            raise NotImplementedError("matrix must be invertible")
modular/modform/eis_series.py\0140:            raise ValueError("The denominator of -B_k/(2*k) (=%s) must be invertible in the ring %s" % (a0den, K))
modular/modform/eis_series.py\0146:            raise ValueError("The numerator of -B_k/(2*k) (=%s) must be invertible in the ring %s" % (a0num, K))
modules/with_basis/morphism.py\0811:            raise ValueError("Non invertible morphism")
modules/with_basis/morphism.py\0813:            raise ValueError("Morphism not known to be invertible; see the invertible option of module_morphism")
modules/matrix_morphism.py\0267:            raise ZeroDivisionError("matrix morphism not invertible")
modules/matrix_morphism.py\0271:            raise ZeroDivisionError("matrix morphism not invertible")
numerical/interactive_simplex_method.py\04899:            raise ValueError("eta matrix is not invertible due to incompatible "
quadratic_forms/genera/genus.py\0871:        raise ArithmeticError("given matrix is not invertible")
rings/tate_algebra_element.pyx\01470:            raise ValueError("this series in not invertible")
rings/number_field/number_field_element.pyx\0153:        raise ZeroDivisionError("%s is not invertible modulo %s" % (elt, I))
rings/number_field/number_field_ideal.py\02802:            raise TypeError("the element must be invertible mod the ideal")
rings/padics/padic_relaxed_errors.pyx\060:        raise ZeroDivisionError("denominator is not invertible")
rings/polynomial/polynomial_element.pyx\011036:                raise ArithmeticError("constant coefficient not invertible in base ring")
rings/polynomial/polynomial_element.pyx\011041:                raise ArithmeticError("exponent not invertible in base ring")
rings/polynomial/polynomial_quotient_ring_element.py\0427:            raise ZeroDivisionError("element %s of quotient polynomial ring not invertible" % self)
rings/polynomial/polynomial_quotient_ring_element.py\0445:            raise ZeroDivisionError("element %s of quotient polynomial ring not invertible" % self)
rings/polynomial/multi_polynomial.pyx\01986:            raise ArithmeticError("element is non-invertible")
rings/polynomial/skew_polynomial_element.pyx\0649:            raise NotImplementedError("the leading coefficient of the divisor is not invertible")
rings/polynomial/polynomial_zmod_flint.pyx\0748:            raise ValueError("leading coefficient must be invertible")
rings/polynomial/polynomial_zmod_flint.pyx\0864:            raise ValueError("the integers 1 up to n={} are required to be invertible over the base field".format(n-1))
rings/localization.py\0706:            raise ValueError('all given elements are invertible in %s' % (base_ring))
rings/function_field/drinfeld_modules/morphism.py\0553:            raise ZeroDivisionError("this morphism is not invertible")
schemes/hyperelliptic_curves/monsky_washnitzer.py\0524:            raise ArithmeticError("2 and 3 must be invertible in the "
schemes/hyperelliptic_curves/monsky_washnitzer.py\01983:            raise ZeroDivisionError("element not invertible")
tensor/modules/free_module_linear_group.py\0380:                    raise TypeError("the {} is not invertible ".format(tens))
tensor/modules/free_module_linear_group.py\0397:                    raise TypeError("the {} is not invertible ".format(endo))

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would say ArithmeticError. For the types of errors involved here, we don't need any deprecation, but some internal code might need to change. At least with the tracebacks people downstream should be able to easily fix their code if they are catching the wrong type of errors. Although such a large change/standardization deserves a sage-devel post.

src/sage/algebras/free_algebra_element.py Outdated Show resolved Hide resolved
src/sage/algebras/free_algebra_element.py Outdated Show resolved Hide resolved
src/sage/algebras/free_algebra.py Outdated Show resolved Hide resolved
src/sage/algebras/free_algebra.py Outdated Show resolved Hide resolved
src/sage/algebras/free_algebra.py Outdated Show resolved Hide resolved
src/sage/algebras/free_algebra.py Outdated Show resolved Hide resolved
Copy link

github-actions bot commented Feb 5, 2024

Documentation preview for this PR (built with commit f621c7f; changes) is ready! 🎉

Copy link
Collaborator

@tscrim tscrim left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you.

vbraun pushed a commit to vbraun/sage that referenced this pull request Feb 7, 2024
…nvert__

    
The final goal is to allow computations in the completion in the free
algebra, that is,
```
sage: A.<x,y> = FreeAlgebra(ZZ)
sage: L = A.completion()
sage: ~L(1 - x - y^2)
1 + x + (x^2+y^2) + (x^3+x*y^2+y^2*x) +
(x^4+x^2*y^2+x*y^2*x+y^2*x^2+y^4) +
(x^5+x^3*y^2+x^2*y^2*x+x*y^2*x^2+x*y^4+y^2*x^3+y^2*x*y^2+y^4*x) + (x^6+x
^4*y^2+x^3*y^2*x+x^2*y^2*x^2+x^2*y^4+x*y^2*x^3+x*y^2*x*y^2+x*y^4*x+y^2*x
^4+y^2*x^2*y^2+y^2*x*y^2*x+y^4*x^2+y^6) + O^7
```
    
URL: sagemath#37199
Reported by: Martin Rubey
Reviewer(s): Martin Rubey, Travis Scrimshaw
@vbraun vbraun merged commit f396146 into sagemath:develop Feb 13, 2024
21 of 22 checks passed
@mantepse mantepse deleted the free_algebra/graded branch February 14, 2024 10:52
@mkoeppe mkoeppe added this to the sage-10.3 milestone Mar 7, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants