min and max Functions Breaking After Conversion From Symbolic to MATLAB Function

If I have a function whose values I want to constrain between some minimum and maximum values, I can use the min and max commands. This works for both function handles and symbolic functions. However, I need to transform a symbolic function that uses min and max into a MATLAB function handle, and it is not working. For example, in the code below, I would expect to get 1, 1, 4, 5, 5, either vertically or horizontally concatenated depending on the input. But I don’t. Can someone advise me on how to get the symbolic version of the function into a MATLAB handle in a way that will produce results consistent with the symbolic (and original) version?
Thank you in advance.
t = 0:4
t = 1×5
0 1 2 3 4
orig_fun = @(x) max(1, min(5, x.^2))
orig_fun = function_handle with value:
@(x)max(1,min(5,x.^2))
syms sym_fun(x)
sym_fun(x) = sym(orig_fun)
sym_fun(x) = 
mat_fun = matlabFunction(sym_fun)
mat_fun = function_handle with value:
@(x)max([1.0,min([5.0,x.^2],[],2,'omitnan')],[],2,'omitnan')
disp(' ')
disp('In a row:')
In a row:
orig_fun(t)
ans = 1×5
1 1 4 5 5
double(sym_fun(t))
ans = 1×5
1 1 4 5 5
mat_fun(t)
ans = 1
disp(' ')
disp('In a column:')
In a column:
orig_fun(t')
ans = 5×1
1 1 4 5 5
double(sym_fun(t'))
ans = 5×1
1 1 4 5 5
mat_fun(t')
Error using horzcat
Dimensions of arrays being concatenated are not consistent.

Error in symengine>@(x)max([1.0,min([5.0,x.^2],[],2,'omitnan')],[],2,'omitnan')

 Accepted Answer

Symbolic variables (that are not symmatrix) are scalars. For scalar x, min(5,x) is the same as min([5,x])
Symbolic operations assume scalar. For example y*x assumes scalar x y and will rewrite to x*y if it makes for better presentation or easier internal operations (canonical internal representation for efficiency).
Any availability to replace variables with multiple values in the function handle is whatever is implemented by matlabFunction based on the expressions that reach it, and it does not try very hard at all. For example [1, x; 2, x.^2] will probably be transformed into a reshape(MATRIX,2,2) which will fail if the inputs are non-scalar.
Do not expect vector behaviour of symbolic variables; do not write symbolic code that is expected to work on vectors that are variable length (other than some element-by-element operations).
You can use vectors of symbols of definite length in combination with matlabFunction 'vars' option to pack the values into a single parameter... but if you need variable length vectors then expect trouble.

3 Comments

Thank you for your response. It seems like there may not be an elegant solution to the problem. How about an inelegant one? I will be generating various symbolic functions that I want to have a maximum and minimum value. That is, when the calculated value falls outside of two limits, the limit is substituted. I will be optimizing those functions using lsqcurvefit, so I need them to be handles. However, I don't need the symbolic versions to have any bounds on them. Do you have any tips?
Brute force by using func2str and then adding my constraints and then putting back using str2func? Or is there something better?
t = 0:4
syms x
sym_fun(x) = x.^2
% Here's where there might be symbolic stuff done on the function, so I
% don't know exactly what it will look like when it is time to put it back
% into a function handle.
mat_fun = matlabFunction(sym_fun)
% I guess this will work, but it's inelegant
text = func2str(mat_fun)
cutoff = min(strfind(text, ')'));
mat_fun = str2func([text(1:cutoff), ' max(1, min(5, ', text((cutoff + 1):end), '))'])
disp(' ')
disp('In a row:')
max(1, min(5, double(sym_fun(t))))
mat_fun(t)
disp(' ')
disp('In a column:')
max(1, min(5, double(sym_fun(t'))))
mat_fun(t')
syms x
sym_fun(x) = x.^2
sym_fun(x) = 
% Here's where there might be symbolic stuff done on the function, so I
% don't know exactly what it will look like when it is time to put it back
% into a function handle.
mat_fun = matlabFunction(sym_fun)
mat_fun = function_handle with value:
@(x)x.^2
BOUND15 = @(X) max(1, min(5, X))
BOUND15 = function_handle with value:
@(X)max(1,min(5,X))
mat_fun = @(X) BOUND15(mat_fun(X))
mat_fun = function_handle with value:
@(X)BOUND15(mat_fun(X))
t = 0:4
t = 1×5
0 1 2 3 4
mat_fun(t)
ans = 1×5
1 1 4 5 5

Sign in to comment.

More Answers (0)

Categories

Products

Release

R2023a

Community Treasure Hunt

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

Start Hunting!