# include/net/node.hpp

# Namespaces

Name
net

# Classes

Name
struct net::half_edge
描述着(某条格点上的)半边的信息,包括这条半边与哪条格点的哪条半边相连
class net::node
存储了网络中一个格点内的信息

# Source code

#ifndef NET_NODE_HPP
#define NET_NODE_HPP

#include "error.hpp"
#include "network.hpp"
#include "traits.hpp"
#include <functional>
#include <map>
#include <string>
#include <vector>

namespace net {

   template <typename NodeVal, typename EdgeVal, typename NodeKey, typename EdgeKey, typename Trait>
   class node;
   template <typename NodeVal, typename EdgeVal, typename NodeKey, typename EdgeKey, typename Trait>
   class network;
   template <typename T>
   std::string to_string(const T & m);

   template <typename NodeVal, typename EdgeVal, typename NodeKey, typename EdgeKey, typename Trait>
   struct half_edge {


      using EdgeItrType = typename std::map<EdgeKey, half_edge<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>, typename Trait::edgekey_less>::iterator ;

      int nb_num;
      NodeKey nbkey;
      EdgeKey nbind;
      typename network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::IterNode nbitr;
      EdgeVal val;

      EdgeItrType nbegitr;

      half_edge() : nb_num(0) {};
      half_edge(const EdgeVal & E) : val(E), nb_num(0) {};
      half_edge(const NodeKey & s1, const EdgeKey & s2, typename network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::IterNode s) :
            nbkey(s1), nbind(s2), nbitr(s), nb_num(1){};
      half_edge(const NodeKey & s1, const EdgeKey & s2, typename network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::IterNode s, const EdgeVal & E) :
            nbkey(s1), nbind(s2), nbitr(s), val(E), nb_num(1){};
      half_edge(const NodeKey & s1, const EdgeKey & s2, const EdgeVal & E) : nbkey(s1), nbind(s2), val(E), nb_num(1){};
      half_edge(const half_edge<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait> &) = default;
   };

   template <typename NodeVal, typename EdgeVal, typename NodeKey, typename EdgeKey, typename Trait>
   class node {
      template <typename NodeVal1, typename EdgeVal1, typename NodeKey1, typename EdgeKey1, typename Trait1>
      friend std::ostream & output_node_text(std::ostream &, const node<NodeVal1, EdgeVal1, NodeKey1, EdgeKey1, Trait1> &);

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

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

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

   public:
      // constructor
      node() = default;
      node(const NodeKey & k) : key(k){};
      node(const NodeKey & k, const NodeVal & s) : key(k),val(s){};
      // copy constructor
      node(const node<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait> &) = default;
      // copy assignment
      node<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait> & operator=(const node<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait> &) = default;
      // move constructor
      node(node<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait> &&) = default;
      // move assignment
      node<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait> & operator=(node<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait> &&) = default;

      using EdgeType = half_edge<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>;
      using NodeKeyType = NodeKey;
      using NodeValType = NodeVal;
      using EdgeKeyType = EdgeKey;
      using EdgeValType = EdgeVal;
      using TraitType = Trait;

      typename half_edge<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::EdgeItrType 
         add_half_edge(const EdgeKey & ind1, const EdgeVal & edgev) ;

      void clean();

      template <typename Condition>
      void delete_half_edge(Condition &&);
      template <typename Condition>
      void break_edge(Condition &&);
      template <typename Condition>
      void delete_edge(Condition &&);
      void delete_nbedge();

      void reset_nbkey_of_nb(const NodeKey &);

      template <typename absorb_type, typename contract_type>
      void absorb_nb(const NodeKey &, const NodeVal &, const absorb_type &, const contract_type &);
      template <typename absorb_type, typename Condition>
      void
      harmless_absorb_nb(NodeVal &, std::set<std::pair<EdgeKey, EdgeKey>, typename Trait::edge2key_less> &, const absorb_type &, Condition &&) const;

      void transfer_edge(const typename network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::IterNode &);
      template <typename Condition>
      void transfer_edge(const typename network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::IterNode &, Condition &&);
      template <typename Condition>
      void transfer_edge(
            const typename network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::IterNode &,
            const typename network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::IterNode &,
            Condition &&);

