MATLAB: Slow Read-in of constant variables in Script Function - matlab

In the latest MATLAB release, I am using the feature of local functions in the script to simplify and shorten the code.
Right now I have a simple script that does mathematical calculations, up to millions of iterations in a for loop. From the loop, I extracted the mathematical part as it is used in multiple independent loops. However, I have the problem with speed and constant variables that need to be in the function. If I write the code without the local function, it is fast, but in the case of using the function, it is 10x slower.
I think it is due to the repetitive read-in of variables in the function. If the read-in happens from a file, it takes forever. The best I have achieved is by using evalin function to call in variables from the base workspace. It works, but as I mentioned, it is 10x slower than without a separate local function.
How to overcome this?
The structure looks like this:
load('Data.mat'); r=1; %Reads variables L,n
for Lx = L1:Ld:L2
for x = x1:d:x2
Yx(r) = myF(x); r=r+1
end
end
%A few more different loops...
function y = myF(x)
L = evalin('base','L');
n = evalin('base','n');
...
a = (x-L)^2; b = sin(a)-n/2; ... y=b*a/L;
end

You will want to explicitly pass the variables as additional input arguments to myF so that you don't have to load them every time. This way you don't have to worry about calling evalin or loading them from the file every iteration through the loop.
load('Data.mat'); r=1; %Reads variables L,n
for Lx = L1:Ld:L2
for x = x1:d:x2
Yx(r) = myF(x, L, n); r=r+1
end
end
function y = myF(x, L, n)
a = (x-L)^2; b = sin(a)-n/2;
y=b*a/L;
end
If for some reason you can't modify myF, just turn the entire thing into a function and make myF a subfunction and it will therefore automatically have access to any variable within the parent function. In this case you'll also want to assign the output of load to a variable to prevent strange behavior and not have issues with adding a variable to a static workspace
function myfunction()
data = load('Data.mat');
L = data.L;
n = data.n;
for Lx = L1:Ld:L2
for x = x1:d:x2
Yx(r) = myF(x);
r=r+1
end
end
function y = myF(x)
a = (x-L)^2; b = sin(a)-n/2;
y=b*a/L;
end
end
A third alternative is to take a hard look at myF and consider whether you can vectorize the contents so that you don't actually have to continuously call it millions of times.
You could vectorize it by doing something like
[Lx, x] = ndgrid(L1:Ld:L2, x1:d:x2);
a = (x - L).^2;
b = sin(a) - (n / 2);
Yx = (b .* a) ./ L;

Related

How to create a function that takes a matrix as an input?

I am new to MatLab.
Write a function that takes as input a matrix D ∈ R^(N×2), D_i = (x_i,y_i), and the period ω and returns a plot showing a fit of the data without noise.
I need help with creating the function that takes the input as a matrix and period ω. Here is what I have so far. Am I on the right track?
function F = fftfuntion(D, omega)
check = 0;
x = D(:,1);
y = D(;,2);
You are on track but there are 3 problems:
First: you are using p variable inside your function which is not defined there. If it is defined in your main code you have to insert it to this function by adding an input to your function as p and when the function is called you have to put p there. Your other solution is to set p as a global variable which is not recommended.
function F = fftfuntion(D, omega,p)
Second: you have said that you need omega as an input and you are changing it with omega = 2*pi which is not right.
Finally I don't see any output which I think that's because you are not still done with the function.
Good luck

Summation of N function handles in MATLAB

I have N functions in MATLAB and I can define them using strcat, num2str and eval in a for loop. So without defining by hand I am able to define N functions. Let N=4 and let them be given as follows:
f1=#(x) a1*x+1;
f2=#(x) a2*x+1;
f3=#(x) a3*x+1;
f4=#(x) a4*x+1;
Now I add these four functions and I can do this by hand as follows:
f=#(x)(f1(x)+f2(x)+f3(x)+f4(x));
Here I can do it by hand because I know that N=4. However, in general I never know how many functions I will have. For all cases I cannot write a new function.
Is there any way to do this automatically? I mean if I give N=6 I am expecting to see MATLAB giving me this:
f=#(x)(f1(x)+f2(x)+f3(x)+f4(x)+f5(x)+f6(x));
Whenever I give N=2 then I must have the function f, defined as follows:
f=#(x)(f1(x)+f2(x));
How can we do this?
First of all, you should read this answer that gives a series of reasons to avoid the use of eval. There are very few occasions where eval is necessary, in all other cases it just complicates things. In this case, you use to dynamically generate variable names, which is considered a very bad practice. As detailed in the linked answer and in further writings linked in that answer, dynamic variable names make the code harder to read, harder to maintain, and slower to execute in MATLAB.
So, instead of defining functions f1, f2, f3, ... fN, what you do is define functions f{1}, f{2}, f{3}, ... f{N}. That is, f is a cell array where each element is an anonymous function (or any other function handle).
For example, instead of
f1=#(x) a1*x+1;
f2=#(x) a2*x+1;
f3=#(x) a3*x+1;
f4=#(x) a4*x+1;
you do
N = 4;
a = [4.5, 3.4, 7.1, 2.1];
f = cell(N,1);
for ii=1:N
f{ii} = #(x) a(ii) * x + 1;
end
With these changes, we can easily answer the question. We can now write a function that outputs the sum of the functions in f:
function y = sum_of_functions(f,x)
y = 0;
for ii=1:numel(f)
y = y + f{ii}(x);
end
end
You can put this in a file called sum_of_functions.m, or you can put it at the end of your function file or script file, it doesn't matter. Now, in your code, when you want to evaluate y = f1(x) + f2(x) + f3(x)..., what you write is y = sum_of_functions(f,x).

