How to get the upper limit of a integration? - matlab

I have a probability distribution function which is the following:
f = #(x) h0 * (1/sqrt(2*pi*sig2)) .* exp(-(x-mh0).^2 / (2*sig2))+ (1-h0) * (1/sqrt(2*pi*sig2)) .* exp(-(x-mh1).^2 / (2*sig2));
I am doing this Matlab. Other than x, everything is constant.
The range for this function is (-4 , 8). I would like to divide this area into equal mass i.e. 1/10 ( 10 intervals, each with mass 1/10).
I am thinking about integrating it and check the upper limit as know the result of the integration. But I didn't find a way to do this?
Can anyone please help me with this?
Thanks in advance

A simple bisection search will find the splitting point simply if you're not worried about ultimate efficiency. E.g., to split in two:
sig2 = rand;
mh0 = rand;
h0 = rand;
mh1 = rand;
f = #(x) h0 * (1/sqrt(2*pi*sig2)) .* exp(-(x-mh0).^2 / (2*sig2))+ (1-h0) * (1/sqrt(2*pi*sig2)) .* exp(-(x-mh1).^2 / (2*sig2));
l = -4;
u = 8;
fprintf('total integral = %e\n', quad(f, l, u));
l0 = l;
u0 = u;
while u0 - l0 > 0.0001
m = 0.5 * (l0 + u0);
w = quad(f, l, m);
if w > 0.5
u0 = m;
else
l0 = m;
end
end
m = 0.5 * (l0 + u0);
fprintf('integral to %e = %e\n', m, quad(f, l, m));
To split into 10 parts, recurse on the subparts. First split at 0.5, then split the low interval at 0.2, then split the low part of that at 0.1, and the upper part at 0.3, and then the 0.3/0.5 interval to get 0.4. Similarly for the upper parts.

Related

Speeding up code which integrates a 2D gpuArray matrix using Simpson's Rule

