MinimalPolynomial[] for expressions containing symbols - wolfram-mathematica

I’m using Mathematica to solve some simple equations relating to geometry, and subsequently hard-coding those solutions in a different language†. Rather than have many pages of code, it would be more concise to code the solutions as a root of a polynomial.
Let’s take:
Solve[{
dist^2 == xstep^2 + ((h - 2 r)/(NR - 1))^2,
dist^2 == (w - 2 r - NC xstep)^2 + (h/2 - r - dist/2)^2
},{xstep, dist}]
That generates a “very large output”, heavy with fractions and square roots and fourth roots. Obviously the two solved variables are the roots of quartic equations.
Please, is there a version of MinimalPolynomial[] that will work on expressions containing symbols? All that’s wanted is the five coefficients of dist’s quartic.
Thank you.
† The “different language” is PostScript, and I really don’t have the expertise to write a //PostScriptForm function. Indeed, finding the optimal balance between recomputing repeated expressions and using “… dup … roll” would, in the general case, be slow.

I wrote a package called "Substitutions" (archived here), which pulls out a hierarchy of sub-expressions, minimizing the coding for complex expressions. It was included in the old MathSource library. Here's the description:
It is often useful, especially when using Mathematica for software
development, to apply substitutions to complex expressions to reduce
their form. For large expressions, this task can become tedious.
Substitutions[] was designed help with the process of finding a useful
set of substitutions to simplify an expression.
It is quite old now, but should still work.

Reduce may be what you want:
I've consolodated some of your symbol groups into A,B,C (not nesesary, makes it fit on screen)
Reduce[{dist^2 == xstep^2 + (A)^2 &&
dist^2 == (C - NC xstep)^2 + (B - dist/2)^2 , {xstep, dist}]]
this produces a fairly large output with a bunch of conditions.
If you have known constraints that preclude various degenrate cases it helps to specify (I made these up)
$Assumptions = B != 0 && B^2 != 3 C^2 && NC^2 != 3/4;
note $Assumptions is used by Simplify, but you need to explicitly add it to the Reduce expression..
Simplify[Reduce[{dist^2 == xstep^2 + (A)^2 &&
dist^2 == (C - NC xstep)^2 + (B - dist/2)^2 && $Assumptions }, {xstep, dist}]]
output.. not too unwiledy .. The Root expression contains the coefficients you seek..
(xstep ==
Root[9 A^4 - 40 A^2 B^2 + 16 B^4 - 24 A^2 C^2 + 32 B^2 C^2 +
16 C^4 + (48 A^2 C NC - 64 B^2 C NC -
64 C^3 NC) #1 + (18 A^2 - 40 B^2 - 24 C^2 - 24 A^2 NC^2 +
32 B^2 NC^2 + 96 C^2 NC^2) #1^2 + (48 C NC -
64 C NC^3) #1^3 + (9 - 24 NC^2 + 16 NC^4) #1^4 &, 1] ||
xstep ==
Root[9 A^4 - 40 A^2 B^2 + 16 B^4 - 24 A^2 C^2 + 32 B^2 C^2 +
16 C^4 + (48 A^2 C NC - 64 B^2 C NC -
64 C^3 NC) #1 + (18 A^2 - 40 B^2 - 24 C^2 - 24 A^2 NC^2 +
32 B^2 NC^2 + 96 C^2 NC^2) #1^2 + (48 C NC -
64 C NC^3) #1^3 + (9 - 24 NC^2 + 16 NC^4) #1^4 &, 2] ||
xstep ==
Root[9 A^4 - 40 A^2 B^2 + 16 B^4 - 24 A^2 C^2 + 32 B^2 C^2 +
16 C^4 + (48 A^2 C NC - 64 B^2 C NC -
64 C^3 NC) #1 + (18 A^2 - 40 B^2 - 24 C^2 - 24 A^2 NC^2 +
32 B^2 NC^2 + 96 C^2 NC^2) #1^2 + (48 C NC -
64 C NC^3) #1^3 + (9 - 24 NC^2 + 16 NC^4) #1^4 &, 3] ||
xstep ==
Root[9 A^4 - 40 A^2 B^2 + 16 B^4 - 24 A^2 C^2 + 32 B^2 C^2 +
16 C^4 + (48 A^2 C NC - 64 B^2 C NC -
64 C^3 NC) #1 + (18 A^2 - 40 B^2 - 24 C^2 - 24 A^2 NC^2 +
32 B^2 NC^2 + 96 C^2 NC^2) #1^2 + (48 C NC -
64 C NC^3) #1^3 + (9 - 24 NC^2 + 16 NC^4) #1^4 &, 4]) &&
3 A^2 + 4 B dist + xstep (8 C NC + 3 xstep) ==
4 (B^2 + C^2 + NC^2 xstep^2)

