Looping through points in the unit triangle - matlab

I have a problem where I have two choice variables x1 and x2 which then pin down a third x3 = 1 - x1 - x2. I would like to loop through various values of [x1, x2, x3]. This code works:
w1 = perms([0.1, 0.1, 0.8]);
w2 = perms([0.1, 0.2, 0.7]);
w3 = perms([0.1, 0.3, 0.6]);
w4 = perms([0.1, 0.4, 0.5]);
w5 = perms([0.2, 0.2, 0.6]);
w6 = perms([0.2, 0.3, 0.5]);
w7 = perms([0.2, 0.4, 0.4]);
w8 = perms([0.3, 0.3, 0.4]);
w = [w1; w2; w3; w4; w5; w6; w7; w8];
w = unique(w,'rows');
% loop
for ii = 1:size(w, 1)
... do some stuff with w(ii, :)
but I am wondering if there is a more elegant way to do this.

This is a classical case for ndgrid
[x1,x2]=ndgrid(0.1:0.1:0.8,0.1:0.1:0.8);
x3 = 1-x1-x2;
%I assume from your example that we want x1,x2,x3 in (0,1) OPEN interval, then:
valid_points = x3>0 & x3 <1
w_prime = [x1(valid_points),x2(valid_points),x3(valid_points)];

Related

What type of (probably syntactic) mistake am I making when using a generic function on an array for plotting?

