ABC: A System for Sequential Synthesis and Verification
 
Loading...
Searching...
No Matches
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
62static int opo_no_make_sparse;
63static int opo_repeated;
64static int opo_exact;
65static void minimize();
66
67void phase_assignment(PLA, opo_strategy)
68pPLA PLA;
69int opo_strategy;
70{
71 opo_no_make_sparse = opo_strategy % 2;
72 skip_make_sparse = opo_no_make_sparse;
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 */
100pPLA 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 */
129pcube find_phase(PLA, first_output, phase1)
130pPLA PLA;
131int first_output;
132pcube 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*/
173pcover opo(phase, T, D, R, first_output)
174pcube phase;
175pcover T, D, R;
176int 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
240pset_family opo_recur(T, D, select, offset, first, last)
241pcover T, D;
242pcube select;
243int 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
278pset_family opo_leaf(T, select, out1, out2)
279register pcover T;
280pset select;
281int 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
315pset_family form_cover_table(F, D, select, f, fbar)
316pcover F, D;
317pset select;
318int 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
343pset_family find_covers(F, D, select, n)
344pcover F, D;
345register pset select;
346int 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
417void output_phase_setup(PLA, first_output)
418INOUT pPLA PLA;
419int 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 */
508INOUT 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
541void opoall(PLA, first_output, last_output, opo_strategy)
542pPLA PLA;
543int first_output, last_output;
544int 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
619static void minimize(PLA)
620pPLA 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
#define TRUE
Definition abcBm.c:38
#define FALSE
Definition abcBm.c:37
#define ABC_NAMESPACE_IMPL_START
#define ABC_NAMESPACE_IMPL_END
#define FREE(obj)
Definition avl.h:31
void setdown_cube()
Definition cubestr.c:95
ABC_NAMESPACE_IMPL_START void cube_setup()
Definition cubestr.c:27
pPLA new_PLA()
Definition cvrin.c:648
ABC_NAMESPACE_IMPL_START pcover espresso(pcover F, pcover D1, pcover R)
Definition espresso.c:53
#define pcover
Definition espresso.h:264
pset_family sf_addset()
#define new_cube()
Definition espresso.h:262
char * pc1()
pset_family opo_leaf()
pset_family find_covers()
#define set_save(r)
Definition espresso.h:166
#define PUTSIZE(set, size)
Definition espresso.h:113
struct PLA_t * pPLA
#define is_in_set(set, e)
Definition espresso.h:170
#define set_free(r)
Definition espresso.h:167
void opoall()
pset_family sf_new()
#define foreachi_set(R, i, p)
Definition espresso.h:143
#define set_new(size)
Definition espresso.h:164
#define set_insert(set, e)
Definition espresso.h:172
bool setp_disjoint()
pset_family opo_recur()
pset set_and()
void fatal()
#define print_time(t)
Definition espresso.h:22
pcube * cube2list()
#define set_full(size)
Definition espresso.h:165
#define INOUT
Definition espresso.h:334
void sf_free()
void free_PLA()
#define pcube
Definition espresso.h:261
#define free_cover(r)
Definition espresso.h:266
bool trace
Definition globals.c:36
#define GETSET(family, index)
Definition espresso.h:161
#define REDUND
Definition espresso.h:130
pPLA set_phase()
pset set_diff()
pset_family sf_save()
pcover opo()
#define set_remove(set, e)
Definition espresso.h:171
bool skip_make_sparse
Definition globals.c:28
pset set_fill()
struct set_family * pset_family
#define foreach_set(R, last, p)
Definition espresso.h:135
pset_family unate_compl()
bool summary
Definition globals.c:35
#define SET(set, flag)
Definition espresso.h:122
#define SIZE(set)
Definition espresso.h:112
pcover minimize_exact()
pcube find_phase()
#define INLINEset_and(r, a, b)
Definition espresso.h:202
#define RESET(set, flag)
Definition espresso.h:123
void phase_assignment()
pset_family form_cover_table()
unsigned int * pset
Definition espresso.h:73
pset set_or()
pset_family unate_intersect()
pset_family sf_append()
void output_phase_setup()
bool cdist0()
pset set_copy()
#define free_cubelist(T)
Definition espresso.h:267
pcube * cube1list()
void repeated_phase_assignment()
#define EXEC_S(fct, name, S)
Definition espresso.h:420
#define new_cover(i)
Definition espresso.h:265
pcover complement()
Cube * p
Definition exorList.c:222
#define POW2(x)
Definition opo.c:539
pcover D
Definition espresso.h:316
pcover R
Definition espresso.h:316
pcube phase
Definition espresso.h:319
pcover F
Definition espresso.h:316
Definition exor.h:123
int count
Definition espresso.h:80
pset data
Definition espresso.h:82
#define ptime()
Definition util_old.h:283