How to return a series of number from a recursive function in Matlab

I use dynamic programming for finding the shortest path between two matrices. I printed all the step of the shortest path, but I would also like to save all of them so I can print them as a 2D figure. I wrote the code like below but it doesn't work. I searched on the internet and it seems like it need to be pass by an object as the argument? Does anyone know how to get the path matrix from the returning value? Thanks in advance!
ttt=find_path(7,7)
function pathMat = find_path(a,b)
pathMat=[];
if (a==0 || b==0)
return;
end
filename = sprintf('/Users/name/Desktop/song1.wav');
[x, Fs]=audioread(filename);
s=x;
filename = sprintf('/Users/name/Desktop/song2.wav');
[x, Fs]=audioread(filename);
t=x;
% dynamic time warping
w=-Inf;
ns=size(s,2);
nt=size(t,2);
%% initialization
D=zeros(ns+2,nt+2)-Inf; % cache matrix
D(1,1)=0;
D(2,2)=0;
% similarity matrix (cosing similarity)
oost = zeros(ns+1,nt+1)-Inf;
for i=1:ns
for j=1:nt
oost(i+1,j+1) =
(dot(s(:,i),t(:,j))/(norm(s(:,i),2)*norm(t(:,j),2))); % = cos(theta)
end
end
%% begin dynamic programming
%find the maximal similarity between two matrix
for i=1:ns
for j=1:nt
D(i+2,j+2)=oost(i+1,j+1)+max([D(i,j+1)+oost(i,j+1), D(i+1,j)+oost(i+1,j), D(i+1,j+1)]);
end
end
d=max(D(:,nt+2));
d_len=nt+2;
while(max(D(:,d_len))==-Inf)
d_len=d_len-1;
d=max(D(:,d_len));
end
fprintf('(%d, %d)', a, b);
pathMat = [pathMat];
if (max([D(a,b+1)+oost(a,b+1), D(a+1,b)+oost(a+1,b), D(a+1,b+1)])==D(a,b+1)+oost(a,b+1))
fprintf('(%d, %d)', a-1, b);
pathMat=[pathMat;find_path(a-1,b)];
find_path(a-2,b-1);
elseif (max([D(a,b+1)+oost(a,b+1), D(a+1,b)+oost(a+1,b), D(a+1,b+1)])==D(a+1,b)+oost(a+1,b))
fprintf('(%d, %d)', a, b-1);
pathMat=[pathMat;find_path(a,b-1)];
find_path(a-1,b-2);
elseif (max([D(a,b+1)+oost(a,b+1), D(a+1,b)+oost(a+1,b), D(a+1,b+1)])==D(a+1,b+1))
find_path(a-1,b-1);
end
end
There are two approaches you can use, to retain values between function calls or store all results in a "global" variable.
Due to the clutter and length of your code (not everything is relevant to the question), I will take the example of a factorial program to describe the approach.
Let there be a function that not only computes the factorial of the given number recursively, but also all the intermediate results of numbers lesser than itself. I believe this is a close model of what you require. An example of what the function should do:
>> [fact, list] = factorial(5)
>> fact = 120
>> list = [1, 2, 6, 24, 120]
Approach 1: Use persistent variables
Persistent variables are the equivalent of static function variables (like in C) in MATLAB.
Persistent variables by default are assigned to [] on first use. Also, the value is retained across function calls as expected. A sample code using this approach to define our factorial program:
function [fact, list] = factorial(n)
if n <= 1
fact = 1;
else
fact = n * factorial(n-1);
end
persistent res;
res = [res, fact];
list = res;
end
This can be used as follows:
>> [f, list] = factorial(4)
f =
24
list =
1 2 6 24
>> clear factorial
>> [f, list] = factorial(3)
f =
6
list =
1 2 6
Approach 2: Sharing variables in nested functions
MATLAB supports nested function definitions, where the inner functions can share variables from the outer one, and modify them without explicitly being passing as arguments. A sample code using this approach:
function [fact, list] = factorial(n)
list = [];
fact = factorial_core(n);
function fact = factorial_core(n)
if n <= 1
fact = 1;
else
fact = n * factorial_core(n-1);
end
list = [list, fact];
end
end
This is used the same way as before, except that clear factorial (that clears the persistent variables) between function calls is not required.
I would recommend you to try out whichever suits your case best. Also, it appears that you are loading the wav files each time of the recursion, which is unnecessary and inefficient. These two approaches can be used to avoid that, apart from solve your problem.

Function Definition Clarification in Matlab

