Ticket #383: 383-binop-decorator.patch

File 383-binop-decorator.patch, 25.6 KB (added by robertwb, 11 years ago)
  • sage/rings/integer.pyx

    Generic coercion binop decorator, Fix #383
    
    diff -r 8f6e2da7a63e sage/rings/integer.pyx
    a b  
    159159import sage.rings.infinity
    160160import sage.libs.pari.all
    161161
     162from sage.structure.element import canonical_coercion
     163
    162164cdef object numpy_long_interface = {'typestr': '=i4' if sizeof(long) == 4 else '=i8' }
    163165cdef object numpy_int64_interface = {'typestr': '=i8'}
    164166cdef object numpy_object_interface = {'typestr': '|O'}
     
    25322534            sage: q, r = a.quo_rem(b)
    25332535            sage: q*b + r == a
    25342536            True
     2537
     2538            sage: 3.quo_rem(ZZ['x'].0)
     2539            (0, 3)
    25352540        """
    25362541        cdef Integer q = PY_NEW(Integer)
    25372542        cdef Integer r = PY_NEW(Integer)
     
    25502555                    mpz_sub_ui(q.value, q.value, 1)
    25512556                    mpz_sub_ui(r.value, r.value, -d)
    25522557               
    2553         else:
    2554             if not PY_TYPE_CHECK_EXACT(other, Integer):
    2555                 other = Integer(other)
     2558        elif PY_TYPE_CHECK_EXACT(other, Integer):
    25562559            if mpz_sgn((<Integer>other).value) == 0:
    25572560                raise ZeroDivisionError, "Integer division by zero"
    25582561            if mpz_size((<Integer>x).value) > 100000:
     
    25612564                _sig_off
    25622565            else:
    25632566                mpz_fdiv_qr(q.value, r.value, self.value, (<Integer>other).value)
     2567               
     2568        else:
     2569            left, right = canonical_coercion(self, other)
     2570            return left.quo_rem(right)
    25642571       
    25652572        return q, r
    25662573
     
    48324839            sage: gcd(21,2^6)
    48334840            1
    48344841        """
     4842        if not isinstance(n, Integer) and not isinstance(n, int):
     4843            left, right = canonical_coercion(self, n)
     4844            return left.gcd(right)
    48354845        cdef Integer m = as_Integer(n)
    48364846        cdef Integer g = <Integer>PY_NEW(Integer)
    48374847        _sig_on
  • sage/rings/polynomial/multi_polynomial_element.py

    diff -r 8f6e2da7a63e sage/rings/polynomial/multi_polynomial_element.py
    a b  
    5656
    5757from sage.rings.arith import gcd
    5858
    59 from sage.structure.element import CommutativeRingElement, canonical_coercion
     59from sage.structure.element import CommutativeRingElement, canonical_coercion, coerce_binop
    6060
    6161from sage.interfaces.all import macaulay2
    6262
     
    15031503    #    P._singular_().set_ring()
    15041504    #    return P(self._singular_().gcd(f._singular_()))
    15051505
     1506    @coerce_binop
    15061507    def quo_rem(self, right):
    15071508        """
    15081509        Returns quotient and remainder of self and right.
  • sage/rings/polynomial/multi_polynomial_libsingular.pyx

    diff -r 8f6e2da7a63e sage/rings/polynomial/multi_polynomial_libsingular.pyx
    a b  
    191191from sage.rings.number_field.number_field_base cimport NumberField
    192192
    193193from sage.rings.arith import gcd
     194from sage.structure.element import coerce_binop
    194195
    195196from sage.structure.parent cimport Parent
    196197from sage.structure.parent_base cimport ParentWithBase
     
    36813682        id_Delete(&_I,r)
    36823683        return new_MP(parent,res)
    36833684
     3685    @coerce_binop
    36843686    def gcd(self, right, algorithm=None, **kwds):
    36853687        """
    36863688        Return the greatest common divisor of self and right.
     
    37973799        res = new_MP((<MPolynomialRing_libsingular>self._parent), _res)
    37983800        return res
    37993801
     3802    @coerce_binop
    38003803    def lcm(self, MPolynomial_libsingular g):
    38013804        """
    38023805        Return the least common multiple of self and g.
     
    38793882
    38803883        return bool(singclap_isSqrFree(self._poly))
    38813884
     3885    @coerce_binop
    38823886    def quo_rem(self, MPolynomial_libsingular right):
    38833887        """
    38843888        Returns quotient and remainder of self and right.
     
    39173921        cdef ring *r = (<MPolynomialRing_libsingular>self._parent)._ring
    39183922        if(r != currRing): rChangeCurrRing(r)
    39193923
    3920         if self._parent is not right._parent:
    3921             right = self._parent._coerce_c(right)
    3922 
    39233924        if right.is_zero():
    39243925            raise ZeroDivisionError
    39253926
  • sage/rings/polynomial/pbori.pyx

    diff -r 8f6e2da7a63e sage/rings/polynomial/pbori.pyx
    a b  
    194194
    195195from sage.structure.parent cimport Parent
    196196from sage.structure.sequence import Sequence
     197from sage.structure.element import coerce_binop
    197198
    198199from sage.categories.action cimport Action
    199200
     
    23252326        """
    23262327        return self.set().navigation()
    23272328
     2329    @coerce_binop
    23282330    def gcd(self, BooleanMonomial rhs):
    23292331        """
    23302332        Return the greatest common divisor of this boolean monomial
  • sage/rings/polynomial/polynomial_element.pyx

    diff -r 8f6e2da7a63e sage/rings/polynomial/polynomial_element.pyx
    a b  
    4343from sage.misc.sage_eval import sage_eval
    4444from sage.misc.latex import latex
    4545from sage.structure.factorization import Factorization
     46from sage.structure.element import coerce_binop
    4647
    4748from sage.interfaces.all import singular as singular_default, is_SingularElement
    4849from sage.libs.all import pari, pari_gen, PariError
     
    27702771            pari.set_real_precision(n)  # restore precision
    27712772        return Factorization(F, unit)
    27722773
     2774    @coerce_binop
    27732775    def lcm(self, other):
    27742776        """
    27752777        Let f and g be two polynomials. Then this function returns the
     
    36703672
    36713673    ######################################################################
    36723674   
     3675    @coerce_binop
    36733676    def resultant(self, other):
    36743677        r"""
    36753678        Returns the resultant of self and other.
     
    37293732            ...
    37303733            PariError: (8)
    37313734        """
    3732         other = self.parent()._coerce_(other)
    37333735        variable = self.parent().gen()._pari_()
    37343736        # The 0 flag tells PARI to use exact arithmetic       
    37353737        res = self._pari_().polresultant(other._pari_(), variable, 0)
  • sage/rings/polynomial/polynomial_element_generic.py

    diff -r 8f6e2da7a63e sage/rings/polynomial/polynomial_element_generic.py
    a b  
    3838
    3939from sage.libs.pari.all import pari, pari_gen
    4040from sage.structure.factorization import Factorization
     41from sage.structure.element import coerce_binop
    4142
    4243from sage.rings.infinity import infinity
    4344from sage.rings.rational_field import QQ
     
    535536                               Polynomial_generic_domain,
    536537                               EuclideanDomainElement):
    537538
     539    @coerce_binop
    538540    def quo_rem(self, other):
    539541        """
    540542        Returns a tuple (quotient, remainder) where
     
    551553            (1, 0, 1)
    552554        """
    553555        P = self.parent()
    554         other = P(other)
    555556        if other.is_zero():
    556557            raise ZeroDivisionError, "other must be nonzero"
    557558           
     
    830831        else:
    831832            return PermutationGroup(H)
    832833
     834    @coerce_binop
    833835    def quo_rem(self, right):
    834836        """
    835837        Returns a tuple (quotient, remainder) where
     
    844846            sage: q*g + r
    845847            x^5 + 17*x + 3       
    846848        """
    847         if not isinstance(right, Polynomial_rational_dense):
    848             right = self.parent()(right)
    849         if right.parent() != self.parent():
    850             raise TypeError
    851849        v = self.__poly.divrem(right.__poly)
    852850        return Polynomial_rational_dense(self.parent(), v[0], construct=True), \
    853851               Polynomial_rational_dense(self.parent(), v[1], construct=True)
  • sage/rings/polynomial/polynomial_integer_dense_flint.pyx

    diff -r 8f6e2da7a63e sage/rings/polynomial/polynomial_integer_dense_flint.pyx
    a b  
    2626
    2727from sage.rings.polynomial.polynomial_element cimport Polynomial
    2828from sage.structure.element cimport ModuleElement, RingElement
     29from sage.structure.element import coerce_binop
    2930
    3031from sage.rings.polynomial.polynomial_element import is_Polynomial
    3132
     
    460461        _sig_off
    461462        return x
    462463
    463 
    464     def quo_rem(self, right):
     464    @coerce_binop
     465    def quo_rem(self, Polynomial_integer_dense_flint right):
    465466        r"""
    466467        Attempts to divide self by right, and return a quotient and remainder.
    467468
     
    499500            sage: z.quo_rem(2*x)
    500501            (0, 0)
    501502
     503        Ticket #383, make sure things get coerced correctly::
     504       
     505            sage: f = x+1; parent(f)
     506            Univariate Polynomial Ring in x over Integer Ring
     507            sage: g = x/2; parent(g)
     508            Univariate Polynomial Ring in x over Rational Field
     509            sage: f.quo_rem(g)
     510            (2, 1)
     511            sage: g.quo_rem(f)
     512            (1/2, -1/2)
     513            sage: parent(f.quo_rem(g)[0])
     514            Univariate Polynomial Ring in x over Rational Field
     515            sage: f.quo_rem(3)
     516            sage: (5*x+7).quo_rem(3)
     517            (x + 2, 2*x + 1)
    502518        """
    503         if not isinstance(right, Polynomial_integer_dense_flint):
    504             right = self._parent(right)
    505         elif self._parent is not right.parent():
    506             raise TypeError
    507 
    508         cdef Polynomial_integer_dense_flint _right = \
    509                 <Polynomial_integer_dense_flint> right
    510 
    511         if _right.is_zero():
     519        if right.is_zero():
    512520            raise ZeroDivisionError, "division by zero polynomial"
    513521
    514522        if self.is_zero():
     
    518526        cdef Polynomial_integer_dense_flint rr = self._new()
    519527
    520528        _sig_on
    521         fmpz_poly_divrem(qq.__poly, rr.__poly, self.__poly, _right.__poly)
     529        fmpz_poly_divrem(qq.__poly, rr.__poly, self.__poly, right.__poly)
    522530        _sig_off
    523531        return qq, rr
    524532
     
    554562        """
    555563        return not (fmpz_poly_degree(self.__poly) == -1)
    556564       
     565    @coerce_binop
    557566    def gcd(self, right):
    558567        r"""
    559568        Return the GCD of self and right.  The leading
     
    567576            sage: f.gcd(g)
    568577            6*x + 47
    569578        """
    570         if not isinstance(right, Polynomial_integer_dense_flint):
    571             right = self._parent(right)
    572         elif self._parent is not right.parent():
    573             raise TypeError
    574 
    575579        cdef Polynomial_integer_dense_flint x = self._new()
    576580        _sig_on
    577581        fmpz_poly_gcd(x.__poly, self.__poly,
     
    580584        return x
    581585
    582586
     587    @coerce_binop
    583588    def lcm(self, right):
    584589        """
    585590        Return the LCM of self and right.
     
    594599            sage: h == (6*x + 47)*(7*x^2 - 2*x + 38)*(3*x^3 + 2*x + 1)
    595600            True
    596601        """
    597         if not PY_TYPE_CHECK(right, Polynomial_integer_dense_flint):
    598             right = self._parent(right)
    599         elif self._parent is not right.parent():
    600             raise TypeError
    601 
    602602        g = self.gcd(right)
    603603        return (self//g)*right
    604604
    605605
     606    @coerce_binop
    606607    def xgcd(self, right):
    607608        """
    608609        This function can't in general return ``(g,s,t)`` as above,
     
    637638            sage: u*F + v*G
    638639            2985984
    639640        """
    640         if not isinstance(right, Polynomial_integer_dense_flint):
    641             right = self._parent(right)
    642         elif self._parent is not right.parent():
    643             raise TypeError
    644 
    645641        cdef Polynomial_integer_dense_flint ss = self._new()
    646642        cdef Polynomial_integer_dense_flint tt = self._new()
    647643        cdef unsigned long bound = fmpz_poly_resultant_bound(self.__poly,
     
    12281224        return [self[i] for i in range(self.degree()+1)]
    12291225
    12301226
     1227    @coerce_binop
    12311228    def resultant(self, other, proof=True):
    12321229        """
    12331230        Returns the resultant of self and other, which must lie in the same
  • sage/rings/polynomial/polynomial_integer_dense_ntl.pyx

    diff -r 8f6e2da7a63e sage/rings/polynomial/polynomial_integer_dense_ntl.pyx
    a b  
    5151
    5252from sage.libs.all import pari, pari_gen
    5353from sage.structure.factorization import Factorization
     54from sage.structure.element import coerce_binop
    5455
    5556from sage.rings.fraction_field_element import FractionFieldElement
    5657from sage.rings.arith import lcm
     
    442443        return x
    443444
    444445
     446    @coerce_binop
    445447    def quo_rem(self, right):
    446448        r"""
    447449        Attempts to divide self by right, and return a quotient and remainder.
     
    492494            (0, 0)
    493495
    494496        """
    495         if not isinstance(right, Polynomial_integer_dense_ntl):
    496             right = self.parent()(right)
    497         elif self.parent() is not right.parent():
    498             raise TypeError
    499 
    500497        cdef Polynomial_integer_dense_ntl _right = <Polynomial_integer_dense_ntl> right
    501498
    502499        if ZZX_IsZero(_right.__poly):
     
    533530
    534531
    535532       
     533    @coerce_binop
    536534    def gcd(self, right):
    537535        r"""
    538536        Return the GCD of self and right.  The leading
     
    546544            sage: f.gcd(g)
    547545            6*x + 47
    548546        """
    549         if not isinstance(right, Polynomial_integer_dense_ntl):
    550             right = self.parent()(right)
    551         elif self.parent() is not right.parent():
    552             raise TypeError
    553 
    554547        # todo: we're doing an unnecessary copy here
    555548        cdef Polynomial_integer_dense_ntl x = self._new()
    556549        cdef ZZX_c* temp = ZZX_gcd(&self.__poly, &(<Polynomial_integer_dense_ntl>right).__poly)
     
    559552        return x
    560553
    561554
     555    @coerce_binop
    562556    def lcm(self, right):
    563557        """
    564558        Return the LCM of self and right.
     
    573567            sage: h == (6*x + 47)*(7*x^2 - 2*x + 38)*(3*x^3 + 2*x + 1)
    574568            True
    575569        """
    576         if not isinstance(right, Polynomial_integer_dense_ntl):
    577             right = self.parent()(right)
    578         elif self.parent() is not right.parent():
    579             raise TypeError
    580 
    581570        g = self.gcd(right)
    582571        return (self * right).quo_rem(g)[0]
    583572
    584573
     574    @coerce_binop
    585575    def xgcd(self, right):
    586576        """
    587577        This function can't in general return ``(g,s,t)`` as above,
     
    616606            sage: u*F + v*G
    617607            2985984
    618608        """
    619         if not isinstance(right, Polynomial_integer_dense_ntl):
    620             right = self.parent()(right)
    621         elif self.parent() is not right.parent():
    622             raise TypeError
    623 
    624609        cdef ZZX_c *s, *t
    625610        cdef ZZ_c *r
    626611
     
    10531038        return [self[i] for i in range(self.degree()+1)]
    10541039
    10551040
     1041    @coerce_binop
    10561042    def resultant(self, other, proof=True):
    10571043        """
    10581044        Returns the resultant of self and other, which must lie in the same
  • sage/rings/polynomial/polynomial_modn_dense_ntl.pyx

    diff -r 8f6e2da7a63e sage/rings/polynomial/polynomial_modn_dense_ntl.pyx
    a b  
    4242import polynomial_singular_interface
    4343from sage.interfaces.all import singular as singular_default
    4444
    45 from sage.structure.element import generic_power, canonical_coercion, bin_op
     45from sage.structure.element import generic_power, canonical_coercion, bin_op, coerce_binop
    4646
    4747from sage.libs.ntl.ntl_ZZ_p_decl cimport *, ZZ_p_c
    4848from sage.libs.ntl.ntl_lzz_p_decl cimport *, zz_p_c
     
    237237        except RuntimeError, msg: # should this really be a TypeError
    238238            raise TypeError, msg
    239239
     240    @coerce_binop
    240241    def quo_rem(self, right):
    241242        """
    242243        Returns a tuple (quotient, remainder) where self = quotient*other +
    243244        remainder.
    244245        """
    245         if not isinstance(right, Polynomial_dense_mod_n):
    246             right = self.parent()(right)
    247         elif self.parent() != right.parent():
    248             raise TypeError
    249 ##        self._ntl_set_modulus()
    250246        v = self.__poly.quo_rem((<Polynomial_dense_mod_n>right).__poly)
    251247        P = self.parent()
    252248        return (P(v[0], construct=True), P(v[1], construct=True) )
     
    839835        else:
    840836            return r
    841837       
     838    @coerce_binop
    842839    def quo_rem(self, right):
    843840        """
    844841        Returns `q` and `r`, with the degree of `r` less than the degree of `right`,
     
    856853            sage: q*g + r
    857854            x^5 + 1
    858855        """
    859         if PY_TYPE(self) != PY_TYPE(right) or self._parent is not (<Element>right)._parent:
    860             self, right = canonical_coercion(self, right)
    861             return self.quo_rem(right)
    862856        cdef Polynomial_dense_modn_ntl_zz q = self._new()
    863857        cdef Polynomial_dense_modn_ntl_zz r = self._new()
    864858        cdef Polynomial_dense_modn_ntl_zz denom = <Polynomial_dense_modn_ntl_zz>right
     
    13811375            return ~r
    13821376        else:
    13831377            return r
    1384        
     1378   
     1379    @coerce_binop
    13851380    def quo_rem(self, right):
    13861381        """
    13871382        Returns `q` and `r`, with the degree of `r` less than the degree of `right`,
     
    13991394            sage: q*g + r
    14001395            x^5 + 1
    14011396        """
    1402         if PY_TYPE(self) != PY_TYPE(right) or self._parent is not (<Element>right)._parent:
    1403             self, right = canonical_coercion(self, right)
    1404             return self.quo_rem(right)
    14051397        cdef Polynomial_dense_modn_ntl_ZZ q = self._new()
    14061398        cdef Polynomial_dense_modn_ntl_ZZ r = self._new()
    14071399        cdef Polynomial_dense_modn_ntl_ZZ denom = <Polynomial_dense_modn_ntl_ZZ>right
     
    16921684    A dense polynomial over the integers modulo p, where p is prime.
    16931685    """
    16941686
     1687    @coerce_binop
    16951688    def gcd(self, right):
    16961689        return self._gcd(right)
    16971690   
     
    17061699        g = self.ntl_ZZ_pX().gcd(right.ntl_ZZ_pX())
    17071700        return self.parent()(g, construct=True)
    17081701
     1702    @coerce_binop
    17091703    def xgcd(self, right):
    17101704        r"""
    17111705        Return the extended gcd of self and other, i.e., elements `r, s, t` such that
     
    17291723        return self.parent()(r, construct=True), self.parent()(s, construct=True), \
    17301724               self.parent()(t, construct=True)
    17311725
     1726    @coerce_binop
    17321727    def resultant(self, other):
    17331728        """
    17341729        Returns the resultant of self and other, which must lie in the same
  • sage/rings/polynomial/polynomial_real_mpfr_dense.pyx

    diff -r 8f6e2da7a63e sage/rings/polynomial/polynomial_real_mpfr_dense.pyx
    a b  
    1414from sage.rings.rational cimport Rational
    1515
    1616from sage.structure.element cimport Element, ModuleElement, RingElement
    17 from sage.structure.element import parent, canonical_coercion, bin_op, gcd
     17from sage.structure.element import parent, canonical_coercion, bin_op, gcd, coerce_binop
    1818from sage.libs.mpfr cimport *
    1919
    2020from sage.libs.all import pari_gen
     
    495495        f._normalize()
    496496        return f
    497497       
     498    @coerce_binop
    498499    def quo_rem(self, PolynomialRealDense other):
    499500        """
    500501        EXAMPLES::
     
    547548        r._normalize()
    548549        return q, r * leading
    549550       
     551    @coerce_binop
    550552    def gcd(self, other):
    551553        """
    552554        Returns the gcd of self and other as a monic polynomial. Due to the
     
    574576            1.00000000000000
    575577
    576578        """
    577         # When #4301 gets in, use the generic gcd there.
    578         if parent(self) != parent(other):
    579             return bin_op(self, other, gcd)
    580579        aval = self.valuation()
    581580        a = self >> aval
    582581        bval = other.valuation()
  • sage/rings/polynomial/polynomial_zmod_flint.pyx

    diff -r 8f6e2da7a63e sage/rings/polynomial/polynomial_zmod_flint.pyx
    a b  
    3535
    3636from sage.libs.ntl.ntl_lzz_pX import ntl_zz_pX
    3737from sage.structure.factorization import Factorization
     38from sage.structure.element import coerce_binop
    3839
    3940# We need to define this stuff before including the templating stuff
    4041# to make sure the function get_cparent is found since it is used in
     
    206207                pass
    207208        return Polynomial.__call__(self, *x, **kwds)
    208209
     210    @coerce_binop
    209211    def resultant(self, Polynomial_zmod_flint other):
    210212        """
    211213        Returns the resultant of self and other, which must lie in the same
     
    226228            sage: r.parent() is GF(19)
    227229            True
    228230        """
    229         other = self.parent()._coerce_(other)
    230231        res = zmod_poly_resultant(&(<Polynomial_template>self).x, &(<Polynomial_template>other).x)
    231232        return self.parent().base_ring()(res)
    232233
  • sage/structure/element.pyx

    diff -r 8f6e2da7a63e sage/structure/element.pyx
    a b  
    1515- Gonzalo Tornaria (2007-06): recursive base extend for coercion --
    1616  lots of tests
    1717
     18- Robert Bradshaw (2007-2010): arithmetic operators and coercion
     19
    1820
    1921The Abstract Element Class Hierarchy
    2022------------------------------------
     
    174176include "../ext/stdsage.pxi"
    175177include "../ext/python.pxi"
    176178
    177 import operator
     179import operator, types
    178180import sys
    179181import traceback
    180182
     183import sage.misc.sageinspect as sageinspect
     184
    181185cdef MethodType
    182186from types import MethodType
    183187
     
    29172921    else:
    29182922        return coercion_model.exception_stack()
    29192923
     2924
     2925cdef class NamedBinopMethod:
     2926    """
     2927    A decorator to be used on binary operation methods that should operate
     2928    on elements of the same parent. If the parents of the arguments differ,
     2929    coercion is performed, then the method is re-looked up by name on the
     2930    first argument.
     2931   
     2932    In short, using the ``NamedBinopMethod`` (alias ``coerce_binop``) decorator
     2933    on a method gives it the exact same semantics of the basic arithmetic
     2934    operations like ``_add_``, ``_sub_``, etc. in that both operands are
     2935    guaranteed to have exactly the same parent.
     2936    """
     2937    cdef _self
     2938    cdef _func
     2939    cdef _name
     2940   
     2941    def __init__(self, func, name=None, obj=None):
     2942        """
     2943        TESTS::
     2944       
     2945            sage: from sage.structure.element import NamedBinopMethod
     2946            sage: NamedBinopMethod(gcd)(12, 15)
     2947            3
     2948        """
     2949        self._func = func
     2950        if name is None:
     2951            if isinstance(func, types.FunctionType):
     2952                name = func.func_name
     2953            if isinstance(func, types.UnboundMethodType):
     2954                name = func.im_func.func_name
     2955            else:
     2956                name = func.__name__
     2957        self._name = name
     2958        self._self = obj
     2959
     2960    def __call__(self, x, y=None, **kwds):
     2961        """
     2962        TESTS::
     2963       
     2964            sage: from sage.structure.element import NamedBinopMethod
     2965            sage: test_func = NamedBinopMethod(lambda x, y, **kwds: (x, y, kwds), '_add_')
     2966           
     2967        Calls func directly if the two arguments have the same parent::
     2968       
     2969            sage: test_func(1, 2)
     2970            (1, 2, {})
     2971       
     2972        Passes through coercion and does a method lookup if the
     2973        left operand is not the same::
     2974       
     2975            sage: test_func(0.5, 1)
     2976            (0.500000000000000, 1.00000000000000, {})
     2977            sage: test_func(1, 2, algorithm='fast')
     2978            (1, 2, {'algorithm': 'fast'})
     2979            sage: test_func(1, 1/2)
     2980            3/2
     2981        """
     2982        if y is None:
     2983            if self._self is None:
     2984                self._func(x, **kwds)
     2985            else:
     2986                x, y = self._self, x
     2987        if not have_same_parent(x, y):
     2988            old_x = x
     2989            x,y = coercion_model.canonical_coercion(x, y)
     2990            if old_x is x:
     2991                return self._func(x,y, *kwds)
     2992            else:
     2993                return getattr(x, self._name)(y, **kwds)
     2994        else:
     2995            return self._func(x,y, **kwds)
     2996   
     2997    def __get__(self, obj, objtype):
     2998        """
     2999        Used to transform from an unbound to a bound method.
     3000       
     3001        TESTS::
     3002            sage: from sage.structure.element import NamedBinopMethod
     3003            sage: R.<x> = ZZ[]
     3004            sage: isinstance(x.quo_rem, NamedBinopMethod)
     3005            True
     3006            sage: x.quo_rem(x)
     3007            (1, 0)
     3008            sage: type(x).quo_rem(x,x)
     3009            (1, 0)
     3010        """
     3011        return NamedBinopMethod(self._func, self._name, obj)
     3012   
     3013    def _sage_doc_(self):
     3014        """
     3015        Return the docstring of the wrapped object for introspection.
     3016       
     3017        EXAMPLES::
     3018       
     3019            sage: from sage.structure.element import NamedBinopMethod
     3020            sage: g = NamedBinopMethod(gcd)
     3021            sage: g._sage_doc_() == gcd.__doc__
     3022            True
     3023        """
     3024        return sageinspect.sage_getdoc(self._func)
     3025   
     3026    def _sage_src_(self):
     3027        """
     3028        Returns the source of the wrapped object for introspection.
     3029       
     3030        EXAMPLES::
     3031
     3032            sage: from sage.structure.element import NamedBinopMethod
     3033            sage: g = NamedBinopMethod(gcd)
     3034            sage: 'def gcd(' in g._sage_src_()
     3035            True
     3036        """
     3037        return sageinspect.sage_getsource(self._func)
     3038   
     3039    def _sage_argspec_(self):
     3040        """
     3041        Returns the argspec of the wrapped object for introspection.
     3042       
     3043        EXAMPLES::
     3044       
     3045            sage: from sage.structure.element import NamedBinopMethod
     3046            sage: g = NamedBinopMethod(gcd)
     3047            sage: g._sage_argspec_()
     3048            (['a', 'b'], None, 'kwargs', (None,))
     3049        """
     3050        return sageinspect.sage_getargspec(self._func)
     3051
     3052coerce_binop = NamedBinopMethod
     3053
    29203054###############################################################################
    29213055
    29223056def lcm(x,y):