Hill climbing in 7D space - matlab

I have below function in 7D space (means x=(x1,x2,x3,x4,x5,x6,x7)) and I want find the minimum point of this function with hill climbing in matlab.
I found this link useful but I don't know how can I implement my function in Matlab.
Update:
I implement below code but I don't really know if it is correct.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% Create a grid of states %%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
clear all ,close all;
n=7;
range=[-32.768:0.1:32.768];
x=[0,0,0,0,0,1,1];
F=-20*exp(-0.2*sqrt(1/n*sum(x.^2)))-exp(1/n*sum(cos(2*pi*x)))+20 +exp(1);
F1=zeros(7,2);
best = -100000000; % Best value found so far.
for (j=1:20)
% Pick a starting location at random, and try and find the maximum state by hill climbing.
% Repeat this a (to be precise, repeat it until j = 20).
s=floor(100*rand(7,1)) ;
% Generate successors, and compute the one with the maximum value.
% Only consider states to the N, S, E, W, and NoMove.
for (i=1:100)
% Find successors
S0=s;
F0=-20*exp(-0.2*sqrt(1/n*sum(S0.^2)))-exp(1/n*sum(cos(2*pi*S0)))+20 +exp(1);
for tt=1:7
arr=[0;0;0;0;0;0;0];
arr(tt)=1;
S1=s+arr;
F1(tt,1)=-20*exp(-0.2*sqrt(1/n*sum(S1.^2)))-exp(1/n*sum(cos(2*pi*S1)))+20 +exp(1);
arr(tt)=-1;
S1=s+arr;
F1(tt,2)=-20*exp(-0.2*sqrt(1/n*sum(S1.^2)))-exp(1/n*sum(cos(2*pi*S1)))+20 +exp(1);
end
[v,vi] = max([F1(:,1)',F1(:,1)',F0]);
arr=[0;0;0;0;0;0;0];
index=mod(vi,7);
if(index==0)
index=7;
end
if(vi<=7 && vi ~= 15)
arr(index)=1;
s=s+arr;
elseif(vi>7 && vi ~= 15)
arr(index)=-1;
s=s+arr;
else
s=s ; %% for better understanding
end
end
end

