# include/net/network.hpp

# Namespaces

Name
net

# Classes

Name
struct net::no_absorb
class net::network
网络包含格点和格点上的半边,两个半边可以相连接

# Source code

#ifndef NETWORK_H
#define NETWORK_H

#include "error.hpp"
#include "node.hpp"
#include "tensor_tools.hpp"
#include "traits.hpp"
#include "tree.hpp"
#include <cstdlib>
#include <functional>
#include <initializer_list>
#include <iostream>
#include <map>
#include <set>
#include <memory>
#include <stdexcept>
#include <vector>

namespace net {

   struct no_absorb {
      template <typename NodeVal, typename EdgeVal, typename EdgeKey>
      NodeVal operator()(const NodeVal & ten1, const EdgeVal & ten2, const EdgeKey & ind) const {
         return ten1;
      }
   };

   template <typename NodeVal, typename EdgeVal, typename NodeKey, typename EdgeKey>
   struct default_traits;
   template <
         typename NodeVal,
         typename EdgeVal,
         typename NodeKey = std::string,
         typename EdgeKey = stdEdgeKey,
         typename Trait = default_traits<NodeVal, EdgeVal, NodeKey, EdgeKey>>
   class network : public std::map<NodeKey, node<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>, typename Trait::nodekey_less> {
      template <typename NodeVal1, typename EdgeVal1, typename NodeKey1, typename EdgeKey1, typename Trait1>
      friend std::ostream & operator<<(std::ostream &, const network<NodeVal1, EdgeVal1, NodeKey1, EdgeKey1, Trait1> &);

      template <typename NodeVal1, typename EdgeVal1, typename NodeKey1, typename EdgeKey1, typename Trait1>
      friend std::istream & operator>>(std::istream &, network<NodeVal1, EdgeVal1, NodeKey1, EdgeKey1, Trait1> &);

      template <typename NodeVal1, typename EdgeVal1, typename NodeKey1, typename EdgeKey1, typename Trait1>
      friend std::ostream & operator<(std::ostream &, const network<NodeVal1, EdgeVal1, NodeKey1, EdgeKey1, Trait1> &);

      template <typename NodeVal1, typename EdgeVal1, typename NodeKey1, typename EdgeKey1, typename Trait1>
      friend std::istream & operator>(std::istream &, network<NodeVal1, EdgeVal1, NodeKey1, EdgeKey1, Trait1> &);

   public:
      // constructor
      network() = default;
      // copy constructor
      network(const network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait> &);
      // copy assignment
      network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait> & operator=(const network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait> &);
      // move constructor
      network(network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait> &&) = default;
      // move assignment
      network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait> & operator=(network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait> &&) = default;
      // destructor
      //~network();

      using IterNode = typename network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::iterator;

      using NodeType = node<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>;
      using NodeKeyType = NodeKey;
      using NodeKeySetType = std::set<NodeKey, typename Trait::nodekey_less>;
      using NodeValType = NodeVal;
      using EdgeKeyType = EdgeKey;
      using EdgeValType = EdgeVal;
      using TraitType = Trait;

      IterNode add(const NodeKey &);

      void add(const network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait> &);

      void add_edge(const NodeKey &, const NodeKey &, const EdgeKey &, const EdgeKey &, const EdgeVal & = EdgeVal());
      void add_edge(IterNode, IterNode, const EdgeKey &, const EdgeKey &, const EdgeVal & = EdgeVal());

      void add_edge(const NodeKey &, const NodeKey &, const EdgeVal & = EdgeVal());
      void add_edge(IterNode, IterNode, const EdgeVal & = EdgeVal());


      void connect_edge(const NodeKey &, const NodeKey &, const EdgeKey &, const EdgeKey &);
      void connect_edge(IterNode, IterNode, const EdgeKey &, const EdgeKey &);

      void add_half_edge(const NodeKey &, const EdgeKey &, const EdgeVal & = EdgeVal());
      void add_half_edge(IterNode, const EdgeKey &, const EdgeVal & = EdgeVal());

      void del(const NodeKey &);
      void del(IterNode);
      void del_edges(const NodeKey &, const NodeKey &);
      void del_edges(IterNode, IterNode);

      void del_edge(const NodeKey &, const EdgeKey &);
      void del_edge(IterNode, const EdgeKey &);

      void del_half_edge(const NodeKey &, const EdgeKey &);
      void del_half_edge(IterNode, const EdgeKey &);

      void break_edge(const NodeKey &, const EdgeKey &);
      void break_edge(IterNode, const EdgeKey &);

      IterNode rename(const NodeKey &, const NodeKey &);
      IterNode rename(const IterNode &, const NodeKey &);

