Is it possible to compute all the values at the same time when writing a script? - matlab

When defining a function, say TEST = #(t) t.^2. If the input is a vector, say [1,2,3,4], TEST([1,2,3,4]) = [1,4,9,16].
Can we do similar thing if the function defined is in script form? What I mean is that if I have a script, say TEST.m such that ret = TEST(x,y,z) which outputs a value when knowing numerical values of x, y and z. Suppose I want to calculate 100 different values of z ranging from 1 to 100 when x, y are fixed, say at 0, 1 respectively. Is it possible to output TEST(0,1,1:1:100) without writing a for loop or changing any contents of the script TEST.m?
The reason to ask such question comes from the computation time. Usually, the script I have may be a little complicated so that the calculate of a single value may take few minutes to go. Writing for-loop to output it can be very time-consuming. I think of writing parfor loop, but the computation time is still long to me for further uses. I wonder if I can calculate all the 100 values at a time. I am a starter of programmer, and I hope I can get satisfactory answers after this post. Thanks for all your help.

You cab define a new anonymous function to get the fixed values as parameters, and the vector as input. Then use arrayfun to compute it on all values of the array.
Say you have this functions:
function ret = TEST(x,y,z)
ret = f(x)+g(y)+h(z);
end
function r = f(x)
r = x^2;
end
function r = g(y)
r = y^3;
end
function r = h(z)
r = z^4;
end
And you call it from:
x = 2;
y = 3;
z = 1:5;
T = #(z) TEST(x,y,z);
arrayfun(T,z)
So T is a new function that treat x and y as constants, and only have z as input. Then arrayfun takes T and compute it for every element in z, and you get:
ans =
32 47 112 287 656
Now, you can use arrayfun with more vectors, like [a,b,c] = arrayfun(T,z,w,v), if x and y can stay constant.
Hopes it answers your question ;)

Related

How to run a for loop using two variables at the same time in Matlab

I am using this command in Matlab:
grazAng = grazingang(H,R)
If i fix H, I can treat R as a vector:
z=[];
for i=1:1000
z(i)=abs(grazingang(1,i));
end
Now I would like to have both H and R to by dynamic. For example:
H=[0,0.25,0.5]
R=[1,2,3]
And I would like my loop to run three times, each time selecting a pair of (H,R) values with the same indexes, i.e. (0,1),(0.25,2),(0.5,3) and then store the result in z. Could anyone help me out with this?
Remember, everything in MATLAB is an array. To do this with a loop, you need to index into the arrays:
H = [0,0.25,0.5];
R = [1,2,3];
z = zeros(size(H)); % Pre-allocation is generally advised
for i = 1:1000
z(i) = abs(grazingang(H(i),R(i)));
end
But MATLAB functions generally accept vectors and do this for you, so all you need to do is:
H=[0,0.25,0.5];
R=[1,2,3];
z = abs(grazingang(H,R));

Vectorized function as output of matlabFunction

I am trying to automatize a process in MATLAB. I have a symbolic function that has to be converted into an anonymous function.
Basically, I have something like this:
syms x y z t
var = [x y z t];
f = x.^2+y;
gf = gradient(f, var);
gf_fun = matlabFunction(gf, 'vars', {var});
giving as output
gf_fun =
function_handle with value:
#(in1)[in1(:,1).*2.0;1.0;0.0;0.0]
Now, I'd like to evaluate this gf_fun in several points at a time, but, of course, I got strange results, due to how gf_fun is written. For example, if I want to evaluate gf_fun in 6 (different) points simultaneously, what I get is
rng('deafult')
vv = ones(6,4);
gf_fun(vv)
ans =
1.3575
1.5155
1.4863
0.7845
1.3110
0.3424
1.0000
0
0
instead of a matrix with dimensions 4x6, with each colomn being the evaluation of a single point.
I know that a workaround will be the use of a for loop, that is
results = zeros(4,6);
for i = 1:6
results(:,i) = gf_fun(vv(i,:));
end
but I must avoid it due to code performances reasons.
Is there a way to automatize all the process, having a matrix as output of gf_fun while evaluating different point at a time? So, basically, there is a simple way to replace the 0.0 and 1.0 in gf_fun with a more general zeros(size(in1)) and ones(size(in1)) automatically?
Thank you for you help!

How to resolve MATLAB trapz function error?

