cuiksort.c
Go to the documentation of this file.
1 #include "box_list.h"
2 #include "box.h"
3 #include "glr.h"
4 #include "llr.h"
5 #include "defines.h"
6 #include "error.h"
7 #include "filename.h"
8 
9 
10 #include <string.h>
11 #include <stdlib.h>
12 
46 /************************************************************************************/
48 /* Topologies used when sorting boxes */
49 
50 #define RN_TOPOLOGY 0 // Defines Rn topology to be used in graph construction
51 #define TORUS_TOPOLOGY 1 // Defines Torus topology to be used in graph construction
52 
53 /* Ways to traverse a graph*/
54 #define TRAVERSE_DEPTH_FIRST 0 // Traverse the graph in depth-first order
55 #define TRAVERSE_CYCLES 1 // Traverse only the cycles of the graph
56 #define TRAVERSE_WITHOUT_ORDER 2 // Traverse the graph with no specific order
57 
58 /* Tolerance in the box intersection when defining a graph */
59 #define INTERSECT_TOL 1e-3 // Threshold to decide whether two boxes intersect
60 
61 boolean NormalIntervalsIntersect(Tinterval *i1, Tinterval *i2);
62 boolean AngleIntervalsIntersect(Tinterval *i1, Tinterval *i2);
63 boolean BoxesAreNeighboring(Tbox* box1, Tbox* box2, double tolerance, int topology);
64 boolean BoxesIntersect(Tbox* box1, Tbox* box2, double tolerance, int topology);
65 void ConnectFirstBoxInGraphOfBoxes(graph G,double tolerance,int topology);
66 graph GraphOfBoxes(Tlist* boxlist, double tolerance, int topology);
67 status TraverseDepthFirstComponent(graph_vertex root_v, graph_vertex curr_v, Tlist* boxlist);
68 llist TraverseDepthFirstGraphOfBoxes(graph G);
69 llist TraverseCyclesGraphOfBoxes(graph G, int nskip);
70 llist TraverseAllNodesWithoutOrder(graph G);
71 llist TraverseGraphOfBoxes(graph G, int traversal_type);
72 void PrintWalk(FILE* f, llist walk, int stepsize);
73 
74 //*******************************************************************************
75 
76 //******************************************************************************
77 // NormalIntervalsIntersect
78 //
79 // Tells whether two "normal" intervals intersect. The intervals must have their
80 // lower limit below their upper limit.
81 //******************************************************************************
82 boolean NormalIntervalsIntersect(Tinterval *i1, Tinterval *i2)
83 {
84  return(Intersect(i1,i2));
85 }
86 
87 //******************************************************************************
88 // AngleIntervalsIntersect
89 //
90 // Tells whether two angle intervals intersect. The intervals must be in the
91 // range [0,2pi]. Intervals with lower limit > upper limit are allowed, provided
92 // the limits are within the [0,2pi] range.
93 //******************************************************************************
94 boolean AngleIntervalsIntersect(Tinterval *i1, Tinterval *i2)
95 {
96  double i1l, i1u, i2l, i2u;
97  Tinterval a, b, c, d;
98 
99  // Interval limits
100  i1l = i1->lower_limit; i1u = i1->upper_limit;
101  i2l = i2->lower_limit; i2u = i2->upper_limit;
102 
103  // If intervals are "normal" (with lower < upper)...
104  if(i1l <= i1u && i2l <= i2u)
105  {
106  // ... check first whether they are connected through 0 or 2pi
107  if((i1l == 0 && i2u == 2*M_PI) || (i2l == 0 && i1u == 2*M_PI))
108  return(TRUE);
109  // else check intersection in the normal way
110  else
111  return(Intersect(i1,i2));
112  }
113 
114  // If i1 has lower > upper ...
115  if(i1l > i1u)
116  {
117  // ... split i1 into two intervals a and b, and call me again
118  NewInterval(i1l,2*M_PI,&a);
119  NewInterval(0,i1u,&b);
120  return(AngleIntervalsIntersect(&a,i2) || AngleIntervalsIntersect(&b,i2));
121  }
122 
123  // If i2 has lower > upper ...
124  if(i2l > i2u)
125  {
126  // ... split i2 into two intervals c and d, and call me again
127  NewInterval(i2l,2*M_PI,&c);
128  NewInterval(0,i2u,&d);
129  return(AngleIntervalsIntersect(i1,&c) || AngleIntervalsIntersect(i1,&d));
130  }
131 
132  return(FALSE);
133 }
134 
135 //******************************************************************************
136 // ConnectFirstBoxInGraphOfBoxes - Connects the first box of a box graph to any
137 // neighboring boxes.
138 //******************************************************************************
139 
140 boolean BoxesAreNeighboring(Tbox* box1, Tbox* box2, double tolerance, int topology)
141 {
142  return(BoxesIntersect(box1,box2,tolerance,topology));
143 }
144 
145 //******************************************************************************
146 // BoxesIntersect - Returns TRUE if the given boxes intersect
147 // Two boxes intersect iff no pair of corresponding intervals are disjoint
148 //******************************************************************************
149 boolean BoxesIntersect(Tbox* box1, Tbox* box2, double tolerance, int topology)
150 {
151  Tinterval* intv1;
152  Tinterval* intv2;
153  unsigned int i, dim;
154  double i1l, i1u, i2l, i2u;
155  boolean intersect;
156 
157  // Get boxes dimension
158  dim = GetBoxNIntervals(box1);
159 
160  // Iterate over all intervals of the boxes
161  intersect=TRUE;
162  for(i=0;((intersect)&&(i<dim));i++)
163  {
164  // Get corresponding intervals
165  intv1 = GetBoxInterval(i,box1);
166  intv2 = GetBoxInterval(i,box2);
167 
168  // Backup interval limits
169  i1l = intv1->lower_limit; i1u = intv1->upper_limit;
170  i2l = intv2->lower_limit; i2u = intv2->upper_limit;
171 
172  // Enlarge intervals a samll amount
173  intv1->lower_limit = intv1->lower_limit - tolerance;
174  intv1->upper_limit = intv1->upper_limit + tolerance;
175  intv2->lower_limit = intv2->lower_limit - tolerance;
176  intv2->upper_limit = intv2->upper_limit + tolerance;
177 
178  // Test intersection
179  switch(topology)
180  {
181  case RN_TOPOLOGY:
182  intersect = NormalIntervalsIntersect(intv1,intv2);
183  break;
184  case TORUS_TOPOLOGY:
185  intersect = AngleIntervalsIntersect(intv1,intv2);
186  break;
187  }
188 
189  // Restore original intervals
190  intv1->lower_limit = i1l; intv1->upper_limit = i1u;
191  intv2->lower_limit = i2l; intv2->upper_limit = i2u;
192  }
193 
194  // If all intervals intersect, the boxes intersect
195  return(intersect);
196 }
197 
198 //******************************************************************************
199 // ConnectFirstBoxInGraphOfBoxes - Connects the first box of a box graph to any
200 // neighboring boxes.
201 //******************************************************************************
202 void ConnectFirstBoxInGraphOfBoxes(graph G,double tolerance,int topology)
203 {
204  llist curr_v;
205  llist first_v;
206  Tbox* first_box;
207  Tbox* curr_box;
208  static int edge_count=1;
209 
210  // Pointer to first vertex and its box
211  first_v = G;
212  if(first_v==NULL)
213  Error("Error: empty graph in ConnectFirstBox");
214 
215  first_box = (Tbox*)SPECIFIC_VERTEX_DATA(first_v);
216 
217  // Iterate from the second to the last vertices (boxes)
218  for(curr_v=NEXT(first_v); curr_v!=NULL; curr_v=NEXT(curr_v))
219  {
220  curr_box = (Tbox*)SPECIFIC_VERTEX_DATA(curr_v);
221  if(BoxesAreNeighboring(first_box,curr_box,tolerance,topology))
222  {
223  add_edge_with_pointers(first_v,curr_v,NULL);
224  printf("Edge added number %d\n", edge_count);
225  edge_count++;
226  }
227  }
228 }
229 
230 graph GraphOfBoxes(Tlist* boxlist, double tolerance, int topology)
231 {
232  graph G;
233  Tbox* curr_box;
234  Titerator iter;
235  int boxnumber;
236 
237  // Initialize graph of boxes
238  if(init_graph(&G)==ERROR)
239  Error("Error:: init_graph() failed in GraphOfBoxes()");
240 
241  // Iterate over the list of boxes
242  InitIterator(&iter,boxlist);
243  First(&iter);
244  boxnumber=1;
245  while(!EndOfList(&iter))
246  {
247  // Get a box from the list
248  curr_box=(Tbox*)GetCurrent(&iter);
249  printf("Adding box %d to the graph\n", boxnumber);
250 
251  // Add it as the first box of the graph
252  if(insert_vertex(&G,boxnumber,(void*)curr_box)==ERROR)
253  Error("Error in Graph of Boxes: couldn't insert vertex");
254 
255  // Connect the box to its neighbouring boxes
256  ConnectFirstBoxInGraphOfBoxes(G,tolerance,topology);
257 
258  // Advance cursors and box number
259  Advance(&iter);
260  boxnumber++;
261  }
262 
263  return(G);
264 }
265 
266 
267 //*******************************************************************************
268 // TraverseDepthFirstComponent
269 // Preconditions: at the top-level call all vertices must be marked as non-visited.
270 //*******************************************************************************
271 
272 status TraverseDepthFirstComponent(graph_vertex root_v,
273  graph_vertex curr_v,
274  Tlist* boxlist)
275 {
276  llist curr_e; // Current edge: an edge emanating from current vertex
277  llist adj_v; // The vertex adjacent to current vertex
278  Tbox* curr_box; // The box stored in current vertex
279 /* static int count = 0; */
280 
281  // protection against the case of NULL pointers
282  if(root_v==NULL || curr_v==NULL)
283  return ERROR;
284 
285 /* // Print the degree */
286 /* if(degree(curr_v)>2) */
287 /* { */
288 /* printf("%d:: degree = %d\n", count, degree(curr_v)); */
289 /* curr_box = (Tbox*)SPECIFIC_VERTEX_DATA(curr_v); */
290 /* PrintBox(stdout,curr_box); */
291 /* } */
292 /* count++; */
293 
294  // mark the current vertex as visited
295  VISITED(curr_v)=TRUE;
296 
297  // store the box in it
298  curr_box = (Tbox*)SPECIFIC_VERTEX_DATA(curr_v);
299  AddLastElement((void*)curr_box,boxlist);
300 
301  // for all neighboring vertices of curr_v ...
302  for(curr_e=EMANATING(curr_v); curr_e!=NULL; curr_e=NEXT(curr_e))
303  {
304  // get pointer to the current adjacent vertex
305  adj_v = VERTEX_POINTER(curr_e);
306 
307  // if adjacent vertex is not yet visited ...
308  if(!VISITED(adj_v))
309  {
310  // visit the vertex and its descendants ...
311  if(TraverseDepthFirstComponent(root_v,adj_v,boxlist)==ERROR)
312  return ERROR;
313  // store the box again upon backtracking
314  // AddLastElement((void*)curr_box,boxlist);
315  }
316  }
317 
318  return OK;
319 }
320 
321 //*******************************************************************************
322 // TraverseAllNodesWithoutOrder
323 //*******************************************************************************
324 
325 llist TraverseAllNodesWithoutOrder(graph G)
326 {
327  llist walk_list; // A list of connected box components
328  graph_vertex curr_v; // Current vertex while searching for connected components
329  Tlist* box_list; // A list of boxes for a walk
330  Tbox* curr_box; // The box stored in current vertex
331 
332  // pertinent protection
333  if(G==NULL)
334  Error("Error in TraverseDepthFirstGraphOfBoxes: empty graph");
335 
336  // Initialize list of walks to be returned
337  if(init_list(&walk_list)==ERROR)
338  Error("Error in TraverseDepthFirstGraphOfBoxes: unable to initialize list");
339 
340  // Traverse the graph
341  NEW(box_list,1,Tlist);
342  InitListOfBoxes(box_list);
343 
344  for(curr_v=G; curr_v!=NULL; curr_v=NEXT(curr_v))
345  {
346  curr_box = (Tbox*)SPECIFIC_VERTEX_DATA(curr_v);
347  AddLastElement((void*)curr_box,box_list);
348  }
349 
350  // Insert list of boxes into walk_list
351  insert(&walk_list,(generic_ptr)box_list);
352 
353  // Return list of walks
354  return(walk_list);
355 }
356 
357 
358 //*******************************************************************************
359 // TraverseDepthFirstGraphOfBoxes
360 //
361 // Traverses all connected components of a graph G, in depth first order. Returns
362 // a list of walks, where wach walk is a depth-first traversal of a connected
363 // component. Each node of this returned list actually points to a list of boxes,
364 // the boxes corresponding to the mentioned walk.
365 //*******************************************************************************
366 
367 llist TraverseDepthFirstGraphOfBoxes(graph G)
368 {
369  llist walk_list; // A list of connected box components
370  graph_vertex curr_v; // Current vertex while searching for connected components
371  Tlist* box_list; // A list of boxes for a walk
372 
373  // pertinent protection
374  if(G==NULL)
375  Error("Error in TraverseDepthFirstGraphOfBoxes: empty graph");
376 
377  // Initialize list of walks to be returned
378  if(init_list(&walk_list)==ERROR)
379  Error("Error in TraverseDepthFirstGraphOfBoxes: unable to initialize list");
380 
381  // Traverse the graph
382  mark_all_unvisited(G);
383  for(curr_v=G; curr_v!=NULL; curr_v=NEXT(curr_v)) {
384  if(!VISITED(curr_v)) {
385  // Traverse the connected component of current vertex, ntimes times
386  NEW(box_list,1,Tlist);
387  InitListOfBoxes(box_list);
388  TraverseDepthFirstComponent(curr_v, curr_v, box_list);
389  insert(&walk_list,(generic_ptr)box_list);
390  }
391  }
392 
393  // Return list of walks
394  return(walk_list);
395 }
396 
397 
398 //*******************************************************************************
399 // TraverseCyclesGraphOfBoxes
400 //
401 // Traverses the cycles of a graph G. Returns a list of cycles. Each node in this
402 // list points to a cycle of boxes.
403 //*******************************************************************************
404 
405 llist TraverseCyclesGraphOfBoxes(graph G, int nskip)
406 {
407  llist components; // List of components of G
408  llist root; // Pointer to a vertex of current component
409  llist cycles; // List of cycles of a component
410  llist walk_list; // List of walks to be returned
411  Tlist* box_list; // The list of boxes of a walk
412  Tbox* curr_box; // The box stored in current vertex
413  llist node_comp; // A node of the lit "components"
414  llist node_cyc; // A node of the list "cycles"
415  llist node_vert; // A node of the list CYC_VERTICES(cycles)
416  int i;
417 
418  // Initialize list of walks to be returned
419  if(init_list(&walk_list)==ERROR)
420  Error("Error in TraverseCyclesGraphOfBoxes: unable to initialize list");
421 
422  // Generate list of connected components
423  init_list(&components);
424  if(connected_components(G,&components)==ERROR)
425  Error("Error in TraverseCyclesGraphOfBoxes: connected_components failed");
426 
427  printf("Generating list of walks. One walk for each cycle of the graph...\n");
428  printf("\tNumber of connected components is %d\n", length(components));
429 
430  // Get the cycles of each connected component
431  for(node_comp=components; node_comp!=NULL; node_comp=NEXT(node_comp))
432  {
433  // Get pointer to current component
434  root = (llist)(DATA(node_comp));
435  printf("\tNew component:\n");
436 
437  // Obtain the cycles of this component
438  init_list(&cycles);
439  if(detect_fundamental_cycles(root, &cycles, NULL)==ERROR)
440  Error("Error in TraverseCyclesGraphOfBoxes: failed to detect fundamental cycles");
441  printf("\t\tNumber of cycles of this component is %d\n", length(cycles));
442 
443  // Generate a walk for each cycle, and add it to the list of walks
444  for(node_cyc = cycles; node_cyc!=NULL; node_cyc=NEXT(node_cyc))
445  {
446  // Generate the list of boxes of this cycle (of type Tlist)
447  NEW(box_list,1,Tlist);
448  InitListOfBoxes(box_list);
449  for(node_vert=CYC_VERTICES(node_cyc); node_vert!=NULL; node_vert=NEXT(node_vert))
450  {
451  // We convert the *list* of vertices to a *Tlist* of boxes
452  // curr_vertex = (graph_vertex)DATA(node_vert);
453  // curr_box = (Tbox*)SPECIFIC_VERTEX_DATA(curr_vertex);
454  curr_box = (Tbox*)SPECIFIC_VERTEX_DATA(node_vert);
455  AddLastElement((void*)curr_box,box_list);
456 
457  // Skip nskip boxes (usefull when clustering exists, e.g. cycloheptane)
458  i=0;
459  while(NEXT(node_vert)!=NULL && i<nskip)
460  {
461  node_vert=NEXT(node_vert);
462  i++;
463  }
464  }
465 
466  // Add the list of boxes as a node of the list of walks (of type list)
467  append(&walk_list,(generic_ptr)box_list);
468  }
469 
470  // Destroy temporary list of cycles
471  destroy_list(&cycles,NULL);
472  }
473 
474  // Destroy dynamic memory
475  destroy_list(&components,NULL);
476 
477  return(walk_list);
478 }
479 
480 //*******************************************************************************
481 // TraverseGraphOfBoxes
482 //
483 // Traverses a graph of boxes. Returns a list of walks. Each
484 // walk is a list of boxes corresponding either to a cycle (when
485 // traversal_type==TRAVERSE_CYCLES) or to a connected component traversed
486 // in a depth-first order (when traversal_type==TRAVERSE_DEPTH_FIRST)
487 //*******************************************************************************
488 
489 llist TraverseGraphOfBoxes(graph G, int traversal_type)
490 {
491  llist walk_list=NULL;
492 
493  // Different traversals are possible
494  switch(traversal_type)
495  {
496  case TRAVERSE_CYCLES:
497  // Returns a list of cycle traversals
498  walk_list = TraverseCyclesGraphOfBoxes(G,0);
499  break;
500  case TRAVERSE_DEPTH_FIRST:
501  // Returns a list of connected component traversals
502  walk_list = TraverseDepthFirstGraphOfBoxes(G);
503  break;
504  case TRAVERSE_WITHOUT_ORDER:
505  // Returns a list of all boxes in the graph, with no specific order
506  walk_list = TraverseAllNodesWithoutOrder(G);
507  break;
508  default:
509  // Detect invalid traversal type
510  Error("Error in TraverseGraphOfBoxes: invalid traversal type");
511  break;
512  }
513 
514  return(walk_list);
515 }
516 
517 //*******************************************************************************
518 // PrintWalk
519 // Prints the boxes of a walk to a file "f".
520 //*******************************************************************************
521 void PrintWalk(FILE* f, llist walk, int stepsize)
522 {
523  Tbox* curr_box;
524  Titerator iter;
525  Tlist* walk_box_list;
526  unsigned int i;
527 
528  // Get the list of boxes of the walk
529  walk_box_list = (Tlist*)DATA(walk);
530 
531  // Iterate over all boxes and print them
532  InitIterator(&iter,walk_box_list);
533  First(&iter);
534  while(!EndOfList(&iter))
535  {
536  // Get current box
537  curr_box = (Tbox *)GetCurrent(&iter);
538 
539  // Print the box
540  PrintBox(f,curr_box);
541 
542  // Forward stepsize elements
543  for(i=0;i<(unsigned int)stepsize;i++)
544  Advance(&iter);
545  }
546 }
576 int main(int argc, char **arg)
577 {
578  if (argc<2)
579  {
580  fprintf(stdout,"Use:\n");
581  fprintf(stdout," cuiksort <basename> <tolerance> <topology> <travmode> <stepsize> \n");
582  fprintf(stdout,"Where:\n");
583  fprintf(stdout," basename : The basename of the *.sol input file\n");
584  fprintf(stdout," tolerance: Tolerance when detecting box intersections\n");
585  fprintf(stdout," topology : May be 'r' (for Rn topology) or 't' (for torus topology)\n");
586  fprintf(stdout," travmode : May be 'd' (depth 1st) or 'c' (for cycles) or 'u' (for unordered)\n");
587  fprintf(stdout," stepsize : Stepsize used when printing the boxes of a walk to a file\n");
588  fprintf(stdout,"Examples:\n");
589  fprintf(stdout," sortboxes ./examples/cyclohexane r d 1\n");
590  fprintf(stdout," sortboxes ./examples/cycloheptane r d 1\n");
591  fprintf(stdout," sortboxes ./examples/cycloctane r d 1\n");
592  }
593  else
594  {
595  char suffix[50];
596  Tlist sol_box_list; // List of solution boxes
597  graph G; // Graph of boxes, made out of sol_box_list
598  llist walk_list; // List of walks, altogether integrating a traversal of G
599  llist curr_walk; // Current walk in the previous list
600  Tlist* walk_box_list; // List of boxes of a walk
601  int traversal_type=0;
602  int walk_number;
603  int topology;
604  double tolerance;
605  FILE *fd;
606  int nisol;
607  graph_vertex curr_v;
608  Tbox* curr_box;
609  int stepsize;
610  Tfilename fsols,fout;
611 
612 
613  if (argc<3)
614  tolerance = INTERSECT_TOL; //default tolerance
615  else
616  {
617  tolerance = atof(arg[2]);
618  // Tolerance can not be negative
619  if (tolerance < 0)
620  tolerance = INTERSECT_TOL;
621  }
622 
623  if (argc<4)
624  topology = RN_TOPOLOGY; //default topology
625  else
626  {
627  // Get topology
628  switch(arg[3][0])
629  {
630  case 'r':
631  topology = RN_TOPOLOGY;
632  printf("Using Rn topology\n");
633  break;
634  case 't':
635  topology = TORUS_TOPOLOGY;
636  printf("Using torus topology\n");
637  break;
638  }
639  }
640 
641  if (argc<5)
642  traversal_type = TRAVERSE_DEPTH_FIRST; // default traverse mode
643  else
644  {
645  // Get traversal type
646  switch(arg[4][0])
647  {
648  case 'd':
649  traversal_type = TRAVERSE_DEPTH_FIRST;
650  printf("Walks in depth-first mode\n");
651  break;
652  case 'c':
653  traversal_type = TRAVERSE_CYCLES;
654  printf("Walks in cycles mode\n");
655  break;
656  case 'u':
657  traversal_type = TRAVERSE_WITHOUT_ORDER;
658  printf("Walks in unordered mode\n");
659  break;
660  default:
661  Error("Unknown traversal mode\n");
662  break;
663  }
664  }
665 
666  if (argc<6)
667  stepsize=1;
668  else
669  {
670  // Get stepsize
671  stepsize = (unsigned int)(atoi(arg[5]));
672  }
673 
674  // Read the list of solution boxes (TRUE avoids reading duplicated variables)
675  CreateFileName(NULL,arg[1],NULL,SOL_EXT,&fsols);
676  ReadListOfBoxes(GetFileFullName(&fsols),&sol_box_list);
677  if(ListSize(&sol_box_list)==0)
678  Error("Couldn't open solutions file\n");
679 
680  // Generate graph of boxes
681  G = GraphOfBoxes(&sol_box_list,tolerance,topology);
682 
683  // Traverse the graph, generating a list of walks
684  walk_list = TraverseGraphOfBoxes(G,traversal_type);
685 
686  // Generate one *.sol file for each walk, excluding one-box walks
687  walk_number=1;
688  for(curr_walk=walk_list; curr_walk!=NULL; curr_walk=NEXT(curr_walk))
689  {
690  // Get list of boxes in current walk
691  walk_box_list = (Tlist*)DATA(curr_walk);
692 
693  if(ListSize(walk_box_list) > 1)
694  {
695  // Open output file
696  sprintf(suffix,"_%d",walk_number);
697  CreateFileName(NULL,arg[1],suffix,SOL_EXT,&fout);
698  printf("Generating %s ...",GetFileFullName(&fout));
699  fd = fopen(GetFileFullName(&fout),"w");
700  if(fd==NULL)
701  Error("Couldn't open output file\n");
702 
703  // Print the walk
704  PrintWalk(fd,curr_walk,stepsize);
705  fclose(fd);
706  printf("done.\n");
707  DeleteFileName(&fout);
708 
709  walk_number++;
710  }
711  }
712 
713  // Generate an extra *.sol with all isolated boxes
714  nisol = 0;
715  CreateFileName(NULL,arg[1],"_isol",SOL_EXT,&fout);
716  fd = fopen(GetFileFullName(&fout),"w");
717  if(fd==NULL)
718  Error("Couldn't open file\n");
719  printf("Generating %s ...",GetFileFullName(&fout));
720  for(curr_v=G; curr_v!=NULL; curr_v = NEXT(curr_v))
721  {
722  if(degree(curr_v)==0)
723  {
724  curr_box = (Tbox*)SPECIFIC_VERTEX_DATA(curr_v);
725  PrintBox(fd,curr_box);
726  nisol ++;
727  }
728  }
729  fclose(fd);
730  printf("done.\n");
731  printf("%d isolated boxes.\n",nisol);
732 
733  DeleteFileName(&fout);
734  DeleteFileName(&fsols);
735  }
736 
737  return(EXIT_SUCCESS);
738 }
739