      int edge_num(const NodeKey &);
      int edge_num(const IterNode &);

      template <typename absorb_type, typename contract_type>
      void absorb(const NodeKey &, const NodeKey &, const absorb_type &, const contract_type &);
      template <typename absorb_type, typename contract_type>
      void absorb(IterNode, IterNode, const absorb_type &, const contract_type &);

      template <typename split_type>
      void
      split(const NodeKey &,
            const NodeKey &,
            const NodeKey &,
            const std::unordered_set<EdgeKey> &,
            const EdgeKey &,
            const EdgeKey &,
            const split_type &);

      template <typename split_type>
      std::pair<IterNode, IterNode>
      split(IterNode,
            const NodeKey &,
            const NodeKey &,
            const std::unordered_set<EdgeKey> &,
            const EdgeKey &,
            const EdgeKey &,
            const split_type &);

      template <typename split_type>
      void
      split(const NodeKey &,
            const NodeKey &,
            const std::unordered_set<EdgeKey> &,
            const EdgeKey &,
            const EdgeKey &,
            const split_type &);

      template <typename split_type>
      IterNode
      split(IterNode, const NodeKey &, const std::unordered_set<EdgeKey> &, const EdgeKey &, const EdgeKey &, const split_type &);
#ifdef NET_GRAPH_VIZ
      void draw_to_file(const std::string &, const std::string &, const bool) const;
      void draw_to_file(const std::string &, const std::string &, const std::vector<std::set<NodeKey, typename Trait::nodekey_less>> &, const bool) const;
      void draw(const std::string &, const bool) const;
      void draw(const std::string &, const std::vector<std::set<NodeKey, typename Trait::nodekey_less>> &, const bool) const;
#endif
      std::string gviz(const std::string &, const std::vector<std::set<NodeKey, typename Trait::nodekey_less>> &, const bool) const;

      std::string gviz_legend(const std::vector<std::set<NodeKey, typename Trait::nodekey_less>> &) const;
      bool contains(const NodeKey &);

      bool consistency(std::ostream & diagnosis = std::cout) const;

      template <typename absorb_type, typename contract_type>
      NodeVal contract(const absorb_type &, const contract_type &) const;

      template <typename absorb_type, typename contract_type>
      NodeVal contract(std::set<NodeKey, typename Trait::nodekey_less>, const absorb_type &, const contract_type &) const;

      template <typename TreeType, typename absorb_type, typename contract_type>
      NodeVal contract_tree(std::shared_ptr<TreeType>, const absorb_type &, const contract_type &) const;


      template <typename absorb_type, typename contract_type>
      NodeKey absorb(std::set<NodeKey, typename Trait::nodekey_less>, const absorb_type &, const contract_type &);

      template <typename TreeType, typename absorb_type, typename contract_type>
      NodeKey absorb_tree(std::shared_ptr<TreeType>, const absorb_type &, const contract_type &);

      template <typename absorb_type, typename contract_type>
      void
      tn_contract1(const NodeKey &, const std::set<NodeKey, typename Trait::nodekey_less> &, NodeVal &, const absorb_type &, const contract_type &)
            const;
      template <typename absorb_type, typename contract_type>
      void
      tn_contract1(IterNode, const std::set<NodeKey, typename Trait::nodekey_less> &, NodeVal &, const absorb_type &, const contract_type &) const;


      template <typename absorb_type, typename contract_type>
      NodeVal tn_contract2(
            const std::set<NodeKey, typename Trait::nodekey_less> &,
            const NodeVal &,
            const std::set<NodeKey, typename Trait::nodekey_less> &,
            const NodeVal &,
            const absorb_type &,
            const contract_type &) const;


      template <typename NetType2>
      NetType2
      fmap(std::function<typename NetType2::NodeValType(const NodeVal &)> f1,
           std::function<typename NetType2::EdgeValType(const EdgeVal &)> f2) const;

      template <typename NetType2>
      NetType2
      fmap(std::function<typename NetType2::NodeValType(const NodeVal &)> f1,
           std::function<typename NetType2::EdgeValType(const EdgeVal &)> f2,
           std::function<typename NetType2::NodeKeyType(const NodeKey &)> f3,
           std::function<typename NetType2::EdgeKeyType(const EdgeKey &)> f4) const;

      template <typename NodeVal2, typename EdgeVal2, typename Trait2>
      network<NodeVal2, EdgeVal2, NodeKey, EdgeKey, Trait2>
      gfmap(std::function<NodeVal2(const node<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait> &)> f1,
         std::function<EdgeVal2(const node<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait> &,const EdgeKey &)> f2) const;