I am trying to plot a geodesic on a 3D surface (tractrix) with Matlab. This worked for me in the past when I didn't need to parametrize the surface (see here). However, the tractrix called for parameterization, chain rule differentiation, and collection of u,v,x,y and f(x,y) values.
After many mistakes I think that I'm getting the right values for x = f1(u,v) and y = f2(u,v) describing a spiral right at the base of the surface:
What I can't understand is why the z value or height of the 3D plot of the curve is consistently zero, when I'm applying the same mathematical formula that allowed me to plot the surface in the first place, ie. f = #(x,y) a.* (y - tanh(y)) .
Here is the code, which runs without any errors on Octave. I'm typing a special note in upper case on the crucial calls. Also note that I have restricted the number of geodesic lines to 1 to decrease the execution time.
a = 0.3;
u = 0:0.1:(2 * pi);
v = 0:0.1:5;
[X,Y] = meshgrid(u,v);
% NOTE THAT THESE FORMULAS RESULT IN A SUCCESSFUL PLOT OF THE SURFACE:
x = a.* cos(X) ./ cosh(Y);
y = a.* sin(X) ./ cosh(Y);
z = a.* (Y - tanh(Y));
h = surf(x,y,z);
zlim([0, 1.2]);
set(h,'edgecolor','none')
colormap summer
hold on
% THESE ARE THE GENERIC FUNCTIONS (f) WHICH DON'T SEEM TO WORK AT THE END:
f = #(x,y) a.* (y - tanh(y));
f1 = #(u,v) a.* cos(u) ./ cosh(v);
f2 = #(u,v) a.* sin(u) ./ cosh(v);
dfdu = #(u,v) ((f(f1(u,v)+eps, f2(u,v)) - f(f1(u,v) - eps, f2(u,v)))/(2 * eps) .*
(f1(u+eps,v)-f1(u-eps,v))/(2*eps) +
(f(f1(u,v), f2(u,v)+eps) - f(f1(u,v), f2(u,v)-eps))/(2 * eps) .*
(f2(u+eps,v)-f2(u-eps,v))/(2*eps));
dfdv = #(u,v) ((f(f1(u,v)+eps, f2(u,v)) - f(f1(u,v) - eps, f2(u,v)))/(2 * eps) .*
(f1(u,v+eps)-f1(u,v-eps))/(2*eps) +
(f(f1(u,v), f2(u,v)+eps) - f(f1(u,v), f2(u,v)-eps))/(2 * eps) .*
(f2(u,v+eps)-f2(u,v-eps))/(2*eps));
% Normal vector to the surface:
N = #(u,v) [- dfdu(u,v), - dfdv(u,v), 1]; % Normal vec to surface # any pt.
% Some colors to draw the lines:
C = {'k','r','g','y','m','c'};
for s = 1:1 % No. of lines to be plotted.
% Starting points:
u0 = [0, u(length(u))];
v0 = [0, v(length(v))];
du0 = 0.001;
dv0 = 0.001;
step_size = 0.00005; % Will determine the progression rate from pt to pt.
eta = step_size / sqrt(du0^2 + dv0^2); % Normalization.
eps = 0.0001; % Epsilon
max_num_iter = 100000; % Number of dots in each line.
% Semi-empty vectors to collect results:
U = [[u0(s), u0(s) + eta*du0], zeros(1,max_num_iter - 2)];
V = [[v0(s), v0(s) + eta*dv0], zeros(1,max_num_iter - 2)];
for i = 2:(max_num_iter - 1) % Creating the geodesic:
ut = U(i);
vt = V(i);
xt = f1(ut,vt);
yt = f2(ut,vt);
ft = f(xt,yt);
utm1 = U(i - 1);
vtm1 = V(i - 1);
xtm1 = f1(utm1,vtm1);
ytm1 = f2(utm1,vtm1);
ftm1 = f(xtm1,ytm1);
usymp = ut + (ut - utm1);
vsymp = vt + (vt - vtm1);
xsymp = f1(usymp,vsymp);
ysymp = f2(usymp,vsymp);
fsymp = ft + (ft - ftm1);
df = fsymp - f(xsymp,ysymp); % Is the surface changing? How much?
n = N(ut,vt); % Normal vector at point t
gamma = df * n(3); % Scalar x change f x z value of N
xtp1 = xsymp - gamma * n(1); % Gamma to modulate incre. x & y.
ytp1 = ysymp - gamma * n(2);
U(i + 1) = usymp - gamma * n(1);;
V(i + 1) = vsymp - gamma * n(2);;
end
% THE PROBLEM! f(f1(U,V),f2(U,V)) below YIELDS ALL ZEROS!!! The expected values are between 0 and 1.2.
P = [f1(U,V); f2(U,V); f(f1(U,V),f2(U,V))]; % Compiling results into a matrix.
units = 35; % Determines speed (smaller, faster)
packet = floor(size(P,2)/units);
P = P(:,1: packet * units);
for k = 1:packet:(packet * units)
hold on
plot3(P(1, k:(k+packet-1)), P(2,(k:(k+packet-1))), P(3,(k:(k+packet-1))),
'.', 'MarkerSize', 5,'color',C{s})
drawnow
end
end
The answer is to Cris Luengo's credit, who noticed that the upper-case assigned to the variable Y, used for the calculation of the height of the curve z, was indeed in the parametrization space u,v as intended, and not in the manifold x,y! I don't use Matlab/Octave other than for occasional simulations, and I was trying every other syntactical permutation I could think of without realizing that f fed directly from v (as intended). I changed now the names of the different variables to make it cleaner.
Here is the revised code:
a = 0.3;
u = 0:0.1:(3 * pi);
v = 0:0.1:5;
[U,V] = meshgrid(u,v);
x = a.* cos(U) ./ cosh(V);
y = a.* sin(U) ./ cosh(V);
z = a.* (V - tanh(V));
h = surf(x,y,z);
zlim([0, 1.2]);
set(h,'edgecolor','none')
colormap summer
hold on
f = #(x,y) a.* (y - tanh(y));
f1 = #(u,v) a.* cos(u) ./ cosh(v);
f2 = #(u,v) a.* sin(u) ./ cosh(v);
dfdu = #(u,v) ((f(f1(u,v)+eps, f2(u,v)) - f(f1(u,v) - eps, f2(u,v)))/(2 * eps) .*
(f1(u+eps,v)-f1(u-eps,v))/(2*eps) +
(f(f1(u,v), f2(u,v)+eps) - f(f1(u,v), f2(u,v)-eps))/(2 * eps) .*
(f2(u+eps,v)-f2(u-eps,v))/(2*eps));
dfdv = #(u,v) ((f(f1(u,v)+eps, f2(u,v)) - f(f1(u,v) - eps, f2(u,v)))/(2 * eps) .*
(f1(u,v+eps)-f1(u,v-eps))/(2*eps) +
(f(f1(u,v), f2(u,v)+eps) - f(f1(u,v), f2(u,v)-eps))/(2 * eps) .*
(f2(u,v+eps)-f2(u,v-eps))/(2*eps));
% Normal vector to the surface:
N = #(u,v) [- dfdu(u,v), - dfdv(u,v), 1]; % Normal vec to surface # any pt.
% Some colors to draw the lines:
C = {'y','r','k','m','w',[0.8 0.8 1]}; % Color scheme
for s = 1:6 % No. of lines to be plotted.
% Starting points:
u0 = [0, -pi/2, 2*pi, 4*pi/3, pi/4, pi];
v0 = [0, 0, 0, 0, 0, 0];
du0 = [0, -0.0001, 0.001, - 0.001, 0.001, -0.01];
dv0 = [0.1, 0.01, 0.001, 0.001, 0.0005, 0.01];
step_size = 0.00005; % Will determine the progression rate from pt to pt.
eta = step_size / sqrt(du0(s)^2 + dv0(s)^2); % Normalization.
eps = 0.0001; % Epsilon
max_num_iter = 180000; % Number of dots in each line.
% Semi-empty vectors to collect results:
Uc = [[u0(s), u0(s) + eta*du0(s)], zeros(1,max_num_iter - 2)];
Vc = [[v0(s), v0(s) + eta*dv0(s)], zeros(1,max_num_iter - 2)];
for i = 2:(max_num_iter - 1) % Creating the geodesic:
ut = Uc(i);
vt = Vc(i);
xt = f1(ut,vt);
yt = f2(ut,vt);
ft = f(xt,yt);
utm1 = Uc(i - 1);
vtm1 = Vc(i - 1);
xtm1 = f1(utm1,vtm1);
ytm1 = f2(utm1,vtm1);
ftm1 = f(xtm1,ytm1);
usymp = ut + (ut - utm1);
vsymp = vt + (vt - vtm1);
xsymp = f1(usymp,vsymp);
ysymp = f2(usymp,vsymp);
fsymp = ft + (ft - ftm1);
df = fsymp - f(xsymp,ysymp); % Is the surface changing? How much?
n = N(ut,vt); % Normal vector at point t
gamma = df * n(3); % Scalar x change f x z value of N
xtp1 = xsymp - gamma * n(1); % Gamma to modulate incre. x & y.
ytp1 = ysymp - gamma * n(2);
Uc(i + 1) = usymp - gamma * n(1);;
Vc(i + 1) = vsymp - gamma * n(2);;
end
x = f1(Uc,Vc);
y = f2(Uc,Vc);
P = [x; y; f(Uc,Vc)]; % Compiling results into a matrix.
units = 35; % Determines speed (smaller, faster)
packet = floor(size(P,2)/units);
P = P(:,1: packet * units);
for k = 1:packet:(packet * units)
hold on
plot3(P(1, k:(k+packet-1)), P(2,(k:(k+packet-1))), P(3,(k:(k+packet-1))),
'.', 'MarkerSize', 5,'color',C{s})
drawnow
end
end

