// SPDX-FileCopyrightText: 2023 Ă„min Baumeler and Eleftherios-Ermis Tselentis // // SPDX-License-Identifier: GPL-3.0-or-later #include #include #include /*** * Read graphs from file. * Input `filename': string * Input `cnt': pointer to int * Input `maxdim': pointer to int * Output: pointer to graph data * * This function sets `cnt' to the total number of graphs read from `filename', * sets `maxdim' to the dimension (number of nodes) of the largest graph, * and returns the graph data. Graph data is structured as follows: * {dimension graph 1 | (0,0) | (0,1) | ... | (1,0) | (1,1) | ... | dimension graph 2 | ...} * The ith graph is at position i*(maxdim*maxdim + 1). ***/ int* read_graphs(char* filename, int *cnt, int *maxdim) { // Open file FILE *fp; fp = fopen(filename, "r"); if(fp == NULL) return NULL; // Count number of lines, allocate space and initiate counter char ch; int n = 0; *cnt = 0; // Total number of graphs *maxdim = 0; // Maximum number of vertices while(!feof(fp)) { ch = fgetc(fp); switch(ch) { case '\n': (*cnt)++; n = 0; break; case '{': case '}': *maxdim = (n > *maxdim) ? n : *maxdim; n = 0; break; case '0': case '1': n++; break; case ',': case ' ': case 0xffffffff: break; default: return NULL; // Format error } } rewind(fp); // Return to start of file // Allocate space for graph data const int gdatasize = *maxdim * *maxdim + 1; // Size allocation per graph const int arraysize = (1+ *cnt) * gdatasize; // Total space to allocate int *graphs = (int*)malloc(sizeof(int)*arraysize); // Allocation if(!graphs) { fprintf(stderr, "ERROR: Could not allocate enough memory to store the graphs.\n"); return NULL; } // Parse file int col = 0; // Column number int row = 0; // Row number int i = 0; // Current graph index n = -1; // Graph dimension int j = 0; // Running index while ((ch = fgetc(fp)) != EOF) { // New line encountered if(ch == '\n') { if(row != n) { fprintf(stderr, "ERROR: File not properly formatted.\n"); return NULL; } graphs[i*gdatasize] = n; i++; j = 0; col = 0; row = 0; n = -1; // Matrix entry encountered } else if(ch == '0' || ch == '1') { int x = ch - '0'; graphs[i*gdatasize + 1 + j] = x; col++; j++; // End-of-row or end-of-matrix encountered } else if(ch == '}') { if(n == -1) { n = col; } else if(col > 0 && n != col) { fprintf(stderr, "ERROR: File not properly formatted.\n"); return NULL; } // End of row if(col != 0) { row++; col = 0; } } } // Close file fclose(fp); return graphs; } /*** * Increase intervention counter by one. * Returns 0 if we run out of interventions, and 1 otherwise. ***/ int nextintervention(int n, int *interventionslen, int *interventionidx) { for(int i=0; i 0) { x /= 10; res++; } return res; } /*** * Verify the admissibility of the graphs * Go through all graphs and test them * `startidx': Index from which to start, assumed to be non-negative * `len': Number of graphs to test, assumed to be non-negative and such that startidx+len does not exceed the length of the `graphs' array * `maxn': Max. number of nodes * `graphs': Pointer to graph structure * * Return 0 if test succeeds, else return graphidx+1 of failed graph (this is the line number). * Return -1 on error. ***/ int test_graphs(int startidx, int len, int maxn, const int *graphs) { const int gdatasize = maxn * maxn + 1; // Size allocation per graph const int idatasize = (maxn+1)*(maxn+1)*2; // Max number of interventions per party 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 interventionslen[maxn]; // Number of interventions per party int interventionidx[maxn]; // Current intervention executed int parents[maxn*maxn]; // List all parents per party int parentslen[maxn]; // Number of parents per party int children[maxn*maxn]; // List all children per party int childrenlen[maxn]; // Numer of children per party const int padlen = ceillog10(len); time_t t0 = time(NULL); const time_t tstart = t0; for(int graphidx=startidx; graphidx t0) { const int count = graphidx - startidx + 1; const float percentage = 100*(float)count/(float)len; const int deltat = t1-tstart; 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); t0 = t1; } // Test graph with index `graphidx' // `n' is the order of this graph const int n = graphs[graphidx*gdatasize]; // Get parents and children // Adj matrix is such that (row,col) = 1 <=> edge from row to col for(int i=0; i= 3) START = atoi(argv[2]); if(argc >= 4) { if(argv[3][0] == '+') NUM = atoi(argv[3]+1); else NUM = atoi(argv[3])-START+1; } if(!(argc >= 2 && (argc < 3 || START > 0) && (argc < 4 || NUM > 0) && argc <= 4)) { fprintf(stderr, "Usage: %s [ [ | +]]\n", argv[0]); fprintf(stderr, " File name with adjacency matrices of simple directed graphs\n"); fprintf(stderr, " Verify graphs starting from line `startline'\n"); fprintf(stderr, " Verify graphs up to and including line `endline'\n"); fprintf(stderr, " + Verify `count' number of graphs\n"); fprintf(stderr, "\n"); fprintf(stderr, "[FILE FORMAT]\n"); fprintf(stderr, " Each line in `filename' must contain the adjacency matrix of a simple directed graph in the format\n"); fprintf(stderr, " {{a00,a01,...},{a10,a11,...},...} where aij=1 if and only if the graph has the edge i -> j\n"); fprintf(stderr, " The file `filename' may contain graphs with different order (number of vertices)\n"); fprintf(stderr, "\n"); fprintf(stderr, "This program verifies the admissibility of simple directed graphs.\n"); return -1; } // Read Graphs from File int graphcount = 0; int maxdimension = -1; const int *graphs = read_graphs(argv[1], &graphcount, &maxdimension); if(graphs == NULL) { fprintf(stderr, "ERROR: Could not read graphs from file `%s'.\n", argv[1]); return -1; } const int startidx = START ? START-1 : 0; // Index of graph to start verifying const int tot = NUM ? NUM : graphcount-startidx; // Number of graphs to be verified if(startidx >= graphcount || tot <= 0 || tot+startidx-1 >= graphcount) { fprintf(stderr, "ERROR: Lines to be verified are out of range\n"); return -1; } // 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); const int result = test_graphs(startidx, tot, maxdimension, graphs); if (result == 0) printf("These graphs are admissible\n"); else if(result == -1) fprintf(stderr, "ERROR: Something went wrong\n"); else printf("The function alpha does not represent the fixed point, or the graph on line %d is inadmissible\n", result); return result; }