      void fope(std::function<NodeVal(const NodeVal &)>, std::function<EdgeVal(const EdgeVal &)>);

      void gfope(std::function<NodeVal(const node<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait> &)> f1,
         std::function<EdgeVal(const node<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait> &,const EdgeKey &)> f2);
   };

   template <typename T>
   std::string to_string(const T & m) {
      std::stringstream a;
      a << m;
      return a.str();
   }

   template <typename NodeVal, typename EdgeVal, typename NodeKey, typename EdgeKey, typename Trait>
   // this is not default because [i].edges[j].neighbor needs redirection
   network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::network(const network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait> & N) {
      std::map<NodeKey, node<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>, typename Trait::nodekey_less>::operator=(N);
      for (auto & s : *this)
         s.second.relink(*this);
   }

   template <typename NodeVal, typename EdgeVal, typename NodeKey, typename EdgeKey, typename Trait>
   // this is not default because [i].edges[j].neighbor needs redirection
   network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait> &
   network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::operator=(const network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait> & N) {
      if (this != &N) {
         std::map<NodeKey, node<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>, typename Trait::nodekey_less>::operator=(N);
         for (auto & s : *this)
            s.second.relink(*this);
      }
      return *this;
   }

   // valid for c++17

   template <typename NodeVal, typename EdgeVal, typename NodeKey, typename EdgeKey, typename Trait>
   bool network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::contains(const NodeKey & nodekey) {
      return (this->count(nodekey) == 1);
   }

   template <typename NodeVal, typename EdgeVal, typename NodeKey, typename EdgeKey, typename Trait>
   typename network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::IterNode
   network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::add(const NodeKey & nodekey) {
      auto [s1, succ1] = this->insert(make_pair(nodekey, node<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>(nodekey)));
      if (!succ1) {
         throw key_exist_error("In network.add, node " + to_string(nodekey) + " already exists!");
      }
      return s1;
   }

   template <typename NodeVal, typename EdgeVal, typename NodeKey, typename EdgeKey, typename Trait>
   void network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::add(const network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait> & n) {
      for (auto & s : n)
         add(s.first)->second = s.second;
      for (auto & s : *this)
         s.second.relink(*this);
   }
   template <typename NodeVal, typename EdgeVal, typename NodeKey, typename EdgeKey, typename Trait>
   void network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::del(const NodeKey & nodekey) {
      auto node_itr = this->find(nodekey);
      if (node_itr == this->end()) {
         throw key_unfound_error("In network.del, node " + to_string(nodekey) + " is not found!");
      }

      node_itr->second.delete_nbedge();
      this->erase(node_itr);
   }
   template <typename NodeVal, typename EdgeVal, typename NodeKey, typename EdgeKey, typename Trait>
   void network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::del(network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::IterNode it) {
      it->second.delete_nbedge();
      this->erase(it);
   }

   template <typename NodeVal, typename EdgeVal, typename NodeKey, typename EdgeKey, typename Trait>
   void network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::del_edges(const NodeKey & nodekey1, const NodeKey & nodekey2) {
      auto node_itr1 = this->find(nodekey1);
      if (node_itr1 == this->end()) {
         throw key_unfound_error("In network.del_edge, node " + to_string(nodekey1) + " is not found!");
      }

      if (this->count(nodekey2) == 0) {
         throw key_unfound_error("In network.del_edge, node " + to_string(nodekey2) + " is not found!");
      }

      node_itr1->second.delete_edge([&nodekey2](auto & egitr) { return egitr->second.nbkey == nodekey2; });
   }

   template <typename NodeVal, typename EdgeVal, typename NodeKey, typename EdgeKey, typename Trait>
   void network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::del_edges(
         network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::IterNode it1,
         network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::IterNode it2) {
      it1->second.delete_edge([&it2](auto & egitr) { return egitr->second.nbkey == it2->first; });
   }

   template <typename NodeVal, typename EdgeVal, typename NodeKey, typename EdgeKey, typename Trait>
   void network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::del_edge(const NodeKey & nodekey, const EdgeKey & ind) {
      auto node_itr = this->find(nodekey);
      if (node_itr == this->end()) {
         throw key_unfound_error("In network.del_leg, node " + to_string(nodekey) + " is not found!");
      }
      node_itr->second.delete_edge([&ind](auto & egitr) { return egitr->first == ind; });
   }

   template <typename NodeVal, typename EdgeVal, typename NodeKey, typename EdgeKey, typename Trait>
   void
   network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::del_edge(network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::IterNode it, const EdgeKey & ind) {
      it->second.delete_edge([&ind](auto & egitr) { return egitr->first == ind; });
   }