Related

Non-linear system of 9 equations 9 unknowns MATLAB - unknowns coupled in polynomial ratio

Goal
I want to solve a system of 9 non-linear equation with 9 unknowns with solve Matlab.
All 9 unknowns are coupled as a ration of polynoms (see myfun lower)
Fsolve
x02=[5000,5000,5000,0.4,0.4,0.4,0.4,0.4,0.4];
ctrl2=[9894+1i*0.118,9894+1i*0.118,9894+1i*0.118,0.5,0.5,0.5,0.5,0.5,0.5];
f2 = #(x) myfun(x,Peff);
options2 = optimoptions('fsolve','Algorithm','trust-region-dogleg','Display','iter-detailed'...
,'MaxFunEvals', 100000, 'MaxIter', 100000,'TolX',1e-12,'TolFun',1e-12,...
'Jacobian','on');
[x2,F2,exitflag2,output2] = fsolve(f2,x02,options2);
Function myfun, return the system of equation to feed into fsolve an corresponding Jacobian
function [F,J] = myfun( x, p)
% System of equation
F(1) = -(x(1) - x(1)*x(8)*x(9))/(x(4)*x(5) + x(6)*x(7) + x(8)*x(9) + x(4)*x(8)*x(7) + x(6)*x(5)*x(9) - 1) - p(1,1);
F(2) = -(x(2)*x(4) + x(2)*x(6)*x(9))/(x(4)*x(5) + x(6)*x(7) + x(8)*x(9) + x(4)*x(8)*x(7) + x(6)*x(5)*x(9) - 1) - p(1,2);
F(3) = -(x(3)*x(6) + x(3)*x(4)*x(8))/(x(4)*x(5) + x(6)*x(7) + x(8)*x(9) + x(4)*x(8)*x(7) + x(6)*x(5)*x(9) - 1) - p(1,3);
F(4) = -(x(1)*x(5) + x(1)*x(8)*x(7))/(x(4)*x(5) + x(6)*x(7) + x(8)*x(9) + x(4)*x(8)*x(7) + x(6)*x(5)*x(9) - 1) - p(2,1);
F(5) = -(x(2) - x(2)*x(6)*x(7))/(x(4)*x(5) + x(6)*x(7) + x(8)*x(9) + x(4)*x(8)*x(7) + x(6)*x(5)*x(9) - 1) - p(2,2);
F(6) = -(x(3)*x(8) + x(3)*x(6)*x(5))/(x(4)*x(5) + x(6)*x(7) + x(8)*x(9) + x(4)*x(8)*x(7) + x(6)*x(5)*x(9) - 1) - p(2,3);
F(7) = -(x(1)*x(7) + x(1)*x(5)*x(9))/(x(4)*x(5) + x(6)*x(7) + x(8)*x(9) + x(4)*x(8)*x(7) + x(6)*x(5)*x(9) - 1) - p(3,1);
F(8) = -(x(2)*x(9) + x(2)*x(4)*x(7))/(x(4)*x(5) + x(6)*x(7) + x(8)*x(9) + x(4)*x(8)*x(7) + x(6)*x(5)*x(9) - 1) - p(3,2);
F(9) = -(x(3) - x(3)*x(4)*x(5))/(x(4)*x(5) + x(6)*x(7) + x(8)*x(9) + x(4)*x(8)*x(7) + x(6)*x(5)*x(9) - 1) - p(3,3);
%% Jacobian
I compute the Jacobian myself but will spare you the detail, as it is considerably long
end
Results
Norm of First-order Trust-region
Iteration Func-count f(x) step optimality radius
0 1 2.45042e+19 1.39e+14 1
1 2 2.45042e+19 1 1.39e+14 1
2 3 2.45031e+19 0.25 4.77e+15 0.25
3 4 2.45031e+19 0.625 4.77e+15 0.625
4 5 2.45031e+19 0.15625 4.77e+15 0.156
5 6 2.44992e+19 0.0390625 6.8e+16 0.0391
6 7 2.44992e+19 0.0976562 6.8e+16 0.0977
7 8 2.44992e+19 0.0244141 6.8e+16 0.0244
8 9 2.4495e+19 0.00610352 2.03e+17 0.0061
9 10 2.4495e+19 0.0152588 2.03e+17 0.0153
10 11 2.4486e+19 0.0038147 7.67e+17 0.00381
11 12 2.4486e+19 0.00953674 7.67e+17 0.00954
12 13 2.44592e+19 0.00238419 4.62e+18 0.00238
13 14 2.44592e+19 0.00596046 4.62e+18 0.00596
14 15 2.40048e+19 0.00149012 5.62e+20 0.00149
15 16 2.40048e+19 0.00372529 5.62e+20 0.00373
16 17 2.40048e+19 0.000931323 5.62e+20 0.000931
17 18 2.40048e+19 0.000232831 5.62e+20 0.000233
18 19 2.36832e+19 5.82077e-05 1.52e+21 5.82e-05
19 20 2.36832e+19 0.000145519 1.52e+21 0.000146
20 21 2.3131e+19 3.63798e-05 4.24e+21 3.64e-05
21 22 2.3131e+19 9.09495e-05 4.24e+21 9.09e-05
22 23 2.21355e+19 2.27374e-05 1.26e+22 2.27e-05
23 24 2.21355e+19 5.68434e-05 1.26e+22 5.68e-05
24 25 2.01772e+19 1.42109e-05 4.2e+22 1.42e-05
25 26 2.01772e+19 3.55271e-05 4.2e+22 3.55e-05
26 27 1.5592e+19 8.88178e-06 1.76e+23 8.88e-06
27 28 1.5592e+19 2.22045e-05 1.76e+23 2.22e-05
28 29 1.17854e+18 5.55112e-06 7.24e+23 5.55e-06
29 30 3.43734e+16 1.38778e-05 1.9e+23 1.39e-05
30 31 1.23843e+15 3.46945e-05 4.04e+22 3.47e-05
31 32 1.23843e+15 8.67362e-05 4.04e+22 8.67e-05
32 33 7.49991e+13 2.1684e-05 4.25e+21 2.17e-05
33 34 7.49991e+13 5.42101e-05 4.25e+21 5.42e-05
34 35 3.19073e+13 1.35525e-05 3.46e+21 1.36e-05
35 36 3.19073e+13 3.38813e-05 3.46e+21 3.39e-05
36 37 3.19073e+13 8.47033e-06 3.46e+21 8.47e-06
37 38 3.19073e+13 2.11758e-06 3.46e+21 2.12e-06
38 39 3.19073e+13 5.29396e-07 3.46e+21 5.29e-07
39 40 3.19073e+13 1.32349e-07 3.46e+21 1.32e-07
40 41 3.19073e+13 3.30872e-08 3.46e+21 3.31e-08
41 42 3.19073e+13 8.27181e-09 3.46e+21 8.27e-09
42 43 3.19073e+13 2.06795e-09 3.46e+21 2.07e-09
43 44 3.19073e+13 5.16988e-10 3.46e+21 5.17e-10
44 45 3.16764e+13 1.29247e-10 3e+21 1.29e-10
45 46 3.16764e+13 1.29247e-10 3e+21 1.29e-10
46 47 3.16764e+13 3.23117e-11 3e+21 3.23e-11
47 48 3.16764e+13 8.07794e-12 3e+21 8.08e-12
48 49 3.16764e+13 2.01948e-12 3e+21 2.02e-12
49 50 3.16764e+13 5.04871e-13 3e+21 5.05e-13
50 51 3.16764e+13 1.26218e-13 3e+21 1.26e-13
51 52 3.16764e+13 3.15544e-14 3e+21 3.16e-14
52 53 3.16764e+13 7.88861e-15 3e+21 7.89e-15
53 54 3.16764e+13 1.97215e-15 3e+21 1.97e-15
54 55 3.16764e+13 4.93038e-16 3e+21 4.93e-16
fsolve stopped because the relative norm of the current step, 1.097484e-16, is less than
max(options.TolX^2,eps) = 2.220446e-16. However, the sum of squared function values,
r = 3.167644e+13, exceeds sqrt(options.TolFun) = 1.000000e-06.
Optimization Metric Options
relative norm(step) = 1.10e-16 max(TolX^2,eps) = 2e-16 (selected)
r = 3.17e+13 sqrt(TolFun) = 1.0e-06 (selected)
exitflag2 =
-2
output2 =
iterations: 54
funcCount: 55
algorithm: 'trust-region-dogleg'
firstorderopt: 3.000805388686251e+21
message: 'No solution found.…'
Problem
Initial guess
x02 =
1.0e+03 *
Columns 1 through 5
5.000000000000000 5.000000000000000 5.000000000000000 0.000400000000000 0.000400000000000
Columns 6 through 9
0.000400000000000 0.000400000000000 0.000400000000000 0.000400000000000
Solution given by fsolve
x2 =
1.0e+03 *
Columns 1 through 2
5.000098340971978 - 0.000000066639557i 5.000100855522207 + 0.000000027141142i
Columns 3 through 4
5.000100887684736 + 0.000000021333305i 0.000500827051867 + 0.000000033172152i
Columns 5 through 6
0.000498312570833 - 0.000000060511167i 0.000500859436647 + 0.000000027409553i
Columns 7 through 8
0.000500831092720 + 0.000000033506374i 0.000500831171443 + 0.000000033543065i
Column 9
0.000498337065684 - 0.000000066909835i
What the solution should be (control)
ctrl2 =
1.0e+03 *
Columns 1 through 2
9.894000000000000 + 0.355900000000000i 9.894000000000000 + 0.355900000000000i
Columns 3 through 4
9.894000000000000 + 0.355900000000000i 0.000499999000000 + 0.000000000000000i
Columns 5 through 6
0.000499999000000 + 0.000000000000000i 0.000499999000000 + 0.000000000000000i
Columns 7 through 8
0.000499999000000 + 0.000000000000000i 0.000499999000000 + 0.000000000000000i
Column 9
0.000499999000000 + 0.000000000000000i
Comments
As you can see solve crashes fairly quick without going very far from the initial guess.
I tried changing TolX TolFun Algorithm but still crashes (following advice from Matlab website under what to do when algorithm fails)
The algorithm crashes similarly for other algorithm in fsolve and lsqnonlin (levnberg, trust-region-dogleg, trust-region-reflective)
Question to you:
Can you help figure out what I need to do in order to build an
algorithm that will converge to the control values?
Thank you
What you are experiencing is actually nothing wrong with the solver. More than likely, you simply have many local minimizers in the problem, and the optimization algorithm is getting stuck there. There is really not much you can do about that... Almost all optimization solvers that you get your hand on are based on the principle of gradient descent (more or less), so they will guide you to a minimizer, but not necessarily the global one. What some people do is to generate a large set of random initial conditions, and to run the optimization solver for each initial condition. This isn't guaranteed to mean that one of the solutions you get back is a global minimizer, but at least you should be able to do better than a single initial guess.
If you really NEED to find the global minimizer, then you need to use some type of "Groebner-basis" solution method. These types of solvers are based on "elimination theory" and will yield a univariate polynomiial containing all of the global minimizers. However, these solvers are usually symbolic, extremely memory intensive, and basically aren't guaranteed to finish in a finite amount of time. I would suspect (I don't really know) that these problems are NP hard. In my experience, a seemingly small problem like the one you show can take very long to solve (if at all).

