# substituting expressions for numbers

Say you have some formula in the form of an expression:

sage: x,y,a,b = var("x y a b")
sage: f = 10*x+2*y
sage: type(f)
<type 'sage.symbolic.expression.Expression'>


Now I want to replace the 10 by the variable a. What's the easiest way to do this? It's the opposite of the typical substitution, so the functions I'd usually throw at it all fail.

So far I can only up with (1) string techniques, which are bugs waiting to happen, or (2) walking the entire expression tree and constructing a new expression from each operator/operand triplet.

edit retag close merge delete

Sort by » oldest newest most voted

If you don't want to use strings, then I think you do have to walk the expression tree at the moment. Sage does come with some tools to help with this in sage.symbolic.expression_conversions, but they could be improved. For example, something like the following should be added to the Sage library:

from sage.symbolic.expression_conversions import Converter

class DoNothing(Converter):
def arithmetic(self, ex, operator):
return reduce(operator, map(self, ex.operands()))
def pyobject(self, ex, obj):
return ex
def symbol(self, ex):
return ex
def relation(self, ex, operator):
return operator(*map(self, ex.operands()))
def derivative(self, ex, operator):
#We'll just ignore this for now
return ex
def composition(self, ex, operator):
return operator(*map(self, ex.operands()))


Then,

sage: f = 10*x + 3
sage: d = DoNothing()
sage: d(f)
10*x + 3


With this little utility class in place, you can write:

class TenReplacer(DoNothing):
def pyobject(self, ex, obj):
return 99 if obj == 10 else obj


and have

sage: f = 10*x + 3
sage: t = TenReplacer()
sage: t(f)
99*x + 3
sage: t(f == 10)
99*x + 3 == 99
sage: t(f == 100)
99*x + 3 == 100

more

That is pretty cool. If you open a ticket for this, please copy me. I sadly don't understand quite enough about how this works yet to contribute to it, but could help review. Walking expression trees is a constant support request, so this would be great. If that's what this does?

( 2011-02-28 07:13:21 -0600 )edit
1

Nice. Expression hacking is too handy not to have better support; maybe Expressions should grow some more methods to handle common cases? Even a convert-to/from-sequence representation method would have made a question a while back a two-liner. I still can't help feeling that .subs({10:a}) should Just Work, though.

( 2011-02-28 12:49:16 -0600 )edit

So that this is recorded somewhere, here's the simplest way I found (thanks @kcrisman-- I always forget that we can access maxima functionality). It turns out maxima's subst is pretty powerful:

sage: var("x a")
(x, a)
sage: f = 10*x+3
sage: f
10*x + 3
sage: maxima.subst(a, 10, f).sage()
a*x + 3


but then you have to live with any changes induced on the trip, whereas with Mike's solution you don't have to worry about that, and you can replace the "==" comparison by something which is as finely-tuned as you want.

I'd like f.subs({10:a}) to work, but I get lost in the code as soon as _gobjs start showing up..

more

Yikes! I assume you are doing an explicit example and now want to generalize.

Sorry, I think you will have to walk the expression tree. Hopefully I am wrong, but Sage just doesn't have methods for this built in yet. I don't even know that Maxima does. Axiom/Fricas might be more along those lines, I don't know. Honestly, I'd probably even do a string thing, as long as I could watch it step by step - like in a text editor - to make sure I wasn't making any erroneous replacements.

more

That was exactly the cause: there was a specific troublesome function and I wanted to see if I could find a smaller example when I realized I didn't know how..

( 2011-02-28 12:37:55 -0600 )edit