oaqc/0000755000176200001440000000000014700737462011207 5ustar liggesusersoaqc/tests/0000755000176200001440000000000014677305315012352 5ustar liggesusersoaqc/tests/testthat/0000755000176200001440000000000014700737462014211 5ustar liggesusersoaqc/tests/testthat/test-oaqc.R0000644000176200001440000000110314677306124016227 0ustar liggesuserstest_that("oaqc works", { coC4 <- data.frame( source = c(0, 2), target = c(1, 3) ) coC4orbits <- oaqc(coC4, non_ind_freq = FALSE) expect_true(all(coC4orbits$n_orbits_ind[, 4] == 1)) expect_true(all(coC4orbits$e_orbits_ind[, 2] == 1)) expect_error(oaqc("graph")) k4 <- as.matrix(data.frame( source = c(0, 0, 0, 1, 1, 2), target = c(1, 2, 3, 2, 3, 3) )) k4orbits <- oaqc(k4, non_ind_freq = FALSE) expect_true(all(k4orbits$n_orbits_ind[, 20] == 1)) expect_true(all(k4orbits$e_orbits_ind[, 14] == 1)) }) oaqc/tests/testthat.R0000644000176200001440000000060414677305315014335 0ustar liggesusers# This file is part of the standard setup for testthat. # It is recommended that you do not modify it. # # Where should you do additional test configuration? # Learn more about the roles of various files in: # * https://r-pkgs.org/testing-design.html#sec-tests-files-overview # * https://testthat.r-lib.org/articles/special-files.html library(testthat) library(oaqc) test_check("oaqc") oaqc/MD50000644000176200001440000000227114700737462011521 0ustar liggesusers2eae1980d7bcabfe6023d290de250353 *DESCRIPTION e87b550441993ea6df5f98497da449df *NAMESPACE 324c7d7896b7933c888d451b6f83b2e2 *NEWS.md a029bb9e509983a34a0ddea24727fba7 *R/oaqc.R 70a34c6e2cbe3e9aae6cabe7066ffc71 *README.md aa5e5a2cbfaea3d9b6cdbe378ac48cee *build/partial.rdb 968e50937d1e6721e7570edda3769b86 *build/vignette.rds e0fa004a584de829f068b440e388387f *inst/CITATION 35bf01cb27020a2f94243da26fb92aa3 *inst/doc/oaqc.R 3f9162f6c039feace6e0430885cca698 *inst/doc/oaqc.Rmd 976b3117c819cb14a3cff5bcbd4adf18 *inst/doc/oaqc.html 951255bc9940f9a0b7474cf60c1e4f04 *man/annotate_result.Rd 9f43fca0155550166f49dff3df610e16 *man/as.edge_list.Rd bc3347019390f3be5605d963c75aa9d2 *man/figures/logo.png c94cc0d66e950fdef762b86d6f29f729 *man/oaqc.Rd 0f8e051f005a98eb1208ba412cc99182 *src/Graph.cpp 1a7fe775551c166fd3fbbab2ef9a4282 *src/Graph.h a214bebab822e7bd9490b30ca01264d1 *src/QuadCensus.cpp 7d830d45ff00e5318585128b459889c8 *src/QuadCensus.h cfb108949381a6d08ae23af65bce4acf *src/init.cpp d00c8f3b6e8a430be1f7659627b8923e *tests/testthat.R 03bf4fc6668a5276231dbcce32fb4eff *tests/testthat/test-oaqc.R 3f9162f6c039feace6e0430885cca698 *vignettes/oaqc.Rmd 030bf730b7fd86c36f93b19122c74438 *vignettes/quad_census.svg oaqc/R/0000755000176200001440000000000014674505364011414 5ustar liggesusersoaqc/R/oaqc.R0000644000176200001440000000676114674507560012474 0ustar liggesusers#' @title Orbit-aware Quad Census computation #' @name oaqc #' @useDynLib oaqc, .registration=T "_PACKAGE" #' Coerce graph input. #' #' @param graph A matrix, data.frame or graph object. #' @return Edge list matrix. as.edge_list <- function(graph) { if (is.matrix(graph)) { if (length(dim(graph)) != 2 && ncol(graph) != 2) { stop(paste( "not coercable to edge list", "only matrices with 2 columns supported" )) } graph } else if (is.data.frame(graph)) { if (ncol(graph) != 2) { stop(paste( "not coercable to edge list", "only data frames with 2 columns supported" )) } data.matrix(graph) } else if (inherits(graph, "igraph") && requireNamespace("igraph", quietly = TRUE)) { igraph::as_edgelist(graph) - 1 } else { stop(paste( "unrecognized graph type", "use matrix/data frame with 2 columns or igraph objects" )) } } #' Annotates the igraph object with orbit labels. #' #' @param graph Unmodified input graph. #' @param orbits List with n_orbits, e_orbits matrices. #' @param non_ind_freq A flag indicating whether non-induced frequencies have to be written or not. #' @return \code{orbits} if the input is not an igraph, the annotated igraph #' instead. annotate_result <- function(graph, orbits, non_ind_freq) { if (inherits(graph, "igraph") && requireNamespace("igraph", quietly = T)) { for (i in seq_len(ncol(orbits$n_orbits_ind))) { graph <- igraph::set_vertex_attr(graph, paste("orbit_ind", i, sep = "_"), value = orbits$n_orbits_ind[, i] ) } for (i in seq_len(col(orbits$e_orbits_ind))) { graph <- igraph::set_edge_attr(graph, paste("orbit_ind", i, sep = "_"), value = orbits$e_orbits_ind[, i] ) } if (non_ind_freq) { for (i in seq_len(ncol(orbits$`n_orbits_non_ind`))) { graph <- igraph::set_vertex_attr(graph, paste("orbit_non_ind", i, sep = "_"), value = orbits$`n_orbits_non_ind`[, i] ) } for (i in seq_len(ncol(orbits$`e_orbits_non_ind`))) { graph <- igraph::set_edge_attr(graph, paste("orbit_non_ind", i, sep = "_"), value = orbits$`e_orbits_non_ind`[, i] ) } } return(graph) } return(orbits) } #' Calculates the orbit-aware quad census on an edge and node level, see #' \code{vignette('oaqc')}. #' #' @param graph A matrix, data.frame or graph object. #' @param non_ind_freq A flag indicating whether non-induced frequencies have to be returned or not. #' @param file Name (and location) of the file to be written. #' @return orbit-aware quad census on a node and edge level. Consult #' \code{vignette('oaqc')} to see the correspondence between orbit and quad. #' @examples #' k4 <- data.frame( #' source = c(0, 0, 0, 1, 1, 2), #' target = c(1, 2, 3, 2, 3, 3) #' ) #' #' k4orbits <- oaqc(k4, non_ind_freq = TRUE) #' print(k4orbits) #' @export oaqc <- function(graph, non_ind_freq = F, file = "") { edges <- as.edge_list(graph) orbits <- .Call( entry, as.integer(max(edges) + 1), as.integer(edges), as.logical(non_ind_freq), as.character(file) ) return(annotate_result(graph, orbits, as.logical(non_ind_freq))) } oaqc/vignettes/0000755000176200001440000000000014700723647013217 5ustar liggesusersoaqc/vignettes/oaqc.Rmd0000644000176200001440000000323414674530710014605 0ustar liggesusers--- title: "Introduction to oaqc" author: "Mark Ortmann" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{oaqc} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- # Introduction to oaqc This package provides an efficient algorithm to calculate for a given graph the **o**rbit-**a**ware **q**uad **c**ensus. More precisely the frequency distribution of all induced and non-induced non-isomorphic four node subgraphs, i.e. quads, on a node and edge level; see the figure below for the relation between orbit and quad. ![quad census](quad_census.svg) ## Input The input can either be an edgelist (matrix or data.frame) or a graph Object ('igraph') Despite the input format the graph should not contain loops or multi-edges and the vertex indices have to lie in range [0,n-1) with n denoting the number of vertices in the graph. Note that if the smallest index is 1 the algorithm will create an isolated vertex with index 0. ## Calculating the orbit-aware quad census The following code exemplifies the use of this package. ```{r} library(oaqc) ### k4, pure R k4 <- data.frame( source = c(0, 0, 0, 1, 1, 2), target = c(1, 2, 3, 2, 3, 3) ) k4orbits <- oaqc(k4, non_ind_freq = FALSE, file = "") # print(k4orbits) ``` In order to calculate the non-induced frequencies as well just set the corresponding flag to `TRUE`. Since the orbit-aware frequencies can be rather large integers, which can cause some problems with R, the results can be directly written to a file. ## Result The results of the, e.g., induced frequencies of the nodes in orbit 10 can be accessed in the following way. ```{r} print(k4orbits$n_orbits_ind[, 10]) ```oaqc/vignettes/quad_census.svg0000644000176200001440000023573213202564173016257 0ustar liggesusers image/svg+xml1 1 1 1 co- K 4 2 3 2 3 1 co-diamond 4 4 4 4 2 2 co- C 4 6 5 7 6 3 3 co-paw 8 8 9 8 4 4 4 co-claw 10 10 11 11 6 5 5 P 4 12 13 13 13 7 7 7 claw 14 15 16 15 9 8 9 10 paw 17 17 17 17 11 11 11 11 C 4 18 19 19 18 12 12 12 12 13 diamond 20 20 20 20 14 14 14 14 14 14 K 4 Figure: All non-isomorphic subgraph with four nodes (quads). Node and edgelabels refer to the orbits (different automorphism classes in each quad) andwere enumerated such that each orbit is identified with a single quad. oaqc/src/0000755000176200001440000000000014700723647011776 5ustar liggesusersoaqc/src/init.cpp0000644000176200001440000000772314674505311013452 0ustar liggesusers#define R_NO_REMAP #include #include #include #include #include // for NULL #include #include #include "QuadCensus.h" using namespace std; using namespace oaqc; static SEXP c_to_r(const unsigned int* const rMap, const unsigned long* orbit, unsigned int size, unsigned long orbitCount) { const unsigned long len = size * orbitCount; SEXP rvec = PROTECT(Rf_allocVector(REALSXP, len)); // set dimensions SEXP dim = PROTECT(Rf_allocVector(INTSXP, 2)); INTEGER(dim)[0] = size; INTEGER(dim)[1] = orbitCount; Rf_setAttrib(rvec, R_DimSymbol, dim); // copy (cast and transpose) data double* data = REAL(rvec); unsigned int j = 0; for (unsigned int o = 0; o < orbitCount; ++o) { for (unsigned int i = 0; i < size; ++i) { unsigned int pos = i; if (rMap != NULL) { pos = rMap[i]; } data[j++] = (double)orbit[pos * orbitCount + o]; } } UNPROTECT(2); return rvec; } static void write_to_file(string fName, const unsigned int* const rMap, const unsigned long* orbit, unsigned int size, unsigned long orbitCount) { ofstream writer; // open the writer writer.open(fName.c_str()); if (!writer.is_open()) { throw ios_base::failure("cannot open " + fName); } for (unsigned int o = 0; o < orbitCount - 1; ++o) { writer << "orbit_" << o << ";"; } writer << "orbit_" << (orbitCount - 1) << std::endl; for (unsigned int i = 0; i < size; ++i) { unsigned int pos = i; if (rMap != NULL) { pos = rMap[i]; } for (unsigned int o = 0; o < orbitCount - 1; ++o) { writer << orbit[pos * orbitCount + o] << ";"; } writer << orbit[pos * orbitCount + orbitCount - 1] << std::endl; } // flush and close writer.flush(); writer.close(); } static void write_results(SEXP& a_value, SEXP& a_names, unsigned int& sIndex, const unsigned int n, const unsigned int m, QuadCensus& qc, string& filePrefix, string rType) { if (!filePrefix.empty()) { write_to_file(filePrefix + "_n_orbits_" + rType + ".csv", qc.getMapping(), qc.nOrbits(), n, qc.getNOrbitCount()); write_to_file(filePrefix + "_e_orbits_" + rType + ".csv", NULL, qc.eOrbits(), m, qc.getEOrbitCount()); } SET_STRING_ELT(a_names, sIndex, Rf_mkChar(("n_orbits_" + rType).c_str())); SET_VECTOR_ELT(a_value, sIndex, c_to_r(qc.getMapping(), qc.nOrbits(), n, qc.getNOrbitCount())); ++sIndex; SET_STRING_ELT(a_names, sIndex, Rf_mkChar(("e_orbits_" + rType).c_str())); SET_VECTOR_ELT(a_value, sIndex, c_to_r(NULL, qc.eOrbits(), m, qc.getEOrbitCount())); ++sIndex; } extern "C" SEXP entry(SEXP a_n, SEXP a_edges, SEXP a_freqFlag, SEXP a_file) { const unsigned int n = INTEGER(a_n)[0]; const unsigned int m = Rf_length(a_edges) / 2; const int* edges = INTEGER(a_edges); string filePrefix(CHAR(STRING_ELT(a_file, 0))); const bool wNonIndFreq = LOGICAL(a_freqFlag)[0]; unsigned int res_size; if (wNonIndFreq) { res_size = 4; } else { res_size = 2; } QuadCensus qc(n, m, edges); SEXP value = PROTECT(Rf_allocVector(VECSXP, res_size)); // VECSXP == list SEXP names = PROTECT(Rf_allocVector(STRSXP, res_size)); unsigned int pos = 0; if (wNonIndFreq) { write_results(value, names, pos, n, m, qc, filePrefix, "non_ind"); } qc.calcInducedFrequencies(); write_results(value, names, pos, n, m, qc, filePrefix, "ind"); Rf_setAttrib(value, R_NamesSymbol, names); UNPROTECT(2); return value; } #define CALLDEF(name, n) {#name, (DL_FUNC) & name, n} static const R_CallMethodDef CallEntries[] = {CALLDEF(entry, 4), {NULL, NULL, 0}}; extern "C" void R_init_oaqc(DllInfo* dll) { R_registerRoutines(dll, NULL, CallEntries, NULL, NULL); R_useDynamicSymbols(dll, FALSE); R_forceSymbols(dll, TRUE); } oaqc/src/QuadCensus.h0000644000176200001440000000310714674505321014220 0ustar liggesusers/* * QuadCensus.h * * Created on: 14 Sep 2017 * Author: ortmann */ #ifndef QUADCENSUS_H_ #define QUADCENSUS_H_ #include "Graph.h" namespace oaqc { #define N_ORBIT(nIndex,orbit) _nOrbits[nIndex * _nodeOrbitCount + orbit] #define E_ORBIT(eIndex,orbit) _eOrbits[eIndex * _edgeOrbitCount + orbit] class QuadCensus { public: QuadCensus(const unsigned int n, const unsigned int m, const int * const edges); virtual ~QuadCensus(); const unsigned long getNOrbitCount() const{ return _nodeOrbitCount; } const unsigned long getEOrbitCount() const { return _edgeOrbitCount; } const unsigned int* getMapping() const{ return _graph.getMapping(); } const unsigned long* eOrbits(); const unsigned long* nOrbits(); void calcInducedFrequencies(); private: const unsigned long _nodeOrbitCount; const unsigned long _edgeOrbitCount; unsigned long* _eTriCount; unsigned long* _nTriCount; unsigned long* _nNonIndC4Count; unsigned long* _eNonIndC4Count; unsigned long* _eOrbits; unsigned long* _nOrbits; unsigned long* _neighDeg; unsigned long long _k3Count; unsigned long long _2pathCount; const Graph _graph; void init(); void clear(); void initCounts(); void calcK3K4C4(); void calcK3RelNonIndCounts(); void calcNonInducedFrequencies(); inline unsigned long choose2(const unsigned long val) { if (val < 1) { return 0; } return (val * (val - 1)) / 2; } inline unsigned long choose3(const unsigned long val) { if (val < 3) { return 0; } return (val * (val - 1) * (val - 2)) / 6; } }; } /* namespace oaqc */ #endif /* QUADCENSUS_H_ */ oaqc/src/Graph.h0000644000176200001440000000261514674505277013223 0ustar liggesusers/* * Graph.h * * Created on: 14 Sep 2017 * Author: ortmann */ #ifndef GRAPH_H_ #define GRAPH_H_ #include typedef std::pair< unsigned int, unsigned int> Edge; namespace oaqc { class Graph { public: Graph(const unsigned int n, const unsigned int m, const int * const edges); virtual ~Graph(); Edge* const _edges; // TODO private inline const unsigned int* const getMapping() const{ return _mapping; } inline unsigned int n() const { return _n; } inline unsigned int m() const { return _m; } inline unsigned int firstInEdge(const unsigned int v) const { return _inOffset[v]; } inline unsigned int lastInEdge(const unsigned int v) const { return _outOffset[v]; } inline unsigned int firstOutEdge(const unsigned int v) const { return _outOffset[v]; } inline unsigned int lastOutEdge(const unsigned int v) const { return _inOffset[v + 1]; } inline unsigned int opInd(const unsigned int pos) const { return _edges[pos].first; } inline unsigned int edgeInd(const unsigned int pos) const { return _edges[pos].second; } private: unsigned const int _n; unsigned const int _m; unsigned int* const _inOffset; unsigned int* const _outOffset; unsigned int* const _mapping; void createGraph(const int * const edges); void bucketSort(const int * const edges); }; } /* namespace oaqc */ #endif /* GRAPH_H_ */ oaqc/src/Graph.cpp0000644000176200001440000000506514674505277013560 0ustar liggesusers/* * Graph.cpp * * Created on: 14 Sep 2017 * Author: ortmann */ #include "Graph.h" #include namespace oaqc { Graph::Graph(const unsigned int n, const unsigned int m, const int* const edges) : _edges(new Edge[2 * m]), // _n(n), // _m(m), // _inOffset(new unsigned int[n + 1]), // _outOffset(new unsigned int[n]), // _mapping(new unsigned int[n]) { // used to find the highest indexed outgoing edge _inOffset[_n] = 2 * _m; createGraph(edges); } Graph::~Graph() { delete[] _mapping; delete[] _outOffset; delete[] _inOffset; delete[] _edges; } void Graph::createGraph(const int* const edges) { bucketSort(edges); // store the graph for (unsigned int i = 0; i < _m; ++i) { const unsigned int n1 = _mapping[edges[i]]; const unsigned int n2 = _mapping[edges[i + _m]]; _edges[_outOffset[n1]].first = n2; _edges[_outOffset[n1]].second = i; ++_outOffset[n1]; _edges[_outOffset[n2]].first = n1; _edges[_outOffset[n2]].second = i; ++_outOffset[n2]; } // sort the edges according the opposite indices for (unsigned int i = 0; i < _n; ++i) { // this works since all ids are unique => second values are never compared // set the outOffset std::sort(_edges + _inOffset[i], _edges + _inOffset[i + 1]); for (unsigned int pos = _inOffset[i]; pos < _inOffset[i + 1]; ++pos) { if (_edges[pos].first > i) { _outOffset[i] = pos; break; } } } } void Graph::bucketSort(const int* const edges) { // calculate node degrees unsigned int* const deg = new unsigned int[_n](); for (unsigned int i = 0; i < _m; ++i) { ++deg[edges[i]]; ++deg[edges[i + _m]]; } // init the buckets array unsigned int maxDegree = 0; for (unsigned int i = 0; i < _n; ++i) { maxDegree = std::max(maxDegree, deg[i]); } unsigned int* const bucket = new unsigned int[maxDegree + 1](); // compute size of each bucket for (unsigned int i = 0; i < _n; ++i) { ++bucket[deg[i]]; } unsigned int first = 0; unsigned int size; // calculate the lower end point of each bucket for (unsigned int i = 0; i <= maxDegree; ++i) { size = bucket[i]; bucket[i] = first; first += size; } unsigned int* const reverseMapping = new unsigned int[_n]; for (unsigned int i = 0; i < _n; ++i) { const unsigned int degree = deg[i]; unsigned int pos = bucket[degree]; _mapping[i] = pos; reverseMapping[pos] = i; ++bucket[degree]; } unsigned int m = 0; for (unsigned int i = 0; i < _n; ++i) { _inOffset[i] = m; _outOffset[i] = m; m += deg[reverseMapping[i]]; } delete[] bucket; delete[] deg; delete[] reverseMapping; } } /* namespace oaqc */ oaqc/src/QuadCensus.cpp0000644000176200001440000003560414674505321014562 0ustar liggesusers/* * QuadCensus.cpp * * Created on: 14 Sep 2017 * Author: ortmann */ #include "QuadCensus.h" #include #include "Graph.h" namespace oaqc { QuadCensus::QuadCensus(const unsigned int n, const unsigned int m, const int * const edges) : _nodeOrbitCount(20), // _edgeOrbitCount(14), // _eTriCount(0), // _nTriCount(0), // _nNonIndC4Count(0), // _eNonIndC4Count(0), // _eOrbits(0), // _nOrbits(0), // _neighDeg(0), // _k3Count(0), // _2pathCount(0),// _graph(n,m,edges){ init(); initCounts(); calcK3K4C4(); calcK3RelNonIndCounts(); calcNonInducedFrequencies(); } QuadCensus::~QuadCensus() { clear(); } const unsigned long* QuadCensus::eOrbits() { return _eOrbits; } const unsigned long* QuadCensus::nOrbits() { return _nOrbits; } void QuadCensus::init() { const unsigned int n = _graph.n(); const unsigned int m = _graph.m(); _eTriCount = new unsigned long[m](); _nTriCount = new unsigned long[n](); _eNonIndC4Count = new unsigned long[m](); _nNonIndC4Count = new unsigned long[n](); _eOrbits = new unsigned long[_edgeOrbitCount * m](); _nOrbits = new unsigned long[_nodeOrbitCount * n](); _neighDeg = new unsigned long[n](); } void QuadCensus::clear() { delete[] _eTriCount; delete[] _nTriCount; delete[] _nNonIndC4Count; delete[] _eNonIndC4Count; delete[] _eOrbits; delete[] _nOrbits; delete[] _neighDeg; } void QuadCensus::initCounts() { for (unsigned int i = 0; i < _graph.n(); ++i) { const unsigned long deg = _graph.lastOutEdge(i) - _graph.firstInEdge(i); _2pathCount += choose2(deg); N_ORBIT(i, 11)= choose3 (deg); const unsigned int endInd = _graph.lastInEdge(i); for (unsigned int neigh = _graph.firstInEdge(i); neigh < endInd; ++neigh) { const unsigned int neighInd = _graph.opInd(neigh); _neighDeg[i] += _graph.lastOutEdge(neighInd) - _graph.firstInEdge(neighInd); _neighDeg[neighInd] += deg; } } } void QuadCensus::calcK3K4C4() { int* const innerMark = new int[_graph.n()]; std::fill_n(innerMark, _graph.n(), -1); int* const outerMark = new int[_graph.n()]; std::fill_n(outerMark, _graph.n(), -1); unsigned int* const visCount = new unsigned int[_graph.n()](); unsigned int* const workCount = new unsigned int[_graph.n()](); for (unsigned int t4 = 1; t4 < _graph.n(); ++t4) { const unsigned int t4StartIncInd = _graph.firstInEdge(t4); const unsigned int t4EndIncInd = _graph.lastInEdge(t4); // mark the edges for (unsigned int i = t4StartIncInd; i < t4EndIncInd; i++) { outerMark[_graph.opInd(i)] = _graph.edgeInd(i); } // now find K3, K4, C4 for (unsigned int t1EdgeInd = t4StartIncInd; t1EdgeInd < t4EndIncInd; ++t1EdgeInd) { unsigned int t1 = _graph.opInd(t1EdgeInd); unsigned int l = outerMark[t1]; outerMark[t1] = -1; unsigned int t1StartIncInd = _graph.firstInEdge(t1); unsigned int t1StartOutInd = _graph.firstOutEdge(t1); // for C4 counting for (; t1StartIncInd < t1StartOutInd; ++t1StartIncInd) { const unsigned int pos = _graph.opInd(t1StartIncInd); ++visCount[pos]; ++workCount[pos]; } unsigned int t1EndOutInd = t1StartIncInd; // for K4 counting for (unsigned int i = _graph.opInd(t1EndOutInd); i != t4; i = _graph.opInd(++t1EndOutInd)) { ++visCount[i]; ++workCount[i]; innerMark[i] = _graph.edgeInd(t1EndOutInd); } for (unsigned int t2EdgeInd = t1StartOutInd; t2EdgeInd < t1EndOutInd; ++t2EdgeInd) { const unsigned int t2 = _graph.opInd(t2EdgeInd); const unsigned int s1 = _graph.edgeInd(t2EdgeInd); innerMark[t2] = -1; if (outerMark[t2] == -1) { continue; } const unsigned int s2 = outerMark[t2]; // this is an triangle ++_eTriCount[s1]; ++_eTriCount[s2]; ++_eTriCount[l]; ++_nTriCount[t4]; ++_nTriCount[t1]; ++_nTriCount[t2]; int t2StartOudInd = _graph.firstOutEdge(t2); const int t2EndOutInd = _graph.lastOutEdge(t2); while (t2StartOudInd < t2EndOutInd) { const int t3 = _graph.opInd(t2StartOudInd); const int s3 = _graph.edgeInd(t2StartOudInd); // this is a k4 if (outerMark[t3] >= 0 && innerMark[t3] >= 0) { ++E_ORBIT(s1, 13); ++E_ORBIT(s2, 13); ++E_ORBIT(s3, 13); ++E_ORBIT(l, 13); ++E_ORBIT(innerMark[t3], 13); ++E_ORBIT(outerMark[t3], 13); ++N_ORBIT(t1, 19); ++N_ORBIT(t2, 19); ++N_ORBIT(t3, 19); ++N_ORBIT(t4, 19); } ++t2StartOudInd; } } } for (unsigned int t1EdgeInd = t4StartIncInd; t1EdgeInd < t4EndIncInd; ++t1EdgeInd) { const unsigned int t1 = _graph.opInd(t1EdgeInd); const unsigned int l = _graph.edgeInd(t1EdgeInd); unsigned int t1StartIncInd = _graph.firstInEdge(t1); unsigned int t2; while ((t2 = _graph.opInd(t1StartIncInd)) != t4) { const int c4count = visCount[t2] - 1; if (--workCount[t2] == 0) { const long val = choose2(c4count + 1); _nNonIndC4Count[t4] += val; _nNonIndC4Count[t2] += val; visCount[t2] = 0; } _nNonIndC4Count[t1] += c4count; _eNonIndC4Count[l] += c4count; _eNonIndC4Count[_graph.edgeInd(t1StartIncInd)] += c4count; ++t1StartIncInd; } } } delete[] innerMark; delete[] outerMark; delete[] visCount; delete[] workCount; } void QuadCensus::calcK3RelNonIndCounts() { int* const mark = new int[_graph.n()]; std::fill_n(mark, _graph.n(), -1); for (unsigned int t3 = 2; t3 < _graph.n(); ++t3) { unsigned int t3FirstInInd = _graph.firstInEdge(t3); unsigned int t3EndInInd = _graph.lastInEdge(t3); for (unsigned int i = t3FirstInInd; i < t3EndInInd; ++i) { mark[_graph.opInd(i)] = _graph.edgeInd(i); } for (unsigned int i = t3FirstInInd; i < t3EndInInd; ++i) { const unsigned int t1 = _graph.opInd(i); const int l = mark[t1]; mark[t1] = -1; unsigned int t1StartOutInd = _graph.firstOutEdge(t1); unsigned int t2; while ((t2 = _graph.opInd(t1StartOutInd)) != t3) { if (mark[t2] >= 0) { ++_k3Count; const unsigned int s1 = _graph.edgeInd(t1StartOutInd); const unsigned int s2 = mark[t2]; const unsigned long s1T = _eTriCount[s1]; const unsigned long s2T = _eTriCount[s2]; const unsigned long lT = _eTriCount[l]; const unsigned int t1D = _graph.lastOutEdge(t1) - _graph.firstInEdge(t1); const unsigned int t2D = _graph.lastOutEdge(t2) - _graph.firstInEdge(t2); const unsigned int t3D = _graph.lastOutEdge(t3) - _graph.firstInEdge(t3); // update diamond counts E_ORBIT(l, 11)+= s1T + s2T; E_ORBIT(s1, 11)+= s2T + lT; E_ORBIT(s2, 11)+= s1T + lT; N_ORBIT(t1, 17)+= s2T; N_ORBIT(t2, 17)+= lT; N_ORBIT(t3, 17)+= s1T; // update paw counts E_ORBIT(s1, 9)+= t3D; E_ORBIT(s2, 9)+= t1D; E_ORBIT(l, 9)+= t2D; N_ORBIT(t1, 14)+= t2D + t3D; N_ORBIT(t2, 14)+= t1D + t3D; N_ORBIT(t3, 14)+= t1D + t2D; } ++t1StartOutInd; } } } delete[] mark; } void QuadCensus::calcNonInducedFrequencies() { // for each edge for (unsigned int i = 0; i < _graph.n(); i++) { const unsigned int endIndex = _graph.lastInEdge(i); const unsigned int srcDeg = _graph.lastOutEdge(i) - _graph.firstInEdge(i); for (unsigned int neighPos = _graph.firstInEdge(i); neighPos < endIndex; neighPos++) { const unsigned int tgtIndex = _graph.opInd(neighPos); const unsigned int eIndex = _graph.edgeInd(neighPos); const unsigned int tgtDeg = _graph.lastOutEdge(tgtIndex) - _graph.firstInEdge(tgtIndex); // set non-induced edge orbit counts E_ORBIT(eIndex, 12)= choose2(_eTriCount[eIndex] ); E_ORBIT(eIndex, 11)= E_ORBIT(eIndex, 11) - 2 * _eTriCount[eIndex]; E_ORBIT(eIndex, 10)=_eNonIndC4Count[eIndex]; E_ORBIT(eIndex, 9)= E_ORBIT(eIndex, 9) - 2 * _eTriCount[eIndex]; E_ORBIT(eIndex, 8)= _eTriCount[eIndex] * (srcDeg + tgtDeg - 4); E_ORBIT(eIndex, 7)= _nTriCount[i] + _nTriCount[tgtIndex] - 2 * _eTriCount[eIndex]; E_ORBIT(eIndex, 6)= choose2(srcDeg - 1) + choose2(tgtDeg - 1); E_ORBIT(eIndex, 5)=(srcDeg - 1) * (tgtDeg - 1) - _eTriCount[eIndex]; E_ORBIT(eIndex, 4)= _neighDeg[i] + _neighDeg[tgtIndex] - 2 * (srcDeg + tgtDeg) + 2 - 2 * _eTriCount[eIndex]; E_ORBIT(eIndex, 3)= _eTriCount[eIndex] * (_graph.n() - 3); E_ORBIT(eIndex, 2)=((srcDeg - 1) + (tgtDeg - 1)) * (_graph.n() - 3); E_ORBIT(eIndex, 1)= _graph.m() - srcDeg - tgtDeg + 1; E_ORBIT(eIndex, 0)= choose2(_graph.n() - 2); // set non-induced node orbit counts N_ORBIT(i, 18)+= choose2(_eTriCount[eIndex]); N_ORBIT(i, 15)+= _nTriCount[tgtIndex] - _eTriCount[eIndex]; N_ORBIT(i, 12)+= choose2(tgtDeg - 1); N_ORBIT(i, 10)+= _neighDeg[tgtIndex] - tgtDeg; N_ORBIT(i, 9)+= (srcDeg - 1) * (tgtDeg - 1) - _eTriCount[eIndex]; N_ORBIT(i, 6)+= tgtDeg - 1; N_ORBIT(i, 3)+= _graph.m() - (srcDeg + tgtDeg - 1); N_ORBIT(tgtIndex, 18)+= choose2(_eTriCount[eIndex]); N_ORBIT(tgtIndex, 15)+= _nTriCount[i] - _eTriCount[eIndex]; N_ORBIT(tgtIndex, 12)+= choose2(srcDeg - 1); N_ORBIT(tgtIndex, 10)+= _neighDeg[i] - srcDeg; N_ORBIT(tgtIndex, 9)+= (srcDeg - 1) * (tgtDeg - 1) - _eTriCount[eIndex]; N_ORBIT(tgtIndex, 6)+= srcDeg - 1; N_ORBIT(tgtIndex, 3)+= _graph.m() - (srcDeg + tgtDeg - 1); } } // solve remaining non-induced node frequencies const unsigned long allPairs = choose3(_graph.n() - 1); for (unsigned int i = 0; i < _graph.n(); ++i) { const unsigned int deg = _graph.lastOutEdge(i) - _graph.firstInEdge(i); N_ORBIT(i, 17)-= _nTriCount[i]; N_ORBIT(i, 16)= _nNonIndC4Count[i]; N_ORBIT(i, 14)-= _nTriCount[i] * 4; N_ORBIT(i, 13)= _nTriCount[i] * (deg - 2); N_ORBIT(i, 11)= choose3(deg); N_ORBIT(i, 10)-= deg * (deg - 1) + 2 * _nTriCount[i]; N_ORBIT(i, 8)= _k3Count - _nTriCount[i]; N_ORBIT(i, 7)= _nTriCount[i] * (_graph.n() - 3); N_ORBIT(i, 5)= N_ORBIT(i, 6); N_ORBIT(i, 6)= _2pathCount - N_ORBIT(i, 6) - choose2(deg); N_ORBIT(i, 5)= N_ORBIT(i, 5) * (_graph.n() - 3); N_ORBIT(i, 4)= choose2(deg) * (_graph.n() - 3); N_ORBIT(i, 2)= (_graph.m() - deg) * (_graph.n() - 3); N_ORBIT(i, 1)= choose2(_graph.n() - 2) * deg; N_ORBIT(i, 0)= allPairs; } } void QuadCensus::calcInducedFrequencies() { for (unsigned int i = 0; i < _graph.n(); ++i) { const unsigned int endIndex = _graph.lastInEdge(i); for (unsigned int neighPos = _graph.firstInEdge(i); neighPos < endIndex; ++neighPos) { const unsigned int eIndex = _graph.edgeInd(neighPos); E_ORBIT(eIndex, 12)-= E_ORBIT(eIndex, 13); E_ORBIT(eIndex, 11)-= 4 * E_ORBIT(eIndex, 13); E_ORBIT(eIndex, 10)-= E_ORBIT(eIndex, 11) + 2 * E_ORBIT(eIndex, 13); E_ORBIT(eIndex, 9)-= E_ORBIT(eIndex, 11) + 2 * E_ORBIT(eIndex, 13); E_ORBIT(eIndex, 8)-= E_ORBIT(eIndex, 11) + 4 * E_ORBIT(eIndex, 12) + 4 * E_ORBIT(eIndex, 13); E_ORBIT(eIndex, 7)-= E_ORBIT(eIndex, 11) + 2 * E_ORBIT(eIndex, 13); E_ORBIT(eIndex, 6)-= E_ORBIT(eIndex, 7) + E_ORBIT(eIndex, 8) + E_ORBIT(eIndex, 11) + 2 * E_ORBIT(eIndex, 12) + 2 * E_ORBIT(eIndex, 13); E_ORBIT(eIndex, 5)-= E_ORBIT(eIndex, 8) + E_ORBIT(eIndex, 10) + E_ORBIT(eIndex, 11) + 2 * E_ORBIT(eIndex, 12) + 2 * E_ORBIT(eIndex, 13); E_ORBIT(eIndex, 4)-= 2 * E_ORBIT(eIndex, 7) + 2 * E_ORBIT(eIndex, 9) + 2 * E_ORBIT(eIndex, 10) + 3 * E_ORBIT(eIndex, 11) + 4 * E_ORBIT(eIndex, 13); E_ORBIT(eIndex, 3)-= E_ORBIT(eIndex, 8) + E_ORBIT(eIndex, 9) + E_ORBIT(eIndex, 11) + 2 * E_ORBIT(eIndex, 12) + 2 * E_ORBIT(eIndex, 13); E_ORBIT(eIndex, 2)-= 2 * E_ORBIT(eIndex, 3) + E_ORBIT(eIndex, 4) + 2 * E_ORBIT(eIndex, 5) + 2 * E_ORBIT(eIndex, 6) + 2 * E_ORBIT(eIndex, 7) + 3 * E_ORBIT(eIndex, 8) + 2 * E_ORBIT(eIndex, 9) + 2 * E_ORBIT(eIndex, 10) + 3 * E_ORBIT(eIndex, 11) + 4 * E_ORBIT(eIndex, 12) + 4 * E_ORBIT(eIndex, 13); E_ORBIT(eIndex, 1)-= E_ORBIT(eIndex, 4) + E_ORBIT(eIndex, 7) + E_ORBIT(eIndex, 9) + E_ORBIT(eIndex, 10) + E_ORBIT(eIndex, 11) + E_ORBIT(eIndex, 13); E_ORBIT(eIndex, 0)-= E_ORBIT(eIndex, 1) + E_ORBIT(eIndex, 2) + E_ORBIT(eIndex, 3) + E_ORBIT(eIndex, 4) + E_ORBIT(eIndex, 5) + E_ORBIT(eIndex, 6) + E_ORBIT(eIndex, 7) + E_ORBIT(eIndex, 8) + E_ORBIT(eIndex, 9) + E_ORBIT(eIndex, 10) + E_ORBIT(eIndex, 11) + E_ORBIT(eIndex, 12) + E_ORBIT(eIndex, 13); } } for (unsigned int i = 0; i < _graph.n(); ++i) { N_ORBIT(i, 18)-= 3 * N_ORBIT(i, 19); N_ORBIT(i, 17)-= 3 * N_ORBIT(i, 19); N_ORBIT(i, 16)-= 3 * N_ORBIT(i, 19) + N_ORBIT(i, 18) + N_ORBIT(i, 17); N_ORBIT(i, 15)-= 3 * N_ORBIT(i, 19) + 2 * N_ORBIT(i, 17); N_ORBIT(i, 14)-= 6 * N_ORBIT(i, 19) + 2 * N_ORBIT(i, 18) + 2 * N_ORBIT(i, 17); N_ORBIT(i, 13)-= 3 * N_ORBIT(i, 19) + 2 * N_ORBIT(i, 18); N_ORBIT(i, 12)-= 3 * N_ORBIT(i, 19) + N_ORBIT(i, 18) + 2 * N_ORBIT(i, 17) + N_ORBIT(i, 15) + N_ORBIT(i, 14); N_ORBIT(i, 11)-= N_ORBIT(i, 19) + N_ORBIT(i, 18) + N_ORBIT(i, 13); N_ORBIT(i, 10)-= 6 * N_ORBIT(i, 19) + 2 * N_ORBIT(i, 18) + 4 * N_ORBIT(i, 17) + 2 * N_ORBIT(i, 16) + 2 * N_ORBIT(i, 15) + N_ORBIT(i, 14); N_ORBIT(i, 9)-= 6 * N_ORBIT(i, 19) + 4 * N_ORBIT(i, 18) + 2 * N_ORBIT(i, 17) + 2 * N_ORBIT(i, 16) + N_ORBIT(i, 14) + 2 * N_ORBIT(i, 13); N_ORBIT(i, 8)-= N_ORBIT(i, 19) + N_ORBIT(i, 17) + N_ORBIT(i, 15); N_ORBIT(i, 7)-= 3 * N_ORBIT(i, 19) + 2 * N_ORBIT(i, 18) + N_ORBIT(i, 17) + N_ORBIT(i, 14) + N_ORBIT(i, 13); N_ORBIT(i, 6)-= 3 * N_ORBIT(i, 19) + N_ORBIT(i, 18) + 3 * N_ORBIT(i, 17) + N_ORBIT(i, 16) + 3 * N_ORBIT(i, 15) + N_ORBIT(i, 14) + N_ORBIT(i, 12) + N_ORBIT(i, 10) + 3 * N_ORBIT(i, 8); N_ORBIT(i, 5)-= 6 * N_ORBIT(i, 19) + 4 * N_ORBIT(i, 18) + 4 * N_ORBIT(i, 17) + 2 * N_ORBIT(i, 16) + 2 * N_ORBIT(i, 15) + 3 * N_ORBIT(i, 14) + 2 * N_ORBIT(i, 13) + 2 * N_ORBIT(i, 12) + N_ORBIT(i, 10) + N_ORBIT(i, 9) + 2 * N_ORBIT(i, 7); N_ORBIT(i, 4)-= 3 * N_ORBIT(i, 19) + 3 * N_ORBIT(i, 18) + N_ORBIT(i, 17) + N_ORBIT(i, 16) + N_ORBIT(i, 14) + 3 * N_ORBIT(i, 13) + 3 * N_ORBIT(i, 11) + N_ORBIT(i, 9) + N_ORBIT(i, 7); N_ORBIT(i, 3)-= 3 * N_ORBIT(i, 19) + 2 * N_ORBIT(i, 18) + 2 * N_ORBIT(i, 17) + 2 * N_ORBIT(i, 16) + N_ORBIT(i, 15) + N_ORBIT(i, 14) + N_ORBIT(i, 13) + N_ORBIT(i, 10) + N_ORBIT(i, 9); N_ORBIT(i, 2)-= 3 * N_ORBIT(i, 19) + 2 * N_ORBIT(i, 18) + 3 * N_ORBIT(i, 17) + 2 * N_ORBIT(i, 16) + 3 * N_ORBIT(i, 15) + 2 * N_ORBIT(i, 14) + N_ORBIT(i, 13) + 2 * N_ORBIT(i, 12) + 2 * N_ORBIT(i, 10) + N_ORBIT(i, 9) + 3 * N_ORBIT(i, 8) + N_ORBIT(i, 7) + 2 * N_ORBIT(i, 6) + N_ORBIT(i, 5) + N_ORBIT(i, 3); N_ORBIT(i, 1)-= 3 * N_ORBIT(i, 19) + 3 * N_ORBIT(i, 18) + 2 * N_ORBIT(i, 17) + 2 * N_ORBIT(i, 16) + N_ORBIT(i, 15) + 2 * N_ORBIT(i, 14) + 3 * N_ORBIT(i, 13) + N_ORBIT(i, 12) + 3 * N_ORBIT(i, 11) + N_ORBIT(i, 10) + 2 * N_ORBIT(i, 9) + 2 * N_ORBIT(i, 7) + N_ORBIT(i, 5) + 2 * N_ORBIT(i, 4) + N_ORBIT(i, 3); N_ORBIT(i, 0)-= N_ORBIT(i, 19) + N_ORBIT(i, 18) + N_ORBIT(i, 17) + N_ORBIT(i, 16) + N_ORBIT(i, 15) + N_ORBIT(i, 14) + N_ORBIT(i, 13) + N_ORBIT(i, 12) + N_ORBIT(i, 11) + N_ORBIT(i, 10) + N_ORBIT(i, 9) + N_ORBIT(i, 8) + N_ORBIT(i, 7) + N_ORBIT(i, 6) + N_ORBIT(i, 5) + N_ORBIT(i, 4) + N_ORBIT(i, 3) + N_ORBIT(i, 2) + N_ORBIT(i, 1); } } } /* namespace oaqc */ oaqc/NAMESPACE0000644000176200001440000000013414674507537012434 0ustar liggesusers# Generated by roxygen2: do not edit by hand export(oaqc) useDynLib(oaqc, .registration=T) oaqc/NEWS.md0000644000176200001440000000020714677303632012305 0ustar liggesusers# oaqc 2.0.0 * Switch of Maintainer * Adapted C code to recent adaption of the R/C interface # oaqc 1.0.0 * Initial version on CRANoaqc/inst/0000755000176200001440000000000014700723647012164 5ustar liggesusersoaqc/inst/CITATION0000644000176200001440000000113614677305163013324 0ustar liggesusersbibentry( bibtype = "Manual", title = "oaqc: Computation of the Orbit-Aware Quad Census", author = c( person("Mark", "Ortmann"), person("Felix", "Schoenenberger"), person("David", "Schoch") ), year = 2024, note = "R package version 2.0.0" ) bibentry("Article", title = "Efficient orbit-aware triad and quad census in directed and undirected graphs", author = "Mark Ortmann and Ulrik Brandes", journal = "Applied Network Science", year = "2017", volume = "2", number = "", pages = "1--17", doi = "10.1007/s41109-017-0027-2" ) oaqc/inst/doc/0000755000176200001440000000000014700723647012731 5ustar liggesusersoaqc/inst/doc/oaqc.Rmd0000644000176200001440000000323414674530710014317 0ustar liggesusers--- title: "Introduction to oaqc" author: "Mark Ortmann" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{oaqc} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- # Introduction to oaqc This package provides an efficient algorithm to calculate for a given graph the **o**rbit-**a**ware **q**uad **c**ensus. More precisely the frequency distribution of all induced and non-induced non-isomorphic four node subgraphs, i.e. quads, on a node and edge level; see the figure below for the relation between orbit and quad. ![quad census](quad_census.svg) ## Input The input can either be an edgelist (matrix or data.frame) or a graph Object ('igraph') Despite the input format the graph should not contain loops or multi-edges and the vertex indices have to lie in range [0,n-1) with n denoting the number of vertices in the graph. Note that if the smallest index is 1 the algorithm will create an isolated vertex with index 0. ## Calculating the orbit-aware quad census The following code exemplifies the use of this package. ```{r} library(oaqc) ### k4, pure R k4 <- data.frame( source = c(0, 0, 0, 1, 1, 2), target = c(1, 2, 3, 2, 3, 3) ) k4orbits <- oaqc(k4, non_ind_freq = FALSE, file = "") # print(k4orbits) ``` In order to calculate the non-induced frequencies as well just set the corresponding flag to `TRUE`. Since the orbit-aware frequencies can be rather large integers, which can cause some problems with R, the results can be directly written to a file. ## Result The results of the, e.g., induced frequencies of the nodes in orbit 10 can be accessed in the following way. ```{r} print(k4orbits$n_orbits_ind[, 10]) ```oaqc/inst/doc/oaqc.html0000644000176200001440000035156614700723647014562 0ustar liggesusers Introduction to oaqc

