matlabFunction parse error
I'm using version 2.2.2 of symbolic package (which, BTW, is pretty awesome!) in Octave 3.8.2 and 0.7.6 version of SymPy.
I'm not sure if this is a feature request, bug or an upstream issue, but anyway - matlabFunction doesn't seem to currently support specifying array input arguments when passing a cell array as 'vars' parameter. An example may make that clearer:
syms x y a b
f = a*x^2 + b*y^2
fnum = matlabFunction(f, 'vars', {[x;y], [a;b]})
would result in a function handle callable e.g. as fnum([1;2], [3;4]) with MATLAB Symb. toolbox, but with octsympy it yields this error instead:
parse error:
syntax error
>>> @(Matrix([[x], [y]]),Matrix([[a], [b]])) a.*x.^2 + b.*y.^2
^
parse error:
invalid parameter list
>>> @(Matrix([[x], [y]]),Matrix([[a], [b]])) a.*x.^2 + b.*y.^2
^
error: called from:
error: [...]/symbolic-2.2.2/@sym/function_handle.m at line 169, column 9
error: [...]/symbolic-2.2.2/@sym/matlabFunction.m at line 35, column 5
I see. And what is it supposed to do if I pass num([1 2; 3 4], [5 6; 7 8])? Is a = [5 6] in that case?
I'd certainly accept a patch if you feel like hacking on this...? Not sure when I'll get around to it :(
The generated function handle in MATLAB reads as
fnum = @(in1,in2) in2(1,:).*in1(1,:).^2+in2(2,:).*in1(2,:).^2
so it seems that if one passes cell array with column vectors of symbols to matlabFunction, the generated function is vectorized in the horizontal direction... i.e. "symbolic" function
f: R^{n x 1} x R^{m x 1} -> R^{p x 1}
is transformed into numeric function
fn: R^{n x t} x R^{m x t} -> R^{p x t}
(if one instead passes row symbolic vectors, it's the other way round). But I guess in many cases one wouldn't actually need such additional vectorization into 2D arrays, evaluating with just vectors would be fine.
I'm afraid my SymPy (and Python in general) skills are pretty basic for now, so I'm not sure if I'll be able to make progress (and looking at docs for @sym/function_handle, it doesn't make any claims of supporting the syntax I mentioned anyway, so if you prefer, please feel free to close the issue).
Yes you're right: it would likely require some modifications of the Octave_Codegen printer in SymPy... (for the record, this is "Indexes" in sympy.utilities.codegen: but I don't recall if any of it works for Octave or not...) This bit I can look into (some day!)
I suggest we:
- change the issue title to something more descriptive.
- change the
function_handle.mdocumentation to note that we don't yet support this. - change the
function_handle.mto detect when one of the inputs is not a scalar (?) and output an error message pointing to this bug.
Would you be interested in giving those a try?
Bit of a brain dump for future work on this. Here's some current SymPy:
A = IndexedBase('A')
v = IndexedBase('v')
w = IndexedBase('w')
i = Idx('i', 2)
j = Idx('j', 3)
g = Eq(w[i], A[i, j]*v[j])
(f1, code), = codegen(('matvec', g), "octave", header=False, empty=False)
print(code)
function w = matvec(A, v)
for i = 1:2
w(i) = 0;
end
for i = 1:2
for j = 1:3
w(i) = v(j).*A(i, j) + w(i);
end
end
end
Probably making codegen vectorize the inner loops there would be one way to achieve this.
I suggest we:
- change the issue title to something more descriptive.
- change the function_handle.m documentation to note that we don't yet support this.
- change the function_handle.m to detect when one of the inputs is not a scalar (?) and output an error message pointing to this bug.
Would you be interested in giving those a try?
Thanks for the reply, that sounds like a good course of action. I've been busy for a few days, but now I gave it a try - parsing the 'vars' argument takes place at lines 140-155 of inst/@sym/private/codegen.m, so adding the check there should do the trick. One problem I've come across though is the case when user passes cell array with strings:
syms x y
h = function_handle(2*x*y, x+y, 'vars', {'x' 'y'});
Then the codegen function sees only strings, not symbolic objects themselves, so the check doesn't work. Other than that, I can try to submit a pull request (once I figure out how, heh).
Sounds great! Does SMT also allow the 'vars', {'x' 'y'}) form?
Yes, looks like it does. Relevant docs:
['Vars':] Order of input variables or vectors in generated MATLAB function, specified as a cell array of strings or symbolic arrays, or a vector of symbolic variables.