Daniel Underwood
Daniel Underwood

Reputation: 2261

Split Anonymous Function into Terms

I am wanting to take a matlab anonymous function of something like @(x) = x + x^2 and split it into a cell array so that

f{1} = @(x) x
f{2} = @(x) x^2

I want to be able to do this with some arbitrary function handle. The best that I have come up with so far is taking in @(x) = x + x^2 as a string and splitting it by the addition signs and appending @(x) to the beginning of this. However, I would like to be able to directly use a function handle as the function argument. It would also be nice as using other variables could lead to some difficulty in the string approach.

I am also considering just taking in a cell array of function handles as an argument, which would be more difficult for the user but easier in my code.

For some background, I'm wanting to do this for some least squares data fitting code that I am writing for a class. This code will be for taking in a model function as an argument and I need to evaluate each term separately for the least squares process. I'm not limiting these models to polynomials and even if a polynomial is the model, I want the option to leave out certain powers in the polynomial. If someone has a better suggestion for taking a model function, that would be great too.

UPDATE: Someone wanted to know what I meant by

I'm not limiting these models to polynomials and even if a polynomial is the model, I want the option to leave out certain powers in the polynomial.

For some clarification, I was saying that I didn't want to limit the models to

c0 + c1*x + ... + cn*x^n

in which case I could just take in n as a parameter and create terms from that similar to what happens in polyfit. For example, if I know that my input data fits an even or odd function, I may want one of the following models

c0 + c1*x^2 + c2*x^4 + ... + ck*x^(2k)
c1*x + c2*x^3 + ... + cm*x^(2m-1)

Where k is even and m is odd. Or possibly a model that isn't strictly a polynomial, but keeps the coefficients linear, such as

c0 + exp(x) * ( c1 + c2*x + ... cn*x^(n-1) )

Upvotes: 3

Views: 350

Answers (1)

Luis Mendo
Luis Mendo

Reputation: 112659

This is an interesting problem. The string should not be split at + signs that are within a parenthesis group. For example, with

f = @(x) x + (x+1)*sqrt(x) + x^2 + exp(x+2);

the string should be split at the first, but not at the second + sign.

This can be accomplished as follows. To detect only + signs that are outside parentheses, add 1 for each opening parenthesis and subtract 1 for each closing parenthesis. Then the desired + signs are those with count 0.

I'm assuming the output should be a cell array of function handles. If it should be a cell array of strings just remove the last line.

F = functions(f);
str = F.function; %// get string from function handle
[pref, body] = regexp(str, '@\(.+?\)', 'match', 'split'); %// pref is the '@(...)' part
body = body{2}; %// body is the main part
ind = cumsum((body=='(')-(body==')'))==0 & body=='+'; %// indices for splitting
body(ind) = '?'; %// '?' will be used as split marker
ff = strcat(pref, strsplit(body, '?')); %// split, and then add prefix
ff = cellfun(@str2func, ff, 'uniformoutput', 0); %// convert strings to functions

Result in this example:

ff{1} =
    @(x)x
ff{2} =
    @(x)(x+1)*sqrt(x)
ff{3} =
    @(x)x^2
ff{4} =
    @(x)exp(x+2)

Upvotes: 2

Related Questions