replaced tabs with whitespace, linted c code, reduced line lengths if possible for better readability

This commit is contained in:
Ämin Baumeler 2023-09-07 13:36:33 +02:00
parent ab5a90dc38
commit 642b78c900
4 changed files with 935 additions and 826 deletions

View File

@ -1,4 +1,5 @@
// SPDX-FileCopyrightText: 2023 Ämin Baumeler <amin@indyfac.ch> and Eleftherios-Ermis Tselentis <eleftheriosermis.tselentis@oeaw.ac.at> // SPDX-FileCopyrightText: 2023 Ämin Baumeler <amin@indyfac.ch> and
// Eleftherios-Ermis Tselentis <eleftheriosermis.tselentis@oeaw.ac.at>
// //
// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-License-Identifier: GPL-3.0-or-later
@ -57,9 +58,12 @@ int* read_graphs(char* filename, int *cnt, int *maxdim) {
rewind(fp); // Return to start of file rewind(fp); // Return to start of file
// Allocate space for graph data // Allocate space for graph data
const int gdatasize = *maxdim * *maxdim + 1; // Size allocation per graph // Size allocation per graph
const int arraysize = (1+ *cnt) * gdatasize; // Total space to allocate const int gdatasize = *maxdim * *maxdim + 1;
int *graphs = (int*)malloc(sizeof(int)*arraysize); // Allocation // Total space to allocate
const int arraysize = (1+ *cnt) * gdatasize;
// Allocation
int *graphs = (int*)malloc(sizeof(int)*arraysize);
if (!graphs) { if (!graphs) {
fprintf(stderr, "ERROR: Could not allocate enough memory to store the graphs.\n"); fprintf(stderr, "ERROR: Could not allocate enough memory to store the graphs.\n");
return NULL; return NULL;
@ -132,14 +136,17 @@ int nextintervention(int n, int *interventionslen, int *interventionidx) {
* If `party' has no parents, then `party' will definitely receive a 1. * If `party' has no parents, then `party' will definitely receive a 1.
* If the fixed-point value cannot be inferred, return -1. * If the fixed-point value cannot be inferred, return -1.
***/ ***/
int alphapre(int party, const int *parents, const int *parentslen, const int *interventions, const int *interventionidx, int maxn) { int alphapre(int party, const int *parents, const int *parentslen, \
const int *interventions, const int *interventionidx, int maxn) {
if (parentslen[party] == 0) if (parentslen[party] == 0)
return 1; return 1;
const int idatasize = (maxn+1)*(maxn+1)*2; // Max nr of interventions/party const int idatasize = (maxn+1)*(maxn+1)*2; // Max nr of interventions/party
for (int pidx = 0; pidx < parentslen[party]; pidx++) { for (int pidx = 0; pidx < parentslen[party]; pidx++) {
const int parent = parents[maxn*party + pidx]; const int parent = parents[maxn*party + pidx];
const int f0 = interventions[idatasize*parent + 2*interventionidx[parent] + 0]; const int f0 = interventions[idatasize*parent + \
const int f1 = interventions[idatasize*parent + 2*interventionidx[parent] + 1]; 2*interventionidx[parent] + 0];
const int f1 = interventions[idatasize*parent + \
2*interventionidx[parent] + 1];
if (f0 != party && f1 != party) if (f0 != party && f1 != party)
return 0; return 0;
} }
@ -154,7 +161,9 @@ int alphapre(int party, const int *parents, const int *parentslen, const int *in
* *
* Make sure to run alphapre before running this. * Make sure to run alphapre before running this.
***/ ***/
int alpha(int *path, int pathlen, const int *parents, const int *parentslen, const int *interventions, const int *interventionidx, const int *fp, int n, int maxn) { int alpha(int *path, int pathlen, const int *parents, const int *parentslen, \
const int *interventions, const int *interventionidx, const int *fp, \
int n, int maxn) {
const int party = path[pathlen-1]; const int party = path[pathlen-1];
for (int i = 0; i < pathlen-1; i++) { for (int i = 0; i < pathlen-1; i++) {
if (party == path[i]) { if (party == path[i]) {
@ -164,11 +173,14 @@ int alpha(int *path, int pathlen, const int *parents, const int *parentslen, con
const int idatasize = (maxn+1)*(maxn+1)*2; // Max nr of interventions/party const int idatasize = (maxn+1)*(maxn+1)*2; // Max nr of interventions/party
// Iterate over all parents // Iterate over all parents
// If one parent does not vote for `party', immediattely return a zero. // If one parent does not vote for `party', immediattely return a zero.
// If all parents vote for `party' --- which can only be inferred after we queried all parents --- return a one. // If all parents vote for `party' --- which can only be inferred after we
// queried all parents --- return a one.
for (int pidx = 0; pidx < parentslen[party]; pidx++) { for (int pidx = 0; pidx < parentslen[party]; pidx++) {
const int parent = parents[maxn*party + pidx]; const int parent = parents[maxn*party + pidx];
const int f0 = interventions[idatasize*parent + 2*interventionidx[parent] + 0]; const int f0 = interventions[idatasize*parent + 2*interventionidx[parent] \
const int f1 = interventions[idatasize*parent + 2*interventionidx[parent] + 1]; + 0];
const int f1 = interventions[idatasize*parent + 2*interventionidx[parent] \
+ 1];
if (f0 == party && f1 == party) if (f0 == party && f1 == party)
continue; continue;
// Re-use already computed fixed points, else enter recursion // Re-use already computed fixed points, else enter recursion
@ -177,7 +189,8 @@ int alpha(int *path, int pathlen, const int *parents, const int *parentslen, con
val = fp[parent]; val = fp[parent];
} else { } else {
path[pathlen] = parent; path[pathlen] = parent;
val = alpha(path, pathlen+1, parents, parentslen, interventions, interventionidx, fp, n, maxn); val = alpha(path, pathlen+1, parents, parentslen, interventions, \
interventionidx, fp, n, maxn);
} }
// Evaluate the intervention on the input // Evaluate the intervention on the input
const int muOfVal = (val == 0) ? f0 : f1; const int muOfVal = (val == 0) ? f0 : f1;
@ -213,10 +226,15 @@ int ceillog10(int x) {
***/ ***/
int test_graphs(int startidx, int len, int maxn, const int *graphs) { int test_graphs(int startidx, int len, int maxn, const int *graphs) {
const int gdatasize = maxn * maxn + 1; // Size allocation per graph const int gdatasize = maxn * maxn + 1; // Size allocation per graph
const int idatasize = (maxn+1)*(maxn+1)*2; // Max number of interventions per party const int idatasize = (maxn+1)*(maxn+1)*2; // Max number of interventions
// per party
int range[maxn+1]; // Range of intervention int range[maxn+1]; // Range of intervention
int interventions[maxn*idatasize]; // Hold all interventions per party {f_0(0), f_0(1), g_0(0), g_0(1), ... , f_1(0), f_1(1), ...} int interventions[maxn*idatasize]; // Hold all interventions per
int interventionslen[maxn]; // Number of interventions per party // party {f_0(0), f_0(1),
// g_0(0), g_0(1), ... ,
// f_1(0), f_1(1), ...}
int interventionslen[maxn]; // Number of intervention per
// party
int interventionidx[maxn]; // Current intervention executed int interventionidx[maxn]; // Current intervention executed
int parents[maxn*maxn]; // List all parents per party int parents[maxn*maxn]; // List all parents per party
int parentslen[maxn]; // Number of parents per party int parentslen[maxn]; // Number of parents per party
@ -232,7 +250,8 @@ int test_graphs(int startidx, int len, int maxn, const int *graphs) {
const float percentage = 100*(float)count/(float)len; const float percentage = 100*(float)count/(float)len;
const int deltat = t1-tstart; const int deltat = t1-tstart;
const float rate = (float)count/(float)deltat; const float rate = (float)count/(float)deltat;
fprintf(stderr, "\r%6.2f%% %*d/%d (%*.2f graphs/s in %d seconds; current line %d)",percentage,padlen,count,len,padlen+3,rate,deltat,graphidx+1); fprintf(stderr, "\r%6.2f%% %*d/%d (%*.2f graphs/s in %d seconds; current line %d)", \
percentage, padlen, count, len, padlen+3, rate, deltat, graphidx+1);
t0 = t1; t0 = t1;
} }
// Test graph with index `graphidx' // Test graph with index `graphidx'
@ -260,7 +279,8 @@ int test_graphs(int startidx, int len, int maxn, const int *graphs) {
// Fill in interventions // Fill in interventions
for (int party = 0; party < n; party++) { for (int party = 0; party < n; party++) {
// This is a small trick to speed-up processing: // This is a small trick to speed-up processing:
// If the party `party' has two or more children, ignore the `discard' intervention (-1) (tmp=0), // If the party `party' has two or more children,
// ignore the `discard' intervention (-1) (tmp=0),
// else make use of the `discard' internvetion (tmp=1). // else make use of the `discard' internvetion (tmp=1).
// Populate range of `party's interventions // Populate range of `party's interventions
// The range has childrenlen[party]+tmp entries // The range has childrenlen[party]+tmp entries
@ -270,7 +290,8 @@ int test_graphs(int startidx, int len, int maxn, const int *graphs) {
range[j+tmp] = children[maxn*party+j]; range[j+tmp] = children[maxn*party+j];
} }
// Enumerate, store, and count all possible interventions // Enumerate, store, and count all possible interventions
// Each intervention is a tuple (mu(0), mu(1)), x corresponds to the first entry, y to the second // Each intervention is a tuple (mu(0), mu(1)), x corresponds to the first
// entry, y to the second
int cnt = 0; int cnt = 0;
for (int x = 0; x < childrenlen[party]+tmp; x++) { for (int x = 0; x < childrenlen[party]+tmp; x++) {
for (int y = 0; y < childrenlen[party]+tmp; y++) { for (int y = 0; y < childrenlen[party]+tmp; y++) {
@ -285,19 +306,24 @@ int test_graphs(int startidx, int len, int maxn, const int *graphs) {
int fp[n]; // Array to store alpha(party) values int fp[n]; // Array to store alpha(party) values
int afterfp[n]; // \omega(\mu(fp)) int afterfp[n]; // \omega(\mu(fp))
int path[n+1]; // Current path int path[n+1]; // Current path
for(int i=0; i<n; i++) interventionidx[i] = 0; // Initialize intervention index to the first intervention // Initialize intervention index to the first intervention
int running = 1; // Flag to see whether we are still verifying, or we verified all interventions for (int i = 0; i < n; i++) interventionidx[i] = 0;
// Flag to see whether we are still verifying, or we verified all
// interventions
int running = 1;
while (running) { while (running) {
// Reset fixed-point entries // Reset fixed-point entries
for (int party = 0; party < n; party++) for (int party = 0; party < n; party++)
fp[party] = -1; fp[party] = -1;
// Fill out fixed-points that are trivially computed // Fill out fixed-points that are trivially computed
for (int party = 0; party < n; party++) for (int party = 0; party < n; party++)
alphapre(party, parents, parentslen, interventions, interventionidx, maxn); alphapre(party, parents, parentslen, interventions, interventionidx, \
maxn);
// Invoke recursive function // Invoke recursive function
for (int party = 0; party < n; party++) { for (int party = 0; party < n; party++) {
path[0] = party; path[0] = party;
const int val = alpha(path, 1, parents, parentslen, interventions, interventionidx, fp, n, maxn); const int val = alpha(path, 1, parents, parentslen, interventions, \
interventionidx, fp, n, maxn);
fp[party] = val; fp[party] = val;
} }
@ -309,8 +335,10 @@ int test_graphs(int startidx, int len, int maxn, const int *graphs) {
// Loop over parents of this party // Loop over parents of this party
for (int pidx = 0; pidx < parentslen[party]; pidx++) { for (int pidx = 0; pidx < parentslen[party]; pidx++) {
const int parent = parents[maxn*party + pidx]; const int parent = parents[maxn*party + pidx];
const int f0 = interventions[idatasize*parent + 2*interventionidx[parent] + 0]; const int f0 = interventions[idatasize*parent + \
const int f1 = interventions[idatasize*parent + 2*interventionidx[parent] + 1]; 2*interventionidx[parent] + 0];
const int f1 = interventions[idatasize*parent + \
2*interventionidx[parent] + 1];
// If `parent' never votes for `party', this value is 0. // If `parent' never votes for `party', this value is 0.
if (f0 != party && f1 != party) { if (f0 != party && f1 != party) {
afterfp[party] = 0; afterfp[party] = 0;
@ -321,19 +349,21 @@ int test_graphs(int startidx, int len, int maxn, const int *graphs) {
continue; continue;
// Evaluate intervention on the input (fp[parent]) // Evaluate intervention on the input (fp[parent])
const int muOfVal = (fp[parent] == 0) ? f0 : f1; const int muOfVal = (fp[parent] == 0) ? f0 : f1;
// If `parent' does not vote for `party', this value is 0, else check the other parents. // If `parent' does not vote for `party', this value is 0, else check
// the other parents.
if (muOfVal != party) { if (muOfVal != party) {
afterfp[party] = 0; afterfp[party] = 0;
break; break;
} }
} }
// All parents voted `party' // All parents voted `party'
if (afterfp[party] == -1) if (afterfp[party] == -1)
afterfp[party] = 1; afterfp[party] = 1;
} }
// Compare the output of the recursive alpha function (fp) with \omega(\mu(fp)) (afterfp) // Compare the output of the recursive alpha function (fp) with
// If these two arrays differ, return the line number of the graph we falsified // \omega(\mu(fp)) (afterfp)
// If these two arrays differ, return the line number of the graph we
// falsified
for (int party = 0; party < n; party++) for (int party = 0; party < n; party++)
if (fp[party] != afterfp[party]) if (fp[party] != afterfp[party])
return graphidx+1; return graphidx+1;
@ -344,7 +374,8 @@ int test_graphs(int startidx, int len, int maxn, const int *graphs) {
} }
const int deltat = time(NULL) - tstart; const int deltat = time(NULL) - tstart;
const float rate = (deltat == 0) ? len : (float)len/(float)deltat; const float rate = (deltat == 0) ? len : (float)len/(float)deltat;
fprintf(stderr, "\r%6.2f%% %*d/%d (%*.2f graphs/s in %d seconds; current line %d)\n",100.0,padlen,len,len,padlen+3,rate,deltat,startidx+len); fprintf(stderr, "\r%6.2f%% %*d/%d (%*.2f graphs/s in %d seconds; current line %d)\n", \
100.0, padlen, len, len, padlen+3, rate, deltat, startidx+len);
return 0; return 0;
} }
@ -360,7 +391,8 @@ int main(int argc, char *argv[]) {
else else
NUM = atoi(argv[3])-START+1; NUM = atoi(argv[3])-START+1;
} }
if(!(argc >= 2 && (argc < 3 || START > 0) && (argc < 4 || NUM > 0) && argc <= 4)) { if (!(argc >= 2 && (argc < 3 || START > 0) && (argc < 4 || NUM > 0) && \
argc <= 4)) {
fprintf(stderr, "Usage: %s <filename> [<startline> [<endline> | +<count>]]\n", argv[0]); fprintf(stderr, "Usage: %s <filename> [<startline> [<endline> | +<count>]]\n", argv[0]);
fprintf(stderr, " <filename> File name with adjacency matrices of simple directed graphs\n"); fprintf(stderr, " <filename> File name with adjacency matrices of simple directed graphs\n");
fprintf(stderr, " <startline> Verify graphs starting from line `startline'\n"); fprintf(stderr, " <startline> Verify graphs starting from line `startline'\n");
@ -392,13 +424,15 @@ int main(int argc, char *argv[]) {
} }
// Test `tot' graphs, starting from index `startidx' // Test `tot' graphs, starting from index `startidx'
printf("Verifying the admissibility of %d graphs in the file `%s' (line %d to line %d)\n", tot, argv[1], startidx+1, startidx+tot); printf("Verifying the admissibility of %d graphs in the file `%s' (line %d to line %d)\n", \
tot, argv[1], startidx+1, startidx+tot);
const int result = test_graphs(startidx, tot, maxdimension, graphs); const int result = test_graphs(startidx, tot, maxdimension, graphs);
if (result == 0) if (result == 0)
printf("These graphs are admissible\n"); printf("These graphs are admissible\n");
else if (result == -1) else if (result == -1)
fprintf(stderr, "ERROR: Something went wrong\n"); fprintf(stderr, "ERROR: Something went wrong\n");
else else
printf("The function alpha does not represent the fixed point, or the graph on line %d is inadmissible\n", result); printf("The function alpha does not represent the fixed point, or the graph on line %d is inadmissible\n", \
result);
return result; return result;
} }

View File

@ -1,4 +1,5 @@
// SPDX-FileCopyrightText: 2023 Ämin Baumeler <amin@indyfac.ch> and Eleftherios-Ermis Tselentis <eleftheriosermis.tselentis@oeaw.ac.at> // SPDX-FileCopyrightText: 2023 Ämin Baumeler <amin@indyfac.ch> and
// Eleftherios-Ermis Tselentis <eleftheriosermis.tselentis@oeaw.ac.at>
// //
// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-License-Identifier: GPL-3.0-or-later
@ -62,7 +63,8 @@ int blocksize(int n) {
/*** /***
* Recrusive bi-directional graph traversal, used to check connectivity. * Recrusive bi-directional graph traversal, used to check connectivity.
***/ ***/
void traverse(int vertex, int *visited, int n, const int *parents, const int *parentslen, const int *children, const int *childrenlen) { void traverse(int vertex, int *visited, int n, const int *parents, \
const int *parentslen, const int *children, const int *childrenlen) {
visited[vertex] = 1; visited[vertex] = 1;
for (int i = 0; i < parentslen[vertex]; i++) { for (int i = 0; i < parentslen[vertex]; i++) {
int u = parents[n*vertex + i]; int u = parents[n*vertex + i];
@ -79,7 +81,8 @@ void traverse(int vertex, int *visited, int n, const int *parents, const int *pa
/*** /***
* Return 1 if the graph is connected, and 0 otherwise. * Return 1 if the graph is connected, and 0 otherwise.
***/ ***/
int isconnected(int n, const int *parents, const int *parentslen, const int *children, const int *childrenlen) { int isconnected(int n, const int *parents, const int *parentslen, \
const int *children, const int *childrenlen) {
// Early check: Is there a node with 0 total degree? // Early check: Is there a node with 0 total degree?
for (int i = 0; i < n; i++) if (parentslen[i]+childrenlen[i] == 0) return 0; for (int i = 0; i < n; i++) if (parentslen[i]+childrenlen[i] == 0) return 0;
// Check connectivity // Check connectivity
@ -95,7 +98,8 @@ int isconnected(int n, const int *parents, const int *parentslen, const int *chi
* Interpret graph number `graph' as a simple digraph, and populate the arrays `parents', `parentslen', `children', `childrenlen' * Interpret graph number `graph' as a simple digraph, and populate the arrays `parents', `parentslen', `children', `childrenlen'
* The number `graph' is understood as the adjacency matrix with the diagonal removed (no self loops). * The number `graph' is understood as the adjacency matrix with the diagonal removed (no self loops).
***/ ***/
void graphnrtolists(int n, unsigned long long int graph, int *parents, int *parentslen, int *children, int *childrenlen) { void graphnrtolists(int n, unsigned long long int graph, int *parents, \
int *parentslen, int *children, int *childrenlen) {
for (int i = 0; i < n; i++) { for (int i = 0; i < n; i++) {
parentslen[i] = 0; parentslen[i] = 0;
childrenlen[i] = 0; childrenlen[i] = 0;
@ -119,7 +123,6 @@ void graphnrtolists(int n, unsigned long long int graph, int *parents, int *pare
col = 0; col = 0;
row++; row++;
} }
} }
} }
@ -127,13 +130,17 @@ void graphnrtolists(int n, unsigned long long int graph, int *parents, int *pare
* Find the tail in `path' of length `pathlen' that includes a cycle, and save the canonical representation. * Find the tail in `path' of length `pathlen' that includes a cycle, and save the canonical representation.
* The canonical representation is the listing of the nodes of the cycle starting from the smallest one. * The canonical representation is the listing of the nodes of the cycle starting from the smallest one.
***/ ***/
void canonical_cycle(int n, int *cycle, int *cyclelen, const int *path, int pathlen) { void canonical_cycle(int n, int *cycle, int *cyclelen, const int *path, \
int pathlen) {
int startidx; int startidx;
int pathhascycle = 0; int pathhascycle = 0;
const int last = path[pathlen-1]; // This is the last node const int last = path[pathlen-1]; // This is the last node
for (int k = 0; k < pathlen-1; k++) { for (int k = 0; k < pathlen-1; k++) {
if(path[k]==last) { // We have found the first occurance of node `last' on the path if (path[k] == last) {
// The cycle is the following part of path: path[startidx], path[startidx+1], ..., path[pathlen-2], and therefore has length pathlen-startidx-1 // We have found the first occurance of node `last' on the path
// The cycle is the following part of path: path[startidx],
// path[startidx+1], ..., path[pathlen-2], and therefore has
// length pathlen-startidx-1
startidx = k; startidx = k;
(*cyclelen) = pathlen-startidx-1; (*cyclelen) = pathlen-startidx-1;
pathhascycle = 1; pathhascycle = 1;
@ -155,22 +162,30 @@ void canonical_cycle(int n, int *cycle, int *cyclelen, const int *path, int path
} }
} }
// Now, copy cycle to `cycle' starting from the smallest // Now, copy cycle to `cycle' starting from the smallest
int j=0; // This is the index on where to write on the array `cycle' // This is the index on where to write on the array `cycle'
int j = 0;
for (int i = smallestidx;; i++) { for (int i = smallestidx;; i++) {
if(j==*cyclelen) break; // Stop filling in, if we reached the end // 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 if (j == *cyclelen) break;
cycle[j] = path[i]; // Write at position `j' the element from the cycle on the path at position `i`' // If we reach the end of the path, jump to the start
j++; // Increase index to write on `cycle' if (i == pathlen-1) i = startidx;
// Write at position `j' the element from the cycle on the path at
// position `i`'
cycle[j] = path[i];
// Increase index to write on `cycle'
j++;
} }
} }
/*** /***
* Return 1 if the cycle is not in `cycles', otherwise 0. * 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) { int cycleisnew(int n, const int *c, int clen, const int *cycles, \
const int *cyclescnt) {
const int cnt = cyclescnt[clen]; const int cnt = cyclescnt[clen];
const int bs = blocksize(n); const int bs = blocksize(n);
for(int i=0; i<cnt; i++) { // Iterate over all cycles of the same length // Iterate over all cycles of the same length
for (int i = 0; i < cnt; i++) {
int j; int j;
const int startidx = clen*bs + i*clen; // We start here const int startidx = clen*bs + i*clen; // We start here
for (j = 0; j < clen; j++) // Go position by position for (j = 0; j < clen; j++) // Go position by position
@ -186,11 +201,12 @@ int cycleisnew(int n, const int *c, int clen, const int *cycles, const int *cycl
* Save the given cycle `c' of length `clen' in `cycles'. * Save the given cycle `c' of length `clen' in `cycles'.
***/ ***/
void savecycle(int n, const int *c, int clen, int *cycles, int *cyclescnt) { void savecycle(int n, const int *c, int clen, int *cycles, int *cyclescnt) {
const int m = cyclescnt[clen]; // There are already `m' cycles of length `clen' const int m = cyclescnt[clen]; // There are `m' `clen'-cycles
const int bs = blocksize(n); const int bs = blocksize(n);
const int startidx = clen*bs + m*clen; // We start writing here const int startidx = clen*bs + m*clen; // We start writing here
for (int i = 0; i < clen; i++) cycles[startidx+i] = c[i]; for (int i = 0; i < clen; i++) cycles[startidx+i] = c[i];
cyclescnt[clen]++; // Increase the counter that holds the number of cycles of length `clen' cyclescnt[clen]++; // Increase the counter that holds
// the number of `clen'-cycles
} }
@ -204,32 +220,43 @@ void savecycle(int n, const int *c, int clen, int *cycles, int *cyclescnt) {
* Parameter `n': Number of nodes * Parameter `n': Number of nodes
* Parameter `found': Pointer to integer to count the number of cycles found * Parameter `found': Pointer to integer to count the number of cycles found
***/ ***/
void dfs(const int *useless, int *path, int pathlen, int *visited, int n, const int *children, const int *childrenlen, int *cycles, int *cyclescnt, unsigned int *found) { void dfs(const int *useless, int *path, int pathlen, int *visited, int n, \
const int *children, const int *childrenlen, int *cycles, int *cyclescnt, \
unsigned int *found) {
int cycle[n]; // Temporary store for cycle int cycle[n]; // Temporary store for cycle
int cyclelen; // Length of temporarilly stored cycle int cyclelen; // Length of temporarilly stored cycle
const int vertex = path[pathlen-1]; // We go on duing a dfs from node `vertex' // We go on duing a dfs from node `vertex'
const int vertex = path[pathlen-1];
for (int i = 0; i < childrenlen[vertex]; i++) { for (int i = 0; i < childrenlen[vertex]; i++) {
const int u = children[n*vertex + i]; // Enter node `u' const int u = children[n*vertex + i]; // Enter node `u'
if (useless[u]) continue; // This one is useless if (useless[u]) continue; // This one is useless
if (visited[u] == 0) { // Not visited yet if (visited[u] == 0) { // Not visited yet
visited[u] = 1; // Mark as visited visited[u] = 1; // Mark as visited
path[pathlen] = u; // Append to path, and re-enter recursion... path[pathlen] = u; // Append to path, and re-enter
dfs(useless, path, pathlen+1, visited, n, children, childrenlen, cycles, cyclescnt, found); // recursion...
visited[u] = 0; // Undo marking, we are going to take another route dfs(useless, path, pathlen+1, visited, n, children, childrenlen, cycles, \
cyclescnt, found);
visited[u] = 0; // Undo marking, we are going to
// take another route
} else { } else {
// We have reached a node on the path, i.e., we have found a cycle! // We have reached a node on the path, i.e., we have found a cycle!
// The cycle is somewhere along the path // The cycle is somewhere along the path
// path[0], path[1], ... path[pathlen-1] // path[0], path[1], ... path[pathlen-1]
// More specifically, node `u' is somewhere there. // More specifically, node `u' is somewhere there.
// To detect this, we first place `u' on the path. // To detect this, we first place `u' on the path.
// The method `canonical_cycle' will then use this information to find and return the canonical form of the cycle. // The method `canonical_cycle' will then use this information to find
// and return the canonical form of the cycle.
path[pathlen] = u; path[pathlen] = u;
canonical_cycle(n, cycle, &cyclelen, path, pathlen+1); // Find cycle and generate the canonical representation. // Find cycle and generate the canonical representation.
if(cycleisnew(n, cycle, cyclelen, cycles, cyclescnt)) { // Is it new? If yes, save canonical_cycle(n, cycle, &cyclelen, path, pathlen+1);
(*found)++; // Increase the number of found cycles by 1 // Is it new? If yes, save
savecycle(n, cycle, cyclelen, cycles, cyclescnt); // Save cycle if (cycleisnew(n, cycle, cyclelen, cycles, cyclescnt)) {
// Increase the number of found cycles by 1
(*found)++;
// Save cycle
savecycle(n, cycle, cyclelen, cycles, cyclescnt);
} }
// else dont do anything.. // else dont do anything...
} }
} }
return; return;
@ -240,10 +267,14 @@ void dfs(const int *useless, int *path, int pathlen, int *visited, int n, const
* The cycles are stored in `cycles' and `cyclescnt'. * The cycles are stored in `cycles' and `cyclescnt'.
* This uses a recursive depth-first-search. * This uses a recursive depth-first-search.
***/ ***/
int find_cycles(int *cycles, int *cyclescnt, int n, const int *children, const int *childrenlen) { int find_cycles(int *cycles, int *cyclescnt, int n, const int *children, \
const int *childrenlen) {
int visited[n]; int visited[n];
int useless[n]; // Some nodes are useless, mark them as such // Some nodes are useless, mark them as such
int path[n+1]; // We use n+1 here because we will "close" the path to form a cycle, i.e., one node will be repeated. int useless[n];
// We use n+1 here because we will "close" the path to form a cycle,
// i.e., one node will be repeated.
int path[n+1];
unsigned int found = 0; // Store total number of cycles found unsigned int found = 0; // Store total number of cycles found
// Initialize cyclescnt to zero // Initialize cyclescnt to zero
for (int i = 0; i < n+1; i++) for (int i = 0; i < n+1; i++)
@ -256,10 +287,13 @@ int find_cycles(int *cycles, int *cyclescnt, int n, const int *children, const i
for (int vertex = 0; vertex < n; vertex++) { for (int vertex = 0; vertex < n; vertex++) {
if (useless[vertex]) continue; if (useless[vertex]) continue;
for (int i = 0; i < n; i++) visited[i] = 0; // Mark all as univisited for (int i = 0; i < n; i++) visited[i] = 0; // Mark all as univisited
path[0] = vertex; // We start at `vertex' // We start at `vertex'
visited[vertex] = 1; // Mark `vertex' as visited. If we revisit a node, we found a cycle. path[0] = vertex;
// Mark `vertex' as visited. If we revisit a node, we found a cycle.
visited[vertex] = 1;
// Enter depth-first-search recursion // Enter depth-first-search recursion
dfs(useless, path, 1, visited, n, children, childrenlen, cycles, cyclescnt, &found); dfs(useless, path, 1, visited, n, children, childrenlen, cycles, \
cyclescnt, &found);
// We processed this. Every cycle that goes through `vertex' has been found. // We processed this. Every cycle that goes through `vertex' has been found.
useless[vertex] = 1; useless[vertex] = 1;
} }
@ -280,18 +314,23 @@ int find_cycles(int *cycles, int *cyclescnt, int n, const int *children, const i
* *
* A SOC (Siblings-on-Cycles) is a simple digraph where every cycle has siblings, i.e., nodes with common parents. * A SOC (Siblings-on-Cycles) is a simple digraph where every cycle has siblings, i.e., nodes with common parents.
***/ ***/
int gissoc(int n, const int *parents, const int *parentslen, const int *children, const int *childrenlen, int *cycles, int *cyclescnt) { int gissoc(int n, const int *parents, const int *parentslen, \
// We store the cycles in groups of the cycle lenghts (length of cycle is the number of edges, or equivalentelly, the number of distinct nodes) const int *children, const int *childrenlen, int *cycles, int *cyclescnt) {
// We store the cycles in groups of the cycle lenghts (length of cycle is the
// number of edges, or equivalentelly, the number of distinct nodes)
// Since the graph is a simple digraph, the smallest cycles have length 2. // Since the graph is a simple digraph, the smallest cycles have length 2.
// cycles[0], cycles[1] is the first cycle of length 2 // cycles[0], cycles[1] is the first cycle of length 2
// cycles[2], cycles[3] is the second cycle of length 2 // cycles[2], cycles[3] is the second cycle of length 2
// etc. // etc.
// There are at most (n choose 2) cycles of length 2. // There are at most (n choose 2) cycles of length 2.
// There are at most (n choose n/2) cycles of length n/2. This is upper bounded by 2^n/sqrt(pi*n/2) < 2^n; this is the largest binomial coefficient. // There are at most (n choose n/2) cycles of length n/2. This is upper
// bounded by 2^n/sqrt(pi*n/2) < 2^n; this is the largest binomial
// coefficient.
// Since generally n will be small, we just use this bound for all groups. // Since generally n will be small, we just use this bound for all groups.
// So, the cycles with length k are saved at and after cycles[k*(2^n)]. // So, the cycles with length k are saved at and after cycles[k*(2^n)].
// Each block has size 2^n. // Each block has size 2^n.
/* Early and saftey check for self loops. SOCs dont have self-loops, and we should never generate them. Anyhow, test */ /* Early and saftey check for self loops. SOCs dont have self-loops, and we
* should never generate them. Anyhow, test */
for (int i = 0; i < n; i++) { for (int i = 0; i < n; i++) {
int num = childrenlen[i]; int num = childrenlen[i];
for (int cidx = 0; cidx < num; cidx++) for (int cidx = 0; cidx < num; cidx++)
@ -308,9 +347,13 @@ int gissoc(int n, const int *parents, const int *parentslen, const int *children
// In that iteration process, mark all parents. // In that iteration process, mark all parents.
// If a marked parent is marked again, we have found a common parent. // If a marked parent is marked again, we have found a common parent.
for (int len = 2; len < n+1; len++) { for (int len = 2; len < n+1; len++) {
const int cnt = cyclescnt[len]; // Number of cycles of length `len' // Number of cycles of length `len'
for(int i=0; i<cnt; i++) { // Iterate over cycles const int cnt = cyclescnt[len];
const int startidx = len*bs+len*i; // The cycle we look at (length=`len', index=`i') is saved starting from index `startidx' // Iterate over cycles
for (int i = 0; i < cnt; i++) {
// The cycle we look at (length=`len', index=`i') is saved starting from
// index `startidx'
const int startidx = len*bs+len*i;
// Initialize marks // Initialize marks
int marked[n]; int marked[n];
for (int k = 0; k < n; k++) marked[k] = 0; for (int k = 0; k < n; k++) marked[k] = 0;
@ -321,17 +364,24 @@ int gissoc(int n, const int *parents, const int *parentslen, const int *children
const int vertex = cycles[startidx+k]; const int vertex = cycles[startidx+k];
for (int pidx = 0; pidx < parentslen[vertex]; pidx++) { for (int pidx = 0; pidx < parentslen[vertex]; pidx++) {
const int parent = parents[n*vertex+pidx]; const int parent = parents[n*vertex+pidx];
if(marked[parent]) commonparentfound = 1; // The node `parent' is a common parent // Check if `parent' is a common parent, else mark
else marked[parent] = 1; // Mark the parent node if (marked[parent])
if(commonparentfound) break; // We have found a common parent, break out of the for loop over `pidx' commonparentfound = 1;
else
marked[parent] = 1;
// We have found a common parent, break out of the `pidx' loop
if (commonparentfound) break;
} }
if(commonparentfound) break; // We have found a common parent, break out of the for loop over `k' // We have found a common parent, break out of the for loop over `k'
if (commonparentfound) break;
} }
if(!commonparentfound) // On cycle `i' we did NOT find a common parent, this is not a SOC // On cycle `i' we did NOT find a common parent, this is not a SOC
if (!commonparentfound)
return 0; return 0;
} }
} }
return 1; // If all test pass, we have found a SOC // If all test pass, we have found a SOC
return 1;
} }
/*** /***
@ -354,7 +404,8 @@ int grandchildrenlen(int node, const int *children, const int *childrenlen) {
* If the graph does not satisfy this `canonical' form, then another ismorphic to it (it's simply a permutation of the nodes) * If the graph does not satisfy this `canonical' form, then another ismorphic to it (it's simply a permutation of the nodes)
* will be degree-ordered. * will be degree-ordered.
***/ ***/
int isdegreeordered(int n, const int *parents, const int *parentslen, const int *children, const int *childrenlen) { int isdegreeordered(int n, const int *parents, const int *parentslen, \
const int *children, const int *childrenlen) {
// Decreasingling order by in-degree, then out-degree, then ... // Decreasingling order by in-degree, then out-degree, then ...
for (int i = 0; i < n-1; i++) { for (int i = 0; i < n-1; i++) {
if (parentslen[i] > parentslen[i+1]) { if (parentslen[i] > parentslen[i+1]) {
@ -363,10 +414,13 @@ int isdegreeordered(int n, const int *parents, const int *parentslen, const int
if (childrenlen[i] > childrenlen[i+1]) { if (childrenlen[i] > childrenlen[i+1]) {
return 0; return 0;
} else if (childrenlen[i] == childrenlen[i+1]) { } else if (childrenlen[i] == childrenlen[i+1]) {
if(grandparentslen(i,parents,parentslen) > grandparentslen(i+1,parents,parentslen)) { if (grandparentslen(i, parents, parentslen) > \
grandparentslen(i+1, parents, parentslen)) {
return 0; return 0;
} else if(grandparentslen(i,parents,parentslen) == grandparentslen(i+1,parents,parentslen)) { } else if (grandparentslen(i, parents, parentslen) == \
if(grandchildrenlen(i,children,childrenlen) > grandchildrenlen(i+1,children,childrenlen)) { grandparentslen(i+1, parents, parentslen)) {
if (grandchildrenlen(i, children, childrenlen) > \
grandchildrenlen(i+1, children, childrenlen)) {
return 0; return 0;
} }
} }
@ -414,15 +468,15 @@ int main(int argc, char *argv[]) {
} else if (strcmp(argv[i], "-r") == 0 && i+1 < argc) { } else if (strcmp(argv[i], "-r") == 0 && i+1 < argc) {
RANDOM = atoi(argv[i+1]); RANDOM = atoi(argv[i+1]);
i++; i++;
} else if(strcmp(argv[i], "-c") == 0) } else if (strcmp(argv[i], "-c") == 0) {
NONDAGONLY = 1; NONDAGONLY = 1;
else if(strcmp(argv[i], "--no-sink") == 0) } else if (strcmp(argv[i], "--no-sink") == 0) {
NOSINK = 1; NOSINK = 1;
else if(strcmp(argv[i], "--no-source") == 0) } else if (strcmp(argv[i], "--no-source") == 0) {
NOSOURCE = 1; NOSOURCE = 1;
else if(strcmp(argv[i], "--graphviz") == 0) } else if (strcmp(argv[i], "--graphviz") == 0) {
GRAPHVIZ = 1; GRAPHVIZ = 1;
else { } else {
UNKOPTION = 1; UNKOPTION = 1;
break; break;
} }
@ -451,7 +505,8 @@ int main(int argc, char *argv[]) {
const int bs = blocksize(n); const int bs = blocksize(n);
int *cycles = (int*)malloc(sizeof(int)*(n+2)*bs); int *cycles = (int*)malloc(sizeof(int)*(n+2)*bs);
if (!cycles) { if (!cycles) {
fprintf(stderr, "Failed to allocate memory to store cycles (tried to allocate %lu bytes)\n", sizeof(int)*(n+2)*bs); fprintf(stderr, "Failed to allocate memory to store cycles (tried to allocate %lu bytes)\n", \
sizeof(int)*(n+2)*bs);
return -1; return -1;
} }
int cyclescnt[n+1]; // cyclescnt[k] stores the number of cycles with length k int cyclescnt[n+1]; // cyclescnt[k] stores the number of cycles with length k
@ -459,7 +514,8 @@ int main(int argc, char *argv[]) {
// Initiate graph enumeration // Initiate graph enumeration
const int m = n*(n-1); const int m = n*(n-1);
if (m > 64) { if (m > 64) {
fprintf(stderr, "Too many graphs to enumarate with an unsiged long long integer (number of node pairs = %d)\n", m); fprintf(stderr, "Too many graphs to enumarate with an unsiged long long integer (number of node pairs = %d)\n", \
m);
return -1; return -1;
} }
unsigned long long max = 1L << m; // Largest `graphnumber' unsigned long long max = 1L << m; // Largest `graphnumber'
@ -470,29 +526,38 @@ int main(int argc, char *argv[]) {
srand((unsigned) time(&t)); srand((unsigned) time(&t));
// EO Initiate graph enumeration // EO Initiate graph enumeration
fprintf(stderr, "Generating SOCs with %d nodes\n", n); fprintf(stderr, "Generating SOCs with %d nodes\n", n);
if(RANDOM) fprintf(stderr, " Picking graphs at random\n"); if (RANDOM)
if(NONDAGONLY) fprintf(stderr, " Filter: Omitting DAGs\n"); fprintf(stderr, " Picking graphs at random\n");
if(NOSINK) fprintf(stderr, " Filter: Omitting graphs with sink nodes\n"); if (NONDAGONLY)
if(NOSOURCE) fprintf(stderr, " Filter: Omitting graphs with source nodes\n"); fprintf(stderr, " Filter: Omitting DAGs\n");
unsigned long long graphnumber = 0; // We will always omit the graph with `graphnumber' 0; it is unintersting anyway if (NOSINK)
fprintf(stderr, " Filter: Omitting graphs with sink nodes\n");
if (NOSOURCE)
fprintf(stderr, " Filter: Omitting graphs with source nodes\n");
// We will always omit the graph with `graphnumber' 0;
// it is unintersting anyway
unsigned long long graphnumber = 0;
unsigned long long graphschecked = 0; unsigned long long graphschecked = 0;
for (; graphnumber < max && (!RANDOM || len < RANDOM);) { for (; graphnumber < max && (!RANDOM || len < RANDOM);) {
const time_t now = time(NULL); 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 // Print status every second
if (now > t) { if (now > t) {
t = now; t = now;
const int deltat = now - t0; const int deltat = now - t0;
const float rate = (float)graphschecked/(float)deltat; const float rate = (float)graphschecked/(float)deltat;
const float SOCrate = (float)len/(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 percentage = (RANDOM == 0) ? \
const float ETC = (RANDOM==0) ? ((float)(max - graphschecked)/(rate))/3600 : ((float)(RANDOM - len)/(SOCrate))/3600; 100*(float)graphnumber/(float)max : 100*(float)len/(float)RANDOM;
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); 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); fflush(stderr);
} }
// Convert graph index `grpahnumber' to the lists parents, children, parentslen, childrenlen // Convert graph index `grpahnumber' to the lists parents, children,
// parentslen, childrenlen
graphnrtolists(n, graphnumber, parents, parentslen, children, childrenlen); graphnrtolists(n, graphnumber, parents, parentslen, children, childrenlen);
// Increase checked counter and prepare for next iteration // Increase checked counter and prepare for next iteration
graphschecked++; graphschecked++;
@ -515,17 +580,23 @@ int main(int argc, char *argv[]) {
if (NOSINK && minoutdegree == 0) continue; if (NOSINK && minoutdegree == 0) continue;
if (NOSOURCE && minindegree == 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) // Check whether this graph is canonical or not; continue if graph has not
if(!isdegreeordered(n, parents, parentslen, children, childrenlen)) continue; // 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 // Ignore graphs that are not connected
if(!isconnected(n, parents, parentslen, children, childrenlen)) continue; if (!isconnected(n, parents, parentslen, children, childrenlen))
continue;
// Find cycles // Find cycles
const int num_cycles = find_cycles(cycles, cyclescnt, n, children, childrenlen); const int num_cycles = find_cycles(cycles, cyclescnt, n, children, \
childrenlen);
// If enabled, ignore DAGs // If enabled, ignore DAGs
if (NONDAGONLY && num_cycles > 0) continue; if (NONDAGONLY && num_cycles > 0) continue;
// Test the Siblings-On-Cycles property // Test the Siblings-On-Cycles property
// A DAG is trivially a SOC // A DAG is trivially a SOC
if(num_cycles > 0 && !gissoc(n, parents, parentslen, children, childrenlen, cycles, cyclescnt)) continue; if (num_cycles > 0 && !gissoc(n, parents, parentslen, children, \
childrenlen, cycles, cyclescnt)) continue;
// We have found a SOC // We have found a SOC
len++; len++;
if (GRAPHVIZ) if (GRAPHVIZ)
@ -534,9 +605,12 @@ int main(int argc, char *argv[]) {
dumpgraph(n, children, childrenlen); dumpgraph(n, children, childrenlen);
} }
const int deltat = time(NULL) - t0; const int deltat = time(NULL) - t0;
const float rate = (deltat == 0) ? graphschecked : (float)graphschecked/(float)deltat; const float rate = (deltat == 0) ? graphschecked : \
(float)graphschecked/(float)deltat;
const float SOCrate = (deltat == 0) ? len : (float)len/(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, "\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); fprintf(stderr, "\nFound %d SOCs in %d seconds\n", len, deltat);
// Free manually allocated memory // Free manually allocated memory
free(cycles); free(cycles);

View File

@ -1,4 +1,5 @@
// SPDX-FileCopyrightText: 2023 Ämin Baumeler <amin@indyfac.ch> and Eleftherios-Ermis Tselentis <eleftheriosermis.tselentis@oeaw.ac.at> // SPDX-FileCopyrightText: 2023 Ämin Baumeler <amin@indyfac.ch> and
// Eleftherios-Ermis Tselentis <eleftheriosermis.tselentis@oeaw.ac.at>
// //
// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-License-Identifier: GPL-3.0-or-later
@ -32,10 +33,9 @@ int main(int argc, char *argv[]) {
int n = -1; int n = -1;
int row = 0; int row = 0;
int col = 0; int col = 0;
char ch;
printf("strict digraph \"File_%s_line_%d\" {", argv[1], line); printf("strict digraph \"File_%s_line_%d\" {", argv[1], line);
while (!feof(fp)) { while (!feof(fp)) {
ch = fgetc(fp); char ch = fgetc(fp);
switch (ch) { switch (ch) {
case '{': case '{':
if (row == 0 && col == 0 && headprinted == 0) { if (row == 0 && col == 0 && headprinted == 0) {

View File

@ -1,6 +1,7 @@
#!/usr/bin/python3 #!/usr/bin/python3
""" """
SPDX-FileCopyrightText: 2023 Ämin Baumeler <amin@indyfac.ch> and Eleftherios-Ermis Tselentis <eleftheriosermis.tselentis@oeaw.ac.at> SPDX-FileCopyrightText: 2023 Ämin Baumeler <amin@indyfac.ch> and
Eleftherios-Ermis Tselentis <eleftheriosermis.tselentis@oeaw.ac.at>
SPDX-License-Identifier: GPL-3.0-or-later SPDX-License-Identifier: GPL-3.0-or-later
""" """