Introduction to oaqc

Mark Ortmann

Introduction to oaqc

This package provides an efficient algorithm to calculate for a given graph the orbit-aware quad census. More precisely the frequency distribution of all induced and non-induced non-isomorphic four node subgraphs, i.e. quads, on a node and edge level; see the figure below for the relation between orbit and quad.

quad census
quad census

Input

The input can either be an edgelist (matrix or data.frame) or a graph Object (‘igraph’)

Despite the input format the graph should not contain loops or multi-edges and the vertex indices have to lie in range [0,n-1) with n denoting the number of vertices in the graph. Note that if the smallest index is 1 the algorithm will create an isolated vertex with index 0.

Calculating the orbit-aware quad census

The following code exemplifies the use of this package.

library(oaqc)
### k4, pure R
k4 <- data.frame(
    source = c(0, 0, 0, 1, 1, 2),
    target = c(1, 2, 3, 2, 3, 3)
)
k4orbits <- oaqc(k4, non_ind_freq = FALSE, file = "")
# print(k4orbits)

In order to calculate the non-induced frequencies as well just set the corresponding flag to TRUE.

Since the orbit-aware frequencies can be rather large integers, which can cause some problems with R, the results can be directly written to a file.

Result

The results of the, e.g., induced frequencies of the nodes in orbit 10 can be accessed in the following way.

