Skip to content

Uniformize the API to compute the inverse of an element #17965

@nthiery

Description

@nthiery

Some classes in Sage implement the inverse of an element through the
inverse method:

mistral-/opt/sage/src/sage>grep "def inverse(" **/*.py
algebras/finite_dimensional_algebras/finite_dimensional_algebra_element.py:    def inverse(self):
algebras/iwahori_hecke_algebra.py:            def inverse(self):
categories/coxeter_groups.py:        def inverse(self):
combinat/affine_permutation.py:    def inverse(self):
combinat/permutation.py:    def inverse(self):
combinat/tableau_tuple.py:    def inverse(self,k):
crypto/classical_cipher.py:    def inverse(self):
crypto/classical_cipher.py:    def inverse(self):
crypto/classical_cipher.py:    def inverse(self):
crypto/classical_cipher.py:    def inverse(self):
dynamics/interval_exchanges/iet.py:    def inverse(self):
groups/abelian_gps/element_base.py:    def inverse(self):
groups/abelian_gps/values.py:    def inverse(self):
groups/affine_gps/group_element.py:    def inverse(self):
modules/matrix_morphism.py:    def inverse(self):
rings/number_field/class_group.py:    def inverse(self):
rings/universal_cyclotomic_field/universal_cyclotomic_field.py:        def inverse(self):
schemes/elliptic_curves/formal_group.py:    def inverse(self, prec=20):
schemes/elliptic_curves/weierstrass_transform.py:    def inverse(self):

Some other through the __invert__ method:

mistral-/opt/sage/src/sage>grep "def __invert__(" **/*.py 
categories/algebras_with_basis.py:        def __invert__(self):
categories/magmas.py:                def __invert__(self):
categories/modules_with_basis.py:    def __invert__(self):
categories/modules_with_basis.py:    def __invert__(self):
combinat/combinatorial_algebra.py:    def __invert__(self):
combinat/sf/dual.py:        def __invert__(self):
combinat/species/generating_series.py:    def __invert__(self):
groups/indexed_free_group.py:        def __invert__(self):
groups/indexed_free_group.py:        def __invert__(self):
groups/matrix_gps/group_element.py:    def __invert__(self):
groups/raag.py:        def __invert__(self):
libs/coxeter3/coxeter_group.py:        def __invert__(self):
logic/boolformula.py:    def __invert__(self):
misc/sage_input.py:    def __invert__(self):
modular/dirichlet.py:    def __invert__(self):
modular/local_comp/smoothchar.py:    def __invert__(self):
modules/matrix_morphism.py:    def __invert__(self):
rings/continued_fraction.py:    def __invert__(self):
rings/finite_rings/element_ext_pari.py:    def __invert__(self):
rings/function_field/function_field_ideal.py:    def __invert__(self):
rings/infinity.py:    def __invert__(self):
rings/multi_power_series_ring_element.py:    def __invert__(self):
rings/number_field/morphism.py:    def __invert__(self):
rings/number_field/number_field_ideal.py:    def __invert__(self):
rings/number_field/number_field_ideal_rel.py:    def __invert__(self):
rings/pari_ring.py:    def __invert__(self):
rings/polynomial/polynomial_quotient_ring_element.py:    def __invert__(self):
rings/qqbar.py:    def __invert__(self):
rings/quotient_ring_element.py:    def __invert__(self):
rings/universal_cyclotomic_field/universal_cyclotomic_field.py:        def __invert__(self):
sandpiles/sandpile.py:    def __invert__(self):
schemes/elliptic_curves/heegner.py:    def __invert__(self):
schemes/elliptic_curves/height.py:    def __invert__(self):
schemes/elliptic_curves/weierstrass_morphism.py:    def __invert__(self):
schemes/elliptic_curves/weierstrass_morphism.py:    def __invert__(self):
schemes/hyperelliptic_curves/monsky_washnitzer.py:    def __invert__(self):
structure/factorization.py:    def __invert__(self):

Usually they provide a crosslink so that __invert__ and
inverse are equivalent, but this is done on a case by case bases,
so of course such links are missing here and there:

sage: ~AA(sqrt(~2))
1.414213562373095?
sage: AA(sqrt(~2)).inverse()
...
AttributeError: 'AlgebraicReal' object has no attribute 'inverse'
sage: R.<u,v,w> = QQ[]
sage: f = EllipticCurve_from_cubic(u^3 + v^3 + w^3, [1,-1,0], morphism=True)
sage: f.inverse()
Scheme morphism:
...
sage: ~f
...
TypeError: bad operand type for unary ~: 'WeierstrassTransformationWithInverse_class'

Shall we change the code to systematically implement __invert__ as
per Python's convention, and then implement the cross link inverse
-> __invert__ once for all high up in the class hierarchy,
typically in Magmas.ElementMethods?

Caveat: this won't cover all cases since we have invertible elements
that don't belong to a magma; e.g. a isomorphisms between two
different parents; so it will still be necessary to handle a couple
special cases by hand.

See also comment about __inverse__ in
sage.categories.coxeter_groups.py around line 699.

Note: the default implementation ~f = 1/f provided by Element should
probably be implemented in Monoids.ElementMethods; see also #17692.

Note: the qqbar classes also implement an invert method, but that's
for a slightly different use case. So we may, or not, want to make
this uniform too. invert does not fit Sage's usual verb/noun
convention since it's a verb while it is not inplace.

CC: @saliola @videlec @simon-king-jena @slel @tscrim

Component: categories

Author: Frédéric Chapoton

Branch/Commit: 312a91d

Reviewer: Travis Scrimshaw

Issue created by migration from https://trac.sagemath.org/ticket/17965

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions