How to generate a function inside a script file in MATLAB - matlab

I am looking for a way to write a script file in MATLAB that generates a sequence of functions and save them each in a separate m-file.
More precisely, suppose you have a script file and you want to generates N different functions; something like this:
for i=1:N
Step 1: Do some symbolic calculation and find the expression of fi
Step 2: Define the function fi=fi(...)
Step 3: Save the the function in an m-file say fi.m
end
I myself have not found any clue so far. Here is two questions that if answered, such code then follows straightforwardly:
1. How to define a function in a script file and automatically save it in an m-file:
Let say y=f(x)=x^2 is a symbolic relation calculated in a script file; how to automatically generate a function for it and save it in an m-file
2. How to use a string as a file name, function name, etc: Suppose you are creating an string "fi" in a loop for every i, and you want to use this string as a function name
Thanks for your help in advance

https://www.mathworks.com/help/symbolic/matlabfunction.html#bul5mb5-1
If you want to convert symbolic functions to MATLAB function files, MATLAB has a function (called matlabFunction) that does exactly that.
Example from that page:
syms x y z
r = x^2 + y^2 + z^2;
f = matlabFunction(log(r)+r^(-1/2),'File','myfile');
Which creates 'myfile.m':
function out1 = myfile(x,y,z)
%MYFILE
% OUT1 = MYFILE(X,Y,Z)
t2 = x.^2;
t3 = y.^2;
t4 = z.^2;
t5 = t2 + t3 + t4;
out1 = log(t5) + 1.0./sqrt(t5);

Related

Can someone explaine why my function handle does not work?