print(k4orbits$n_orbits_ind[, 10])
## [1] 0 0 0 0
oaqc/inst/doc/oaqc.R0000644000176200001440000000060314700723647013776 0ustar liggesusers## ----------------------------------------------------------------------------- library(oaqc) ### k4, pure R k4 <- data.frame( source = c(0, 0, 0, 1, 1, 2), target = c(1, 2, 3, 2, 3, 3) ) k4orbits <- oaqc(k4, non_ind_freq = FALSE, file = "") # print(k4orbits) ## ----------------------------------------------------------------------------- print(k4orbits$n_orbits_ind[, 10]) oaqc/README.md0000644000176200001440000000713514677316552012502 0ustar liggesusers # oaqc [![R-CMD-check](https://github.com/schochastics/oaqc/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/schochastics/oaqc/actions/workflows/R-CMD-check.yaml) [![CRAN status](https://www.r-pkg.org/badges/version/oaqc)](https://CRAN.R-project.org/package=oaqc) This package provides an efficient algorithm to calculate for a given graph the **o**rbit-**a**ware **q**uad **c**ensus. More precisely the frequency distribution of all induced and non-induced non-isomorphic four node subgraphs, i.e. quads, on a node and edge level; see the figure below for the relation between orbit and quad.
quad census
## Installation You can install the development version of oaqc like so: ``` r remotes::install_github("schochastics/oaqc") ``` ## Input The input can either be an edgelist (matrix or data.frame) or a graph Object (‘igraph’) Despite the input format the graph should not contain loops or multi-edges and the vertex indices have to lie in range \[0,n-1) with n denoting the number of vertices in the graph. Note that if the smallest index is 1 the algorithm will create an isolated vertex with index 0. ## Calculating the orbit-aware quad census The following code exemplifies the use of this package. ``` r library(oaqc) ### k4, pure R k4 <- data.frame( source = c(0, 0, 0, 1, 1, 2), target = c(1, 2, 3, 2, 3, 3) ) k4orbits <- oaqc(k4, non_ind_freq = FALSE, file = "") k4orbits #> $n_orbits_ind #> [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] [,12] [,13] [,14] #> [1,] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 #> [2,] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 #> [3,] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 #> [4,] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 #> [,15] [,16] [,17] [,18] [,19] [,20] #> [1,] 0 0 0 0 0 1 #> [2,] 0 0 0 0 0 1 #> [3,] 0 0 0 0 0 1 #> [4,] 0 0 0 0 0 1 #> #> $e_orbits_ind #> [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] [,12] [,13] [,14] #> [1,] 0 0 0 0 0 0 0 0 0 0 0 0 0 1 #> [2,] 0 0 0 0 0 0 0 0 0 0 0 0 0 1 #> [3,] 0 0 0 0 0 0 0 0 0 0 0 0 0 1 #> [4,] 0 0 0 0 0 0 0 0 0 0 0 0 0 1 #> [5,] 0 0 0 0 0 0 0 0 0 0 0 0 0 1 #> [6,] 0 0 0 0 0 0 0 0 0 0 0 0 0 1 ``` In order to calculate the non-induced frequencies as well just set the corresponding flag to `TRUE`. Since the orbit-aware frequencies can be rather large integers, which can cause some problems with R, the results can be directly written to a file. ## Result The results of the, e.g., induced frequencies of the nodes in orbit 10 can be accessed in the following way. ``` r k4orbits$n_orbits_ind[, 10] #> [1] 0 0 0 0 ``` ## Acknowledgement The following resources were used for the logo: [Atv icons created by Skyclick - Flaticon](https://www.flaticon.com/free-icons/atv) [Group icons created by Vectors Market - Flaticon](https://www.flaticon.com/free-icons/group) oaqc/build/0000755000176200001440000000000014700723647012306 5ustar liggesusersoaqc/build/vignette.rds0000644000176200001440000000027714700723647014653 0ustar liggesusersb```b`aad`b2 1# 'O,L MAgqfIA & ȂLaBRŚZ% 5/$~NN,/AQs[fN*ސ89 d Bw(,/׃ @?{49'ݣ\)%ziE@ wnYmoaqc/build/partial.rdb0000644000176200001440000000007514700723643014431 0ustar liggesusersb```b`aad`b1 H020piּb C"he7oaqc/man/0000755000176200001440000000000014677316467011775 5ustar liggesusersoaqc/man/oaqc.Rd0000644000176200001440000000250314674507537013204 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/oaqc.R \docType{package} \name{oaqc} \alias{oaqc-package} \alias{oaqc} \title{Orbit-aware Quad Census computation} \usage{ oaqc(graph, non_ind_freq = F, file = "") } \arguments{ \item{graph}{A matrix, data.frame or graph object.} \item{non_ind_freq}{A flag indicating whether non-induced frequencies have to be returned or not.} \item{file}{Name (and location) of the file to be written.} } \value{ orbit-aware quad census on a node and edge level. Consult \code{vignette('oaqc')} to see the correspondence between orbit and quad. } \description{ Implements the efficient algorithm by Ortmann and Brandes (2017) \doi{10.1007/s41109-017-0027-2} to compute the orbit-aware frequency distribution of induced and non-induced quads, i.e. subgraphs of size four. Given an edge matrix, data frame, or a graph object (e.g., 'igraph'), the orbit-aware counts are computed respective each of the edges and nodes. } \examples{ k4 <- data.frame( source = c(0, 0, 0, 1, 1, 2), target = c(1, 2, 3, 2, 3, 3) ) k4orbits <- oaqc(k4, non_ind_freq = TRUE) print(k4orbits) } \author{ \strong{Maintainer}: David Schoch \email{david@schochastics.net} (\href{https://orcid.org/0000-0003-2952-4812}{ORCID}) Authors: \itemize{ \item Mark Ortmann \item Felix Schoenenberger } } oaqc/man/annotate_result.Rd0000644000176200001440000000112414674505744015464 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/oaqc.R \name{annotate_result} \alias{annotate_result} \title{Annotates the igraph object with orbit labels.} \usage{ annotate_result(graph, orbits, non_ind_freq) } \arguments{ \item{graph}{Unmodified input graph.} \item{orbits}{List with n_orbits, e_orbits matrices.} \item{non_ind_freq}{A flag indicating whether non-induced frequencies have to be written or not.} } \value{ \code{orbits} if the input is not an igraph, the annotated igraph instead. } \description{ Annotates the igraph object with orbit labels. } oaqc/man/figures/0000755000176200001440000000000014677316467013441 5ustar liggesusersoaqc/man/figures/logo.png0000644000176200001440000014431714677316467015121 0ustar liggesusersPNG  IHDRX? cHRMz&u0`:pQ<bKGD pHYs.#.#x?vtIME uѴIDATxw]y]kӧϨWT( ь1cl%1=ž7&Nrt߸m 6$$z/3]sH|]^kӟG" fTOqNR}&a (uGxfQ ~K%M.T@[LSI dX x/-gQK q B_ b 3uފd 5?࿀!t?əE;܇gwF΄ Dy3jN7@gF;@cXsnE-|z1%ѺB/8pF%; 0 0ŻP|XZBHSxUu| 9K 3]*-#@ET~ UN`!c @HzGqpw7)}ʍ~W1-LO\7/`%S5MOwJ\e[C E0 )o]7`yJ"UJb.\ox .},5E1|I?7gpS:]uH@}=l:xmE!PJ+IKlW o~)kVA0O"%Kbuoz*\ ^t*W5ǀ+X($ob,߁ wA)u_EW1{8ƀP|fK ےS,Rǽ"2K\& ?nZjBq7m2͌ԖSsc@ 6 rYw'W/3!Pb鞹3AOkN@dK>݀+e(~XR@l!ůoN\Lq݆w/1+ ncXS_?Va/՚wj ɞu71$2p'p1 hG[r [6}g .$t>^uy_bYNmn(K@ng<'JToŗD> R-$88۟{x+ù2pt"PfC@kѱb5ݼ~WБkvR ?>6<|yg8ϹH=ka򒕹T/Cۀڃ(/Pfܱ82h`Hп } 3p=W_iea CYbJse+"f_Qb S d뻪5YQhKqw=m0ۏ_盈qa`[%X`!%R R!>8.*Pc)Qͫ+INwqӆ[8{3OFSt^\j \42ᐿ\Wl?Fp1G p]dmӇy|uJ*qUmSh{!  D%-LR q\LAK %9$_aQ!O!x7=mq12cש F6Ep{,+r ` `kHEG%qG P)|p]B#` [ܢpۦqH9Q) )1[$ lK f uBP(FsǢAB8U?~U6ca5rb7U?c/֎' lF7dI hqrW'.Ǜ>#{@ZU5O{¡=)Flq'{&\te -bJ zZsyu_g^i p;iLMLCM_<,MyW44xqDr (ވ YXR~-pאH5" :V}Ѭ?'eս7]y\Ri_@PiAִ):.:<> 7`oz|% ZCq6A4bM_d Ujt.9Jr%p]QǶgi-\i `:m{(r5j%x1DN%a DDvty.WЕhGt*naR$ Lv_*w9 ?6[Ϸc+J8c# }|Z6r2ΫܶL y \O-A$R`G7uN +3ZLC,oV._u'H1 2b|O;TM.zyˀ. +&ytmջOM1I646Tl2PTi|4x8D 9q@nvk\ Wt6\nx =^ ˜x`3! SE @uמAiN܄\.mG/g?S$ꔳipm퐈ZmvBcÐˀVL@U.T2&<>} ϟ oDל}xXҹ{BwPy⯻~ܠuCN,cR姴\chl)W};Pg lJ{[]DUJ#CKyZ30ʴ5[&qst'SW]/곿G{X={A@dq8N 7`Ϲ(>AmnM_v^AФ o2ⱠC6q)b^$V#4L : զ ^WCc.#Ǔu|Sov2-|6|KVyڢb/:me}͛9׉I? Ѿ8Yߓ_m>cz֔ V=-.mF#SE!ֿ,vTqHڻ ҉ _*9>[S4h5w(V'"c\yí],tYO ~}0 j/ͪ?||Rň]\`gEAd-Ae,iIZu__A. CP,2{wˆgHBGw`Ɗ81C.\{QtTW9xmLȢ-cvhvYIqe1Q|1.ܱͯf pJQNA4b4 NI73DsB|wiQZw/)Hg ~*aŊxzh5Bq+YvaĢAM16\ekYG5>i$.:x`[s`:YBEJ)l|`6'hθIjQB"S4fhj8 ?ݏm;-SM~ vN%5JEj-ο6rgmX4g^͏6}玼Ǎ ׭]6ݧ`x@뾾wi =:{ jP8Alr+W7]x+gl-Nԏ߅"$VSu%ԩbr9Eͯ_N.B?=o 칑t )|*ƸtA'jUQ!ծ#zNAFA i!Q[! OKb ?n6&ׯ=-G&4^lDQ'xpTBm99&p?Fp#`U;{bl wm]~81!4Lsl8XшX,eWN\=H! ٪e?θ8զ-›.mZ#n,~YvM8A}@!z=*t5n~WC4? H<q$tYKɕ82((8SI1q:zQ>^koәm&V?>Ŗ{%.5z|~ܹ=YhXq9p% |:9xCg/x6VI| *#gY(*,F{P,kUi~i5汸[bYMtaS9Ti:o Xy TM"å+~Mn܅O& 苭ϋVot9xeܶԋ'm̘&TJ?5b'ZϞ{/vDeI K+nn)8!tXPa]9o$@HCHB&Fk'k&*(*gM)g`Tg%M?7xg&,siNpОod@]/^jrp(sl76~shhͬ?3lgq%a5K%ou` !QJrddz9QrAJ,[T$"aXVh/>XDm>x;0QA.y ;wfLN[\qD$v_@MIמgOgܴhqcڃ(PԁkmGve=Ᏻ|A"vHv Y#CR @Q*csN$Ty ČĉXp6 V^ѳ|DwȜb3j G\F== xӇytf%絔PT^gWsQ^{޷yݺ1@d;O"y{&ΈV8Veh=u@ܹ=r;O/:9X-1E]j"F{N'־R)˱[>4eqԐ ѺeW1wк2 [ZO>sIbʮy_kLKl&y{L5\U5X%.ypMt׿bnfe ;–WRt/ q$C"AĮwԫR 56DߎG7ٻ̌ D#C4;I.`ц#\&a̘*qKl(H[<+5N[Fǿӗxjƀ x-&]'?ûod"BbEB2V݁$!@rcl{+<>TQ uŰr!,;[}fYh_v%+8_{U+?τuTx~AnX ;m61?>`zԅk`#՛T(*ol1x]b;T?BM7&Ba{:hkյxN]'7@,,/W_ E*w\  On۹BQ 3bvNbXIH +эNh'z$a CQ ?ƺ~r\>޲/zt x C$A,9)d x+Χ[mQYV\6(aAyJN Us6p^d{>ó't-ꆷ r5l\y 𮿇>rg, !1w$mÊu`Ż.#ڶh]ViF@9|W-? Ү̉۳~s)V~%~ QWkHռ#88p6oy-s/z="8Nkeg N4 IwG-Q{?ŖS6_G r4Ǎ:i6#){ٛ4lŴ6KIvCѶvrW/nkjaG\Wu9Xh7Z0=/;=`[V1E.s\'Y\}`He9اMB%G o|A9yɁ ؼtȌg%мԬPE6 s?M>VEYڢb?:mk(Q)V RЉ`E(ރ(7NKľmӇybrp:HAzzh\)i`ZqJϞG>šGXr0xjgKW5q?K_/#CC J"bRxyeb)ٳuo*5Wme+⦍O5N[$A'l'.-hks8.&/6}'_wƤM&\Oj ! aFl(<y n=/?}'5К$'b ϗv~P}q~쯰#6bRH.%NͤI!= 1p';0|b@X)͎ڊwM_cūAy'`]̢ͺIQtP:Y x ]lW]W~T8:=^2k8_֧!Z\X"zn}N 뚖0"gľ?<{j5);[^5'ac[-I>{?1"9w%i҇{ ` r,Ǐ.}qvFGNR.`ݛJc`M/?-1, mŷQbb$ t|]0aHw۷k;a Bu2zS :e%'sc4Xs@깦02O_ vƮR//;b]+;Miף'>74d.v<'}MO=Gr'-f[.VYsf G(}= U-_(ox /UhnE-F8AL>הJ\Y [pb<}w8A_HRh߮!u/ۄ&*ROѕ~gs & nzns2f %Rx"a9d{k3.;୬ <>xaq_.=esys9ͣ3O>MOwq7*$%5Bx'-7ж +>kVuGbx󅷲z UnP;Qdh='}^tG$"x)ɮ d՞ד)CFLEK!b l24$!JeHp\(| EEAw"Ŋ?40PqY\+ 2+( oVѷu> /_UKg~X_rk}U?l~I</l{'ef$ER֓YGgUXΚo0p`Dձ UWrמ-nX l+2vFLrKv9]ϷLb/ / S QhOģK9{!0$ (:<+ˮSXZXU˦95 eEH$>"T}zwÊO?u7r|DI06:;yyM xҌ`EHtcŴ/Q+I<"0`gU*(=r>c뉷 /| \;n4?fWMCFz~AV%$ e36(dAh^&bPP|ZPϕ0VPȲ.s8&E =ENxƜ`5\pX<vo}+/Ê Dc &ˊ $ P &x:TB!%DmA[B),S<ә>+\IyJW\cn~^n^xM ?>K^0E1PZ׿n~3c?WF1=Zc֤$1k抔Wbe$35(m3Q_ &@Uĸ,U kznO1k;n?N~bWNLjO[拰癖纳aϒw>S+dV|W1#xQNQҪ!uE$5$7}EH I7oD$|ŗ|8(e{Gd@z~C<Ag>)EKIML&Witc0MY/*\\,Lsj H>@Cq \q9o:+w̤Awq\G"-sJ6]+Q1S~ w< U>fi"iK1Ø;uN!,,#j{ RW/aUh ,T0q{J C\\Qp<\Jυ [Y5 3/S81fL֍Zz MmH6>S w5Uf3ҊR(JؘV[f@p[ ifE Oe *6$t$]:S2gO\K2mI]$1\W\71/1}#{ZxXҹk~,[ڀQOrqb8ףu/oJEgң#eNuJAZ&6D`SAkBc Bşp\x UB$;.`^ܨahFwO47RyzMlBss_+I^ ?s#+:{u =Gf>SuYϢ OUB,qK4seظxӞHhh61ל63 _N4w.4IHh,dÉBDH&Sd.Fl$ee&RP 1+6ZY:; kCXp3~^cT2žnV-[L4>hr4#h_J]+,x;ZG8I cDtd,Q"b0a,;O["Eg[B7j@M]fHYnjNB 3}պZ=|.7r v]kk ?p"ՊHJEk\4Mjzj&Q贱RAOl-m4^BJTBXYsM$p81ö!J1ϹmI^/W~9.dpbkwpOoX809&,ڕ˸h9t1uAW[+ŒÞyl֚sRnVP27e +CI 3038NoH(U^Ʈc)D)H1 r8.ha0ˢ)W $3I  |)S6~ЄPJ㗻7PeOl&4dZ'&TͿK Y<FD<5/xF>5+upH!zem~*t&T* 5Jvٴn0eF y͔-vB`dAV@ŦГ)1-:7 wR~A1DUh0TCCX,J2T,iZ0SNoNtdub5B?Fuxx9;rmY,]0^+/fDl0=8|e n`5G,!_(|V;[Ŏw3Ք&U)#D4q]|_UAD Ck#RzƆr୙`'='-B`R dz+zd-ݻ >jO5wP(%W ,@<e%\xW\t:E"*w~q?_Xrݝe)h~m `'zW(i!8-RؖI[Kx4XtV낶ۛ}|Q_T7BZ$%r%DhMgΘKHF="͚s)t+?{୙ądFYv}QA"#Y d,<ߘA݄Z' >ݪE}fx6g-]՗]+. YEV)D%gwP*aV{ȉ~vwRž vKY^NgUkGY?v&ˆb(sK$1R84_HLett2~23QZ O4mm_` p9"i43\ZGe,5s@&o>YPÐ&cmQ @]/;_?~0ׁ*"йf@"$߭Pb^ώhtC xu5X e*d3Qs3Ouo{ē 'M ]UkG1Yp4H hy~>l\Kۡ5UVBa*?p";W^>OÐģԸLmם)bs8Ceg d.0ޓZ4'uB]0 lS18CZF4] ߫4TeH(5yٖ*0{Bk_IcUâum@WB4pvCO & 1y#Q(>v为#bѓb[;GA&+iqX ]-h3zl20IR<3<3OŹpa'W+W,b )5GPvy `<@NhH+"1+!cgRv( 3x 1t,OIQc4 \5+.#s#KOsiqx8ߜ\sߙGIXU+p%l!i^D>s'1x♺%{ 24f^)\tmn=8= @ |_M t(ajY0'M}OUxPVΕ2rWeAp(J\:i:V"wvt%/h6‚RiҺRx'NqG bHfow7gQ=WOsõWssno1dãu̮h\aVݠÞQfk(f?dz$ƟӻDhדJ0b@NSa sdS9h 焄>օ0wi ,ѕ./п/?ۺnS.y>Gڗ_ux֞E"+?]{寞lz==8m,8],cD[Sf3x*D"n\F%?2rD̚PjÍ,(Pzo\WSkbt|5{P#k22 њ%`< Х=-\OoZ"t9ԕH34~,tȩjiGt \O&N*!DI_ Fs"k2v]ϟP*#A"T?0],˻肸׌~mr<<=pKB_]f6(lOs{u6!c_{I[aQ|v'R>c{WPr\/*.B֛c.%%tn$ZZsjGB{}LT*')Oe2--;ujӦ?.Oja韭 xeoǞ=fL|ap!0!B6Jܜ3E&-`$Œ I-F;-06O0)jVhjPD9&a:4co+(bլY@StefQ*>!Λj Mɂc-=) VՔv:!R6"XR]:OsvU-s"<}UK+t%͟>9󎃺HJm[r቙)e*6f/b Rr\OђJ5.W-z@s6W4SśNق"[4f|!siOl<BA;̘Nt'p*Ov+vlN3|29Hk[A$9 ټ.F($bЫkCժUwĢxf\:܇- YF3prڕkJ N趦k,je2ep痯Y,KgE#"A,K|"[}i~D( SH1U8<"'r F2]"@A "lA: AZR"ᣁjG[-ӞRF§PpJu/:k}ҷǤO۲͋?|Ͳ*{T]3fOTrYSK9e*G)i;V\[R {(P^ sP^I,9}s6Β;{bNX:^v.B-z76M,$~@!% F nPeaqJ90lĂ:򚩄ꝾK80}ajax~2R qJ1'Tf!vwf7=)auaq"w*^u7_ sO}6սE!dp+z \םGTmX p7"D"%-~ȍ`שԱ %ĈJ1'm5\n &Jt(bsJfU0əީ$w,mz3 -f@lۧs틾lqw轭6M ~ ^'NpItT_DxUzzSC\2m :MzE!Dӗšaf[f:S\Yp \_t8Ĭ8|.+:Ѳ9YY %' rE,68;D9CZldfO1kkUs5ڝ/߄Q`^s=`Fg깵5 eZ3'NA@+d@S,PΓ 8\e0H\O̊+sV EGZtiO "aYF dsy d8Ը^b^]?J~V d=,m}l[}@˂Y|f Neq]G0אae (J5j J &P%7a SAUr\F,F:K>eO|.c,c, a13ADH'7ȑg'?xGt͏wd#ֶ*~zUq'zlQ!↩MaC_ EwDx&|l+l6w@VJ2y dWL`A] TL% ]ŹlQU\LL.Gh] `$f)b́>w; $(VSi_A1sA鐓Qk+_Ǵ. xTUcy&B_7MeFLǪI(>B@䊊K2j`̅jB2d9Qa6o7R:Y"S"1#bz4r^`oNH&3B6W~/1LD)#&G`Ï)$c6a>|\qꐐ&BH#IaE۰=D[в"Z^DmC. > Ǟ&ۿ}K.㜫58.TW>vYϝ#`&'+O[!ؖtv|s\%[8^Ϲ؃s Ϩs%ASDDk,CA\Ollo (GX ia 'CzSǧ6JR,]ӬdE>؄|_'؉ +N`EېfLwu4mYLNJW;w3tP~"[BtWK)@p ΐB[MPj'8G*+'U#J*.`$g/iXK &/JQ,9_c\AgQ9 X)SH|sQ_%QBW ^_'ݤN5EQl۞yfƕPCiYx1J T/[B>BHx7]sF1r1vcO,$d7׿iX,@΃eJ,;ܙP+[|"fD-J\!e9D4#C*\OPtBPPr!Wxw3Wt\;jIK*_ B_DfA*iauJD4aSdQyz7޿2x=qcHd(eEr+-ĴX b+^z#Ix̉ $ӹ]kzs '=[;o.8EW1VS(,\' "*D%B5}CQ=6א*qzUj FaAwe}( ikA6i!5BZ杇߀?Ѳ<~=]©5ƴWy y<  0e:LX",3PM3 x`!.Q7CČԌ>B?o1sF֯lUhz%`'=wira8[LXlaQ<kHͿ`E۠N;EMa"R%ש #wNAV`iAm:p-54n`MͲ>O@E |'0٬.5/$ RRą<4{{e{. Ͻ#CJ=> tҌѱj\/b B @-UEU\ԢixWn)(ҨV* U`ka~z[v4:F=1>bR_@I q\ScˬgLpwmE m]_q:YS*MpU<{~Ύwj1[Y6(ׇ[P,xZm$:(˔DQHvU7/D\Cx:V'_ {W3^<{E/ Q((A_% Dm+҆gPXVC'멄0T|jHZ1vrynLOX!Fij)" 9}bli<vY6[uJpJ%ʼnʱz&_N;LXr5pDJY9*N(LCMh e\1X(#mr#Tgy(/T: T~-I|NEWe#h $+NU)eed ߏ>RpӡѷGuY u-+;צcz(DXdYM4 G iH|Jbswi{*BKibqR]gѺr ;-K +ɺ\ l+fpG~l6m5|:ӎe"kGD8n)l痂Ӣ H/!x">ˣ";@|f|>G`&~Ry3Jvsf< \XC0|Gy(yKa"[42$B'Xx1YYV4!&X;:y>+.")a݅yٻ{紞-9ְ`+AJr]Jʯo٭$#(16 7= x2 Tv+ zAPr1TC|ߣ^)K71o> Mӟzׯ?ghhÇ|+[M4+wup_Cb|1tO%)WHaYv¨*IYA!ɝ2h"*04ib^o!SF/˵\,hѢ)[ A~x?㛦t |Io|2xE#!RJ144D&D"Ql.43b8##Czyzٍs.L eV^7Hâ e/WE0;^zKFQ>SyFv$H i0|j"t?YƔQ9CSH7w# uM+CJ%5ࣇG}k&tb\jWzbJIIJ^^wZJ:D!l4ۨ/ ?ЁO/WGdi.,eH"Y)bE2xW)Y +1r17%l;˵\};l9W,ׁ;o2PrDS9\MWj1װ Nv38+$]DқsaHb[%<ߝIp=K#E _DB"oBrt=:X&꤬#aQʝhr|L3iqMo4|8<*Fw+$#4٦dٜ}Zz J6PaRL-2s:V>;fԶ!J4t+{i v#dN%V0 :cJIV/W9Gj'YN!ZoOT ;IkV]s߈Zb\g9;.><68BIrÇp9☞g|LY*1eK)0~֞#GWaefwWCKF2i{$v?cЯ ۘΛXriYB)[V(] .a1KA_L[D*x"p.wt/ acQh vxbZ筡uXx"EI5Zi'X}yܸJy~y+A!)cL߮Q̍̚M=_k;l!Ҟk:Cؑ䫙b6}2BO17gFn8g]$z֡K4u:+!`Y;k5🿂;v@q M ;^YW rNʉa&°0!, iHR*޸GZx17>{JYcG8Y{'1"d?gp}.pb/Htò+!gnQX˻Oi_> a.DF nTr 3Z kaZ>?Т={%3hH9sOJd*zϮ{nҌ$Hu[t[KŸ^ x"`F[Yv2o{-S tW!|lSFNٍC_4~yCf4A"]1x3bCO~w!5 uWP MXiV7O'SG6?Ho.2EK4Ys?k[Yw0uv Z|0dIES Hv)eBl M㖫+g|01^sD (&vHx~N!Y}Az$0_IVg9ht RzgցQOpbޅѷvJ!@aPxu`&J&Ao#G{]wwPf ;9`"2!6 X8#3-mκ&p8R`Y&2()gkZ-R(!70v)})L;.@ruBq˕-kɐ"B}1^Gl!SNb=th^cUM$H@rޅبD/:uEֈeݍKrglvv2tws7C|ǡad]&v0)dwe,D=U1L_R-Ws\dҿ'(o*^kxaba3qØX\٥x0SKq3xyVgӆY9Jk1a^NV?Ht%7srn廄H^qBv0wl ybGI}և8࿐_ ÈN[H }{y_ xrκoH̻\GTϻAp ƐkswsJ9Ќ&F3N;CP/k),+Xk* !U&5SZnYlgx7z3|x`yȏrUz 喦}YfbCOXnmVD2eM]8i!lSf =S34Uf^%fRifK#0{YW{vąеT֨ 7kԯ0v,;rBR=G!ri$ poc܋w&KF,!3gVi XM(HfpIbY9 7[j.`90@m?ͦͼN9>l Ქ2fX޲~ l>V"&u{BY)80tAP{z$+V,Yn.,(G==3YS~x C{YrL* BJ)l{uAId+MRBx?w]Ph%bx"SwQJ1E)[p[#.P#IfNٵeǝ`pyZݰHsyv't+o@ /?clB9z}+GpFk* 1Q졔8psϸ5ɎSzM| 7aEf+OϜH3vҳTMob'OvF?Ё -9͖gJ>t5\pɪnAg&o|kO;_~̡yپ!ᮝK4W^VL:0b-{C2ܷz?1rᦺn<ɛXLbjy}12سcӓ.ā#>^|-R |vĊaESDS h_r- 7< +ցB⺥J3)E,WBilip*e=VU:8TK# ?aȓ:`)U.G<`N_nW\~Ųzwv }]˯y ;~X{J?Ȯ[{wꊕ{\J!9xA 5^諽s܈;~ކ6Leh+_mcG\Zn{oǏ}'kxTŘ(붕%QH)8J |O6g,ж2l/0(\N`QVTPnR{=qڞuanOYQ;,>X`3yZEFG`[/<{T'8uRD#S1'8?rw l_q\cƹmQb QRp-rٷۙun;R'.h_!3(6m.*0b=&׈U˚ 7ޭS>0#ViF0(Ҍ"й.W}ט$߇HTWفl/_8jꁬNOzP^)x-^*?x7H)=U n6x^|6gJ8魒4#v ӎa) ;a$ upKR-'7^rC,@ REdRՙN5bMX;VnЛ(ֲX 蘷dG1 +0P"z8!";I+y7#{?cjY6%S_ႋ,~yG|s8{9Z=-xxb7\WTw|?{ycSK$G}εz%s>V 3҂Ry]|'[+ =߹ὔ2}zM{$kJ140a:0So7t_eŒ.\˲?G;!H"ֶEӽĻÎu"$rNfB 6BҶ(+)oe`=M1o})3;\z +(mf4 ^7?yCR02?|92/dY,ty=ѶZǛk1AA/RV $] ~Ғ[Ux) 7) g7Ձ=H&S! 2)Ҋp^U|hQ^E'SPi|7KuudB}O40@&Og_'j8a ^uͷ'=֠V[L((o(^bVbP's|I@ ty j"Á#=EǫڭdD[I7hD/iQQcZoV)RBiT*ҰNbJD`Ir8Nk2pm'=:_ϑS|,X, ?tU[N۱,|>ϡC9\kg`bϥF-/AޡſM|/?%K`0ε<'X3]E:І淓A1窊d\!qI`Z9\DNa $ËfN;m*J\ћ+e !7ϒJq^i WB8VX"#ٹu9vb>°t'wo:)q GkO:Nk[EV ;$/4MZ[[r_b^cKN܋aň-mFږ\J 1#I2Ǟd_XXHE'?zP]ݒ|,J$ZqDי&bP< hX(}n?p^awFU6%j$B^[ |ن.&aؖr預1<\@rɵ8!>=M#@vBiʼnѶr:eW%D/qEczYb DJL#4[)@X84x|HͦS5P!ԭ4VDwΉ?dwSNӹ@?-ϧsFGzHݳz_?Mf0 2/L8W|SY-4xe,%,YnO Fj78eKYs*}>wȯ(yχcwȠ#_dBK }6k'K?ľ&<`{a*TwrvmߡeV׼h g),9A #Q?1 Ҋ5V R?L?ožu<MƦ:Aې S5X !uaFEz)S/8um=nуSJX3# }|z1-ݫXs?XrR=l>>RIku2DNż_ZZZmmn>MO9dӊj#N3WyY}nmݕO1|1#f(2|aF?KږcX K(*U1S $ByYitKik9}CqU$I8RJ<#%$σ]/tH/4ss5g_-}eHj T-88Z.1<@vh7 Rb"A(Ncz! *Wp5Rw5pRzt%]:5)ILXx,|EǢb1bQDTIRQE1`U}v{OOPef<2tAluCu |F?W3;jpVD_b\2LL&B1 <]F|TsgnHj>k^Xymy)2a_ibYmc6ibFy-BJyw1zIX's a %b PH TXyaH4$RjIΐi4W@n9ӁNMIKZceWNĕɖH,S(1|I-d c#O<ǟϔ'&ib18hB}}qJB\.G>Z{a&#P"tz+2}opǁX)ѷ\~eWX6Zn#47or94Ôcnye&ʴO\z @y.%klYDfCV/ sfqmO(l^^TE} VӒؖ"bBRH!PK$y pD84VUr<ўPc&K qrO^XĴ =39-+G<w&B@mmmR)hӎ'0J^R q( 266FXli=o>,~ +^.k0o&ۿ~iGW .A̢Rb7j$'X,Xw3Bc-p/?X,VX,V4M"J(u) 122BPh8N~}#^)ꗽ2mGI&Mb1mj.[nø V]Qh&.'sǑkh6/0%$cБ2ID.:O#4A<&,Xg$ȕ$Sȳ_D.RmO;OQd "q ?%iM"ieu?sGW`Ʒ -4?mۤR) u,7HkS(K9WSpO4b҂eYD:LH$$NYpX}0 mLiIƉEXK02 Caۊx'UR>ټOhy<@F)G{q3(=!!iОDm O5MNk'CRJ"ݤR)+Z1>Ix7]s 0naR/He}\?{+?sD!^ITR4=d4~y\Gw r ȸkL`6Or)?J] 3\H,cɒ%R gKJќDz,9RW+)5x4LϓϟAA;nzga@Slfɒ%zst24~mGO0=ʶ>¥ҵL+saji$bZC(8Ɯ]"HLզa.yڇQ(@!:)RqkX;ZlVx1x3uM}nSK.%w(qPt"E"𞊹BŋkDj:6w n)\ۉؖAGʠ_ih84XlVE"n#28PCNIV 딚.bMDKC[x¯DXhQ =y-uEϿ)d& .-'ͨzS .9obkYv^uH54=(B`- c+@n<#cIΔO"f7=QAŀÆ1O_! 0M!X\/8XH푯pK)%͛ 6 ޸TsȑMP`E/39%Qa_)R:ֺhV/i6 h4yRV;_[[RGN>=ևʂbEULJX(;NJ)!iIX`!Sf-zfh7֖ب漾7.82*PNZ-HAEsf)9qoE[Qvttfo,XŋIRJGG|{ߣX͔*ozG ."= Ӄн./ӌ־P"ofttFGGֽfkk+]]]H)O\Wqgg'l +NWM|-P,hs+0+"D`uDӁ!AKB!p(yEǨ;0c6C9b%i4RzBczmu)|*J` ډgx{dG'FZE"zzzJ) àt:]W^~=Gioo i9r~^X׽^u] = Q:xG=\[Qo;/urQm3omx+ ,J83Anx'<ϣ7=gvlFU|S!=ر~7Ӄy!!\;wG[[DPv]:0~/G `dӚѨjKeç tJ>lFfCôhKJvr'C!Z4<H$IDAToaHjuBDEYo:9i6-ѹZdʛ) IL&F- !hooghhhge˖-XeqgD&{vx=XNwN$='˲Xv-e<6ỏ'3]4..Ju:LK4և'Ao95NAL\ȤzҦU;lVhĤ-(:ZJ?-"ړξEΖX'Tp{%;a:rZGGGP4%O~T'/]JIT=r #B'OaJ%"H bOOprA)!c I)Od*:,DBFwbgZ[[W"GedddRqX,rq" ,VHd2ȄD1v^TW 5LBC7c8 C=8WM ]|%|mO!8yvxxiϮc!͒H$Z{"iOZ҅ܪ:t]U-MStML^=~-MTűy.:̳Yn=u^u9U=QZmgkYrЍ)<$݈􌯰`1٘h:@a4AWMYd[N>Nާm q99I^A} U ~rFJ> 1Y30Si|h 1~фFȜ׿ZŻh_u17~Eg:G5ɄH7#-=>c~ `] KDc èT:U/ r^ubB2.`4셞Tif޷^"aT6ڍ}  uue3z|$xCMt[>M&hr[YjӼD[!4֥#ٽݷ28Դy]ɷg9̒eU&14<+/PF͏Z׍=[ +Y;O@ӼqRs*QO4H覊FAz|~[x=UGk)UKn_qk/H %&`̿3vj M9ԺD~cxoBC74um`Pb>~Ӻ}$6"W器O+g#pԧ:H/~]Onŏ =3~w˙u8@KBi\\2[=P}S1;g/ѩB1yU?ktSEQOm[oнwliald*vO^sQ$3L l Al\O!u+?BG3S,=+f(p\ehFÌniNaF 'VWn#Fӕg-}~dK+zWp51Dg$J~7,θƊ5jؑzrR{S9S74M8tUqzIҐQi>B誱cD;#ulK!+I "}T>B['_׍أP ys]z;58U 47/0f~$TOGZԐJt}Q_N SJN&ѫ0?DŽ+ڵ#HK~xC sx|}{nm׀)5b#W=y`^$:֡  Bݼd29m^,j_MѴYI9r)Qm\T - F[&|d뺒aC ,h~81_Lq<]VSwm eduBJ!eYG6Ld W0E"‘z_|2IܲA~I㝦OZg H`eҲή5>s]T*հ3+tRZZZQ4V.]ڰ4%:VcF[hX^b;ODJƦ%KZ7/_>%-)NW.n&H*gvWldb# Q륢\6bBG$d-}k1b(tR%˕ }OspOetΪ鄚N“'/՜t_O@y;:9if%;|WF3zdddM$\ނKDkMXpSU nHr'#R.J4B )-:hz8BS#aU0 YBh,Zr2X+leuKX$N7 `Piwmmm~]KUDSMR222RmFIvn0R NN.cE݁j-K&뤐D^,%7]imm˲( 6Ms;|ytt94xv4M _!U:!q)n, yKh_*}YtZ…[2Z+ijN2Y&UJ׼`%v~M(ޜ)2XJ^cZ`p:Ou1A* ;.D׼u>R')u`O7P*Zi8UihR"M3ƺMpGNe``GT3t#܄XH;&2U^Hh+6|͘+.}}}UMӌ~ńÍ9ׂ<`v[bʏכ R9A hjfO7 xY*H&{ttDhYt*- O)uEt%!7@z?S!l]%Ջ9Ǫ6y=22RǼYtfŶMPX/R˻,ϴ4`{$Bq%ZDsgL LD} OtXšC+eYzzzifyk/ƈ$U5XXϼn 0W6l#2qi84Ӕd驚ť!6t x;3w k2YJ,%pܩ9A_ฐ/85iJC41č2O!يljdsYgi:4csbȡCjn_v6KFoJ)NN{&ױW8;Eg xM-?V=&sС  >U>1!fVm^K _t}JOS"HLH>[#Rj:؍xhZ: ق0 @r%EuUocxxVxgN ^P(pD Vgbdɫ>ؓ|r`h\a߉5UK)1",E+J8p@sco.k"ATRo"LGÜg8d.:*I)(8:)ь=R oзv@[z;~ ၙXT7K ;L7Јznhsdي3If2_Yia_uv ]TZu-lUiT $MAn34(߿T*uTxJطo_ֻH.KWin 콆x3NPͭ MH)%hVv)% .ڂ ѻHYTVȗxi0)KOGXj{ǞkX,M%crިq(ִbӵ8B0-l'萨",FM &v/߁AV5O5 YCT366FWWXlF`ddf[%43:z]/`y64L,ShQL,!qiu3ΒӿB!}jvXu6IS9לS.2Fz~#HdQޟ`I$u4}rOqH1^Av 3A{4`_(TW]8-c9}*M\ehhT*E2$Lβ4cccMZ#4yfmW|EMVe%c9i Ɯ+ioI8m^$ID]5\<;ךnԫ8F\[N5Cje!4C&n4bO8 L#W:drp|waZpJKIMnh-{WC*0c9~Ny'0Hx޾>k9|rLL&C6DQ6)NoH.o" CҶ$vnB4B ںx229$oH:4m öCiWڞ(%۶lSlAJ,`yH8́gon|GISPYX^7,!d!"VmZZԢݬ> ڲL1SqHӤR41 5,?wOfg^)Hda!^BHI {7Ȯƅt%( H%b gߚEt4]W±8.d .iH u1I񟈵bSTu]ֶM[Yoh_A4=T*RzaSp]IX$f0D s\hk?) >p3KN?3vǧLFԢļ,?Z}!3[$1&AtH+Bψ Ei Ks"s 5e^;JmTa0/L.fކԽ}މT)ܴyfɟ'ڲ;4hFɃ/ҥb[YBE WX |tDF>-z_ԡYP9*`4+dXԬNRUC)I:ob \aPU$3=Cjn]|*M\Q` 2d"Zٞ*#ZіrL!Wƙ+{ ֶw:V_B˷3Sɸ@$εk$矂fDurZađAP6l0" jGtaEޒ要mQx/4ߋ,cOǚKn߸~f:}1GǪZw%-BŽAꅗkj45B>릝BQ2q`*^ҍw&O?9+sǮxDc@V@H M 94E$N0 sqfz8T#U .LA'סC#<}ߐًS2 &4ptk? >T[@q\wu56!d az霊s=ͥ` $W%<@@^vx^K"; CoC| jmP׺'ֺйRmA3Uy]5uISġ%.E 4]c5`5Yבd.)=lxF{0 m-oOF%͕r8O}w캞W혈iY04IĄX؛5l@Ww8TިeKUƞC% RI;,Xa()XjϪhf ڈ$DrH4G5c..-!]ۻJ A$lDS<<~Ǹp`x5ߜY-Hz] ]iBU@_ Op\ϔP&LZ8 N1E1;#Ql+DC3cfBvp=C3"Tdkf 7E] i Xҽ!Dx,aƿ4.)xyln WFpRv' kZyl+]ΏZYtacQ0["0ݘvP-@uS M@pHD\bapHj!MQuF-ZT^h׈,q b?p嶛9}CDC-v?!d A$jx.kgyիvNI2rJn{D}Ɲub;ܬڈVq+TMz i ZrDZYnY\m$bQܙfTSEHFKQB"pepx$O?LeJ 2Ќ6 ll@8/>ۘ I,4ˆ2PVބtIRE l ^QUx ŭop[`OiKU ?A/B-H$ nw>@ފMIXԇ LaYYlR}l uM0C=8\#ED%hin"6l-\5ZRT^rϡE4Gi\;bd ,x˸s޻Wꪔ|@..9pҸVq!IՃ49fqx0K\Zc6-qI8˞d xʒNMv.zr53}LWk f1uRe:Z 2u[I]Y/{nb'1uU{o  ZHlɕ@s-lIS]Vj,~9hGacAi,_*jmXV+IjM"e J:!6{,)-@rv2/\WuR+*v>]˓ЎzKզݟaͼ]\^uHj2u[ay]{U Q$}@hWjw޸\۔**΄ĠY\;eqɥajTǖ!$zikBuѰ٘\T@y01=0Lk- !tEiu2) ]2v.rKգ(u67Ç6~Nɀ;NaN>MlP@@17* Hfׁs} v=dᢓGsǰ, ]4C7Wth" WJ4RC*KU4uJvrGSEƩ 8L݈&l2Jvvmwro՟chDGo8"d/j V"3S*GeMa|;7^R#dٶQvnK#djI] |1bT l\, .塗olѴs*c MfNQ H m!/t^d\'Wtye_7f)Xh8D{[M^ ASښ4ڛmM* !d&%tqPۙ|?&V7tںt-nk^dB#C(NI l% ?DѲKHmM&kX0J{$d9wzOc ǝ#v,\ /rŖoqΚhrPFDyRm Q8KPs7H7zqǮ[.4'jhh0mocAG]LmLev_r`e.hpIik t :ᛲtA%2_G34\yWgOdI-470tQq_8zqg7 8.<;ƅOW?Ͼ'},$d>0l* s\ɻEt\q  vU6'oɧٷ?3dq+/_̼xbaxDyЛ!`yb‰h$̥gv󚉄u\I&$"!Jopq@1>Γoe1sr $BpЃS/LrkK_w_Ar!yZbmanicŲDb1c۟ ܗ$34RBkkK?kudAɇϊWw~fUSJFGˁNA%/ GVrXK NwH)u^;X.HjCׁ҄LZ5l5r۾",^\iY.9m#:*'-!j.-H~ȪN ]9)vnWyj#؃ߎ+yJhO_rϞ/ka$q\ma|#iI; 98j JcYYVl/QcO)K$Hˏ;8t87%=OJqN'n٫ Z*e 3_y W,;5Iijϑl:En|r{c׍<|P\xcx фgb8{ս$"c\8;ldj٦ `7-{pہ/;PaA9sx˷AZy/+AU:%oZQ08Y磗v!hj+pQG*\(ζ754ƭ=^CD;.:6NCp9h9v+8&I9Jw"yǁ*JӅ=|ɎwsǮ}}XvxNej^mDx!@$Iӛ?OL,^)QG].0J[;ޡ=mGQm}#*0[sWl6+^PDuuB8GSUE+c <\T1U@X G_|'8IT9*AJ%AiXzy^Yt/Y9;ʵgAǖ Y@}q_Ց-B?y.~Ķ%2Ǖ%7!1A(:{I*r2:e[S>/_  R sׅ ]x(gP0v*%r@y&F@e=t(ˣJYui>Sڞ=Nе5;T.m]{d^-ؼG}z۱vd?C8i/+ >8k}ܹz~%d cfK oUnY!uIJu ]YhdR}(u *dQoѣK+M ?MwΨDU =uBuh5o]f΀S?)'J}r5 Ηرn}/{1)[R(2=t4Axp-z%6}  <UIt >Oָ;ez/7|3WO(̀}2˭.08V&H-r#:)aoO~g\`$ݪG;AkKdY^)%#EG#%O]{&LS45w ;sxxw8ﶦ /]\t^Cʲ-.S>v#qx\@ p J;%:KYr4'LO@`O# Tt߸\Ǜ}ܵ^uރT y+*B6 ThVjtbqhjF"i|l6$/rxRyb pΦ)2ŽUp[XI7pX!y, V#uⰚ3zNZ-^n5@e\ȣ6~G{yg`~秙R{%6H$DNr]lrYY=rH450Q@בC,FmS:xviؼw\fN^a3_K]k!㍪8JjdX06'R^ɝHC !.mN]0~O-iQ,5F26a?_xI@"ZZ|rJ: $8mF2;3Vj*["޿vcCCro\(2*k0a5)Tɿ:I$p)/!8 ^MzN]"Shj_ KK\iQǗdn975®,J{3vHim1sYv4%-{ksRA:$i~s&qXADWxƎ{*s{!w캁Xkla.m &pHZ8]fX8!?+EopٖrҚ%qA0 pDܘ(yvXUK'ƪJN gW!s`+Oj嘼t nu#ϼrV|@chȥ5!I4L,6 @RmΆ%+;'+h7pu?Û%d#y*:1[୨*b-noa73I~]g%U$[rxdiL>%C$qD tM KQ29`q\,[R$a,oR4\YYyS`A^>\6:'sGQSΉ\iA<7ygm\ojC;SEऊZ4.!8۟]ϥhGYבR-bk!B[r )઎ [`;`;W /nJ]nqΚ;bYWE5<rp|&pzČcbF uzi+O@Ny+kv&Q<%Ku)& {sM<J2l[(Wm&[<^̯t/D Drvӱ*Xh8[͸U2P\$*R@~<5-FO[R7Vv)笹Hm;Wr>\B;6f* b81>js&5eFV5MH +,M9J࢓nߧy _=q#` 2Ί𚵝rZб@ةɟzʃ(Vg9;v rִEe~g+~ve~Bjœ^}8dPYTeT VR[iVvI HA&L;v5<וTc 2M m7qLV׀[Φ!.ue]!,Z}1hcwWrׯ|t1GW|w8o/h N~?nA*X܊VozGQU>T٢r_B 4lW۹c׍S1+xAt$'\ T7__9fnz gx$5|w``~n9`jč3N.(G\M؁ TXW ]7`,ZS`~ro>t]w'sPwac8J߸qN7xs&IO;.ǔ5:QoDE+̮rs}l+wqoEU]!*+ R߃%!stqjj5@x YV e[ygiض1Bfvf'8 `8l&sp٢9 ` {S&.y$.a|٢,0&d'/$?@m-}I]?F{ȃK_}:#E2&_F`&,ב > dy5ɩ@7OzODUSHz6,TN/9s KTaǁT-?$G ㈪8tv\ Description: Implements the efficient algorithm by Ortmann and Brandes (2017) to compute the orbit-aware frequency distribution of induced and non-induced quads, i.e. subgraphs of size four. Given an edge matrix, data frame, or a graph object (e.g., 'igraph'), the orbit-aware counts are computed respective each of the edges and nodes. URL: https://github.com/schochastics/oaqc BugReports: https://github.com/schochastics/oaqc/issues Depends: R (>= 3.4) Suggests: igraph, knitr, rmarkdown, testthat (>= 3.0.0) License: GPL (>= 3) Encoding: UTF-8 NeedsCompilation: yes RoxygenNote: 7.3.2 VignetteBuilder: knitr Config/testthat/edition: 3 Packaged: 2024-10-07 09:19:36 UTC; david Author: Mark Ortmann [aut], Felix Schoenenberger [aut], David Schoch [aut, cre] () Repository: CRAN Date/Publication: 2024-10-07 11:00:02 UTC