%Generates a simple, bipartite, 3-regular graphs, then swaps 2 edges (see Richter's paper),
%calculates and stores the second largest eigenvalue if it isn't 3, and walkSteps times.
clear all;close all;pack;
tic
E=0;
EigenTwo=0;
k=3;
options.disp=0;%This makes the 'eigs' function not display the iterations converging to the eigenvalu
EdgeFlipsPerStep=1;
walkSteps=10000;%Number of eigenvalues to be collected
nVec=[100 125 158 199 251 316 398 501 630 794 1000];%These are the sizes of ONE HALF of the graphs
for c=1:length(nVec)
   %This loop runs over graphs sizes 
   n=nVec(c);
   A=spalloc(n,n,3*n); 
   while(max(max(A))~=1)%Continues until SIMPLE graphs is found
         %This loop uses Bollobas' configuration model algorithm to generate k-regular graphs.  
         %For a good description see section 2 in N.C. Wormald's Models of Random Regular Graphs
         %This is just for the FIRST graph.  After this one, edge-swapping is used.
      Pairs=[randperm(n*k); randperm(n*k)+n];
      A=spalloc(2*n,2*n,3*n);  
      for i=1:(n*k)
         m1= mod(Pairs(1,i),n)+1;
         m2= mod(Pairs(2,i),n)+n+1;         
         A(m1,m2) =  A(m1,m2) + 1;
         A(m2,m1) =  A(m2,m1) + 1;
      end
   end
   Edges=A(1:n, n+1:2*n);
   for w = 1:walkSteps
      EdgesOld = Edges; %Stores the info for the last adjacency matrix, so that if a graph that is not
      %connected is formed, we can revert back to the last one.
      for x=1:EdgeFlipsPerStep
         [i,j] = find(Edges);
         r1 = ceil(length(i)*rand);
         r2 = ceil(length(j)*rand);
         E1i = i(r1); E1j = j(r1);
         E2i = i(r2); E2j = j(r2);         
         while( Edges(E2i, E1j)==1 | Edges(E1i, E2j)==1)
         %Loop continues until 2 edges that satisfy Richter's swapping conditions are found
            r1 = ceil(length(i)*rand);
            r2 = ceil(length(j)*rand);
            E1i = i(r1); E1j = j(r1);
            E2i = i(r2); E2j = j(r2);         
         end
         Edges(E1i, E1j)=0; Edges(E2i, E2j)=0;
         Edges(E1i, E2j)=1; Edges(E2i, E1j)=1;
      end
      A=[spalloc(n,n,3*n) Edges; Edges' spalloc(n,n,3*n)];   
      E=sort(eigs(A,2,'LA', options));%Sorted Eigenvalues of A (This line takes bulk of running-time)
      ZeroIfConnected =E(1)==E(2);   
      if(ZeroIfConnected==0)%True if A represents a CONNECTED graph
         EigenTwo(c,w)=E(1);
      else
         Edges=EdgesOld;
         w=w-1;
         %Theoretically, this line makes an infinite loop possible. However, this wasn't a problem.
      end   
      if(mod(w,100)==0)
         save motherAuto2 EigenTwo walkSteps n A%Saves data every 100 eigenvalues
      end
   end
end
RunTime=toc;
save motherAuto2 EigenTwo walkSteps nVec RunTime A