Opened 3 years ago

# Warn with substitution of derived classes using equality

Reported by: Owned by: rws major sage-8.2 symbolics N/A

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

### comment:1 Changed 3 years ago by rws

• Description modified (diff)

### comment:2 Changed 3 years 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 3 years ago by rws

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

### comment:4 Changed 3 years 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 3 years ago by rws

• Description modified (diff)

### comment:6 Changed 3 years ago by rws

• Description modified (diff)

### comment:7 follow-up: ↓ 11 Changed 3 years 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 3 years ago by rws (previous) (diff)

### comment:8 Changed 3 years ago by rws

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

Version 0, edited 3 years ago by rws (next)

### comment:9 Changed 3 years 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 3 years ago by rws

• Description modified (diff)

### comment:11 in reply to: ↑ 7 Changed 3 years ago by jdemeyer

```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 3 years 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: ↓ 14 Changed 3 years 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 3 years 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.