1 /*
2  * This file is part of the RingDecomposerLib, licensed
3  * under BSD New license (see LICENSE in the root directory).
4  * Copyright (c) 2016
5  * University of Hamburg, ZBH - Center for Bioinformatics
6  * Niek Andresen, Florian Flachsenberg, Matthias Rarey
7  *
8  * Please cite:
9  *
10  * Kolodzik, A.; Urbaczek, S.; Rarey, M.
11  * Unique Ring Families: A Chemically Meaningful Description
12  * of Molecular Ring Topologies.
13  * J. Chem. Inf. Model., 2012, 52 (8), pp 2013-2021
14  *
15  * Flachsenberg, F.; Andresen, N.; Rarey, M.
16  * RingDecomposerLib: An Open-Source Implementation of
17  * Unique Ring Families and Other Cycle Bases.
18  * J. Chem. Inf. Model., 2017, 57 (2), pp 122-126
19  */
20 
21 #include <assert.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <limits.h>
25 #include <string.h>
26 #include <float.h>
27 #include <math.h>
28 
29 #include "RingDecomposerLib.h"
30 
31 #include "RDLapsp.h"
32 #include "RDLbitset.h"
33 #include "RDLcycleFams.h"
34 #include "RDLdataStruct.h"
35 #include "RDLgraph.h"
36 #include "RDLhandler.h"
37 #include "RDLinfo.h"
38 #include "RDLrelation.h"
39 #include "RDLtarjan.h"
40 #include "RDLutility.h"
41 
42 const unsigned RDL_RESERVED_START = 64;
43 
44 /* define some constants */
45 const unsigned RDL_INVALID_RESULT = UINT_MAX;
46 const unsigned RDL_DUPLICATE_EDGE = UINT_MAX - 1;
47 const unsigned RDL_NO_RINGSYSTEM = UINT_MAX - 2;
48 const double RDL_INVALID_RC_COUNT = DBL_MAX;
49 
50 /* public, set the global output function */
RDL_setOutputFunction(RDL_outputFunction func)51 void RDL_setOutputFunction(RDL_outputFunction func)
52 {
53   RDL_outputFunc = func;
54 }
55 
56 /* public */
RDL_initNewGraph(unsigned V)57 RDL_graph *RDL_initNewGraph(unsigned V)
58 {
59   return RDL_initNewGraph_g(V, 1);
60 }
61 
62 /* public, add an edge with range check! */
RDL_addUEdge(RDL_graph * gra,RDL_node from,RDL_node to)63 unsigned RDL_addUEdge(RDL_graph *gra, RDL_node from, RDL_node to)
64 {
65   return RDL_addUEdge_g(gra, from, to);
66 }
67 
68 /* public, the calculation routine */
RDL_calculate(RDL_graph * gra)69 RDL_data *RDL_calculate(RDL_graph *gra)
70 {
71   RDL_data *data;
72   unsigned i, j, k, urf_index, rcf_index;
73   unsigned nof_relevant_fams, nof_relevant_fams_sum;
74 
75   if (!gra) {
76     RDL_outputFunc(RDL_ERROR, "The graph is NULL.\n");
77     return NULL;
78   }
79 
80   /* we can't calculate anything if there isn't at least one node */
81   if(!gra->V) {
82     RDL_outputFunc(RDL_ERROR, "The graph has no nodes.\n");
83     return NULL;
84   }
85 
86   data = malloc(sizeof(*data));
87 
88   /* FIRST STEP: TARJAN */
89   data->bccGraphs = RDL_tarjanBCC(gra);
90   data->nofURFs = 0;
91   data->nofRCFs = 0;
92 
93   /* allocate result structures */
94   data->spiPerBCC = malloc(data->bccGraphs->nof_bcc * sizeof(*data->spiPerBCC));
95   data->CFsPerBCC = malloc(data->bccGraphs->nof_bcc * sizeof(*data->CFsPerBCC));
96   data->urfInfoPerBCC = malloc(data->bccGraphs->nof_bcc * sizeof(*data->urfInfoPerBCC));
97   data->nofURFsPerBCC = malloc(data->bccGraphs->nof_bcc * sizeof(*data->nofURFsPerBCC));
98   data->nofRCFsPerBCC = malloc(data->bccGraphs->nof_bcc * sizeof(*data->nofRCFsPerBCC));
99 
100   /* the followeing steps are performed for each BCC */
101   for (i = 0; i < data->bccGraphs->nof_bcc; ++i) {
102     /* solve APSP problem */
103     data->spiPerBCC[i] = RDL_AllPairsShortestPaths(data->bccGraphs->bcc_graphs[i]);
104     /* calculate RCFs with Vismara's algortihm */
105     data->CFsPerBCC[i] = RDL_findCycleFams(data->bccGraphs->bcc_graphs[i], data->spiPerBCC[i]);
106     /* this can fail if the BCC is to large */
107     if (!data->CFsPerBCC[i]) {
108       /* delete families and APSP information UPTO current index */
109       for (j = 0; j < i; ++j) {
110         RDL_deleteAPSP(data->spiPerBCC[j], data->bccGraphs->bcc_graphs[j]->V);
111         RDL_deleteCycleFams(data->CFsPerBCC[j]);
112         if (data->nofURFsPerBCC[j] > 0) {
113           RDL_deleteURFInfo(data->urfInfoPerBCC[j]);
114         }
115       }
116       /* delete APSP for current index (there is no RCF info) */
117       RDL_deleteAPSP(data->spiPerBCC[i], data->bccGraphs->bcc_graphs[i]->V);
118 
119       /* free alloced per BCC structures */
120       free(data->spiPerBCC);
121       free(data->CFsPerBCC);
122       free(data->nofURFsPerBCC);
123       free(data->nofRCFsPerBCC);
124       free(data->urfInfoPerBCC);
125       /* and of course the BCC graph */
126       RDL_deleteBCCGraph(data->bccGraphs);
127       /* free resulting struct */
128       free(data);
129 
130       return NULL;
131     }
132     if(data->CFsPerBCC[i]->nofFams > 0) {
133       /* if there is at least one RCF, check URF relation */
134       data->urfInfoPerBCC[i] = RDL_checkURFRelation(data->CFsPerBCC[i],
135           data->bccGraphs->bcc_graphs[i], data->spiPerBCC[i]);
136       data->nofURFsPerBCC[i] = data->urfInfoPerBCC[i]->nofURFs;
137 
138       nof_relevant_fams = 0;
139       /* count RCFs */
140       for (j = 0; j < data->CFsPerBCC[i]->nofFams; ++j) {
141         if (data->CFsPerBCC[i]->fams[j]->mark) {
142           ++nof_relevant_fams;
143         }
144       }
145 
146       nof_relevant_fams_sum = 0;
147       for (j = 0; j < data->nofURFsPerBCC[i]; ++j) {
148         nof_relevant_fams_sum += data->urfInfoPerBCC[i]->nofCFsPerURF[j];
149       }
150 
151       if (nof_relevant_fams != nof_relevant_fams_sum) {
152         RDL_outputFunc(RDL_ERROR, "different number of relevant families!\n");
153         /* internal check, should never happen */
154         assert(0);
155       }
156       data->nofRCFsPerBCC[i] = nof_relevant_fams;
157     }
158     else {
159       data->nofURFsPerBCC[i] = 0;
160       data->nofRCFsPerBCC[i] = 0;
161     }
162     data->nofURFs += data->nofURFsPerBCC[i];
163     data->nofRCFs += data->nofRCFsPerBCC[i];
164   }
165 
166   /* create a mapping from URFs to BCCs */
167   data->urf_to_bcc = malloc(data->nofURFs * sizeof(*data->urf_to_bcc));
168   /* create a mapping from RCFs to URFs */
169   data->rcf_to_urf = malloc(data->nofRCFs * sizeof(*data->rcf_to_urf));
170   urf_index = 0;
171   rcf_index = 0;
172   for (i = 0; i < data->bccGraphs->nof_bcc; ++i) {
173     for (j = 0; j < data->nofURFsPerBCC[i]; ++j, ++urf_index) {
174       data->urf_to_bcc[urf_index][0] = i;
175       data->urf_to_bcc[urf_index][1] = j;
176       for (k = 0; k < data->urfInfoPerBCC[i]->nofCFsPerURF[j]; ++k, ++rcf_index) {
177         data->rcf_to_urf[rcf_index][0] = urf_index;
178         data->rcf_to_urf[rcf_index][1] = k;
179       }
180     }
181   }
182 
183   data->graph = gra;
184 
185   return data;
186 }
187 
188 /* public, free memory */
RDL_deleteData(RDL_data * data)189 void RDL_deleteData(RDL_data *data)
190 {
191   unsigned i;
192 
193   for (i = 0; i < data->bccGraphs->nof_bcc; ++i) {
194     RDL_deleteAPSP(data->spiPerBCC[i], data->bccGraphs->bcc_graphs[i]->V);
195     RDL_deleteCycleFams(data->CFsPerBCC[i]);
196     if (data->nofURFsPerBCC[i] > 0) {
197       RDL_deleteURFInfo(data->urfInfoPerBCC[i]);
198     }
199   }
200   free(data->spiPerBCC);
201   free(data->CFsPerBCC);
202   free(data->nofURFsPerBCC);
203   free(data->nofRCFsPerBCC);
204   free(data->urfInfoPerBCC);
205   RDL_deleteBCCGraph(data->bccGraphs);
206   free(data->urf_to_bcc);
207   free(data->rcf_to_urf);
208 
209   RDL_deleteGraph(data->graph);
210   free(data);
211 }
212 
213 /* public, get the total number of URFs */
RDL_getNofURF(const RDL_data * data)214 unsigned RDL_getNofURF(const RDL_data *data)
215 {
216   if (!data) {
217     RDL_outputFunc(RDL_ERROR, "RDL_data is NULL!\n");
218     return RDL_INVALID_RESULT;
219   }
220   return data->nofURFs;
221 }
222 
223 /* public, get the total number of RCFs */
RDL_getNofRCF(const RDL_data * data)224 unsigned RDL_getNofRCF(const RDL_data *data)
225 {
226   if (!data) {
227     RDL_outputFunc(RDL_ERROR, "RDL_data is NULL!\n");
228     return RDL_INVALID_RESULT;
229   }
230   return data->nofRCFs;
231 }
232 
233 /*
234  * private
235  * return the weight for INTERNAL indices,
236  * urf_internal_index relative to bcc_index and rcf_internal_index relative to URF
237  */
RDL_getWeight_internal(const RDL_data * data,unsigned bcc_index,unsigned urf_internal_index,unsigned rcf_internal_index)238 static unsigned RDL_getWeight_internal(const RDL_data *data,
239     unsigned bcc_index, unsigned urf_internal_index, unsigned rcf_internal_index)
240 {
241   return data->urfInfoPerBCC[bcc_index]->URFs[urf_internal_index][rcf_internal_index]->weight;
242 }
243 
244 /* public, get weight for the given URF */
RDL_getWeightForURF(const RDL_data * data,unsigned index)245 unsigned RDL_getWeightForURF(const RDL_data *data, unsigned index)
246 {
247   unsigned bcc_index, internal_index;
248   if (!data) {
249     RDL_outputFunc(RDL_ERROR, "RDL_data is NULL!\n");
250     return RDL_INVALID_RESULT;
251   }
252 
253   if (index >= data->nofURFs) {
254     RDL_outputFunc(RDL_ERROR, "invalid index: %u\n", index);
255     return RDL_INVALID_RESULT;
256   }
257   /* ger internal index */
258   bcc_index = data->urf_to_bcc[index][0];
259   internal_index = data->urf_to_bcc[index][1];
260   return RDL_getWeight_internal(data, bcc_index, internal_index, 0);
261 }
262 
263 /* public, get weight for the given RCF */
RDL_getWeightForRCF(const RDL_data * data,unsigned index)264 unsigned RDL_getWeightForRCF(const RDL_data *data, unsigned index)
265 {
266   unsigned bcc_index, urf_internal_index, rcf_internal_index, urf_index;
267   if (!data) {
268     RDL_outputFunc(RDL_ERROR, "RDL_data is NULL!\n");
269     return RDL_INVALID_RESULT;
270   }
271 
272   if (index >= data->nofRCFs) {
273     RDL_outputFunc(RDL_ERROR, "invalid index: %u\n", index);
274     return RDL_INVALID_RESULT;
275   }
276 
277   /* map rcf to urf and urf to bcc */
278   urf_index = data->rcf_to_urf[index][0];
279   rcf_internal_index = data->rcf_to_urf[index][1];
280   bcc_index = data->urf_to_bcc[urf_index][0];
281   urf_internal_index = data->urf_to_bcc[urf_index][1];
282   return RDL_getWeight_internal(data, bcc_index,
283       urf_internal_index, rcf_internal_index);
284 }
285 
286 /*
287  * private
288  * return the nodes for INTERNAL indices,
289  * urf_internal_index relative to bcc_index and rcf_internal_index relative to URF
290  */
RDL_getNodes_internal(const RDL_data * data,unsigned bcc_index,unsigned urf_internal_index,unsigned rcf_internal_index,char * atoms)291 static void RDL_getNodes_internal(const RDL_data *data, unsigned bcc_index,
292     unsigned urf_internal_index, unsigned rcf_internal_index, char* atoms)
293 {
294   const RDL_cfam **URF;
295   char *visited;
296   const RDL_graph* graph;
297 
298   graph = data->bccGraphs->bcc_graphs[bcc_index];
299 
300   URF = (const RDL_cfam **)data->urfInfoPerBCC[bcc_index]->URFs[urf_internal_index];
301 
302   visited = malloc(graph->V *  sizeof(*visited));
303 
304   /* BFS on both shortest path graphs */
305   memset(visited, 0, graph->V *  sizeof(*visited));
306   RDL_giveVertices(URF[rcf_internal_index]->r, URF[rcf_internal_index]->q,
307       atoms, data->spiPerBCC[bcc_index], visited);
308 
309   memset(visited, 0, graph->V *  sizeof(*visited));
310   RDL_giveVertices(URF[rcf_internal_index]->r, URF[rcf_internal_index]->p,
311       atoms, data->spiPerBCC[bcc_index], visited);
312 
313   if(URF[rcf_internal_index]->x < UINT_MAX) /*even cycle*/ {
314     atoms[URF[rcf_internal_index]->x] = 1;
315   }
316   free(visited);
317 }
318 
319 
320 /* private
321  * gives an array of indices of nodes that are contained in the URF with the
322  * given index. Array is terminated by UINT_MAX
323  */
RDL_getNodesURF(const RDL_data * data,unsigned index)324 static RDL_node *RDL_getNodesURF(const RDL_data *data, unsigned index)
325 {
326   unsigned i,nofFams,nextfree=0,alloced, bcc_index, internal_index;
327   char *atoms;
328   RDL_node *result;
329   const RDL_graph* graph;
330 
331   bcc_index = data->urf_to_bcc[index][0];
332   internal_index = data->urf_to_bcc[index][1];
333   graph = data->bccGraphs->bcc_graphs[bcc_index];
334   atoms = malloc(graph->V * sizeof(*atoms));
335   memset(atoms, 0, graph->V * sizeof(*atoms));
336 
337   nofFams = data->urfInfoPerBCC[bcc_index]->nofCFsPerURF[internal_index];
338   alloced = RDL_RESERVED_START;
339   result = malloc(alloced * sizeof(*result));
340 
341   /* iterate over all RCFs in this URFs and collect data in one bitset (atoms) */
342   for(i=0; i<nofFams; ++i) {
343     RDL_getNodes_internal(data, bcc_index, internal_index, i, atoms);
344   }
345 
346   /* translate into a dynamic table */
347   for(i=0; i<graph->V; ++i) {
348     if(atoms[i] == 1) {
349       if(nextfree == alloced) {/*double the size*/
350         alloced *= 2;
351         result = realloc(result, alloced*sizeof(*result));
352       }
353       result[nextfree++] = data->bccGraphs->node_from_bcc_mapping[bcc_index][i];
354     }
355   }
356 
357   result = realloc(result, (nextfree+1)*sizeof(*result));
358 
359   result[nextfree] = UINT_MAX;
360   free(atoms);
361 
362   return result;
363 }
364 
365 /* private
366  * gives an array of indices of nodes that are contained in the RRF with the
367  * given index. Array is terminated by UINT_MAX
368  */
RDL_getNodesRCF(const RDL_data * data,unsigned index)369 static RDL_node *RDL_getNodesRCF(const RDL_data *data, unsigned index)
370 {
371   unsigned i,nextfree=0,alloced, bcc_index,
372       urf_internal_index, rcf_internal_index, urf_index;
373   char *atoms;
374   RDL_node *result;
375   const RDL_graph* graph;
376 
377   urf_index = data->rcf_to_urf[index][0];
378   rcf_internal_index = data->rcf_to_urf[index][1];
379   bcc_index = data->urf_to_bcc[urf_index][0];
380   urf_internal_index = data->urf_to_bcc[urf_index][1];
381   graph = data->bccGraphs->bcc_graphs[bcc_index];
382   atoms = malloc(graph->V * sizeof(*atoms));
383   memset(atoms, 0, graph->V * sizeof(*atoms));
384 
385   alloced = RDL_RESERVED_START;
386   result = malloc(alloced * sizeof(*result));
387 
388   /* save the nodes into bitset */
389   RDL_getNodes_internal(data, bcc_index, urf_internal_index,
390       rcf_internal_index, atoms);
391 
392   /* translate into a dynamic table */
393   for(i=0; i<graph->V; ++i) {
394     if(atoms[i] == 1) {
395       if(nextfree == alloced) {/*double the size*/
396         alloced *= 2;
397         result = realloc(result, alloced*sizeof(*result));
398       }
399       result[nextfree++] = data->bccGraphs->node_from_bcc_mapping[bcc_index][i];
400     }
401   }
402 
403   result = realloc(result, (nextfree+1)*sizeof(*result));
404 
405   result[nextfree] = UINT_MAX;
406   free(atoms);
407 
408   return result;
409 }
410 
411 /* public, calculate the number of RCs */
RDL_getNofRC(const RDL_data * data)412 double RDL_getNofRC(const RDL_data *data)
413 {
414   double result = 0, intermediate;
415   unsigned i;
416 
417   if (!data) {
418     RDL_outputFunc(RDL_ERROR, "RDL_data is NULL!\n");
419     return RDL_INVALID_RC_COUNT;
420   }
421 
422   /* add up results for URFs */
423   for (i = 0; i < data->nofURFs; ++i) {
424     intermediate = RDL_getNofRCForURF(data, i);
425     if (intermediate == RDL_INVALID_RC_COUNT) {
426       return RDL_INVALID_RC_COUNT;
427     }
428 
429     result += intermediate;
430   }
431 
432   return result;
433 }
434 
435 /*
436  * private
437  * return the # RCs for INTERNAL indices,
438  * urf_internal_index relative to bcc_index and rcf_internal_index relative to URF
439  */
RDL_getNofRCForRCF_internal(const RDL_data * data,unsigned bcc_index,unsigned urf_internal_index,unsigned rcf_internal_index)440 static double RDL_getNofRCForRCF_internal(const RDL_data *data,
441     unsigned bcc_index, unsigned urf_internal_index,
442     unsigned rcf_internal_index)
443 {
444   double nofPaths1, nofPaths2, result;
445   const double prod_limit = sqrt(DBL_MAX) - 1.0;
446   const RDL_cfam** URF;
447   const RDL_graph* graph;
448 
449   result = 0.0;
450 
451   graph = data->bccGraphs->bcc_graphs[bcc_index];
452 
453   URF = (const RDL_cfam **)data->urfInfoPerBCC[bcc_index]->URFs[urf_internal_index];
454 
455   /* count the number of paths one both sides */
456   nofPaths1 = RDL_countPaths(URF[rcf_internal_index]->r, URF[rcf_internal_index]->q,
457       graph->V, data->spiPerBCC[bcc_index]);
458   nofPaths2 = RDL_countPaths(URF[rcf_internal_index]->r, URF[rcf_internal_index]->p,
459       graph->V, data->spiPerBCC[bcc_index]);
460 
461   result = nofPaths1 * nofPaths2;
462 
463   /* check if either of the number paths is larger than what we can multiply */
464   if (nofPaths1 >= prod_limit || nofPaths2 >= prod_limit) {
465     RDL_outputFunc(RDL_WARNING, "result overflow when counting paths!\n");
466     return RDL_INVALID_RC_COUNT;
467   }
468 
469   return result;
470 }
471 
472 /* public, return the # RCs for given RCF */
RDL_getNofRCForRCF(const RDL_data * data,unsigned index)473 double RDL_getNofRCForRCF(const RDL_data *data, unsigned index)
474 {
475   unsigned bcc_index, urf_id, urf_internal_index, rcf_internal_index;
476 
477   if (!data) {
478     RDL_outputFunc(RDL_ERROR, "RDL_data is NULL!\n");
479     return RDL_INVALID_RC_COUNT;
480   }
481 
482   if (index >= data->nofRCFs) {
483     RDL_outputFunc(RDL_ERROR, "invalid index: %u\n", index);
484     return RDL_INVALID_RC_COUNT;
485   }
486 
487   /* map indices */
488   urf_id = data->rcf_to_urf[index][0];
489   rcf_internal_index = data->rcf_to_urf[index][1];
490 
491   bcc_index = data->urf_to_bcc[urf_id][0];
492   urf_internal_index = data->urf_to_bcc[urf_id][1];
493 
494   return RDL_getNofRCForRCF_internal(data, bcc_index,
495       urf_internal_index, rcf_internal_index);
496 }
497 
498 /* public, return the # RCs for given URF */
RDL_getNofRCForURF(const RDL_data * data,unsigned index)499 double RDL_getNofRCForURF(const RDL_data *data, unsigned index)
500 {
501   unsigned i,nofFams, bcc_index, internal_index;
502   double result=0, prod;
503 
504   const double sum_limit = DBL_MAX/2.0 - 1.0;
505 
506   if (!data) {
507     RDL_outputFunc(RDL_ERROR, "RDL_data is NULL!\n");
508     return RDL_INVALID_RC_COUNT;
509   }
510 
511   if (index >= data->nofURFs) {
512     RDL_outputFunc(RDL_ERROR, "invalid index: %u\n", index);
513     return RDL_INVALID_RC_COUNT;
514   }
515 
516   /* map indices */
517   bcc_index = data->urf_to_bcc[index][0];
518   internal_index = data->urf_to_bcc[index][1];
519 
520   nofFams = data->urfInfoPerBCC[bcc_index]->nofCFsPerURF[internal_index];
521 
522   /* iterate all RCFs in this URF */
523   for(i=0; i<nofFams; ++i) {
524     prod = RDL_getNofRCForRCF_internal(data, bcc_index, internal_index, i);
525 
526     /* check if any summand is larger than limit */
527     if (prod >= sum_limit || result >= sum_limit) {
528       RDL_outputFunc(RDL_WARNING, "result overflow when counting paths!\n");
529       return RDL_INVALID_RC_COUNT;
530     }
531 
532     result += prod;
533   }
534 
535   return result;
536 }
537 
538 /* private
539  * return the edges for INTERNAL indices,
540  * urf_internal_index relative to bcc_index and rcf_internal_index relative to URF
541  */
RDL_getEdges_internal(const RDL_data * data,unsigned bcc_index,unsigned urf_internal_index,unsigned rcf_internal_index,char * edges)542 static void RDL_getEdges_internal(const RDL_data *data,
543     unsigned bcc_index, unsigned urf_internal_index,
544     unsigned rcf_internal_index, char* edges)
545 {
546   const RDL_cfam **URF;
547   char *visited;
548   const RDL_graph* graph;
549 
550   graph = data->bccGraphs->bcc_graphs[bcc_index];
551 
552   URF = (const RDL_cfam **)data->urfInfoPerBCC[bcc_index]->URFs[urf_internal_index];
553 
554   /* perform BFS on both paths and collect edges */
555   visited = malloc(graph->V *  sizeof(*visited));
556   memset(visited, 0, graph->V *  sizeof(*visited));
557 
558   RDL_giveEdges(URF[rcf_internal_index]->r, URF[rcf_internal_index]->q,
559       edges, graph, data->spiPerBCC[bcc_index], visited);
560 
561   memset(visited, 0, graph->V *  sizeof(*visited));
562   RDL_giveEdges(URF[rcf_internal_index]->r, URF[rcf_internal_index]->p,
563       edges, graph, data->spiPerBCC[bcc_index], visited);
564 
565   /*
566    * in contrast to the nodes, we have to add additional edges, because we're
567    * looking at cycles...
568    */
569   if(URF[rcf_internal_index]->x < UINT_MAX) /*even cycle*/ {
570     edges[RDL_edgeId(graph,URF[rcf_internal_index]->q,URF[rcf_internal_index]->x)] = 1;
571     edges[RDL_edgeId(graph,URF[rcf_internal_index]->p,URF[rcf_internal_index]->x)] = 1;
572   }
573   else /*odd cycle*/ {
574     edges[RDL_edgeId(graph,URF[rcf_internal_index]->q,URF[rcf_internal_index]->p)] = 1;
575   }
576   free(visited);
577 }
578 
579 
580 /* private
581  * gives an array of indices of edges that are contained in the URF with the
582  * given index. Array is terminated by UINT_MAX
583  */
RDL_getEdgesURF(const RDL_data * data,unsigned index)584 static unsigned *RDL_getEdgesURF(const RDL_data *data, unsigned index)
585 {
586   unsigned i,nofFams,nextfree=0,alloced, bcc_index, internal_index;
587   char *edges;
588   unsigned *result;
589   const RDL_graph* graph;
590 
591   /* map indices */
592   bcc_index = data->urf_to_bcc[index][0];
593   internal_index = data->urf_to_bcc[index][1];
594   graph = data->bccGraphs->bcc_graphs[bcc_index];
595   edges = malloc(graph->E * sizeof(*edges));
596   memset(edges, 0, graph->E * sizeof(*edges));
597 
598   nofFams = data->urfInfoPerBCC[bcc_index]->nofCFsPerURF[internal_index];
599   alloced = RDL_RESERVED_START;
600   result = malloc(alloced * sizeof(*result));
601 
602   /* iterate over all RCFs in this URF and collect results in bitset (edges) */
603   for(i=0; i<nofFams; ++i) {
604     RDL_getEdges_internal(data, bcc_index, internal_index, i, edges);
605   }
606 
607   /* translate into dynamic table */
608   for(i=0; i<graph->E; ++i) {
609     if(edges[i] == 1) {
610       if(nextfree == alloced)
611       {/*double the size*/
612         alloced *= 2;
613         result = realloc(result, alloced*sizeof(*result));
614       }
615       result[nextfree++] = data->bccGraphs->edge_from_bcc_mapping[bcc_index][i];
616     }
617   }
618   result = realloc(result, (nextfree+1)*sizeof(*result));
619 
620   result[nextfree] = UINT_MAX;
621 
622   free(edges);
623   return result;
624 }
625 
626 /* private
627  * gives an array of indices of edges that are contained in the RCF with the
628  * given index. Array is terminated by UINT_MAX
629  */
RDL_getEdgesRCF(const RDL_data * data,unsigned index)630 static unsigned *RDL_getEdgesRCF(const RDL_data *data, unsigned index)
631 {
632   unsigned j,nextfree=0,alloced, urf_index, bcc_index,
633       urf_internal_index, rcf_internal_index;
634   char *edges;
635   unsigned *result;
636   const RDL_graph* graph;
637 
638   /* index mapping */
639   urf_index = data->rcf_to_urf[index][0];
640   rcf_internal_index = data->rcf_to_urf[index][1];
641   bcc_index = data->urf_to_bcc[urf_index][0];
642   urf_internal_index = data->urf_to_bcc[urf_index][1];
643   graph = data->bccGraphs->bcc_graphs[bcc_index];
644   edges = malloc(graph->E * sizeof(*edges));
645   memset(edges, 0, graph->E * sizeof(*edges));
646 
647   alloced = RDL_RESERVED_START;
648   result = malloc(alloced * sizeof(*result));
649 
650   RDL_getEdges_internal(data, bcc_index, urf_internal_index,
651       rcf_internal_index, edges);
652 
653   /* translate into dynamic table */
654   for(j=0; j<graph->E; ++j) {
655     if(edges[j] == 1) {
656       if(nextfree == alloced)
657       {/*double the size*/
658         alloced *= 2;
659         result = realloc(result, alloced*sizeof(*result));
660       }
661       result[nextfree++] = data->bccGraphs->edge_from_bcc_mapping[bcc_index][j];
662     }
663   }
664 
665   result = realloc(result, (nextfree+1)*sizeof(*result));
666 
667   result[nextfree] = UINT_MAX;
668 
669   free(edges);
670   return result;
671 }
672 
673 
674 /* private, calls getNodesURF() or getEdgesURF() depending on mode 'a' or 'b' */
RDL_giveURF(const RDL_data * data,unsigned index,char mode)675 static unsigned *RDL_giveURF(const RDL_data *data, unsigned index, char mode)
676 {
677   unsigned *result;
678   if(mode == 'a')
679   {
680     result = RDL_getNodesURF(data, index);
681   }
682   else if(mode == 'b')
683   {
684     result = RDL_getEdgesURF(data, index);
685   }
686   else
687   {
688     RDL_outputFunc(RDL_ERROR, "tried to call 'RDL_giveURF()' with invalid mode '%c'\n", mode);
689     /* cannot occur when using interface */
690     assert(0);
691     return NULL;
692   }
693 
694   return result;
695 }
696 
697 /* private, calls getNodesRCF() or getEdgesRCF() depending on mode 'a' or 'b' */
RDL_giveRCF(const RDL_data * data,unsigned index,char mode)698 static unsigned *RDL_giveRCF(const RDL_data *data, unsigned index, char mode)
699 {
700   unsigned *result;
701   if(mode == 'a')
702   {
703     result = RDL_getNodesRCF(data, index);
704   }
705   else if(mode == 'b')
706   {
707     result = RDL_getEdgesRCF(data, index);
708   }
709   else
710   {
711     RDL_outputFunc(RDL_ERROR, "tried to call 'RDL_giveRCF()' with invalid mode '%c'\n", mode);
712     /* cannot occur when using interface */
713     assert(0);
714     return NULL;
715   }
716 
717   return result;
718 }
719 
720 /* public, function for retrieving nodes in an URF */
RDL_getNodesForURF(const RDL_data * data,unsigned index,RDL_node ** ptr)721 unsigned RDL_getNodesForURF(const RDL_data *data, unsigned index, RDL_node **ptr)
722 {
723   unsigned i;
724 
725   if (!data) {
726     RDL_outputFunc(RDL_ERROR, "RDL_data is NULL!\n");
727     (*ptr) = malloc(sizeof(**ptr));
728     return RDL_INVALID_RESULT;
729   }
730 
731   if (index >= data->nofURFs) {
732     RDL_outputFunc(RDL_ERROR, "invalid index: %u\n", index);
733     (*ptr) = malloc(sizeof(**ptr));
734     return RDL_INVALID_RESULT;
735   }
736 
737   (*ptr) = RDL_getNodesURF(data, index);
738   for(i=0; (*ptr)[i]<UINT_MAX; ++i); /*counts the number of atoms*/
739   return i;
740 }
741 
742 /* public, function for retrieving nodes in an RCF */
RDL_getNodesForRCF(const RDL_data * data,unsigned index,RDL_node ** ptr)743 unsigned RDL_getNodesForRCF(const RDL_data *data, unsigned index, RDL_node **ptr)
744 {
745   unsigned i;
746 
747   if (!data) {
748     RDL_outputFunc(RDL_ERROR, "RDL_data is NULL!\n");
749     (*ptr) = malloc(sizeof(**ptr));
750     return RDL_INVALID_RESULT;
751   }
752 
753   if (index >= data->nofRCFs) {
754     RDL_outputFunc(RDL_ERROR, "invalid index: %u\n", index);
755     (*ptr) = malloc(sizeof(**ptr));
756     return RDL_INVALID_RESULT;
757   }
758 
759   (*ptr) = RDL_getNodesRCF(data, index);
760   for(i=0; (*ptr)[i]<UINT_MAX; ++i); /*counts the number of atoms*/
761   return i;
762 }
763 
764 /* public, function for retrieving edges of URF */
RDL_getEdgesForURF(const RDL_data * data,unsigned index,RDL_edge ** ptr)765 unsigned RDL_getEdgesForURF(const RDL_data *data, unsigned index, RDL_edge **ptr)
766 {
767   unsigned nextfree, alloced;
768   RDL_edge *result;
769   unsigned *edgeIndices;
770   unsigned i;
771 
772   if (!data) {
773     RDL_outputFunc(RDL_ERROR, "RDL_data is NULL!\n");
774     (*ptr) = malloc(sizeof(**ptr));
775     return RDL_INVALID_RESULT;
776   }
777 
778   if (index >= data->nofURFs) {
779     RDL_outputFunc(RDL_ERROR, "invalid index: %u\n", index);
780     (*ptr) = malloc(sizeof(**ptr));
781     return RDL_INVALID_RESULT;
782   }
783 
784   nextfree = 0;
785   alloced = RDL_RESERVED_START;
786   result = malloc(alloced * sizeof(*result));
787   edgeIndices = RDL_getEdgesURF(data, index);
788   /* translate result from edge indices to edges */
789   for(i=0; edgeIndices[i]<UINT_MAX; ++i)
790   {
791     if(nextfree == alloced)/*more space needed in result*/
792     {
793       alloced *= 2; /* double the space */
794       result = realloc(result, alloced * sizeof(*result));
795     }
796     result[nextfree][0] = data->graph->edges[edgeIndices[i]][0];
797     result[nextfree][1] = data->graph->edges[edgeIndices[i]][1];
798     ++nextfree;
799   }
800   result = realloc(result, nextfree * sizeof(*result));
801   free(edgeIndices);
802   (*ptr) = result;
803   return nextfree;
804 }
805 
806 /* public, function for retrieving edges of RCF */
RDL_getEdgesForRCF(const RDL_data * data,unsigned index,RDL_edge ** ptr)807 unsigned RDL_getEdgesForRCF(const RDL_data *data, unsigned index, RDL_edge **ptr)
808 {
809   unsigned nextfree, alloced;
810   RDL_edge *result;
811   unsigned *edgeIndices;
812   unsigned i;
813 
814   if (!data) {
815     RDL_outputFunc(RDL_ERROR, "RDL_data is NULL!\n");
816     (*ptr) = malloc(sizeof(**ptr));
817     return RDL_INVALID_RESULT;
818   }
819 
820   if (index >= data->nofRCFs) {
821     RDL_outputFunc(RDL_ERROR, "invalid index: %u\n", index);
822     (*ptr) = malloc(sizeof(**ptr));
823     return RDL_INVALID_RESULT;
824   }
825 
826   nextfree = 0;
827   alloced = RDL_RESERVED_START;
828   result = malloc(alloced * sizeof(*result));
829   edgeIndices = RDL_getEdgesRCF(data, index);
830   /* translate result from edge indices to edges */
831   for(i=0; edgeIndices[i]<UINT_MAX; ++i)
832   {
833     if(nextfree == alloced)/*more space needed in result*/
834     {
835       alloced *= 2; /* double the space */
836       result = realloc(result, alloced * sizeof(*result));
837     }
838     result[nextfree][0] = data->graph->edges[edgeIndices[i]][0];
839     result[nextfree][1] = data->graph->edges[edgeIndices[i]][1];
840     ++nextfree;
841   }
842   result = realloc(result, nextfree * sizeof(*result));
843   free(edgeIndices);
844   (*ptr) = result;
845   return nextfree;
846 }
847 
848 /* public, to delete result of RDL_getCyclesChar() */
RDL_deleteCyclesChar(char ** cycles)849 void RDL_deleteCyclesChar(char **cycles)
850 {
851   unsigned i;
852   for(i=0; cycles[i]!=NULL; ++i)
853   {
854     free(cycles[i]);
855   }
856   free(cycles);
857 }
858 
859 /* public, delete cycle */
RDL_deleteCycle(RDL_cycle * cycle)860 void RDL_deleteCycle(RDL_cycle *cycle)
861 {
862   free(cycle->edges);
863   free(cycle);
864 }
865 
866 /* public, delete cycles */
RDL_deleteCycles(RDL_cycle ** cycles,unsigned number)867 void RDL_deleteCycles(RDL_cycle **cycles, unsigned number)
868 {
869   unsigned i;
870   for(i=0; i<number; ++i)
871   {
872     RDL_deleteCycle(cycles[i]);
873   }
874   free(cycles);
875 }
876 
877 /*
878  * private
879  * Gives all families containing the object, which can be an atom or a bond.
880 mode:
881   - 'a': nodes
882   - 'b': edges
883 returns an array of integers containing all indices of families containing the
884 object. The array ends with a terminating UINT_MAX on its last position and has
885 to be deallocated with 'free()'
886 */
RDL_listFamilies(const RDL_data * data,unsigned object,char mode,char family)887 static unsigned *RDL_listFamilies(const RDL_data *data, unsigned object,
888     char mode, char family)
889 {
890   unsigned *result;
891   unsigned nof_families;
892   unsigned nextfree=0, alloced=RDL_RESERVED_START;
893   unsigned *objects;
894   unsigned i,j, bcc_index, target_bcc, urf_index;
895   char contained, can_be_contained;
896 
897   if(!(mode == 'a' || mode == 'b'))
898   {
899     RDL_outputFunc(RDL_ERROR, "tried to call 'RDL_listFamilies()' with invalid mode '%c'\n",mode);
900     /* cannot occur when using interface */
901     assert(0);
902     return NULL;
903   }
904 
905   unsigned* (*giveFamily) (const RDL_data*, unsigned, char) = NULL;
906 
907   if (family == 'u') {
908     nof_families = data->nofURFs;
909     giveFamily = RDL_giveURF;
910   }
911   else if (family == 'r') {
912     nof_families = data->nofRCFs;
913     giveFamily = RDL_giveRCF;
914   }
915   else {
916     RDL_outputFunc(RDL_ERROR, "tried to call 'RDL_listFamilies()' with invalid family '%c'\n",family);
917     /* cannot occur when using interface */
918     assert(0);
919     return NULL;
920   }
921 
922   result=malloc(alloced * sizeof(*result));
923   for(i = 0; i < nof_families; ++i)
924   {
925     if (family == 'u') {
926       urf_index = i;
927     }
928     else if (family == 'r') {
929       urf_index = data->rcf_to_urf[i][0];
930     }
931 
932     bcc_index = data->urf_to_bcc[urf_index][0];
933 
934     /*
935      * check if object belongs to this BCC at all,
936      * if not it can't be in the URF either
937      */
938     can_be_contained = 0;
939     if (mode == 'a') {
940       for (j = 0; j < data->bccGraphs->nof_bcc_per_node[object]; ++j) {
941         target_bcc = data->bccGraphs->node_to_bcc_mapping[object][2*j];
942         if (target_bcc == bcc_index) {
943           can_be_contained = 1;
944           break;
945         }
946       }
947     }
948     else {
949       target_bcc = data->bccGraphs->edge_to_bcc_mapping[object][0];
950       if (target_bcc == bcc_index) {
951         can_be_contained = 1;
952       }
953     }
954 
955     contained = 0;
956     if (can_be_contained) {
957       objects = giveFamily(data, i, mode);
958       for(j=0; objects[j]<UINT_MAX; ++j)
959       {
960         if(objects[j] == object)
961         {
962           contained = 1;
963           break;
964         }
965       }
966       free(objects);
967     }
968     if (contained) {
969       if(nextfree == alloced) {
970         alloced *= 2;
971         result = realloc(result, alloced*sizeof(*result));
972       }
973       result[nextfree++] = i;
974     }
975   }
976 
977   result = realloc(result, (nextfree+1)*sizeof(*result));
978   result[nextfree] = UINT_MAX;
979   return result;
980 }
981 
982 /* private, get families containing a node */
RDL_getFamiliesContainingNode_internal(const RDL_data * data,RDL_node object,unsigned ** ptr,char family)983 static unsigned RDL_getFamiliesContainingNode_internal(
984     const RDL_data *data, RDL_node object, unsigned **ptr,
985     char family)
986 {
987   unsigned i;
988 
989   if (!data) {
990     RDL_outputFunc(RDL_ERROR, "RDL_data is NULL!\n");
991     (*ptr) = malloc(sizeof(**ptr));
992     return RDL_INVALID_RESULT;
993   }
994 
995   if (object >= data->graph->V) {
996     RDL_outputFunc(RDL_ERROR, "invalid node: %u\n", object);
997     (*ptr) = malloc(sizeof(**ptr));
998     return RDL_INVALID_RESULT;
999   }
1000 
1001   if (data->nofURFs < 1) {
1002     (*ptr) = malloc(sizeof(**ptr));
1003     return 0;
1004   }
1005 
1006   *ptr = RDL_listFamilies(data, object, 'a', family);
1007   for(i=0; (*ptr)[i]<UINT_MAX; ++i);
1008   return i;
1009 }
1010 
1011 /* public, get the RCF indices with this node */
RDL_getRCFsContainingNode(const RDL_data * data,RDL_node object,unsigned ** ptr)1012 unsigned RDL_getRCFsContainingNode(const RDL_data *data, RDL_node object,
1013                                    unsigned **ptr)
1014 {
1015   return RDL_getFamiliesContainingNode_internal(data, object, ptr, 'r');
1016 }
1017 
1018 /* public, get the URF indices with this node */
RDL_getURFsContainingNode(const RDL_data * data,RDL_node object,unsigned ** ptr)1019 unsigned RDL_getURFsContainingNode(const RDL_data *data, RDL_node object,
1020                                    unsigned **ptr)
1021 {
1022   return RDL_getFamiliesContainingNode_internal(data, object, ptr, 'u');
1023 }
1024 
1025 /* private, get the family indices with this edge */
RDL_getFamiliesContainingEdge_internal(const RDL_data * data,RDL_node node1,RDL_node node2,unsigned ** ptr,char family)1026 static unsigned RDL_getFamiliesContainingEdge_internal(
1027     const RDL_data *data, RDL_node node1, RDL_node node2, unsigned **ptr,
1028     char family)
1029 {
1030   unsigned i, edge;
1031 
1032   if (!data) {
1033     RDL_outputFunc(RDL_ERROR, "RDL_data is NULL!\n");
1034     (*ptr) = malloc(sizeof(**ptr));
1035     return RDL_INVALID_RESULT;
1036   }
1037 
1038   if (node1 >= data->graph->V || node2 >= data->graph->V) {
1039     RDL_outputFunc(RDL_ERROR, "invalid edge: %u %u\n", node1, node2);
1040     (*ptr) = malloc(sizeof(**ptr));
1041     return RDL_INVALID_RESULT;
1042   }
1043 
1044   edge = RDL_edgeId(data->graph, node1, node2);
1045 
1046   /* check if this edge exists at all */
1047   if (edge == RDL_INVALID_RESULT) {
1048     RDL_outputFunc(RDL_ERROR, "invalid edge: %u %u\n", node1, node2);
1049     (*ptr) = malloc(sizeof(**ptr));
1050     return RDL_INVALID_RESULT;
1051   }
1052 
1053   if (data->nofURFs < 1) {
1054     (*ptr) = malloc(sizeof(**ptr));
1055     return 0;
1056   }
1057 
1058   *ptr = RDL_listFamilies(data, edge, 'b', family);
1059   for(i=0; (*ptr)[i]<UINT_MAX; ++i);
1060   return i;
1061 }
1062 
1063 
1064 /* public, get the RCF indices with this edge */
RDL_getRCFsContainingEdge(const RDL_data * data,RDL_node node1,RDL_node node2,unsigned ** ptr)1065 unsigned RDL_getRCFsContainingEdge(const RDL_data *data, RDL_node node1,
1066                                    RDL_node node2, unsigned **ptr)
1067 {
1068   return RDL_getFamiliesContainingEdge_internal(data, node1, node2, ptr, 'r');
1069 }
1070 
1071 /* public, get the URF indices with this edge */
RDL_getURFsContainingEdge(const RDL_data * data,RDL_node node1,RDL_node node2,unsigned ** ptr)1072 unsigned RDL_getURFsContainingEdge(const RDL_data *data, RDL_node node1,
1073                                    RDL_node node2, unsigned **ptr)
1074 {
1075   return RDL_getFamiliesContainingEdge_internal(data, node1, node2, ptr, 'u');
1076 }
1077 
1078 /* public, get the number of URFs that this node is part of */
RDL_getNofURFContainingNode(const RDL_data * data,RDL_node node)1079 unsigned RDL_getNofURFContainingNode(const RDL_data *data, RDL_node node)
1080 {
1081   unsigned number;
1082   unsigned *arr;
1083   number = RDL_getURFsContainingNode(data, node, &arr);
1084   free(arr);
1085   return number;
1086 }
1087 
1088 /* public, get the number of URFs that this edge is part of */
RDL_getNofURFContainingEdge(const RDL_data * data,RDL_node node1,RDL_node node2)1089 unsigned RDL_getNofURFContainingEdge(const RDL_data *data, RDL_node node1, RDL_node node2)
1090 {
1091   unsigned number;
1092   unsigned *arr;
1093   number = RDL_getURFsContainingEdge(data, node1, node2, &arr);
1094   free(arr);
1095   return number;
1096 }
1097 
1098 /* public, get the number of RCFs that this node is part of */
RDL_getNofRCFContainingNode(const RDL_data * data,RDL_node node)1099 unsigned RDL_getNofRCFContainingNode(const RDL_data *data, RDL_node node)
1100 {
1101   unsigned number;
1102   unsigned *arr;
1103   number = RDL_getRCFsContainingNode(data, node, &arr);
1104   free(arr);
1105   return number;
1106 }
1107 
1108 /* public, get the number of RCFs that this edge is part of */
RDL_getNofRCFContainingEdge(const RDL_data * data,RDL_node node1,RDL_node node2)1109 unsigned RDL_getNofRCFContainingEdge(const RDL_data *data, RDL_node node1, RDL_node node2)
1110 {
1111   unsigned number;
1112   unsigned *arr;
1113   number = RDL_getRCFsContainingEdge(data, node1, node2, &arr);
1114   free(arr);
1115   return number;
1116 }
1117 
1118 /* construct a SSSR */
RDL_getSSSR(const RDL_data * data,RDL_cycle *** ptr)1119 unsigned RDL_getSSSR(const RDL_data *data, RDL_cycle ***ptr)
1120 {
1121   unsigned j, k, rcf=0, urf=0;
1122   RDL_cycle **result;
1123   unsigned size, added, currBond;
1124   unsigned bcc_index, internal_index;
1125   char* prototype;
1126   const RDL_graph* curr_graph;
1127   unsigned total_counter, alloced;
1128   unsigned edge;
1129   unsigned char *currentCycle;
1130   unsigned char **basisCycles;
1131   unsigned char **prototypesForGaussian;
1132   unsigned currentBasisCyclesSize;
1133   unsigned oldBasisCyclesSize;
1134   unsigned compressedSize = 0;
1135   const unsigned char* empty_cycle;
1136 
1137 
1138   if (!data) {
1139     RDL_outputFunc(RDL_ERROR, "RDL_data is NULL!\n");
1140     (*ptr) = malloc(sizeof(**ptr));
1141     return RDL_INVALID_RESULT;
1142   }
1143 
1144   if (data->nofURFs < 1) {
1145     (*ptr) = malloc(sizeof(**ptr));
1146     return 0;
1147   }
1148 
1149   total_counter = 0;
1150   if (data->graph->E < data->graph->V) {
1151     /*
1152      * if E - V + 1 < 1  <=> E - V < 0 <=> E < V
1153      *
1154      * graph is not connected and our heuristic for reservation
1155      * fails => allocate something ;)
1156      * */
1157     alloced = RDL_RESERVED_START;
1158   }
1159   else {
1160     alloced = data->graph->E - data->graph->V + 1;
1161   }
1162   result = malloc(alloced * sizeof(*result));
1163 
1164   /* calculate basis for each BCC (and therefore for each CC) */
1165 
1166   for (bcc_index = 0; bcc_index < data->bccGraphs->nof_bcc; ++bcc_index) {
1167     curr_graph = data->bccGraphs->bcc_graphs[bcc_index];
1168 
1169     size=curr_graph->E - curr_graph->V + 1;
1170 
1171     basisCycles = malloc(size * sizeof(*basisCycles));
1172     prototypesForGaussian =
1173         malloc(data->nofURFsPerBCC[bcc_index] * sizeof(*prototypesForGaussian));
1174 
1175     /* copy the prototypes for gaussian elimination */
1176     /*
1177      * it is sufficient to take the first prototype for each URF
1178      * (the other's are linearly dependent anyway
1179      */
1180     for (internal_index = 0;
1181         internal_index < data->nofURFsPerBCC[bcc_index]; ++internal_index) {
1182       compressedSize = RDL_bitset_compressed(&(prototypesForGaussian[internal_index]),
1183           data->urfInfoPerBCC[bcc_index]->URFs[internal_index][0]->prototype,
1184           curr_graph->E);
1185     }
1186 
1187     empty_cycle = malloc(compressedSize * sizeof(*empty_cycle));
1188     memset((unsigned char*)empty_cycle, 0, compressedSize * sizeof(*empty_cycle));
1189 
1190     added = 0;
1191     currentBasisCyclesSize = 0;
1192 
1193     for (internal_index = 0;
1194         internal_index < data->nofURFsPerBCC[bcc_index]; ++internal_index, ++urf) {
1195 
1196       currentCycle = malloc(compressedSize * sizeof(*currentCycle));
1197       memcpy(currentCycle, prototypesForGaussian[internal_index],
1198           compressedSize * sizeof(*currentCycle));
1199 
1200       /*
1201        * basisCycles is in row echelon form!result = realloc(result, nextfree * sizeof(*result));
1202        * [this corresponds to "add row operation"]
1203        */
1204       for (k = 0; k < currentBasisCyclesSize; ++k) {
1205         if (RDL_bitset_test(currentCycle, k)) {
1206           RDL_bitset_xor_inplace(currentCycle, basisCycles[k], compressedSize);
1207         }
1208       }
1209 
1210       if (RDL_bitset_empty(currentCycle, empty_cycle, compressedSize)) {
1211         free(currentCycle);
1212         continue;
1213       }
1214       /*
1215        * the current cycle is indepedent of equal and smaller
1216        * sized cycles => part of the basis
1217        */
1218       oldBasisCyclesSize = currentBasisCyclesSize;
1219       basisCycles[currentBasisCyclesSize] = currentCycle;
1220       ++currentBasisCyclesSize;
1221 
1222       /*
1223        * this is where the magic is happening: ensure that the basis is
1224        * indeed in row echelon form (we use the property throughout the algorithm)
1225        *
1226        * swap columns such that indeed the current ring with index currentBasisCycleSize-1
1227        * has a 1 at column currentBasisCycleSize-1
1228        * => ROW ECHELON FORM
1229        *
1230        * [this corresponds to the "swap columns operation" of gaussian elimination]
1231        */
1232       if (!RDL_bitset_test(currentCycle, oldBasisCyclesSize)) {
1233         for (k = oldBasisCyclesSize + 1; k < curr_graph->E; ++k) {
1234           if (RDL_bitset_test(currentCycle, k)) {
1235             RDL_swap_columns(basisCycles, currentBasisCyclesSize, oldBasisCyclesSize, k);
1236             RDL_swap_columns(prototypesForGaussian, data->nofURFsPerBCC[bcc_index], oldBasisCyclesSize, k);
1237             break;
1238           }
1239         }
1240       }
1241 
1242       prototype = data->urfInfoPerBCC[bcc_index]->URFs[internal_index][0]->prototype;
1243 
1244       /* can happen for unconnected graphs */
1245       if (total_counter >= alloced) {
1246         alloced *= 2;
1247         result = realloc(result, (alloced) * sizeof(*result));
1248       }
1249 
1250       currBond = 0;
1251       result[total_counter] = malloc(sizeof(**result));
1252       result[total_counter]->edges = malloc(data->urfInfoPerBCC[bcc_index]->URFs[internal_index][0]->weight *
1253                                    sizeof(*(result[total_counter]->edges)));
1254       result[total_counter]->weight = data->urfInfoPerBCC[bcc_index]->URFs[internal_index][0]->weight;
1255       result[total_counter]->urf = urf;
1256       result[total_counter]->rcf = rcf;
1257       for(j=0; j < curr_graph->E; ++j) {
1258         if(prototype[j] == 1) {
1259           edge = data->bccGraphs->edge_from_bcc_mapping[bcc_index][j];
1260           result[total_counter]->edges[currBond][0] = data->graph->edges[edge][0];
1261           result[total_counter]->edges[currBond][1] = data->graph->edges[edge][1];
1262           ++currBond;
1263         }
1264       }
1265 
1266       rcf += data->urfInfoPerBCC[bcc_index]->nofCFsPerURF[internal_index];
1267 
1268       /*if enough inRDL_dependent cycles were found, break out of the loop*/
1269       ++total_counter;
1270       if(++added == size) {
1271         break;
1272       }
1273     }
1274 
1275     for (k = 0; k < currentBasisCyclesSize; ++k) {
1276       free(basisCycles[k]);
1277     }
1278     free(basisCycles);
1279 
1280     for (k = 0; k < data->nofURFsPerBCC[bcc_index]; ++k) {
1281       free(prototypesForGaussian[k]);
1282     }
1283     free(prototypesForGaussian);
1284     free((void*)empty_cycle);
1285   }
1286 
1287   result = realloc(result, total_counter * sizeof(*result));
1288 
1289   (*ptr) = result;
1290   return total_counter;
1291 }
1292 
1293 /* public, get the RCPs */
RDL_getRCPrototypes(const RDL_data * data,RDL_cycle *** ptr)1294 unsigned RDL_getRCPrototypes(const RDL_data *data, RDL_cycle ***ptr)
1295 {
1296   RDL_cycle **result;
1297   unsigned nof_urf;
1298   unsigned nofRel=0, rcf=0;
1299   unsigned currFam=0, currEdge;
1300   unsigned i,j,k;
1301   const char* prototype;
1302   unsigned bcc_index, mapped_edge;
1303 
1304   if (!data) {
1305     RDL_outputFunc(RDL_ERROR, "RDL_data is NULL!\n");
1306     (*ptr) = malloc(sizeof(**ptr));
1307     return RDL_INVALID_RESULT;
1308   }
1309 
1310   if (data->nofURFs < 1) {
1311     (*ptr) = malloc(sizeof(**ptr));
1312     return 0;
1313   }
1314 
1315   for (i = 0; i < data->bccGraphs->nof_bcc; ++i) {
1316     for (j = 0; j < data->nofURFsPerBCC[i]; ++j) {
1317       nofRel += data->urfInfoPerBCC[i]->nofCFsPerURF[j];
1318     }
1319   }
1320 
1321   /*allocate space*/
1322   result = malloc(nofRel * sizeof(*result));
1323 
1324   for (bcc_index = 0; bcc_index < data->bccGraphs->nof_bcc; ++bcc_index) {
1325     nof_urf = data->nofURFsPerBCC[bcc_index];
1326     for (i = 0; i < nof_urf; ++i) {
1327       for (j = 0; j < data->urfInfoPerBCC[bcc_index]->nofCFsPerURF[i]; ++j, ++rcf) {
1328         prototype = data->urfInfoPerBCC[bcc_index]->URFs[i][j]->prototype;
1329         result[currFam] = malloc(sizeof(**result));
1330         result[currFam]->edges = malloc(data->urfInfoPerBCC[bcc_index]->URFs[i][j]->weight *
1331                                   sizeof(*result[currFam]->edges));
1332         result[currFam]->weight = data->urfInfoPerBCC[bcc_index]->URFs[i][j]->weight;
1333         result[currFam]->urf = i;
1334         result[currFam]->rcf = rcf;
1335         currEdge = 0;
1336         for (k = 0; k < data->bccGraphs->bcc_graphs[bcc_index]->E; ++k) {
1337           if (prototype[k] == 1) {
1338             mapped_edge = data->bccGraphs->edge_from_bcc_mapping[bcc_index][k];
1339             result[currFam]->edges[currEdge][0] = data->graph->edges[mapped_edge][0];
1340             result[currFam]->edges[currEdge][1] = data->graph->edges[mapped_edge][1];
1341             ++currEdge;
1342           }
1343         }
1344         ++currFam;
1345       }
1346     }
1347   }
1348 
1349   (*ptr) = result;
1350   return nofRel;
1351 }
1352 
1353 /* public, get an RDL_cycleIterator for RCFs */
RDL_getRCyclesForRCFIterator(const RDL_data * data,unsigned index)1354 RDL_cycleIterator* RDL_getRCyclesForRCFIterator(const RDL_data *data, unsigned index)
1355 {
1356   RDL_cycleIterator* it;
1357   unsigned rcf_internal_index, urf_internal_index, urf_index;
1358   unsigned bcc_index;
1359 
1360   if (!data) {
1361     RDL_outputFunc(RDL_ERROR, "RDL_data is NULL!\n");
1362     return NULL;
1363   }
1364 
1365   if (index >= data->nofRCFs) {
1366     RDL_outputFunc(RDL_ERROR, "invalid index: %u\n", index);
1367     return NULL;
1368   }
1369 
1370   urf_index = data->rcf_to_urf[index][0];
1371   rcf_internal_index = data->rcf_to_urf[index][1];
1372   bcc_index = data->urf_to_bcc[urf_index][0];
1373   urf_internal_index = data->urf_to_bcc[urf_index][1];
1374 
1375   it = RDL_initCycleIterator(RDL_RCF_IT,
1376       rcf_internal_index, rcf_internal_index,
1377       urf_internal_index, urf_internal_index,
1378       bcc_index, bcc_index,
1379       'b', data);
1380 
1381   return it;
1382 }
1383 
1384 /* public, get an RDL_cycleIterator for URFs */
RDL_getRCyclesForURFIterator(const RDL_data * data,unsigned index)1385 RDL_cycleIterator* RDL_getRCyclesForURFIterator(const RDL_data *data, unsigned index)
1386 {
1387   RDL_cycleIterator* it;
1388   unsigned urf_internal_index, bcc_index;
1389 
1390   if (!data) {
1391     RDL_outputFunc(RDL_ERROR, "RDL_data is NULL!\n");
1392     return NULL;
1393   }
1394 
1395   if (index >= data->nofURFs) {
1396     RDL_outputFunc(RDL_ERROR, "invalid index: %u\n", index);
1397     return NULL;
1398   }
1399 
1400   bcc_index = data->urf_to_bcc[index][0];
1401   urf_internal_index = data->urf_to_bcc[index][1];
1402 
1403   it = RDL_initCycleIterator(
1404       RDL_URF_IT,
1405       0, 0,
1406       urf_internal_index, urf_internal_index,
1407       bcc_index, bcc_index,
1408       'b', data);
1409 
1410   return it;
1411 }
1412 
1413 /* public, get an RDL_cycleIterator for all RCs */
RDL_getRCyclesIterator(const RDL_data * data)1414 RDL_cycleIterator* RDL_getRCyclesIterator(const RDL_data *data)
1415 {
1416   RDL_cycleIterator* it;
1417 
1418   if (!data) {
1419     RDL_outputFunc(RDL_ERROR, "RDL_data is NULL!\n");
1420     return NULL;
1421   }
1422 
1423   it = RDL_initCycleIterator(
1424       RDL_ALL_IT,
1425       0, 0,
1426       0, 0,
1427       0, data->bccGraphs->nof_bcc-1,
1428       'b', data);
1429 
1430   return it;
1431 }
1432 
1433 /* private, get RCs from an RDL_cycleIterator */
RDL_getRCycles_internal(const RDL_data * data,RDL_cycle *** ptr,RDL_cycleIterator * it)1434 static unsigned RDL_getRCycles_internal(
1435     const RDL_data *data, RDL_cycle ***ptr, RDL_cycleIterator* it)
1436 {
1437   RDL_cycle **result;
1438   unsigned alloced, nextfree;
1439 
1440   alloced = RDL_RESERVED_START;
1441   nextfree = 0;
1442   result = malloc(alloced * sizeof(*result));
1443 
1444   while (!RDL_cycleIteratorAtEnd(it)) {
1445     if(nextfree == alloced) {
1446       alloced *= 2;
1447       result = realloc(result, alloced * sizeof(*result));
1448     }
1449     result[nextfree] = RDL_cycleIteratorGetCycle(it);
1450     ++nextfree;
1451 
1452     RDL_cycleIteratorNext(it);
1453   }
1454   RDL_deleteCycleIterator(it);
1455 
1456   result = realloc(result, nextfree * sizeof(*result));
1457 
1458   *ptr = result;
1459   return nextfree;
1460 }
1461 
1462 /* public, get all RCs */
RDL_getRCycles(const RDL_data * data,RDL_cycle *** ptr)1463 unsigned RDL_getRCycles(const RDL_data *data, RDL_cycle ***ptr)
1464 {
1465   RDL_cycleIterator* it;
1466 
1467   it = RDL_getRCyclesIterator(data);
1468 
1469   if (it == NULL) {
1470     RDL_outputFunc(RDL_ERROR, "Iterator is NULL!\n");
1471     (*ptr) = malloc(sizeof(**ptr));
1472     return RDL_INVALID_RESULT;
1473   }
1474 
1475   return RDL_getRCycles_internal(data, ptr, it);
1476 }
1477 
1478 /* public, get all RCs for given URF */
RDL_getRCyclesForURF(const RDL_data * data,unsigned index,RDL_cycle *** ptr)1479 unsigned RDL_getRCyclesForURF(const RDL_data *data, unsigned index, RDL_cycle ***ptr)
1480 {
1481   RDL_cycleIterator* it;
1482 
1483   it = RDL_getRCyclesForURFIterator(data, index);
1484 
1485   if (it == NULL) {
1486     RDL_outputFunc(RDL_ERROR, "Iterator is NULL!\n");
1487     (*ptr) = malloc(sizeof(**ptr));
1488     return RDL_INVALID_RESULT;
1489   }
1490 
1491   return RDL_getRCycles_internal(data, ptr, it);
1492 }
1493 
1494 /* public, get all RCs for given RCF */
RDL_getRCyclesForRCF(const RDL_data * data,unsigned index,RDL_cycle *** ptr)1495 unsigned RDL_getRCyclesForRCF(const RDL_data *data, unsigned index, RDL_cycle ***ptr)
1496 {
1497   RDL_cycleIterator* it;
1498 
1499   it = RDL_getRCyclesForRCFIterator(data, index);
1500 
1501   if (it == NULL) {
1502     RDL_outputFunc(RDL_ERROR, "Iterator is NULL!\n");
1503     (*ptr) = malloc(sizeof(**ptr));
1504     return RDL_INVALID_RESULT;
1505   }
1506 
1507   return RDL_getRCycles_internal(data, ptr, it);
1508 }
1509 
1510 /* public, utils function for converting cycle to bitset representation */
RDL_translateCycArray(const RDL_data * data,RDL_cycle ** array,unsigned number,char *** ptr)1511 unsigned RDL_translateCycArray(const RDL_data *data, RDL_cycle **array,
1512                                unsigned number, char ***ptr)
1513 {
1514   unsigned i,j,RDL_edgeIdx;
1515   char **result;
1516 
1517   if (!data) {
1518     RDL_outputFunc(RDL_ERROR, "RDL_data is NULL!\n");
1519     (*ptr) = RDL_alloc2DCharArray(0, 0);
1520     return RDL_INVALID_RESULT;
1521   }
1522 
1523   if (number < 1) {
1524     (*ptr) = RDL_alloc2DCharArray(0, 0);
1525     return 0;
1526   }
1527 
1528   result = RDL_alloc2DCharArray(number, data->graph->E);
1529   for(i=0; i<number;  ++i)/*initialize to 0s*/
1530   {
1531     for(j=0; j<data->graph->E; ++j)
1532     {
1533       result[i][j] = 0;
1534     }
1535   }
1536 
1537   for(i=0; i<number; ++i)
1538   {
1539     for(j=0; j<array[i]->weight; ++j)
1540     {
1541       RDL_edgeIdx = RDL_edgeId(data->graph, array[i]->edges[j][0],
1542                                array[i]->edges[j][1]);
1543       result[i][RDL_edgeIdx] = 1;
1544     }
1545   }
1546   (*ptr) = result;
1547   return number;
1548 }
1549 
1550 /* public, delete an edge array */
RDL_deleteEdgeIdxArray(char ** cycles,unsigned num)1551 void RDL_deleteEdgeIdxArray(char **cycles, unsigned num)
1552 {
1553   RDL_delete2DCharArray(cycles, num);
1554 }
1555 
1556 /* public, get the edges of the graph */
RDL_getEdgeArray(const RDL_data * data,RDL_edge ** ptr)1557 unsigned RDL_getEdgeArray(const RDL_data *data, RDL_edge **ptr)
1558 {
1559   RDL_edge *result;
1560   unsigned idx;
1561 
1562   if (!data) {
1563     RDL_outputFunc(RDL_ERROR, "RDL_data is NULL!\n");
1564     (*ptr) = malloc(sizeof(**ptr));
1565     return RDL_INVALID_RESULT;
1566   }
1567 
1568   result = malloc(data->graph->E * sizeof(*result));
1569   for(idx=0; idx<data->graph->E; ++idx)
1570   {
1571     result[idx][0] = data->graph->edges[idx][0];
1572     result[idx][1] = data->graph->edges[idx][1];
1573   }
1574   (*ptr) = result;
1575   return data->graph->E;
1576 }
1577 
1578 /* public, get the number of edges in the graph */
RDL_getNofEdges(const RDL_data * data)1579 unsigned RDL_getNofEdges(const RDL_data *data)
1580 {
1581   if (!data) {
1582     RDL_outputFunc(RDL_ERROR, "RDL_data is NULL!\n");
1583     return RDL_INVALID_RESULT;
1584   }
1585   return data->graph->E;
1586 }
1587 
1588 /* public, get the number of ringsystems calculated */
RDL_getNofRingsystems(const RDL_data * data)1589 unsigned RDL_getNofRingsystems(const RDL_data* data)
1590 {
1591   if (!data) {
1592     RDL_outputFunc(RDL_ERROR, "RDL_data is NULL!\n");
1593     return RDL_INVALID_RESULT;
1594   }
1595 
1596   return data->bccGraphs->nof_bcc;
1597 }
1598 
1599 /* public, get the number of nodes for the ring sytem */
RDL_getNofNodesForRingsystem(const RDL_data * data,unsigned idx)1600 unsigned RDL_getNofNodesForRingsystem(const RDL_data *data, unsigned idx)
1601 {
1602   if (!data) {
1603     RDL_outputFunc(RDL_ERROR, "RDL_data is NULL!\n");
1604     return RDL_INVALID_RESULT;
1605   }
1606 
1607   if(idx >= data->bccGraphs->nof_bcc) {
1608     RDL_outputFunc(RDL_ERROR, "idx %d is out of range!\n", idx);
1609     return RDL_INVALID_RESULT;
1610   }
1611 
1612   return data->bccGraphs->bcc_graphs[idx]->V;
1613 }
1614 
1615 /* public, get the number of edges for the ring sytem */
RDL_getNofEdgesForRingsystem(const RDL_data * data,unsigned idx)1616 unsigned RDL_getNofEdgesForRingsystem(const RDL_data *data, unsigned idx)
1617 {
1618   if (!data) {
1619     RDL_outputFunc(RDL_ERROR, "RDL_data is NULL!\n");
1620     return RDL_INVALID_RESULT;
1621   }
1622 
1623   if(idx >= data->bccGraphs->nof_bcc) {
1624     RDL_outputFunc(RDL_ERROR, "idx %d is out of range!\n", idx);
1625     return RDL_INVALID_RESULT;
1626   }
1627 
1628   return data->bccGraphs->bcc_graphs[idx]->E;
1629 
1630 }
1631 
1632 /* public, get the edge for the ring sytem */
RDL_getEdgesForRingsystem(const RDL_data * data,unsigned idx,RDL_edge ** edges)1633 unsigned RDL_getEdgesForRingsystem(
1634     const RDL_data *data, unsigned idx, RDL_edge** edges)
1635 {
1636   unsigned i, edge;
1637 
1638   if (!data) {
1639     RDL_outputFunc(RDL_ERROR, "RDL_data is NULL!\n");
1640     (*edges) = malloc(sizeof(**edges));
1641     return RDL_INVALID_RESULT;
1642   }
1643 
1644   if(idx >= data->bccGraphs->nof_bcc) {
1645     RDL_outputFunc(RDL_ERROR, "idx %d is out of range!\n", idx);
1646     (*edges) = malloc(sizeof(**edges));
1647     return RDL_INVALID_RESULT;
1648   }
1649 
1650   (*edges) = malloc(data->bccGraphs->bcc_graphs[idx]->E * sizeof(**edges));
1651 
1652   for (i = 0; i < data->bccGraphs->bcc_graphs[idx]->E; ++i) {
1653     edge = data->bccGraphs->edge_from_bcc_mapping[idx][i];
1654     (*edges)[i][0] = data->graph->edges[edge][0];
1655     (*edges)[i][1] = data->graph->edges[edge][1];
1656   }
1657 
1658   return data->bccGraphs->bcc_graphs[idx]->E;
1659 }
1660 
1661 /* public, get the nodes for the ring sytem */
RDL_getNodesForRingsystem(const RDL_data * data,unsigned idx,RDL_node ** nodes)1662 unsigned RDL_getNodesForRingsystem(
1663     const RDL_data *data, unsigned idx, RDL_node** nodes)
1664 {
1665   unsigned i, node;
1666 
1667   if (!data) {
1668     RDL_outputFunc(RDL_ERROR, "RDL_data is NULL!\n");
1669     (*nodes) = malloc(sizeof(**nodes));
1670     return RDL_INVALID_RESULT;
1671   }
1672 
1673   if(idx >= data->bccGraphs->nof_bcc) {
1674     RDL_outputFunc(RDL_ERROR, "idx %d is out of range!\n", idx);
1675     (*nodes) = malloc(sizeof(**nodes));
1676     return RDL_INVALID_RESULT;
1677   }
1678 
1679   (*nodes) = malloc(data->bccGraphs->bcc_graphs[idx]->V * sizeof(*nodes));
1680 
1681   for (i = 0; i < data->bccGraphs->bcc_graphs[idx]->V; ++i) {
1682     node = data->bccGraphs->node_from_bcc_mapping[idx][i];
1683     (*nodes)[i] = node;
1684   }
1685 
1686   return data->bccGraphs->bcc_graphs[idx]->V;
1687 }
1688 
1689 /* public, get the ringsystem an edge belongs to */
RDL_getRingsystemForEdge(const RDL_data * data,unsigned from,unsigned to)1690 unsigned RDL_getRingsystemForEdge(
1691     const RDL_data* data, unsigned from, unsigned to)
1692 {
1693   unsigned edge;
1694 
1695   edge = RDL_getEdgeId(data, from, to);
1696 
1697   if (edge == RDL_INVALID_RESULT) {
1698     return RDL_INVALID_RESULT;
1699   }
1700 
1701   return data->bccGraphs->edge_to_bcc_mapping[edge][0];
1702 }
1703 
1704 /* public, get the ID of an edge */
RDL_getEdgeId(const RDL_data * data,unsigned from,unsigned to)1705 unsigned RDL_getEdgeId(const RDL_data *data, unsigned from, unsigned to)
1706 {
1707   if (!data) {
1708     RDL_outputFunc(RDL_ERROR, "RDL_data is NULL!\n");
1709     return RDL_INVALID_RESULT;
1710   }
1711 
1712   if (!data->graph) {
1713     RDL_outputFunc(RDL_ERROR, "RDL_graph is NULL!\n");
1714     return RDL_INVALID_RESULT;
1715   }
1716 
1717   if (from >= data->graph->V || to >= data->graph->V) {
1718     RDL_outputFunc(RDL_ERROR, "invalid edge %u %u\n", from, to);
1719     return RDL_INVALID_RESULT;
1720   }
1721 
1722   return RDL_edgeId(data->graph, from, to);
1723 }
1724