// SPDX-FileCopyrightText: 2023 Ă„min Baumeler and Eleftherios-Ermis Tselentis // // SPDX-License-Identifier: GPL-3.0-or-later #include #include #include #include /*** * Print the graph's adjacency matrix ***/ void dumpgraph(int n, const int *children, const int *childrenlen) { int adj[n*n]; for(int i=0; i path[k]) { smallest = path[k]; smallestidx = k; } } // Now, copy cycle to `cycle' starting from the smallest int j=0; // This is the index on where to write on the array `cycle' for(int i=smallestidx;; i++) { if(j==*cyclelen) break; // Stop filling in, if we reached the end if(i==pathlen-1) i = startidx; // If we reach the end of the path, jump to the start cycle[j] = path[i]; // Write at position `j' the element from the cycle on the path at position `i`' j++; // Increase index to write on `cycle' } } /*** * Return 1 if the cycle is not in `cycles', otherwise 0. ***/ int cycleisnew(int n, const int *c, int clen, const int *cycles, const int *cyclescnt) { const int cnt = cyclescnt[clen]; const int bs = blocksize(n); for(int i=0; i parentslen[i+1]) { return 0; } else if(parentslen[i] == parentslen[i+1]) { if(childrenlen[i] > childrenlen[i+1]) { return 0; } else if(childrenlen[i] == childrenlen[i+1]) { if(grandparentslen(i,parents,parentslen) > grandparentslen(i+1,parents,parentslen)) { return 0; } else if(grandparentslen(i,parents,parentslen) == grandparentslen(i+1,parents,parentslen)) { if(grandchildrenlen(i,children,childrenlen) > grandchildrenlen(i+1,children,childrenlen)) { return 0; } } } } } return 1; } /* Random nubers */ #if RAND_MAX/256 >= 0xFFFFFFFFFFFFFF #define LOOP_COUNT 1 #elif RAND_MAX/256 >= 0xFFFFFF #define LOOP_COUNT 2 #elif RAND_MAX/256 >= 0x3FFFF #define LOOP_COUNT 3 #elif RAND_MAX/256 >= 0x1FF #define LOOP_COUNT 4 #else #define LOOP_COUNT 5 #endif u_int64_t rand_uint64(unsigned long long max) { u_int64_t r = 0; for (int i=LOOP_COUNT; i > 0; i--) { r = r*(RAND_MAX + (u_int64_t)1) + rand(); } return r%max; } /* End of random numbers */ int main(int argc, char *argv[]) { // Parse command-line arguments int n = -1; int NONDAGONLY = 0; int NOSINK = 0; int NOSOURCE = 0; int RANDOM = 0; int UNKOPTION = 0; for(int i=1; i [-r ] [FILTER ...]\n", argv[0]); fprintf(stderr, " -n Generate SOCs with `order' connected nodes\n"); fprintf(stderr, " -r Pick directed graphs at random, and exit after having found `num' SOCs\n"); fprintf(stderr, "\n"); fprintf(stderr, "[FILTER] Consider only simple directed graphs ...\n"); fprintf(stderr, " -c ... that are cyclic (i.e., not DAGs)\n"); fprintf(stderr, " --no-sink ... without sink nodes (this logically implies -c)\n"); fprintf(stderr, " --no-source ... without source nodes (also this logically implies -c)\n"); fprintf(stderr, "\n"); fprintf(stderr, "This program prints the found SOCs as adjacency matrices to stdout.\n"); fprintf(stderr, "To exclude (some) of the isomorphic SOCs, it uses a degree-order filter.\n"); return -1; } // EO Parse command-line arguments // Setup datastructures int parents[n*n]; // Each node i can have at most n-1 parents. These are listed at parents[n*i+k] for 0<=k64) { fprintf(stderr, "Too many graphs to enumarate with an unsiged long long integer (number of node pairs = %d)\n", m); return -1; } const unsigned long long max = 1L << m; // Largest `graphnumber' const int padlen = (int)((float)m/3.322)+1; // Convert log 2 to log 10 int len = 0; time_t t0 = time(NULL); time_t t = time(NULL); srand((unsigned) time(&t)); // EO Initiate graph enumeration fprintf(stderr, "Generating SOCs with %d nodes\n", n); if(RANDOM) fprintf(stderr, " Picking graphs at random\n"); if(NONDAGONLY) fprintf(stderr, " Filter: Omitting DAGs\n"); if(NOSINK) fprintf(stderr, " Filter: Omitting graphs with sink nodes\n"); if(NOSOURCE) fprintf(stderr, " Filter: Omitting graphs with source nodes\n"); unsigned long long graphnumber = 0; // We will always omit the graph with `graphnumber' 0; it is unintersting anyway unsigned long long graphschecked = 0; for(;graphnumber < max && (!RANDOM || len < RANDOM);) { const time_t now = time(NULL); // Break if we exhaustively check all graphs or if we found enough SOCs at random //if(graphnumber >= max || (RANDOM && len >= RANDOM)) // break; // Print status every second if(now > t) { t = now; const int deltat = now - t0; const float rate = (float)graphschecked/(float)deltat; const float SOCrate = (float)len/(float)deltat; const float percentage = (RANDOM==0) ? 100*(float)graphnumber/(float)max : 100*(float)len/(float)RANDOM; const float ETC = (RANDOM==0) ? ((float)(max - graphschecked)/(rate))/3600 : ((float)(RANDOM - len)/(SOCrate))/3600; fprintf(stderr, "\r%6.2f%% %*llu/%llu (%i SOCs found, %d seconds, %*.2f graphs/s, %*.2f SOCs/s, %*.2fh estimated time left)",percentage,padlen,graphnumber,max,len,deltat,padlen+3,rate,padlen+3,SOCrate,padlen,ETC); fflush(stderr); } // Convert graph index `grpahnumber' to the lists parents, children, parentslen, childrenlen graphnrtolists(n, graphnumber, parents, parentslen, children, childrenlen); // Increase checked counter and prepare for next iteration graphschecked++; if(RANDOM) graphnumber = rand_uint64(max); else graphnumber++; // EO Increase checked counter and prepare for next iteration // If enabled, compare against degree options if(NOSINK || NOSOURCE) { // Get some degree properties int minindegree = n; int minoutdegree = n; for(int node=0; node parentslen[node]) minindegree = parentslen[node]; if(minoutdegree > childrenlen[node]) minoutdegree = childrenlen[node]; } if(NOSINK && minoutdegree == 0) continue; if(NOSOURCE && minindegree == 0) continue; } // Check whether this graph is canonical or not; continue if graph has not proper ordering of degress (there is an isomorphic graphs to this one that has been or will be checked) if(!isdegreeordered(n, parents, parentslen, children, childrenlen)) continue; // Ignore graphs that are not connected if(!isconnected(n, parents, parentslen, children, childrenlen)) continue; // Find cycles const int num_cycles = find_cycles(cycles, cyclescnt, n, children, childrenlen); // If enabled, ignore DAGs if(NONDAGONLY && num_cycles > 0) continue; // Test the Siblings-On-Cycles property // A DAG is trivially a SOC if(num_cycles > 0 && !gissoc(n, parents, parentslen, children, childrenlen, cycles, cyclescnt)) continue; // We have found a SOC len++; dumpgraph(n, children, childrenlen); } const int deltat = time(NULL) - t0; const float rate = (deltat == 0) ? graphschecked : (float)graphschecked/(float)deltat; const float SOCrate = (deltat == 0) ? len : (float)len/(float)deltat; fprintf(stderr, "\r%6.2f%% %*llu/%llu (%i SOCs found, %d seconds, %*.2f graphs/s, %*.2f SOCs/s, %*.2fh estimated time left)",100.00,padlen,graphnumber,max,len,deltat,padlen+3,rate,padlen+3,SOCrate,padlen,0.00); fprintf(stderr, "\nFound %d SOCs in %d seconds\n", len,deltat); // Free manually allocated memory free(cycles); return 0; }