0

I have a vector of functions and I am trying to obtain subsets from it. I transform the functions in the vector into a cell array so that I can index into it. Here is the script

coeff1 = 1;
coeff2 = 2;
coeff3 = 3;

F = @(x) [... 
coeff1*x(1)*x(4); ...
0; ...
coeff2*x(3); ... 
coeff3*x(7)*x(3) ...
];

G = regexp(func2str(F), ';|\[|\]', 'split');
H = cellfun(@str2func, strcat(G{1}, G(2:end-1)), 'uni', 0);
F2 = @(y)cellfun(@(x)x(y),H(2:4));
F2(rand(1,4));

But I get an error when testing the function. It says coeff1 is undefined. Somehow the parsed function does not recognize it. What could be wrong?

Thanks in advance.

milez
  • 2,201
  • 12
  • 31
  • Just to clarify, `F` is not a vector of functions, it's a function returning a vector – zeeMonkeez Mar 29 '16 at 16:13
  • So why does indexing the output of `F` not suffice? – zeeMonkeez Mar 29 '16 at 16:15
  • @zeeMonkeez Thanks for the correction! Indexing the output of F does not suffice. I need subsets for I am testing an algorithm that requires that. – milez Mar 29 '16 at 16:21
  • Maybe you can explain the underlying problem. `regexp`ing function strings and putting those back together seems pretty hackish and unreliable – zeeMonkeez Mar 29 '16 at 16:23
  • 1
    This behavior is explicitly stated in [the documentation](http://www.mathworks.com/help/matlab/ref/str2func.html): `Function handles created using str2func do not have access to variables outside of their local workspace or to nested functions.` [And there is an example](http://www.mathworks.com/help/matlab/ref/str2func.html#buyd7x5-1). – sco1 Mar 29 '16 at 16:29
  • @zeeMonkeez My original problem is stated in this Q: http://stackoverflow.com/questions/36279499/how-to-obtain-a-subset-of-functions-from-a-function-handle-that-is-a-vector-of-f. I got an answer but it is not as efficient as this would be if it worked, due to cell indexing being slow. – milez Mar 29 '16 at 16:31
  • @excaza but these variables are not outside the local workspace? – milez Mar 29 '16 at 16:31
  • Functions have their own workspace, the base workspace is not the local workspace for an anonymous function. – sco1 Mar 29 '16 at 16:32
  • You could try to replace occurrences of `coeff1` etc with the actual value (using `strrep`). But really, is there no way to start with something other than `F` if it isn't supposed to be evaluated all at once, anyways? – zeeMonkeez Mar 29 '16 at 16:40
  • @zeeMonkeez I will look into that. Also I have to evaluate it all at once at times, then extract many different subsets and evaluate those (computing times). – milez Mar 29 '16 at 16:41

1 Answers1

0

As @excaza has noted, functions generated with str2func do not have access to variables not in their workspace. That leaves you with two workarounds: you could replace occurrences of variable names with the value with strrep or regexprep: coeff1 becomes (1), etc. Or you could store all coefficients in one vector and pass them as a second argument:

F = @(x, coeff) [... 
coeff(1)*x(1)*x(4); ...

That still leaves you to deal with string operations and function handle operations. Both are costly and prone to breaking. Since your original question is slightly different, and specifically mentions that you want speed, let me suggest a different approach:

Your example suggests that F has a particular structure, namely that each line is the product of particular elements of x, multiplied by a constant. In that case, you can utilize the this structure to generate function handles as you need them:

% Coefficient matrix for x. Along second dimension, 
% elements of x will be multiplied with these factors. Along third
% dimension, these products (multiplied with the corresponding item of C)
% will be summed. 

X = logical(cat(3, ...
  [  1     0     0
     0     1     1
     0     0     0
     0     0     0
     1     1     1  ], ...
  [  0     0     0
     1     0     0
     0     0     0
     0     0     1
     0     0     0  ]));

% coefficients for each row
C = [ 1, 2
      2, 3
      0, 0
      0, 3
      1, 0 ];

% anonymous function generating anonymous functions for particular rows
F = @(ind) @(x) sum(C(ind, :) .* squeeze(prod(bsxfun(@times, X(ind, :, :), x) + ~X(ind, :, :), 2)), 2);
% get one of those functions and test
newF = F([2 4]);
x = [1, 2, 3];
newF(x)

allF = F(':');
allF(x)

So F is the function that, given row indices, returns a function that can be applied to x.

zeeMonkeez
  • 5,057
  • 3
  • 33
  • 56
  • It is clever, but there are some rows of the form coeffx*x1*x2+coeffy*x3*x4. And this does not really answer the question :s – milez Mar 30 '16 at 06:54
  • @milez excaza and I have lined out why what you are trying to do is impossible, with some caveats; this is in my answer now. I also extended the example to reflect the sum. I still bet this is way faster than string/cell/str2func operations. – zeeMonkeez Mar 30 '16 at 13:33
  • Yeah, it is efficient! And its good to know that it cant be done the way I imagined. – milez Mar 30 '16 at 13:54