Interpretation of these root objects

I have solved this system of equations (see below) in Mathematica for real x where the coefficients of the equations are functions of real parameters a,b and c. Mathematica then displays real solutions x with constraints on a,b and c.
The constraints for c (for example) are written in function of roots objects Root[,k]. In the output, I see for instance Root[,1] < c <= Root[,2]. On the other hand, I also see the condition 0< c < Root[,3].
If I'm correct, this implies that I can assume that Root[,1] < Root[,2]? However, can I also assume that Root[,2] < Root[,3]? Furthermore, since Mathematica displays the constraints this way I can assume that these roots (I mean the root objects) are all real, otherwise the statements would be meaningless? I know these root objects are difficult to handle but I really need a proper interpretation to set up the admissible (a,b,c) domain such that the system admits a real solution x.
The Mathematica code for the system is:
Reduce[
16 x^4 - 40 a x^3 + (15 a^2 + 24 b) x^2 - 18 a b x + 3 b^2 == 0
&& 5 a x - 4 x^2 - b > 0
&& 15 a x - 20 x^2 - 3 b < 0
&& 4 x^3 - 8 c x^2 + 5 c a x - c b > 0
&& c > 0 && x > 0,
x, Reals]
Thanks in advance!
Cheers.

Simple way to calculate number of chess material combinations

