Memory usage of a function - matlab

I am trying to measure the memory usage of a function. I would like to compare the memory requirements for different methods of solving a linear system of equations. I am looking for a way of measuring it like this:
N = 100;
A = rand(N, N);
b = rand(N, 1);
mem1 = memory(sol = A \ b);
mem2 = memory(sol = sparse(A) \ b);

Related

Nested for loops in Matlab GPU programming

I want to run this specific nested for loop in GPU using matlab, can anyboy help me,
Phi=rand(100,100); FluxD=rand(100,100); FluxC=rand(100,100);
Ima = 100;
Jma = 100;
for i=1:Ima-1
for j=1:Jma-1
Phi(i,j) =Phi(i,j)+dt*(FluxD(i,j)-FluxC(i,j));
end
end
You need to do two things here - firstly, build your data on the GPU, and then for best performance, operate on it in a vectorised manner, like this:
% Build input data arrays directly on the GPU
Phi = rand(100, 'gpuArray');
FluxD = rand(100, 'gpuArray');
FluxC = rand(100, 'gpuArray');
Ima = 100;
Jma = 100;
% For convenience, make index vectors for i and j
ii = 1:Ima-1;
jj = 1:Jma-1;
% Compute Phi in a vectorised manner
Phi(ii, jj) = Phi(ii, jj) + dt * (FluxD(ii,jj) - FluxC(ii,jj));

Interpolation using polyfit (Matlab)