      void relink(std::map<NodeKey, node<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>, typename Trait::nodekey_less> &);

      bool consistency(const std::map<NodeKey, node<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>, typename Trait::nodekey_less> &, const NodeKey & t, std::ostream &)const;

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

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

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

      template <typename NodeVal2, typename EdgeVal2, typename Trait2>
      node<NodeVal2, EdgeVal2, NodeKey, EdgeKey, Trait2>
      gfmap(const NodeKey & this_key,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 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);
      NodeKey key;
      NodeVal val;
      std::map<EdgeKey, half_edge<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>, typename Trait::edgekey_less> edges;
   };
   template <typename NodeVal, typename EdgeVal, typename NodeKey, typename EdgeKey, typename Trait>
   template <typename Condition>
   void node<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::delete_half_edge(Condition && cond) {
      for (auto edge_itr = edges.begin(); edge_itr != edges.end();) {
         if (cond(edge_itr)) {
            if(edge_itr->second.nbnum!=0){
               edge_itr->second.nbegitr->second.nbnum=0;
               edge_itr->second.nbegitr->second.nbkey=edge_itr->second.nbkey;
               edge_itr->second.nbegitr->second.nbind=edge_itr->second.nbind;
               edge_itr->second.nbegitr->second.nbitr=edge_itr->second.nbitr;
               edge_itr->second.nbegitr->second.nbegitr=edge_itr->second.nbegitr;
            }
            edge_itr = edges.erase(edge_itr);
         } else {
            ++edge_itr;
         }
      }
   }

   template <typename NodeVal, typename EdgeVal, typename NodeKey, typename EdgeKey, typename Trait>
   template <typename Condition>
   void node<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::break_edge(Condition && cond) {
      for (auto edge_itr = edges.begin(); edge_itr != edges.end();++edge_itr) {
         if (cond(edge_itr)) {
            if(edge_itr->second.nb_num!=0){
               edge_itr->second.nbegitr->second.nb_num=0;
               edge_itr->second.nbegitr->second.nbkey=edge_itr->second.nbkey;
               edge_itr->second.nbegitr->second.nbind=edge_itr->second.nbind;
               edge_itr->second.nbegitr->second.nbitr=edge_itr->second.nbitr;
               edge_itr->second.nbegitr->second.nbegitr=edge_itr->second.nbegitr;

               edge_itr->second.nb_num=0;
               edge_itr->second.nbkey=this->key;
               edge_itr->second.nbind=edge_itr->first;
               edge_itr->second.nbitr=edge_itr;
               edge_itr->second.nbegitr=edge_itr;
            }
         }
      }
   }

   template <typename NodeVal, typename EdgeVal, typename NodeKey, typename EdgeKey, typename Trait>
   template <typename Condition>
   void node<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::delete_edge(Condition && cond) {
      for (auto edge_itr = edges.begin(); edge_itr != edges.end();) {
         if (cond(edge_itr)) {
            if(edge_itr->second.nb_num!=0){
               edge_itr->second.nbitr->second.edges.erase(edge_itr->second.nbegitr);
            }
            edge_itr = edges.erase(edge_itr);
         } else {
            ++edge_itr;
         }
      }
   }

   template <typename NodeVal, typename EdgeVal, typename NodeKey, typename EdgeKey, typename Trait>
   void node<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::delete_nbedge() {
      for (auto & b : edges) {
         if(b.second.nb_num!=0){
            b.second.nbitr->second.edges.erase(b.second.nbegitr);
         }
      }
      edges.clear();
   }

   
   template <typename NodeVal, typename EdgeVal, typename NodeKey, typename EdgeKey, typename Trait>
   void node<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::reset_nbkey_of_nb(const NodeKey & newkey) {
      for (auto & b : edges) {
         if(b.second.nb_num!=0){
            b.second.nbegitr->second.nbkey = newkey;
         }
      }
   }