I implement it here. I hope be useful for another reader that have problem.
clear all ,close all;
clc;
n=7;
range=[-32.768:0.1:32.768];
%x=[0,0,0,0,0,1,1];
%F=-20*exp(-0.2*sqrt(1/n*sum(x.^2)))-exp(1/n*sum(cos(2*pi*x)))+20 +exp(1);
F1=zeros(7,2);
for (j=1:20)
s=floor(rand(7,1)*64-32) ;
i=0;
convergence=0;
while(convergence~=1 && i <10000)
% Find successors
S0=s;
F0=-20*exp(-0.2*sqrt(1/n*sum(S0.^2)))-exp(1/n*sum(cos(2*pi*S0)))+20 +exp(1);
%step=rand();
step=0.005; % this is step of climbing
for tt=1:7
arr=[0;0;0;0;0;0;0];
arr(tt)=step;
S1=s+arr;
F1(tt,1)=-20*exp(-0.2*sqrt(1/n*sum(S1.^2)))-exp(1/n*sum(cos(2*pi*S1)))+20 +exp(1);
arr(tt)=-step;
S1=s+arr;
F1(tt,2)=-20*exp(-0.2*sqrt(1/n*sum(S1.^2)))-exp(1/n*sum(cos(2*pi*S1)))+20 +exp(1);
end
[v,vi] = max([F1(:,1)',F1(:,1)',F0]);
arr=[0;0;0;0;0;0;0];
index=mod(vi,7);
if(index==0)
index=7;
end
if(vi<=7 && vi ~= 15)
arr(index)=step;
s=s+arr;
elseif(vi>7 && vi ~= 15)
arr(index)=-step;
s=s+arr;
else
convergence=1; %this means no neighbor has better value than current a
%maybe this point be local optimom
end
i=i+1;
end
disp('*****************************');
disp(sprintf('Step of convergence %i:',i));
disp('coordination of optimum point :');
disp(s');
disp('*****************************');
end

Related

Table performance / general performance / vectorizing

I implemented a 4D Interpolation in matlab, where performance is really important. The interpolation method is a nearest neighbor interpolation based on a delaunay triangulation. As I am quite new to matlab coding, I want to ask, if I should use arrays or cells instead of tables, because of their poor performance. Also the general question, if you see anything, where I can speed up my code. I already saved the mat files in v6 so this is not an option. Below the text you see the code of the main program. After that the code for the 2D interpolation.
the tables I loaded in consist of 7 coloums filled with AeroDataId, X_C coordinate, CP (pressure derivative), Mach number, lift coefficient, ReynoldsNumber and Transition. One AeroDataId belongs to in the most cases 280 x_c coordinates with the different pressure coefficients.
Filtering all the data seems to be faster than using sql queries.
clc
close
clear
%% ReynoldsNumbers and Transitions known in the database
ReynoldsNumbers=[1e6;1.5e6;2.5e6;5e6;8e6;14e6;25e6;50e6;100e6];
Transition=[0;0.1;0.2;0.3;0.4;0.5;0.6;0.7;0.8;0.9];
%% parameters
Ma=0.85;
C_l=0.345;
Tl=0.15;
Re=55e6;
AirfoilId=0;
delta=0.015;
delta_ini=0.15;
%% try to find the neighbours of the parameters, which already exist in the database
tic
Re_u=ReynoldsNumbers(ReynoldsNumbers==Re);
Tl_u=Transition(Transition==Tl);
Tl_o=[];
Re_o=[];
if isempty(Re_u)
Re_u_index=nearestpoint(Re,ReynoldsNumbers,'previous');
Re_o_index=nearestpoint(Re,ReynoldsNumbers,'next');
Re_o=ReynoldsNumbers(Re_o_index);
Re_u=ReynoldsNumbers(Re_u_index);
if Re < 1e6
Re_u=1e6;
Re_o=1.5e6;
elseif Re > 100e6
Re_u=50e6;
Re_o=100e6;
end
end
if isempty(Tl_u)
Tl_u_index=nearestpoint(Tl,Transition,'previous');
Tl_o_index=nearestpoint(Tl,Transition,'next');
Tl_u=Transition(Tl_u_index);
Tl_o=Transition(Tl_o_index);
end
toc
%% load data based on the airfoilId size of new_upper_airfoil 25000000x7 table
if AirfoilId==0
load('new_upper_airfoil_all_0');
load('new_lower_airfoil_all_0');
elseif AirfoilId==1
load('new_upper_airfoil_all_1');
load('new_lower_airfoil_all_1');
elseif AirfoilId==2
load('new_upper_airfoil_all_2');
load('new_lower_airfoil_all_2');
end
%% no need to to make all the interpolation with the whole data, only a specific delta
new_upper_airfoil=new_upper_airfoil_all(new_upper_airfoil_all.Ma < (Ma+delta_ini) & new_upper_airfoil_all.Ma > (Ma-delta_ini) & new_upper_airfoil_all.CL_res < (C_l+delta_ini) & new_upper_airfoil_all.CL_res > (C_l-delta_ini),2:7);
new_lower_airfoil=new_lower_airfoil_all(new_lower_airfoil_all.Ma < (Ma+delta_ini) & new_lower_airfoil_all.Ma > (Ma-delta_ini) & new_lower_airfoil_all.CL_res < (C_l+delta_ini) & new_lower_airfoil_all.CL_res > (C_l-delta_ini),2:7);
%% filter data for the first 2D - Interpoaltion and execute it
new_upper_airfoil1=new_upper_airfoil(new_upper_airfoil.ReynoldsNumber==Re_u & new_upper_airfoil.Transition==Tl_u,1:4);
new_lower_airfoil1=new_lower_airfoil(new_lower_airfoil.ReynoldsNumber==Re_u & new_lower_airfoil.Transition==Tl_u,1:4);
DV1=delaunay_nearest(new_upper_airfoil1, new_lower_airfoil1, Ma, C_l, delta);
DV_1=table(DV1.X_C, DV1.CP, repmat(Re_u,280,1),repmat(Tl_u,280,1),'VariableNames',{'X_C','CP','Re','Tl'});
%% secound
if ~isempty(Tl_o)
new_upper_airfoil2=new_upper_airfoil(new_upper_airfoil.ReynoldsNumber==Re_u & new_upper_airfoil.Transition==Tl_o,1:4);
new_lower_airfoil2=new_lower_airfoil(new_lower_airfoil.ReynoldsNumber==Re_u & new_lower_airfoil.Transition==Tl_o,1:4);
DV2=delaunay_nearest(new_upper_airfoil2, new_lower_airfoil2, Ma, C_l, delta);
DV_2=table(DV2.X_C, DV2.CP, repmat(Re_u,280,1), repmat(Tl_o,280,1),'VariableNames',{'X_C','CP','Re','Tl'});
else
DV_2=[];
end
%% third
if ~isempty(Re_o)
new_upper_airfoil3=new_upper_airfoil(new_upper_airfoil.ReynoldsNumber==Re_o & new_upper_airfoil.Transition==Tl_u,1:4);
new_lower_airfoil3=new_lower_airfoil(new_lower_airfoil.ReynoldsNumber==Re_o & new_lower_airfoil.Transition==Tl_u,1:4);
DV3=delaunay_nearest(new_upper_airfoil3, new_lower_airfoil3, Ma, C_l, delta);
DV_3=table(DV3.X_C, DV3.CP, repmat(Re_o,280,1),repmat(Tl_u,280,1),'VariableNames',{'X_C','CP','Re','Tl'});
else
DV_3=[];
end
%% fourth
if ~isempty(Re_o) && ~isempty(Tl_o)
new_upper_airfoil4=new_upper_airfoil(new_upper_airfoil.ReynoldsNumber==Re_o & new_upper_airfoil.Transition==Tl_o,1:4);
new_lower_airfoil4=new_lower_airfoil(new_lower_airfoil.ReynoldsNumber==Re_o & new_lower_airfoil.Transition==Tl_o,1:4);
DV4=delaunay_nearest(new_upper_airfoil4, new_lower_airfoil4, Ma, C_l, delta);
DV_4=table(DV4.X_C, DV4.CP, repmat(Re_o,280,1),repmat(Tl_o,280,1),'VariableNames',{'X_C','CP','Re','Tl'});
else
DV_4=[];
end
%% Interpolation of the 4 2D Interpolations
DV_inter=[DV_1;DV_2;DV_3;DV_4];
if size(DV_inter,1)==280
DV=DV_1(:,1:2);
% figure
% hold on
% plot(DV.X_C,-DV.CP,'bl-');
% grid on;
% xlabel('X_C');
% ylabel('Cp');
%
else
%% interpolation with inverse distance weighted interpoaltion
load('x_c0');
DV=zeros(281,2);
for x_c=1:1:280
x_c_inter=x_c0(x_c);
Find=DV_inter(DV_inter.X_C==x_c_inter,:);
cp_inter=IDW(Find.Re, Find.Tl,Find.CP,Re,Tl,-2,'ng',2);
DV(x_c,:)=[x_c_inter,cp_inter];
end
DV(281,:)=DV(1,:);
figure
hold on
plot(DV(:,1),-DV(:,2),'r-');
grid on;
xlabel('X_C');
ylabel('Cp');
end
function DV = delaunay_nearest(new_upper_airfoil,new_lower_airfoil,Ma,C_l,delta)
Error=true;
load('x_c0');
while(Error)
%% build table for the pressure distribution
DV=array2table(zeros(280,2),'VariableNames',{'X_C','CP'});
%% another smaller delta for the interpolation (if too small the exception will be catched and the interpolation is restarted with a higher delta
new_upper_airfoil_loop=new_upper_airfoil(new_upper_airfoil.Ma < (Ma+delta) & new_upper_airfoil.Ma > (Ma-delta) & new_upper_airfoil.CL_res < (C_l+delta) & new_upper_airfoil.CL_res > (C_l-delta),:);
new_lower_airfoil_loop=new_lower_airfoil(new_lower_airfoil.Ma < (Ma+delta) & new_lower_airfoil.Ma > (Ma-delta) & new_lower_airfoil.CL_res < (C_l+delta) & new_lower_airfoil.CL_res > (C_l-delta),:);
%% try to build the delaunay triangulation
try
DT=delaunayTriangulation(new_upper_airfoil_loop.Ma,new_upper_airfoil_loop.CL_res);
% figure
% hold on;
% triplot(DT);
% plot(Ma,C_l,'ro');
%% find nearest neighbor
pointindex=dsearchn(DT.Points,[Ma,C_l]);
point=DT.Points(pointindex,:);
Error=0;
catch
delta=delta+0.005;
disp('Die Deltas wurden um 0.005 erhöht, da der Bereich der Daten zu klein war.');
continue;
end
%% search for the nearest neighbor
new_upper_airfoil_loop=new_upper_airfoil_loop(new_upper_airfoil_loop.Ma==point(1,1) & new_upper_airfoil_loop.CL_res==point(1,2),1:2);
new_lower_airfoil_loop=new_lower_airfoil_loop(new_lower_airfoil_loop.Ma==point(1,1) & new_lower_airfoil_loop.CL_res==point(1,2),1:2);
%% 2D Interpolation for all 280 points of the airfoil with the same x/c coordinates
for x_c=1:1:280
x_c_inter=x_c0(x_c);
%% upper_airfoil
if x_c < 146
FIND=new_upper_airfoil_loop(abs(new_upper_airfoil_loop.X_C-x_c_inter)<0.0005,:);
if(isempty(FIND))
leftNeighborIndex=nearestpoint(x_c_inter,new_upper_airfoil_loop.X_C,'previous');
if isnan(leftNeighborIndex)
leftNeighborIndex=1;
end
rightNeighborIndex=leftNeighborIndex+1;
if rightNeighborIndex > height(new_upper_airfoil_loop)
rightNeighborIndex=leftNeighborIndex-1;
end
average=interp1([new_upper_airfoil_loop.X_C(leftNeighborIndex,:),new_upper_airfoil_loop.X_C(rightNeighborIndex,:)], [new_upper_airfoil_loop.CP(leftNeighborIndex,:),new_upper_airfoil_loop.CP(rightNeighborIndex,:)], x_c_inter, 'linear','extrap');
FIND.X_C(1,:)=x_c_inter;
FIND.CP(1,:)=average;
DV(x_c,:)=FIND;
else
FIND.X_C(1,1)=x_c_inter;
DV(x_c,:)=FIND(1,:);
end
end
%% lower airfoil
if x_c > 145
FIND=new_lower_airfoil_loop(abs(new_lower_airfoil_loop.X_C-x_c_inter)<0.00008,:);
if(isempty(FIND))
leftNeighborIndex=nearestpoint(x_c_inter,new_lower_airfoil_loop.X_C,'previous');
if isnan(leftNeighborIndex)
leftNeighborIndex=height(new_lower_airfoil_loop);
end
rightNeighborIndex=leftNeighborIndex-1;
average=interp1([new_lower_airfoil_loop.X_C(leftNeighborIndex,:),new_lower_airfoil_loop.X_C(rightNeighborIndex,:)], [new_lower_airfoil_loop.CP(leftNeighborIndex,:),new_lower_airfoil_loop.CP(rightNeighborIndex,:)], x_c_inter, 'linear','extrap');
FIND.X_C(1,:)=x_c_inter;
FIND.CP(1,:)=average;
DV(x_c,:)=FIND;
else
FIND.X_C(1,1)=x_c_inter;
DV(x_c,:)=FIND(1,:);
end
end
end
end
end

How do I adjust this code so that I can enter how many runs I want and it will store each run in a matrix?

I have created this code to generate a 1 set of lottery numbers, but I am trying to make it so that the user can enter how many sets they want (input n), and it will print out as one long matrix of size nX6? I was messing around with a few options from online suggestions, but to no avail. I put the initial for i=1:1:n at the beginning, but I do not know how to store each run into a growing matrix. Right now it still generates just 1 set.
function lottery(n)
for i=1:1:n
xlow=1;
xhigh=69;
m=5;
i=1;
while (i<=m)
lottonum(i)=floor(xlow+rand*(xhigh-xlow+1));
flag=0;
for j=1:i-1
if (lottonum(i)==lottonum(j))
flag=1;
end
end
if flag==0
i=i+1;
end
end
ylow=1;
yhigh=26;
m=1;
lottonum1=floor(ylow+rand*(yhigh-ylow+1));
z = horzcat(lottonum, lottonum1);
end
disp('The lotto numbers picked are')
fprintf('%g ',z)
disp (' ')
The problem is that you are not storing or displaying the newly generated numbers, only the last set. To solve this, initialize z with NaNs or zeros, and later index z to store each set in a row of z, by using z(i,:) = lottonum.
However, you are using i as iterator in the while loop already, so you should use another variable, e.g. k.
You can also set z as an output of the function, so you can use this matrix in some other part of a program.
function z = lottery(n)
% init z
z = NaN(n,6);
for k = 1:n
xlow=1;
xhigh=69;
m=5;
i=1;
while (i<=m)
lottonum(i)=floor(xlow+rand*(xhigh-xlow+1));
flag=0;
for j=1:i-1
if (lottonum(i)==lottonum(j))
flag=1;
end
end
if flag==0
i=i+1;
end
end
ylow=1;
yhigh=26;
lottonum1 = floor(ylow+rand*(yhigh-ylow+1));
z(k,:) = horzcat(lottonum, lottonum1); % put the numbers in a row of z
end
disp('The lotto numbers picked are')
disp(z) % prettier display than fprintf in this case.
disp (' ')
end
The nice answer from rinkert corrected your basic mistakes (like trying to modify your loop iterator i from within the loop => does not work), and answered your question on how to store all your results.
This left you with a working code, however, I'd like to propose to you a different way to look at it.
The porposed architecture is to divide the tasks into separate functions:
One function draw_numbers which can draw N numbers randomly (and does only that)
One function draw_lottery which call the previous function as many times as it needs (your n), collect the results and display them.
draw_lottery
This architecture has the benefit to greatly simplify your main function. It can now be as simple as:
function Draws = draw_lottery(n)
% define your draw parameters
xmin = 1 ; % minimum number drawn
xmax = 69 ; % maximum number drawn
nballs = 5 ; % number of number to draw
% pre allocate results
Draws = zeros( n , nballs) ;
for iDraw=1:1:n
% draw "nballs" numbers
thisDraw = draw_numbers(xmin,xmax,nballs) ;
% add them to the result matrix
Draws(iDraw,:) = thisDraw ;
end
disp('The lotto numbers picked are:')
disp (Draws)
disp (' ')
end
draw_numbers
Instead of using a intricated set of if conditions and several iterators (i/m/k) to branch the program flow, I made the function recursive. It means the function may have to call itself a number of time until a condition is satisfied. In our case the condition is to have a set of nballs unique numbers.
The function:
(1) draws N integer numbers randomly, using randi.
(2) remove duplicate numbers (if any). Using unique.
(3) count how many unique numbers are left Nu
(4a) if Nu = N => exit function
(4b) if Nu < N => Call itself again, sending the existing Nu numbers and asking to draw an additional N-Nu numbers to add to the collection. Then back to step (2).
in code, it looks like that:
function draw = draw_numbers(xmin,xmax,nballs,drawn_set)
% check if we received a partial set
if nargin == 4
% if yes, adjust the number of balls to draw
n2draw = nballs - numel(drawn_set) ;
else
% if not, make a full draw
drawn_set = [] ;
n2draw = nballs ;
end
% draw "nballs" numbers between "xmin" and "xmax"
% and concatenate these new numbers with the partial set
d = [drawn_set , randi([xmin xmax],1,n2draw)] ;
% Remove duplicate
drawn_set = unique(d) ;
% check if we have some more balls to draw
if numel(drawn_set) < nballs
% draw some more balls
draw = draw_numbers(xmin,xmax,nballs,drawn_set) ;
else
% we're good to go, assign output and exit funtion
draw = drawn_set ;
end
end
You can have both functions into the same file if you want.
I encourage you to look at the documentation of a couple of Matlab built-in functions used:
randi
unique

How to save results from my script in vectors in Matlab?

I was wondering if someone could help me with MatLab.
Is there a way to save these 2 values count_zero and count_value into 2 vectors.
The part of interest in the following code is inside the while loop, the upper part is irrelevant for this question.
For example all values of count_zero should be saved in vector a=[count_zero count_zero ..] and all values of count_value in vector b=[count_value count_value ...].
This is my code, thanks in advance.
threeminutesofvideo_Youtube;
h=[0:0.5:179];
for idx=1:length(h)
threshold=h(idx);
m =find(threshold-1<=x & x<=threshold);
Y(idx)=sum(y(m));
end
count_zero=0;
count_value=0;
i=1;
while i<length(Y)
if (Y(i)==0)
count_zero=count_zero+1;
i=i+1;
while Y(i)==0 && i<length(Y)
count_zero=count_zero+1;
i=i+1;
end
if i<(length(Y))
count_zero
count_zero=0;
end
if i==(length(Y)) && Y(length(Y))~=0
count_value=1;
count_value
count_value=0;
elseif i==(length(Y)) && Y(length(Y))==0
count_zero=count_zero + 1;
count_zero
count_zero=0;
end
else
count_value=count_value+1;
i=i+1;
while Y(i)~=0 && i<length(Y)
count_value=count_value+1;
i=i+1;
end
if i<(length(Y))
count_value
count_value=0;
end
if i==(length(Y)) && Y(length(Y))~=0
count_value=count_value+1;
count_value
count_value=0;
elseif i==(length(Y)) && Y(length(Y))==0
count_zero=1;
count_zero
count_zero=0;
end
end
end
As far as I have understood you want to memorize the values in a vector, not to save to file don't you?
In this case let us call the vector in which you want to memorize If you know a priori the number of values you want to memorize you can do this
a = NaN*ones(num_of_values,1);
i=1;
while condition
...
a(i) = temp_val;
i = i+1;
end
If you don't know the number of values a priori:
a=[];
i=1;
while condition
...
a = [a;temp_val];
i=i+1;
end
I hope to have been helpful

Matlab not plotting, endless loop

I'm trying to use the bisection method in Matlab to find the root of an equation as q varies from 2000-3000 in 10 step intervals. My code however does not print out a graph even though I have a plot statement and I think it creates an infinite loop since when I run it matlab says busy and I can't close the program unless I force close. I can't see anything in my code that would cause this though, could someone help me out?
function myFunction
a = 20;
b = 40;
tol = 1e-4;
q = 2000:10:3000;
t = zeros(101,1);
for i=(1:length(q))
f = #(x) (((1800).*log((160000)./(160000 - (x.*q(i)))) - (9.812).*x)./750) - 1;
t(i) = bisect(f,a,b,tol);
end
figure(1)
plot(q,t)
function c=bisect(f,a,b,tol)
k=0;
while b-a > tol
c = (a-b)/2;
if sign(f(c)) == sign(f(b))
b=c;
else
a=c;
end
k=k+1;
end
end
end
It should also be noted that I have used this bisect method before and it does work so I don't think the problem is with that function.
Your error is here:
c = (a-b)/2;
You initialize a=20 and b=40. c is initially set to -10. But you really want c to be halfway between a and b, which means you want:
c = (a+b)/2;
Also, add a drawnow right after you plot statement to force MATLAB to draw graphics.

intermittent loops in matlab

Hello again logical friends!
I’m aware this is quite an involved question so please bear with me! I think I’ve managed to get it down to two specifics:- I need two loops which I can’t seem to get working…
Firstly; The variable rollers(1).ink is a (12x1) vector containing ink values. This program shares the ink equally between rollers at each connection. I’m attempting to get rollers(1).ink to interact with rollers(2) only at specific timesteps. The ink should transfer into the system once for every full revolution i.e. nTimesSteps = each multiple of nBins_max. The ink should not transfer back to rollers(1).ink as the system rotates – it should only introduce ink to the system once per revolution and not take any back out. Currently I’ve set rollers(1).ink = ones but only for testing. I’m truly stuck here!
Secondly; The reason it needs to do this is because at the end of the sim I also wish to remove ink in the form of a printed image. The image should be a reflection of the ink on the last roller in my system and half of this value should be removed from the last roller and taken out of the system at each revolution. The ink remaining on the last roller should be recycled and ‘re-split’ in the system ready for the next rotation.
So…I think it’s around the loop beginning line86 where I need to do all this stuff. In pseudo, for the intermittent in-feed I’ve been trying something like:
For k = 1:nTimeSteps
While nTimesSteps = mod(nTimeSteps, nBins_max) == 0 % This should only output when nTimeSteps is a whole multiple of nBins_max i.e. one full revolution
‘Give me the ink on each segment at each time step in a matrix’
End
The output for averageAmountOfInk is the exact format I would like to return this data except I don’t really need the average, just the actual value at each moment in time. I keep getting errors for dimensional mismatches when I try to re-create this using something like:
For m = 1:nTimeSteps
For n = 1:N
Rollers(m,n) = rollers(n).ink’;
End
End
I’ll post the full code below if anyone is interested to see what it does currently. There’s a function at the end also which of course needs to be saved out to a separate file.
I’ve posted variations of this question a couple of times but I’m fully aware it’s quite a tricky one and I’m finding it difficult to get my intent across over the internets!
If anyone has any ideas/advice/general insults about my lack of programming skills then feel free to reply!
%% Simple roller train
% # Single forme roller
% # Ink film thickness = 1 micron
clc
clear all
clf
% # Initial state
C = [0,70; % # Roller centres (x, y)
10,70;
21,61;
11,48;
21,34;
27,16;
0,0
];
R = [5.6,4.42,9.8,6.65,10.59,8.4,23]; % # Roller radii (r)
% # Direction of rotation (clockwise = -1, anticlockwise = 1)
rotDir = [1,-1,1,-1,1,-1,1]';
N = numel(R); % # Amount of rollers
% # Find connected rollers
isconn = #(m, n)(sum(([1, -1] * C([m, n], :)).^2)...
-sum(R([m, n])).^2 < eps);
[Y, X] = meshgrid(1:N, 1:N);
conn = reshape(arrayfun(isconn, X(:), Y(:)), N, N) - eye(N);
% # Number of bins for biggest roller
nBins_max = 50;
nBins = round(nBins_max*R/max(R))';
% # Initialize roller struct
rollers = struct('position',{}','ink',{}','connections',{}',...
'rotDirection',{}');
% # Initialise matrices for roller properties
for ii = 1:N
rollers(ii).ink = zeros(1,nBins(ii));
rollers(ii).rotDirection = rotDir(ii);
rollers(ii).connections = zeros(1,nBins(ii));
rollers(ii).position = 1:nBins(ii);
end
for ii = 1:N
for jj = 1:N
if(ii~=jj)
if(conn(ii,jj) == 1)
connInd = getConnectionIndex(C,ii,jj,nBins(ii));
rollers(ii).connections(connInd) = jj;
end
end
end
end
% # Initialize averageAmountOfInk and calculate initial distribution
nTimeSteps = 1*nBins_max;
averageAmountOfInk = zeros(nTimeSteps,N);
inkPerSeg = zeros(nTimeSteps,N);
for ii = 1:N
averageAmountOfInk(1,ii) = mean(rollers(ii).ink);
end
% # Iterate through timesteps
for tt = 1:nTimeSteps
rollers(1).ink = ones(1,nBins(1));
% # Rotate all rollers
for ii = 1:N
rollers(ii).ink(:) = ...
circshift(rollers(ii).ink(:),rollers(ii).rotDirection);
end
% # Update all roller-connections
for ii = 1:N
for jj = 1:nBins(ii)
if(rollers(ii).connections(jj) ~= 0)
index1 = rollers(ii).connections(jj);
index2 = find(ii == rollers(index1).connections);
ink1 = rollers(ii).ink(jj);
ink2 = rollers(index1).ink(index2);
rollers(ii).ink(jj) = (ink1+ink2)/2;
rollers(index1).ink(index2) = (ink1+ink2)/2;
end
end
end
% # Calculate average amount of ink on each roller
for ii = 1:N
averageAmountOfInk(tt,ii) = sum(rollers(ii).ink);
end
end
image(5:20) = (rollers(7).ink(5:20))./2;
inkPerSeg1 = [rollers(1).ink]';
inkPerSeg2 = [rollers(2).ink]';
inkPerSeg3 = [rollers(3).ink]';
inkPerSeg4 = [rollers(4).ink]';
inkPerSeg5 = [rollers(5).ink]';
inkPerSeg6 = [rollers(6).ink]';
inkPerSeg7 = [rollers(7).ink]';
This is an extended comment rather than a proper answer, but the comment box is a bit too small ...
Your code overwhelms me, I can't see the wood for the trees. I suggest that you eliminate all the stuff we don't need to see to help you with your immediate problem (all those lines drawing figures for example) -- I think it will help you to debug your code yourself to put all that stuff into functions or scripts.
Your code snippet
For k = 1:nTimeSteps
While nTimesSteps = mod(nTimeSteps, nBins_max) == 0
‘Give me the ink on each segment at each time step in a matrix’
End
might be (I don't quite understand your use of the while statement, the word While is not a Matlab keyword, and as you have written it the value returned by the statement doesn't change from iteration to iteration) equivalent to
For k = 1:nBins_max:nTimeSteps
‘Give me the ink on each segment at each time step in a matrix’
End
You seem to have missed an essential feature of Matlab's colon operator ...
1:8 = [1 2 3 4 5 6 7 8]
but
1:2:8 = [1 3 5 7]
that is, the second number in the triplet is the stride between successive elements.
Your matrix conn has a 1 at the (row,col) where rollers are connected, and a 0 elsewhere. You can find the row and column indices of all the 1s like this:
[ri,ci] = find(conn==1)
You could then pick up the (row,col) locations of the 1s without the nest of loops and if statements that begins
for ii = 1:N
for jj = 1:N
if(ii~=jj)
if(conn(ii,jj) == 1)
I could go on, but won't, that's enough for one comment.