Using subs for multiple substitution when the symbolic expression is a matrix

3 views (last 30 days)
Hi,
I have an expression DesignMatrixMult which is 2*2 matrix (in general it will be a n*n matrix). The expression is in terms of four symbolic variables q1/q2/x1/x2.
DesignMatrixMult = [ ((q1*(exp(-q1*x1) - exp(-q2*x1)))/(q1 - q2)^2 - (exp(-q1*x1) - exp(-q2*x1))/(q1 - q2) + (q1*x1*exp(-q1*x1))/(q1 - q2))^2 + ((q1*(exp(-q1*x2) - exp(-q2*x2)))/(q1 - q2)^2 - (exp(-q1*x2) - exp(-q2*x2))/(q1 - q2) + (q1*x2*exp(-q1*x2))/(q1 - q2))^2, - ((q1*(exp(-q1*x1) - exp(-q2*x1)))/(q1 - q2)^2 + (q1*x1*exp(-q2*x1))/(q1 - q2))*((q1*(exp(-q1*x1) - exp(-q2*x1)))/(q1 - q2)^2 - (exp(-q1*x1) - exp(-q2*x1))/(q1 - q2) + (q1*x1*exp(-q1*x1))/(q1 - q2)) - ((q1*(exp(-q1*x2) - exp(-q2*x2)))/(q1 - q2)^2 + (q1*x2*exp(-q2*x2))/(q1 - q2))*((q1*(exp(-q1*x2) - exp(-q2*x2)))/(q1 - q2)^2 - (exp(-q1*x2) - exp(-q2*x2))/(q1 - q2) + (q1*x2*exp(-q1*x2))/(q1 - q2))]
[ - ((q1*(exp(-q1*x1) - exp(-q2*x1)))/(q1 - q2)^2 + (q1*x1*exp(-q2*x1))/(q1 - q2))*((q1*(exp(-q1*x1) - exp(-q2*x1)))/(q1 - q2)^2 - (exp(-q1*x1) - exp(-q2*x1))/(q1 - q2) + (q1*x1*exp(-q1*x1))/(q1 - q2)) - ((q1*(exp(-q1*x2) - exp(-q2*x2)))/(q1 - q2)^2 + (q1*x2*exp(-q2*x2))/(q1 - q2))*((q1*(exp(-q1*x2) - exp(-q2*x2)))/(q1 - q2)^2 - (exp(-q1*x2) - exp(-q2*x2))/(q1 - q2) + (q1*x2*exp(-q1*x2))/(q1 - q2)), ((q1*(exp(-q1*x1) - exp(-q2*x1)))/(q1 - q2)^2 + (q1*x1*exp(-q2*x1))/(q1 - q2))^2 + ((q1*(exp(-q1*x2) - exp(-q2*x2)))/(q1 - q2)^2 + (q1*x2*exp(-q2*x2))/(q1 - q2))^2]
I want to evaluate RANK of the DesignMatrixMult for specific values of the four symbolic variables. I use SUBS function on DesignMatrixMult, then use DOUBLE followed by RANK and this whole process takes ~0.016 second per evaluation (average by checking on a FOR loop run 10^4 times) but this is not good enough as I need to do this evaluation 10^8 times. I want to understand ways to speed up the evaluation process while retaining the accuracy afforded by symbolic approach.
I thought by doing multiple evaluations together the process will be faster so tried various ways (see below) but not any headway till now.
% METHOD 1 - Using <http://www.mathworks.com/help/symbolic/subs.html SUBS> with "Multiple Scalar Expansion"
%Note, dataset C contains the necessary values for the 4 symbolic variables. q1/q2 lies between 0 and 1, while x1/x2 lies between 0 and 500
EvalRankDesignMatrixMultMethod1 = rank(double(vpa(subs(DesignMatrixMult,{t1(1),t1(2),q(1),q(2)},{C.z26,C.z27,C.z21,C.z22}))));
But the above approach gives wrong answers. Specifically, DesignMatrixMult is a 2*2 matrix and in the output the rows corresponding to 10^8 instances are not arranged in correct order and subsequent rank is incorrect.
How to make the above subs approach work?
% METHOD 2 - Using cellfun approach on entire set of 10^8 rows
%Create a symbolic function corresponding to DesignMatrixMult.
DesignMatrixMultF = symfun(DesignMatrixMult,[t1 q]);
%Create an anonymous function to calculate rank of DesignMatrixMultF.
RankDesignMatrixMultF = @(xsub1,xsub2,qsub1,qsub2)rank(double(DesignMatrixMultF(xsub1,xsub2,qsub1,qsub2)));
%Evalauting rank for all the 10^8 combinations in one go
EvalRankDesignMatrixMultMethod2=cell2mat(cellfun(RankDesignMatrixMultF,num2cell(double(C.z26)),num2cell(double(C.z27)),num2cell(double(C.z21)),num2cell(double(C.z22)),'UniformOutput',false));
The above code starts executing but after a couple of minutes it issues an out of memory error and my computer had to be restarted.
% METHOD 3 - Using cellfun approach on chunks of 10^4 rows. Idea is that I will execute these chunks 10^4 times so that out of memory error will not happen.
StartCnter = 1;
EndCnter = 10000;
%Running the Cellfun in chunks of 10^4
EvalRankDesignMatrixMultMethod3 = cell2mat(cellfun(RankDesignMatrixMultF,num2cell(double(C.z26(StartCnter:EndCnter))),num2cell(double(C.z27(StartCnter:EndCnter))),num2cell(double(C.z21(StartCnter:EndCnter))),num2cell(double(C.z22(StartCnter:EndCnter))),'UniformOutput',false));
The above approach works but takes ~160 seconds..so this means 0.016 seconds per evaluation...so for the complete dataset it will take impractical amount of time. So it seems cellfun approach (even by doing it in chunks) is not a worthy alternative.
PS: If I had used a matlabFunction approach (no symbolic) then per evaluation takes ~ 6E-5 so 10^8 evaluations wraps in 6000 seconds which is amazing...I understand symbolic can't achieve this peformance but how can I bridge the gap.
  1 Comment
Hari
Hari on 26 Aug 2014
Hi,
Could I get feedback in case the question is confusing etc. Or am I asking something to which there is no better solution than what I already have.
Would to be great to get some inputs.
Thanks Hari

Sign in to comment.

Answers (1)

Christopher Creutzig
Christopher Creutzig on 29 Aug 2014
If you want to substitute values for all variables, want to get a double, and plan to do that more often, I definitely recommend you use matlabFunction.
In case that is not an option (I don't see why it wouldn't in your case, but such cases can exist for some inputs), you should still make sure you use vpa values to substitute, i.e., instead of
subs(A, x, 1.234)
use
subs(A, x, vpa(1.234))
since the default of returning an exact, somewhat simplified, symbolic result takes more time and is hardly ever needed if in the end you are not interested in an exact value (like sqrt(2)+sin(1)) but convert to double instead (to get the approximation 2.2557 or whatever).

Community Treasure Hunt

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

Start Hunting!