10

Mathematica keeps rewriting expressions, so it is hard to figure what pattern to use.

I am trying to replace all occurrences of $\frac{y}{x}$ by $t$, but Mathematica re-writes $\frac{1}{\left(\frac{y}{x}\right)}$ to $\frac{x}{y}$ so pattern y/x fails sometimes depending on if it is in the numerator or denominator.

So switched to using at FullForm and checking for all combinations. But that also does not work, and I am sure I will miss some cases.

Here is an example

ClearAll[t, x, y]
expr = (y/x)^2;
FullForm[expr]

Gives

 Times[Power[x,-2], Power[y,2]]

So why does the below not match?

 expr/.Times[Power[x,-(any0_.)], Power[y,any0_.]] :>  t^any0

I am literally writing the same exact full form! But I changed the power to be anything. So in this case any0_. should match the 2, right? But it does not:

Mathematica graphics

It turned out removing the minus sign before any0 above made it work, but I had to give the other power a different pattern name

   expr/.Times[Power[x, any0_.], Power[y, any1_.]] :>  t^any0

Mathematica graphics

But that is not what I want. It should be $t^2$, I want the same pattern/power on both, but one with a minus sign to match. It looks like a when there is a minus sign there is a problem.

The main problem is really this: How do I change all (y/x)s anywhere in the expression to t so (y/x)^3 will change to t^3 as example?

The problem is also that Mathematica rewrites the expression internally so it is hard to know what pattern to use. What I am looking at is not what it is internally.

I even used the excellent function by Carl Woll:

getPatterns[expr_, pat_] := Last@Reap[expr /. a : pat :> Sow[a], _, Sequence @@ #2 &];
getPatterns[(y/x)^2, (y/x)^any_.]

But that did not pick this due to the re-writing.

 {}

I can't use HoldForm either on these things. Any idea how to do this which will work all the time?

Examples to test with


expr = (1 + 2 (y^2/x^2))/(2 (y/x))

Mathematica graphics

This should be transformed to $\frac{1+ 2 t^2}{2 t}$

 expr = y/x + Sqrt[1 + (y/x)^2]

Mathematica graphics

It should be transformed to $t+\sqrt{1+t^2}$

Note: It is not required that the pattern transforms things like y^4/x^3 to y t^3. It can be assumed that y/x always shows with same power. But if the transformation can handle this general case, it will be even better, but not required.

m_goldberg
  • 107,779
  • 16
  • 103
  • 257
Nasser
  • 143,286
  • 11
  • 154
  • 359
  • 2
    What about e.g. x^3/y^5? Should it be left unchanged, replaced by 1/(t^3 y^2) or by 1/(t^5 x^2)? – jkuczm Jul 29 '17 at 10:48
  • @jkuczm This is meant as algebraic transformation, so yes, x^3/y^5 should become (1/t^3 y^2) but for now, this is not required, as I make sure I enter the expression with terms as (y/x)^n only. i.e. the expression will contain only terms of (y/x) of some powers. I am keeping it simple. But if the code will also support the general case you showed, I will not complain ofcourse :) – Nasser Jul 29 '17 at 10:55
  • What is your intent behind HoldForm in these examples? As I attempted to illustrate in my answer that substantially changes the problem. – Mr.Wizard Jul 29 '17 at 10:59
  • @Mr.Wizard oh, I just used HoldForm for illustration of what the input look like on the screen. Nothing more. Else mathematica will re-write it and becomes hard to see the y/x pattern. I do not use HoldForm at all in the code. Will remove HoldForm now so not be confusing. – Nasser Jul 29 '17 at 11:01

3 Answers3

10

At least one of the problems you are encountering is that -2 and -x do not share the same structure:

{-2, -x} // FullForm
List[-2, Times[-1, x]]

You can not destructure -2 using patterns. You can check numerically however:

(y/x)^2 /. x^a_. y^b_. /; b == -a :> t^b
t^2

Remember also that a matched expression is not further replaced, so you may need ReplaceRepeated. Applied to your examples:

(1 + 2 (y^2/x^2))/(2 (y/x)) //. x^a_. y^b_. /; b == -a :> t^b

y/x + Sqrt[1 + (y/x)^2] //. x^a_. y^b_. /; b == -a :> t^b
(1 + 2 t^2)/(2 t)

t + Sqrt[1 + t^2]


A second potential problem is operating on a manually entered held form such as HoldForm[(1 + 2 (y^2/x^2))/(2 (y/x))] without realizing that this can have a very different internal form compared to an evaluated expression. Compare:

foo = HoldForm[(1 + 2 (y^2/x^2))/(2 (y/x))];
bar = HoldForm @@ {(1 + 2 (y^2/x^2))/(2 (y/x))};

foo // TreeForm
bar // TreeForm

enter image description here

enter image description here


I would be remiss not to mention that general algebraic manipulation should not be done with pattern matching if at all avoidable. See for example Replacing composite variables by a single variable and be aware of:


Other things to be aware of:

