Converting a string to an expression in MATLAB - string

I'm writing a small MATLAB package and I'd like to ask for user input for a function. So if the user enters:
x.^2 + sin(x)
I want to use this user input to appear elsewhere in the code, but x would already be defined and so the expression above would be a vector (or scalar if length(x) is 1).

You can use the eval function for this. For example:
>> x = 5
x =
5
>> eval('x*3')
ans =
15

You can create a function handle:
% some variable you already defined
myVar = 5;
% Create an anonymous function in some z
f = str2func('#(z) z.^2 + sin(z)');
% Call function supplying the input
f(myVar)

Related

Expanding anonymous function into a string

I have a set of anonymous functions, and I want to convert them into strings. Normally I would just use func2str, but the problem is I want the variables and internal functions to be expanded out into their "true" values. The problem I'm running into is that MATLAB is keeping these by the names, but recognizing the values. Example
classdef Bclass
properties
equation
end
function obj = Bclass(inEquation, inValue)
obj.equation = #(t,y) inEquation(t,y) * inValue;
end
function out = getStr(obj)
out = func2str(obj.equation);
end
end
The problem is that the func2str call is outputting #(t,y) inEquation(t,y) * inValue, when I actually want it to output something like #(t,y) t*y * 5, if we had said b = Bclass(#(t,y) t*y, 5).
Is there a way to retrieve these variable values from MATLAB?
You can do this, but it could quickly become very difficult if your problem becomes any more complex than the example given above (i.e. more complicated anonymous functions, multiple nesting levels, etc.). You'll have to make use of the functions function to get information on the function handle, and its behavior may change between releases. Additionally, you'll have to do quite a bit of string manipulation (using functions like regexp, regexprep, strsplit, and strrep, as I do below).
I've tried to include here the most general approach I could, allowing for the following possibilities:
inEquation can be a non-anonymous function handle (i.e. #times).
inEquation can simply be passed along as is without actually being invoked.
inEquation can be called multiple times in the anonymous function.
The input arguments to inEquation can be named differently than what it is invoked with in obj.equation.
obj.equation can contain indexing operations.
First, we'll initialize some variables to mimic your example:
f1 = #(m, n) m*n; % Note the different variable names, but it will still work
inEquation = f1;
inValue = 5;
f2 = #(t, y) inEquation(t, y)*inValue; % Function constructed using workspace variables
Next, we'll get the function information for f2:
s = functions(f2);
varNames = fieldnames(s.workspace{1});
varValues = struct2cell(s.workspace{1});
out = s.function;
The workspace field holds the variable names and values that were used to construct f2, and the function field is the string you'd get by calling func2str on f2. We'll also need to compute a few things so we can correctly parse opening and closing parentheses in f2:
openIndex = (out == '(');
closeIndex = (out == ')');
parenIndex = cumsum(openIndex-[false closeIndex(1:end-1)]).*(openIndex | closeIndex);
Now, we'll loop over the workspace variables, convert their values to strings (if possible), and replace them in out:
for iVar = 1:numel(varNames)
name = varNames{iVar};
value = varValues{iVar};
if isa(value, 'function_handle') % Workspace variable is a function handle
value = func2str(value);
callIndex = strfind(out, [name, '('])+numel(name);
fcnParts = regexp(value, '#\({1}([^\)])*\){1}(\S)*', 'once', 'tokens');
if isempty(callIndex) % Function handle is not invoked
if isempty(fcnParts) % Non-anonymous function handle (i.e. #times)
value = ['#' value];
end
out = strrep(out, name, value);
elseif isempty(fcnParts) % Invoked function handle (i.e. #times)
out = strrep(out, name, value);
else % Invoked anonymous function handle
for iCall = callIndex
args = out(iCall+(1:find(parenIndex(iCall+1:end) == parenIndex(iCall), 1)-1));
value = regexprep(fcnParts{2}, ...
strcat('(?<!\w)', strsplit(fcnParts{1}, ','), '(?!\w)'), ...
strsplit(args, ','));
out = strrep(out, [name, '(', args, ')'], value);
end
end
elseif isnumeric(value) && isscalar(value) % Workspace variable is a numeric scalar
out = strrep(out, name, num2str(value));
end
end
And we get the desired result for out:
>> out
out =
#(t,y)t*y*5
Note that this will also work as expected with a non-anonymous function handle as well:
>> f1 = #times;
>> inEquation = f1;
>> inValue = 5;
>> f2 = #(t, y) inEquation(t, y)*inValue;
% Repeat above processing...
>> out
out =
#(t,y)times(t,y)*5
It will also work on some more complicated functions:
>> postVolt = #(g, V) -.05*g*(V+80);
>> preIdx = 5;
>> postIdx = 1;
>> index = 6;
>> obj.values = {};
>> f2 = #(t) postVolt(obj.values{preIdx}(index), obj.values{preIdx}(obj.voltIdx{postIdx}));
% Repeat above processing...
>> out
out =
#(t)-.05*obj.values{5}(6)*(obj.values{5}(obj.voltIdx{1})+80)

Converting strings to code

This is a programming question for Python 3.5
Say I have a string s which I define as
s = "a + b"
and I have some variables
a = 1
b = 2
How can I make a function from the string that uses the variables a and b?
s is something that you can arbitrarily enter as a string input.
def f1(s):
???Code???
return a + b
or
s = "a*b"
def f2(s):
???Code???
return a*b
Does this involve symbolic programming? Is this even possible?
You can use the eval function.
https://docs.python.org/3/library/functions.html#eval
Example:
a = 2
b = 5
eval('a+b') # 7

MATLAB generate combination from a string

I've a string like this "FBECGHD" and i need to use MATLAB and generate all the required possible permutations? In there a specific MATLAB function that does this task or should I define a custom MATLAB function that perform this task?
Use the perms function. A string in matlab is a list of characters, so it will permute them:
A = 'FBECGHD';
perms(A)
You can also store the output (e.g. P = perms(A)), and, if A is an N-character string, P is a N!-by-N array, where each row corresponds to a permutation.
If you are interested in unique permutations, you can use:
unique(perms(A), 'rows')
to remove duplicates (otherwise something like 'ABB' would give 6 results, instead of the 3 that you might expect).
As Richante answered, P = perms(A) is very handy for this. You may also notice that P is of type char and it's not convenient to subset/select individual permutation. Below worked for me:
str = 'FBECGHD';
A = perms(str);
B = cellstr(reshape(A,7,[])');
C = unique(B);
It also appears that unique(A, 'rows') is not removing duplicate values:
>> A=[11, 11];
>> unique(A, 'rows')
ans =
11 11
However, unique(A) would:
>> unique(A)
ans =
11
I am not a matlab pro by any means and I didn't investigate this exhaustively but at least in some cases it appears that reshape is not what you want. Notice that below gives 999 and 191 as permutations of 199 which isn't true. The reshape function as written appears to operate "column-wise" on A:
>> str = '199';
A = perms(str);
B = cellstr(reshape(A,3,[])');
C = unique(B);
>> C
C =
'191'
'199'
'911'
'919'
'999'
Below does not produce 999 or 191:
B = {};
index = 1;
while true
try
substring = A(index,:);
B{index}=substring;
index = index + 1;
catch
break
end
end
C = unique(B)
C =
'199' '919' '991'

Strrep not working in Matlab to make String into function

Hello I am new to MATLAB , I wanted to know how can I make my string into function . I want to access the function as a string from user in standard Matlab format (e.g exp(-10*X)-sin(pi*X)-2*tanh(X) ) Here X is the variable. Then I want to replace 'X' with 'low' and 'high' variables to calculate value of function at these limits. I have used 'strrep' for this purpose. I am getting the following errors
1)Undefined function or variable 'X'.
2) I cannot see whether 'X' was replaced with 'low' and 'high'.
Any help will be truly appreciated.
Below is my code.
high=input('Upper Limit of the Interval : ');
low=input('\nLower Limit of the interval : ');
usr_funct=input('Enter The Function in standard Matlab Format.\nEnter "X" for the
variable and * for multiply \n'); % Example exp(-10*X)-sin(pi*X)-2*tanh(X);
middle = (low+high)/2;
Flow =strrep(usr_funct, 'X', 'low');
Fhigh =strrep(usr_funct, 'X', 'high');
sprintf('Flow '); % This was to check if 'X' was replaced with 'low'. It is not printing anything
Use:
usr_funct=input('Enter The Function...', 's');
This will return the entered text as a MATLAB string, without evaluating expressions.
I think that you are looking for the eval function. That will evaluate a string as matlab code.
Here is an example:
str = 'exp(-10*X)-sin(pi*X)-2*tanh(X)' ; % let str be your math expression
high = 10; % Ask the user
low = -5; % Ask the user
% Now we evaluate for High and Low
X = low; % We want to evaluate for low
ResultLow = eval(str); % That will return your value for X = low
X = high; % We want to evaluate for low
ResultHigh = eval(str); % That will return your value for X = high
1) Undefined function or variable 'X'
If you look at the documentation for input, it says that by default, it evaluates the expression. You need to add a second argument of 's' for it to just save a string.
2) I cannot see whether 'X' was replace with 'low' and 'high'
You should type sprintf(Flow) instead of sprintf('Flow'). The latter will just output "Flow" onto the screen while the former will output the value of Flow.
Finally, the eval function may be of use later on when you actually want to evaluate your expression.

solution of an implicit equation with fzero on MATLAB

I've been trying to solve this implicit equation by using fzero in MATLAB. File that holds the code is named as "colebrook" and I've typed so far is as below.
D = input('Please enter the pipe diameter in meters: ');
V = input('Please enter the fluid velocity in m/s: ');
rho = input('Please enter fluid density in kg/m^3: ');
mew = input('Please enter fluid viscosity in kg/m*s: ');
Re = D*V*rho/mew;
eps = input('Enter absolute roughness in milimeters: ');
eD = eps/(D*1000);
a = fzero(colebrookfunc,0.1);
fprintf(a);
Equation that I want to solve is kept in another m-file called "colebrookfunc", and the code it contains is as below.
function F = colebrookfunc(x)
F = x - 1./(-4 * log10(eD/3.7 + 1.256./(Re*x.^0.5))).^2;
When i run in i get this error(s):
??? Input argument "x" is undefined.
Error in ==> colebrookfunc at 2
F = x - 1./(-4 * log10(eD/3.7 + 1.256./(Re*x.^0.5))).^2;
Error in ==> colebrook at 28
a = fzero(colebrookfunc,0.1);
What is my mistake?
Thank you.
You have to pass colebrookfunc as a function handle. Also, unless you define colebrookfunc as a nested function (which you, apparently, don't), you need to somehow pass the parameters to the function.
Thus, your call to fzero should look like:
a = fzero(#(x)colebrookfunc(x,eD,Re),0.1)
And the first line of coolebrookfunc has to be
function F = colebrookfunc(x,eD,Re)

Resources