# include/net/algorithm.hpp

# Namespaces

Name
net

# Source code

#ifndef NET_ALGORITHM_HPP
#define NET_ALGORITHM_HPP

#include "network.hpp"
#include <vector>
#include <set>
#include <memory>
#include <random>
#include <utility>
#include <iterator>
#include <valarray>
#include <iostream>

namespace net{

   bool is_connected(const int & N, const std::set<std::pair<int,int>> & edge){ // check if a graph is connected
      std::vector<std::shared_ptr<std::set<int>>> connected_componets(N);
      for(int i=0;i<N;++i)
         connected_componets[i]=std::make_shared<std::set<int>>(std::set<int>{i});
      for(auto & e:edge){
         //std::cout<<"   ---"<<e.first<<' '<<e.second<<'\n';
         if(connected_componets[e.first]!=connected_componets[e.second]){
            connected_componets[e.first]->insert(connected_componets[e.second]->begin(),connected_componets[e.second]->end());
            connected_componets[e.second]=connected_componets[e.first];
         }
      }
      //std::cout<<connected_componets[0]->size()<<' '<<N<<'\n';
      return (connected_componets[0]->size()==N);
   }

   std::set<std::pair<int,int>> random_edges(const int & N, const int & d, std::default_random_engine & R){
   // reference: Generating random regular graphs quickly, A. STEGER and N. C. WORMALD
   // reference: Efficient and Simple Generation of Random Simple Connected Graphs with Prescribed Degree Sequence, Fabien Viger and Matthieu Latapy

      std::valarray<int> avail(N);
      auto distribution = std::uniform_real_distribution<double>(0., 1.);
      std::set<std::pair<int,int>> edges;
      int tot_avail;
      int ind1,ind2,site1,site2;
      bool found;
      do{
         tot_avail=N*d;
         for(int i=0;i<N;++i)
            avail[i]=d;
         edges.clear();

         for(int i=0;i<N;++i){
            edges.insert({i,(i+1)%N});
            avail[i]--;
            avail[(i+1)%N]--;
            tot_avail-=2;
         }
         found = true;
         while(tot_avail>0){
            //std::cout<<tot_avail<<'\n';
            if(!found){ // if there's no available edge, delete d edges
               for(int i=0;i<d;++i){
                  if(edges.size()>0){
                     auto it=edges.begin();
                     std::advance(it,int(edges.size()*distribution(R)));
                     avail[it->first]++;
                     avail[it->second]++;
                     edges.erase(it);
                     tot_avail+=2;
                  }
               }
               // for(auto s:avail)
               //    std::cout<<s<<' ';
               // std::cout<<std::endl;
            }

            found = false;
            for(int i=0;i<1000;i++){
               ind1=tot_avail*distribution(R);
               ind2=tot_avail*distribution(R);
               //std::cout<<' '<<ind1<<' '<<ind2<<' '<<tot_avail<<'\n';
               site1=-1;
               for(int site_cumu=-1;site_cumu<ind1;site_cumu+=avail[++site1]){
                  //std::cout<<' '<<site1<<' '<<avail[site1]<<site_cumu<<'\n';
               }
               //std::cout<<' '<<site1<<'\n';
               site2=-1;
               for(int site_cumu=-1;site_cumu<ind2;site_cumu+=avail[++site2]);
               //std::cout<<' '<<site1<<' '<<site2<<'\n';
               if(site1 != site2 && edges.count({site1,site2})==0 && edges.count({site2,site1}) ==0){
                                           // avoid double edge and loop on one site
                  found=true;
                  edges.insert({site1,site2});
                  avail[site1]--;
                  avail[site2]--;
                  //std::cout<<site1<<' '<<site2<<' '<<N<<'\n';
                  tot_avail-=2;
                  break;
               }
            } 
         }
      }while(!is_connected(N,edges)); // do until the network is connected

      int pos1,pos2,sf1,sf2,sf3,sf4; // shuffle edges
      std::pair<int,int> edge1,edge2;
      for(int i=0;i<2000;i++){
         //std::cout<< i<<'\n';
         do{
            pos1=N*d/2*distribution(R);
            pos2=(N*d/2-1)*distribution(R);
            if(pos2==pos1) pos2++;

            auto it=edges.begin();
            std::advance(it,pos1);
            edge1=*it;
            it=edges.begin();
            std::advance(it,pos2);
            edge2=*it;

            sf1=edge1.first;
            sf2=edge1.second;
            if(distribution(R)<0.5){
               sf3=edge2.first;
               sf4=edge2.second;
            }else{
               sf3=edge2.second;
               sf4=edge2.first;
            }
            // delete sf1-sf2 and sf3-sf4, add sf1-sf3 and sf2-sf4
         }while(sf1==sf3 || sf2==sf4 || edges.count({sf1,sf3})>0 || edges.count({sf3,sf1})>0
          || edges.count({sf2,sf4})>0 || edges.count({sf4,sf2})>0);
         edges.erase(edge1);
         edges.erase(edge2);
         edges.insert({sf1,sf3});
         edges.insert({sf2,sf4});
         if(!is_connected(N,edges)){
            edges.insert(edge1);
            edges.insert(edge2);
            edges.erase({sf1,sf3});
            edges.erase({sf2,sf4}); 
         }
      }

      return edges;
   }

   template<typename NetType>
   void generate_random_regular_network(NetType & N, const int & d, std::default_random_engine & R){

      auto edges = random_edges(N.size(),d,R);
      std::vector<typename NetType::NodeKeyType> keys;
      for(auto & s:N)
         keys.push_back(s.first);
      for(auto & e:edges){
         //std::cout<<e.first<<' '<<e.second<<'\n';
         N.add_edge(keys[e.first],keys[e.second]);
      }
   }

}
#endif

Updated on 15 June 2022 at 16:04:19 CST