Loading [MathJax]/extensions/tex2jax.js
barry: Your go-to motif accountant  0.0-1
Full enumeration of sample space and fast count of sufficient statistics for binary arrays
All Classes Namespaces Files Functions Variables Typedefs Friends Macros Modules
network.hpp
Go to the documentation of this file.
1 #ifndef BARRAY_NETWORK_H
2 #define BARRAY_NETWORK_H 1
3 
11 
19 class NetworkData {
20 public:
21 
22  bool directed = true;
23  std::vector< std::vector< double > > vertex_attr;
24 
26 
34  std::vector< double > vertex_attr_,
35  bool directed_ = true
36  ) : directed(directed_), vertex_attr(1u, vertex_attr_) {};
37 
46  std::vector< std::vector< double > > vertex_attr_,
47  bool directed_ = true
48  ) : directed(directed_), vertex_attr(vertex_attr_) {};
49 
50 
52 };
53 
57 public:
58 
59  std::vector< size_t > indices;
60  std::vector< double > numbers;
61 
62  NetCounterData() : indices(0u), numbers(0u) {};
64  const std::vector< size_t > & indices_,
65  const std::vector< double > & numbers_
66  ): indices(indices_), numbers(numbers_) {};
67 
69 
70  // const size_t get_size_t
71 
72 };
73 
74 #define NET_C_DATA_IDX(i) (data.indices[i])
75 #define NET_C_DATA_NUM(i) (data.numbers[i])
76 
77 
84 
85 #define BARRY_ZERO_NETWORK 0.0
86 #define BARRY_ZERO_NETWORK_DENSE 0
87 
88 template <typename Tnet = Network>
90 
91 template <typename Tnet = Network>
93 
94 template <typename Tnet = Network>
96 
97 template <typename Tnet = Network>
99 
100 template <typename Tnet>
102 
103 template <typename Tnet = Network>
105 
106 template <typename Tnet = Network>
109 
113 
114 #define NETWORK_COUNTER(a) \
115 template<typename Tnet = Network>\
116 inline double (a) (const Tnet & Array, size_t i, size_t j, NetCounterData & data)
117 
119 #define NETWORK_COUNTER_LAMBDA(a) \
120 Counter_fun_type<Tnet, NetCounterData> a = \
121  [](const Tnet & Array, size_t i, size_t j, NetCounterData & data)
122 
123 #define NETWORKDENSE_COUNTER_LAMBDA(a) \
124 Counter_fun_type<NetworkDense, NetCounterData> a = \
125  [](const NetworkDense & Array, size_t i, size_t j, NetCounterData & data)
127 
128 
132 
133 #define NETWORK_RULE(a) \
134 template<typename Tnet = Network>\
135 inline bool (a) (const Tnet & Array, size_t i, size_t j, bool & data)
136 
138 #define NETWORK_RULE_LAMBDA(a) \
139 Rule_fun_type<Tnet, bool> a = \
140 [](const Tnet & Array, size_t i, size_t j, bool & data)
142 
149 // -----------------------------------------------------------------------------
151 template<typename Tnet = Network>
153 {
154 
155  NETWORK_COUNTER_LAMBDA(count_edges)
156  {
157  return 1.0;
158  };
159 
160  counters->add_counter(
161  count_edges, nullptr, nullptr,
162  NetCounterData(),
163  "Edge counts",
164  "Number of edges"
165  );
166 
167  return;
168 
169 }
170 
171 
172 // -----------------------------------------------------------------------------
174 template<typename Tnet = Network>
176 {
177 
178  NETWORK_COUNTER_LAMBDA(tmp_count)
179  {
180 
181  if (i == j)
182  return 0.0;
183 
184  double res = 0.0;
185 
186  // i is sending its first tie
187  if (Array.row(i).size() == 1u && Array.col(i).size() == 0u)
188  res -= 1.0;
189 
190  // j is receiving its first tie, meaning that he
191  // has no other tie but i's?
192  if (Array.row(j).size() == 0u && Array.col(j).size() == 1u)
193  res -= 1.0;
194 
195  return res;
196 
197  };
198 
199  NETWORK_COUNTER_LAMBDA(tmp_init)
200  {
201  return static_cast<double>(Array.nrow());
202  };
203 
204  counters->add_counter(
205  tmp_count, tmp_init, nullptr,
206  NetCounterData(),
207  "Isolates",
208  "Number of isolate vertices"
209  );
210 
211  return;
212 }
213 
214 template<>
216 {
217 
218  NETWORKDENSE_COUNTER_LAMBDA(tmp_count)
219  {
220 
221  if (i == j)
222  return 0.0;
223 
224  double res = 0.0;
225 
226  // Checking the in and out degree
227  if (Array.rowsum(i) == 1u && Array.colsum(i) == 0u)
228  res -= 1.0;
229 
230  // Now looking at j
231  if (Array.rowsum(j) == 0u && Array.colsum(j) == 1u)
232  res -= 1.0;
233 
234  return res;
235 
236  };
237 
239  {
240  return static_cast<double>(Array.nrow());
241  };
242 
243  counters->add_counter(
244  tmp_count, tmp_init, nullptr,
245  NetCounterData(),
246  "Isolates", "Number of isolate vertices"
247  );
248 
249  return;
250 
251 }
252 
253 // -----------------------------------------------------------------------------
255 template<typename Tnet = Network>
257 {
258 
259  NETWORK_COUNTER_LAMBDA(tmp_count)
260  {
261 
262  // Is there any tie at ji? If not, then we have a new mutual!
263  // but this only makes sence if the jth row and ith column exists
264  // if ((Array.nrow() > j) && (Array.ncol() > i))
265  if (i == j)
266  return 0.0;
267 
268  // printf_barry("Checking if it is empty or not at (%i, %i)... ", i, j);
269  if (!Array.is_empty(j, i, false))
270  {
271  // printf_barry("Yes, mutual.\n");
272  return 1.0;
273  }
274  // printf_barry("No, no mutual.\n");
275 
276  return 0.0;
277 
278  };
279 
280  NETWORK_COUNTER_LAMBDA(tmp_init)
281  {
282 
283  if (Array.nrow() != Array.ncol())
284  throw std::logic_error("The -mutual- counter only works on square arrays.");
285 
286  if (Array.D_ptr() == nullptr)
287  throw std::logic_error("The array data has not been initialized");
288 
289  if (!Array.D_ptr()->directed)
290  throw std::logic_error(
291  "The -mutual- counter only works on directed (non-symmetric) arrays."
292  );
293 
294  return 0.0;
295 
296  };
297 
298  counters->add_counter(
299  tmp_count, tmp_init, nullptr,
300  NetCounterData(),
301  "Reciprocity",
302  "Number of mutual ties"
303  );
304 
305  return;
306 
307 }
308 
309 
310 // 2-istars --------------------------------------------------------------------
311 template<typename Tnet = Network>
313 {
314 
315  NETWORK_COUNTER_LAMBDA(tmp_count)
316  {
317  // Need to check the receiving, if he/she is getting a new set of stars
318  // when looking at triads
319 
320  if (Array.col(j).size() == 1u)
321  return 0.0;
322 
323  return static_cast<double>(Array.col(j).size() - 1.0);
324 
325  };
326 
327  counters->add_counter(
328  tmp_count, nullptr, nullptr,
329  NetCounterData(),
330  "Istar 2",
331  "Indegree 2-star"
332  );
333 
334  return ;
335 }
336 
337 template<>
339 {
340 
341  NETWORKDENSE_COUNTER_LAMBDA(tmp_count)
342  {
343  // Need to check the receiving, if he/she is getting a new set of stars
344  // when looking at triads
345  // int indeg = 1;
346  // for (size_t k = 0u; k < Array.nrow(); ++k)
347  // {
348  // if (i == k)
349  // continue;
350 
351  // if (Array(k,j) != BARRY_ZERO_NETWORK_DENSE)
352  // indeg++;
353  // }
354 
355  // if (indeg == 1)
356  // return 0.0;
357 
358  // return static_cast<double>(indeg - 1);
359  return static_cast<double>(Array.colsum(j) - 1);
360 
361  };
362 
363  counters->add_counter(
364  tmp_count, nullptr, nullptr,
365  NetCounterData(),
366  "Istar 2",
367  "Indegree 2-star"
368  );
369 
370  return ;
371 }
372 
373 
374 // 2-ostars --------------------------------------------------------------------
375 template<typename Tnet = Network>
377 {
378 
379  NETWORK_COUNTER_LAMBDA(tmp_count)
380  {
381 
382  // Need to check the receiving, if he/she is getting a new set of stars
383  // when looking at triads
384 
385  if (Array.row(i).size() == 1u)
386  return 0.0;
387 
388  return static_cast<double>( Array.row(i).size() - 1.0);
389 
390  };
391 
392  counters->add_counter(
393  tmp_count, nullptr, nullptr,
394  NetCounterData(),
395  "Ostar 2",
396  "Outdegree 2-star"
397  );
398 
399  return ;
400 
401 }
402 
403 template<>
405 {
406 
407  NETWORKDENSE_COUNTER_LAMBDA(tmp_count)
408  {
409 
410  // Need to check the receiving, if he/she is getting a new set of stars
411  // when looking at triads
412  // int nties = 0;
413  // for (size_t k = 0u; k < Array.ncol(); ++k)
414  // {
415  // if (Array(i, k) != BARRY_ZERO_NETWORK_DENSE)
416  // ++nties;
417  // }
418 
419  // if (nties == 1u)
420  // return 0.0;
421 
422  // return static_cast<double>(nties - 1.0);
423  return static_cast<double>(Array.rowsum(i) - 1);
424 
425  };
426 
427  counters->add_counter(
428  tmp_count, nullptr, nullptr,
429  NetCounterData(),
430  "Ostar 2",
431  "Outdegree 2-star"
432  );
433 
434  return ;
435 
436 }
437 
438 
439 // ttriads ---------------------------------------------------------------------
440 template<typename Tnet = Network>
442 {
443 
444  NETWORK_COUNTER_LAMBDA(tmp_count)
445  {
446 
447  // Self ties do not count
448  if (i == j)
449  return 0.0;
450 
451  double ans = 0.0;
452 
453  // Case 1: i-j, i-k, j-k
454  if (Array.row(j).size() < Array.row(i).size())
455  {
456 
457  for (auto j_row = Array.row(j).begin(); j_row != Array.row(j).end(); ++j_row)
458  if ((j != j_row->first) && (i != j_row->first) && !Array.is_empty(i, j_row->first, false))
459  ans += 1.0;
460 
461  } else {
462 
463  for (auto i_row = Array.row(i).begin(); i_row != Array.row(i).end(); ++i_row)
464  if ((i != i_row->first) && (i_row->first != j) && !Array.is_empty(j, i_row->first, false))
465  ans += 1.0;
466 
467  }
468 
469  // Case 2: i-j, i-k, k-j
470  if (Array.row(i).size() > Array.col(j).size())
471  {
472 
473  for (auto j_col = Array.col(j).begin(); j_col != Array.col(j).end(); ++j_col)
474  if ((j != j_col->first) && (i != j_col->first) && !Array.is_empty(i, j_col->first, false))
475  ans += 1.0;
476 
477  } else {
478 
479  for (auto i_row = Array.row(i).begin(); i_row != Array.row(i).end(); ++i_row)
480  if ((i != i_row->first) && (j != i_row->first) && !Array.is_empty(i_row->first, j, false))
481  ans += 1.0;
482 
483  }
484 
485  // Case 3: i->j, k->j, k->i
486  if (Array.col(i).size() > Array.col(j).size())
487  {
488 
489  for (auto j_col = Array.col(j).begin(); j_col != Array.col(j).end(); ++j_col)
490  if ((j != j_col->first) && (i != j_col->first) && !Array.is_empty(j_col->first, i, false))
491  ans += 1.0;
492 
493  } else {
494 
495  for (auto i_col = Array.col(i).begin(); i_col != Array.col(i).end(); ++i_col)
496  if ((i != i_col->first) && (j != i_col->first) && !Array.is_empty(i_col->first, j, false))
497  ans += 1.0;
498 
499  }
500 
501  // The regular counter double counts
502  return ans;
503 
504  };
505 
506  NETWORK_COUNTER_LAMBDA(tmp_init)
507  {
508 
509  if (Array.D_ptr() == nullptr)
510  throw std::logic_error("The array data has not been initialized");
511 
512  if (!(Array.D_ptr()->directed))
513  throw std::invalid_argument("The ttriads counter is only valid for directed networks. This is undirected.");
514 
515  return 0.0;
516 
517  };
518 
519  counters->add_counter(
520  tmp_count, tmp_init, nullptr,
521  NetCounterData(),
522  "Balance",
523  "Number of directed triangles"
524  );
525 
526  return;
527 
528 }
529 
530 template<>
532 {
533 
534  NETWORKDENSE_COUNTER_LAMBDA(tmp_count)
535  {
536 
537  const auto & dat = Array.get_data();
538  size_t N = Array.nrow();
539 
540  // Self ties do not count
541  if (i == j)
542  return 0.0;
543 
544  // This is the first i sends, so nothing will change
545  if (Array.rowsum(i) == BARRY_ZERO_NETWORK_DENSE)
546  return 0.0;
547 
548 
549  double ans = 0.0;
550  for (size_t k = 0u; k < N; ++k)
551  {
552 
553  // In all cases k receives, so if not, then continue
554  if ((Array.colsum(k) == BARRY_ZERO_NETWORK_DENSE) && (Array.rowsum(k) == BARRY_ZERO_NETWORK_DENSE))
555  continue;
556 
557  if ((j != k) & (i != k))
558  {
559 
560  if (dat[k * N + i] != BARRY_ZERO_NETWORK_DENSE)
561  {
562  // Case 1: i-j, i-k, j-k
563  if (dat[k * N + j])
564  ans += 1.0;
565 
566  // Case 2: i-j, i-k, k-j
567  if (dat[j * N + k] != BARRY_ZERO_NETWORK_DENSE)
568  ans += 1.0;
569  }
570 
571  // Case 3: i-j, k-i, k-j
572  if ((dat[i * N + k] != BARRY_ZERO_NETWORK_DENSE) && (dat[j * N + k] != BARRY_ZERO_NETWORK_DENSE))
573  ans += 1.0;
574 
575  }
576  }
577 
578  // The regular counter double counts
579  return ans;
580 
581  };
582 
584  {
585 
586  if (Array.D_ptr() == nullptr)
587  throw std::logic_error("The array data has not been initialized");
588 
589  if (!(Array.D_ptr()->directed))
590  throw std::invalid_argument("The ttriads counter is only valid for directed networks. This is undirected.");
591 
592  return 0.0;
593 
594  };
595 
596  counters->add_counter(
597  tmp_count, tmp_init, nullptr,
598  NetCounterData(),
599  "Balance",
600  "Number of directed triangles"
601  );
602 
603  return;
604 
605 }
606 
607 
608 // Cycle triads --------------------------------------------------------------
609 template<typename Tnet = Network>
611 {
612 
613  NETWORK_COUNTER_LAMBDA(tmp_count)
614  {
615 
616  if (i == j)
617  return 0.0;
618 
619  double ans = 0.0;
620  if (Array.col(i).size() < Array.row(j).size())
621  {
622 
623  for (auto i_col = Array.col(i).begin(); i_col != Array.col(i).end(); ++i_col)
624  if ((i != i_col->first) && (j != i_col->first) && !Array.is_empty(j, i_col->first, false))
625  ans += 1.0;
626 
627  } else {
628 
629  for (auto j_row = Array.row(j).begin(); j_row != Array.row(j).end(); ++j_row)
630  if ((j != j_row->first) && (i != j_row->first) && !Array.is_empty(j_row->first, i, false))
631  ans += 1.0;
632 
633  }
634 
635  return ans;
636 
637  };
638 
639  NETWORK_COUNTER_LAMBDA(tmp_init)
640  {
641 
642  if (Array.D_ptr() == nullptr)
643  throw std::logic_error("The array data has not been initialized");
644 
645  if (!(Array.D_ptr()->directed))
646  throw std::invalid_argument(
647  "The ctriads counter is only valid for directed networks. This is undirected."
648  );
649 
650  return 0.0;
651 
652  };
653 
654  counters->add_counter(
655  tmp_count, tmp_init, nullptr,
656  NetCounterData(),
657  "Cyclical triads"
658  );
659 
660  return;
661 
662 }
663 
664 template<>
666 {
667 
668  NETWORKDENSE_COUNTER_LAMBDA(tmp_count)
669  {
670 
671  if (i == j)
672  return 0.0;
673 
674  // i->j->k->i
675  double ans = 0.0;
676  #if defined(__OPENMP) || defined(_OPENMP)
677  #pragma omp simd reduction(+:ans)
678  #endif
679  for (size_t k = 0u; k < Array.nrow(); ++k)
680  {
681 
682  // If isolated, then next
683  if (Array.colsum(k) == BARRY_ZERO_NETWORK_DENSE)
684  continue;
685 
686  if (Array.rowsum(k) == BARRY_ZERO_NETWORK_DENSE)
687  continue;
688 
689  if (i != k && j != k)
690  {
691 
692  if ((Array(j, k) != BARRY_ZERO_NETWORK_DENSE) && (Array(k, i) != BARRY_ZERO_NETWORK_DENSE))
693  ans += 1.0;
694 
695  }
696  }
697 
698  return ans;
699 
700  };
701 
703  {
704 
705  if (Array.D_ptr() == nullptr)
706  throw std::logic_error("The array data has not been initialized");
707 
708  if (!(Array.D_ptr()->directed))
709  throw std::invalid_argument(
710  "The ctriads counter is only valid for directed networks. This is undirected."
711  );
712 
713  return 0.0;
714 
715  };
716 
717  counters->add_counter(
718  tmp_count, tmp_init, nullptr,
719  NetCounterData(),
720  "Cyclical triads"
721  );
722 
723  return;
724 
725 }
726 
727 // Density --------------------------------------------------------------
728 template<typename Tnet = Network>
730 {
731 
732  NETWORK_COUNTER_LAMBDA(tmp_count)
733  {
734 
735  return
736  1.0/(Array.nrow() * (Array.ncol() - 1.0)) / (
737  (Array.D_ptr()->directed)? 1.0 : 2.0
738  );
739 
740  };
741 
742  // Preparing the counter data and returning. We make sure that the memory is
743  // released so we set delete_data = true.
744  counters->add_counter(
745  tmp_count, nullptr, nullptr,
746  NetCounterData(),
747  "Density",
748  "Proportion of present ties"
749  );
750 
751  return ;
752 
753 }
754 
755 // idegree1.5 -------------------------------------------------------------
756 template<typename Tnet = Network>
758 {
759 
760  NETWORK_COUNTER_LAMBDA(tmp_count)
761  {
762 
763  // In case of the first, we need to add
764  if (Array.col(j).size() == 1u)
765  return 1.0;
766 
767  return
768  pow(static_cast<double> (Array.col(j).size()), 1.5) -
769  pow(static_cast<double> (Array.col(j).size() - 1), 1.5)
770  ;
771 
772  };
773 
774  counters->add_counter(
775  tmp_count, nullptr, nullptr,
776  NetCounterData(),
777  "Indegree^(1.5)"
778  );
779 
780  return;
781 
782 }
783 
784 template<>
786 {
787 
788  NETWORKDENSE_COUNTER_LAMBDA(tmp_count)
789  {
790 
791  // In case of the first, we need to add
792  int ideg = 0;
793  for (size_t k = 0u; k < Array.nrow(); ++k)
794  {
795  if (k == j)
796  continue;
797 
798  if (Array(k, j) != BARRY_ZERO_NETWORK_DENSE)
799  ideg++;
800 
801  }
802 
803  if (ideg == 0)
804  return 0.0;
805 
806  if (ideg == 1)
807  return 1.0;
808 
809  double res = std::pow(static_cast<double> (ideg), 1.5) -
810  std::pow(static_cast<double> (ideg - 1.0), 1.5);
811 
812  if (std::isnan(res))
813  throw std::domain_error("Resulting indeg is undefined.");
814 
815  return
816  std::pow(static_cast<double> (ideg), 1.5) -
817  std::pow(static_cast<double> (ideg - 1.0), 1.5)
818  ;
819 
820  };
821 
822  counters->add_counter(
823  tmp_count, nullptr, nullptr,
824  NetCounterData(),
825  "Indegree^(1.5)"
826  );
827 
828  return;
829 
830 }
831 
832 // odegree1.5 -------------------------------------------------------------
833 template<typename Tnet = Network>
835 {
836 
837  NETWORK_COUNTER_LAMBDA(tmp_count)
838  {
839 
840  // In case of the first, we need to add
841  if (Array.row(i).size() == 1u)
842  return 1.0;
843 
844  return
845  pow(static_cast<double>(Array.row(i).size()), 1.5) -
846  pow(static_cast<double>(Array.row(i).size() - 1), 1.5)
847  ;
848 
849  };
850 
851  counters->add_counter(
852  tmp_count, nullptr, nullptr,
853  NetCounterData(),
854  "Outdegree^(1.5)"
855  );
856 
857  return;
858 
859 }
860 
861 template<>
863 {
864 
865  NETWORKDENSE_COUNTER_LAMBDA(tmp_count)
866  {
867 
868  // In case of the first, we need to add
869  int odeg = 0;
870  for (size_t k = 0u; k < Array.ncol(); ++k)
871  {
872 
873  if (k == i)
874  continue;
875 
876  if (Array(i, k) != BARRY_ZERO_NETWORK_DENSE)
877  odeg++;
878 
879  }
880 
881  if (odeg == 0)
882  return 0.0;
883 
884  if (odeg == 1)
885  return 1.0;
886 
887  return
888  pow(static_cast<double>(odeg), 1.5) -
889  pow(static_cast<double>(odeg - 1), 1.5)
890  ;
891 
892  };
893 
894  counters->add_counter(
895  tmp_count, nullptr, nullptr,
896  NetCounterData(),
897  "Outdegree^(1.5)"
898  );
899 
900  return;
901 
902 }
903 
904 
905 // -----------------------------------------------------------------------------
907 template<typename Tnet = Network>
908 inline void counter_absdiff(
910  size_t attr_id,
911  double alpha = 1.0
912 ) {
913 
914  NETWORK_COUNTER_LAMBDA(tmp_count)
915  {
916 
917  return std::pow(std::fabs(
918  Array.D_ptr()->vertex_attr[NET_C_DATA_IDX(0u)][i] -
919  Array.D_ptr()->vertex_attr[NET_C_DATA_IDX(0u)][j]
920  ), NET_C_DATA_NUM(0u));
921 
922  };
923 
924  NETWORK_COUNTER_LAMBDA(tmp_init)
925  {
926 
927  if (Array.D_ptr() == nullptr)
928  throw std::logic_error("The array data has not been initialized");
929 
930  if (Array.D_ptr()->vertex_attr.size() == 0u)
931  throw std::range_error("No attributes in the Array.");
932 
933  if ((NET_C_DATA_IDX(0u) != 0u) && (Array.D_ptr()->vertex_attr.size() <= (NET_C_DATA_IDX(0u) - 1u)))
934  throw std::range_error("Attribute index out of range.");
935 
936  return 0.0;
937 
938  };
939 
940  counters->add_counter(
941  tmp_count, tmp_init, nullptr,
942  NetCounterData({attr_id}, {alpha}),
943  "Absdiff"
944  );
945 
946  return;
947 
948 }
949 
950 // -----------------------------------------------------------------------------
952 template<typename Tnet = Network>
953 inline void counter_diff(
955  size_t attr_id,
956  double alpha = 1.0,
957  double tail_head = true
958 ) {
959 
960  NETWORK_COUNTER_LAMBDA(tmp_count)
961  {
962 
963  return std::pow(NET_C_DATA_NUM(1u) * (
964  Array.D_ptr()->vertex_attr[NET_C_DATA_IDX(0u)][i] -
965  Array.D_ptr()->vertex_attr[NET_C_DATA_IDX(0u)][j]
966  ), NET_C_DATA_NUM(0u));
967 
968  };
969 
970  NETWORK_COUNTER_LAMBDA(tmp_init)
971  {
972 
973  if (Array.D_ptr() == nullptr)
974  throw std::logic_error("The array data has not been initialized");
975 
976  if (Array.D_ptr()->vertex_attr.size() == 0u)
977  throw std::range_error("No attributes in the Array.");
978 
979  if ((NET_C_DATA_IDX(0u) != 0u) && (Array.D_ptr()->vertex_attr.size() <= (NET_C_DATA_IDX(0u) - 1u)))
980  throw std::range_error("Attribute index out of range.");
981 
982  return 0.0;
983 
984  };
985 
986  counters->add_counter(
987  tmp_count, tmp_init, nullptr,
988  NetCounterData({attr_id}, {alpha, tail_head ? 1.0: -1.0}),
989  "Absdiff^(" + std::to_string(alpha) + ")"
990  );
991 
992  return;
993 
994 }
995 
996 // Nodeicov, nodeocov, and Nodematch -------------------------------------------
997 NETWORK_COUNTER(init_single_attr)
998 {
999 
1000  if (Array.D_ptr() == nullptr)
1001  throw std::logic_error("The array data has not been initialized");
1002 
1003  if (Array.D_ptr()->vertex_attr.size() == 0u)
1004  throw std::range_error("No attributes in the Array.");
1005 
1006  if ((NET_C_DATA_IDX(0u) != 0u) && (Array.D_ptr()->vertex_attr.size() <= (NET_C_DATA_IDX(0u) - 1u)))
1007  throw std::range_error("Attribute index out of range.");
1008 
1009  return 0.0;
1010 
1011 }
1012 
1013 // -----------------------------------------------------------------------------
1014 //*@brief Attribute sum over receiver nodes */
1015 template<typename Tnet = Network>
1016 inline void counter_nodeicov(
1018  size_t attr_id
1019 ) {
1020 
1021  NETWORK_COUNTER_LAMBDA(tmp_count)
1022  {
1023 
1024  return Array.D_ptr()->vertex_attr[NET_C_DATA_IDX(0u)][j];
1025 
1026  };
1027 
1028  counters->add_counter(
1029  tmp_count, init_single_attr<Tnet>, nullptr,
1030  NetCounterData({attr_id}, {}),
1031  "nodeicov", "Sum of ego attribute"
1032  );
1033 
1034  return;
1035 
1036 }
1037 
1038 // -----------------------------------------------------------------------------
1039 //*@brief Attribute sum over sender nodes */
1040 template<typename Tnet = Network>
1041 inline void counter_nodeocov(
1043  size_t attr_id
1044 ) {
1045 
1046  NETWORK_COUNTER_LAMBDA(tmp_count)
1047  {
1048 
1049  return Array.D_ptr()->vertex_attr[NET_C_DATA_IDX(0u)][i];
1050 
1051  };
1052 
1053  counters->add_counter(
1054  tmp_count, init_single_attr<Tnet>, nullptr,
1055  NetCounterData({attr_id}, {}),
1056  "nodeocov", "Sum of alter attribute"
1057  );
1058 
1059  return;
1060 
1061 }
1062 
1063 // -----------------------------------------------------------------------------
1064 //*@brief Attribute sum over receiver and sender nodes */
1065 template<typename Tnet = Network>
1066 inline void counter_nodecov(
1068  size_t attr_id
1069 ) {
1070 
1071  NETWORK_COUNTER_LAMBDA(tmp_count)
1072  {
1073 
1074  return Array.D_ptr()->vertex_attr[NET_C_DATA_IDX(0u)][i] +
1075  Array.D_ptr()->vertex_attr[NET_C_DATA_IDX(0u)][j];
1076 
1077  };
1078 
1079  counters->add_counter(
1080  tmp_count, init_single_attr<Tnet>, nullptr,
1081  NetCounterData({attr_id}, {}),
1082  "nodecov", "Sum of nodes covariates"
1083  );
1084 
1085  return;
1086 }
1087 
1088 // -----------------------------------------------------------------------------
1089 //* @brief Number of homophililic ties */
1090 template<typename Tnet = Network>
1091 inline void counter_nodematch(
1093  size_t attr_id
1094 ) {
1095 
1096  NETWORK_COUNTER_LAMBDA(tmp_count)
1097  {
1098 
1099  return
1100  (
1101  Array.D_ptr()->vertex_attr[NET_C_DATA_IDX(0u)][i] ==
1102  Array.D_ptr()->vertex_attr[NET_C_DATA_IDX(0u)][j]
1103  )? 1.0 : 0.0;
1104 
1105  };
1106 
1107  // Preparing the counter data and returning. We make sure that the memory is
1108  // released so we set delete_data = true.
1109  counters->add_counter(
1110  tmp_count, init_single_attr<Tnet>, nullptr,
1111  NetCounterData({attr_id}, {}),
1112  "Homophily",
1113  "Number of homophilic ties"
1114  );
1115 
1116  return ;
1117 
1118 }
1119 
1120 // -----------------------------------------------------------------------------
1122 template<typename Tnet = Network>
1123 inline void counter_idegree(
1125  std::vector< size_t > d
1126 ) {
1127 
1128  NETWORK_COUNTER_LAMBDA(tmp_count)
1129  {
1130 
1131  size_t d = Array.col(j).size();
1132  if (d == NET_C_DATA_IDX(0u))
1133  return 1.0;
1134  else if (d == (NET_C_DATA_IDX(0u) + 1))
1135  return -1.0;
1136 
1137  return 0.0;
1138 
1139  };
1140 
1141  NETWORK_COUNTER_LAMBDA(tmp_init)
1142  {
1143 
1144  if (Array.D_ptr() == nullptr)
1145  throw std::logic_error("The array data has not been initialized");
1146 
1147  if (!Array.D_ptr()->directed)
1148  throw std::logic_error("-odegree- counter is only valid for directed graphs");
1149 
1150  if (NET_C_DATA_IDX(0u) == 0u)
1151  return static_cast<double>(Array.nrow());
1152 
1153  return 0.0;
1154 
1155  };
1156 
1157  for (auto iter = d.begin(); iter != d.end(); ++iter)
1158  counters->add_counter(
1159  tmp_count, tmp_init, nullptr,
1160  NetCounterData({*iter}, {}),
1161  "Nodes indeg " + std::to_string(*iter),
1162  "Number of nodes with indigree " + std::to_string(*iter)
1163  );
1164 
1165  return;
1166 
1167 }
1168 
1169 template<>
1170 inline void counter_idegree(
1172  std::vector< size_t > d
1173 ) {
1174 
1175  NETWORKDENSE_COUNTER_LAMBDA(tmp_count)
1176  {
1177 
1178  size_t indeg = 0u;
1179  for (size_t k = 0u; k < Array.nrow(); ++k)
1180  if (Array(k, j) != BARRY_ZERO_NETWORK_DENSE)
1181  indeg++;
1182 
1183  if (indeg == NET_C_DATA_IDX(0u))
1184  return 1.0;
1185  else if (indeg == (NET_C_DATA_IDX(0u) + 1))
1186  return -1.0;
1187 
1188  return 0.0;
1189 
1190  };
1191 
1192  NETWORKDENSE_COUNTER_LAMBDA(tmp_init)
1193  {
1194 
1195  if (Array.D_ptr() == nullptr)
1196  throw std::logic_error("The array data has not been initialized");
1197 
1198  if (!Array.D_ptr()->directed)
1199  throw std::logic_error("-odegree- counter is only valid for directed graphs");
1200 
1201  if (NET_C_DATA_IDX(0u) == 0u)
1202  return static_cast<double>(Array.nrow());
1203 
1204  return 0.0;
1205 
1206  };
1207 
1208  for (auto iter = d.begin(); iter != d.end(); ++iter)
1209  counters->add_counter(
1210  tmp_count, tmp_init, nullptr,
1211  NetCounterData({*iter}, {}),
1212  "Nodes indeg " + std::to_string(*iter),
1213  "Number of nodes with indigree " + std::to_string(*iter)
1214  );
1215 
1216  return;
1217 
1218 }
1219 
1220 // -----------------------------------------------------------------------------
1222 template<typename Tnet = Network>
1223 inline void counter_odegree(
1225  std::vector<size_t> d
1226 ) {
1227 
1228  NETWORK_COUNTER_LAMBDA(tmp_count)
1229  {
1230 
1231  size_t d = Array.row(i).size();
1232  if (d == NET_C_DATA_IDX(0u))
1233  return 1.0;
1234  else if (d == (NET_C_DATA_IDX(0u) + 1))
1235  return -1.0;
1236 
1237  return 0.0;
1238 
1239  };
1240 
1241  NETWORK_COUNTER_LAMBDA(tmp_init)
1242  {
1243 
1244  if (Array.D_ptr() == nullptr)
1245  throw std::logic_error("The array data has not been initialized");
1246 
1247  if (!Array.D_ptr()->directed)
1248  throw std::logic_error("-odegree- counter is only valid for directed graphs");
1249 
1250  if (NET_C_DATA_IDX(0u) == 0u)
1251  return static_cast<double>(Array.nrow());
1252 
1253  return 0.0;
1254 
1255  };
1256 
1257 
1258  for (auto iter = d.begin(); iter != d.end(); ++iter)
1259  counters->add_counter(
1260  tmp_count, tmp_init, nullptr,
1261  NetCounterData({*iter}, {}),
1262  "Nodes w/ outdeg " + std::to_string(*iter),
1263  "Number of nodes with outdegree " + std::to_string(*iter)
1264  );
1265 
1266  return;
1267 
1268 }
1269 
1270 template<>
1271 inline void counter_odegree(
1273  std::vector<size_t> d
1274 ) {
1275 
1276  NETWORKDENSE_COUNTER_LAMBDA(tmp_count)
1277  {
1278 
1279  size_t d = 0;
1280  for (size_t k = 0u; k < Array.ncol(); ++k)
1281  if (Array(i, k) != BARRY_ZERO_NETWORK_DENSE)
1282  d++;
1283 
1284  if (d == NET_C_DATA_IDX(0u))
1285  return 1.0;
1286  else if (d == (NET_C_DATA_IDX(0u) + 1))
1287  return -1.0;
1288 
1289  return 0.0;
1290 
1291  };
1292 
1293  NETWORKDENSE_COUNTER_LAMBDA(tmp_init)
1294  {
1295 
1296  if (Array.D_ptr() == nullptr)
1297  throw std::logic_error("The array data has not been initialized");
1298 
1299  if (!Array.D_ptr()->directed)
1300  throw std::logic_error("-odegree- counter is only valid for directed graphs");
1301 
1302  if (NET_C_DATA_IDX(0u) == 0u)
1303  return static_cast<double>(Array.nrow());
1304 
1305  return 0.0;
1306 
1307  };
1308 
1309 
1310  for (auto iter = d.begin(); iter != d.end(); ++iter)
1311  counters->add_counter(
1312  tmp_count, tmp_init, nullptr,
1313  NetCounterData({*iter}, {}),
1314  "Nodes w/ outdeg " + std::to_string(*iter),
1315  "Number of nodes with outdegree " + std::to_string(*iter)
1316  );
1317 
1318  return;
1319 
1320 }
1321 
1322 
1323 // -----------------------------------------------------------------------------
1325 template<typename Tnet = Network>
1326 inline void counter_degree(
1328  std::vector<size_t> d
1329 ) {
1330 
1331  NETWORK_COUNTER_LAMBDA(tmp_count) {
1332 
1333  size_t d = Array.row(i).size();
1334  if (d == NET_C_DATA_IDX(0u))
1335  return 1.0;
1336  else if (d == (NET_C_DATA_IDX(0u) + 1))
1337  return -1.0;
1338 
1339  return 0.0;
1340  };
1341 
1342  NETWORK_COUNTER_LAMBDA(tmp_init) {
1343 
1344  if (Array.D_ptr() == nullptr)
1345  throw std::logic_error("The array data has not been initialized");
1346 
1347  if (Array.D_ptr()->directed)
1348  throw std::logic_error("-degree- counter is only valid for undirected graphs");
1349 
1350  if (NET_C_DATA_IDX(0u) == 0u)
1351  return static_cast<double>(Array.nrow());
1352 
1353  return 0.0;
1354  };
1355 
1356 
1357  for (auto iter = d.begin(); iter != d.end(); ++iter)
1358  {
1359  counters->add_counter(
1360  tmp_count, tmp_init, nullptr,
1361  NetCounterData({*iter}, {})
1362  );
1363  }
1364 
1365  return;
1366 }
1367 
1368 #include "network-css.hpp"
1369 
1371 
1372 
1378 // -----------------------------------------------------------------------------
1380 template<typename Tnet = Network>
1381 inline void rules_zerodiag(NetRules<Tnet> * rules) {
1382 
1383  NETWORK_RULE_LAMBDA(no_self_tie) {
1384  return i != j;
1385  };
1386 
1387  rules->add_rule(
1388  no_self_tie, false,
1389  "No self-ties",
1390  "No self-ties"
1391  );
1392 
1393  return;
1394 }
1395 
1397 
1399 
1400 #undef NET_C_DATA_IDX
1401 #undef NET_C_DATA_NUM
1402 
1403 #endif
Baseline class for binary arrays.
Baseline class for binary arrays.
A counter function based on change statistics.
Vector of counters.
General framework for discrete exponential models. This class allows generating discrete exponential ...
Definition: model-bones.hpp:34
Data class used to store arbitrary size_t or double vectors.
Definition: network.hpp:56
std::vector< size_t > indices
Definition: network.hpp:59
NetCounterData(const std::vector< size_t > &indices_, const std::vector< double > &numbers_)
Definition: network.hpp:63
std::vector< double > numbers
Definition: network.hpp:60
Data class for Networks.
Definition: network.hpp:19
std::vector< std::vector< double > > vertex_attr
Definition: network.hpp:23
NetworkData(std::vector< double > vertex_attr_, bool directed_=true)
Constructor using a single attribute.
Definition: network.hpp:33
~NetworkData()
Definition: network.hpp:51
bool directed
Definition: network.hpp:22
NetworkData(std::vector< std::vector< double > > vertex_attr_, bool directed_=true)
Constructor using multiple attributes.
Definition: network.hpp:45
Rule for determining if a cell should be included in a sequence.
Definition: rules-bones.hpp:20
Vector of objects of class Rule.
Definition: rules-bones.hpp:71
void add_rule(Rule< Array_Type, Data_Type > rule)
Definition: rules-meat.hpp:72
Count stats for a single Array.
Compute the support of sufficient statistics.
return res
return
size_t size_t j
size_t i
void counter_nodematch(NetCounters< Tnet > *counters, size_t attr_id)
Definition: network.hpp:1091
void counter_idegree(NetCounters< Tnet > *counters, std::vector< size_t > d)
Counts number of vertices with a given in-degree.
Definition: network.hpp:1123
void counter_istar2(NetCounters< Tnet > *counters)
Definition: network.hpp:312
void counter_mutual(NetCounters< Tnet > *counters)
Number of mutual ties.
Definition: network.hpp:256
void counter_ostar2(NetCounters< Tnet > *counters)
Definition: network.hpp:376
void counter_nodeicov(NetCounters< Tnet > *counters, size_t attr_id)
Definition: network.hpp:1016
void counter_ttriads(NetCounters< Tnet > *counters)
Definition: network.hpp:441
void counter_odegree(NetCounters< Tnet > *counters, std::vector< size_t > d)
Counts number of vertices with a given out-degree.
Definition: network.hpp:1223
void counter_density(NetCounters< Tnet > *counters)
Definition: network.hpp:729
void counter_ctriads(NetCounters< Tnet > *counters)
Definition: network.hpp:610
void counter_degree(NetCounters< Tnet > *counters, std::vector< size_t > d)
Counts number of vertices with a given out-degree.
Definition: network.hpp:1326
void counter_isolates(NetCounters< Tnet > *counters)
Number of isolated vertices.
Definition: network.hpp:175
void counter_nodecov(NetCounters< Tnet > *counters, size_t attr_id)
Definition: network.hpp:1066
void counter_edges(NetCounters< Tnet > *counters)
Number of edges.
Definition: network.hpp:152
void counter_diff(NetCounters< Tnet > *counters, size_t attr_id, double alpha=1.0, double tail_head=true)
Sum of attribute difference between ego and alter to pow(alpha)
Definition: network.hpp:953
void counter_absdiff(NetCounters< Tnet > *counters, size_t attr_id, double alpha=1.0)
Sum of absolute attribute difference between ego and alter.
Definition: network.hpp:908
void counter_nodeocov(NetCounters< Tnet > *counters, size_t attr_id)
Definition: network.hpp:1041
void counter_odegree15(NetCounters< Tnet > *counters)
Definition: network.hpp:834
void counter_idegree15(NetCounters< Tnet > *counters)
Definition: network.hpp:757
#define NETWORKDENSE_COUNTER_LAMBDA(a)
Definition: network.hpp:123
#define BARRY_ZERO_NETWORK_DENSE
Definition: network.hpp:86
#define NETWORK_RULE_LAMBDA(a)
Definition: network.hpp:138
#define NETWORK_COUNTER_LAMBDA(a)
Definition: network.hpp:119
BArrayDense< int, NetworkData > NetworkDense
Definition: network.hpp:83
#define NET_C_DATA_IDX(i)
Definition: network.hpp:74
BArray< double, NetworkData > Network
Definition: network.hpp:82
#define NET_C_DATA_NUM(i)
Definition: network.hpp:75
#define NETWORK_COUNTER(a)
Definition: network.hpp:114
void rules_zerodiag(NetRules< Tnet > *rules)
Number of edges.
Definition: network.hpp:1381