5

What language feature or outside-the-box hack can I use to accomplish function inlining in MATLAB? Annoyingly, a Google search for "matlab inline function" reveals that MATLAB's designers thought that "to inline" means "to construct an anonymous function out of a string" (...wtf?).

The reason I ask is I am writing a script that needs to run fast, and I am encountering a lot of situations where it would be nice to have a helper function handle some simple addition or something to avoid off-by-one errors. However, the cost of a function call (as measured by tic/toc) would not be worth it. I refuse to believe that MATLAB would lack a function inlining feature because that would discourage decomposition!

Worst case, I could resort to using M4 macros.


EDIT: In response to eat's comment, here is a situation where I might like to inline a helper:

At one point, I need to loop (yeah, I know) over all windows of width windowWidth within a list:

lastWindowStartIdx = length(list) - windowWidth + 1;
for windowStartIdx = 1:lastWindowStartIdx
   display(list[windowStartIdx:windowStartIdx+windowWidth-1]); %the window we're looking at
end

It would be nice to be able to factor out those tricky, off-by-one-error-prone windowWidth calculations. E.g.:

lastWindowStartIdx = calcLastWindowStartIdx(length(list), windowWidth);
for windowStartIdx = 1:lastWindowStartIdx
   display(list[windowStartIdx:calcWindowEndIdx(windowStartIdx, windowWidth)]); %the window we're looking at
end
gnovice
  • 125,304
  • 15
  • 256
  • 359
AlcubierreDrive
  • 3,654
  • 2
  • 29
  • 45
  • Care to show any code where actually your `in lining` would be really beneficial? What you mean by `off-by-one errors`? Thanks – eat Mar 11 '11 at 16:06
  • @eat I've edited my question to include an example – AlcubierreDrive Mar 11 '11 at 16:23
  • 1
    When you say you "refuse to believe Matlab doesn't have inlining", this makes me think you are not very familiar with Matlab. MathWorks does not care about the performance of method and function calls, especially with respect to decomposition. The new MCOS classes, whose syntax supports decomposed design, have much slower method calls than old classes, there are silly syntax-related performance quirks, and there's a bug that doubles the old-style method call overhead in 64-bit Matlab. The official way to get M-code to go faster is to vectorize it. "Inline" wouldn't be their style. (Flame off.) – Andrew Janke Mar 11 '11 at 20:29
  • @Andrew You're right, I am new to Matlab. Sorry for the rantful tone in my question. It's just very strange to me (based mainly on experience in C-like languages and Python) that a language would actually not encourage decomp. – AlcubierreDrive Mar 14 '11 at 18:43
  • No worries. I kinda got my rant on too. It took me a long time (like, over a year) to get used to coding in Matlab coming from C, Java, and Perl. It really is different. And I'm not saying you shouldn't want inline and support for fast small objects in Matlab. (I want that too, and rather badly.) Just that you shouldn't be surprised to not get it. – Andrew Janke Mar 18 '11 at 22:54

2 Answers2

9

Specific answer:

In reference to your example use-case, this honestly strikes me as a sort of micro-optimization. These plus-one operations are certainly not the bottleneck in your code keeping it from running fast, so you should instead focus on speeding up the parts of your code where the bulk of your computations take place.

If you are only wanting to make this change for aesthetic (spelled it on the first try!) reasons, or because you just don't like keeping track of the extra ones, then creating a function to handle it as in your example is a bad choice in my opinion because it just makes the code that much harder to read and understand. I would suggest simply creating a new variable like so:

windowOffset = windowWidth - 1;
lastWindowStartIdx = length(list) - windowOffset;
for windowStartIdx = 1:lastWindowStartIdx
   display(list[windowStartIdx:windowStartIdx + windowOffset]);
end

General answer:

Regarding your more general question about how to create true inline functions in MATLAB like you can in C or C++, I don't believe there's any way to do this. I thought perhaps that an anonymous function may fit the bill, but after doing some simple timing comparisons with a number of different types of functions in MATLAB I found that an anonymous function is actually slower than a good ol' subfunction for a simple +1 operation.

Here were the sample functions I tested:

function parent_function
  add_one_anon = @(A) A+1;         %# An anonymous function
  add_one_inline = inline('A+1');  %# An "inline" function
  function add_one_nest            %# A nested function
    A = A+1;
  end
  %# Did the timing here ...
end
function A = add_one_sub(A)        %# A subfunction
  A = A+1;
end

I ran each of these 100,000 times incrementing a scalar value that started at 1, and here are the results:

            | Time (sec)
------------+------------       
subfunction |   0.0507
anonymous   |   0.0672
nested      |   0.0932
inline      |  14.7095

If anonymous functions acted like true inline functions, I would have expected them to be the fastest solution.

gnovice
  • 125,304
  • 15
  • 256
  • 359
  • Fair enough, that is indeed a great solution for this particular example. But before I accept your answer, could you please address my actual question, which is how (even a hackish way) to accomplish inlining? Thanks! – AlcubierreDrive Mar 11 '11 at 16:51
  • 1
    @Jon Rodriguez: You already mentioned M4. Other code generation techniques would also work. MATLAB has a JIT, so assuming they did that right (which is not necessarily a good assumption with MathWorks) there should not be much reason to manually specify the inlining. Many C and C++ compilers ignore user-provided inline directives anyway, since the compiler is better at figuring those out than humans. – kenm Mar 11 '11 at 17:30
  • 2
    Doing generalized inlining in the Matlab JIT would probably be very difficult, because what function is actually dispatched depends on the type of all the input variables and the state of the Matlab path at the time of that particular function call. – Andrew Janke Mar 11 '11 at 19:59
  • 1
    See http://stackoverflow.com/questions/1693429/matlab-oop-is-it-slow-or-am-i-doing-something-wrong/1745686#1745686 for benchmarks on various function call types. (It's a simplification because it doesn't consider cost of input and output arguments.) Also, in your benchmark, consider breaking the nested function out to a separate benchmark function. Its mere existence changes the enclosing parent_function to a "static workspace" and may have side effects (good or bad) on how the other function types are called from within parent_function. – Andrew Janke Mar 11 '11 at 21:54
  • @Andrew: The first few times I ran my benchmarks I didn't have the nested function in there, and I didn't see any appreciable difference in timing results after I added it in. – gnovice Mar 12 '11 at 03:23
0

In short, you can't inline, in C++ terms, functions in MATLAB. You probably already know this, but loops in MATLAB are slow and you should replace them with vectorized operations instead.

If you need to accelerate just the function call, you should probably pre-compute all your indices as a vectorized operation and then loop over the results.

windows = window_ranges(1, length(list), windowWidth);
for i = 1:size(windows,1),
   display(list[windows(i,1):windows(i,2)]);
end

function [ windows ] = window_ranges ( lower, upper, span )
    count = upper - span;
    windows = zeros(count, 2);
    windows(:,1) = 1:count;
    windows(:,2) = windows(:,1)+span-1;
end
André Caron
  • 44,541
  • 12
  • 67
  • 125
  • As a side note, the `window_ranges` could be made more general by actually using the `lower` parameter when you want it to be other than 1. – André Caron Mar 11 '11 at 17:39