Difference between revisions of "User:Zeracles/Starmap/Minimal Spanning Tree"
< User:Zeracles | Starmap
Jump to navigation
Jump to search
m (renamed target and added line) |
(Boruvka's algorithm is faster, at least the way I've done it) |
||
Line 1: | Line 1: | ||
− | =Jarnik/Prim's Algorithm= | + | I originally coded up [[wikipedia:Prim's_algorithm|Jarnik/Prim's algorithm]]. In the process of optimising it, I unwittingly reinvented [[wikipedia:Bor%C5%AFvka%27s_algorithm|Boruvka's algorithm]], which handles large numbers of input points better, at least the way I've done it. |
+ | ==Boruvka's Algorithm== | ||
+ | Also downloadable [http://www.physics.usyd.edu.au/~asmith/files/sc1/MST_Boruvka.m here] | ||
+ | % minimal spannng tree in matlab | ||
+ | % Boruvka's algorithm (independently invented by yours truly) | ||
+ | % see http://www.star-control.com/forum/index.php/topic,1660 | ||
+ | % by Anthony Smith (Zeracles) | ||
+ | % astroant@hotmail.com | ||
+ | |||
+ | % if only after an MST, leave separation=pruning=0 | ||
+ | |||
+ | load('inputpositions') | ||
+ | |||
+ | localcount=8; | ||
+ | |||
+ | separation=0; | ||
+ | separationlength=0.03; | ||
+ | |||
+ | pruning=0; | ||
+ | prunesteps=1; % how many times to have a go at the tree | ||
+ | prunelevel=10; % length of branch to cut each time | ||
+ | |||
+ | % detect input properties and set up index | ||
+ | sizeinputpositions=size(inputpositions); | ||
+ | lengthinputpositions=sizeinputpositions(1); | ||
+ | dimensions=sizeinputpositions(2); | ||
+ | |||
+ | index=transpose(linspace(1,lengthinputpositions,lengthinputpositions)); | ||
+ | |||
+ | inputpositionxs=inputpositions(:,1); | ||
+ | inputpositionys=inputpositions(:,2); | ||
+ | if dimensions>2 | ||
+ | inputpositionzs=inputpositions(:,3); | ||
+ | end | ||
+ | |||
+ | % initialise search parameters | ||
+ | minx=min(inputpositionxs); | ||
+ | maxx=max(inputpositionxs); | ||
+ | xextent=minx*maxx; | ||
+ | |||
+ | miny=min(inputpositionys); | ||
+ | maxy=max(inputpositionys); | ||
+ | yextent=miny*maxy; | ||
+ | |||
+ | if dimensions>2 | ||
+ | minz=min(inputpositionzs); | ||
+ | maxz=max(inputpositionzs); | ||
+ | zextent=minz*maxz; | ||
+ | end | ||
+ | |||
+ | if dimensions==2 | ||
+ | measure=xextent*yextent; | ||
+ | localmeasure=measure/lengthinputpositions; | ||
+ | searchincrement=((localcount*localmeasure)/pi)^(1/2); | ||
+ | end | ||
+ | if dimensions==3 | ||
+ | measure=xextent*yextent*zextent; | ||
+ | localmeasure=measure/lengthinputpositions; | ||
+ | searchincrement=((localcount*localmeasure)/(4/3)/pi)^(1/3); | ||
+ | end | ||
+ | |||
+ | treenumber=index; | ||
+ | numbertrees=length(unique(treenumber)); | ||
+ | branches=[]; | ||
+ | searchfactor=1; % setting this to zero can lead to infinite loop if this is scaled multiplicatively | ||
+ | searchfactors=zeros(lengthinputpositions,1); | ||
+ | |||
+ | while numbertrees>1 % each input point is treated as a separate tree, and we join them together until we only have one tree | ||
+ | searchfactor=2*searchfactor; % calculate interpoint distances for ``close" points, with ``close" defined by this variable | ||
+ | while min(searchfactors)<searchfactor % searchfactors stores the searchfactors searched for each existing tree | ||
+ | tree=treenumber(min(find(searchfactors<(searchfactor)))); % choose a tree to search which has been searched with the smallest distance so far | ||
+ | treesearched=0; | ||
+ | while treesearched==0 % while we're not yet done looking around the nodes of this tree for links | ||
+ | maskvector=treenumber==tree; | ||
+ | treeindices=find(maskvector); | ||
+ | lengthtreepositions=sum(maskvector); | ||
+ | |||
+ | remainingpositionxs=inputpositionxs(find(maskvector==0)); | ||
+ | remainingpositionys=inputpositionys(find(maskvector==0)); | ||
+ | if dimensions>2 | ||
+ | remainingpositionzs=inputpositionzs(find(maskvector==0)); | ||
+ | end | ||
+ | |||
+ | remainingpositionindices=index(find(maskvector==0)); | ||
+ | |||
+ | mindistances=[]; | ||
+ | for i=linspace(1,lengthtreepositions,lengthtreepositions) % search around each of the tree positions for remainingpositions | ||
+ | % retrieve coordinates of a tree position | ||
+ | treepositionx=inputpositions(treeindices(i),1); | ||
+ | treepositiony=inputpositions(treeindices(i),2); | ||
+ | if dimensions>2 | ||
+ | treepositionz=inputpositions(treeindices(i),3); | ||
+ | end | ||
+ | treeindex=treeindices(i); | ||
+ | |||
+ | % search for remainingpositions | ||
+ | boxradius=searchfactor*searchincrement; | ||
+ | |||
+ | boxminx=treepositionx-boxradius; | ||
+ | boxmaxx=treepositionx+boxradius; | ||
+ | boxminy=treepositiony-boxradius; | ||
+ | boxmaxy=treepositiony+boxradius; | ||
+ | if dimensions>2 | ||
+ | boxminz=treepositionz-boxradius; | ||
+ | boxmaxz=treepositionz+boxradius; | ||
+ | end | ||
+ | |||
+ | if dimensions==2 | ||
+ | closerremainingmask=(boxminx<=remainingpositionxs).*(remainingpositionxs<=boxmaxx).*(boxminy<=remainingpositionys).*(remainingpositionys<=boxmaxy); | ||
+ | end | ||
+ | if dimensions==3 | ||
+ | closerremainingmask=(boxminx<=remainingpositionxs).*(remainingpositionxs<=boxmaxx).*(boxminy<=remainingpositionys).*(remainingpositionys<=boxmaxy).*(boxminz<=remainingpositionzs).*(remainingpositionzs<=boxmaxz); | ||
+ | end | ||
+ | |||
+ | mindistancecandidates=[]; | ||
+ | mindistancecandidateindices=[]; | ||
+ | if sum(closerremainingmask)>0 % if there are remainingpositions inside the box, calculate the actual distances to them | ||
+ | for k=transpose(find(closerremainingmask==1)); | ||
+ | branchcandidatex=remainingpositionxs(k); | ||
+ | branchcandidatey=remainingpositionys(k); | ||
+ | if dimensions>2 | ||
+ | branchcandidatez=remainingpositionzs(k); | ||
+ | end | ||
+ | branchcandidateindex=remainingpositionindices(k); % set up to remember the index of each prospective link destination | ||
+ | |||
+ | if dimensions==2 | ||
+ | mindistancecandidate=((branchcandidatex-treepositionx).^2+(branchcandidatey-treepositiony).^2).^(1/2); | ||
+ | end | ||
+ | if dimensions==3 | ||
+ | mindistancecandidate=((branchcandidatex-treepositionx).^2+(branchcandidatey-treepositiony).^2+(branchcandidatez-treepositionz).^2).^(1/2); | ||
+ | end | ||
+ | if mindistancecandidate<=boxradius | ||
+ | mindistancecandidates=[mindistancecandidates;mindistancecandidate]; | ||
+ | mindistancecandidateindices=[mindistancecandidateindices;branchcandidateindex]; | ||
+ | end | ||
+ | end | ||
+ | end | ||
+ | if numel(mindistancecandidates)>0 % minimum distance from this position on the tree | ||
+ | mindistance=[min(mindistancecandidates),treeindex,mindistancecandidateindices(find(mindistancecandidates==min(mindistancecandidates)))]; % minimum distances carry the indices of the prospective link destination | ||
+ | mindistances=[mindistances;mindistance]; | ||
+ | end | ||
+ | end | ||
+ | if numel(mindistances)==0 | ||
+ | searchfactors(maskvector)=searchfactor; | ||
+ | treesearched=1; | ||
+ | end | ||
+ | if numel(mindistances)>0 | ||
+ | branchdistance=min(mindistances(:,1)); | ||
+ | branchindex=find(branchdistance==mindistances(:,1)); | ||
+ | numberbranchcandidates=numel(branchindex); | ||
+ | if numberbranchcandidates>1 % if there's a tie for minimum length | ||
+ | branchindex=branchindex(ceil(numberbranchcandidates*rand(1))); | ||
+ | end | ||
+ | |||
+ | % add this branch to the tree | ||
+ | branch=mindistances(branchindex,:); | ||
+ | branches=[branches;branch]; | ||
+ | |||
+ | % join the two trees together | ||
+ | targettree=treenumber(branch(3)); % need to update the treenumber variable, which remembers which points belong to which trees | ||
+ | treenumber(find(treenumber==targettree))=tree; | ||
+ | numbertrees=numbertrees-1; % so that we are one step closer to finishing | ||
+ | end | ||
+ | end | ||
+ | end | ||
+ | end | ||
+ | |||
+ | % do custom stuff with this tree | ||
+ | % separation - remove all branches above a certain length | ||
+ | if separation==1 | ||
+ | separationmask=(branches(:,1))<=separationlength; | ||
+ | branches=branches(find(separationmask),:); | ||
+ | end | ||
+ | |||
+ | % pruning - remove wandering branches | ||
+ | if pruning==1 | ||
+ | degrees=[]; | ||
+ | for i=linspace(1,lengthinputpositions,lengthinputpositions) | ||
+ | degree=(sum((branches(:,2))==i))+(sum((branches(:,3))==i)); | ||
+ | degrees=[degrees;degree]; | ||
+ | end | ||
+ | |||
+ | while prunesteps>0 | ||
+ | protectednodes=index(find(degrees>2)); | ||
+ | |||
+ | tempprunelevel=prunelevel; | ||
+ | while tempprunelevel>0 | ||
+ | ends=index(find(degrees==1)); % find branch end nodes | ||
+ | for i=transpose(ends) | ||
+ | if sum(i==protectednodes)==0 | ||
+ | if (degrees(i))>0 | ||
+ | deletemask=((branches(:,2))==i)+((branches(:,3))==i); | ||
+ | cutbranch=branches(find(deletemask),:); | ||
+ | |||
+ | branches=branches(find(deletemask==0),:); | ||
+ | degrees(cutbranch(2))=(degrees(cutbranch(2)))-1; | ||
+ | degrees(cutbranch(3))=(degrees(cutbranch(3)))-1; | ||
+ | end | ||
+ | end | ||
+ | end | ||
+ | tempprunelevel=tempprunelevel-1; | ||
+ | end | ||
+ | prunesteps=prunesteps-1; | ||
+ | end | ||
+ | end | ||
+ | |||
+ | save('branches','branches') | ||
+ | |||
+ | % for plotting | ||
+ | sizebranches=size(branches); | ||
+ | numberofbranches=sizebranches(1); | ||
+ | |||
+ | figure | ||
+ | hold on | ||
+ | box on | ||
+ | if dimensions==2 | ||
+ | plot(inputpositions(:,1),inputpositions(:,2),'k.') | ||
+ | end | ||
+ | if dimensions==3 | ||
+ | plot3(inputpositions(:,1),inputpositions(:,2),inputpositions(:,3),'k.') | ||
+ | end | ||
+ | |||
+ | for i=linspace(1,numberofbranches,numberofbranches) | ||
+ | if dimensions==2 | ||
+ | startindex=branches(i,2); | ||
+ | finishindex=branches(i,3); | ||
+ | |||
+ | startx=inputpositions(startindex,1); | ||
+ | starty=inputpositions(startindex,2); | ||
+ | |||
+ | finishx=inputpositions(finishindex,1); | ||
+ | finishy=inputpositions(finishindex,2); | ||
+ | |||
+ | line([startx;finishx],[starty;finishy],'Color','k') | ||
+ | end | ||
+ | if dimensions==3 | ||
+ | startindex=branches(i,2); | ||
+ | finishindex=branches(i,3); | ||
+ | |||
+ | startx=inputpositions(startindex,1); | ||
+ | starty=inputpositions(startindex,2); | ||
+ | startz=inputpositions(startindex,3); | ||
+ | |||
+ | finishx=inputpositions(finishindex,1); | ||
+ | finishy=inputpositions(finishindex,2); | ||
+ | finishz=inputpositions(finishindex,3); | ||
+ | |||
+ | line([startx;finishx],[starty;finishy],[startz;finishz],'Color','k') | ||
+ | end | ||
+ | end | ||
+ | ==Jarnik/Prim's Algorithm== | ||
Also downloadable [http://www.physics.usyd.edu.au/~asmith/files/sc1/MST_JarnikPrim.m here] | Also downloadable [http://www.physics.usyd.edu.au/~asmith/files/sc1/MST_JarnikPrim.m here] | ||
% minimal spannng tree in matlab | % minimal spannng tree in matlab |
Revision as of 14:49, 14 February 2010
I originally coded up Jarnik/Prim's algorithm. In the process of optimising it, I unwittingly reinvented Boruvka's algorithm, which handles large numbers of input points better, at least the way I've done it.
Boruvka's Algorithm
Also downloadable here
% minimal spannng tree in matlab % Boruvka's algorithm (independently invented by yours truly) % see http://www.star-control.com/forum/index.php/topic,1660 % by Anthony Smith (Zeracles) % astroant@hotmail.com % if only after an MST, leave separation=pruning=0 load('inputpositions') localcount=8; separation=0; separationlength=0.03; pruning=0; prunesteps=1; % how many times to have a go at the tree prunelevel=10; % length of branch to cut each time % detect input properties and set up index sizeinputpositions=size(inputpositions); lengthinputpositions=sizeinputpositions(1); dimensions=sizeinputpositions(2); index=transpose(linspace(1,lengthinputpositions,lengthinputpositions)); inputpositionxs=inputpositions(:,1); inputpositionys=inputpositions(:,2); if dimensions>2 inputpositionzs=inputpositions(:,3); end % initialise search parameters minx=min(inputpositionxs); maxx=max(inputpositionxs); xextent=minx*maxx; miny=min(inputpositionys); maxy=max(inputpositionys); yextent=miny*maxy; if dimensions>2 minz=min(inputpositionzs); maxz=max(inputpositionzs); zextent=minz*maxz; end if dimensions==2 measure=xextent*yextent; localmeasure=measure/lengthinputpositions; searchincrement=((localcount*localmeasure)/pi)^(1/2); end if dimensions==3 measure=xextent*yextent*zextent; localmeasure=measure/lengthinputpositions; searchincrement=((localcount*localmeasure)/(4/3)/pi)^(1/3); end treenumber=index; numbertrees=length(unique(treenumber)); branches=[]; searchfactor=1; % setting this to zero can lead to infinite loop if this is scaled multiplicatively searchfactors=zeros(lengthinputpositions,1); while numbertrees>1 % each input point is treated as a separate tree, and we join them together until we only have one tree searchfactor=2*searchfactor; % calculate interpoint distances for ``close" points, with ``close" defined by this variable while min(searchfactors)<searchfactor % searchfactors stores the searchfactors searched for each existing tree tree=treenumber(min(find(searchfactors<(searchfactor)))); % choose a tree to search which has been searched with the smallest distance so far treesearched=0; while treesearched==0 % while we're not yet done looking around the nodes of this tree for links maskvector=treenumber==tree; treeindices=find(maskvector); lengthtreepositions=sum(maskvector); remainingpositionxs=inputpositionxs(find(maskvector==0)); remainingpositionys=inputpositionys(find(maskvector==0)); if dimensions>2 remainingpositionzs=inputpositionzs(find(maskvector==0)); end remainingpositionindices=index(find(maskvector==0)); mindistances=[]; for i=linspace(1,lengthtreepositions,lengthtreepositions) % search around each of the tree positions for remainingpositions % retrieve coordinates of a tree position treepositionx=inputpositions(treeindices(i),1); treepositiony=inputpositions(treeindices(i),2); if dimensions>2 treepositionz=inputpositions(treeindices(i),3); end treeindex=treeindices(i); % search for remainingpositions boxradius=searchfactor*searchincrement; boxminx=treepositionx-boxradius; boxmaxx=treepositionx+boxradius; boxminy=treepositiony-boxradius; boxmaxy=treepositiony+boxradius; if dimensions>2 boxminz=treepositionz-boxradius; boxmaxz=treepositionz+boxradius; end if dimensions==2 closerremainingmask=(boxminx<=remainingpositionxs).*(remainingpositionxs<=boxmaxx).*(boxminy<=remainingpositionys).*(remainingpositionys<=boxmaxy); end if dimensions==3 closerremainingmask=(boxminx<=remainingpositionxs).*(remainingpositionxs<=boxmaxx).*(boxminy<=remainingpositionys).*(remainingpositionys<=boxmaxy).*(boxminz<=remainingpositionzs).*(remainingpositionzs<=boxmaxz); end mindistancecandidates=[]; mindistancecandidateindices=[]; if sum(closerremainingmask)>0 % if there are remainingpositions inside the box, calculate the actual distances to them for k=transpose(find(closerremainingmask==1)); branchcandidatex=remainingpositionxs(k); branchcandidatey=remainingpositionys(k); if dimensions>2 branchcandidatez=remainingpositionzs(k); end branchcandidateindex=remainingpositionindices(k); % set up to remember the index of each prospective link destination if dimensions==2 mindistancecandidate=((branchcandidatex-treepositionx).^2+(branchcandidatey-treepositiony).^2).^(1/2); end if dimensions==3 mindistancecandidate=((branchcandidatex-treepositionx).^2+(branchcandidatey-treepositiony).^2+(branchcandidatez-treepositionz).^2).^(1/2); end if mindistancecandidate<=boxradius mindistancecandidates=[mindistancecandidates;mindistancecandidate]; mindistancecandidateindices=[mindistancecandidateindices;branchcandidateindex]; end end end if numel(mindistancecandidates)>0 % minimum distance from this position on the tree mindistance=[min(mindistancecandidates),treeindex,mindistancecandidateindices(find(mindistancecandidates==min(mindistancecandidates)))]; % minimum distances carry the indices of the prospective link destination mindistances=[mindistances;mindistance]; end end if numel(mindistances)==0 searchfactors(maskvector)=searchfactor; treesearched=1; end if numel(mindistances)>0 branchdistance=min(mindistances(:,1)); branchindex=find(branchdistance==mindistances(:,1)); numberbranchcandidates=numel(branchindex); if numberbranchcandidates>1 % if there's a tie for minimum length branchindex=branchindex(ceil(numberbranchcandidates*rand(1))); end % add this branch to the tree branch=mindistances(branchindex,:); branches=[branches;branch]; % join the two trees together targettree=treenumber(branch(3)); % need to update the treenumber variable, which remembers which points belong to which trees treenumber(find(treenumber==targettree))=tree; numbertrees=numbertrees-1; % so that we are one step closer to finishing end end end end % do custom stuff with this tree % separation - remove all branches above a certain length if separation==1 separationmask=(branches(:,1))<=separationlength; branches=branches(find(separationmask),:); end % pruning - remove wandering branches if pruning==1 degrees=[]; for i=linspace(1,lengthinputpositions,lengthinputpositions) degree=(sum((branches(:,2))==i))+(sum((branches(:,3))==i)); degrees=[degrees;degree]; end while prunesteps>0 protectednodes=index(find(degrees>2)); tempprunelevel=prunelevel; while tempprunelevel>0 ends=index(find(degrees==1)); % find branch end nodes for i=transpose(ends) if sum(i==protectednodes)==0 if (degrees(i))>0 deletemask=((branches(:,2))==i)+((branches(:,3))==i); cutbranch=branches(find(deletemask),:); branches=branches(find(deletemask==0),:); degrees(cutbranch(2))=(degrees(cutbranch(2)))-1; degrees(cutbranch(3))=(degrees(cutbranch(3)))-1; end end end tempprunelevel=tempprunelevel-1; end prunesteps=prunesteps-1; end end save('branches','branches') % for plotting sizebranches=size(branches); numberofbranches=sizebranches(1); figure hold on box on if dimensions==2 plot(inputpositions(:,1),inputpositions(:,2),'k.') end if dimensions==3 plot3(inputpositions(:,1),inputpositions(:,2),inputpositions(:,3),'k.') end for i=linspace(1,numberofbranches,numberofbranches) if dimensions==2 startindex=branches(i,2); finishindex=branches(i,3); startx=inputpositions(startindex,1); starty=inputpositions(startindex,2); finishx=inputpositions(finishindex,1); finishy=inputpositions(finishindex,2); line([startx;finishx],[starty;finishy],'Color','k') end if dimensions==3 startindex=branches(i,2); finishindex=branches(i,3); startx=inputpositions(startindex,1); starty=inputpositions(startindex,2); startz=inputpositions(startindex,3); finishx=inputpositions(finishindex,1); finishy=inputpositions(finishindex,2); finishz=inputpositions(finishindex,3); line([startx;finishx],[starty;finishy],[startz;finishz],'Color','k') end end
Jarnik/Prim's Algorithm
Also downloadable here
% minimal spannng tree in matlab % Jarnik/Prim's algorithm - runs pretty slowly for any more than 50 input points % see http://www.star-control.com/forum/index.php/topic,1660.msg33938.html#msg33938 % by Anthony Smith (Zeracles) % astroant@hotmail.com load('inputpositions') remainingpositions=inputpositions; % detect input properties and set up index sizeremainingpositions=size(remainingpositions); lengthremainingpositions=sizeremainingpositions(1); dimensions=sizeremainingpositions(2); index=transpose(linspace(1,lengthremainingpositions,lengthremainingpositions)); remainingpositionxs=remainingpositions(:,1); remainingpositionys=remainingpositions(:,2); if dimensions>2 remainingpositionzs=remainingpositions(:,3); end % initialise search parameters minx=min(remainingpositionxs); maxx=max(remainingpositionxs); xextent=minx*maxx; miny=min(remainingpositionys); maxy=max(remainingpositionys); yextent=miny*maxy; if dimensions>2 minz=min(remainingpositionzs); maxz=max(remainingpositionzs); zextent=minz*maxz; end if dimensions==2 measure=xextent*yextent; localmeasure=measure/lengthremainingpositions; searchincrement=((10*localmeasure)/pi)^(1/2); end if dimensions==3 measure=xextent*yextent*zextent; localmeasure=measure/lengthremainingpositions; searchincrement=((10*localmeasure)/(4/3)/pi)^(1/3); end % initialise with a seed point seedindex=1; maskvector=zeros(lengthremainingpositions,1); maskvector(seedindex)=1; remainingpositionxs=remainingpositionxs(find(maskvector==0)); remainingpositionys=remainingpositionys(find(maskvector==0)); if dimensions>2 remainingpositionzs=remainingpositionzs(find(maskvector==0)); end remainingpositionindices=index(find(maskvector==0)); lengthremainingpositions=lengthremainingpositions-1; treeindices=index(seedindex,:); lengthtreepositions=1; branches=[]; while lengthremainingpositions>0 % keep going until nothing remains unlinked to the tree (the ``remainingpositions") mindistances=[]; for i=linspace(1,lengthtreepositions,lengthtreepositions) % search around each of the tree positions for remainingpositions % retrieve coordinates of a tree position treepositionx=inputpositions(treeindices(i),1); treepositiony=inputpositions(treeindices(i),2); if dimensions>2 treepositionz=inputpositions(treeindices(i),3); end treeindex=treeindices(i); occupiedbox=0; searchfactor=1; while occupiedbox==0 % search for remainingpositions inside a box that grows until some are found boxradius=searchfactor*searchincrement; boxminx=treepositionx-boxradius; boxmaxx=treepositionx+boxradius; boxminy=treepositiony-boxradius; boxmaxy=treepositiony+boxradius; if dimensions>2 boxminz=treepositionz-boxradius; boxmaxz=treepositionz+boxradius; end if dimensions==2 closerremainingmask=(boxminx<=remainingpositionxs).*(remainingpositionxs<=boxmaxx).*(boxminy<=remainingpositionys).*(remainingpositionys<=boxmaxy); end if dimensions==3 closerremainingmask=(boxminx<=remainingpositionxs).*(remainingpositionxs<=boxmaxx).*(boxminy<=remainingpositionys).*(remainingpositionys<=boxmaxy).*(boxminz<=remainingpositionzs).*(remainingpositionzs<=boxmaxz); end mindistancecandidates=[]; mindistancecandidateindices=[]; if sum(closerremainingmask)>0 % if there are remainingpositions inside the box, calculate the actual distances to them for k=find(closerremainingmask==1) branchcandidatex=remainingpositionxs(k); branchcandidatey=remainingpositionys(k); if dimensions>2 branchcandidatez=remainingpositionzs(k); end branchcandidateindex=remainingpositionindices(k); % set up to remember the index of each prospective link destination if dimensions==2 mindistancecandidate=((branchcandidatex-treepositionx).^2+(branchcandidatey-treepositiony).^2).^(1/2); end if dimensions==3 mindistancecandidate=((branchcandidatex-treepositionx).^2+(branchcandidatey-treepositiony).^2+(branchcandidatez-treepositionz).^2).^(1/2); end if mindistancecandidate<=boxradius mindistancecandidates=[mindistancecandidates;mindistancecandidate]; mindistancecandidateindices=[mindistancecandidateindices;branchcandidateindex]; end end end if numel(mindistancecandidates)>0 mindistance=[min(mindistancecandidates),treeindex,mindistancecandidateindices(find(mindistancecandidates==min(mindistancecandidates)))]; % minimum distances carry the indices of the prospective link destination mindistances=[mindistances;mindistance]; occupiedbox=1; end searchfactor=searchfactor+1; % make the search box bigger end end branchdistance=min(mindistances(:,1)); branchindex=find(branchdistance==mindistances(:,1)); numberbranchcandidates=numel(branchindex); if numberbranchcandidates>1 % if there's a tie for minimum length branchindex=branchindex(ceil(numberbranchcandidates*rand(1))); end % add this branch to the tree branch=mindistances(branchindex,:); branches=[branches;branch]; % add that location to the tree treeindices=[treeindices;branch(3)]; lengthtreepositions=lengthtreepositions+1; % remove that location from the remainingpositions remainingmask=ones(lengthremainingpositions,1); removed=find(remainingpositionindices==branch(3)); remainingmask(removed)=0; remainingpositionindices=remainingpositionindices(find(remainingmask)); remainingpositionxs=remainingpositionxs(find(remainingmask)); remainingpositionys=remainingpositionys(find(remainingmask)); if dimensions>2 remainingpositionzs=remainingpositionzs(find(remainingmask)); end lengthremainingpositions=lengthremainingpositions-1; end save('branches','branches') % for plotting sizebranches=size(branches); numberofbranches=sizebranches(1); figure hold on box on plot(inputpositions(:,1),inputpositions(:,2),'k.') for i=linspace(1,numberofbranches,numberofbranches) startindex=branches(i,2); finishindex=branches(i,3); startx=inputpositions(startindex,1); starty=inputpositions(startindex,2); finishx=inputpositions(finishindex,1); finishy=inputpositions(finishindex,2); line([startx;finishx],[starty;finishy],'Color','k') end