Reduce length of sum of products of symbolic variables

4 views (last 30 days)
I am using Matlab symbolics toolbox to simplify an expression which is a sum of many single-variable products, where variables re-occur:
G1*P3 + G1*P5 + G1*P6 + G2*P3 + G2*P6 + G3*P2 + G3*P5 + G4*P2 + G4*P3 + G4*P5 + G4*P6 + G5*P2 + G5*P3 + G5*P5 + G5*P6 + G6*P3 + G6*P6 + G7*P2 + G7*P5 + G8*P2 + G8*P3 + G8*P5 + G8*P6
(created by using a loop with sym(sprintf('G%d', i))
Using simplify does not change the expression. I tried a custom command using collect(tmp,sym(sprintf('P%d', i))) in a loop. However, this simplifies up to
(G3 + G4 + G5 + G7 + G8)*P2 + (G1 + G2 + G4 + G5 + G6 + G8)*P3 + (G1 + G2 + G4 + G5 + G6 + G8)*P6 + (G1 + G3 + G4 + G5 + G7 + G8)*P5
How do I get
(G1 + G2 + G4 + G5 + G6 + G8)*(P3+P6) + (G1 + G3 + G4 + G5 + G7 + G8)*P5 + (G3 + G4 + G5 + G7 + G8)*P2
which is shorter and which you can get from directly looking at the expression? I started creating my own logic for simplification, but that seems not feasible.
I already tried this in Maple (with help by the Maple forum), but I have the expression in Matlab (and hundreds others, which are similiar). I want to omit calling Maple from Matlab for this.
A similar solution in Matlab does not work for me (tmp is expression):
matlabFunction(tmp, 'File', filename_test, 'Optimize', true)
The generated code file is unchanged relative to the initial expression.

Accepted Answer

Paul
Paul on 21 Nov 2022
Edited: Paul on 21 Nov 2022
Hi Moritz,
Would you mind explaining why it's necessary to get the expression into a particular form?
Recreating the expression
G=sym('G',[1 8]);
syms(G)
P=sym('P',[1 8]);
syms(P)
E = G1*P3 + G1*P5 + G1*P6 + G2*P3 + G2*P6 + G3*P2 + G3*P5 + G4*P2 + G4*P3 + G4*P5 + G4*P6 + G5*P2 + G5*P3 + G5*P5 + G5*P6 + G6*P3 + G6*P6 + G7*P2 + G7*P5 + G8*P2 + G8*P3 + G8*P5 + G8*P6
E = 
Surprised that simplify can't do better.
simplify(collect(E,P),100)
ans = 
One option might be to use coeffs.
[co,terms] = coeffs(E,P)
co = 
terms = 
Use unique to find unique coeffiecients.
[uniqueco,iuniqueco,ico] = unique(co)
uniqueco = 
iuniqueco = 3×1
1 2 3
ico = 4×1
1 2 3 2
Loop through the unique coefficients and combine with sum of corresponding terms:
Enew = 0;
for ii = 1:numel(unique(co))
Enew = Enew + uniqueco(ii)*sum(terms(ico == ico(ii)));
end
Enew
Enew = 
I don't know how robust unique is for vectors of sym expressions. It may be better to loop through manually and find matches using isAlways.
  2 Comments
Moritz Schappler
Moritz Schappler on 22 Nov 2022
Thanks for the quick reply. It works well for the given example, but as you mentioned, unique does not seem to work in all cases. If I for example have
G=sym('G',[1 9]);
syms(G)
P=sym('P',[1 9]);
syms(P)
E = G1*P2 + G2*P1 + G1*P3 + G3*P1 + G2*P3 + G3*P2 + G1*P8 + G9*P1 + G2*P9 + G9*P8
E = 
then I get Enew as
P2*(G1 + G2) + P3*(G1 + G3) + P8*(G1 + G9) + P9*(G2 + G3 + G9) + G2*P1;
After expansion this is
G1*P2 + G2*P1 + G1*P3 + G2*P2 + G3*P3 + G1*P8 + G2*P9 + G3*P9 + G9*P8 + G9*P9;
which is not the original expression, as can be seen e.g. by the missing G3*P1.
I used the following updated code based on your suggestion:
P=sym('P',[1 9]);
[co,terms] = coeffs(E,P);
assert(simplify(sum(co .* terms) - E)==0, 'error getting coefficients');
terms2 = sym(zeros(1,length(terms)));
for ii = 1:length(co)
for jj = 1:length(co)
if isAlways(co(ii)==co(jj), 'unknown', 'false')
terms2(ii) = terms2(ii) + terms(jj);
terms(jj) = 0;
end
end
end
Enew = sum(co .* terms2);
assert(simplify(Enew - E)==0, 'error simplifying the coefficients');
disp(Enew);
I want to have this particular form to express combinations of the G- and P-value in a table. Each of the expressions is a row in the table, saying, that these combinations work for the case of the table row. I afterwards reshape this into a string, which looks like "(v,t,r,c)-t, (v,t,r,p)-v" (different example). The G- and P-values are then separated by the dash (left G, right P) and v=P1, t=P2 and so on.
Paul
Paul on 22 Nov 2022
Hi Moritz,
Thank you for pointing out that error. The problem isn't with unique(), rather it was a bug in my use of unique. Here is an update that works for both of the examples. It uses unique to find the unique coefficients and then loops over those to find the correct mapping to the P terms
G=sym('G',[1 9]);
syms(G)
P=sym('P',[1 9]);
syms(P)
% first example
E = G1*P3 + G1*P5 + G1*P6 + G2*P3 + G2*P6 + G3*P2 + G3*P5 + G4*P2 + G4*P3 + G4*P5 + G4*P6 + G5*P2 + G5*P3 + G5*P5 + G5*P6 + G6*P3 + G6*P6 + G7*P2 + G7*P5 + G8*P2 + G8*P3 + G8*P5 + G8*P6;
Enew = func(E,P);
E,Enew,simplify(Enew - E)
E = 
Enew = 
ans = 
0
% second example
E = G1*P2 + G2*P1 + G1*P3 + G3*P1 + G2*P3 + G3*P2 + G1*P8 + G9*P1 + G2*P9 + G9*P8;
Enew = func(E,P);
E,Enew,simplify(Enew - E)
E = 
Enew = 
ans = 
0
function Enew = func(E,P)
[co,terms] = coeffs(E,P);
uniqueco = unique(co);
Enew = 0;
index = 1:numel(co);
for ii = 1:numel(uniqueco)
Enew = Enew + uniqueco(ii)*sum(terms(index(isAlways(uniqueco(ii) == co,'unknown','false'))));
end
end

Sign in to comment.

More Answers (0)

Products


Release

R2022b

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!