# Matching (y/x)^u terms wherever the appear in an expression

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: 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 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)) This should be transformed to $\frac{1+ 2 t^2}{2 t}$

 expr = y/x + Sqrt[1 + (y/x)^2] 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.

• 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

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

• 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

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

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

• 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
• @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
• 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