   template <typename NodeVal, typename EdgeVal, typename NodeKey, typename EdgeKey, typename Trait>
   template <typename absorb_type, typename contract_type>
   void node<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::absorb_nb(
         const NodeKey & nbkey,
         const NodeVal & nbval,
         const absorb_type & absorb_fun,
         const contract_type & contract_fun) {
      std::set<std::pair<EdgeKey, EdgeKey>, typename Trait::edge2key_less> ind_pairs;

      // set ind_pairs and erase iterator in node1
      for (auto iter = edges.begin(); iter != edges.end();) {
         if (iter->second.nb_num!=0 && iter->second.nbkey == nbkey) {
            ind_pairs.insert({iter->first, iter->second.nbind});
            val = absorb_fun(val, iter->second.val, iter->first);
            iter = edges.erase(iter);
         } else {
            ++iter;
         }
      }
      val = contract_fun(val, nbval, ind_pairs);
   }

   template <typename NodeVal, typename EdgeVal, typename NodeKey, typename EdgeKey, typename Trait>
   template <typename absorb_type, typename Condition>
   void node<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::harmless_absorb_nb(
         NodeVal & thisval,
         std::set<std::pair<EdgeKey, EdgeKey>, typename Trait::edge2key_less> & ind_pairs,
         const absorb_type & absorb_fun,
         Condition && cond) const {
      for (auto & b : edges) {
         // std::cout<<"edge"<<b.first<<' '<<b.second.nbkey<<'\n';
         if (b.second.nb_num!=0 && cond(b)) {
            // std::cout<<"edgehere"<<b.first<<' '<<b.second.nbkey<<'\n';
            ind_pairs.insert({b.first, b.second.nbind});
            thisval = absorb_fun(thisval, b.second.val, b.first);
         }
      }
   }

   template <typename NodeVal, typename EdgeVal, typename NodeKey, typename EdgeKey, typename Trait>
   void node<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::transfer_edge(
         const typename network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::IterNode & newit) {
         while(edges.size()>0) {
            auto nh = edges.extract(edges.begin());
            auto status = newit->second.edges.insert(std::move(nh));
            if(status.position->second.nb_num!=0){
               status.position->second.nbegitr->second.nbkey = newit->first;
               status.position->second.nbegitr->second.nbitr = newit;
               status.position->second.nbegitr->second.nbegitr = status.position;
            }
         }
   }

   template <typename NodeVal, typename EdgeVal, typename NodeKey, typename EdgeKey, typename Trait>
   template <typename Condition>
   void node<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::transfer_edge(
         const typename network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::IterNode & newit,
         Condition && cond) {
      for (auto iter = edges.begin(); iter != edges.end();) {
         if (cond(iter)) {
            auto nh = edges.extract(iter++);
            auto status = newit->second.edges.insert(std::move(nh));
            if(status.position->second.nb_num!=0){
               status.position->second.nbegitr->second.nbkey = newit->first;
               status.position->second.nbegitr->second.nbitr = newit;
               status.position->second.nbegitr->second.nbegitr = status.position;
            }
         } else {
            ++iter;
         }
      }
   }

   template <typename NodeVal, typename EdgeVal, typename NodeKey, typename EdgeKey, typename Trait>
   template <typename Condition>
   void node<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::transfer_edge(
         const typename network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::IterNode & newit,
         const typename network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::IterNode & newit2,
         Condition && cond) {
      for (auto iter = edges.begin(); iter != edges.end();) {
         auto nh = edges.extract(iter++);
         if (cond(iter)) {
            auto status = newit->second.edges.insert(std::move(nh));
            if(status.position->second.nb_num!=0){
               status.position->second.nbegitr->second.nbkey = newit->first;
               status.position->second.nbegitr->second.nbitr = newit;
               status.position->second.nbegitr->second.nbegitr = status.position;
            }
         } else {
            auto status = newit2->second.edges.insert(std::move(nh));
            if(status.position->second.nb_num!=0){
               status.position->second.nbegitr->second.nbkey = newit2->first;
               status.position->second.nbegitr->second.nbitr = newit2;
               status.position->second.nbegitr->second.nbegitr = status.position;
            }
         }
      }
   }
   template <typename NodeVal, typename EdgeVal, typename NodeKey, typename EdgeKey, typename Trait>
   typename half_edge<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::EdgeItrType 
      node<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::add_half_edge(const EdgeKey & ind1, const EdgeVal & edgev) {

      auto [egit1, succ1] = edges.insert({ind1, typename node<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::EdgeType(edgev)});
      if (!succ1)
         throw key_exist_error("In node.add_edge_node, ind " + to_string(ind1) + " already exist!");
      return egit1;
   }