I have a (real) 2D gpuArray, which I am using as part of a larger code, and now am trying to also integrate the array using the Composite Simpson Rule inside my main loop (several 10000 iterations at least). A MWE looks like the following:
%%%%%%%%%%%%%%%%%% MAIN CODE %%%%%%%%%%%%%%%%%%
Ny = 501; % Dimensions of matrix M
Nx = 503; %
dx = 0.1; % Grid spacings
dy = 0.2; %
M = rand(Ny, Nx, 'gpuArray'); % Initialise a matrix
for k = 1:10000
% M = function1(M) % Apply some other functions to M
% ... etc ...
I = simpsons_integration_2D(M, dx, dy, Nx, Ny); % Now integrate M
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%% Integrator %%%%%%%%%%%%%%%%%
function I = simpsons_integration_2D(F, dx, dy, Nx, Ny)
% Integrate the 2D function F with Nx columns and Ny rows, and grid spacings
% dx and dy using Simpson's rule.
% Integrate along x direction (vertically) --> IX is a vector afterwards
sX = sum( F(:,1:2:Nx-2) + 4*F(:,2:2:(Nx-1)) + F(:,3:2:Nx) , 2);
IX = dx/3 * sX;
% Integrate along y direction --> I is a scalar afterwards
sY = sum( IX(1:2:Ny-2) + 4*IX(2:2:(Ny-1)) + IX(3:2:Ny) , 1);
I = dy/3 * sY;
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
The operation of performing the integration is around 850 µs, which is currently a significant part of my code. This was measured using
f = #() simpsons_integration_2D(M, dx, dy, Nx, Ny);
t = gputimeit(f)
Is there a way to reduce the execution time for integrating the gpuArray matrix?
(The graphics card is the Nvidia Quadro P4000)
Many thanks
Assuming that the matrix has odd dimensions here is a way to optimize the function:
function I = simpsons_integration_2D(F, dx, dy, Nx, Ny)
sX = 2 * sum(F,2) + 2 * sum (F(:,2:2:(Nx-1)),2) - F(:,1) - F(:,Nx);
sY = dx/3 * (2 * sum(sX) + 2 * sum (sX(2:2:(Ny-1))) - sX(1) - sX(Ny));
I = dy/3 * sY;
end
EDIT
A more optimized solution using matrix multiplication:
function I = simpsons_integration_2D2(F, dx, dy, Nx, Ny)
mx = repmat (2, Nx, 1);
mx(2:2:(Nx-1)) = 4;
mx(1) = 1;
mx(Nx) = 1;
my = repmat (2, 1, Ny);
my(2:2:(Ny-1)) = 4;
my(1) = 1;
my(Ny) = 1;
I = (dx*dy/9) * (my * (F * mx));
end
If Nx and Ny are the same you need to compute only one of them mx or my:
function I = simpsons_integration_2D2(F, dx, dy, Nx, Ny)
mx = repmat (2, Nx, 1);
mx(2:2:(Nx-1)) = 4;
mx(1) = 1;
mx(Nx) = 1;
I = (dx*dy/9) * (mx.' * (F * mx));
end
If Nx and Ny are constant you can precompute mx outside the function and pass it as a function argument:
function I = simpsons_integration_2D2(F, dx, dy, mx)
I = (dx*dy/9) * (mx.' * (F * mx));
end
EDIT:
If both mx and my can be precomputed the problem is reduced to a dot product:
m = reshape (my.' .* mx.', 1, []);
function I = simpsons_integration_2D3(F, dx, dy, m)
I = (dx*dy/9) * (m * F(:));
end
Well I cannot test this for you but there are a few things that may help.
First the axis 1 and then the the axis 2 may make some difference in terms of locality of the modified terms (I don't know if to better or to worse).
function I = variation1(F, dx, dy, Nx, Ny)
% Sum each term separately, prevents the creation of a big intermediate matrix
% Multiply outside the summation does only Ny multiplications by 4 instead of Ny*Nx/2
sX = sum(F(:,1:2:Nx-2), 2) + 4*sum(F(:,2:2:(Nx-1)), 2) + sum(F(:,3:2:Nx), 2);
IX = dx/3 * sX;
sY = sum(IX(1:2:Ny-2), 1) + 4*sum(IX(2:2:(Ny-1)), 1) + sum(IX(3:2:Ny) , 1);
I = dy/3 * sY;
end
function I = variation2(F, dx, dy, Nx, Ny)
% a.
% Sum each term separately, prevents the creation of a big intermediate matrix
% Multiply outside the summation does only Ny multiplications by 4 instead of Ny*Nx/2
% b.
% Notice that the terms 2:3:NX-2 appear in two summations
% Saves Nx*Ny/2 additions at the expense of Ny multiplications by 2
sX = 2*sum(F(:,3:2:Nx-2), 2) + 4*sum(F(:,2:2:(Nx-1)), 2) + F(:,1) + F(:,Nx);
% saves Ny multiplications by moving the constant factor after the next sum
sY = 2*sum(sX(3:2:Ny-2), 1) + 4*sum(sX(2:2:(Ny-1)), 1) + sX(1) + sX(Ny);
I = (dy*dy/9) * sY;
end
function I = alternate_simpsons_integration_2D(F, dx, dy, Nx, Ny)
% Integrate the 2D function F with Nx columns and Ny rows, and grid spacings
% dx and dy using Simpson's rule.
% Notice that sum(F(:,1:2:Nx-2) + F(:,3:2:Nx)) have all but the end poitns repeated.
IX = 4*sum(F(:,2:2:Nx-1), 2) + 2 * sum(F(:,3:2:Nx-2) , 2) + F(:,1) + F(:,Nx);
disp(size(IX))
% Integrate along y direction --> I is a scalar afterwards
sY = 4*sum(IX(2:2:Ny-1)) + 2*sum(IX(3:2:Ny-2)) + IX(1) + IX(Ny);
I = dy*dy/9 * sY;
end
If you think it is better to make a single summation then you can do using the formula 2*(sum(2*F(2:2:end-1) + F(1:2:end-2)) + F(end) - F(1) that gives the same result but has Nx*Ny/2 less additions on the first integration. But these options have to be tested in your environment.
Transposed implementation
function I = transposed_simpsons_integration_2D(F, dx, dy, Nx, Ny)
sY = 2*sum(2*F(2:2:end-1, :) + F(1:2:end-2, :), 1) + F(end, :) - F(1, :);
sX = 2*sum(2*sY(2:2:end-1) + sY(1:2:end-2)) + sY(end) - sY(1);
I = dy*dy/9 * sX;
end
Using octave (usually slower than matlab) I get a run time of ~400us per iteration with. This is not the type of workload that will be interesting to run on the GPU. For comparison, randn about 10 times slower than this function.

How to compute the derivatives automatically within for-loop in Matlab?

For the purpose of generalization, I hope Matlab can automatically compute the 1st & 2nd derivatives of the associated function f(x). (in case I change f(x) = sin(6x) to f(x) = sin(8x))
I know there exists built-in commands called diff() and syms, but I cannot figure out how to deal with them with the index i in the for-loop. This is the key problem I am struggling with.
How do I make changes to the following set of codes? I am using MATLAB R2019b.
n = 10;
h = (2.0 * pi) / (n - 1);
for i = 1 : n
x(i) = 0.0 + (i - 1) * h;
f(i) = sin(6 * x(i));
dfe(i) = 6 * cos(6 * x(i)); % first derivative
ddfe(i) = -36 * sin(6 * x(i)); % second derivative
end
You can simply use subs and double to do that. For your case:
% x is given here
n = 10;
h = (2.0 * pi) / (n - 1);
syms 'y';
g = sin(6 * y);
for i = 1 : n
x(i) = 0.0 + (i - 1) * h;
f(i) = double(subs(g,y,x(i)));
dfe(i) = double(subs(diff(g),y,x(i))); % first derivative
ddfe(i) = double(subs(diff(g,2),y,x(i))); % second derivative
end
By #Daivd comment, you can vectorize the loop as well:
% x is given here
n = 10;
h = (2.0 * pi) / (n - 1);
syms 'y';
g = sin(6 * y);
x = 0.0 + ((1:n) - 1) * h;
f = double(subs(g,y,x));
dfe = double(subs(diff(g),y,x)); % first derivative
ddfe = double(subs(diff(g,2),y,x)); % second derivative

2D Discrete Fourier Transform and Inverse DFT in matlab

I am currently implementing 2D DFT and IDFT for images in matlab without using built-in library. I successfully output a spectrum image after DFT but I fail to get back the original image after IDFT.
Here's my code for DFT
input = im2double(img_input);
[M, N] = size(input);
Wm = zeros(M, M);
Wn = zeros(N, N);
for x = 1:M-1
for y = 1:N-1
input(x, y) = input(x, y) * (-1)^(x + y);
end
end
for u = 0:M-1
for x = 0:M-1
Wm(u+1, x+1) = exp(-li * pi * 2 * u * x/ M);
end
end
for v = 0:N-1
for y = 0:N-1
Wn(v+1, y+1) = exp(-li * pi * 2 * v * y / N);
end
end
F = Wm * input * Wn / 200;
output = im2uint8(log(1 + abs(F)));
IDFT:
[M, N] = size(input);
Wm = zeros(M, M);
Wn = zeros(N, N);
for x = 0:M-1
for u = 0:M-1
Wm(x+1, u+1) = exp(2 * pi * 1i * u * x/ M);
end
end
for y = 0:N-1
for v = 0:N-1
Wn(y+1, v+1) = exp(2 * pi * 1i * v * y / N);
end
end
f = Wm * input * Wn;
for x = 1:M-1
for y = 1:N-1
f(x, y) = f(x, y) * (-1)^(x + y);
end
end
output = im2uint8(abs(f));
I multiply the input by (-1)^(x+y) in order to shift the coordinate origin. I have no idea why I can't get back the original image after performing IDFT on the DFTed image.
Original Image
Image after DFT
Image after IDFT
Your code works fine. To get output of the second function to be identical to img_input of the first function, I had to make the following changes:
1st function:
F = Wm * input * Wn; % Don't divide by 200 here.
output = im2uint8(log(1 + abs(F))); % Skip this line altogether
2nd function: Make sure F from the first function is used as input here.
f = Wm * input * Wn / N / M; % Divide by N*M, proper normalization
Note that the normalization is usually put into the IDFT, but you can also put it into the DFT if you prefer. The normalization by 200 is not correct though.

Solving System of Second Order Ordinary Differential Equation in Matlab

Introduction
I am using Matlab to simulate some dynamic systems through numerically solving systems of Second Order Ordinary Differential Equations using ODE45. I found a great tutorial from Mathworks (link for tutorial at end) on how to do this.
In the tutorial the system of equations is explicit in x and y as shown below:
x''=-D(y) * x' * sqrt(x'^2 + y'^2)
y''=-D(y) * y' * sqrt(x'^2 + y'^2) + g(y)
Both equations above have form y'' = f(x, x', y, y')
Question
However, I am coming across systems of equations where the variables can not be solved for explicitly as shown in the example. For example one of the systems has the following set of 3 second order ordinary differential equations:
y double prime equation
y'' - .5*L*(x''*sin(x) + x'^2*cos(x) + (k/m)*y - g = 0
x double prime equation
.33*L^2*x'' - .5*L*y''sin(x) - .33*L^2*C*cos(x) + .5*g*L*sin(x) = 0
A single prime is first derivative
A double prime is second derivative
L, g, m, k, and C are given parameters.
How can Matlab be used to numerically solve a set of second order ordinary differential equations where second order can not be explicitly solved for?
Thanks!
Your second system has the form
a11*x'' + a12*y'' = f1(x,y,x',y')
a21*x'' + a22*y'' = f2(x,y,x',y')
which you can solve as a linear system
[x'', y''] = A\f
or in this case explicitly using Cramer's rule
x'' = ( a22*f1 - a12*f2 ) / (a11*a22 - a12*a21)
y'' accordingly.
I would strongly recommend leaving the intermediate variables in the code to reduce chances for typing errors and avoid multiple computation of the same expressions.
Code could look like this (untested)
function dz = odefunc(t,z)
x=z(1); dx=z(2); y=z(3); dy=z(4);
A = [ [-.5*L*sin(x), 1] ; [.33*L^2, -0.5*L*sin(x)] ]
b = [ [dx^2*cos(x) + (k/m)*y-g]; [-.33*L^2*C*cos(x) + .5*g*L*sin(x)] ]
d2 = A\b
dz = [ dx, d2(1), dy, d2(2) ]
end
Yes your method is correct!
I post the following code below:
%Rotating Pendulum Sym Main
clc
clear all;
%Define parameters
global M K L g C;
M = 1;
K = 25.6;
L = 1;
C = 1;
g = 9.8;
% define initial values for theta, thetad, del, deld
e_0 = 1;
ed_0 = 0;
theta_0 = 0;
thetad_0 = .5;
initialValues = [e_0, ed_0, theta_0, thetad_0];
% Set a timespan
t_initial = 0;
t_final = 36;
dt = .01;
N = (t_final - t_initial)/dt;
timeSpan = linspace(t_final, t_initial, N);
% Run ode45 to get z (theta, thetad, del, deld)
[t, z] = ode45(#RotSpngHndl, timeSpan, initialValues);
%initialize variables
e = zeros(N,1);
ed = zeros(N,1);
theta = zeros(N,1);
thetad = zeros(N,1);
T = zeros(N,1);
V = zeros(N,1);
x = zeros(N,1);
y = zeros(N,1);
for i = 1:N
e(i) = z(i, 1);
ed(i) = z(i, 2);
theta(i) = z(i, 3);
thetad(i) = z(i, 4);
T(i) = .5*M*(ed(i)^2 + (1/3)*L^2*C*sin(theta(i)) + (1/3)*L^2*thetad(i)^2 - L*ed(i)*thetad(i)*sin(theta(i)));
V(i) = -M*g*(e(i) + .5*L*cos(theta(i)));
E(i) = T(i) + V(i);
end
figure(1)
plot(t, T,'r');
hold on;
plot(t, V,'b');
plot(t,E,'y');
title('Energy');
xlabel('time(sec)');
legend('Kinetic Energy', 'Potential Energy', 'Total Energy');
Here is function handle file for ode45:
function dz = RotSpngHndl(~, z)
% Define Global Parameters
global M K L g C
A = [1, -.5*L*sin(z(3));
-.5*L*sin(z(3)), (1/3)*L^2];
b = [.5*L*z(4)^2*cos(z(3)) - (K/M)*z(1) + g;
(1/3)*L^2*C*cos(z(3)) + .5*g*L*sin(z(3))];
X = A\b;
% return column vector [ed; edd; ed; edd]
dz = [z(2);
X(1);
z(4);
X(2)];

Writing Own fft2() Function on MATLAB

I want to write my own 2 Dimensional DFT function with reduced loops.
What I try to implement is Discrete Fourier Transform:
Using the separability property of transform (actually exponential function), we can write this as multiplication of two 1 dimensional DFT. Then, we can calculate the exponential terms for rows (the matrix wM below) and columns (the matrix wN below) of transform. Then, for summation process we can multiply them as "F = wM * original_matrix * wN"
Here is the code I wrote:
f = imread('cameraman.tif');
[M, N, ~] = size(f);
wM = zeros(M, M);
wN = zeros(N, N);
for u = 0 : (M - 1)
for x = 0 : (M - 1)
wM(u+1, x+1) = exp(-2 * pi * 1i / M * x * u);
end
end
for v = 0 : (N - 1)
for y = 0 : (N - 1)
wN(y+1, v+1) = exp(-2 * pi * 1i / N * y * v);
end
end
F = wM * im2double(f) * wN;
The first thing is I dont want to use 2 loops which are MxM and NxN times running. If I used a huge matrix (or image), that would be a problem. Is there any chance to make this code faster (for example eliminating the loops)?
The second thing is displaying the Fourier Transform result. I use the codes below to display the transform:
% // "log" method
fl = log(1 + abs(F));
fm = max(fl(:));
imshow(im2uint8(fl / fm))
and
% // "abs" method
fa = abs(F);
fm = max(fa(:));
imshow(fa / fm)
When I use the "abs" method, I see only black figure, nothing else. What is wrong with "abs" method you think?
And the last thing is when I compare the transform result of my own function with MATLAB' s fft2() function', mine displays darker figure than MATLAB' s result. What am I missing here? Implementation misktake?
The transform result of my own function:
The transform result of MATLAB fft2() function:
I am happy you solved your problem but unfortunately you answer is not completely right. Indeed it does the job, but as I commented, im2double will normalize everything to 1, therefore showing the scaled result you have. What you want (if you are looking for performance) is not doing im2doubleand then multiply by 255, but directly casting to double().
You can eliminate loops by using meshgrid.
For example:
M = 1024;
tic
[ mX, mY ] = meshgrid( 0 : M - 1, 0 : M - 1 );
wM1 = exp( -2 * pi * 1i / M .* mX .* mY );
toc
tic
for u = 0 : (M - 1)
for x = 0 : (M - 1)
wM2( u + 1, x + 1 ) = exp( -2 * pi * 1i / M * x * u );
end
end
toc
all( wM1( : ) == wM2( : ) )
The timing on my system was:
Elapsed time is 0.130923 seconds.
Elapsed time is 0.493163 seconds.