My script is supposed to run Runge-Kutta and then interpolate around the tops using polyfit to calculate the max values of the tops. I seem to get the x-values of the max points correct but the y-values are off for some reason. Have sat with it for 3 days now. The problem should be In the last for-loop when I calculate py?
Function:
function funk = FU(t,u)
L0 = 1;
C = 1*10^-6;
funk = [u(2); 2.*u(1).*u(2).^2./(1+u(1).^2) - u(1).*(1+u(1).^2)./(L0.*C)];
Program:
%Runge kutta
clear all
close all
clc
clf
%Given values
U0 = [240 1200 2400];
L0 = 1;
C = 1*10^-6;
T = 0.003;
h = 0.000001;
W = [];
% Runge-Kutta 4
for i = 1:3
u0 = [0;U0(i)];
u = u0;
U = u;
tt = 0:h:T;
for t=tt(1:end-1)
k1 = FU(t,u);
k2 = FU(t+0.5*h,u+0.5*h*k1);
k3 = FU((t+0.5*h),(u+0.5*h*k2));
k4 = FU((t+h),(u+k3*h));
u = u + (1/6)*(k1+2*k2+2*k3+k4)*h;
U = [U u];
end
W = [W;U];
end
I1 = W(1,:); I2 = W(3,:); I3 = W(5,:);
dI1 = W(2,:); dI2 = W(4,:); dI3 = W(6,:);
I = [I1; I2; I3];
dI = [dI1; dI2; dI3];
%Plot of the currents
figure (1)
plot(tt,I1,'r',tt,I2,'b',tt,I3,'g')
hold on
legend('U0 = 240','U0 = 1200','U0 = 2400')
BB = [];
d = 2;
px = [];
py = [];
format short
for l = 1:3
[H,Index(l)]=max(I(l,:));
Area=[(Index(l)-2:Index(l)+2)*h];
p = polyfit(Area,I(Index(l)-2:Index(l)+2),4);
rotp(1,:) = roots([4*p(1),3*p(2),2*p(3),p(4)]);
B = rotp(1,2);
BB = [BB B];
Imax(l,:)=p(1).*B.^4+p(2).*B.^3+p(3).*B.^2+p(4).*B+p(5);
Tsv(i)=4*rotp(1,l);
%px1 = linspace(h*(Index(l)-d-1),h*(Index(l)+d-2));
px1 = BB;
py1 = polyval(p,px1(1,l));
px = [px px1];
py = [py py1];
end
% Plots the max points
figure(1)
plot(px1(1),py(1),'b*-',px1(2),py(2),'b*-',px1(3),py(3),'b*-')
hold on
disp(Imax)
Your polyfit line should read:
p = polyfit(Area,I(l, Index(l)-2:Index(l)+2),4);
More interestingly, take note of the warnings you get about poor conditioning of that polynomial (I presume you're seeing these). Why? Partly because of numerical precision (your numbers are very small, scaled around 10^-6) and partly because you're asking for a 4th-order fit to five points (which is singular). To do this "better", use more input points (more than 5), or a lower-order polynomial fit (quadratic is usually plenty), and (probably) rescale before you use the polyfit tool.
Having said that, in practice this problem is often solved using three points and a quadratic fit, because it's computationally cheap and gives very nearly the same answers as more complex approaches, but you didn't get that from me (with noiseless data like this, it doesn't much matter anyway).

MATLAB - Exponential Curve Fitting without Toolbox

I have data points (x, y) that I need to fit an exponential function to,
y = A + B * exp(C * x),
but I can neither use the Curve Fitting Toolbox nor the Optimization Toolbox.
User rayryeng was good enough to help me with working code:
x = [0 0.0036 0.0071 0.0107 0.0143 0.0178 0.0214 0.0250 0.0285 0.0321 0.0357 0.0392 0.0428 0.0464 0.0464];
y = [1.3985 1.3310 1.2741 1.2175 1.1694 1.1213 1.0804 1.0395 1.0043 0.9691 0.9385 0.9080 0.8809 0.7856 0.7856];
M = [ones(numel(x),1), x(:)]; %// Ensure x is a column vector
lny = log(y(:)); %// Ensure y is a column vector and take ln
X = M\lny; %// Solve for parameters
A = exp(X(1)); %// Solve for A
b = X(2); %// Get b
xval = linspace(min(x), max(x));
yval = A*exp(b*xval);
plot(x,y,'r.',xval,yval,'b');
However, this code only fits the equation without offset
y = A * exp(B * x).
How can I extend this code to fit the three-parameter equation?
In another attempt, I managed to fit the function using fminsearch:
function [xval, yval] = curve_fitting_exponential_1_optimized(x,y,xval)
start_point = rand(1, 3);
model = #expfun;
est = fminsearch(model, start_point);
function [sse, FittedCurve] = expfun(params)
A = params(1);
B = params(2);
C = params(3);
FittedCurve = A + B .* exp(-C * x);
ErrorVector = FittedCurve - y;
sse = sum(ErrorVector .^ 2);
end
yval = est(1)+est(2) * exp(-est(3) * xval);
end
The problem here is that the result depends on the starting point which is randomly chosen, so I don't get a stable solution. But since I need the function for automatization, I need something stable. How can I get a stable solution?
How to adapt rayryeng's code for three parameters?
rayryeng used the strategy to linearize a nonlinear equation so that standard regression methods can be applied. See also Jubobs' answer to a similar question.
This strategy does no longer work if there is a non-zero offset A. We can fix the situation by getting a rough estimate of the offset. As rubenvb mentioned in the comments, we could estimate A by min(y), but then the logarithm gets applied to a zero. Instead, we could leave a bit of space between our guess of A and the minimum of the data, say half its range. Then we subtract A from the data and use rayreng's method:
x = x(:); % bring the data into the standard, more
y = y(:); % convenient format of column vectors
Aguess = min(y) - (max(y) - min(y) / 2;
guess = [ones(size(x)), -x] \ log(y - Aguess);
Bguess = exp(guess(1));
Cguess = guess(2);
For the given data, this results in
Aguess = 0.4792
Bguess = 0.9440
Cguess = 21.7609
Other than for the two-parameter situation, we cannot expect this to be a good fit. Its SSE is 0.007331.
How to get a stable solution?
This guess is however useful as a starting point for the nonlinear optimization:
start_point = [Aguess, Bguess, Cguess];
est = fminsearch(#expfun, start_point);
Aest = est(1);
Best = est(2);
Cest = est(3);
Now the optimization arrives at a stable estimate, because the computation is deterministic:
Aest = -0.1266
Best = 1.5106
Cest = 10.2314
The SSE of this estimate is 0.004041.
This is what the data (blue dots) and fitted curves (green: guess, red: optimized) look like:
Here is the whole function in all its glory - special thanks to A. Donda!
function [xval, yval] = curve_fitting_exponential_1_optimized(x,y,xval)
x = x(:); % bring the data into the standard, more convenient format of column vectors
y = y(:);
Aguess = min(y) - (max(y)-min(y)) / 2;
guess = [ones(size(x)), -x] \ log(y - Aguess);
Bguess = exp(guess(1));
Cguess = guess(2);
start_point = [Aguess, Bguess, Cguess];
est = fminsearch(#expfun, start_point);
function [sse, FittedCurve] = expfun(params)
A = params(1);
B = params(2);
C = params(3);
FittedCurve = A + B .* exp(-C * x);
ErrorVector = FittedCurve - y;
sse = sum(ErrorVector .^ 2);
end
yval = est(1)+est(2) * exp(-est(3) * xval);
end

Is there a cleaner way to generate a sum of sinusoids?

I have written a simple matlab / octave function to create the sum of sinusoids with independent amplitude, frequency and phase for each component. Is there a cleaner way to write this?
## Create a sum of cosines with independent amplitude, frequency and
## phase for each component:
## samples(t) = SUM(A[i] * sin(2 * pi * F[i] * t + Phi[i])
## Return samples as a column vector.
##
function signal = sum_of_cosines(A = [1.0],
F = [440],
Phi = [0.0],
duration = 1.0,
sampling_rate = 44100)
t = (0:1/sampling_rate:(duration-1/sampling_rate));
n = length(t);
signal = sum(repmat(A, n, 1) .* cos(2*pi*t' * F + repmat(Phi, n, 1)), 2);
endfunction
In particular, the calls to repmat() seem a bit clunky -- is there some nifty vectorization technique waiting for me to learn?
Is this the same?
signal = cos(2*pi*t' * F + repmat(Phi, n, 1)), 2) * A';
And then maybe
signal = real(exp(j*2*pi*t'*F) * (A .* exp(j*Phi))');
If you are memory constrained, this should work nicely:
e_jtheta = exp(j * 2 * pi * F / sampling_rate);
phasor = A .* exp(j*Phi);
samples = zeros(duration,1);
for k = 1:duration
samples(k) = real((e_jtheta .^ k) * phasor');
end
For row vectors A, F, and Phi, so you can use bsxfun to get rid of the repmat, but it is arguably uglier looking:
signal = cos(bsxfun(#plus, 2*pi*t' * F, Phi)) * A';
Heh. When I call any of the above vectorized versions with length(A) = 10000, octave fills up VM and grinds to a halt (or at least, a slow crawl -- I haven't had the patience to wait for it to complete.
As a result, I've fallen back to the straightforward iterative version:
function signal = sum_of_cosines(A = [1.0],
F = [440],
Phi = [0.0],
duration = 1.0,
sampling_rate = 44100)
t = (0:1/sampling_rate:(duration-1/sampling_rate));
n = length(t);
signal = zeros(n, 1);
for i=1:length(A)
samples += A(i) * cos(2*pi*t'*F(i) + Phi(i));
endfor
endfunction
This version works plenty fast and teaches me a lesson about trying to be 'elegant'.
P.S.: This doesn't diminish my appreciation for the answers given by #BenVoigt and #chappjc -- I've learned something useful from both!

how to pass one array as parameter in arrayfun in matlab?

I am multiplying two matrices A (of size nxn) and B (of size nxm). The simplest way in matlab will be
n = 1000;
m = 500;
for k=1:n
A(k, :) = (1:n)+k;
end
B = rand(n, m);
C = A*B; % C of the size nxm
however, this code occupies too much of memory when n and/or m too big. So I am looking for a vectorize version of array to implement that
n = 1000;
m = 500;
B = rand(n, m);
func0 = #(k, colv) [(1:n)+k]*colv;
func1 = #(V) arrayfun(func0, 1:n, V);
func1(B)
but it doesn't work. It said the dimension doesn't match up. Anybody has any suggestion?
I would not use anything fancy for this, just break down the linear algebra being performed.
C = zeros(n,m);
for k = 1:n
C(k,:) = ((1:n)+k) * B;
end
Or, slightly more verbosely
C = zeros(n,m);
for k = 1:n
A_singleRow = ((1:n)+k);
C(k,:) = A_singleRow* B;
end
For crazy-big sizes (which it sounds like you have), try reformulating the problem so that you can iterate on columns, rather than rows. (Matlab uses column-major matrix storage, which means that elements in the same column are adjacent in memory. Usually thining about this falls into the realm of over-optimization, but maybe not for you.)
For example, you could construct Ctranspose as follows:
Ctranspose = zeros(m,n); %Note reversed order of n, m
Btranspose = B'; %Of course you may want to just create Btranspose first
for k = 1:n
A_singleRowAsColumn = ((1:n)'+k);
Ctranspose(:,k) = Btranspose * A_singleRowAsColumn;
end
The tools arrayfun, cellfun are very useful to functionalize a for loop, which can be used to make code more clear. However they are not generally useful when trying to squeeze performance. Even if the anonymous function/arrayfun implementation was debugged, I suspect it would require roughly the same memory usage.