Rewriting with instance as rule

46 views
Skip to first unread message

JSS95

unread,
May 11, 2021, 11:10:41 PM5/11/21
to sympy
Current Basic.rewrite() allows three types as the rule: a str, a function class, or a singleton instance. For example, fibonacci(n).rewrite(S.GoldenRatio) calls  fibonacci(n)._eval_rewrite_as_GoldenRatio which returns the transformed expression.

The problem is that current design does not allow non-singleton instance to be taken as rewrite rule. For example, I want to rewrite a boolean expression which contains Eq(x, y) so that the equality is transformed to Q.zero(x, y). expr.rewrite(Q.zero) calls expr._eval_rewrite_as_Predicate, and I cannot define a logic which selectively works for Q.zero (but not for Q.real, Q.infinite, etc).

This will be even more problematic when we introduce functions as instances. I plan to resolve it by redesigning _eval_refine and _eval_rewrite_as_[...] methods, but it may break the backwards compatibility so I would like to hear other opinions first.

Jisoo Song

Aaron Meurer

unread,
May 11, 2021, 11:40:11 PM5/11/21
to sympy
I also never liked how rewrite transforms the class name into a string
for the method name. That makes it simple to implement for the basic
cases, but it limits how expressive it can be. I think we can make a
more expressive API which overlaps with the existing one, so that
doesn't break compatibility.

Aaron Meurer
> --
> You received this message because you are subscribed to the Google Groups "sympy" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to sympy+un...@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/sympy/d980c0ca-1a52-4a48-b0a5-1e959d8ce025n%40googlegroups.com.

JSS95

unread,
May 12, 2021, 9:17:16 AM5/12/21
to sympy
Any idea to improve the API? The first that comes to my mind is singledispatch, but probably it's an overkill.

Jisoo Song

2021년 5월 12일 수요일 오후 12시 40분 11초 UTC+9에 asme...@gmail.com님이 작성:

Aaron Meurer

unread,
May 12, 2021, 3:42:03 PM5/12/21
to sympy
I would just pass the object through to the function, like

expr.rewrite(expr2) calls

expr._eval_rewrite(expr2)

except it should still prefer the existing API if a method matches.

This way, the function can do whatever dispatching is necessary.

Another thing to think about for this is that some of the existing
rewrite methods are not as expressive as they could be. Consider for
example trig functions. There are several different ways to rewrite
one trig function in terms of another. For example, sin(x) = cos(pi/2
- x) = sqrt(1 - cos(x)**2) = 2*sin(x/2)*cos(x/2) and so on. Right now
sin(x).rewrite(cos) gives cos(x - pi/2), but the other forms could be
useful depending on the context. Is there some way we could design the
API to make it easy for people to pick which form they want to rewrite
to (without having to explicitly remember the identities, which they
could just do manually with replace()).

Aaron Meurer
> To view this discussion on the web visit https://groups.google.com/d/msgid/sympy/d2661899-3c47-4523-8a58-29bd36048fddn%40googlegroups.com.

JSS95

unread,
May 17, 2021, 4:26:36 AM5/17/21
to sympy
I opened a PR #21472 for this. I will wait for your review.

Jisoo Song

2021년 5월 13일 목요일 오전 4시 42분 3초 UTC+9에 asme...@gmail.com님이 작성:

Chris Smith

unread,
Jun 5, 2021, 10:36:33 AM6/5/21
to sympy
>  There are several different ways to rewrite one trig function in terms of another. 

  The `fu` patterns can be used to do different types of rewriting. But in the case you gave, rewriting as cos, Pow or Mul might make sense.

Reply all
Reply to author
Forward
0 new messages