   template <typename NodeVal, typename EdgeVal, typename NodeKey, typename EdgeKey, typename Trait>
   void network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::del_half_edge(const NodeKey & nodekey, const EdgeKey & ind) {
      auto node_itr = this->find(nodekey);
      if (node_itr == this->end()) {
         throw key_unfound_error("In network.del_leg, node " + to_string(nodekey) + " is not found!");
      }
      node_itr->second.delete_half_edge([&ind](auto & egitr) { return egitr->first == ind; });
   }

   template <typename NodeVal, typename EdgeVal, typename NodeKey, typename EdgeKey, typename Trait>
   void
   network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::del_half_edge(network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::IterNode it, const EdgeKey & ind) {
      it->second.delete_half_edge([&ind](auto & egitr) { return egitr->first == ind; });
   }


   template <typename NodeVal, typename EdgeVal, typename NodeKey, typename EdgeKey, typename Trait>
   void network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::break_edge(const NodeKey & nodekey, const EdgeKey & ind) {
      auto node_itr = this->find(nodekey);
      if (node_itr == this->end()) {
         throw key_unfound_error("In network.del_leg, node " + to_string(nodekey) + " is not found!");
      }
      node_itr->second.break_edge([&ind](auto & egitr) { return egitr->first == ind; });
   }

   template <typename NodeVal, typename EdgeVal, typename NodeKey, typename EdgeKey, typename Trait>
   void
   network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::break_edge(network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::IterNode it, const EdgeKey & ind) {
      it->second.break_edge([&ind](auto & egitr) { return egitr->first == ind; });
   }
   template <typename NodeVal, typename EdgeVal, typename NodeKey, typename EdgeKey, typename Trait>
   typename network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::IterNode
   network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::rename(const NodeKey & old_key, const NodeKey & new_key) {
      auto node_handle = this->extract(old_key);
      if (node_handle.empty()) {
         throw key_unfound_error("In network.rename, node " + to_string(old_key) + " is not found!");
      }
      node_handle.key = new_key;

      auto status = this->insert(std::move(node_handle));
      if (!status.inserted)
         throw key_exist_error("In network.rename, node " + to_string(new_key) + " already exists!");
      status.position->second.reset_nbkey_of_nb(new_key);

      return status.position;
   }
   template <typename NodeVal, typename EdgeVal, typename NodeKey, typename EdgeKey, typename Trait>
   typename network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::IterNode network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::rename(
         const network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::IterNode & it,
         const NodeKey & new_key) {
      auto node_handle = this->extract(it);
      if (node_handle.empty()) {
         throw key_unfound_error("In network.rename, node " + to_string(it->first) + " is not found!");
      }
      node_handle.key = new_key;
      node_handle.value.key = new_key;

      auto status = this->insert(std::move(node_handle));
      if (!status.inserted)
         throw key_exist_error("In network.rename, node " + to_string(new_key) + " already exists!");
      status.position->second.reset_nbkey_of_nb(new_key);

      return status.position;
   }

   template <typename NodeVal, typename EdgeVal, typename NodeKey, typename EdgeKey, typename Trait>
   int network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::edge_num(const NodeKey & nk) {
      return (*this)[nk].edges.size();
   }

   template <typename NodeVal, typename EdgeVal, typename NodeKey, typename EdgeKey, typename Trait>
   int network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::edge_num(const network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::IterNode & it) {
      return it->second.edges.size();
   }

   template <typename NodeVal, typename EdgeVal, typename NodeKey, typename EdgeKey, typename Trait>
   void network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::add_half_edge(
         network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::IterNode it1,
         const EdgeKey & ind1,
         const EdgeVal & edgeval) {
      it1->second.add_half_edge(ind1,edgeval);
   }
   
   template <typename NodeVal, typename EdgeVal, typename NodeKey, typename EdgeKey, typename Trait>
   void network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::add_half_edge(
         const NodeKey & nodekey1,
         const EdgeKey & ind1,
         const EdgeVal & edgeval) {
      auto node_itr1 = this->find(nodekey1);
      if (node_itr1 == this->end()) {
         throw key_unfound_error("In network.add_half_edge, node " + to_string(nodekey1) + " is not found!");
      }
      node_itr1->second.add_half_edge(ind1,edgeval);
   }

   template <typename NodeVal, typename EdgeVal, typename NodeKey, typename EdgeKey, typename Trait>
   void network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::add_edge(
         const NodeKey & nodekey1,
         const NodeKey & nodekey2,
         const EdgeKey & ind1,
         const EdgeKey & ind2,
         const EdgeVal & edgeval) {
      auto node_itr1 = this->find(nodekey1);
      if (node_itr1 == this->end()) {
         throw key_unfound_error("In network.add_edge, node " + to_string(nodekey1) + " is not found!");
      }
      auto node_itr2 = this->find(nodekey2);
      if (node_itr2 == this->end()) {
         throw key_unfound_error("In network.add_edge, node " + to_string(nodekey2) + " is not found!");
      }

      add_edge_node(node_itr1,node_itr2,ind1,ind2,edgeval);
   }