   template <typename IterNode, typename EdgeKey, typename EdgeVal>
   void add_edge_node(IterNode it1, IterNode it2, const EdgeKey & ind1,const EdgeKey & ind2, const EdgeVal & edgev) {

      auto egit1 = it1->second.add_half_edge(ind1,edgev);
      auto egit2 = it2->second.add_half_edge(ind2,edgev);
      egit1->second.nb_num=1;
      egit1->second.nbkey= it2->first;
      egit1->second.nbind= ind2;
      egit1->second.nbitr=it2;
      egit1->second.nbegitr=egit2;

      egit2->second.nb_num=1;
      egit2->second.nbkey= it1->first;
      egit2->second.nbind= ind1;
      egit2->second.nbitr=it1;
      egit2->second.nbegitr=egit1;
   }

   template <typename IterNode, typename EdgeKey, typename EdgeVal>
   void connect_edge_node(IterNode it1, IterNode it2, const EdgeKey & ind1,const EdgeKey & ind2) {

      auto egit1 = it1->second.edges.find(ind1);
      if (egit1 == it1->second.edges.end()) 
         throw key_unfound_error("In node.connect_edge_node, ind " + to_string(ind1) + " is not found!");
      if(egit1->second.nb_num==1)
         throw key_exist_error("In node.connect_edge_node, ind " + to_string(ind1) + " already linked!");
      auto egit2 = it2->second.edges.find(ind2);
      if (egit2 == it2->second.edges.end()) 
         throw key_unfound_error("In node.connect_edge_node, ind " + to_string(ind2) + " is not found!");
      if(egit2->second.nb_num==1)
         throw key_exist_error("In node.connect_edge_node, ind " + to_string(ind2) + " already linked!");

      egit1->second.nb_num=1;
      egit1->second.nbkey=it2->first;
      egit1->second.nbind=ind2;
      egit1->second.nbitr=it2;
      egit1->second.nbegitr=egit2;

      egit2->second.nb_num=1;
      egit2->second.nbkey=it1->first;
      egit2->second.nbind=ind1;
      egit2->second.nbitr=it1;
      egit2->second.nbegitr=egit1;

   }

   template <typename NodeVal, typename EdgeVal, typename NodeKey, typename EdgeKey, typename Trait>
   void node<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::relink(
         std::map<NodeKey, node<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>, typename Trait::nodekey_less> & nodes) {
      for (auto & b : edges){
         if(b.second.nb_num==1){
            b.second.nbitr = nodes.find(b.second.nbkey);
            b.second.nbegitr = b.second.nbitr->second.edges.find(b.second.nbind);
         }
      }
   }

