Replace and subs

103 views
Skip to first unread message

Paul Royik

unread,
Mar 19, 2015, 7:45:35 AM3/19/15
to sy...@googlegroups.com
What is the best way to replace cos(4x+6) with cos(2u) if u=2x+3?

cos(4x+6).subs(2x+3, u) doesn't work and I don't know how to write it using replace.

I can' t do factor, since expression can be very big and factoring is not desirable.
Is it possible to do it without factoring in clean way?


Thank you.

Francesco Bonazzi

unread,
Mar 19, 2015, 10:27:42 AM3/19/15
to sy...@googlegroups.com
Try this one:

cos(4*x+6).replace(
   
lambda expr: expr.is_Add,
   
lambda expr: ((expr/(2*x+3)).simplify()*u)
)

Paul Royik

unread,
Mar 19, 2015, 10:52:44 AM3/19/15
to sy...@googlegroups.com
Thanks.

Mike Boyle

unread,
Mar 19, 2015, 10:56:42 AM3/19/15
to sy...@googlegroups.com
It seems to me that the easy way to do this is to solve your replacement for `x`:

cos(4*x+6).subs(x, (u-3)/2)

And if this is just a special case of a more general substitution, you can of course do that solve step with sympy.

I can't tell from your question, but this might not be exactly what you wanted.  For example, look at

(x*cos(4*x+6)).subs(x, (u-3)/2)

This will also replace the `x` out front.  If you don't want that, you'd need to do an even more complicated version of what Francesco suggests.

Paul Royik

unread,
Mar 20, 2015, 4:01:05 AM3/20/15
to sy...@googlegroups.com

Yes. This version  is not for me.
x in front of cosine shouldn't be replaced.

Francesco Bonazzi

unread,
Mar 20, 2015, 9:11:40 AM3/20/15
to sy...@googlegroups.com
There are also wildcards to use in the replacement matcher, unfortunately in SymPy wild symbols often match too much or in an unexpected way.

Consider an attempt with a wild:

In [1]: w = Wild('w')

In [2]: cos(4*x+6).replace(w*(2*x+3), u*w)
Out[2]:
   
    2              
   
 4u x       6u  
cos
⎜────────── + ───────⎟
   
        2   2x + 3
   
⎝(2x + 3)          


It would be nice to have assumptions work on wildcards, in order to restrict their matching possibilities.

Mike Boyle

unread,
Mar 20, 2015, 10:09:54 AM3/20/15
to sy...@googlegroups.com
I agree that wildcards behave very strangely -- especially under multiplication, because they can basically divide by whatever they're multiplying.  In my experience, their real power comes from repeated uses.  For example, the following would work in your example, Francesco:

cos(4*x+6).replace((w*2*x+w*3), u*w)

Also, note that there is an `exclude` flag to the wildcard constructor that can help in some cases (though wouldn't have helped in your example).


While we're at it, I might add a couple more examples that make your original suggestion a little more specific, so that they may deal with Paul's situation more generally.  First, assuming there might be another term in the expression (and, as he mentioned, other `x`s shouldn't be replaced), this will be do:

(3 + x*cos(4*x+6)).replace(
   
lambda expr: expr.is_Add and simplify(expr/(2*x+3)).is_Number,
   
lambda expr: u*simplify(expr/(2*x+3))
)

That extra condition in the first lambda function is needed to make sure the whole expression (which is now an `Add`) won't be multiplied by u/(2*x+3).

Or, if only arguments to `sin` and `cos` functions should be replaced, this would work:

(x*(8*x+12) + x*cos(4*x+6)).replace(
    lambda expr: (expr.func == cos or expr.func == sin) and simplify(expr.args[0]/(2*x+3)).is_Number,
    lambda expr: expr.func(u*simplify(expr.args[0]/(2*x+3)))
)

Aaron Meurer

unread,
Mar 20, 2015, 12:29:17 PM3/20/15
to sy...@googlegroups.com
I think we should make it so that cos(4*x + 6).replace(2*x + 3, u) works.

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 post to this group, send email to sy...@googlegroups.com.
> Visit this group at http://groups.google.com/group/sympy.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/sympy/e76ad3b1-7fe0-4f3e-9afd-2ff19b1d6124%40googlegroups.com.
>
> For more options, visit https://groups.google.com/d/optout.

Mike Boyle

unread,
Mar 20, 2015, 12:50:00 PM3/20/15
to sy...@googlegroups.com

I think we should make it so that cos(4*x + 6).replace(2*x + 3, u) works.

That would be nice.  Also, Francesco's wildcard replacement looks buggy.  The `4*x` apparently matches twice, once for 4 and once for x:

In [1]: u = symbols('u')

In [2]: w = Wild('w')

In [3]: cos(4*x+6).replace(w*(2*x+3), u*w, map=True)
Out[3]:

      2                                                    
   4u x       6u         4u         6u         ux  ⎫⎟
cos⎜────────── + ───────⎟, 4: ───────, 6: ───────, x: ───────⎬⎟
          2   2x + 3     2x + 3     2x + 3     2x + 3⎭⎟
  ⎝(2x + 3)                                                


This seems to contradict the documentation's claims that "changes made are targeted only once" and "changes are not made twice".  I thought maybe I just misunderstood the `simultaneous` flag, but that makes things even worse.  Or am I misunderstanding that?

Mike Boyle

unread,
Mar 20, 2015, 1:03:29 PM3/20/15
to sy...@googlegroups.com
Oh, I think I get it now.  `replace(w*(2*x+3)` starts at the bottom of the expression tree.  So at first it's not looking to replace expressions, it's looking to replace atoms.

Now I'm wondering if it would make sense for an `if` statement inserted into the logic to ensure that `w*(2*x+3)` doesn't match an atom.  Because it seems like that would never be desirable, and basically makes (non-repeated) multiplication by Wild objects useless...
Reply all
Reply to author
Forward
0 new messages