   template <typename NodeVal, typename EdgeVal, typename NodeKey, typename EdgeKey, typename Trait>
   void network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::add_edge(
         network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::IterNode it1,
         network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::IterNode it2,
         const EdgeKey & ind1,
         const EdgeKey & ind2,
         const EdgeVal & edgeval) {
      add_edge_node(it1,it2,ind1,ind2,edgeval);
   }
   template <typename NodeVal, typename EdgeVal, typename NodeKey, typename EdgeKey, typename Trait>
   void network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::add_edge(const NodeKey & nodekey1, const NodeKey & nodekey2, const EdgeVal & edgeval) {
      add_edge(nodekey1, nodekey2, Trait::bind(nodekey1, nodekey2), Trait::bind(nodekey2, nodekey1), edgeval);
   }
   template <typename NodeVal, typename EdgeVal, typename NodeKey, typename EdgeKey, typename Trait>
   void network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::add_edge(
         network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::IterNode it1,
         network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::IterNode it2,
         const EdgeVal & edgeval) {
      add_edge(it1, it2, Trait::bind(it1->first, it2->first), Trait::bind(it2->first, it1->first), edgeval);
   }


   template <typename NodeVal, typename EdgeVal, typename NodeKey, typename EdgeKey, typename Trait>
   void network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::connect_edge(
         const NodeKey & nodekey1,
         const NodeKey & nodekey2,
         const EdgeKey & ind1,
         const EdgeKey & ind2) {
      auto node_itr1 = this->find(nodekey1);
      if (node_itr1 == this->end()) {
         throw key_unfound_error("In network.connect_edge, node " + to_string(nodekey1) + " is not found!");
      }
      auto node_itr2 = this->find(nodekey2);
      if (node_itr2 == this->end()) {
         throw key_unfound_error("In network.connect_edge, node " + to_string(nodekey2) + " is not found!");
      }

      connect_edge_node(node_itr1,node_itr2,ind1,ind2);
   }

   template <typename NodeVal, typename EdgeVal, typename NodeKey, typename EdgeKey, typename Trait>
   void network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::connect_edge(
         network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::IterNode it1,
         network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::IterNode it2,
         const EdgeKey & ind1,
         const EdgeKey & ind2) {
      connect_edge_node(it1,it2,ind1,ind2);
   }
   template <typename NodeVal, typename EdgeVal, typename NodeKey, typename EdgeKey, typename Trait>
   template <typename absorb_type, typename contract_type>
   void network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::absorb(
         const NodeKey & nodekey1,
         const NodeKey & nodekey2,
         const absorb_type & absorb_fun,
         const contract_type & contract_fun) {
      auto node_itr1 = this->find(nodekey1);
      if (node_itr1 == this->end()) {
         throw key_unfound_error("In network.absorb, node " + to_string(nodekey1) + " is not found!");
      }
      auto node_itr2 = this->find(nodekey2);
      if (node_itr2 == this->end()) {
         throw key_unfound_error("In network.absorb, node " + to_string(nodekey2) + " is not found!");
      }

      node_itr1->second.absorb_nb(nodekey2, node_itr2->second.val, absorb_fun, contract_fun);
      node_itr2->second.transfer_edge(node_itr1, [&node_itr1](auto & egitr) { return egitr->second.nbitr != node_itr1; });
      this->erase(node_itr2);
   }

