static void process(Agraph_t* G) { Agnode_t* n; Agraph_t* map; int nc = 0; float nontree_frac; int Maxdegree; Stack stack; sccstate state; aginit(G,AGRAPH,"scc_graph",sizeof(Agraphinfo_t),TRUE); aginit(G,AGNODE,"scc_node",sizeof(Agnodeinfo_t),TRUE); state.Comp = state.ID = 0; state.N_nodes_in_nontriv_SCC = 0; if (Verbose) nc = countComponents(G,&Maxdegree,&nontree_frac); initStack(&stack, agnnodes(G) + 1); map = agopen("scc_map",Agdirected,(Agdisc_t *)0); for (n = agfstnode(G); n; n = agnxtnode(n)) if (getval(n) == 0) visit(n,map,&stack,&state); freeStack(&stack); if (!Silent) agwrite(map,stdout); agclose(map); if (Verbose) fprintf(stderr,"%d %d %d %d %.4f %d %.4f\n", agnnodes(G), agnedges(G), nc, state.Comp, state.N_nodes_in_nontriv_SCC / (double) agnnodes(G), Maxdegree, nontree_frac); else fprintf(stderr,"%d nodes, %d edges, %d strong components\n", agnnodes(G), agnedges(G), state.Comp); }
static int visit(Agnode_t * n, Agraph_t * map, Stack * sp, sccstate * st) { unsigned int m, min; Agnode_t *t; Agraph_t *subg; Agedge_t *e; min = ++(st->ID); setval(n, min); push(sp, n); #ifdef USE_CGRAPH for (e = agfstout(n->root, n); e; e = agnxtout(n->root, e)) { #else for (e = agfstout(n); e; e = agnxtout(e)) { #endif t = aghead(e); if (getval(t) == 0) m = visit(t, map, sp, st); else m = getval(t); if (m < min) min = m; } if (getval(n) == min) { if (!wantDegenerateComp && (top(sp) == n)) { setval(n, INF); pop(sp); } else { char name[32]; Agraph_t *G = agraphof(n);; sprintf(name, "cluster_%d", (st->Comp)++); subg = agsubg(G, name, TRUE); agbindrec(subg, "scc_graph", sizeof(Agraphinfo_t), TRUE); setrep(subg, agnode(map, name, TRUE)); do { t = pop(sp); agsubnode(subg, t, TRUE); setval(t, INF); setscc(t, subg); st->N_nodes_in_nontriv_SCC++; } while (t != n); #ifdef USE_CGRAPH nodeInduce(subg, map); #else nodeInduce(subg); #endif if (!Silent) agwrite(subg, stdout); } } return min; } static int label(Agnode_t * n, int nodecnt, int *edgecnt) { Agedge_t *e; setval(n, 1); nodecnt++; #ifdef USE_CGRAPH for (e = agfstedge(n->root, n); e; e = agnxtedge(n->root, e, n)) { #else for (e = agfstedge(n); e; e = agnxtedge(e, n)) { #endif (*edgecnt) += 1; if (e->node == n) e = agopp(e); if (!getval(e->node)) nodecnt = label(e->node, nodecnt, edgecnt); } return nodecnt; } static int countComponents(Agraph_t * g, int *max_degree, float *nontree_frac) { int nc = 0; int sum_edges = 0; int sum_nontree = 0; int deg; int n_edges; int n_nodes; Agnode_t *n; #ifdef USE_CGRAPH for (n = agfstnode(g); n; n = agnxtnode(g, n)) { #else for (n = agfstnode(g); n; n = agnxtnode(n)) { #endif if (!getval(n)) { nc++; n_edges = 0; n_nodes = label(n, 0, &n_edges); sum_edges += n_edges; sum_nontree += (n_edges - n_nodes + 1); } } if (max_degree) { int maxd = 0; #ifdef USE_CGRAPH for (n = agfstnode(g); n; n = agnxtnode(g, n)) { deg = agdegree(g, n, TRUE, TRUE); #else for (n = agfstnode(g); n; n = agnxtnode(n)) { deg = agdegree(n, TRUE, TRUE); #endif if (maxd < deg) maxd = deg; setval(n, 0); } *max_degree = maxd; } if (nontree_frac) { if (sum_edges > 0) *nontree_frac = (float) sum_nontree / (float) sum_edges; else *nontree_frac = 0.0; } return nc; } static void process(Agraph_t * G) { Agnode_t *n; Agraph_t *map; int nc = 0; float nontree_frac = 0; int Maxdegree = 0; Stack stack; sccstate state; aginit(G, AGRAPH, "scc_graph", sizeof(Agraphinfo_t), TRUE); aginit(G, AGNODE, "scc_node", sizeof(Agnodeinfo_t), TRUE); state.Comp = state.ID = 0; state.N_nodes_in_nontriv_SCC = 0; if (Verbose) nc = countComponents(G, &Maxdegree, &nontree_frac); initStack(&stack, agnnodes(G) + 1); map = agopen("scc_map", Agdirected, (Agdisc_t *) 0); #ifdef USE_CGRAPH for (n = agfstnode(G); n; n = agnxtnode(G, n)) #else for (n = agfstnode(G); n; n = agnxtnode(n)) #endif if (getval(n) == 0) visit(n, map, &stack, &state); freeStack(&stack); if (!Silent) agwrite(map, stdout); agclose(map); if (Verbose) fprintf(stderr, "%d %d %d %d %.4f %d %.4f\n", agnnodes(G), agnedges(G), nc, state.Comp, state.N_nodes_in_nontriv_SCC / (double) agnnodes(G), Maxdegree, nontree_frac); else fprintf(stderr, "%d nodes, %d edges, %d strong components\n", agnnodes(G), agnedges(G), state.Comp); } static char *useString = "Usage: %s [-sdv?] <files>\n\ -s - silent\n\ -d - allow degenerate components\n\ -v - verbose\n\ -? - print usage\n\ If no files are specified, stdin is used\n"; static void usage(int v) { printf(useString, CmdName); exit(v); }
const NGroupPresentation& Dim4Triangulation::fundamentalGroup() const { if (fundGroup_.known()) return *fundGroup_.value(); NGroupPresentation* ans = new NGroupPresentation(); if (isEmpty()) return *(fundGroup_ = ans); ensureSkeleton(); // Each non-boundary not-in-forest tetrahedron is a generator. // Each non-boundary triangle is a relation. long nBdryTets = 0; for (BoundaryComponentIterator bit = boundaryComponents_.begin(); bit != boundaryComponents_.end(); ++bit) nBdryTets += (*bit)->countTetrahedra(); // Cast away all unsignedness in case we run into problems subtracting. long nGens = static_cast<long>(countTetrahedra()) - nBdryTets - static_cast<long>(size()) + static_cast<long>(countComponents()); // Insert the generators. ans->addGenerator(nGens); // Find out which tetrahedron corresponds to which generator. long* genIndex = new long[countTetrahedra()]; long i = 0; for (Dim4Tetrahedron* tet : tetrahedra()) if (! (tet->isBoundary() || tet->inMaximalForest())) genIndex[tet->index()] = i++; // Run through each triangle and insert the corresponding relations. Dim4Pentachoron* pent; int facet; Dim4Tetrahedron* tet; NGroupExpression* rel; for (Dim4Triangle* f : triangles()) { if (f->isBoundary()) continue; // Put in the relation corresponding to this triangle. rel = new NGroupExpression(); for (auto& emb : *f) { pent = emb.pentachoron(); facet = emb.vertices()[3]; tet = pent->tetrahedron(facet); if (tet->inMaximalForest()) continue; // We define the "direction" for this dual edge to point // from embedding tet->front() to embedding tet->back(). // // Test whether we are traversing this dual edge forwards or // backwards as we walk around the triangle (*fit). if ((tet->front().pentachoron() == pent) && (tet->front().tetrahedron() == facet)) rel->addTermLast(genIndex[tet->index()], 1); else rel->addTermLast(genIndex[tet->index()], -1); } ans->addRelation(rel); } // Tidy up. delete[] genIndex; ans->intelligentSimplify(); return *(fundGroup_ = ans); }