Mr.Wizard
  • 271,378
  • 34
  • 587
  • 1,371
4

A simple solution: replace y with t x, and if there are any cases of t x hanging around with the x not cancelling, replace them with y.

(expression /. {y -> t x}) /. t x -> y

Testing it on some examples:

((1 + 2 (y^2/x^2))/(2 (y/x)) /. {y -> t x}) /. t x -> y
(y/5 /. {y -> t x}) /. t x -> y
(x/y /. {y -> t x}) /. t x -> y
(y/x + Sqrt[1 + (y/x)^2] /. {y -> t x}) /. t x -> y

(1 + 2 t^2)/(2 t)

y/5

1/t

t + Sqrt[1 + t^2]

I would imagine that this is unlikely to be very robust. But I haven't tested on any convoluted examples.

Edit: To deal with the xs left at the end, just replace them all with y/t

r[expr_] := expr /. {y -> t x} /. {t x -> y} /. {x -> y/t}

Then, in addition to the above examples, we get

r[(y/x)*y]
r[y^4/x^3]

t y

t^3 y

aardvark2012
  • 5,424
  • 1
  • 11
  • 22
  • Although this works so far, it has some strange side effect. For example, I expected (y/x)*y to be transformed to t y right? But it changes it to t^2 x. Which is still correct, but a little unexpected. But that is not a big problem for me, as the input I have all contains (y/x) only terms and this case will not show up for what I need this for. – Nasser Jul 29 '17 at 11:17
  • @Nasser See my edit. Is that what you mean? – aardvark2012 Jul 29 '17 at 11:31
  • yes, thanks , this looks good. – Nasser Jul 29 '17 at 12:09
  • FWIW you do not strictly need the parentheses here as /. automatically groups this way. expr /. y -> t x /. t x -> y /. x -> y/t should work the same. If you like including explicit grouping of course that is your prerogative. Nice method, by the way. – Mr.Wizard Jul 29 '17 at 17:17
  • @Mr.Wizard Thanks for that. Re: parentheses... Yes, I have parenthesis paranoia (parenthenoia?), so I tend to put them in where they're not really needed. I've removed them now. – aardvark2012 Jul 29 '17 at 23:44
2

I know, this is not really the answer to your question. But at least in this specific problem, this helps:

expr /. {y -> t x}

Next try:

r = {
   Times[z___, Power[x, k_], Power[y, l_], w___] :> If[k == -l,
     Times[z, Power[t, l], w],
     Times[z, Power[x, k], Power[y, l], w]
     ],
   Times[z___, x, Power[y, -1], w___] :> Times[z, 1/t, w],
   Times[z___, Power[x, -1], y, w___] :> Times[z, t, w]
   };

x/y //. r
y^2/x^2 //. r
y^3/x^2 //. r
(1 + 2 (y^2/x^2))/(2 (y/x)) //. r
y/x + Sqrt[1 + (y/x)^2] //. r

(* 1/t *)
(* t^2 *)
(* y^3/x^2 *)
(* (1 + 2 t^2)/(2 t) *)
(* t + Sqrt[1 + t^2] *)

The second branch of the If statement can be used to further elaborate on the third example. But admittedly, this is starting to get complicated...

Henrik Schumacher
  • 106,770
  • 7
  • 179
  • 309
  • Thanks, but this does not really do it. I need to first check that the y/x actually is there ! Else, I will be replacing y/5 by t x/5 which makes no sense. This is meant to only replace y/x if it exists ! – Nasser Jul 29 '17 at 10:17
  • I know... This is a really interesting problem that I also stumpled upon several times. – Henrik Schumacher Jul 29 '17 at 10:20
  • no problem. This is hard, because mathematica re-writes expression. so what one is looking at, is not the same as what is used internally. So patterns sometimes do not work because of this. – Nasser Jul 29 '17 at 10:22
  • 1
    @Nasser You could use this function as only transformation function of Simplify: Simplify[{(a y)/(b x), x/y, y^2/x^2, y^5/x^3, a x y}, TransformationFunctions -> {# /. y -> t x &}] (* {(a t)/b, 1/t, t^2, t^5 x^2, a x y} *). If this will be to eager and replace some instance we don't want to be replaced, one could also play with ComplexityFunction to prevent it. – jkuczm Jul 29 '17 at 10:30
  • 3
    As an extension to @HenrikSchumacher's first answer, you could try (expression /. {y -> t x}) /. t x -> y. It appears to work for the test case at the end of the question (returns the required expression in t), y/5 (which remains unaltered), and x/y (returns 1/t). Very probably not robust, I would guess, but nice and simple if it works. – aardvark2012 Jul 29 '17 at 10:36
  • Thanks for trying. But I can't get your code to do the transformation on the two examples I showed. – Nasser Jul 29 '17 at 10:45
  • @aardvark2012 thanks! Your code actually worked on the two examples I have ! Will try it on more examples. Feel free to post it as answer. – Nasser Jul 29 '17 at 10:47