Solving and plotting a piecewise ODE

I have a function dφ/dt = γ - F(φ) (where F(φ) -- a is 2π-periodic function) and the graph of the function F(φ).
I need to create a program that outputs 6 plots of φ(t) for different values of γ (γ = 0.1, 0.5, 0.95, 1.05, 2, 5), and t∈[0,100].
Here is the definition of the F(φ) function:
-φ/a - π/a, if φ ∈ [-π, -π + a]
-1, if φ ∈ [-π + a, - a]
F(φ) = φ/a, if φ ∈ [- a, a]
1, if φ ∈ [a, π - a]
-φ/a + π/a, if φ ∈ [π - a, π]
^ F(φ)
|
|1 ______
| /| \
| / | \
| / | \ φ
__-π_______-a____|/___|________\π____>
\ | /|0 a
\ | / |
\ | / |
\ |/ |
¯¯¯¯¯¯ |-1
My problem is I don't know what inputs to give ode45 in terms of the bounds and the initial condition. What I do know is that the evolution of φ(t) must be continuous.
This is the code for case of γ = 0.1:
hold on;
df1dt = #(t,f1) 0.1 - f1 - 3.14;
df2dt = #(t,f2)- 1;
df3dt = #(t,f3) 0.1 + f3;
df4dt = #(t,f4)+1;
df5dt = #(t,f5) 0.1 - f5 + 3.14;
[T1,Y1] = ode45(df1dt, ...);
[T2,Y2] = ode45(df2dt, ...);
[T3,Y3] = ode45(df3dt, ...);
[T4,Y4] = ode45(df4dt, ...);
[T5,Y5] = ode45(df5dt, ...);
plot(T1,Y1);
plot(T2,Y2);
plot(T3,Y3);
plot(T4,Y4);
plot(T5,Y5);
hold off;
title('\gamma = 0.1')
Let us first define F(φ,a):
function out = F(p, a)
phi = mod(p,2*pi);
out = (0 <= phi & phi < a ).*(phi/a) ...
+ (a <= phi & phi < pi-a ).*(1) ...
+ (pi-a <= phi & phi < pi+a ).*(-phi/a + pi/a) ...
+ (pi+a <= phi & phi < 2*pi-a).*(-1) ...
+ (2*pi-a <= phi & phi < 2*pi ).*(phi/a - 2*pi/a);
end
Which for some example inputs gives:
using the plotting code:
x = linspace(-3*pi, 3*pi, 200);
a = pi/6;
figure(); plot(x,F(x, a));
xlim([-3*pi,3*pi]);
xticks(-3*pi:pi:3*pi);
xticklabels((-3:3)+ "\pi");
grid on; grid minor
ax = gca;
ax.XAxis.MinorTick = 'on';
ax.XAxis.MinorTickValues = ax.XAxis.Limits(1):pi/6:ax.XAxis.Limits(2);
From there you don't need to bother with the ranges anymore, and simply call ode45:
% Preparations:
a = pi/6;
g = [0.1, 0.5, 0.95, 1.05, 2, 5]; % γ
phi0 = 0; % you need to specify the correct initial condition (!)
tStart = 0;
tEnd = 100;
% Calling the solver:
[t, phi] = arrayfun(#(x)ode45(#(t,p)x-F(p,a), [tStart, tEnd], phi0), g, 'UniformOutput', false);
% Plotting:
plotData = [t; phi];
figure(); plot(plotData{:});
legend("γ=" + g, 'Location', 'northwest');
Resulting in:

Closing the figure window causes a new figure window to open

This is a analog clock. It runs perfectly. But once I close the clock, another figure opens up, and only the clock hands show. This makes it difficult to stop the program. How can I stop the program?
x=0;y=0;r=10;
hold on;
theta = 0:pi/60:2*pi;
xc = r * cos(theta);
yc = r * sin(theta);
h = plot(xc,yc,'r','linewidth',4);
axis off
r=9; i=1;
set(gca,'FontWeight','bold');
for theta = pi/6: pi/6: 2*pi
y1 = r * cos(theta);
x1 = r * sin(theta);
plot([x1/9*8 x1/9*7],[y1/9*8 y1/9*7],'color',[0 0 1])
text(x1/9*9.5,y1/9*9.5,num2str(i),'color',[0 0 1]);
i=i+1;
end
for theta=pi/30 : pi/30 : 2*pi
y1 = 10 * cos(theta);
x1 = 10 * sin(theta);
plot([x1/9*8 x1/9*7],[y1/9*8 y1/9*7],'color',[0 0 0])
end
while(1)
tic
c = clock;
c = c(1,4:6);
minute =c(1,2); sec=c(1,3);
if (c(1,1)>12)
hr = c(1,1)-12;
else
hr = c(1,1);
end
min1 = ceil(minute/12);
theta = (hr*pi)/6 + (min1*pi)/30;
f=figure(1); hold on;
y1 = 3 * cos(theta); Yhr = [0 y1];
x1 = 3 * sin(theta); Xhr = [0 x1];
hrhnd=plot(Xhr,Yhr);hold on;
theta1 = (minute*pi)/30;
y2 = 4.5 * cos(theta1); Ymin = [0 y2];
x2 = 4.5 * sin(theta1); Xmin = [0 x2];
minhnd=plot(Xmin,Ymin);
theta2 = (sec*pi)/30;
y3 = 5 * cos(theta2); Ysec = [0 y3];
x3 = 5 * sin(theta2); Xsec = [0 x3];
sechnd=plot(Xsec,Ysec);
z=toc;
pause(1-z);
delete(sechnd);
delete(minhnd);
delete(hrhnd);
end
The simplest way to stop the script when you close the window is to have the script test inside its loop if the window still exists.
We start the script by creating a figure window and recording its handle:
fig = figure;
Next, in the loop, we check to see if the window still exists using ishandle:
while(ishandle(fig))
...
end
The full program:
x=0;y=0;r=10;
fig = figure; %!!! NEW LINE
hold on;
theta = 0:pi/60:2*pi;
xc = r * cos(theta);
yc = r * sin(theta);
h = plot(xc,yc,'r','linewidth',4);
axis off
r=9; i=1;
set(gca,'FontWeight','bold');
for theta = pi/6: pi/6: 2*pi
y1 = r * cos(theta);
x1 = r * sin(theta);
plot([x1/9*8 x1/9*7],[y1/9*8 y1/9*7],'color',[0 0 1])
text(x1/9*9.5,y1/9*9.5,num2str(i),'color',[0 0 1]);
i=i+1;
end
for theta=pi/30 : pi/30 : 2*pi
y1 = 10 * cos(theta);
x1 = 10 * sin(theta);
plot([x1/9*8 x1/9*7],[y1/9*8 y1/9*7],'color',[0 0 0])
end
while(ishandle(fig)) %!!! UPDATED LINE
tic
c = clock;
c = c(1,4:6);
minute =c(1,2); sec=c(1,3);
if (c(1,1)>12)
hr = c(1,1)-12;
else
hr = c(1,1);
end
min1 = ceil(minute/12);
theta = (hr*pi)/6 + (min1*pi)/30;
f=figure(1); hold on;
y1 = 3 * cos(theta); Yhr = [0 y1];
x1 = 3 * sin(theta); Xhr = [0 x1];
hrhnd=plot(Xhr,Yhr);hold on;
theta1 = (minute*pi)/30;
y2 = 4.5 * cos(theta1); Ymin = [0 y2];
x2 = 4.5 * sin(theta1); Xmin = [0 x2];
minhnd=plot(Xmin,Ymin);
theta2 = (sec*pi)/30;
y3 = 5 * cos(theta2); Ysec = [0 y3];
x3 = 5 * sin(theta2); Xsec = [0 x3];
sechnd=plot(Xsec,Ysec);
z=toc;
pause(1-z);
delete(sechnd);
delete(minhnd);
delete(hrhnd);
end
You could improve your program by not deleting and re-drawing the hands, but updating their position. You'd do hrhnd=plot(Xhr,Yhr); before the loop, to draw the hand in its initial position, and then set(hrhnd,'XData',Xhr,'YData', Yhr) to update its position.
You could also do axis equal after drawing the clock face, to ensure it is round.
Note that you only need to give hold on once at the top, it is not needed after every plot command.

MATLAB optimization of the function

I want to optimize this function:
function Y_res = GetY( Y, P )
cnt = length(P);
denom = 0;
for i = 1:cnt
Y(i) = rand;
denom = denom + P(i) / (1 - Y(i));
end
Y_res = 1 - 1 / denom;
Y
Y_res
end
This function receives Y and P. P is a constant array. I need to optimize Y array values. And I trying to do this:
Y = [0.3 0.2 0.1]; % need to be optimized
P = [0.65 0.2 0.15]; % constant array
fhnd_GetY = #(x) GetY(Y, P);
options = optimset('TolX', 1e-3);
optimal_x = fminbnd(fhnd_GetY, 0.2, 0.4, options);
But the result of optimal_x variable does not equals to Y_res, which you can see on the screen during iterations of GetY function. Why? I need to optimze Y_res between 0.2 and 0.4 for example. So as a result I need to receive Y_res between 0.2 and 0.4 (for example) and Y array with values by means of which I can receive Y_res.
Assuming that you only intend to optimize the function GetY and given the fact that you are creating Y inside it and as such don't need to externally input Y into it, see if this modified function is optimized enough for you -
function [Y_res,Y] = GetY( P )
found = false;
while ~found
Y = rand(size(P));
Y_res = 1-1./sum(P./(1-Y));
if Y_res>0.2 & Y_res<0.4
found = true;
end
end
return;
Please note that if you don't need Y as an output, you can use Yres = GetY([0.65 0.2 0.15]) instead, but most probably you would need that (my guess though).
Few sample runs -
>> [Yres,Y] = GetY([0.65 0.2 0.15])
Yres =
0.3711
Y =
0.4243 0.2703 0.1971
>> [Yres,Y] = GetY([0.65 0.2 0.15])
Yres =
0.2723
Y =
0.1897 0.4950 0.1476
>> [Yres,Y] = GetY([0.65 0.2 0.15])
Yres =
0.3437
Y =
0.3624 0.0495 0.4896

2d interpolation table (Matlab)

I have a table( w, alfa, eta ):
w = [0, 0.5, 1]
alfa = [0, 0.3, 0.6, 0.9]
eta(0,0.3) = 0.23
eta(0.5,0) = 0.18
eta(0.5,0.6) = 0.65
eta(1,0.9) = 0.47
where, eta = f(w,alfa)
How can I interpolate the data to obtain all values ​​in this table?
I try griddata, interp2 etc but i can't do it.
It seems like griddata should do the work in your case. However, you should notice that your inputs requires extrapolation as well as interpolation.
>> [xout yout] = meshgrid( w, alfa ); % output points
>> w_in = [ 0, 0.5, 0.5, 1 ];
>> a_in = [ 0.3, 0, 0.6, 0.9 ];
>> e_in = [ 0.23, 0.18, 0.65, 0.47 ];
>> eta_out = griddata( w_in, a_in, e_in, xout, yout, 'linear' )