   template <typename NodeVal, typename EdgeVal, typename NodeKey, typename EdgeKey, typename Trait>
   template <typename absorb_type, typename contract_type>
   void network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::absorb(
         network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::IterNode node_itr1,
         network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::IterNode node_itr2,
         const absorb_type & absorb_fun,
         const contract_type & contract_fun) {
      node_itr1->second.absorb_nb(node_itr2->first, node_itr2->second.val, absorb_fun, contract_fun);
      node_itr2->second.transfer_edge(node_itr1, [&node_itr1](auto & egitr) { return egitr->second.nbitr != node_itr1; });
      this->erase(node_itr2);
   }
   template <typename NodeVal, typename EdgeVal, typename NodeKey, typename EdgeKey, typename Trait>
   template <typename split_type>
   std::pair<
         typename network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::IterNode,
         typename network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::IterNode>
   network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::split(
         network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::IterNode s1,
         const NodeKey & nodekey2,
         const NodeKey & nodekey3,
         const std::unordered_set<EdgeKey> & inds,
         const EdgeKey & ind2,
         const EdgeKey & ind3,
         const split_type & split_fun) {
      auto s2 = add(nodekey2);
      auto s3 = add(nodekey3);

      s1->second.transfer_edge(s2, s3, [&inds](auto & egitr) { return inds.count(egitr->first) == 0; });

      EdgeVal env;
      split_fun(s1->second.val, s2->second.val, s3->second.val, inds, ind2, ind3, env);
      add_edge_node(s2,s3,ind2,ind3,env);
      this->erase(s1);
      return std::make_pair(s2, s3);
   }
   template <typename NodeVal, typename EdgeVal, typename NodeKey, typename EdgeKey, typename Trait>
   template <typename split_type>
   void network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::split(
         const NodeKey & nodekey1,
         const NodeKey & nodekey2,
         const NodeKey & nodekey3,
         const std::unordered_set<EdgeKey> & inds,
         const EdgeKey & ind2,
         const EdgeKey & ind3,
         const split_type & split_fun) {
      auto s1 = this->find(nodekey1);
      auto s2 = add(nodekey2);
      auto s3 = add(nodekey3);

      s1->second.transfer_edge(s2, s3, [&inds](auto & egitr) { return inds.count(egitr->first) == 0; });

      EdgeVal env;
      split_fun(s1->second.val, s2->second.val, s3->second.val, inds, ind2, ind3, env);
      add_edge_node(s2,s3,ind2,ind3,env);
      this->erase(s1);
   }
   template <typename NodeVal, typename EdgeVal, typename NodeKey, typename EdgeKey, typename Trait>
   template <typename split_type>
   typename network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::IterNode network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::split(
         network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::IterNode s1,
         const NodeKey & nodekey2,
         const std::unordered_set<EdgeKey> & inds,
         const EdgeKey & ind1,
         const EdgeKey & ind2,
         const split_type & split_fun) {
      auto s2 = add(nodekey2);

      s1->second.transfer_edge(s2, [&inds](auto & egitr) { return inds.count(egitr->first) == 1; });

      auto temp = s1->second.val;
      EdgeVal env;
      split_fun(temp, s1->second.val, s2->second.val, inds, ind1, ind2, env);
      // s1->second.set_edge(ind1, nodekey2, ind2, s2, env);
      // s2->second.set_edge(ind2, s1->first, ind1, s1, env);
      add_edge_node(s1,s2,ind1,ind2,env);
      return s2;
   }
   template <typename NodeVal, typename EdgeVal, typename NodeKey, typename EdgeKey, typename Trait>
   template <typename split_type>
   void network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::split(
         const NodeKey & nodekey1,
         const NodeKey & nodekey2,
         const std::unordered_set<EdgeKey> & inds,
         const EdgeKey & ind1,
         const EdgeKey & ind2,
         const split_type & split_fun) {

      auto s1 = this->find(nodekey1);
      auto s2 = add(nodekey2);

      s1->second.transfer_edge(s2, [&inds](auto & egitr) { return inds.count(egitr->first) == 1; });

      auto temp = s1->second.val;

      EdgeVal env;
      split_fun(temp, s1->second.val, s2->second.val, inds, ind1, ind2, env);
      // s1->second.set_edge(ind1, nodekey2, ind2, s2, env);
      // s2->second.set_edge(ind2, nodekey1, ind1, s1, env);
      add_edge_node(s1,s2,ind1,ind2,env);
   }
   template <typename NodeVal, typename EdgeVal, typename NodeKey, typename EdgeKey, typename Trait>
   template <typename absorb_type, typename contract_type>
   NodeVal network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::contract(const absorb_type & absorb_fun, const contract_type & contract_fun) const {
      NodeVal tot;
      std::set<NodeKey, typename Trait::nodekey_less> contracted;
      for (auto s : *this) {
         if (contracted.count(s.first) == 0) {
            tn_contract1(s.first, contracted, tot, absorb_fun, contract_fun);
            contracted.insert(s.first);
         }
      }
      return tot;
   }

   template <typename NodeVal, typename EdgeVal, typename NodeKey, typename EdgeKey, typename Trait>
   template <typename absorb_type, typename contract_type>
   NodeKey network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::absorb(
         std::set<NodeKey, typename Trait::nodekey_less> part,
         const absorb_type & absorb_fun,
         const contract_type & contract_fun) {
      if(part.size()==0){
         return NodeKey();
      }else{
         auto it0=part.begin();
         for(auto it =part.begin();it!=part.end();++it){
            if(it!=it0) absorb(*it0,*it,absorb_fun,contract_fun);
         }
         return *it0;
      }
   }