   template <typename NodeVal, typename EdgeVal, typename NodeKey, typename EdgeKey, typename Trait>
   template <typename NodeVal2, typename EdgeVal2, typename Trait2>
   node<NodeVal2, EdgeVal2, NodeKey, EdgeKey, Trait2> node<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::gfmap( const NodeKey & this_key,
         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 {
      node<NodeVal2, EdgeVal2, NodeKey, EdgeKey, Trait2> result(this_key,f1(*this));
      for (auto & b : edges)
         if(b.second.nb_num==1){
            result.edges[b.first] = half_edge<NodeVal2, EdgeVal2, NodeKey, EdgeKey, Trait2>(b.second.nbkey, b.second.nbind, f2(*this, b.first));
         }else{
            result.edges[b.first] = half_edge<NodeVal2, EdgeVal2, NodeKey, EdgeKey, Trait2>(f2(*this, b.first));
         }
      return result;
   }

   template <typename NodeVal, typename EdgeVal, typename NodeKey, typename EdgeKey, typename Trait>
   template <typename NodeType2>
   NodeType2 node<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::fmap( const NodeKey & this_key,
         std::function<typename NodeType2::NodeValType(const NodeVal &)> f1,
         std::function<typename NodeType2::EdgeValType(const EdgeVal &)> f2) const {
      NodeType2 result(this_key, f1(val));
      for (auto & b : edges)
         if(b.second.nb_num==1){
            result.edges[b.first] = typename NodeType2::EdgeType(b.second.nbkey, b.second.nbind, f2(b.second.val));
         }else{
            result.edges[b.first] = typename NodeType2::EdgeType(f2(b.second.val));
         }
         
      return result;
   }

   template <typename NodeVal, typename EdgeVal, typename NodeKey, typename EdgeKey, typename Trait>
   template <typename NodeType2>
   NodeType2 node<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::fmap( const NodeKey & new_key,
         std::function<typename NodeType2::NodeValType(const NodeVal &)> f1,
         std::function<typename NodeType2::EdgeValType(const EdgeVal &)> f2,
         std::function<typename NodeType2::NodeKeyType(const NodeKey &)> f3,
         std::function<typename NodeType2::EdgeKeyType(const EdgeKey &)> f4) const {
      NodeType2 result(new_key,f1(val));
      for (auto & b : edges)
         if(b.second.nb_num==1){
            result.edges[f4(b.first)] = typename NodeType2::EdgeType(f3(b.second.nbkey), f4(b.second.nbind), f2(b.second.val));
         }else{
            result.edges[f4(b.first)] = typename NodeType2::EdgeType(f2(b.second.val));
         }
      return result;
   }

   template <typename NodeVal, typename EdgeVal, typename NodeKey, typename EdgeKey, typename Trait>
   void
   node<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::fope(std::function<NodeVal(const NodeVal &)> f1, std::function<EdgeVal(const EdgeVal &)> f2) {
      val = f1(val);
      for (auto & b : edges)
         b.second.val = f2(b.second.val);
   }
   template <typename NodeVal, typename EdgeVal, typename NodeKey, typename EdgeKey, typename Trait>
   void
   node<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) {
      auto temp = f1(*this);
      for (auto & b : edges)
         b.second.val = f2(*this,b.first);
      val = temp;
   }

   template <typename NodeVal, typename EdgeVal, typename NodeKey, typename EdgeKey, typename Trait>
   bool node<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::consistency(
         const std::map<NodeKey, node<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>, typename Trait::nodekey_less> & nodes,
         const NodeKey & this_key, std::ostream & diagnosis) const {
      if(key!=this_key){
         diagnosis << "Network is not consistent, node at " + to_string(this_key) + " has wrong key!\n";
         return false;  
      }
      for (auto & b : edges) { // check if b is consistent
         if(b.second.nb_num!=0){
            if (nodes.count(b.second.nbkey) == 0) {
               diagnosis << "Network is not consistent, neighbor " + to_string(b.second.nbkey) + " is not found!\n";
               return false;
            } else if (nodes.at(b.second.nbkey).edges.count(b.second.nbind) == 0) {
               diagnosis << "Network is not consistent, neighbor " + to_string(b.second.nbkey) + " has no index named " + to_string(b.second.nbind) +
                                  " !\n";
               return false;
            } else if (b.second.nbitr != nodes.find(b.second.nbkey)) {
               diagnosis << "Network is not consistent, pointer to neighbor " + to_string(b.second.nbkey) + " is not correctly pointed !\n";
               return false;
            } else if (b.second.nbegitr != b.second.nbitr->second.edges.find(b.second.nbind)) {
               diagnosis << "Network is not consistent, pointer to neighbor edge " + to_string(b.second.nbind) + " is not correctly pointed !\n";
               return false;
            } else if (b.second.nbegitr->second.nb_num == 0) {
               diagnosis << "Network is not consistent, neighboring half edge to " + to_string(b.second.nbind) + " is dangling !\n";
               return false;
            } else if (b.second.nbegitr->second.nbkey != this_key) {
               diagnosis << "Network is not consistent, neighboring half edge to " + to_string(b.second.nbind) + " is not matching 0 !\n";
               return false;
            } else if (b.second.nbegitr->second.nbind != b.first) {
               diagnosis << "Network is not consistent, neighboring half edge to " + to_string(b.second.nbind) + " is not matching 1 !\n";
               return false;
            }
         }
      }

      return true;
   }
} // namespace net

#endif

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