I am working on an assignment that requires me to use the trapz function in MATLAB in order to evaluate an integral. I believe I have written the code correctly, but the program returns answers that are wildly incorrect. I am attempting to find the integral of e^(-x^2) from 0 to 1.
x = linspace(0,1,2000);
y = zeros(1,2000);
for iCnt = 1:2000
y(iCnt) = e.^(-(x(iCnt)^2));
end
a = trapz(y);
disp(a);
This code currently returns
1.4929e+03
What am I doing incorrectly?
You need to just specify also the x values:
x = linspace(0,1,2000);
y = exp(-x.^2);
a = trapz(x,y)
a =
0.7468
More details:
First of all, in MATLAB you can use vectors to avoid for-loops for performing operation on arrays (vectors). So the whole four lines of code
y = zeros(1,2000);
for iCnt = 1:2000
y(iCnt) = exp(-(x(iCnt)^2));
end
will be translated to one line:
y = exp(-x.^2)
You defined x = linspace(0,1,2000) it means that you need to calculate the integral of the given function in range [0 1]. So there is a mistake in the way you calculate y which returns it to be in range [1 2000] and that is why you got the big number as the result.
In addition, in MATLAB you should use exp there is not function as e in MATLAB.
Also, if you plot the function in the range, you will see that the result makes sense because the whole page has an area of 1x1.

Implementing iterative solution of integral equation in Matlab

We have an equation similar to the Fredholm integral equation of second kind.
To solve this equation we have been given an iterative solution that is guaranteed to converge for our specific equation. Now our only problem consists in implementing this iterative prodedure in MATLAB.
For now, the problematic part of our code looks like this:
function delta = delta(x,a,P,H,E,c,c0,w)
delt = #(x)delta_a(x,a,P,H,E,c0,w);
for i=1:500
delt = #(x)delt(x) - 1/E.*integral(#(xi)((c(1)-c(2)*delt(xi))*ms(xi,x,a,P,H,w)),0,a-0.001);
end
delta=delt;
end
delta_a is a function of x, and represent the initial value of the iteration. ms is a function of x and xi.
As you might see we want delt to depend on both x (before the integral) and xi (inside of the integral) in the iteration. Unfortunately this way of writing the code (with the function handle) does not give us a numerical value, as we wish. We can't either write delt as two different functions, one of x and one of xi, since xi is not defined (until integral defines it). So, how can we make sure that delt depends on xi inside of the integral, and still get a numerical value out of the iteration?
Do any of you have any suggestions to how we might solve this?
Using numerical integration
Explanation of the input parameters: x is a vector of numerical values, all the rest are constants. A problem with my code is that the input parameter x is not being used (I guess this means that x is being treated as a symbol).
It looks like you can do a nesting of anonymous functions in MATLAB:
f =
#(x)2*x
>> ff = #(x) f(f(x))
ff =
#(x)f(f(x))
>> ff(2)
ans =
8
>> f = ff;
>> f(2)
ans =
8
Also it is possible to rebind the pointers to the functions.
Thus, you can set up your iteration like
delta_old = #(x) delta_a(x)
for i=1:500
delta_new = #(x) delta_old(x) - integral(#(xi),delta_old(xi))
delta_old = delta_new
end
plus the inclusion of your parameters...
You may want to consider to solve a discretized version of your problem.
Let K be the matrix which discretizes your Fredholm kernel k(t,s), e.g.
K(i,j) = int_a^b K(x_i, s) l_j(s) ds
where l_j(s) is, for instance, the j-th lagrange interpolant associated to the interpolation nodes (x_i) = x_1,x_2,...,x_n.
Then, solving your Picard iterations is as simple as doing
phi_n+1 = f + K*phi_n
i.e.
for i = 1:N
phi = f + K*phi
end
where phi_n and f are the nodal values of phi and f on the (x_i).

How can I speed up this call to quantile in Matlab?