   template <typename NodeVal, typename EdgeVal, typename NodeKey, typename EdgeKey, typename Trait>
   template <typename TreeType, typename absorb_type, typename contract_type>
   NodeKey network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::absorb_tree(
         std::shared_ptr<TreeType> ctree,
         const absorb_type & absorb_fun,
         const contract_type & contract_fun) {
      if (!ctree)
         return NodeKey();
      else if (!ctree->left_child && !ctree->right_child)
         return absorb(ctree->val.node_set, absorb_fun, contract_fun);
      else if (!ctree->left_child && ctree->right_child)
         return absorb_tree<TreeType>(ctree->right_child, absorb_fun, contract_fun);
      else if (ctree->left_child && !ctree->right_child)
         return absorb_tree<TreeType>(ctree->left_child, absorb_fun, contract_fun);
      else{
         NodeKey left = absorb_tree<TreeType>(ctree->left_child, absorb_fun, contract_fun);
         NodeKey right = absorb_tree<TreeType>(ctree->right_child, absorb_fun, contract_fun);
         if(left == NodeKey()){
            return right;
         }else if(right == NodeKey()){
            return left;
         }else{
            absorb(left,right, absorb_fun, contract_fun);
            return left;
         }

      }
   }

   template <typename NodeVal, typename EdgeVal, typename NodeKey, typename EdgeKey, typename Trait>
   template <typename absorb_type, typename contract_type>
   NodeVal network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::contract(
         std::set<NodeKey, typename Trait::nodekey_less> part,
         const absorb_type & absorb_fun,
         const contract_type & contract_fun) const {
      NodeVal tot;
      std::set<NodeKey, typename Trait::nodekey_less> contracted;
      for (auto p : part) {
         if (contracted.count(p) == 0) {
            tn_contract1(p, contracted, tot, absorb_fun, contract_fun);
            contracted.insert(p);
         }
      }
      return tot;
   }

   template <typename NodeVal, typename EdgeVal, typename NodeKey, typename EdgeKey, typename Trait>
   template <typename TreeType, typename absorb_type, typename contract_type>
   NodeVal network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::contract_tree(
         std::shared_ptr<TreeType> ctree,
         const absorb_type & absorb_fun,
         const contract_type & contract_fun) const {
      if (!ctree)
         return NodeVal();
      else if (!ctree->left_child && !ctree->right_child)
         return contract(ctree->val.node_set, absorb_fun, contract_fun);
      else if (!ctree->left_child && ctree->right_child)
         return contract_tree<TreeType>(ctree->right_child, absorb_fun, contract_fun);
      else if (ctree->left_child && !ctree->right_child)
         return contract_tree<TreeType>(ctree->left_child, absorb_fun, contract_fun);
      else
         return tn_contract2(
               ctree->left_child->val.node_set,
               contract_tree<TreeType>(ctree->left_child, absorb_fun, contract_fun),
               ctree->right_child->val.node_set,
               contract_tree<TreeType>(ctree->right_child, absorb_fun, contract_fun),
               absorb_fun,
               contract_fun);
   }


   template <typename NodeVal, typename EdgeVal, typename NodeKey, typename EdgeKey, typename Trait>
   template <typename absorb_type, typename contract_type>
   void network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::tn_contract1(
         const NodeKey & nodekey,
         const std::set<NodeKey, typename Trait::nodekey_less> & group,
         NodeVal & ten,
         const absorb_type & absorb_fun,
         const contract_type & contract_fun) const {
      auto node_itr1 = this->find(nodekey);
      if (node_itr1 == this->end()) {
         throw key_unfound_error("In network.tn_contract1, node " + to_string(nodekey) + " is not found!");
      }

      if (group.size() == 0) {
         ten = node_itr1->second.val;
      } else {
         auto node_t = node_itr1->second.val;
         std::set<std::pair<EdgeKey, EdgeKey>, typename Trait::edge2key_less> ind_pairs;
         node_itr1->second.harmless_absorb_nb(node_t, ind_pairs, absorb_fun, [&group](auto & eg) { return group.count(eg.second.nbkey) == 1; });
         ten = contract_fun(node_t, ten, ind_pairs);
      }
   }

   template <typename NodeVal, typename EdgeVal, typename NodeKey, typename EdgeKey, typename Trait>
   template <typename absorb_type, typename contract_type>
   void network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::tn_contract1(
         network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::IterNode it1,
         const std::set<NodeKey, typename Trait::nodekey_less> & group,
         NodeVal & ten,
         const absorb_type & absorb_fun,
         const contract_type & contract_fun) const {
      if (group.size() == 0) {
         ten = it1->second.val;
      } else {
         auto node_t = it1->second.val;
         std::set<std::pair<EdgeKey, EdgeKey>, typename Trait::edge2key_less> ind_pairs;

         it1->second.harmless_absorb_nb(node_t, ind_pairs, absorb_fun, [&group](auto & eg) { return group.count(eg.second.nbkey) == 1; });

         ten = contract_fun(node_t, ten, ind_pairs);
      }
   }

