source: vis_dev/glu-2.1/src/cuBdd/cuddLinear.c @ 8

Last change on this file since 8 was 8, checked in by cecile, 13 years ago

src glu

File size: 38.1 KB
Line 
1/**CFile***********************************************************************
2
3  FileName    [cuddLinear.c]
4
5  PackageName [cudd]
6
7  Synopsis    [Functions for DD reduction by linear transformations.]
8
9  Description [ Internal procedures included in this module:
10                <ul>
11                <li> cuddLinearAndSifting()
12                <li> cuddLinearInPlace()
13                <li> cuddUpdateInteractionMatrix()
14                <li> cuddInitLinear()
15                <li> cuddResizeLinear()
16                </ul>
17        Static procedures included in this module:
18                <ul>
19                <li> ddLinearUniqueCompare()
20                <li> ddLinearAndSiftingAux()
21                <li> ddLinearAndSiftingUp()
22                <li> ddLinearAndSiftingDown()
23                <li> ddLinearAndSiftingBackward()
24                <li> ddUndoMoves()
25                <li> cuddXorLinear()
26                </ul>]
27
28  Author      [Fabio Somenzi]
29
30  Copyright   [Copyright (c) 1995-2004, Regents of the University of Colorado
31
32  All rights reserved.
33
34  Redistribution and use in source and binary forms, with or without
35  modification, are permitted provided that the following conditions
36  are met:
37
38  Redistributions of source code must retain the above copyright
39  notice, this list of conditions and the following disclaimer.
40
41  Redistributions in binary form must reproduce the above copyright
42  notice, this list of conditions and the following disclaimer in the
43  documentation and/or other materials provided with the distribution.
44
45  Neither the name of the University of Colorado nor the names of its
46  contributors may be used to endorse or promote products derived from
47  this software without specific prior written permission.
48
49  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
50  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
51  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
52  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
53  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
54  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
55  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
56  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
57  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
58  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
59  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
60  POSSIBILITY OF SUCH DAMAGE.]
61
62******************************************************************************/
63
64#include "util.h"
65#include "cuddInt.h"
66
67/*---------------------------------------------------------------------------*/
68/* Constant declarations                                                     */
69/*---------------------------------------------------------------------------*/
70
71#define CUDD_SWAP_MOVE 0
72#define CUDD_LINEAR_TRANSFORM_MOVE 1
73#define CUDD_INVERSE_TRANSFORM_MOVE 2
74#if SIZEOF_LONG == 8
75#define BPL 64
76#define LOGBPL 6
77#else
78#define BPL 32
79#define LOGBPL 5
80#endif
81
82/*---------------------------------------------------------------------------*/
83/* Stucture declarations                                                     */
84/*---------------------------------------------------------------------------*/
85
86/*---------------------------------------------------------------------------*/
87/* Type declarations                                                         */
88/*---------------------------------------------------------------------------*/
89
90/*---------------------------------------------------------------------------*/
91/* Variable declarations                                                     */
92/*---------------------------------------------------------------------------*/
93
94#ifndef lint
95static char rcsid[] DD_UNUSED = "$Id: cuddLinear.c,v 1.26 2004/08/13 18:04:49 fabio Exp $";
96#endif
97
98static  int     *entry;
99
100#ifdef DD_STATS
101extern  int     ddTotalNumberSwapping;
102extern  int     ddTotalNISwaps;
103static  int     ddTotalNumberLinearTr;
104#endif
105
106#ifdef DD_DEBUG
107static  int     zero = 0;
108#endif
109
110/*---------------------------------------------------------------------------*/
111/* Macro declarations                                                        */
112/*---------------------------------------------------------------------------*/
113
114/**AutomaticStart*************************************************************/
115
116/*---------------------------------------------------------------------------*/
117/* Static function prototypes                                                */
118/*---------------------------------------------------------------------------*/
119
120static int ddLinearUniqueCompare (int *ptrX, int *ptrY);
121static int ddLinearAndSiftingAux (DdManager *table, int x, int xLow, int xHigh);
122static Move * ddLinearAndSiftingUp (DdManager *table, int y, int xLow, Move *prevMoves);
123static Move * ddLinearAndSiftingDown (DdManager *table, int x, int xHigh, Move *prevMoves);
124static int ddLinearAndSiftingBackward (DdManager *table, int size, Move *moves);
125static Move* ddUndoMoves (DdManager *table, Move *moves);
126static void cuddXorLinear (DdManager *table, int x, int y);
127
128/**AutomaticEnd***************************************************************/
129
130
131/*---------------------------------------------------------------------------*/
132/* Definition of exported functions                                          */
133/*---------------------------------------------------------------------------*/
134
135
136/**Function********************************************************************
137 
138  Synopsis    [Prints the linear transform matrix.]
139
140  Description [Prints the linear transform matrix. Returns 1 in case of
141  success; 0 otherwise.]
142
143  SideEffects [none]
144
145  SeeAlso     []
146
147******************************************************************************/
148int
149Cudd_PrintLinear(
150  DdManager * table)
151{
152    int i,j,k;
153    int retval;
154    int nvars = table->linearSize;
155    int wordsPerRow = ((nvars - 1) >> LOGBPL) + 1;
156    long word;
157
158    for (i = 0; i < nvars; i++) {
159        for (j = 0; j < wordsPerRow; j++) {
160            word = table->linear[i*wordsPerRow + j];
161            for (k = 0; k < BPL; k++) {
162                retval = fprintf(table->out,"%ld",word & 1);
163                if (retval == 0) return(0);
164                word >>= 1;
165            }
166        }
167        retval = fprintf(table->out,"\n");
168        if (retval == 0) return(0);
169    }
170    return(1);
171
172} /* end of Cudd_PrintLinear */
173
174
175/**Function********************************************************************
176 
177  Synopsis    [Reads an entry of the linear transform matrix.]
178
179  Description [Reads an entry of the linear transform matrix.]
180
181  SideEffects [none]
182
183  SeeAlso     []
184
185******************************************************************************/
186int
187Cudd_ReadLinear(
188  DdManager * table /* CUDD manager */,
189  int  x /* row index */,
190  int  y /* column index */)
191{
192    int nvars = table->size;
193    int wordsPerRow = ((nvars - 1) >> LOGBPL) + 1;
194    long word;
195    int bit;
196    int result;
197
198    assert(table->size == table->linearSize);
199
200    word = wordsPerRow * x + (y >> LOGBPL);
201    bit  = y & (BPL-1);
202    result = (int) ((table->linear[word] >> bit) & 1);
203    return(result);
204
205} /* end of Cudd_ReadLinear */
206
207
208/*---------------------------------------------------------------------------*/
209/* Definition of internal functions                                          */
210/*---------------------------------------------------------------------------*/
211
212
213/**Function********************************************************************
214
215  Synopsis    [BDD reduction based on combination of sifting and linear
216  transformations.]
217
218  Description [BDD reduction based on combination of sifting and linear
219  transformations.  Assumes that no dead nodes are present.
220    <ol>
221    <li> Order all the variables according to the number of entries
222    in each unique table.
223    <li> Sift the variable up and down, remembering each time the
224    total size of the DD heap. At each position, linear transformation
225    of the two adjacent variables is tried and is accepted if it reduces
226    the size of the DD.
227    <li> Select the best permutation.
228    <li> Repeat 3 and 4 for all variables.
229    </ol>
230  Returns 1 if successful; 0 otherwise.]
231
232  SideEffects [None]
233
234******************************************************************************/
235int
236cuddLinearAndSifting(
237  DdManager * table,
238  int  lower,
239  int  upper)
240{
241    int         i;
242    int         *var;
243    int         size;
244    int         x;
245    int         result;
246#ifdef DD_STATS
247    int         previousSize;
248#endif
249
250#ifdef DD_STATS
251    ddTotalNumberLinearTr = 0;
252#endif
253
254    size = table->size;
255
256    var = NULL;
257    entry = NULL;
258    if (table->linear == NULL) {
259        result = cuddInitLinear(table);
260        if (result == 0) goto cuddLinearAndSiftingOutOfMem; 
261#if 0
262        (void) fprintf(table->out,"\n");
263        result = Cudd_PrintLinear(table);
264        if (result == 0) goto cuddLinearAndSiftingOutOfMem;
265#endif
266    } else if (table->size != table->linearSize) {
267        result = cuddResizeLinear(table);
268        if (result == 0) goto cuddLinearAndSiftingOutOfMem; 
269#if 0
270        (void) fprintf(table->out,"\n");
271        result = Cudd_PrintLinear(table);
272        if (result == 0) goto cuddLinearAndSiftingOutOfMem;
273#endif
274    }
275
276    /* Find order in which to sift variables. */
277    entry = ALLOC(int,size);
278    if (entry == NULL) {
279        table->errorCode = CUDD_MEMORY_OUT;
280        goto cuddLinearAndSiftingOutOfMem;
281    }
282    var = ALLOC(int,size);
283    if (var == NULL) {
284        table->errorCode = CUDD_MEMORY_OUT;
285        goto cuddLinearAndSiftingOutOfMem;
286    }
287
288    for (i = 0; i < size; i++) {
289        x = table->perm[i];
290        entry[i] = table->subtables[x].keys;
291        var[i] = i;
292    }
293
294    qsort((void *)var,size,sizeof(int),(DD_QSFP)ddLinearUniqueCompare);
295
296    /* Now sift. */
297    for (i = 0; i < ddMin(table->siftMaxVar,size); i++) {
298        x = table->perm[var[i]];
299        if (x < lower || x > upper) continue;
300#ifdef DD_STATS
301        previousSize = table->keys - table->isolated;
302#endif
303        result = ddLinearAndSiftingAux(table,x,lower,upper);
304        if (!result) goto cuddLinearAndSiftingOutOfMem; 
305#ifdef DD_STATS
306        if (table->keys < (unsigned) previousSize + table->isolated) {
307            (void) fprintf(table->out,"-");
308        } else if (table->keys > (unsigned) previousSize + table->isolated) {
309            (void) fprintf(table->out,"+");     /* should never happen */
310            (void) fprintf(table->out,"\nSize increased from %d to %d while sifting variable %d\n", previousSize, table->keys - table->isolated, var[i]);
311        } else {
312            (void) fprintf(table->out,"=");
313        }
314        fflush(table->out);
315#endif
316#ifdef DD_DEBUG
317        (void) Cudd_DebugCheck(table);
318#endif
319    }
320
321    FREE(var);
322    FREE(entry);
323
324#ifdef DD_STATS
325    (void) fprintf(table->out,"\n#:L_LINSIFT %8d: linear trans.",
326                   ddTotalNumberLinearTr);
327#endif
328
329    return(1);
330
331cuddLinearAndSiftingOutOfMem:
332
333    if (entry != NULL) FREE(entry);
334    if (var != NULL) FREE(var);
335
336    return(0); 
337
338} /* end of cuddLinearAndSifting */
339
340
341/**Function********************************************************************
342 
343  Synopsis    [Linearly combines two adjacent variables.]
344
345  Description [Linearly combines two adjacent variables. Specifically,
346  replaces the top variable with the exclusive nor of the two variables.
347  It assumes that no dead nodes are present on entry to this
348  procedure.  The procedure then guarantees that no dead nodes will be
349  present when it terminates.  cuddLinearInPlace assumes that x &lt;
350  y.  Returns the number of keys in the table if successful; 0
351  otherwise.]
352
353  SideEffects [The two subtables corrresponding to variables x and y are
354  modified. The global counters of the unique table are also affected.]
355
356  SeeAlso     [cuddSwapInPlace]
357
358******************************************************************************/
359int
360cuddLinearInPlace(
361  DdManager * table,
362  int  x,
363  int  y)
364{
365    DdNodePtr *xlist, *ylist;
366    int    xindex, yindex;
367    int    xslots, yslots;
368    int    xshift, yshift;
369    int    oldxkeys, oldykeys;
370    int    newxkeys, newykeys;
371    int    comple, newcomplement;
372    int    i;
373    int    posn;
374    int    isolated;
375    DdNode *f,*f0,*f1,*f01,*f00,*f11,*f10,*newf1,*newf0;
376    DdNode *g,*next,*last;
377    DdNodePtr *previousP;
378    DdNode *tmp;
379    DdNode *sentinel = &(table->sentinel);
380#if DD_DEBUG
381    int    count, idcheck;
382#endif
383
384#ifdef DD_DEBUG
385    assert(x < y);
386    assert(cuddNextHigh(table,x) == y);
387    assert(table->subtables[x].keys != 0);
388    assert(table->subtables[y].keys != 0);
389    assert(table->subtables[x].dead == 0);
390    assert(table->subtables[y].dead == 0);
391#endif
392
393    xindex = table->invperm[x];
394    yindex = table->invperm[y];
395
396    if (cuddTestInteract(table,xindex,yindex)) {
397#ifdef DD_STATS
398        ddTotalNumberLinearTr++;
399#endif
400        /* Get parameters of x subtable. */
401        xlist = table->subtables[x].nodelist; 
402        oldxkeys = table->subtables[x].keys;
403        xslots = table->subtables[x].slots;
404        xshift = table->subtables[x].shift;
405
406        /* Get parameters of y subtable. */
407        ylist = table->subtables[y].nodelist;
408        oldykeys = table->subtables[y].keys;
409        yslots = table->subtables[y].slots;
410        yshift = table->subtables[y].shift;
411
412        newxkeys = 0;
413        newykeys = oldykeys;
414
415        /* Check whether the two projection functions involved in this
416        ** swap are isolated. At the end, we'll be able to tell how many
417        ** isolated projection functions are there by checking only these
418        ** two functions again. This is done to eliminate the isolated
419        ** projection functions from the node count.
420        */
421        isolated = - ((table->vars[xindex]->ref == 1) +
422                     (table->vars[yindex]->ref == 1));
423
424        /* The nodes in the x layer are put in a chain.
425        ** The chain is handled as a FIFO; g points to the beginning and
426        ** last points to the end.
427        */
428        g = NULL;
429        for (i = 0; i < xslots; i++) {
430            f = xlist[i];
431            if (f == sentinel) continue;
432            xlist[i] = sentinel;
433            if (g == NULL) {
434                g = f;
435            } else {
436                last->next = f;
437            }
438            while ((next = f->next) != sentinel) {
439                f = next;
440            } /* while there are elements in the collision chain */
441            last = f;
442        } /* for each slot of the x subtable */
443        last->next = NULL;
444
445#ifdef DD_COUNT
446        table->swapSteps += oldxkeys;
447#endif
448        /* Take care of the x nodes that must be re-expressed.
449        ** They form a linked list pointed by g.
450        */
451        f = g;
452        while (f != NULL) {
453            next = f->next;
454            /* Find f1, f0, f11, f10, f01, f00. */
455            f1 = cuddT(f);
456#ifdef DD_DEBUG
457            assert(!(Cudd_IsComplement(f1)));
458#endif
459            if ((int) f1->index == yindex) {
460                f11 = cuddT(f1); f10 = cuddE(f1);
461            } else {
462                f11 = f10 = f1;
463            }
464#ifdef DD_DEBUG
465            assert(!(Cudd_IsComplement(f11)));
466#endif
467            f0 = cuddE(f);
468            comple = Cudd_IsComplement(f0);
469            f0 = Cudd_Regular(f0);
470            if ((int) f0->index == yindex) {
471                f01 = cuddT(f0); f00 = cuddE(f0);
472            } else {
473                f01 = f00 = f0;
474            }
475            if (comple) {
476                f01 = Cudd_Not(f01);
477                f00 = Cudd_Not(f00);
478            }
479            /* Decrease ref count of f1. */
480            cuddSatDec(f1->ref);
481            /* Create the new T child. */
482            if (f11 == f00) {
483                newf1 = f11;
484                cuddSatInc(newf1->ref);
485            } else {
486                /* Check ylist for triple (yindex,f11,f00). */
487                posn = ddHash(f11, f00, yshift);
488                /* For each element newf1 in collision list ylist[posn]. */
489                previousP = &(ylist[posn]);
490                newf1 = *previousP;
491                while (f11 < cuddT(newf1)) {
492                    previousP = &(newf1->next);
493                    newf1 = *previousP;
494                }
495                while (f11 == cuddT(newf1) && f00 < cuddE(newf1)) {
496                    previousP = &(newf1->next);
497                    newf1 = *previousP;
498                }
499                if (cuddT(newf1) == f11 && cuddE(newf1) == f00) {
500                    cuddSatInc(newf1->ref);
501                } else { /* no match */
502                    newf1 = cuddDynamicAllocNode(table);
503                    if (newf1 == NULL)
504                        goto cuddLinearOutOfMem;
505                    newf1->index = yindex; newf1->ref = 1;
506                    cuddT(newf1) = f11;
507                    cuddE(newf1) = f00;
508                    /* Insert newf1 in the collision list ylist[posn];
509                    ** increase the ref counts of f11 and f00.
510                    */
511                    newykeys++;
512                    newf1->next = *previousP;
513                    *previousP = newf1;
514                    cuddSatInc(f11->ref);
515                    tmp = Cudd_Regular(f00);
516                    cuddSatInc(tmp->ref);
517                }
518            }
519            cuddT(f) = newf1;
520#ifdef DD_DEBUG
521            assert(!(Cudd_IsComplement(newf1)));
522#endif
523
524            /* Do the same for f0, keeping complement dots into account. */
525            /* decrease ref count of f0 */
526            tmp = Cudd_Regular(f0);
527            cuddSatDec(tmp->ref);
528            /* create the new E child */
529            if (f01 == f10) {
530                newf0 = f01;
531                tmp = Cudd_Regular(newf0);
532                cuddSatInc(tmp->ref); 
533            } else {
534                /* make sure f01 is regular */
535                newcomplement = Cudd_IsComplement(f01);
536                if (newcomplement) {
537                    f01 = Cudd_Not(f01);
538                    f10 = Cudd_Not(f10);
539                }
540                /* Check ylist for triple (yindex,f01,f10). */
541                posn = ddHash(f01, f10, yshift);
542                /* For each element newf0 in collision list ylist[posn]. */
543                previousP = &(ylist[posn]);
544                newf0 = *previousP;
545                while (f01 < cuddT(newf0)) {
546                    previousP = &(newf0->next);
547                    newf0 = *previousP;
548                }
549                while (f01 == cuddT(newf0) && f10 < cuddE(newf0)) {
550                    previousP = &(newf0->next);
551                    newf0 = *previousP;
552                }
553                if (cuddT(newf0) == f01 && cuddE(newf0) == f10) {
554                    cuddSatInc(newf0->ref); 
555                } else { /* no match */
556                    newf0 = cuddDynamicAllocNode(table);
557                    if (newf0 == NULL)
558                        goto cuddLinearOutOfMem;
559                    newf0->index = yindex; newf0->ref = 1;
560                    cuddT(newf0) = f01;
561                    cuddE(newf0) = f10;
562                    /* Insert newf0 in the collision list ylist[posn];
563                    ** increase the ref counts of f01 and f10.
564                    */
565                    newykeys++;
566                    newf0->next = *previousP;
567                    *previousP = newf0;
568                    cuddSatInc(f01->ref);
569                    tmp = Cudd_Regular(f10);
570                    cuddSatInc(tmp->ref);
571                }
572                if (newcomplement) {
573                    newf0 = Cudd_Not(newf0);
574                }
575            }
576            cuddE(f) = newf0;
577
578            /* Re-insert the modified f in xlist.
579            ** The modified f does not already exists in xlist.
580            ** (Because of the uniqueness of the cofactors.)
581            */
582            posn = ddHash(newf1, newf0, xshift);
583            newxkeys++;
584            previousP = &(xlist[posn]);
585            tmp = *previousP;
586            while (newf1 < cuddT(tmp)) {
587                previousP = &(tmp->next);
588                tmp = *previousP;
589            }
590            while (newf1 == cuddT(tmp) && newf0 < cuddE(tmp)) {
591                previousP = &(tmp->next);
592                tmp = *previousP;
593            }
594            f->next = *previousP;
595            *previousP = f;
596            f = next;
597        } /* while f != NULL */
598
599        /* GC the y layer. */
600
601        /* For each node f in ylist. */
602        for (i = 0; i < yslots; i++) {
603            previousP = &(ylist[i]);
604            f = *previousP;
605            while (f != sentinel) {
606                next = f->next;
607                if (f->ref == 0) {
608                    tmp = cuddT(f);
609                    cuddSatDec(tmp->ref);
610                    tmp = Cudd_Regular(cuddE(f));
611                    cuddSatDec(tmp->ref);
612                    cuddDeallocNode(table,f);
613                    newykeys--;
614                } else {
615                    *previousP = f;
616                    previousP = &(f->next);
617                }
618                f = next;
619            } /* while f */
620            *previousP = sentinel;
621        } /* for every collision list */
622
623#if DD_DEBUG
624#if 0
625        (void) fprintf(table->out,"Linearly combining %d and %d\n",x,y);
626#endif
627        count = 0;
628        idcheck = 0;
629        for (i = 0; i < yslots; i++) {
630            f = ylist[i];
631            while (f != sentinel) {
632                count++;
633                if (f->index != (DdHalfWord) yindex)
634                    idcheck++;
635                f = f->next;
636            }
637        }
638        if (count != newykeys) {
639            fprintf(table->err,"Error in finding newykeys\toldykeys = %d\tnewykeys = %d\tactual = %d\n",oldykeys,newykeys,count);
640        }
641        if (idcheck != 0)
642            fprintf(table->err,"Error in id's of ylist\twrong id's = %d\n",idcheck);
643        count = 0;
644        idcheck = 0;
645        for (i = 0; i < xslots; i++) {
646            f = xlist[i];
647            while (f != sentinel) {
648                count++;
649                if (f->index != (DdHalfWord) xindex)
650                    idcheck++;
651                f = f->next;
652            }
653        }
654        if (count != newxkeys || newxkeys != oldxkeys) {
655            fprintf(table->err,"Error in finding newxkeys\toldxkeys = %d \tnewxkeys = %d \tactual = %d\n",oldxkeys,newxkeys,count);
656        }
657        if (idcheck != 0)
658            fprintf(table->err,"Error in id's of xlist\twrong id's = %d\n",idcheck);
659#endif
660
661        isolated += (table->vars[xindex]->ref == 1) +
662                    (table->vars[yindex]->ref == 1);
663        table->isolated += isolated;
664
665        /* Set the appropriate fields in table. */
666        table->subtables[y].keys = newykeys;
667
668        /* Here we should update the linear combination table
669        ** to record that x <- x EXNOR y. This is done by complementing
670        ** the (x,y) entry of the table.
671        */
672
673        table->keys += newykeys - oldykeys;
674
675        cuddXorLinear(table,xindex,yindex);
676    }
677
678#ifdef DD_DEBUG
679    if (zero) {
680        (void) Cudd_DebugCheck(table);
681    }
682#endif
683
684    return(table->keys - table->isolated);
685
686cuddLinearOutOfMem:
687    (void) fprintf(table->err,"Error: cuddLinearInPlace out of memory\n");
688
689    return (0);
690
691} /* end of cuddLinearInPlace */
692
693
694/**Function********************************************************************
695 
696  Synopsis    [Updates the interaction matrix.]
697
698  Description []
699
700  SideEffects [none]
701
702  SeeAlso     []
703
704******************************************************************************/
705void
706cuddUpdateInteractionMatrix(
707  DdManager * table,
708  int  xindex,
709  int  yindex)
710{
711    int i;
712    for (i = 0; i < yindex; i++) {
713        if (i != xindex && cuddTestInteract(table,i,yindex)) {
714            if (i < xindex) {
715                cuddSetInteract(table,i,xindex);
716            } else {
717                cuddSetInteract(table,xindex,i);
718            }
719        }
720    }
721    for (i = yindex+1; i < table->size; i++) {
722        if (i != xindex && cuddTestInteract(table,yindex,i)) {
723            if (i < xindex) {
724                cuddSetInteract(table,i,xindex);
725            } else {
726                cuddSetInteract(table,xindex,i);
727            }
728        }
729    }
730
731} /* end of cuddUpdateInteractionMatrix */
732
733
734/**Function********************************************************************
735 
736  Synopsis    [Initializes the linear transform matrix.]
737
738  Description [Initializes the linear transform matrix.  Returns 1 if
739  successful; 0 otherwise.]
740
741  SideEffects [none]
742
743  SeeAlso     []
744
745******************************************************************************/
746int
747cuddInitLinear(
748  DdManager * table)
749{
750    int words;
751    int wordsPerRow;
752    int nvars;
753    int word;
754    int bit;
755    int i;
756    long *linear;
757
758    nvars = table->size;
759    wordsPerRow = ((nvars - 1) >> LOGBPL) + 1;
760    words = wordsPerRow * nvars;
761    table->linear = linear = ALLOC(long,words);
762    if (linear == NULL) {
763        table->errorCode = CUDD_MEMORY_OUT;
764        return(0);
765    }
766    table->memused += words * sizeof(long);
767    table->linearSize = nvars;
768    for (i = 0; i < words; i++) linear[i] = 0;
769    for (i = 0; i < nvars; i++) {
770        word = wordsPerRow * i + (i >> LOGBPL);
771        bit  = i & (BPL-1);
772        linear[word] = 1 << bit;
773    }
774    return(1);
775
776} /* end of cuddInitLinear */
777
778
779/**Function********************************************************************
780 
781  Synopsis    [Resizes the linear transform matrix.]
782
783  Description [Resizes the linear transform matrix.  Returns 1 if
784  successful; 0 otherwise.]
785
786  SideEffects [none]
787
788  SeeAlso     []
789
790******************************************************************************/
791int
792cuddResizeLinear(
793  DdManager * table)
794{
795    int words,oldWords;
796    int wordsPerRow,oldWordsPerRow;
797    int nvars,oldNvars;
798    int word,oldWord;
799    int bit;
800    int i,j;
801    long *linear,*oldLinear;
802
803    oldNvars = table->linearSize;
804    oldWordsPerRow = ((oldNvars - 1) >> LOGBPL) + 1;
805    oldWords = oldWordsPerRow * oldNvars;
806    oldLinear = table->linear;
807
808    nvars = table->size;
809    wordsPerRow = ((nvars - 1) >> LOGBPL) + 1;
810    words = wordsPerRow * nvars;
811    table->linear = linear = ALLOC(long,words);
812    if (linear == NULL) {
813        table->errorCode = CUDD_MEMORY_OUT;
814        return(0);
815    }
816    table->memused += (words - oldWords) * sizeof(long);
817    for (i = 0; i < words; i++) linear[i] = 0;
818
819    /* Copy old matrix. */
820    for (i = 0; i < oldNvars; i++) {
821        for (j = 0; j < oldWordsPerRow; j++) {
822            oldWord = oldWordsPerRow * i + j;
823            word = wordsPerRow * i + j;
824            linear[word] = oldLinear[oldWord];
825        }
826    }
827    FREE(oldLinear);
828
829    /* Add elements to the diagonal. */
830    for (i = oldNvars; i < nvars; i++) {
831        word = wordsPerRow * i + (i >> LOGBPL);
832        bit  = i & (BPL-1);
833        linear[word] = 1 << bit;
834    }
835    table->linearSize = nvars;
836
837    return(1);
838
839} /* end of cuddResizeLinear */
840
841
842/*---------------------------------------------------------------------------*/
843/* Definition of static functions                                            */
844/*---------------------------------------------------------------------------*/
845
846
847/**Function********************************************************************
848
849  Synopsis    [Comparison function used by qsort.]
850
851  Description [Comparison function used by qsort to order the
852  variables according to the number of keys in the subtables.
853  Returns the difference in number of keys between the two
854  variables being compared.]
855
856  SideEffects [None]
857
858******************************************************************************/
859static int
860ddLinearUniqueCompare(
861  int * ptrX,
862  int * ptrY)
863{
864#if 0
865    if (entry[*ptrY] == entry[*ptrX]) {
866        return((*ptrX) - (*ptrY));
867    }
868#endif
869    return(entry[*ptrY] - entry[*ptrX]);
870
871} /* end of ddLinearUniqueCompare */
872
873
874/**Function********************************************************************
875
876  Synopsis    [Given xLow <= x <= xHigh moves x up and down between the
877  boundaries.]
878
879  Description [Given xLow <= x <= xHigh moves x up and down between the
880  boundaries. At each step a linear transformation is tried, and, if it
881  decreases the size of the DD, it is accepted. Finds the best position
882  and does the required changes.  Returns 1 if successful; 0 otherwise.]
883
884  SideEffects [None]
885
886******************************************************************************/
887static int
888ddLinearAndSiftingAux(
889  DdManager * table,
890  int  x,
891  int  xLow,
892  int  xHigh)
893{
894
895    Move        *move;
896    Move        *moveUp;                /* list of up moves */
897    Move        *moveDown;              /* list of down moves */
898    int         initialSize;
899    int         result;
900
901    initialSize = table->keys - table->isolated;
902
903    moveDown = NULL;
904    moveUp = NULL;
905
906    if (x == xLow) {
907        moveDown = ddLinearAndSiftingDown(table,x,xHigh,NULL);
908        /* At this point x --> xHigh unless bounding occurred. */
909        if (moveDown == (Move *) CUDD_OUT_OF_MEM) goto ddLinearAndSiftingAuxOutOfMem;
910        /* Move backward and stop at best position. */ 
911        result = ddLinearAndSiftingBackward(table,initialSize,moveDown);
912        if (!result) goto ddLinearAndSiftingAuxOutOfMem;
913
914    } else if (x == xHigh) {
915        moveUp = ddLinearAndSiftingUp(table,x,xLow,NULL);
916        /* At this point x --> xLow unless bounding occurred. */
917        if (moveUp == (Move *) CUDD_OUT_OF_MEM) goto ddLinearAndSiftingAuxOutOfMem;
918        /* Move backward and stop at best position. */
919        result = ddLinearAndSiftingBackward(table,initialSize,moveUp);
920        if (!result) goto ddLinearAndSiftingAuxOutOfMem;
921
922    } else if ((x - xLow) > (xHigh - x)) { /* must go down first: shorter */
923        moveDown = ddLinearAndSiftingDown(table,x,xHigh,NULL);
924        /* At this point x --> xHigh unless bounding occurred. */
925        if (moveDown == (Move *) CUDD_OUT_OF_MEM) goto ddLinearAndSiftingAuxOutOfMem;
926        moveUp = ddUndoMoves(table,moveDown);
927#ifdef DD_DEBUG
928        assert(moveUp == NULL || moveUp->x == x);
929#endif
930        moveUp = ddLinearAndSiftingUp(table,x,xLow,moveUp);
931        if (moveUp == (Move *) CUDD_OUT_OF_MEM) goto ddLinearAndSiftingAuxOutOfMem;
932        /* Move backward and stop at best position. */ 
933        result = ddLinearAndSiftingBackward(table,initialSize,moveUp);
934        if (!result) goto ddLinearAndSiftingAuxOutOfMem;
935
936    } else { /* must go up first: shorter */
937        moveUp = ddLinearAndSiftingUp(table,x,xLow,NULL);
938        /* At this point x --> xLow unless bounding occurred. */
939        if (moveUp == (Move *) CUDD_OUT_OF_MEM) goto ddLinearAndSiftingAuxOutOfMem;
940        moveDown = ddUndoMoves(table,moveUp);
941#ifdef DD_DEBUG
942        assert(moveDown == NULL || moveDown->y == x);
943#endif
944        moveDown = ddLinearAndSiftingDown(table,x,xHigh,moveDown);
945        if (moveDown == (Move *) CUDD_OUT_OF_MEM) goto ddLinearAndSiftingAuxOutOfMem;
946        /* Move backward and stop at best position. */ 
947        result = ddLinearAndSiftingBackward(table,initialSize,moveDown);
948        if (!result) goto ddLinearAndSiftingAuxOutOfMem;
949    }
950
951    while (moveDown != NULL) {
952        move = moveDown->next;
953        cuddDeallocMove(table, moveDown);
954        moveDown = move;
955    }
956    while (moveUp != NULL) {
957        move = moveUp->next;
958        cuddDeallocMove(table, moveUp);
959        moveUp = move;
960    }
961
962    return(1);
963
964ddLinearAndSiftingAuxOutOfMem:
965    while (moveDown != NULL) {
966        move = moveDown->next;
967        cuddDeallocMove(table, moveDown);
968        moveDown = move;
969    }
970    while (moveUp != NULL) {
971        move = moveUp->next;
972        cuddDeallocMove(table, moveUp);
973        moveUp = move;
974    }
975
976    return(0);
977
978} /* end of ddLinearAndSiftingAux */
979
980
981/**Function********************************************************************
982
983  Synopsis    [Sifts a variable up and applies linear transformations.]
984
985  Description [Sifts a variable up and applies linear transformations.
986  Moves y up until either it reaches the bound (xLow) or the size of
987  the DD heap increases too much.  Returns the set of moves in case of
988  success; NULL if memory is full.]
989
990  SideEffects [None]
991
992******************************************************************************/
993static Move *
994ddLinearAndSiftingUp(
995  DdManager * table,
996  int  y,
997  int  xLow,
998  Move * prevMoves)
999{
1000    Move        *moves;
1001    Move        *move;
1002    int         x;
1003    int         size, newsize;
1004    int         limitSize;
1005    int         xindex, yindex;
1006    int         isolated;
1007    int         L;      /* lower bound on DD size */
1008#ifdef DD_DEBUG
1009    int checkL;
1010    int z;
1011    int zindex;
1012#endif
1013
1014    moves = prevMoves;
1015    yindex = table->invperm[y];
1016
1017    /* Initialize the lower bound.
1018    ** The part of the DD below y will not change.
1019    ** The part of the DD above y that does not interact with y will not
1020    ** change. The rest may vanish in the best case, except for
1021    ** the nodes at level xLow, which will not vanish, regardless.
1022    */
1023    limitSize = L = table->keys - table->isolated;
1024    for (x = xLow + 1; x < y; x++) {
1025        xindex = table->invperm[x];
1026        if (cuddTestInteract(table,xindex,yindex)) {
1027            isolated = table->vars[xindex]->ref == 1;
1028            L -= table->subtables[x].keys - isolated;
1029        }
1030    }
1031    isolated = table->vars[yindex]->ref == 1;
1032    L -= table->subtables[y].keys - isolated;
1033
1034    x = cuddNextLow(table,y);
1035    while (x >= xLow && L <= limitSize) {
1036        xindex = table->invperm[x];
1037#ifdef DD_DEBUG
1038        checkL = table->keys - table->isolated;
1039        for (z = xLow + 1; z < y; z++) {
1040            zindex = table->invperm[z];
1041            if (cuddTestInteract(table,zindex,yindex)) {
1042                isolated = table->vars[zindex]->ref == 1;
1043                checkL -= table->subtables[z].keys - isolated;
1044            }
1045        }
1046        isolated = table->vars[yindex]->ref == 1;
1047        checkL -= table->subtables[y].keys - isolated;
1048        if (L != checkL) {
1049            (void) fprintf(table->out, "checkL(%d) != L(%d)\n",checkL,L);
1050        }
1051#endif
1052        size = cuddSwapInPlace(table,x,y);
1053        if (size == 0) goto ddLinearAndSiftingUpOutOfMem;
1054        newsize = cuddLinearInPlace(table,x,y);
1055        if (newsize == 0) goto ddLinearAndSiftingUpOutOfMem;
1056        move = (Move *) cuddDynamicAllocNode(table);
1057        if (move == NULL) goto ddLinearAndSiftingUpOutOfMem;
1058        move->x = x;
1059        move->y = y;
1060        move->next = moves;
1061        moves = move;
1062        move->flags = CUDD_SWAP_MOVE;
1063        if (newsize >= size) {
1064            /* Undo transformation. The transformation we apply is
1065            ** its own inverse. Hence, we just apply the transformation
1066            ** again.
1067            */
1068            newsize = cuddLinearInPlace(table,x,y);
1069            if (newsize == 0) goto ddLinearAndSiftingUpOutOfMem;
1070#ifdef DD_DEBUG
1071            if (newsize != size) {
1072                (void) fprintf(table->out,"Change in size after identity transformation! From %d to %d\n",size,newsize);
1073            }
1074#endif
1075        } else if (cuddTestInteract(table,xindex,yindex)) {
1076            size = newsize;
1077            move->flags = CUDD_LINEAR_TRANSFORM_MOVE;
1078            cuddUpdateInteractionMatrix(table,xindex,yindex);
1079        }
1080        move->size = size;
1081        /* Update the lower bound. */
1082        if (cuddTestInteract(table,xindex,yindex)) {
1083            isolated = table->vars[xindex]->ref == 1;
1084            L += table->subtables[y].keys - isolated;
1085        }
1086        if ((double) size > (double) limitSize * table->maxGrowth) break;
1087        if (size < limitSize) limitSize = size;
1088        y = x;
1089        x = cuddNextLow(table,y);
1090    }
1091    return(moves);
1092
1093ddLinearAndSiftingUpOutOfMem:
1094    while (moves != NULL) {
1095        move = moves->next;
1096        cuddDeallocMove(table, moves);
1097        moves = move;
1098    }
1099    return((Move *) CUDD_OUT_OF_MEM);
1100
1101} /* end of ddLinearAndSiftingUp */
1102   
1103
1104/**Function********************************************************************
1105
1106  Synopsis    [Sifts a variable down and applies linear transformations.]
1107
1108  Description [Sifts a variable down and applies linear
1109  transformations. Moves x down until either it reaches the bound
1110  (xHigh) or the size of the DD heap increases too much. Returns the
1111  set of moves in case of success; NULL if memory is full.]
1112
1113  SideEffects [None]
1114
1115******************************************************************************/
1116static Move *
1117ddLinearAndSiftingDown(
1118  DdManager * table,
1119  int  x,
1120  int  xHigh,
1121  Move * prevMoves)
1122{
1123    Move        *moves;
1124    Move        *move;
1125    int         y;
1126    int         size, newsize;
1127    int         R;      /* upper bound on node decrease */
1128    int         limitSize;
1129    int         xindex, yindex;
1130    int         isolated;
1131#ifdef DD_DEBUG
1132    int         checkR;
1133    int         z;
1134    int         zindex;
1135#endif
1136
1137    moves = prevMoves;
1138    /* Initialize R */
1139    xindex = table->invperm[x];
1140    limitSize = size = table->keys - table->isolated;
1141    R = 0;
1142    for (y = xHigh; y > x; y--) {
1143        yindex = table->invperm[y];
1144        if (cuddTestInteract(table,xindex,yindex)) {
1145            isolated = table->vars[yindex]->ref == 1;
1146            R += table->subtables[y].keys - isolated;
1147        }
1148    }
1149
1150    y = cuddNextHigh(table,x);
1151    while (y <= xHigh && size - R < limitSize) {
1152#ifdef DD_DEBUG
1153        checkR = 0;
1154        for (z = xHigh; z > x; z--) {
1155            zindex = table->invperm[z];
1156            if (cuddTestInteract(table,xindex,zindex)) {
1157                isolated = table->vars[zindex]->ref == 1;
1158                checkR += table->subtables[z].keys - isolated;
1159            }
1160        }
1161        if (R != checkR) {
1162            (void) fprintf(table->out, "checkR(%d) != R(%d)\n",checkR,R);
1163        }
1164#endif
1165        /* Update upper bound on node decrease. */
1166        yindex = table->invperm[y];
1167        if (cuddTestInteract(table,xindex,yindex)) {
1168            isolated = table->vars[yindex]->ref == 1;
1169            R -= table->subtables[y].keys - isolated;
1170        }
1171        size = cuddSwapInPlace(table,x,y);
1172        if (size == 0) goto ddLinearAndSiftingDownOutOfMem; 
1173        newsize = cuddLinearInPlace(table,x,y);
1174        if (newsize == 0) goto ddLinearAndSiftingDownOutOfMem;
1175        move = (Move *) cuddDynamicAllocNode(table);
1176        if (move == NULL) goto ddLinearAndSiftingDownOutOfMem;
1177        move->x = x;
1178        move->y = y;
1179        move->next = moves;
1180        moves = move;
1181        move->flags = CUDD_SWAP_MOVE;
1182        if (newsize >= size) {
1183            /* Undo transformation. The transformation we apply is
1184            ** its own inverse. Hence, we just apply the transformation
1185            ** again.
1186            */
1187            newsize = cuddLinearInPlace(table,x,y);
1188            if (newsize == 0) goto ddLinearAndSiftingDownOutOfMem;
1189            if (newsize != size) {
1190                (void) fprintf(table->out,"Change in size after identity transformation! From %d to %d\n",size,newsize);
1191            }
1192        } else if (cuddTestInteract(table,xindex,yindex)) {
1193            size = newsize;
1194            move->flags = CUDD_LINEAR_TRANSFORM_MOVE;
1195            cuddUpdateInteractionMatrix(table,xindex,yindex);
1196        }
1197        move->size = size;
1198        if ((double) size > (double) limitSize * table->maxGrowth) break;
1199        if (size < limitSize) limitSize = size;
1200        x = y;
1201        y = cuddNextHigh(table,x);
1202    }
1203    return(moves);
1204
1205ddLinearAndSiftingDownOutOfMem:
1206    while (moves != NULL) {
1207        move = moves->next;
1208        cuddDeallocMove(table, moves);
1209        moves = move;
1210    }
1211    return((Move *) CUDD_OUT_OF_MEM);
1212
1213} /* end of ddLinearAndSiftingDown */
1214
1215
1216/**Function********************************************************************
1217
1218  Synopsis    [Given a set of moves, returns the DD heap to the order
1219  giving the minimum size.]
1220
1221  Description [Given a set of moves, returns the DD heap to the
1222  position giving the minimum size. In case of ties, returns to the
1223  closest position giving the minimum size. Returns 1 in case of
1224  success; 0 otherwise.]
1225
1226  SideEffects [None]
1227
1228******************************************************************************/
1229static int
1230ddLinearAndSiftingBackward(
1231  DdManager * table,
1232  int  size,
1233  Move * moves)
1234{
1235    Move *move;
1236    int res;
1237
1238    for (move = moves; move != NULL; move = move->next) {
1239        if (move->size < size) {
1240            size = move->size;
1241        }
1242    }
1243
1244    for (move = moves; move != NULL; move = move->next) {
1245        if (move->size == size) return(1);
1246        if (move->flags == CUDD_LINEAR_TRANSFORM_MOVE) {
1247            res = cuddLinearInPlace(table,(int)move->x,(int)move->y);
1248            if (!res) return(0);
1249        }
1250        res = cuddSwapInPlace(table,(int)move->x,(int)move->y);
1251        if (!res) return(0);
1252        if (move->flags == CUDD_INVERSE_TRANSFORM_MOVE) {
1253            res = cuddLinearInPlace(table,(int)move->x,(int)move->y);
1254            if (!res) return(0);
1255        }
1256    }
1257
1258    return(1);
1259
1260} /* end of ddLinearAndSiftingBackward */
1261
1262
1263/**Function********************************************************************
1264
1265  Synopsis    [Given a set of moves, returns the DD heap to the order
1266  in effect before the moves.]
1267
1268  Description [Given a set of moves, returns the DD heap to the
1269  order in effect before the moves.  Returns 1 in case of success;
1270  0 otherwise.]
1271
1272  SideEffects [None]
1273
1274******************************************************************************/
1275static Move*
1276ddUndoMoves(
1277  DdManager * table,
1278  Move * moves)
1279{
1280    Move *invmoves = NULL;
1281    Move *move;
1282    Move *invmove;
1283    int size;
1284
1285    for (move = moves; move != NULL; move = move->next) {
1286        invmove = (Move *) cuddDynamicAllocNode(table);
1287        if (invmove == NULL) goto ddUndoMovesOutOfMem;
1288        invmove->x = move->x;
1289        invmove->y = move->y;
1290        invmove->next = invmoves;
1291        invmoves = invmove;
1292        if (move->flags == CUDD_SWAP_MOVE) {
1293            invmove->flags = CUDD_SWAP_MOVE;
1294            size = cuddSwapInPlace(table,(int)move->x,(int)move->y);
1295            if (!size) goto ddUndoMovesOutOfMem;
1296        } else if (move->flags == CUDD_LINEAR_TRANSFORM_MOVE) {
1297            invmove->flags = CUDD_INVERSE_TRANSFORM_MOVE;
1298            size = cuddLinearInPlace(table,(int)move->x,(int)move->y);
1299            if (!size) goto ddUndoMovesOutOfMem;
1300            size = cuddSwapInPlace(table,(int)move->x,(int)move->y);
1301            if (!size) goto ddUndoMovesOutOfMem;
1302        } else { /* must be CUDD_INVERSE_TRANSFORM_MOVE */
1303#ifdef DD_DEBUG
1304            (void) fprintf(table->err,"Unforseen event in ddUndoMoves!\n");
1305#endif
1306            invmove->flags = CUDD_LINEAR_TRANSFORM_MOVE;
1307            size = cuddSwapInPlace(table,(int)move->x,(int)move->y);
1308            if (!size) goto ddUndoMovesOutOfMem;
1309            size = cuddLinearInPlace(table,(int)move->x,(int)move->y);
1310            if (!size) goto ddUndoMovesOutOfMem;
1311        }
1312        invmove->size = size;
1313    }
1314
1315    return(invmoves);
1316
1317ddUndoMovesOutOfMem:
1318    while (invmoves != NULL) {
1319        move = invmoves->next;
1320        cuddDeallocMove(table, invmoves);
1321        invmoves = move;
1322    }
1323    return((Move *) CUDD_OUT_OF_MEM);
1324
1325} /* end of ddUndoMoves */
1326
1327
1328/**Function********************************************************************
1329 
1330  Synopsis    [XORs two rows of the linear transform matrix.]
1331
1332  Description [XORs two rows of the linear transform matrix and replaces
1333  the first row with the result.]
1334
1335  SideEffects [none]
1336
1337  SeeAlso     []
1338
1339******************************************************************************/
1340static void
1341cuddXorLinear(
1342  DdManager * table,
1343  int  x,
1344  int  y)
1345{
1346    int i;
1347    int nvars = table->size;
1348    int wordsPerRow = ((nvars - 1) >> LOGBPL) + 1;
1349    int xstart = wordsPerRow * x;
1350    int ystart = wordsPerRow * y;
1351    long *linear = table->linear;
1352
1353    for (i = 0; i < wordsPerRow; i++) {
1354        linear[xstart+i] ^= linear[ystart+i];
1355    }
1356
1357} /* end of cuddXorLinear */
1358
Note: See TracBrowser for help on using the repository browser.