2

Hello fellow Earth hitchhikers, I have just stumbled upon how slow are anonymous functions in Matlab. However, I can't find a convenient alternative. I need to generate about 12 of these channels, each of them having 8 small functions. Here is one for example.

channels = [];
channel.name   = 'CHNAF';
channel.area   = 10;
channel.g      = 0.013;
channel.E      = 87.39;
channel.alphaa = @(V,ion) 0.9*(V+19)/(1-exp(-(V+19)/10));
channel.betaa  = @(V,ion) 36*exp(-0.055*(V + 44));
channel.infa   = @(a,b,V) a/(a+b);
channel.taua   = @(a,b,V) 1/(a+b);
channel.na     = 3;
channel.alphai = @(V,ion) 0.315*exp(-0.3*(V + 44));
channel.betai  = @(V,ion) 4.5/(1 + exp(-(V + 11)/5));
channel.infi   = @(a,b,V) a/(a+b);
channel.taui   = @(a,b,V) 1/(a+b);
channel.ni     = 1;
channels = [channels channel];

The generation is not a problem. But I want to use these functions and the following code makes it very very slow.

ch    = channels(1);
curr  = curr + ch.area*ch.g*ch.m^ch.na*ch.h^ch.ni*(V-ch.E);  
adot  = (ch.infa(ch.alphaa(V,ion),ch.betaa(V,ion),V) - ch.m)/ch.taua(ch.alphaa(V,ion),ch.betaa(V,ion),V);
idot  = (ch.infi(ch.alphai(V,ion),ch.betai(V,ion),V) - ch.h)/ch.taui(ch.alphai(V,ion),ch.betai(V,ion),V);

As noted in this thread it's the use of anonymous functions aka fun = @(x) x; that makes it so. What can I do to make it faster? (Note I am solving an ODE with those, so they are called thousands times).

Two possible concerns you might have.

  1. I do have lots of dummy functions and variables there. Ion or V are not always used. Sometimes channel.na or channel.ni are zero, so there is no need to call any functions. I need those for the sake of generality and simplicity.
  2. I can get rid of alpha and beta functions by doing
    infaNEW = @(V,ion)
    ch.infa(ch.alphaa(V,ion),ch.betaa(V,ion),V)
    This way I'll decrease the number of functions.

Both these enhancements are likely increasing performance 2 fold each, not 20 fold as anonymous functions are slowing me down. Maybe a more direct question: Is there a way to convert anonymous functions to the normal ones, maybe automatically printing them to .m files?

Community
  • 1
  • 1
neuronich
  • 135
  • 1
  • 8
  • What you are doing there, including functions as part of a `struct` goes in the direction of object oriented programming. Maybe you could define your channels as classes, and replace anonymous functions by methods? – A. Donda Dec 26 '13 at 15:49
  • @carandraug, I would gladly do. However it would increase the length of code and introduce many names that would be difficult to work with. As I said I have 12 of those channels, each having alphaa subfunction. So I'll have to write manually functions alphaaChannel1() alphaaChannel2()... After that I wouldn't be able to loop around them and sum them up just as I do now. – neuronich Dec 26 '13 at 15:49
  • @A.Donda Actually I have started implementing them as classes. The problem there is that I was still passing alphaa ... functions as parameters to the class, I wasn't using them as a field. (Because these alphaa functions have different functional shape.) **Can I generate a field for the class outside the class description?** – neuronich Dec 26 '13 at 16:08
  • I'm sorry, I never used OOP in Matlab, I just know it exists. What I imagine is this: You define one class for each of your "channels". Since they are defined separately, they contain different versions of the functions. But since they all provide the same interface, they can be used interchangeably when you pass them to the function that implements the actual numerical integration. In Java one would do it such that either the different classes `implement` the same interface, or they are all derived from the same abstract superclass, whose definition contains the common code. – A. Donda Dec 26 '13 at 16:15
  • Btw., functions wouldn't be "fields" but "methods". – A. Donda Dec 26 '13 at 16:15
  • @A.Donda I will try, but I don't feel it works that way in Matlab. I meant methods, sorry for the mistake. – neuronich Dec 26 '13 at 16:37

1 Answers1

1

I have posted the same question Matlab Central. Walter Roberson has given a pretty good response that has increased the performance by the order of magnitude.

You can convert anonymous functions to regular functions, yes, but the overhead will not be much different. It is the function call overhead that is slowing you down, not the fact that the functions are anonymous.

If you have the Symbolic toolbox, you could pass symbolic V and ion into your formulas, getting out expressions with the various functions expanded "in place"; simplify() that to optimize it a little, and then use matlabFunction() to convert the symbolic expression into an single anonymous function.

syms V ion 
curr  = ch.area*ch.g*ch.m^ch.na*ch.h^ch.ni*(V-ch.E);
adot  = (ch.infa(ch.alphaa(V,ion),ch.betaa(V,ion),V) - h.m)/ch.taua(ch.alphaa(V,ion),ch.betaa(V,ion),V);
idot  = (ch.infi(ch.alphai(V,ion),ch.betai(V,ion),V) - ch.h)/ch.taui(ch.alphai(V,ion),ch.betai(V,ion),V);
triple = [curr,adot,idot];
triplefcn = matlabFunction(simplify(triple), 'vars', [V, ion]);

Now a call to triplefcn passing in actual V and ion will return an array with curr, adot, idot as the columns. (It will be vectorized, too, which your current expressions are not.)

neuronich
  • 135
  • 1
  • 8
  • I don't know if you still store `triplefcn` in a `struct` but not doing that will also make it a tiny bit faster too. Accessing structure fields repeatedly can have a cost as well. The only faster way to do this sort of thing is to write your 12 functions as one big one using matrix/vector math. – horchler Dec 26 '13 at 19:22
  • I tried to do it without a structure but with the cell array of handles, it doesn't have any noticeable difference. However, I did the big MAMA function that would take all the parameters as a vector and spit out the big vector. There is `matlabFunction(fun,'file','myFile')` that will autogenerate the file for you. It works twice as fast. – neuronich Dec 27 '13 at 01:56