barry: Your go-to motif accountant  0.0-1
Full enumeration of sample space and fast count of sufficient statistics for binary arrays
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