   template <typename NodeVal, typename EdgeVal, typename NodeKey, typename EdgeKey, typename Trait>
   template <typename absorb_type, typename contract_type>
   NodeVal network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::tn_contract2(
         const std::set<NodeKey, typename Trait::nodekey_less> & group1,
         const NodeVal & ten1,
         const std::set<NodeKey, typename Trait::nodekey_less> & group2,
         const NodeVal & ten2,
         const absorb_type & absorb_fun,
         const contract_type & contract_fun) const {
      if (group1.size() == 0)
         return ten2;
      if (group2.size() == 0)
         return ten1;
      std::set<std::pair<EdgeKey, EdgeKey>, typename Trait::edge2key_less> ind_pairs;
      auto ten1_temp = ten1;
      for (auto & nk : group1)
         this->at(nk).harmless_absorb_nb(ten1_temp, ind_pairs, absorb_fun, [&group2](auto & eg) { return group2.count(eg.second.nbkey) == 1; });
      return contract_fun(ten1_temp, ten2, ind_pairs);
   }
   template <typename NodeVal, typename EdgeVal, typename NodeKey, typename EdgeKey, typename Trait>
   template <typename NetType2>
   NetType2 network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::fmap(
         std::function<typename NetType2::NodeValType(const NodeVal &)> f1,
         std::function<typename NetType2::EdgeValType(const EdgeVal &)> f2) const {
      NetType2 result;
      for (auto & s : *this)
         result[s.first] = s.second.template fmap<typename NetType2::NodeType>(s.first,f1, f2);
      for (auto & s : result)
         s.second.relink(result);
      return result;
   }
   template <typename NodeVal, typename EdgeVal, typename NodeKey, typename EdgeKey, typename Trait>
   template <typename NetType2>
   NetType2 network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::fmap(
         std::function<typename NetType2::NodeValType(const NodeVal &)> f1,
         std::function<typename NetType2::EdgeValType(const EdgeVal &)> f2,
         std::function<typename NetType2::NodeKeyType(const NodeKey &)> f3,
         std::function<typename NetType2::EdgeKeyType(const EdgeKey &)> f4) const {
      NetType2 result;
      for (auto & s : *this){
         result[f3(s.first)] = s.second.template fmap<typename NetType2::NodeType>(f3(s.first), f1, f2, f3, f4);
      }
      for (auto & s : result)
         s.second.relink(result);
      return result;
   }
   template <typename NodeVal, typename EdgeVal, typename NodeKey, typename EdgeKey, typename Trait>
   template <typename NodeVal2, typename EdgeVal2, typename Trait2>
   network<NodeVal2, EdgeVal2, NodeKey, EdgeKey, Trait2> network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::gfmap(
         std::function<NodeVal2(const node<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait> &)> f1,
         std::function<EdgeVal2(
               const node<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait> &,const EdgeKey &)> f2) const {
      network<NodeVal2, EdgeVal2, NodeKey, EdgeKey, Trait2> result;
      for (auto & s : *this)
         result[s.first] = s.second.template gfmap<NodeVal2,EdgeVal2,Trait2>(s.first, f1, f2);
      for (auto & s : result)
         s.second.relink(result);
      return result;
   }
   template <typename NodeVal, typename EdgeVal, typename NodeKey, typename EdgeKey, typename Trait>
   void
   network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::fope(std::function<NodeVal(const NodeVal &)> f1, std::function<EdgeVal(const EdgeVal &)> f2) {
      for (auto & s : *this)
         s.second.fope(f1, f2);
   }
   template <typename NodeVal, typename EdgeVal, typename NodeKey, typename EdgeKey, typename Trait>
   void
   network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::gfope(
         std::function<NodeVal(const node<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait> &)> f1,
         std::function<EdgeVal(
               const node<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait> &,const EdgeKey &)> f2) {
      for (auto & s : *this)
         s.second.gfope(f1, f2);
   }

   template <typename NodeVal, typename EdgeVal, typename NodeKey, typename EdgeKey, typename Trait>
   bool network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::consistency(std::ostream & diagnosis) const {
      for (auto & s : *this)
         if (!s.second.consistency(*this,s.first, diagnosis)) {
            diagnosis << "Error at node " << s.first << '\n';
            return false;
         }
      return true;
   }

} // namespace net
#endif

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