In chess, one player can have different material combinations, for example:
"1 queen, 2 rooks, 2 knights, 2 bishops, 8 pawns + the king" is one combination
if the player loses one bishop:
"1 queen, 2 rooks, 2 knights, 1 bishop, 8 pawns + the king" is another combination
..afterwards, if a pawn is promoted to a knight, then:
"1 queen, 2 rooks, 3 knights, 1 bishop, 7 pawns + the king" is another combination
OK, the following combination is not valid:
"5 queens, 5 rooks, 5 knights, 5 bishops, 2 pawns + the king"
since you lack of pawns to promote. (5 queens = 4 pawns needed) (5 rooks = 3 pawns needed) , etc. so 4 + 3 + 3 + 3 = 13 pawns needed. Since 2 pawns on the board, then at most 6 pawns could be promoted. Not valid.
How many valid material combinations are there?
I computed 8694 combinations using the following C code. The question is:
Do you find simpler/efficient algorithm to calculate it? (less cycles, less calculations, clearer code, etc.) ... or even a math formulae??
total = 0;
for (queens=0;queens<=9;queens++)
for (rooks=0;rooks<=10;rooks++)
for (bishops=0;bishops<=10;bishops++)
for (knights=0;knights<=10;knights++)
for (pawns=0;pawns<=8;pawns++)
{
pawnsRequested = 0;
if (queens>1) pawnsRequested += queens - 1;
if (rooks>2) pawnsRequested += rooks - 2;
if (bishops>2) pawnsRequested += bishops - 2;
if (knights>2) pawnsRequested += knights - 2;
if (8-pawns < pawnsRequested) continue;
total++;
}
printf("%i\n",total);
If the piece types were independent, then we could just multiply: 10 possibilities for the queens times 11 possibilities for the rooks times etc. We need to track pawn usage, however. There's a mathematical trick called generating functions where we can encode the possibilities for, e.g., rooks as
3 + x + x^2 + x^3 + x^4 + x^5 + x^6 + x^7 + x^8,
where the power of x denotes the number of pawns used, and the coefficient denotes the number of possibilities. Here, there are three possibilities that require no promoted pawns (0, 1, 2), one that requires one promoted pawn (3), one that requires two promoted pawns (4), etc. Now we can multiply each of the factors together (respectively, queens, rooks, bishops, knights, pawns).
(2 + x + x^2 + x^3 + x^4 + x^5 + x^6 + x^7 + x^8)
* (3 + x + x^2 + x^3 + x^4 + x^5 + x^6 + x^7 + x^8)
* (3 + x + x^2 + x^3 + x^4 + x^5 + x^6 + x^7 + x^8)
* (3 + x + x^2 + x^3 + x^4 + x^5 + x^6 + x^7 + x^8)
* (1 + x + x^2 + x^3 + x^4 + x^5 + x^6 + x^7 + x^8)
Here it is from Wolfram Alpha.
The coefficients of 1 through x^8, which are the number of possibilities for 0 to 8 pawns required, are 54, 135, 261, 443, 693, 1024, 1450, 1986, 2648, summing to 8694.

