abc-master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
opo.c
Go to the documentation of this file.
1 /*
2  * Revision Control Information
3  *
4  * $Source$
5  * $Author$
6  * $Revision$
7  * $Date$
8  *
9  */
10 #include "espresso.h"
11 
13 
14 
15 /*
16  * Phase assignment technique (T. Sasao):
17  *
18  * 1. create a function with 2*m outputs which implements the
19  * original function and its complement for each output
20  *
21  * 2. minimize this function
22  *
23  * 3. choose the minimum number of prime implicants from the
24  * result of step 2 which are needed to realize either a function
25  * or its complement for each output
26  *
27  * Step 3 is performed in a rather crude way -- by simply multiplying
28  * out a large expression of the form:
29  *
30  * I = (ab + cdef)(acd + bgh) ...
31  *
32  * which is a product of m expressions where each expression has two
33  * product terms -- one representing which primes are needed for the
34  * function, and one representing which primes are needed for the
35  * complement. The largest product term resulting shows which primes
36  * to keep to implement one function or the other for each output.
37  * For problems with many outputs, this may grind to a
38  * halt.
39  *
40  * Untried: form complement of I and use unate_complement ...
41  *
42  * I have unsuccessfully tried several modifications to the basic
43  * algorithm. The first is quite simple: use Sasao's technique, but
44  * only commit to a single output at a time (rather than all
45  * outputs). The goal would be that the later minimizations can "take
46  * into account" the partial assignment at each step. This is
47  * expensive (m+1 minimizations rather than 2), and the results are
48  * discouraging.
49  *
50  * The second modification is rather complicated. The result from the
51  * minimization in step 2 is guaranteed to be minimal. Hence, for
52  * each output, the set of primes with a 1 in that output are both
53  * necessary and sufficient to implement the function. Espresso
54  * achieves the minimality using the routine MAKE_SPARSE. The
55  * modification is to prevent MAKE_SPARSE from running. Hence, there
56  * are potentially many subsets of the set of primes with a 1 in a
57  * column which can be used to implement that output. We use
58  * IRREDUNDANT to enumerate all possible subsets and then proceed as
59  * before.
60  */
61 
62 static int opo_no_make_sparse;
63 static int opo_repeated;
64 static int opo_exact;
65 static void minimize();
66 
67 void phase_assignment(PLA, opo_strategy)
68 pPLA PLA;
69 int opo_strategy;
70 {
71  opo_no_make_sparse = opo_strategy % 2;
73  opo_repeated = (opo_strategy / 2) % 2;
74  opo_exact = (opo_strategy / 4) % 2;
75 
76  /* Determine a phase assignment */
77  if (PLA->phase != NULL) {
78  FREE(PLA->phase);
79  }
80 
81  if (opo_repeated) {
82  PLA->phase = set_save(cube.fullset);
84  } else {
85  PLA->phase = find_phase(PLA, 0, (pcube) NULL);
86  }
87 
88  /* Now minimize with this assignment */
90  (void) set_phase(PLA);
91  minimize(PLA);
92 }
93 
94 /*
95  * repeated_phase_assignment -- an alternate strategy which commits
96  * to a single phase assignment a step at a time. Performs m + 1
97  * minimizations !
98  */
100 pPLA PLA;
101 {
102  int i;
103  pcube phase;
104 
105  for(i = 0; i < cube.part_size[cube.output]; i++) {
106 
107  /* Find best assignment for all undecided outputs */
108  phase = find_phase(PLA, i, PLA->phase);
109 
110  /* Commit for only a single output ... */
111  if (! is_in_set(phase, cube.first_part[cube.output] + i)) {
112  set_remove(PLA->phase, cube.first_part[cube.output] + i);
113  }
114 
115  if (trace || summary) {
116  printf("\nOPO loop for output #%d\n", i);
117  printf("PLA->phase is %s\n", pc1(PLA->phase));
118  printf("phase is %s\n", pc1(phase));
119  }
120  set_free(phase);
121  }
122 }
123 
124 
125 /*
126  * find_phase -- find a phase assignment for the PLA for all outputs starting
127  * with output number first_output.
128  */
129 pcube find_phase(PLA, first_output, phase1)
130 pPLA PLA;
131 int first_output;
132 pcube phase1;
133 {
134  pcube phase;
135  pPLA PLA1;
136 
137  phase = set_save(cube.fullset);
138 
139  /* setup the double-phase characteristic function, resize the cube */
140  PLA1 = new_PLA();
141  PLA1->F = sf_save(PLA->F);
142  PLA1->R = sf_save(PLA->R);
143  PLA1->D = sf_save(PLA->D);
144  if (phase1 != NULL) {
145  PLA1->phase = set_save(phase1);
146  (void) set_phase(PLA1);
147  }
148  EXEC_S(output_phase_setup(PLA1, first_output), "OPO-SETUP ", PLA1->F);
149 
150  /* minimize the double-phase function */
151  minimize(PLA1);
152 
153  /* set the proper phases according to what gives a minimum solution */
154  EXEC_S(PLA1->F = opo(phase, PLA1->F, PLA1->D, PLA1->R, first_output),
155  "OPO ", PLA1->F);
156  free_PLA(PLA1);
157 
158  /* set the cube structure to reflect the old size */
159  setdown_cube();
160  cube.part_size[cube.output] -=
161  (cube.part_size[cube.output] - first_output) / 2;
162  cube_setup();
163 
164  return phase;
165 }
166 
167 /*
168  * opo -- multiply the expression out to determine a minimum subset of
169  * primes.
170  */
171 
172 /*ARGSUSED*/
173 pcover opo(phase, T, D, R, first_output)
174 pcube phase;
175 pcover T, D, R;
176 int first_output;
177 {
178  int offset, output, i, last_output, ind;
179  pset pdest, select, p, p1, last, last1, not_covered, tmp;
180  pset_family temp, T1, T2;
181 
182  /* must select all primes for outputs [0 .. first_output-1] */
183  select = set_full(T->count);
184  for(output = 0; output < first_output; output++) {
185  ind = cube.first_part[cube.output] + output;
186  foreachi_set(T, i, p) {
187  if (is_in_set(p, ind)) {
188  set_remove(select, i);
189  }
190  }
191  }
192 
193  /* Recursively perform the intersections */
194  offset = (cube.part_size[cube.output] - first_output) / 2;
195  last_output = first_output + offset - 1;
196  temp = opo_recur(T, D, select, offset, first_output, last_output);
197 
198  /* largest set is on top -- select primes which are inferred from it */
199  pdest = temp->data;
200  T1 = new_cover(T->count);
201  foreachi_set(T, i, p) {
202  if (! is_in_set(pdest, i)) {
203  T1 = sf_addset(T1, p);
204  }
205  }
206 
207  set_free(select);
208  sf_free(temp);
209 
210  /* finding phases is difficult -- see which functions are not covered */
211  T2 = complement(cube1list(T1));
212  not_covered = new_cube();
213  tmp = new_cube();
214  foreach_set(T, last, p) {
215  foreach_set(T2, last1, p1) {
216  if (cdist0(p, p1)) {
217  (void) set_or(not_covered, not_covered, set_and(tmp, p, p1));
218  }
219  }
220  }
221  free_cover(T);
222  free_cover(T2);
223  set_free(tmp);
224 
225  /* Now reflect the phase choice in a single cube */
226  for(output = first_output; output <= last_output; output++) {
227  ind = cube.first_part[cube.output] + output;
228  if (is_in_set(not_covered, ind)) {
229  if (is_in_set(not_covered, ind + offset)) {
230  fatal("error in output phase assignment");
231  } else {
232  set_remove(phase, ind);
233  }
234  }
235  }
236  set_free(not_covered);
237  return T1;
238 }
239 
240 pset_family opo_recur(T, D, select, offset, first, last)
241 pcover T, D;
242 pcube select;
243 int offset, first, last;
244 {
245  static int level = 0;
246  int middle;
247  pset_family sl, sr, temp;
248 
249  level++;
250  if (first == last) {
251 #if 0
252  if (opo_no_make_sparse) {
253  temp = form_cover_table(T, D, select, first, first + offset);
254  } else {
255  temp = opo_leaf(T, select, first, first + offset);
256  }
257 #else
258  temp = opo_leaf(T, select, first, first + offset);
259 #endif
260  } else {
261  middle = (first + last) / 2;
262  sl = opo_recur(T, D, select, offset, first, middle);
263  sr = opo_recur(T, D, select, offset, middle+1, last);
264  temp = unate_intersect(sl, sr, level == 1);
265  if (trace) {
266  printf("# OPO[%d]: %4d = %4d x %4d, time = %s\n", level - 1,
267  temp->count, sl->count, sr->count, print_time(ptime()));
268  (void) fflush(stdout);
269  }
270  free_cover(sl);
271  free_cover(sr);
272  }
273  level--;
274  return temp;
275 }
276 
277 
278 pset_family opo_leaf(T, select, out1, out2)
279 register pcover T;
280 pset select;
281 int out1, out2;
282 {
283  register pset_family temp;
284  register pset p, pdest;
285  register int i;
286 
287  out1 += cube.first_part[cube.output];
288  out2 += cube.first_part[cube.output];
289 
290  /* Allocate space for the result */
291  temp = sf_new(2, T->count);
292 
293  /* Find which primes are needed for the ON-set of this fct */
294  pdest = GETSET(temp, temp->count++);
295  (void) set_copy(pdest, select);
296  foreachi_set(T, i, p) {
297  if (is_in_set(p, out1)) {
298  set_remove(pdest, i);
299  }
300  }
301 
302  /* Find which primes are needed for the OFF-set of this fct */
303  pdest = GETSET(temp, temp->count++);
304  (void) set_copy(pdest, select);
305  foreachi_set(T, i, p) {
306  if (is_in_set(p, out2)) {
307  set_remove(pdest, i);
308  }
309  }
310 
311  return temp;
312 }
313 
314 #if 0
315 pset_family form_cover_table(F, D, select, f, fbar)
316 pcover F, D;
317 pset select;
318 int f, fbar; /* indices of f and fbar in the output part */
319 {
320  register int i;
321  register pcube p;
322  pset_family f_table, fbar_table;
323 
324  /* setup required for fcube_is_covered */
325  Rp_size = F->count;
326  Rp_start = set_new(Rp_size);
327  foreachi_set(F, i, p) {
328  PUTSIZE(p, i);
329  }
330  foreachi_set(D, i, p) {
331  RESET(p, REDUND);
332  }
333 
334  f_table = find_covers(F, D, select, f);
335  fbar_table = find_covers(F, D, select, fbar);
336  f_table = sf_append(f_table, fbar_table);
337 
338  set_free(Rp_start);
339  return f_table;
340 }
341 
342 
343 pset_family find_covers(F, D, select, n)
344 pcover F, D;
345 register pset select;
346 int n;
347 {
348  register pset p, last, new;
349  pcover F1;
350  pcube *Flist;
351  pset_family f_table, table;
352  int i;
353 
354  n += cube.first_part[cube.output];
355 
356  /* save cubes in this output, and remove the output variable */
357  F1 = new_cover(F->count);
358  foreach_set(F, last, p)
359  if (is_in_set(p, n)) {
360  new = GETSET(F1, F1->count++);
361  set_or(new, p, cube.var_mask[cube.output]);
362  PUTSIZE(new, SIZE(p));
363  SET(new, REDUND);
364  }
365 
366  /* Find ways (sop form) to fail to cover output indexed by n */
367  Flist = cube2list(F1, D);
368  table = sf_new(10, Rp_size);
369  foreach_set(F1, last, p) {
370  set_fill(Rp_start, Rp_size);
371  set_remove(Rp_start, SIZE(p));
372  table = sf_append(table, fcube_is_covered(Flist, p));
373  RESET(p, REDUND);
374  }
375  set_fill(Rp_start, Rp_size);
376  foreach_set(table, last, p) {
377  set_diff(p, Rp_start, p);
378  }
379 
380  /* complement this to get possible ways to cover the function */
381  for(i = 0; i < Rp_size; i++) {
382  if (! is_in_set(select, i)) {
383  p = set_new(Rp_size);
384  set_insert(p, i);
385  table = sf_addset(table, p);
386  set_free(p);
387  }
388  }
389  f_table = unate_compl(table);
390 
391  /* what a pain, but we need bitwise complement of this */
392  set_fill(Rp_start, Rp_size);
393  foreach_set(f_table, last, p) {
394  set_diff(p, Rp_start, p);
395  }
396 
397  free_cubelist(Flist);
398  sf_free(F1);
399  return f_table;
400 }
401 #endif
402 
403 /*
404  * Take a PLA (ON-set, OFF-set and DC-set) and create the
405  * "double-phase characteristic function" which is merely a new
406  * function which has twice as many outputs and realizes both the
407  * function and the complement.
408  *
409  * The cube structure is assumed to represent the PLA upon entering.
410  * It will be modified to represent the double-phase function upon
411  * exit.
412  *
413  * Only the outputs numbered starting with "first_output" are
414  * duplicated in the output part
415  */
416 
417 void output_phase_setup(PLA, first_output)
418 INOUT pPLA PLA;
419 int first_output;
420 {
421  pcover F, R, D;
422  pcube mask, mask1, last;
423  int first_part, offset;
424  bool save;
425  register pcube p, pr, pf;
426  register int i, last_part;
427 
428  if (cube.output == -1)
429  fatal("output_phase_setup: must have an output");
430 
431  F = PLA->F;
432  D = PLA->D;
433  R = PLA->R;
434  first_part = cube.first_part[cube.output] + first_output;
435  last_part = cube.last_part[cube.output];
436  offset = cube.part_size[cube.output] - first_output;
437 
438  /* Change the output size, setup the cube structure */
439  setdown_cube();
440  cube.part_size[cube.output] += offset;
441  cube_setup();
442 
443  /* Create a mask to select that part of the cube which isn't changing */
444  mask = set_save(cube.fullset);
445  for(i = first_part; i < cube.size; i++)
446  set_remove(mask, i);
447  mask1 = set_save(mask);
448  for(i = cube.first_part[cube.output]; i < first_part; i++) {
449  set_remove(mask1, i);
450  }
451 
452  PLA->F = new_cover(F->count + R->count);
453  PLA->R = new_cover(F->count + R->count);
454  PLA->D = new_cover(D->count);
455 
456  foreach_set(F, last, p) {
457  pf = GETSET(PLA->F, (PLA->F)->count++);
458  pr = GETSET(PLA->R, (PLA->R)->count++);
459  INLINEset_and(pf, mask, p);
460  INLINEset_and(pr, mask1, p);
461  for(i = first_part; i <= last_part; i++)
462  if (is_in_set(p, i))
463  set_insert(pf, i);
464  save = FALSE;
465  for(i = first_part; i <= last_part; i++)
466  if (is_in_set(p, i))
467  save = TRUE, set_insert(pr, i+offset);
468  if (! save) PLA->R->count--;
469  }
470 
471  foreach_set(R, last, p) {
472  pf = GETSET(PLA->F, (PLA->F)->count++);
473  pr = GETSET(PLA->R, (PLA->R)->count++);
474  INLINEset_and(pf, mask1, p);
475  INLINEset_and(pr, mask, p);
476  save = FALSE;
477  for(i = first_part; i <= last_part; i++)
478  if (is_in_set(p, i))
479  save = TRUE, set_insert(pf, i+offset);
480  if (! save) PLA->F->count--;
481  for(i = first_part; i <= last_part; i++)
482  if (is_in_set(p, i))
483  set_insert(pr, i);
484  }
485 
486  foreach_set(D, last, p) {
487  pf = GETSET(PLA->D, (PLA->D)->count++);
488  INLINEset_and(pf, mask, p);
489  for(i = first_part; i <= last_part; i++)
490  if (is_in_set(p, i)) {
491  set_insert(pf, i);
492  set_insert(pf, i+offset);
493  }
494  }
495 
496  free_cover(F);
497  free_cover(D);
498  free_cover(R);
499  set_free(mask);
500  set_free(mask1);
501 }
502 
503 /*
504  * set_phase -- given a "cube" which describes which phases of the output
505  * are to be implemented, compute the appropriate on-set and off-set
506  */
508 INOUT pPLA PLA;
509 {
510  pcover F1, R1;
511  register pcube last, p, outmask;
512  register pcube temp=cube.temp[0], phase=PLA->phase, phase1=cube.temp[1];
513 
514  outmask = cube.var_mask[cube.num_vars - 1];
515  set_diff(phase1, outmask, phase);
516  set_or(phase1, set_diff(temp, cube.fullset, outmask), phase1);
517  F1 = new_cover((PLA->F)->count + (PLA->R)->count);
518  R1 = new_cover((PLA->F)->count + (PLA->R)->count);
519 
520  foreach_set(PLA->F, last, p) {
521  if (! setp_disjoint(set_and(temp, p, phase), outmask))
522  set_copy(GETSET(F1, F1->count++), temp);
523  if (! setp_disjoint(set_and(temp, p, phase1), outmask))
524  set_copy(GETSET(R1, R1->count++), temp);
525  }
526  foreach_set(PLA->R, last, p) {
527  if (! setp_disjoint(set_and(temp, p, phase), outmask))
528  set_copy(GETSET(R1, R1->count++), temp);
529  if (! setp_disjoint(set_and(temp, p, phase1), outmask))
530  set_copy(GETSET(F1, F1->count++), temp);
531  }
532  free_cover(PLA->F);
533  free_cover(PLA->R);
534  PLA->F = F1;
535  PLA->R = R1;
536  return PLA;
537 }
538 
539 #define POW2(x) (1 << (x))
540 
541 void opoall(PLA, first_output, last_output, opo_strategy)
542 pPLA PLA;
543 int first_output, last_output;
544 int opo_strategy;
545 {
546  pcover F, D, R, best_F, best_D, best_R;
547  int i, j, ind, num;
548  pcube bestphase;
549 
550  opo_exact = opo_strategy;
551 
552  if (PLA->phase != NULL) {
553  set_free(PLA->phase);
554  }
555 
556  bestphase = set_save(cube.fullset);
557  best_F = sf_save(PLA->F);
558  best_D = sf_save(PLA->D);
559  best_R = sf_save(PLA->R);
560 
561  for(i = 0; i < POW2(last_output - first_output + 1); i++) {
562 
563  /* save the initial PLA covers */
564  F = sf_save(PLA->F);
565  D = sf_save(PLA->D);
566  R = sf_save(PLA->R);
567 
568  /* compute the phase cube for this iteration */
569  PLA->phase = set_save(cube.fullset);
570  num = i;
571  for(j = last_output; j >= first_output; j--) {
572  if (num % 2 == 0) {
573  ind = cube.first_part[cube.output] + j;
574  set_remove(PLA->phase, ind);
575  }
576  num /= 2;
577  }
578 
579  /* set the phase and minimize */
580  (void) set_phase(PLA);
581  printf("# phase is %s\n", pc1(PLA->phase));
582  summary = TRUE;
583  minimize(PLA);
584 
585  /* see if this is the best so far */
586  if (PLA->F->count < best_F->count) {
587  /* save new best solution */
588  set_copy(bestphase, PLA->phase);
589  sf_free(best_F);
590  sf_free(best_D);
591  sf_free(best_R);
592  best_F = PLA->F;
593  best_D = PLA->D;
594  best_R = PLA->R;
595  } else {
596  /* throw away the solution */
597  free_cover(PLA->F);
598  free_cover(PLA->D);
599  free_cover(PLA->R);
600  }
601  set_free(PLA->phase);
602 
603  /* restore the initial PLA covers */
604  PLA->F = F;
605  PLA->D = D;
606  PLA->R = R;
607  }
608 
609  /* one more minimization to restore the best answer */
610  PLA->phase = bestphase;
611  sf_free(PLA->F);
612  sf_free(PLA->D);
613  sf_free(PLA->R);
614  PLA->F = best_F;
615  PLA->D = best_D;
616  PLA->R = best_R;
617 }
618 
619 static void minimize(PLA)
620 pPLA PLA;
621 {
622  if (opo_exact) {
623  EXEC_S(PLA->F = minimize_exact(PLA->F,PLA->D,PLA->R,1), "EXACT", PLA->F);
624  } else {
625  EXEC_S(PLA->F = espresso(PLA->F, PLA->D, PLA->R), "ESPRESSO ",PLA->F);
626  }
627 }
629 
static ABC_NAMESPACE_IMPL_START void fcube_is_covered()
pset_family opo_recur(pcover T, pcover D, pcube select, int offset, int first, int last)
Definition: opo.c:240
pset set_or()
static void minimize()
void fatal(char *s)
Definition: cvrmisc.c:140
pset_family sf_new()
#define set_free(r)
Definition: espresso.h:167
#define FALSE
Definition: cudd.h:91
ABC_NAMESPACE_IMPL_START pcover espresso(pcover F, pcover D1, pcover R)
Definition: espresso.c:53
#define new_cube()
Definition: espresso.h:262
char * pc1(pcube c)
Definition: cvrout.c:379
static Llb_Mgr_t * p
Definition: llb3Image.c:950
#define free_cover(r)
Definition: espresso.h:266
#define pcover
Definition: espresso.h:264
pset set_copy()
#define set_save(r)
Definition: espresso.h:166
static int opo_repeated
Definition: opo.c:63
pcover opo(pcube phase, pcover T, pcover D, pcover R, int first_output)
Definition: opo.c:173
pset_family form_cover_table()
static ABC_NAMESPACE_IMPL_START int opo_no_make_sparse
Definition: opo.c:62
static int opo_exact
Definition: opo.c:64
#define INLINEset_and(r, a, b)
Definition: espresso.h:202
pset_family find_covers()
bool summary
Definition: globals.c:35
bool trace
Definition: globals.c:36
#define PUTSIZE(set, size)
Definition: espresso.h:113
pset set_and()
ABC_NAMESPACE_IMPL_START void cube_setup()
Definition: cubestr.c:27
int count
Definition: espresso.h:80
void repeated_phase_assignment(pPLA PLA)
Definition: opo.c:99
void sf_free()
void output_phase_setup(INOUT pPLA PLA, int first_output)
Definition: opo.c:417
bool setp_disjoint()
pcover complement(pcube *T)
Definition: compl.c:49
#define SET(set, flag)
Definition: espresso.h:122
#define foreach_set(R, last, p)
Definition: espresso.h:135
#define RESET(set, flag)
Definition: espresso.h:123
#define INOUT
Definition: espresso.h:334
pPLA set_phase(INOUT pPLA PLA)
Definition: opo.c:507
static pcover best_D
Definition: pair.c:371
#define print_time(t)
Definition: espresso.h:22
#define set_full(size)
Definition: espresso.h:165
pset_family sf_addset()
pset set_diff()
void setdown_cube()
Definition: cubestr.c:95
pcube * cube2list(pcover A, pcover B)
Definition: cofactor.c:306
#define EXEC_S(fct, name, S)
Definition: espresso.h:420
#define ABC_NAMESPACE_IMPL_END
Definition: abc_global.h:108
if(last==0)
Definition: sparse_int.h:34
pset_family unate_compl()
#define FREE(obj)
Definition: avl.h:31
#define is_in_set(set, e)
Definition: espresso.h:170
pset_family unate_intersect()
#define new_cover(i)
Definition: espresso.h:265
unsigned int * pset
Definition: espresso.h:73
void phase_assignment(pPLA PLA, int opo_strategy)
Definition: opo.c:67
pcover F
Definition: espresso.h:316
#define ptime()
Definition: util_old.h:283
pset_family opo_leaf(pcover T, pset select, int out1, int out2)
Definition: opo.c:278
pcube find_phase(pPLA PLA, int first_output, pcube phase1)
Definition: opo.c:129
bool skip_make_sparse
Definition: globals.c:28
#define ABC_NAMESPACE_IMPL_START
Definition: abc_global.h:107
#define set_new(size)
Definition: espresso.h:164
pset set_fill()
#define POW2(x)
Definition: opo.c:539
#define set_remove(set, e)
Definition: espresso.h:171
#define TRUE
Definition: cudd.h:88
static pcube phase
Definition: cvrm.c:405
#define free_cubelist(T)
Definition: espresso.h:267
pcube phase
Definition: espresso.h:319
#define set_insert(set, e)
Definition: espresso.h:172
#define GETSET(family, index)
Definition: espresso.h:161
pcover D
Definition: espresso.h:316
pcover R
Definition: espresso.h:316
#define REDUND
Definition: espresso.h:130
void opoall(pPLA PLA, int first_output, int last_output, int opo_strategy)
Definition: opo.c:541
static pcover best_R
Definition: pair.c:371
void free_PLA(pPLA PLA)
Definition: cvrin.c:676
static pcover best_F
Definition: pair.c:371
pPLA new_PLA()
Definition: cvrin.c:648
pset_family sf_append()
pcover minimize_exact()
pset data
Definition: espresso.h:82
bool cdist0()
#define SIZE(set)
Definition: espresso.h:112
#define pcube
Definition: espresso.h:261
#define foreachi_set(R, i, p)
Definition: espresso.h:143
pset_family sf_save()
pcube * cube1list(pcover A)
Definition: cofactor.c:289