chordless filter

This commit is contained in:
Ämin Baumeler 2024-11-20 11:26:27 +01:00
parent 06690e4982
commit e953d8aa1f

View File

@ -324,6 +324,63 @@ int find_cycles(int *cycles, int *cyclescnt, int n, const int *children, \
return found; return found;
} }
/***
* gischordless tests wheter the graph provided has chordless cycles only
* Parameter `n': Number of nodes
* Parameter `parents': Pointer to list of parents per node
* Parameter `parentslen': Pointer to list of number of parents per node
* Parameter `children': Pointer to list of children per node
* Parameter `childrenlen': Pointer to list of number of children per node
* Parameter `cycles': Pointer to list of cycles in the graph
* Parameter `cyclescnt': Pointer to list of cycles count
* Parameter `num_cycles' Total number of cycles
*
* This function retruns 0 if the graph has a directed cycle with a chord, and
* 1 otherwise.
*
* If there is no cycle, then the graph trivially satisfy this condition.
*
* If there are k-cycles, then a chord
* A) introduces a two-cycle, or
* B) introduces a (k-1)-cycle.
* So, if there are no two-cycles, then we must only test the cycles of length
* k where cyclescnt[k-1] is nonzero.
*
* Cycles of length two are trivially chordless.
***/
int gischordless(int n, const int *parents, const int *parentslen, \
const int *children, const int *childrenlen, const int *cycles, \
const int *cyclescnt, int num_cycles) {
if (!num_cycles) return 1;
const int hastwocycles = cyclescnt[2];
for (int clen=n; clen>2; clen--) {
if (!cyclescnt[clen]) continue;
if (!hastwocycles && !cyclescnt[clen-1]) continue;
for (int i=0; i<cyclescnt[clen]; i++) {
const int bs = blocksize(n);
const int startidx = clen*bs + i*clen; // Cycle starts here
int v = cycles[startidx+clen-1];
for (int pos=0; pos<clen; pos++) {
const int u = v;
v = cycles[startidx+pos];
// Cycle has arc u -> v
// Is there a chord, i.e., A) reverse arc u <- v or B) u -> v' for v'
// on the cycle? We test only B), but for all vertices on the cycle.
for (int cidx=0; cidx<childrenlen[u]; cidx++) {
const int child = children[n*u+cidx];
if (child == v) continue;
// Is `child` on the cycle?
for (int j=0; j<clen; j++) {
const int w = cycles[startidx+j];
if (child == w) return 0;
}
}
}
}
}
return 1;
}
/*** /***
* gissoc tests wheter the graph provided is a SOC or not. * gissoc tests wheter the graph provided is a SOC or not.
* Parameter `n': Number of nodes * Parameter `n': Number of nodes
@ -485,6 +542,7 @@ int main(int argc, char *argv[]) {
int RANDOM = 0; int RANDOM = 0;
int GRAPHVIZ = 0; int GRAPHVIZ = 0;
int VECTOR = 0; int VECTOR = 0;
int CHORDLESS = 0;
int UNKOPTION = 0; int UNKOPTION = 0;
int ALL = 0; int ALL = 0;
for (int i = 1; i < argc; i++) { for (int i = 1; i < argc; i++) {
@ -506,6 +564,8 @@ int main(int argc, char *argv[]) {
ALL = 1; ALL = 1;
} else if (strcmp(argv[i], "--vector") == 0) { } else if (strcmp(argv[i], "--vector") == 0) {
VECTOR = 1; VECTOR = 1;
} else if (strcmp(argv[i], "--chordless") == 0) {
CHORDLESS = 1;
} else { } else {
UNKOPTION = 1; UNKOPTION = 1;
break; break;
@ -523,6 +583,7 @@ int main(int argc, char *argv[]) {
fprintf(stderr, " -c ... that are cyclic (i.e., not DAGs)\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-sink ... without sink nodes (this logically implies -c)\n");
fprintf(stderr, " --no-source ... without source nodes (also this logically implies -c)\n"); fprintf(stderr, " --no-source ... without source nodes (also this logically implies -c)\n");
fprintf(stderr, " --chordless ... without cycles that have chords (this is incompatible with --no-source, see paper)\n");
fprintf(stderr, "\n"); fprintf(stderr, "\n");
fprintf(stderr, "This program prints the found SOCs as adjacency matrices to stdout, unless --graphviz has been specified.\n"); fprintf(stderr, "This program prints the found SOCs as adjacency matrices to stdout, unless --graphviz has been specified.\n");
fprintf(stderr, "To exclude (some) of the isomorphic SOCs, it uses a degree-order filter, unless --all is specified.\n"); fprintf(stderr, "To exclude (some) of the isomorphic SOCs, it uses a degree-order filter, unless --all is specified.\n");
@ -566,6 +627,8 @@ int main(int argc, char *argv[]) {
fprintf(stderr, " Filter: Omitting graphs with sink nodes\n"); fprintf(stderr, " Filter: Omitting graphs with sink nodes\n");
if (NOSOURCE) if (NOSOURCE)
fprintf(stderr, " Filter: Omitting graphs with source nodes\n"); fprintf(stderr, " Filter: Omitting graphs with source nodes\n");
if (CHORDLESS)
fprintf(stderr, " Filter: Omitting graphs with chords in directed cycles\n");
// We will always omit the graph with `graphnumber' 0; // We will always omit the graph with `graphnumber' 0;
// it is unintersting anyway // it is unintersting anyway
unsigned long long graphnumber = 0; unsigned long long graphnumber = 0;
@ -630,6 +693,9 @@ int main(int argc, char *argv[]) {
if (num_cycles > 0 && !gissoc(n, parents, parentslen, children, \ if (num_cycles > 0 && !gissoc(n, parents, parentslen, children, \
childrenlen, cycles, cyclescnt)) continue; childrenlen, cycles, cyclescnt)) continue;
// We have found a SOC // We have found a SOC
// If enabled, test chordless property
if (CHORDLESS && !gischordless(n, parents, parentslen, children, \
childrenlen, cycles, cyclescnt, num_cycles)) continue;
len++; len++;
if (GRAPHVIZ) if (GRAPHVIZ)
dumpgv(n, graphnumber, children, childrenlen); dumpgv(n, graphnumber, children, childrenlen);