Borrar filtros
Borrar filtros

How do you create a symbolic function that takes a vector input?

29 visualizaciones (últimos 30 días)
I want to create a symbolic function that takes a 1x3 vector input, and returns 3*the vector. Super simple idea, can't figure it out. I'm getting the error "Error using symfun/subsref (line 141) Symbolic function expected 3 inputs and received 1."
a = sym('a', [1 3]);
f(a) = 3*a;
A = [1 2 3];
b = double(f(A))

Respuesta aceptada

Karan Gill
Karan Gill el 20 de Oct. de 2016
You almost got it right! In fact, you just need to delete a line of code. Don't declare "a" as a 1x3 vector because "a" can be anything by default. Just remove that line and declare "f(a)" instead:
syms f(a)
f(a) = 3*a;
A = [1 2 3];
b = double(f(A))
b =
3 6 9
At least, I think this is what you wanted to do.
  3 comentarios
Karan Gill
Karan Gill el 1 de Nov. de 2016
Sorry for the late reply -- I did not get a notification for your comment. By "matrix operation", do you mean something like what expm does? That is not possible at the moment. Can you provide more information on what you are trying to do?
The workaround here is to convert the cell to sym using "cell2sym":
double(cell2sym(f(b)))
ans =
1 2 3
2 4 6
3 6 9
SkyCat
SkyCat el 30 de Oct. de 2017
what if i change f(a) = A.*a ?

Iniciar sesión para comentar.

Más respuestas (2)

Walter Roberson
Walter Roberson el 19 de Oct. de 2016
a = sym('a', [1 3]);
that creates a as a vector of three symbolic names
f(a) = 3*a;
there you are passing in the vector of three symbolic names in the function definition, but you are treating it as if you had passed a single variable.
syms f(a)
f(a) = 3*a;
double( f(A) )
  4 comentarios
Walter Roberson
Walter Roberson el 20 de Oct. de 2016
Unfortunately, MuPad (the symbolic engine) does not have the facility to be able to indicate that a symbol represents an abstract matrix. MuPad considers each unresolved symbol to be scalar.
You can, in MuPAD, create a matrix of a particular size, but it has to be populated with values and symbols, has to become a particular matrix.
The MuPad way of handling this is to create a procedure to do the work: procedures do not evaluate until they are called on particular arguments (like function handles.) Unfortunately, the interface to create a nice-looking symbolic functions that postpones to the right time is not there -- an ugly version can be created but making it nice requires setting a private field in the symbol.
The work-around looks like this:
feval(symengine, '_assign', sym('A'), sym(A)); %push the value of A into the engine
f = sym('x->A*x');
And then to use,
feval(symengine, f, b)
But if you are going to do that, you might as well use
f = @(x) A*x
In current releases, the sym('x->A*x') will warn about that going away. You could warning('off') that, or you could substitute
feval(symengine, '_assign', sym('A'), sym(A)); %push the value of A into the engine
f = mupadmex('x->A*x', 11); %yes, that IS obscure
feval(symengine, f, b)
or
feval(symengine, '_assign', sym('A'), sym(A)); %push the value of A into the engine
f = evalin(symengine, 'x->A*x');
feval(symengine, f, b)
In theory you should also be able to do
feval(symengine, '_assign', sym('A'), sym(A)); %push the value of A into the engine
f = evalin(symengine, 'proc(x) begin A*x end_proc');
feval(symengine, f, b)
but in practice you will get an error message about running out of memory or the interface needing to be reset.
I will poke around and see if I can find something nicer.
Walter Roberson
Walter Roberson el 21 de Oct. de 2016
My investigations suggest that
f(variable1,variable2,...) = formula
is handled as
f = symfun(formula, [variable1, variable2, ...])
Here, formula is executed and the variables are executed. The execution of each of those parts is a symbolic expression (class sym).
In turn each sym has properties, one of which is a string. For plain symbolic variables, the string is the name of the variable. For expressions and functions, the string is a special form, and it is the name of a temporary variable that exists in the MuPAD engine and has been assigned the expression.
Now, the subsref() for class sym is treated as standard indexing -- so if you have a sym f at hand, f() will always be treated as an indexing attempt. If you have a sym that has somehow gotten defined as a MuPAD proc, and you want to invoke a function it refers to, you need to use feval() to do so, like I showed above.
symfun is slightly different. The constructor for symfun stores the reference to the formula, and stores the list of variable names that are to be parameters, and returns back a symfun object. The subsref() for class symfun checks for '()' indexing style, and when it is found, grabs the formula and subs() the provided values for the remembered variables, f(values) -> subs(stored_formula(f), stored_variables(f), values) . The standard evaluation takes place after subs, so levels of hold() might get lost:
>> sym('hold(hold(hold(b)))')
hold(hold(b))
>> subs(sym('hold(hold(hold(b)))'), 'b', 9)
hold(9)
The subsref() for class symfun does not do
feval(symengine, stored_formula(f), values)
or
feval(symengine, 'fp::apply', stored_formula(f), values)
or
feval(symengine, ['x->' stored_formula(f)]', values)
I am not sure at the moment why that seems so significant to me, but it does make it difficult to use symfun() to created useful delayed evaluation.

Iniciar sesión para comentar.


Daniele Cuomo
Daniele Cuomo el 5 de Feb. de 2019
Editada: Daniele Cuomo el 6 de Feb. de 2019
Is there a clean way to do the same thing but for functions like
x = sym('x', [1 2]);
Ffun(x) = [x(1)^2 + x(2)^2 - 1; sin(pi*x(1)/2) + x(2)^3];
The problem here is that Ffun wants 2 variables and doesn't accept a vector like
x0 = [1 2];
The only way I found is the use of subs function, but it becomes impractical when you need good waiting times.
subs(Ffun, x, x0);
  8 comentarios
Daniele Cuomo
Daniele Cuomo el 7 de Feb. de 2019
Nono, I said it badly. The problem is that I want to declare a symfun to exploit its syntax power (can call the diff function for example) at first. I need a function_handle later because I need to call it a lot of times. Calling matlabFunction does not work because it returns a function_handle with multiple input arguments.
There seems to be no solution to this problem.
Walter Roberson
Walter Roberson el 7 de Feb. de 2019
Call matlabFunction() with the 'vars' option. Pass the 'vars' option a cell array. Within the cell array, each variable name you mention within a vector will be bundled together into a single input argument with the other names in the same vector of variable names. If the vector of names is a row vector then MATLAB will vectorize based upon columns of the corresponding input -- this is suitable for use with the optimization functions such as fminsearch and for use with fsolve(). If the vector of names is a column vector then MATLAB will vectorize based upon rows of the corresponding put -- this is suitable for use with the ode functions for the derivatives argument. If you pass a 2D array of names, then MATLAB will not vectorize and will use linear indexing to pull out appropriate positions from the input argument.
To see how that works out, compare
x = sym('x', [3 2]);
matlabFunction(x*x', 'vars', {x})
matlabFunction(x*x', 'vars', {reshape(x,1,[])})
matlabFunction(x*x', 'vars', {reshape(x,[],1)})

Iniciar sesión para comentar.

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by