Newbe here so please don't be too harsh.
I have these three functions, and each has it's own file:
format long
rd = #(x) runden(x,L);
function y = runden(x,L)
y = (round(x*10^L))/10^L;
endfunction
format long
function z = add(x,y,rd)
z = rd(rd(x)+rd(y));
endfunction
format long
function z = mult(x,y,rd)
z = rd(rd(x)*rd(y));
endfunction
as you see I want to use a function handle, so I can use round in the bottom two functions.
The functions have to be in their own files (wasn't a problem so far in matlab).
My Syntax is off, but I can't find a tutorial that handles function handles with two variables.
If I understand, the function handle rd lives only in the first script, and the other scripts can't access it.
If you will name the first file (function) as runden.m, and define rd in the other functions and not in the first one, they will have access to it.
And two notes- don't override preserved function names as add, and use end instead of endfunction.
I would suggest to arrange the functions like that:
% file 1, named `runden.m`
function y = runden(x,L)
format long
y = (round(x*10^L))/10^L;
end
% file 2, named `ad.m`
function z = ad(x,y,L)
format long
rd = #(x) runden(x,L);
z = rd(rd(x)+rd(y));
end
% file 3, named `mult.m`
function z = mult(x,y,L)
format long
rd = #(x) runden(x,L);
z = rd(rd(x)*rd(y));
end

Too many output arguments error: MATLAB

I just started with MATLAB and I'm seeking advice for how to make a function work with more arguments.
I've built this formula:
I = real((U0.*exp(i.*vw.*vt))./(L.*(-vw.^2+ (R/L).*i.*vw + (1/L.*C)))) + ...
exp((-R.*vt)./(2.*L).*( alpha.*cos( sD.*vt)+ beta.*sin( sD.*vt)));
Therefore I needed the values for U0, vw, vt, L, R
If I put this in the command window:
D = (1/L*C)-((R^.2)/(4*L^.2));
sD = sqrt(D);
vt = linspace(tmin,tmax,200);
vw = omega;
[vw,vt] = meshgrid(vw,vt);
I = real((U0.*exp(i.*vw.*vt))./(L.*(-vw.^2+ (R/L).*i.*vw + (1/L.*C)))) + exp((-R.*vt)./(2.*L).*( alpha.*cos( sD.*vt)+ beta.*sin( sD.*vt)));
surf(vw,vt,I)
It works fine.
So, now I want to create a function which reads the values and calculates all the stuff above and returns a surf plot.
My try:
function [u] = test(L,C,R,tmin,tmax,omega,U0)
D = (1/L*C)-((R^.2)/(4*L^.2));
sD = sqrt(D);
vt = linspace(tmin,tmax,200);
vw = omega;
[vw,vt] = meshgrid(vw,vt);
I = real((U0.*exp(i.*vw.*vt))./(L.*(-vw.^2+ (R/L).*i.*vw + (1/L.*C))))+exp((-R.*vt)./(2.*L).*( alpha.*cos( sD.*vt)+ beta.*sin( sD.*vt)));
surf(vw,vt,I)
end
This error occurs:
Error using alphaToo many output arguments.
Do you have an idea how to make this function work?
What is alpha? It's likely that it exists in your workspace, so when you call those lines from your workspace everything is fine. However, within the test function MATLAB has no visibility of the "base" workspace, and alpha doesn't exist! Pass it as an argument or define it like your other values. Ditto with beta.
Also you have defined the output argument u in your function
% Ouput vvv
function [u] = test(L,C,R,tmin,tmax,omega,U0)
But you never assigned anything to the variable u during the function". If you want to return the surf figure object, assign that to u when it is called.
% Square brackets not needed as only returning one variable
function u = test(L,C,R,tmin,tmax,omega,U0)
% ... stuff
u = surf(vw,vt,I)
end

MATLAB - the function returns unwanted output

and I am pretty new at it. I wrote the simple function below, which gets a pair and returns the polar form
function [r,a] = rect2polar(x,y)
r = sqrt(x^2 + y^2);
a = atan(y/x);
[r,a]
end
and when I try for example rect2polar(3,5) it gives me the next output:
ans =
5.8310 1.0304
ans =
5.8310
It returns the desired output, plus the output 5.8310, in other words it returns the variable r in the function for the second time. How can I fix this? Writing
rect2polar(3,5);
helped (the difference is that I wrote ; at the end), but it doesn't feel right. Any help is appreciated, thanks!
The first displayed part,
ans =
5.8310 1.0304
is produced by this line in your function
[r,a]
Since it is missing a ;, Matlab displays the result.
The second part,
ans =
5.8310
is produced because when you call the function as rect2polar(3,5) you are indicating that you want only one output, namely the first, which is displayed after the function returns.
So, the solution would be:
Remove the line [r, a] in your function, which is doing nothing but display what the function will output;
Call your function as [out1, out2] = rect2polar(3,5).
Or, if you want the function to return a vector:
function out = rect2polar(x,y)
r = sqrt(x^2 + y^2);
a = atan(y/x);
out = [r,a];
end

Is it possible to change an anonymous function keeping the workspace?

What I would like to be able to do is programmatically change an anonymous function for example by changing all the plus signs to multiplication signs in the function. This example can in many cases this can be done as follows:
function f2 = changefunction(f1)
fs = func2str(f1);
fs(fs=='+') = '*';
f2 = str2func(fs);
end
But consider the example
f = #(x) x+5;
a = 5;
g = #(x) x+a;
Both f and g will be anonymous functions that adds 5 to whatever you plug into it; however only f will be changed correctly by the changefunction function, whereas g will be changed into a function that will err on any input.
So my question is is it possible to extract the workspace from the function handle and retain it in the new function handle created? I need to do it programmatically and preferably without using the built-in function functions!
One naive implementation is to replace str2func with eval so you are not running into str2func's roadblock of not allowing access to local variables. We can use functions to obtain the workspace information for the input function handle.
For example:
a = 5;
f = #(x) x+a;
finfo = functions(f)
Yields:
finfo =
struct with fields:
function: '#(x)x+a'
type: 'anonymous'
file: 'X:\testcode-matlab\testcode.m'
workspace: {[1×1 struct]}
within_file_path: 'testcode'
Where workspace is a cell array containing a structure (come on MathWorks...) containing all of the variables in your function handle's namespace:
>> wspace = finfo.workspace{1}
wspace =
struct with fields:
a: 5
Using this functionality, the naive solution is to loop through the variables in this workspace, assign them in the namespace of changefunction, then use eval to generate the new function handle.
For example:
function f2 = changefunction_new(f1)
tmp = functions(f1);
workspacevars = tmp.workspace{1};
varnames = fieldnames(workspacevars);
for ii = 1:length(varnames)
evalstr = sprintf('%s = %d;', varnames{ii}, workspacevars.(varnames{ii}));
eval(evalstr);
end
fs = func2str(f1);
fs(fs=='+') = '*';
f2 = eval(fs);
end
Here I'm assuming that the variables are going to be strictly numeric. You can add logic to check the class of the data to be generated if this is not always the case.
With this we have:
a = 5;
g = #(x) x+a;
test1 = changefunction(g);
test2 = changefunction_new(g);
>> g(1)
ans =
6
>> test1(1)
Undefined function or variable 'a'.
Error in testcode>#(x)x*a
>> test2(1)
ans =
5
All that being said, the best solution really is to just explicitly define your function handles. It may be a pain but it's much easier to understand and debug.
A few caveats:
Because eval arbitrarily executes all code passed to it, it can be a very dangerous function that must be used with care.
The documentation for functions warns against using it programmatically, so take care to check behavior as MATLAB versions change:
Use the functions function for querying and debugging purposes only.
Note: Do not use functions programmatically because its behavior could change in subsequent MATLAB® releases.
One possible way to do this is to save the function handle to a .mat file (using the -v7.3 flag so that it creates an easily-modifiable HDF5 file), modify the struct within the file that contains the workspace data for the anonymous function (using the HDF5 tools built into MATLAB), and then load the anonymous function again from the file.
Here is a little function which does exactly that (and it works for relatively simple variable types)
function result = modifyfunc(f, varname, value)
% modifyfunc - Modify the workspace of an anonymous function
%
% INPUTS:
% f: Function Handle, Anonymous function to modify
% varname: String, Name of the variable to modify
% value: Data to replace the specified variable
% If the value is a struct, recursively modify the function handle
if isstruct(value)
fields = fieldnames(value);
result = f;
% Modify each field separately
for k = 1:numel(fields)
% Append the fieldname to the variable name and modify
name = [varname, '.', fields{k}];
result = modifyfunc(result, name, value.(fields{k}));
end
return;
end
% Write the anonymous function to an HDF5 file
fname = tempname;
save(fname, 'f', '-mat', '-v7.3');
% Replace any "." in the variable name with "/" to construct the HDF5 path
varname = strrep(varname, '.' , '/');
% Now modify the data in the file
h5write(fname, ['/#refs#/e/' varname], value);
% Load the modified function handle from the file
result = load(fname, '-mat');
result = result.f;
% Remove the temporary file
delete(fname);
end
And you can use it like:
a = 1;
b = struct('field', 2);
f = #(x)disp(a + b.field + x);
f(10)
% 13
f2 = modifyfunc(f, 'a', 2);
f2(10)
% 14
f3 = modifyfunc(f2, 'b.field', 3);
f3(10)
% 15
b.field = 4;
f4 = modifyfunc(f3, 'b', b);
f4(10)
% 16
Some caveats include:
The replacement data must be the same size as the original data
This relies upon the format of the .mat file which for anonymous functions is completely undocumented so it could fail in future releases.
This currently doesn't work for variables in the function workspace that are cell arrays.

How can I declare 2-dimentional array as parameter in function In MATLAB?

I have a function that gets a matrix and do some operations on it.
but I do not know how to declare function's parameter .
this is my function Code:
function D=Shirinkage(a)
D(1,:)=a(1,:);%this is X1
for i=2:4
D(i,4)=0;
for j=1:3
D(i,j)=1/2*(a(1,j)+a(i,j));
D(i,4)=D(i,j)^2 + D(i,4); %object function
end
end
end
I tried a(4,4) instead of a (parameter of the function),but the error does not appear.
Error:
??? Input argument "a" is undefined.
Error in ==> Shirinkage at 3
D(1,:)=a(1,:);%this is X1
also I want to declare D correctly.
appreciating any help.
Edited:
i call my function from a script file , in this way:
I have a 2-dimention array(matrix) its size is : 4*4 and its name is A.
i want my function gets this matrix and do the operation on it and the result can be saved again in it.
A=Shirinkage(A)
e.x. A has this values:
A=[1,2,3,4;2,3,4,5;5,6,7,8;1,2,3,4]
The function you created is working fine. The only recommendation I have to pre-allocate the size of D as it varies in each iteration in your current code.
function D = Shirinkage(a)
D = zeros(size(a));
D(1,:) = a(1,:); %this is X1
for i = 2:4
D(i,4) = 0;
for j = 1:3
D(i,j) = 0.5*(a(1,j) + a(i,j));
D(i,4) = D(i,4) + D(i,j)^2; %object function
end
end
end
The function was called from command window by using the same matrix you have used and it gave the following output.
The error you have posted says that the function hasn't received the argument a. If your script and the function are in the same MATLAB path, this should work perfectly.