I have to numerically evaluate, in Matlab, the integral of the product of two functions A(x,y) and B(x,y). These two functions are in 2-dimensional array form. The integral should read as following
I understand that the function such as "trapz" are for numerical integration of arrays of data, but I do not understand ho to adapt to my case.
thank you
Giuseppe
To guide you I will build some (square) matrix functions
%// Problem size.
n = 3;
%// Auxiliary constant matrices.
D1 = rand(n, n);
D2 = rand(n, n);
D3 = rand(n, n);
D4 = rand(n, n);
%// Matrix functions and product.
A = #(x,y) x^2*D1.^2 + y*D2;
B = #(y,z) (log(y)+z)*D3.^3 - z*sin(D4);
P = #(x,y,z) A(x,y)*B(y,z);
In this way P is a function of three variables, now we will integrate it in y, when x and z are both 0.
a = 0;
b = 1;
integral(#(y) P(0,y,0), a, b, 'ArrayValued', true)
To generalize the solution to arbitrary domains we can build a new function in (x,z)
Int = #(x,z) integral(#(y) P(x,y,z), a, b, 'ArrayValued', true);
and define a mesh
x = linspace(-1, 1, 11);
z = linspace(-2, 2, 21);
[X, Z] = meshgrid(x, z);
Now we can evaluate the integral on the whole mesh.
C = arrayfun(Int, X(:), Z(:), 'UniformOutput', false);
In this way C will contain all the integrals, stored in a 1D array of cells.
As a check we can get the result at (x,z) = (0,0) by calling
C{sub2ind([11 21], 6, 11)}
Related
TL;DR: I am trying to optimize the following short code in Matlab. Because it involves loops over large matrices, it is too slow.
for i = 1:sz,
for j = 1:sz,
if X(j) == Q(i) && Y(j) == R(i),
S(i) = Z(j);
break
end
end
end
Specifics: Basically, I started with three vectors of x, y and z data that I wanted to plot as a surface. I generated a mesh of the x and y data and then made a matrix for the corresponding z values using
[X, Y] = meshgrid(x, y);
Z = griddata(x, y, z, X, Y);
Because the data is collected in random order, when generating the surface plot the connections are all wrong and the plot looks all triangulated like the following example.
So, to make sure Matlab was connecting the right dots, I then reorganized the X and Y matrices using
[R, R_indx] = sort(Y);
[Q, Q_indx] = sort(X, 2);
From here I thought it would be a simple problem of reorganizing the matrix Z based on the indices of the sorting for matrix X and Y. But I run into trouble because no matter how I use the indices, I cannot produce the correct matrix. For example, I tried
S = Z(R_indx); % to match the rearrangement of Y
S = S(Q_indx); % to match the rearrangement of X
and I got this barcode...
Running the first block of code gives me the "desired" result pictured here. However, this takes far too long as it is a double loop over a very large matrix.
Question: How can I optimize this rearrangement of the matrix Z without for loops?
Please have a look at the following solutions, and test both with your matrices. Do they perform faster? The array indexing solution does, what you asked for, i.e. the re-arrangement of the matrices. The vector indexing might be even better, since it sorts your original vectors instead of the matrices, and generates the output directly from there.
% Parameters.
dim = 4;
% Test input.
x = [2, -2, 5, 4];
y = [1, -4, 6, -2];
z = rand(dim);
[X, Y] = meshgrid(x, y);
Z = griddata(x, y, z, X, Y);
[R, R_indx] = sort(Y);
[Q, Q_indx] = sort(X, 2);
% Initialize output.
S = zeros(dim);
% Provided solution using loop.
for i = 1:numel(z)
for j = 1:numel(z)
if (X(j) == Q(i) && Y(j) == R(i))
S(i) = Z(j);
break
end
end
end
% Output.
S
% Solution using array indexing; output.
S_array = reshape(((X(:) == Q(:).') & (Y(:) == R(:).')).' * Z(:), dim, dim)
% Solution using vector indexing; output.
[r, r_indx] = sort(y);
[q, q_indx] = sort(x);
[X, Y] = meshgrid(q, r);
Z = griddata(q, r, z, X, Y);
idx = (ones(dim, 1) * ((q_indx - 1) * dim) + r_indx.' * ones(1, dim));
S_vector = Z(idx)
Example output:
S =
0.371424 0.744220 0.777214 0.778058
0.580353 0.686495 0.356647 0.577780
0.436699 0.217288 0.883900 0.800133
0.594355 0.405309 0.544806 0.085540
S_array =
0.371424 0.744220 0.777214 0.778058
0.580353 0.686495 0.356647 0.577780
0.436699 0.217288 0.883900 0.800133
0.594355 0.405309 0.544806 0.085540
S_vector =
0.371424 0.744220 0.777214 0.778058
0.580353 0.686495 0.356647 0.577780
0.436699 0.217288 0.883900 0.800133
0.594355 0.405309 0.544806 0.085540
let's consider a two dimensional fonction f(x,y)
and tree points A,B,C with ABC a triangle
and i want to integrate the function f over the triangle ABC,
is there a way to do that in matlab?
thank you.
You can create a new function h(x,y), that returns f(x,y) if (x,y) is inside the polygon, and 0 otherwise.
For instance:
A = [0, 0];
B = [0, 5];
C = [5, 0];
triangleX = [A(1) B(1) C(1)];
triangleY = [A(2) B(2) C(2)];
f = #(x,y) (1);
h = #(x,y) (inpolygon(x, y, triangleX, triangleY) .* f(x,y));
q = integral2(h, min(triangleX), max(triangleX), min(triangleY), max(triangleY)
'Method', 'iterated')
Outputs (which may be close enough for you):
q =
12.500070877352647
And another function:
f = #(x,y) (x .* y);
q = integral2(#foo, min(triangleX), max(triangleX), min(triangleY), max(triangleY),
'Method', 'iterated')
q =
26.042038561947592
Notice that the integral2 documentation states:
When integrating over nonrectangular regions, the best performance and
accuracy occurs when ymin, ymax, (or both) are function handles. Avoid
setting integrand function values to zero to integrate over a
nonrectangular region. If you must do this, specify 'iterated' method.
So it'll be better if instead of using the above solution, you write two functions that given an x coordinate, give you the minimal and maximal y coordinates of the polygon (triangle).
I found the correct answer,
thanks to this https://math.stackexchange.com/questions/954409/double-integral-over-an-arbitrary-triangle
function r = intm2(f, t)
% f: function
% t: three points of a triangle
% r: integration of f over t
a = t(1,:);
b = t(2,:);
c = t(3,:);
jg = abs((b(1)-a(1))*(c(2)-a(2))-(c(1)-a(1))*(b(2)-a(2)));
ftilda = #(u,v) f(a(1)+u*(b(1)-a(1))+v*(c(1)-a(1)), a(2)+u*(b(2)-a(2))+v*(c(2)- a(2)));
fy = #(x) 1-x;
r = jg * integral2(ftilda, 0,1, 0,fy);
end
I have a vector x = [10,20,30,40] in Matlab, now I would like to apply y = rand(m,1) to each element in x, i.e generating:
y1 = rand(x(1),1);
y2 = rand(x(2),1);
y3 = rand(x(3),1);
y4 = rand(x(4),1);
The straight-forward way is to apply a for loop, but as we know that, for loop is not efficient in Matlab. So is that any other way to do that?
Follow-ups:
Applying a function to each element in vector in Matlab seems a very common problem, how can we handle such cases and avoid using for loop?
create a random vector (ys) it's size is sum of x elements then define a function to extract each y with index:
x=[10,20,30,40];
s = sum(x);
c = cumsum(x);
ys = rand(s, 1);
y = #(i) ys(c(i)-x(i) +1:c(i)) ;
%%%%example
y(3)
y(1)
First, to point out the obvious. You imply that y would be a numerical array, but this is impossible, because each element has a different size. (e.g. y1 is 10x1, but y2 is 20x1)
Therefore, the only output that makes sense here is if you expect y to be a cell array.
You can very straightforwardly use arrayfun (or cellfun etc) to do this:
>> x = [10, 20, 30, 40]
>> f = #(a) {rand(a, 1)}; % output is a "cell" element
>> y = arrayfun(f, x); % apply 'f' to each element of x: returns a 1x4 cell array
I have two matlab questions that seem closely related.
I want to find the most efficient way (no loop?) to multiply a (A x A) matrix with every single matrix of a 3d matrix (A x A x N). Also, I would like to take the trace of each of those products.
http://en.wikipedia.org/wiki/Matrix_multiplication#Frobenius_product
This is the inner frobenius product. On the crappy code I have below I'm using its secondary definition which is more efficient.
I want to multiply each element of a vector (N x 1) with its "corresponding" matrix of a 3d matrix (A x A x N).
function Y_returned = problem_1(X_matrix, weight_matrix)
% X_matrix is the randn(50, 50, 2000) matrix
% weight_matrix is the randn(50, 50) matrix
[~, ~, number_of_matries] = size(X_matrix);
Y_returned = zeros(number_of_matries, 1);
for i = 1:number_of_matries
% Y_returned(i) = trace(X_matrix(:,:,i) * weight_matrix');
temp1 = X_matrix(:,:,i)';
temp2 = weight_matrix';
Y_returned(i) = temp1(:)' * temp2(:);
end
end
function output = problem_2(vector, matrix)
% matrix is the randn(50, 50, 2000) matrix
% vector is the randn(2000, 1) vector
[n1, n2, number_of_matries] = size(matrix);
output = zeros(n1, n2, number_of_matries);
for i = 1:number_of_matries
output(:, :, i) = vector(i) .* matrix(:, :, i);
end
output = sum(output, 3);
end
I assume you mean element-wise multiplication:
Use bsxfun:
A = 10;
N = 4;
mat1 = randn(A,A);
mat2 = randn(A,A,N);
result = bsxfun(#times, mat1, mat2);
Use bsxfun with permute to align dimensions:
A = 10;
N = 4;
vec1 = rand(N,1);
mat2 = randn(A,A,N);
result = bsxfun(#times, permute(vec1,[2 3 1]), mat2);
I have a very simple problem.
I have
x=[ 10 25 50];
y=[ 1.2 3 7.5];
I know my curve fitting function
f(x)=(a*x+1)/(bx+c);
How can I get coefficient(a,b,c) solve in matlab and also plot this curve?
Rearrange y = f(x) to make a, b, and c the unknowns:
y = (ax + 1) / (bx + c)
y(bx + c) = ax + 1
ax - bxy - cy = -1;
This describes a system of simultaneous linear equations in a, b, and c when you substitute your three paired values of x and y.
x = [10, 20, 100];
y = [1.2, 0.7, 0.4];
coeffs = [x', (-x.*y)', -y'];
knowns = [-1, -1, -1]';
v = coeffs \ knowns; % v is [a; b; c]
Now you have the coefficients a, b, and c so you can plot the function.
Addendum: plotting
To plot a function, first choose the x-values of the data points
xt = 1:100;
Then calculate the y-values (assuming you've already got a, b, c)
yt = (a*x + 1) ./ (b*x + c)
Then just plot them!
plot(xt, yt);
Read the Matlab help on the plot function for customizing the style of the plot.