#17965: Uniformization of the API to compute the inverse of an element.
------------------------------+------------------------
       Reporter:  nthiery     |        Owner:
           Type:  defect      |       Status:  new
       Priority:  major       |    Milestone:  sage-6.6
      Component:  categories  |   Resolution:
       Keywords:              |    Merged in:
        Authors:              |    Reviewers:
Report Upstream:  N/A         |  Work issues:
         Branch:              |       Commit:
   Dependencies:              |     Stopgaps:
------------------------------+------------------------
Description changed by nthiery:

Old description:

> 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.

New description:

 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.

--

--
Ticket URL: <http://trac.sagemath.org/ticket/17965#comment:1>
Sage <http://www.sagemath.org>
Sage: Creating a Viable Open Source Alternative to Magma, Maple, Mathematica, 
and MATLAB

-- 
You received this message because you are subscribed to the Google Groups 
"sage-trac" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/sage-trac.
For more options, visit https://groups.google.com/d/optout.

Reply via email to