Opened 15 months ago

Last modified 15 months ago

#24255 new defect

Warn with substitution of derived classes using equality

Reported by: rws Owned by:
Priority: major Milestone: sage-8.2
Component: symbolics Keywords:
Cc: Merged in:
Authors: Reviewers:
Report Upstream: N/A Work issues:
Branch: Commit:
Dependencies: Stopgaps:

Description (last modified by rws)

There is a long-standing problem with substitution in that some substitutions do not work when given as equality but do work when given as dictionary.

sage: (x*pi).subs(x*pi==e)
x*pi
sage: (x*pi).subs({x*pi:e})
e

sage: s = x.series(x,2); s
1*x + Order(x^2)
sage: (x*pi).subs(x*pi==s)
pi*x

It looks like that in some cases the conversion to dict switches lhs and rhs of the equation and this is because of such behaviour:

sage: x*pi==e
e == pi*x
sage: x == s
1*x + Order(x^2) == x

Change History (15)

comment:1 Changed 15 months ago by rws

  • Description modified (diff)

comment:2 Changed 15 months ago by rws

  • Description modified (diff)
  • Summary changed from Fix substitution with pattern given as equation to Fix constants coercion into SR

comment:3 Changed 15 months ago by rws

  • Description modified (diff)
  • Summary changed from Fix constants coercion into SR to Fix constant e coercion into SR

comment:4 Changed 15 months ago by rws

  • Description modified (diff)
  • Summary changed from Fix constant e coercion into SR to Fix Expression subclasses coercion into SR

comment:5 Changed 15 months ago by rws

  • Description modified (diff)

comment:6 Changed 15 months ago by rws

  • Description modified (diff)

comment:7 follow-up: Changed 15 months ago by rws

class A(SageObject):
    def __init__(self):
        from sage.symbolic.ring import SR
        self._parent = SR
    def __eq__(a, b):
        print(a, b)
        return True
    def __repr__(self):
        return "A"

class B(A):
    def __eq__(a, b):
        print(a, b)
        return True
    def __repr__(self):
        return "B"

sage: from sage.symbolic.tests import A,B
sage: A() == B()
(B, A)
True

versus

class A():
    def __init__(self):
        from sage.symbolic.ring import SR
        self._parent = SR
    def __eq__(a, b):
        print(a, b)
        return True
    def __repr__(self):
        return "A"

class B(A):
    def __eq__(a, b):
        print(a, b)
        return True
    def __repr__(self):
        return "B"

sage: from sage.symbolic.tests import A,B
sage: A() == B()
(A, B)
True

The first has A inherit from SageObject the second not.

Last edited 15 months ago by rws (previous) (diff)

comment:8 Changed 15 months ago by rws

Since we cannot use the @richcmp decorator on a cdef class we cannot work around it but must investigate the reason for the argument switching, which is possibly in Cython.

Last edited 15 months ago by rws (previous) (diff)

comment:9 Changed 15 months ago by rws

Adding __eq__ does not work I get a Cython compile error reported at https://github.com/cython/cython/issues/2019

comment:10 Changed 15 months ago by rws

  • Description modified (diff)

comment:11 in reply to: ↑ 7 Changed 15 months ago by jdemeyer

Replying to rws:

class A(SageObject):
    def __init__(self):
        from sage.symbolic.ring import SR
        self._parent = SR
    def __eq__(a, b):
        print(a, b)
        return True
    def __repr__(self):
        return "A"

class B(A):
    def __eq__(a, b):
        print(a, b)
        return True
    def __repr__(self):
        return "B"

sage: from sage.symbolic.tests import A,B
sage: A() == B()
(B, A)
True

versus

class A():
    def __init__(self):
        from sage.symbolic.ring import SR
        self._parent = SR
    def __eq__(a, b):
        print(a, b)
        return True
    def __repr__(self):
        return "A"

class B(A):
    def __eq__(a, b):
        print(a, b)
        return True
    def __repr__(self):
        return "B"

sage: from sage.symbolic.tests import A,B
sage: A() == B()
(A, B)
True

I think this is just a difference between new-style and old-style classes. This has nothing to do with Cython.

comment:12 Changed 15 months ago by jdemeyer

Without any Cython classes involved:

sage: class A(object):
....:     def __eq__(a, b):
....:         print(a, b)
....:         return True
....:     def __repr__(self):
....:         return "A"
....: 
....: class B(A):
....:     def __eq__(a, b):
....:         print(a, b)
....:         return True
....:     def __repr__(self):
....:         return "B"
sage: A() == B()
(B, A)
True

comment:13 follow-up: Changed 15 months ago by rws

Why then would class A(): not switch arguments? Anyway, this ticket either should warn if subclasses are encountered or at least add explanations to the documentation.

comment:14 in reply to: ↑ 13 Changed 15 months ago by rws

Replying to rws:

Why then would class A(): not switch arguments? Anyway, this ticket either should warn if subclasses are encountered or at least add explanations to the documentation.

Okay the answer is https://stackoverflow.com/questions/54867/what-is-the-difference-between-old-style-and-new-style-classes-in-python and Python is a PITA.

comment:15 Changed 15 months ago by rws

  • Summary changed from Fix Expression subclasses coercion into SR to Warn with substitution of derived classes using equality
Note: See TracTickets for help on using tickets.