I wrote some code that works just fine to evaluate theta on its own with some test input. However, I would like to take this code and turn it into a function that I can call within another matlab file. I keep getting the error message, "Function definitions are not permitted in this context."
I want to be able to define four vectors in another matlab file and call SP1 to evaluate theta for those inputs. I'm not sure where I'm going wrong, though. Please help!
Thanks so much.
clc
clear all
function theta = SP1(p,q1,w1,r)
% INPUT:
%function theta = SP1(p,q1,w1,r)
% p = [5; -7; 12];
% q1 = [17.3037; -3.1128; 2.48175];
% w1 = [1/sqrt(8); sqrt(3/8); 1/sqrt(2)];
% r = [1; 2; -3];
% Define vectors u and v as well as u' and v'.
u = p - r;
v = q1 - r;
w1_t = transpose(w1);
u_prime = u - w1 * w1_t * u;
v_prime = v - w1 * w1_t * v;
% Calculate theta if conditions are met for a solution to exist.
if (abs(norm(u_prime)-norm(v_prime))<0.01) & (abs((w1_t * u)-(w1_t * v))<0.01)
X = w1_t*cross(u_prime,v_prime);
Y = dot(u_prime,v_prime);
theta = atan2(X,Y)
else if (norm(u_prime) == 0 | norm(v_prime) == 0)
disp('Infinite Number of Solutions')
else
disp('Conditions not satisfied to find a solution')
end
end
I think you can just remove the top two lines,
clc
clear all
and save the rest of the code starting with function as SP1.m file.
Then you should be able to call this function as SP1 from other m files.
I think you're confused about how functions work. The first line of a function definition defines how many inputs and outputs MATLAB expects:
function theta = SP1(p,q1,w1,r)
This means that calling a function SP1 will require you to give four inputs, and will return one output. It doesn't mean that:
Your inputs need to be named p, q1 and so on
Your output will be called theta automatically
The function will automatically take in the input variables p, q1, etc if they exist in the workspace.
It also doesn't do any checking on the inputs; so if you require that inputs be of a certain type, size, etc. you need to write your own error checking at the start of the file. You might intend that those inputs be 3x1 vectors, but there's nothing in the function to tell MATLAB that. So, SP1(1,2,3,4) will work, to some extent - it will take those inputs and try to run them through the function, and if they don't cause an error it will give you an output. The output might be wrong, but the computer doesn't know that.
Once you have a function you can call it multiple ways from the command line or from within other functions or scripts. As previously mentioned you don't have to stick to the naming of variables within the function, as long as input variables exist when the function is called MATLAB will accept them:
theta = SP1(p8,q27,w35,not_r);
myoutput = SP1(any,variable,I,like);
I don't necessarily have to give an output (but then the first output will be routed to ans)
SP1(this,will,also,work);
If I have some variables stored in a *.mat file (the case you seem to be asking about), I can do it like this:
load('mydata.mat'); %this file contains stored variables p, q1, w1 and r
theta = SP1(p,q1,w1,r);

Passing in an function to solve integral equation with fsolve

I am trying to solve an integral equation of the form
Integrate[f(x)*g(x,w),dx]
Solve for w: ------------------------ = 0.5
Integrate[f(x),dx]
of which there are definite limits (numerical integration).
Searching around on this and mathworks website I found some code that does it using functions in functions. I have run into a few problems though:
The code currently is (simplified equations for testing):
function [bfound]=testingSolveIntegral
options = optimset('MaxFunEvals',50);
bfound = fsolve(#func2minimize,[1 2 3],options); %testing start points at 1,2,3
function output = func2minimize(w)
t0 = -1;
t1 = 1;
L = 0.5;
output = (L - (integral(#myFunc,t0,t1,'ArrayValued',true,'RelTol',1e-30,'AbsTol',1e-30)./integral(#myFunc2,t0,t1,'ArrayValued',true,'RelTol',1e-30,'AbsTol',1e-30)));
function f = myFunc(muu)
f = B.*muu.^2*(w.*muu.^2);
end
function f2 = myFunc2(muu)
f2 = B.*muu^2;
end
end
end
This works wonderfully, but what I would like to do is then solve these equations in a loop for different values of B, eg, B = 1:1:100. I have tried a few things inside this code but only get errors.
Do I need to call this function from an outside script which dictates the B loop?
I would also like to define my functions in this outside script eg something like:
func = #(muu) B.*muu.^2*(w.*muu.^2);
func2 = #(muu) B.*muu^2;
for B = 1:1:100
testingSolveIntegral(func,func2,B)
I have tried a few things but am getting lost in the torrent of functions flying around the place. Assistance on how to set up such a script would be greatly appreciated.
Thanks
The integral doc page tells you how to perfom this task (section "Integrate Parametrized Function").
First define functions f and g with as many arguments as you have parameters/variables. For example, define:
g = #(muu,w) muu.^2*(w.*muu.^2);
f = #(muu) muu.^2;
Then call integral with an anonymous function which fix the values of the parameters:
for w=1:100
q(w) = integral(#(x) g(x,w).*f(x),bmin, bmax)./integral(f,bmin, bmax);
end