0

the problem I am experience is one that I haven't been able to overcome.

The actual code that I am running is a bit too complicated, and so I will just reproduce the problem here in simpler terms.

>> syms x 
>> T_m = [[exp(x), x^2];[x,sin(x)]];
>> sum_matrix = T_m(1,1) + T_m(1,2) + T_m(2,1) + T_m(2,2);
>> main_func = matlabFunction(sum_matrix)
main_func = 

    @(x)x+exp(x)+sin(x)+x.^2

>> integrand = @(x) exp(-x) .* main_func(x);
>> Q = integral(@(x) integrand(x), 0,2*pi);

>> Q
ans =

    9.6677

The main issue that I am having in my actual code is the use of

>> main_func = matlabFunction(sum_matrix)

In this example, the line runs almost instantaneously. The functions that I am dealing with are very complex, and this line of code takes about ~45 seconds to run, which ridiculous.. especially since I'm reiterating through this code 100+ times.

I believe a solution is to work exclusively with function handles rather than symbolic expressions. I haven't been able to do this yet though, mainly because I cannot index into matrices twice (something along the lines of T_m(x)(1,1), which works for many languages but not MATLAB).

Any insight is appreciated, thanks!

RRR
  • 69
  • 6
  • any reason a regular .m file function doesn't work? – user3528438 Feb 28 '16 at 03:38
  • Can you add emphasis to your question? Note that matlabFunction() is a function built in MATLAB. All it does is convert symbolic expressions to function handles. – RRR Feb 28 '16 at 03:41
  • I mean, do you really need to create functions dynamically like this? – user3528438 Feb 28 '16 at 03:46
  • In my actual code, T_m is in a for-loop being defined by several other functions. I break apart the functions into separate variables for readability . In my situation, these functions are well-defined in quantum theory, so the dynamic functions are necessary – RRR Feb 28 '16 at 03:50
  • 1
    Why not just do `sum_matrix = sum(sum(T_m(x)));`? Or is the actual use case much more complicated? – TroyHaskin Feb 28 '16 at 06:00

1 Answers1

1

One possible option would be to use a cell array of function handles, since funcell{k1,k2}(3) is valid syntax. However, using cells would also be pretty slow.

So I suggest transforming your whole symbolic array of functions to an array-valued symbolic array, and working on that. So, with your example:

syms x;
T_m = [[exp(x), x^2];[x,sin(x)]];
funT = matlabFunction(T_m);
%// produces @(x)reshape([exp(x),x,x.^2,sin(x)],[2,2])

You can use the sum of this quantity as a new anonymous function,

main_func = @(x) sum(sum(funT(x)));

which might be the same thing that Troy Haskin suggested.

The main reason I decided to add an answer is to also address your other, related question. If you want to use the individual elements of the original array of functions, you should either use a cell array of handles after all (then you just have to access funcell{k1,k2}(x)), or if it turns out that using cells is slower than unnecessarily computing the full array, just throw away what you don't need:

id1 = eye(size(T_m,1)));  %// for Kronecker delta, essentially
id2 = eye(size(T_m,2)));  %// same here
T_m12 = @(x) id1(1,:)*funT(x)*id2(:,2);

%// or even better, generally
funT_m = @(x,k1,k2) id1(k1,:)*funT(x)*id2(:,k2);

To complete the circle: if you start from a cell array of function handles, you can transform that to an array-valued function handle, which is really ugly and messy, but should work unless your function is a very huge beast (but in that case, all hope's lost anyway).

Final note, just for the sake of completeness: the answer to the suggested duplicate of your other question shows you how you can assign into the return value of a function call, without using a temporary variable. The main problem with this approach is that it makes the code impossible to read by human beings, but otherwise it is as low-level as it gets in terms of efficiency. If you're desperate, you might consider this route as well (as it doesn't involve cells, symbolic math, nor an unnecessary vector-matrix-vector product):

funT_m = @(x,k1,k2) subsref(funT(x),struct('type','()','subs',{{k1,k2}}));

But bear in mind that we're still computing the full array in x, we're just throwing away the unnecessary parts as efficiently as possible.

Post-final note: if you eventually want to integrate every matrix element you have, you should also consider using the full array-valued function in integral, making use of its 'arrayvalued',true parameter-value pair. This will make the integration become slower, but you can compute the integral of every matrix element all at once, without having to throw away any results.

Community
  • 1
  • 1