In Mathematica, how can I cut off the high-order terms in a polynomial?

For example, I have a polynomial y=a_0+a_1 x + ..... + a_50 x^50. Since I know that the high-order terms are imposing negligible effects on the evaluation of y, I want to cut off them and have something like y=a_0+a_1 x + ..... + a_10 x^10, the first eleven terms. How can I realize this?
I thank you all in advance.
In[1]:= y = a0 + a1*x + a2*x^2 + a3*x^3 + a4*x^4;
y /. x^b_ /; b >= 3 -> 0
Out[2]= a0 + a1 x + a2 x^2
The mathematically proper approach..
Series[ a0 + a1*x + a2*x^2 + a3*x^3 + a4*x^4, {x, 0, 2}] // Normal
-> a0 + a1 x + a2 x^2
If your polynomial is actually as simple as shown, with a term for every power of x and none others, you can simply use Take or Part to extract only those terms that you want because of the automatic ordering (in Plus) that Mathematica uses. For example:
exp1 = Expand[(1 + x)^9]
Take[exp1, 5]
1 + 9 x + 36 x^2 + 84 x^3 + 126 x^4 + 126 x^5 + 84 x^6 + 36 x^7 + 9 x^8 + x^9
1 + 9 x + 36 x^2 + 84 x^3 + 126 x^4
If it is not you will need something else. Bill's replacement rule is one concise and efficient method. For more complex manipulations you may wish to decompose the polynomial using CoefficientArrays, CoefficientRules, or CoefficientList.
There is a shortcut to the previous answers which is even more symbolic. You write, say,
y[x_] = a0 + a1 x + a2 x^2 + a3 x^3 + a4 x^4 + a5 x^5;
y[x] + O[x]^3
which gives you,
a0 + a1 x + a2 x^2 + O[x]^3