I have a MATLAB routine with one rather obvious bottleneck. I've profiled the function, with the result that 2/3 of the computing time is used in the function levels:
The function levels takes a matrix of floats and splits each column into nLevels buckets, returning a matrix of the same size as the input, with each entry replaced by the number of the bucket it falls into.
To do this I use the quantile function to get the bucket limits, and a loop to assign the entries to buckets. Here's my implementation:
function [Y q] = levels(X,nLevels)
% "Assign each of the elements of X to an integer-valued level"
p = linspace(0, 1.0, nLevels+1);
q = quantile(X,p);
if isvector(q)
q=transpose(q);
end
Y = zeros(size(X));
for i = 1:nLevels
% "The variables g and l indicate the entries that are respectively greater than
% or less than the relevant bucket limits. The line Y(g & l) = i is assigning the
% value i to any element that falls in this bucket."
if i ~= nLevels % "The default; doesnt include upper bound"
g = bsxfun(#ge,X,q(i,:));
l = bsxfun(#lt,X,q(i+1,:));
else % "For the final level we include the upper bound"
g = bsxfun(#ge,X,q(i,:));
l = bsxfun(#le,X,q(i+1,:));
end
Y(g & l) = i;
end
Is there anything I can do to speed this up? Can the code be vectorized?
If I understand correctly, you want to know how many items fell in each bucket.
Use:
n = hist(Y,nbins)
Though I am not sure that it will help in the speedup. It is just cleaner this way.
Edit : Following the comment:
You can use the second output parameter of histc
[n,bin] = histc(...) also returns an index matrix bin. If x is a vector, n(k) = >sum(bin==k). bin is zero for out of range values. If x is an M-by-N matrix, then
How About this
function [Y q] = levels(X,nLevels)
p = linspace(0, 1.0, nLevels+1);
q = quantile(X,p);
Y = zeros(size(X));
for i = 1:numel(q)-1
Y = Y+ X>=q(i);
end
This results in the following:
>>X = [3 1 4 6 7 2];
>>[Y, q] = levels(X,2)
Y =
1 1 2 2 2 1
q =
1 3.5 7
You could also modify the logic line to ensure values are less than the start of the next bin. However, I don't think it is necessary.
I think you shoud use histc
[~,Y] = histc(X,q)
As you can see in matlab's doc:
Description
n = histc(x,edges) counts the number of values in vector x that fall
between the elements in the edges vector (which must contain
monotonically nondecreasing values). n is a length(edges) vector
containing these counts. No elements of x can be complex.
I made a couple of refinements (including one inspired by Aero Engy in another answer) that have resulted in some improvements. To test them out, I created a random matrix of a million rows and 100 columns to run the improved functions on:
>> x = randn(1000000,100);
First, I ran my unmodified code, with the following results:
Note that of the 40 seconds, around 14 of them are spent computing the quantiles - I can't expect to improve this part of the routine (I assume that Mathworks have already optimized it, though I guess that to assume makes an...)
Next, I modified the routine to the following, which should be faster and has the advantage of being fewer lines as well!
function [Y q] = levels(X,nLevels)
p = linspace(0, 1.0, nLevels+1);
q = quantile(X,p);
if isvector(q), q = transpose(q); end
Y = ones(size(X));
for i = 2:nLevels
Y = Y + bsxfun(#ge,X,q(i,:));
end
The profiling results with this code are:
So it is 15 seconds faster, which represents a 150% speedup of the portion of code that is mine, rather than MathWorks.
Finally, following a suggestion of Andrey (again in another answer) I modified the code to use the second output of the histc function, which assigns entries to bins. It doesn't treat the columns independently, so I had to loop over the columns manually, but it seems to be performing really well. Here's the code:
function [Y q] = levels(X,nLevels)
p = linspace(0,1,nLevels+1);
q = quantile(X,p);
if isvector(q), q = transpose(q); end
q(end,:) = 2 * q(end,:);
Y = zeros(size(X));
for k = 1:size(X,2)
[junk Y(:,k)] = histc(X(:,k),q(:,k));
end
And the profiling results:
We now spend only 4.3 seconds in codes outside the quantile function, which is around a 500% speedup over what I wrote originally. I've spent a bit of time writing this answer because I think it's turned into a nice example of how you can use the MATLAB profiler and StackExchange in combination to get much better performance from your code.
I'm happy with this result, although of course I'll continue to be pleased to hear other answers. At this stage the main performance increase will come from increasing the performance of the part of the code that currently calls quantile. I can't see how to do this immediately, but maybe someone else here can. Thanks again!
You can sort the columns and divide+round the inverse indexes:
function Y = levels(X,nLevels)
% "Assign each of the elements of X to an integer-valued level"
[S,IX]=sort(X);
[grid1,grid2]=ndgrid(1:size(IX,1),1:size(IX,2));
invIX=zeros(size(X));
invIX(sub2ind(size(X),IX(:),grid2(:)))=grid1;
Y=ceil(invIX/size(X,1)*nLevels);
Or you can use tiedrank:
function Y = levels(X,nLevels)
% "Assign each of the elements of X to an integer-valued level"
R=tiedrank(X);
Y=ceil(R/size(X,1)*nLevels);
Surprisingly, both these solutions are slightly slower than the quantile+histc solution.