Simplify Absolute Value in Mathematica

I currently have a large expression with many terms of the form
Abs[-2 b + 2 d1 m + l Tan[\[Theta]]]
I know, from the geometry of my problem, that
-2 b + 2 d1 m + l Tan[\[Theta]] > 0
However, when I try to simplify my expression,
Simplify[Abs[-2 b + 2 d1 m + l Tan[\[Theta]]], -2 b + 2 d1 m + l Tan[\[Theta]] > 0]
I just get back
Abs[-2 b + 2 d1 m + l Tan[\[Theta]]]
How can I make Mathematica simplify out the unnecessary absolute value?
EDIT 1
The full expression which I'm trying to simplify is
-(1/(2 (m - Tan[\[Theta]])))
Sqrt[1 + m^2] (B2 Sqrt[(-2 b + 2 d1 m + l Tan[\[Theta]])^2] +
B4 Sqrt[(-2 b + 2 d2 m + l Tan[\[Theta]])^2] +
B5 Sqrt[(2 b + 2 d3 m + l Tan[\[Theta]])^2] +
B7 Sqrt[(2 b + 2 d4 m + l Tan[\[Theta]])^2] +
B1 Sqrt[(2 b - 2 (d1 + l) m + l Tan[\[Theta]])^2] +
B3 Sqrt[(2 b - 2 (d2 + l) m + l Tan[\[Theta]])^2] +
B6 Sqrt[(-2 (b + (d3 + l) m) + l Tan[\[Theta]])^2] +
B8 Sqrt[(-2 (b + (d4 + l) m) + l Tan[\[Theta]])^2])
The terms being squared under each of the radicals is known to be a positive real number.
Since the terms are all known to be real and positive, squaring and taking the square-root will only give you the same number. Hence, you could do something like
expr /. Sqrt[(x___)^2] :> x
where expr is your giant expression above.
Here are two ideas:
1)
Simplify[Abs[-2 b + 2 d1 m + l Tan[\[Theta]]],
0 < \[Theta] < \[Pi]/2 && l > 0 && 2 d1 m > 0 && -2 b > 0]
2)
f[e_] := 100 Count[e, _Abs, {0, Infinity}] + LeafCount[e]
Simplify[Abs[-2 b + 2 d1 m + l Tan[\[Theta]]], -2 b + 2 d1 m +
l Tan[\[Theta]] > 0, ComplexityFunction -> f]
Th complexity function f makes Abs more expensive than Times. See docu for Simplify. Does that help?
If you only wish to remove specific instances of absolute value, you could do something along these lines:
Clear[removeAbs]
removeAbs[expr_, r_] := expr /. {Sqrt[r^2] :> r, Abs[r] :> r}
That way it only removes the absolute value from any expressions you specify:
In: removeAbs[Abs[x] + Abs[y], x]
Out: x + Abs[y]
I'll see if I can find a nicer looking solution than this.
I'm constantly stimied by things like Abs[a]^2, and stuff like using Assuming with a\[Element]Reals doesn't help.
I found some help here WolframMathWorld - Absolute Square with ComplexExpand[Abs[a]^2, TargetFunctions -> {Conjugate}], but sometimes it still returns stuff like Conjugate[Sqrt[a^2 + b^2]] and I've found wrapping a second ComplexExpand (without parameters) around that helps.

Resources