cuddZddSetop.c 30.1 KB
Newer Older
Alan Mishchenko committed
1 2 3 4 5 6 7 8 9
/**CFile***********************************************************************

  FileName    [cuddZddSetop.c]

  PackageName [cudd]

  Synopsis    [Set operations on ZDDs.]

  Description [External procedures included in this module:
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
                    <ul>
                    <li> Cudd_zddIte()
                    <li> Cudd_zddUnion()
                    <li> Cudd_zddIntersect()
                    <li> Cudd_zddDiff()
                    <li> Cudd_zddDiffConst()
                    <li> Cudd_zddSubset1()
                    <li> Cudd_zddSubset0()
                    <li> Cudd_zddChange()
                    </ul>
               Internal procedures included in this module:
                    <ul>
                    <li> cuddZddIte()
                    <li> cuddZddUnion()
                    <li> cuddZddIntersect()
                    <li> cuddZddDiff()
                    <li> cuddZddChangeAux()
                    <li> cuddZddSubset1()
                    <li> cuddZddSubset0()
                    </ul>
               Static procedures included in this module:
                    <ul>
                    <li> zdd_subset1_aux()
                    <li> zdd_subset0_aux()
                    <li> zddVarToConst()
                    </ul>
              ]
Alan Mishchenko committed
37 38 39 40 41

  SeeAlso     []

  Author      [Hyong-Kyoon Shin, In-Ho Moon]

42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
  Copyright   [Copyright (c) 1995-2004, Regents of the University of Colorado

  All rights reserved.

  Redistribution and use in source and binary forms, with or without
  modification, are permitted provided that the following conditions
  are met:

  Redistributions of source code must retain the above copyright
  notice, this list of conditions and the following disclaimer.

  Redistributions in binary form must reproduce the above copyright
  notice, this list of conditions and the following disclaimer in the
  documentation and/or other materials provided with the distribution.

  Neither the name of the University of Colorado nor the names of its
  contributors may be used to endorse or promote products derived from
  this software without specific prior written permission.

  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  POSSIBILITY OF SUCH DAMAGE.]
Alan Mishchenko committed
73 74 75

******************************************************************************/

76
#include "misc/util/util_hack.h"
77
#include "cuddInt.h"
Alan Mishchenko committed
78

79 80 81
ABC_NAMESPACE_IMPL_START


82

Alan Mishchenko committed
83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102
/*---------------------------------------------------------------------------*/
/* Constant declarations                                                     */
/*---------------------------------------------------------------------------*/


/*---------------------------------------------------------------------------*/
/* Stucture declarations                                                     */
/*---------------------------------------------------------------------------*/


/*---------------------------------------------------------------------------*/
/* Type declarations                                                         */
/*---------------------------------------------------------------------------*/


/*---------------------------------------------------------------------------*/
/* Variable declarations                                                     */
/*---------------------------------------------------------------------------*/

#ifndef lint
103
static char rcsid[] DD_UNUSED = "$Id: cuddZddSetop.c,v 1.25 2004/08/13 18:04:54 fabio Exp $";
Alan Mishchenko committed
104 105 106 107 108 109 110 111 112 113 114 115
#endif

/*---------------------------------------------------------------------------*/
/* Macro declarations                                                        */
/*---------------------------------------------------------------------------*/

/**AutomaticStart*************************************************************/

/*---------------------------------------------------------------------------*/
/* Static function prototypes                                                */
/*---------------------------------------------------------------------------*/

116 117 118
static DdNode * zdd_subset1_aux (DdManager *zdd, DdNode *P, DdNode *zvar);
static DdNode * zdd_subset0_aux (DdManager *zdd, DdNode *P, DdNode *zvar);
static void zddVarToConst (DdNode *f, DdNode **gp, DdNode **hp, DdNode *base, DdNode *empty);
Alan Mishchenko committed
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148

/**AutomaticEnd***************************************************************/

/*---------------------------------------------------------------------------*/
/* Definition of exported functions                                          */
/*---------------------------------------------------------------------------*/


/**Function********************************************************************

  Synopsis [Computes the ITE of three ZDDs.]

  Description [Computes the ITE of three ZDDs. Returns a pointer to the
  result if successful; NULL otherwise.]

  SideEffects [None]

  SeeAlso     []

******************************************************************************/
DdNode *
Cudd_zddIte(
  DdManager * dd,
  DdNode * f,
  DdNode * g,
  DdNode * h)
{
    DdNode *res;

    do {
149 150
        dd->reordered = 0;
        res = cuddZddIte(dd, f, g, h);
Alan Mishchenko committed
151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
    } while (dd->reordered == 1);
    return(res);

} /* end of Cudd_zddIte */


/**Function********************************************************************

  Synopsis [Computes the union of two ZDDs.]

  Description [Computes the union of two ZDDs. Returns a pointer to the
  result if successful; NULL otherwise.]

  SideEffects [None]

  SeeAlso     []

******************************************************************************/
DdNode *
Cudd_zddUnion(
  DdManager * dd,
  DdNode * P,
  DdNode * Q)
{
    DdNode *res;

    do {
178 179
        dd->reordered = 0;
        res = cuddZddUnion(dd, P, Q);
Alan Mishchenko committed
180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206
    } while (dd->reordered == 1);
    return(res);

} /* end of Cudd_zddUnion */


/**Function********************************************************************

  Synopsis [Computes the intersection of two ZDDs.]

  Description [Computes the intersection of two ZDDs. Returns a pointer to
  the result if successful; NULL otherwise.]

  SideEffects [None]

  SeeAlso     []

******************************************************************************/
DdNode *
Cudd_zddIntersect(
  DdManager * dd,
  DdNode * P,
  DdNode * Q)
{
    DdNode *res;

    do {
207 208
        dd->reordered = 0;
        res = cuddZddIntersect(dd, P, Q);
Alan Mishchenko committed
209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235
    } while (dd->reordered == 1);
    return(res);

} /* end of Cudd_zddIntersect */


/**Function********************************************************************

  Synopsis [Computes the difference of two ZDDs.]

  Description [Computes the difference of two ZDDs. Returns a pointer to the
  result if successful; NULL otherwise.]

  SideEffects [None]

  SeeAlso     [Cudd_zddDiffConst]

******************************************************************************/
DdNode *
Cudd_zddDiff(
  DdManager * dd,
  DdNode * P,
  DdNode * Q)
{
    DdNode *res;

    do {
236 237
        dd->reordered = 0;
        res = cuddZddDiff(dd, P, Q);
Alan Mishchenko committed
238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262
    } while (dd->reordered == 1);
    return(res);

} /* end of Cudd_zddDiff */


/**Function********************************************************************

  Synopsis [Performs the inclusion test for ZDDs (P implies Q).]

  Description [Inclusion test for ZDDs (P implies Q). No new nodes are
  generated by this procedure. Returns empty if true;
  a valid pointer different from empty or DD_NON_CONSTANT otherwise.]

  SideEffects [None]

  SeeAlso     [Cudd_zddDiff]

******************************************************************************/
DdNode *
Cudd_zddDiffConst(
  DdManager * zdd,
  DdNode * P,
  DdNode * Q)
{
263 264 265
    int         p_top, q_top;
    DdNode      *empty = DD_ZERO(zdd), *t, *res;
    DdManager   *table = zdd;
Alan Mishchenko committed
266 267 268

    statLine(zdd);
    if (P == empty)
269
        return(empty);
Alan Mishchenko committed
270
    if (Q == empty)
271
        return(P);
Alan Mishchenko committed
272
    if (P == Q)
273
        return(empty);
Alan Mishchenko committed
274 275 276 277

    /* Check cache.  The cache is shared by cuddZddDiff(). */
    res = cuddCacheLookup2Zdd(table, cuddZddDiff, P, Q);
    if (res != NULL)
278
        return(res);
Alan Mishchenko committed
279 280

    if (cuddIsConstant(P))
281
        p_top = P->index;
Alan Mishchenko committed
282
    else
283
        p_top = zdd->permZ[P->index];
Alan Mishchenko committed
284
    if (cuddIsConstant(Q))
285
        q_top = Q->index;
Alan Mishchenko committed
286
    else
287
        q_top = zdd->permZ[Q->index];
Alan Mishchenko committed
288
    if (p_top < q_top) {
289
        res = DD_NON_CONSTANT;
Alan Mishchenko committed
290
    } else if (p_top > q_top) {
291
        res = Cudd_zddDiffConst(zdd, P, cuddE(Q));
Alan Mishchenko committed
292
    } else {
293 294 295 296 297
        t = Cudd_zddDiffConst(zdd, cuddT(P), cuddT(Q));
        if (t != empty)
            res = DD_NON_CONSTANT;
        else
            res = Cudd_zddDiffConst(zdd, cuddE(P), cuddE(Q));
Alan Mishchenko committed
298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326
    }

    cuddCacheInsert2(table, cuddZddDiff, P, Q, res);

    return(res);

} /* end of Cudd_zddDiffConst */


/**Function********************************************************************

  Synopsis [Computes the positive cofactor of a ZDD w.r.t. a variable.]

  Description [Computes the positive cofactor of a ZDD w.r.t. a
  variable. In terms of combinations, the result is the set of all
  combinations in which the variable is asserted. Returns a pointer to
  the result if successful; NULL otherwise.]

  SideEffects [None]

  SeeAlso     [Cudd_zddSubset0]

******************************************************************************/
DdNode *
Cudd_zddSubset1(
  DdManager * dd,
  DdNode * P,
  int  var)
{
327
    DdNode      *r;
Alan Mishchenko committed
328 329

    do {
330 331
        dd->reordered = 0;
        r = cuddZddSubset1(dd, P, var);
Alan Mishchenko committed
332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358
    } while (dd->reordered == 1);

    return(r);

} /* end of Cudd_zddSubset1 */


/**Function********************************************************************

  Synopsis [Computes the negative cofactor of a ZDD w.r.t. a variable.]

  Description [Computes the negative cofactor of a ZDD w.r.t. a
  variable. In terms of combinations, the result is the set of all
  combinations in which the variable is negated. Returns a pointer to
  the result if successful; NULL otherwise.]

  SideEffects [None]

  SeeAlso     [Cudd_zddSubset1]

******************************************************************************/
DdNode *
Cudd_zddSubset0(
  DdManager * dd,
  DdNode * P,
  int  var)
{
359
    DdNode      *r;
Alan Mishchenko committed
360 361

    do {
362 363
        dd->reordered = 0;
        r = cuddZddSubset0(dd, P, var);
Alan Mishchenko committed
364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388
    } while (dd->reordered == 1);

    return(r);

} /* end of Cudd_zddSubset0 */


/**Function********************************************************************

  Synopsis [Substitutes a variable with its complement in a ZDD.]

  Description [Substitutes a variable with its complement in a ZDD.
  returns a pointer to the result if successful; NULL otherwise.]

  SideEffects [None]

  SeeAlso     []

******************************************************************************/
DdNode *
Cudd_zddChange(
  DdManager * dd,
  DdNode * P,
  int  var)
{
389
    DdNode      *res;
Alan Mishchenko committed
390 391 392 393

    if ((unsigned int) var >= CUDD_MAXINDEX - 1) return(NULL);
    
    do {
394 395
        dd->reordered = 0;
        res = cuddZddChange(dd, P, var);
Alan Mishchenko committed
396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432
    } while (dd->reordered == 1);
    return(res);

} /* end of Cudd_zddChange */


/*---------------------------------------------------------------------------*/
/* Definition of internal functions                                          */
/*---------------------------------------------------------------------------*/


/**Function********************************************************************

  Synopsis    [Performs the recursive step of Cudd_zddIte.]

  Description []

  SideEffects [None]

  SeeAlso     []

******************************************************************************/
DdNode *
cuddZddIte(
  DdManager * dd,
  DdNode * f,
  DdNode * g,
  DdNode * h)
{
    DdNode *tautology, *empty;
    DdNode *r,*Gv,*Gvn,*Hv,*Hvn,*t,*e;
    unsigned int topf,topg,toph,v,top;
    int index;

    statLine(dd);
    /* Trivial cases. */
    /* One variable cases. */
433 434
    if (f == (empty = DD_ZERO(dd))) {   /* ITE(0,G,H) = H */
        return(h);
Alan Mishchenko committed
435 436 437 438 439 440 441 442
    }
    topf = cuddIZ(dd,f->index);
    topg = cuddIZ(dd,g->index);
    toph = cuddIZ(dd,h->index);
    v = ddMin(topg,toph);
    top  = ddMin(topf,v);

    tautology = (top == CUDD_MAXINDEX) ? DD_ONE(dd) : dd->univ[top];
443
    if (f == tautology) {                       /* ITE(1,G,H) = G */
Alan Mishchenko committed
444 445 446 447 448 449 450
        return(g);
    }

    /* From now on, f is known to not be a constant. */
    zddVarToConst(f,&g,&h,tautology,empty);

    /* Check remaining one variable cases. */
451 452
    if (g == h) {                       /* ITE(F,G,G) = G */
        return(g);
Alan Mishchenko committed
453 454
    }

455 456
    if (g == tautology) {                       /* ITE(F,1,0) = F */
        if (h == empty) return(f);
Alan Mishchenko committed
457 458 459 460 461
    }

    /* Check cache. */
    r = cuddCacheLookupZdd(dd,DD_ZDD_ITE_TAG,f,g,h);
    if (r != NULL) {
462
        return(r);
Alan Mishchenko committed
463 464 465 466 467 468 469 470
    }

    /* Recompute these because they may have changed in zddVarToConst. */
    topg = cuddIZ(dd,g->index);
    toph = cuddIZ(dd,h->index);
    v = ddMin(topg,toph);

    if (topf < v) {
471 472
        r = cuddZddIte(dd,cuddE(f),g,h);
        if (r == NULL) return(NULL);
Alan Mishchenko committed
473
    } else if (topf > v) {
474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494
        if (topg > v) {
            Gvn = g;
            index = h->index;
        } else {
            Gvn = cuddE(g);
            index = g->index;
        }
        if (toph > v) {
            Hv = empty; Hvn = h;
        } else {
            Hv = cuddT(h); Hvn = cuddE(h);
        }
        e = cuddZddIte(dd,f,Gvn,Hvn);
        if (e == NULL) return(NULL);
        cuddRef(e);
        r = cuddZddGetNode(dd,index,Hv,e);
        if (r == NULL) {
            Cudd_RecursiveDerefZdd(dd,e);
            return(NULL);
        }
        cuddDeref(e);
Alan Mishchenko committed
495
    } else {
496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523
        index = f->index;
        if (topg > v) {
            Gv = empty; Gvn = g;
        } else {
            Gv = cuddT(g); Gvn = cuddE(g);
        }
        if (toph > v) {
            Hv = empty; Hvn = h;
        } else {
            Hv = cuddT(h); Hvn = cuddE(h);
        }
        e = cuddZddIte(dd,cuddE(f),Gvn,Hvn);
        if (e == NULL) return(NULL);
        cuddRef(e);
        t = cuddZddIte(dd,cuddT(f),Gv,Hv);
        if (t == NULL) {
            Cudd_RecursiveDerefZdd(dd,e);
            return(NULL);
        }
        cuddRef(t);
        r = cuddZddGetNode(dd,index,t,e);
        if (r == NULL) {
            Cudd_RecursiveDerefZdd(dd,e);
            Cudd_RecursiveDerefZdd(dd,t);
            return(NULL);
        }
        cuddDeref(t);
        cuddDeref(e);
Alan Mishchenko committed
524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549
    }

    cuddCacheInsert(dd,DD_ZDD_ITE_TAG,f,g,h,r);

    return(r);

} /* end of cuddZddIte */


/**Function********************************************************************

  Synopsis [Performs the recursive step of Cudd_zddUnion.]

  Description []

  SideEffects [None]

  SeeAlso     []

******************************************************************************/
DdNode *
cuddZddUnion(
  DdManager * zdd,
  DdNode * P,
  DdNode * Q)
{
550 551 552
    int         p_top, q_top;
    DdNode      *empty = DD_ZERO(zdd), *t, *e, *res;
    DdManager   *table = zdd;
Alan Mishchenko committed
553 554 555

    statLine(zdd);
    if (P == empty)
556
        return(Q);
Alan Mishchenko committed
557
    if (Q == empty)
558
        return(P);
Alan Mishchenko committed
559
    if (P == Q)
560
        return(P);
Alan Mishchenko committed
561 562 563 564

    /* Check cache */
    res = cuddCacheLookup2Zdd(table, cuddZddUnion, P, Q);
    if (res != NULL)
565
        return(res);
Alan Mishchenko committed
566 567

    if (cuddIsConstant(P))
568
        p_top = P->index;
Alan Mishchenko committed
569
    else
570
        p_top = zdd->permZ[P->index];
Alan Mishchenko committed
571
    if (cuddIsConstant(Q))
572
        q_top = Q->index;
Alan Mishchenko committed
573
    else
574
        q_top = zdd->permZ[Q->index];
Alan Mishchenko committed
575
    if (p_top < q_top) {
576 577 578 579 580 581 582 583 584
        e = cuddZddUnion(zdd, cuddE(P), Q);
        if (e == NULL) return (NULL);
        cuddRef(e);
        res = cuddZddGetNode(zdd, P->index, cuddT(P), e);
        if (res == NULL) {
            Cudd_RecursiveDerefZdd(table, e);
            return(NULL);
        }
        cuddDeref(e);
Alan Mishchenko committed
585
    } else if (p_top > q_top) {
586 587 588 589 590 591 592 593 594
        e = cuddZddUnion(zdd, P, cuddE(Q));
        if (e == NULL) return(NULL);
        cuddRef(e);
        res = cuddZddGetNode(zdd, Q->index, cuddT(Q), e);
        if (res == NULL) {
            Cudd_RecursiveDerefZdd(table, e);
            return(NULL);
        }
        cuddDeref(e);
Alan Mishchenko committed
595
    } else {
596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612
        t = cuddZddUnion(zdd, cuddT(P), cuddT(Q));
        if (t == NULL) return(NULL);
        cuddRef(t);
        e = cuddZddUnion(zdd, cuddE(P), cuddE(Q));
        if (e == NULL) {
            Cudd_RecursiveDerefZdd(table, t);
            return(NULL);
        }
        cuddRef(e);
        res = cuddZddGetNode(zdd, P->index, t, e);
        if (res == NULL) {
            Cudd_RecursiveDerefZdd(table, t);
            Cudd_RecursiveDerefZdd(table, e);
            return(NULL);
        }
        cuddDeref(t);
        cuddDeref(e);
Alan Mishchenko committed
613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638
    }

    cuddCacheInsert2(table, cuddZddUnion, P, Q, res);

    return(res);

} /* end of cuddZddUnion */


/**Function********************************************************************

  Synopsis [Performs the recursive step of Cudd_zddIntersect.]

  Description []

  SideEffects [None]

  SeeAlso     []

******************************************************************************/
DdNode *
cuddZddIntersect(
  DdManager * zdd,
  DdNode * P,
  DdNode * Q)
{
639 640 641
    int         p_top, q_top;
    DdNode      *empty = DD_ZERO(zdd), *t, *e, *res;
    DdManager   *table = zdd;
Alan Mishchenko committed
642 643 644

    statLine(zdd);
    if (P == empty)
645
        return(empty);
Alan Mishchenko committed
646
    if (Q == empty)
647
        return(empty);
Alan Mishchenko committed
648
    if (P == Q)
649
        return(P);
Alan Mishchenko committed
650 651 652 653

    /* Check cache. */
    res = cuddCacheLookup2Zdd(table, cuddZddIntersect, P, Q);
    if (res != NULL)
654
        return(res);
Alan Mishchenko committed
655 656

    if (cuddIsConstant(P))
657
        p_top = P->index;
Alan Mishchenko committed
658
    else
659
        p_top = zdd->permZ[P->index];
Alan Mishchenko committed
660
    if (cuddIsConstant(Q))
661
        q_top = Q->index;
Alan Mishchenko committed
662
    else
663
        q_top = zdd->permZ[Q->index];
Alan Mishchenko committed
664
    if (p_top < q_top) {
665 666
        res = cuddZddIntersect(zdd, cuddE(P), Q);
        if (res == NULL) return(NULL);
Alan Mishchenko committed
667
    } else if (p_top > q_top) {
668 669
        res = cuddZddIntersect(zdd, P, cuddE(Q));
        if (res == NULL) return(NULL);
Alan Mishchenko committed
670
    } else {
671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687
        t = cuddZddIntersect(zdd, cuddT(P), cuddT(Q));
        if (t == NULL) return(NULL);
        cuddRef(t);
        e = cuddZddIntersect(zdd, cuddE(P), cuddE(Q));
        if (e == NULL) {
            Cudd_RecursiveDerefZdd(table, t);
            return(NULL);
        }
        cuddRef(e);
        res = cuddZddGetNode(zdd, P->index, t, e);
        if (res == NULL) {
            Cudd_RecursiveDerefZdd(table, t);
            Cudd_RecursiveDerefZdd(table, e);
            return(NULL);
        }
        cuddDeref(t);
        cuddDeref(e);
Alan Mishchenko committed
688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713
    }

    cuddCacheInsert2(table, cuddZddIntersect, P, Q, res);

    return(res);

} /* end of cuddZddIntersect */


/**Function********************************************************************

  Synopsis [Performs the recursive step of Cudd_zddDiff.]

  Description []

  SideEffects [None]

  SeeAlso     []

******************************************************************************/
DdNode *
cuddZddDiff(
  DdManager * zdd,
  DdNode * P,
  DdNode * Q)
{
714 715 716
    int         p_top, q_top;
    DdNode      *empty = DD_ZERO(zdd), *t, *e, *res;
    DdManager   *table = zdd;
Alan Mishchenko committed
717 718 719

    statLine(zdd);
    if (P == empty)
720
        return(empty);
Alan Mishchenko committed
721
    if (Q == empty)
722
        return(P);
Alan Mishchenko committed
723
    if (P == Q)
724
        return(empty);
Alan Mishchenko committed
725 726 727 728

    /* Check cache.  The cache is shared by Cudd_zddDiffConst(). */
    res = cuddCacheLookup2Zdd(table, cuddZddDiff, P, Q);
    if (res != NULL && res != DD_NON_CONSTANT)
729
        return(res);
Alan Mishchenko committed
730 731

    if (cuddIsConstant(P))
732
        p_top = P->index;
Alan Mishchenko committed
733
    else
734
        p_top = zdd->permZ[P->index];
Alan Mishchenko committed
735
    if (cuddIsConstant(Q))
736
        q_top = Q->index;
Alan Mishchenko committed
737
    else
738
        q_top = zdd->permZ[Q->index];
Alan Mishchenko committed
739
    if (p_top < q_top) {
740 741 742 743 744 745 746 747 748
        e = cuddZddDiff(zdd, cuddE(P), Q);
        if (e == NULL) return(NULL);
        cuddRef(e);
        res = cuddZddGetNode(zdd, P->index, cuddT(P), e);
        if (res == NULL) {
            Cudd_RecursiveDerefZdd(table, e);
            return(NULL);
        }
        cuddDeref(e);
Alan Mishchenko committed
749
    } else if (p_top > q_top) {
750 751
        res = cuddZddDiff(zdd, P, cuddE(Q));
        if (res == NULL) return(NULL);
Alan Mishchenko committed
752
    } else {
753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769
        t = cuddZddDiff(zdd, cuddT(P), cuddT(Q));
        if (t == NULL) return(NULL);
        cuddRef(t);
        e = cuddZddDiff(zdd, cuddE(P), cuddE(Q));
        if (e == NULL) {
            Cudd_RecursiveDerefZdd(table, t);
            return(NULL);
        }
        cuddRef(e);
        res = cuddZddGetNode(zdd, P->index, t, e);
        if (res == NULL) {
            Cudd_RecursiveDerefZdd(table, t);
            Cudd_RecursiveDerefZdd(table, e);
            return(NULL);
        }
        cuddDeref(t);
        cuddDeref(e);
Alan Mishchenko committed
770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795
    }

    cuddCacheInsert2(table, cuddZddDiff, P, Q, res);

    return(res);

} /* end of cuddZddDiff */


/**Function********************************************************************

  Synopsis [Performs the recursive step of Cudd_zddChange.]

  Description []

  SideEffects [None]

  SeeAlso     []

******************************************************************************/
DdNode *
cuddZddChangeAux(
  DdManager * zdd,
  DdNode * P,
  DdNode * zvar)
{
796 797 798 799
    int         top_var, level;
    DdNode      *res, *t, *e;
    DdNode      *base = DD_ONE(zdd);
    DdNode      *empty = DD_ZERO(zdd);
Alan Mishchenko committed
800 801 802

    statLine(zdd);
    if (P == empty)
803
        return(empty);
Alan Mishchenko committed
804
    if (P == base)
805
        return(zvar);
Alan Mishchenko committed
806 807 808 809

    /* Check cache. */
    res = cuddCacheLookup2Zdd(zdd, cuddZddChangeAux, P, zvar);
    if (res != NULL)
810
        return(res);
Alan Mishchenko committed
811 812 813 814 815

    top_var = zdd->permZ[P->index];
    level = zdd->permZ[zvar->index];

    if (top_var > level) {
816 817
        res = cuddZddGetNode(zdd, zvar->index, P, DD_ZERO(zdd));
        if (res == NULL) return(NULL);
Alan Mishchenko committed
818
    } else if (top_var == level) {
819 820
        res = cuddZddGetNode(zdd, zvar->index, cuddE(P), cuddT(P));
        if (res == NULL) return(NULL);
Alan Mishchenko committed
821
    } else {
822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838
        t = cuddZddChangeAux(zdd, cuddT(P), zvar);
        if (t == NULL) return(NULL);
        cuddRef(t);
        e = cuddZddChangeAux(zdd, cuddE(P), zvar);
        if (e == NULL) {
            Cudd_RecursiveDerefZdd(zdd, t);
            return(NULL);
        }
        cuddRef(e);
        res = cuddZddGetNode(zdd, P->index, t, e);
        if (res == NULL) {
            Cudd_RecursiveDerefZdd(zdd, t);
            Cudd_RecursiveDerefZdd(zdd, e);
            return(NULL);
        }
        cuddDeref(t);
        cuddDeref(e);
Alan Mishchenko committed
839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870
    }

    cuddCacheInsert2(zdd, cuddZddChangeAux, P, zvar, res);

    return(res);

} /* end of cuddZddChangeAux */


/**Function********************************************************************

  Synopsis [Computes the positive cofactor of a ZDD w.r.t. a variable.]

  Description [Computes the positive cofactor of a ZDD w.r.t. a
  variable. In terms of combinations, the result is the set of all
  combinations in which the variable is asserted. Returns a pointer to
  the result if successful; NULL otherwise. cuddZddSubset1 performs
  the same function as Cudd_zddSubset1, but does not restart if
  reordering has taken place. Therefore it can be called from within a
  recursive procedure.]

  SideEffects [None]

  SeeAlso     [cuddZddSubset0 Cudd_zddSubset1]

******************************************************************************/
DdNode *
cuddZddSubset1(
  DdManager * dd,
  DdNode * P,
  int  var)
{
871 872
    DdNode      *zvar, *r;
    DdNode      *base, *empty;
Alan Mishchenko committed
873 874 875 876 877 878

    base = DD_ONE(dd);
    empty = DD_ZERO(dd);

    zvar = cuddUniqueInterZdd(dd, var, base, empty);
    if (zvar == NULL) {
879
        return(NULL);
Alan Mishchenko committed
880
    } else {
881 882 883 884 885 886 887
        cuddRef(zvar);
        r = zdd_subset1_aux(dd, P, zvar);
        if (r == NULL) {
            Cudd_RecursiveDerefZdd(dd, zvar);
            return(NULL);
        }
        cuddRef(r);
Alan Mishchenko committed
888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919
        Cudd_RecursiveDerefZdd(dd, zvar);
    }

    cuddDeref(r);
    return(r);

} /* end of cuddZddSubset1 */


/**Function********************************************************************

  Synopsis [Computes the negative cofactor of a ZDD w.r.t. a variable.]

  Description [Computes the negative cofactor of a ZDD w.r.t. a
  variable. In terms of combinations, the result is the set of all
  combinations in which the variable is negated. Returns a pointer to
  the result if successful; NULL otherwise. cuddZddSubset0 performs
  the same function as Cudd_zddSubset0, but does not restart if
  reordering has taken place. Therefore it can be called from within a
  recursive procedure.]

  SideEffects [None]

  SeeAlso     [cuddZddSubset1 Cudd_zddSubset0]

******************************************************************************/
DdNode *
cuddZddSubset0(
  DdManager * dd,
  DdNode * P,
  int  var)
{
920 921
    DdNode      *zvar, *r;
    DdNode      *base, *empty;
Alan Mishchenko committed
922 923 924 925 926 927

    base = DD_ONE(dd);
    empty = DD_ZERO(dd);

    zvar = cuddUniqueInterZdd(dd, var, base, empty);
    if (zvar == NULL) {
928
        return(NULL);
Alan Mishchenko committed
929
    } else {
930 931 932 933 934 935 936
        cuddRef(zvar);
        r = zdd_subset0_aux(dd, P, zvar);
        if (r == NULL) {
            Cudd_RecursiveDerefZdd(dd, zvar);
            return(NULL);
        }
        cuddRef(r);
Alan Mishchenko committed
937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967
        Cudd_RecursiveDerefZdd(dd, zvar);
    }

    cuddDeref(r);
    return(r);

} /* end of cuddZddSubset0 */


/**Function********************************************************************

  Synopsis [Substitutes a variable with its complement in a ZDD.]

  Description [Substitutes a variable with its complement in a ZDD.
  returns a pointer to the result if successful; NULL
  otherwise. cuddZddChange performs the same function as
  Cudd_zddChange, but does not restart if reordering has taken
  place. Therefore it can be called from within a recursive
  procedure.]

  SideEffects [None]

  SeeAlso     [Cudd_zddChange]

******************************************************************************/
DdNode *
cuddZddChange(
  DdManager * dd,
  DdNode * P,
  int  var)
{
968
    DdNode      *zvar, *res;
Alan Mishchenko committed
969 970 971 972 973 974 975

    zvar = cuddUniqueInterZdd(dd, var, DD_ONE(dd), DD_ZERO(dd));
    if (zvar == NULL) return(NULL);
    cuddRef(zvar);

    res = cuddZddChangeAux(dd, P, zvar);
    if (res == NULL) {
976 977
        Cudd_RecursiveDerefZdd(dd,zvar);
        return(NULL);
Alan Mishchenko committed
978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008
    }
    cuddRef(res);
    Cudd_RecursiveDerefZdd(dd,zvar);
    cuddDeref(res);
    return(res);

} /* end of cuddZddChange */


/*---------------------------------------------------------------------------*/
/* Definition of static functions                                            */
/*---------------------------------------------------------------------------*/


/**Function********************************************************************

  Synopsis [Performs the recursive step of Cudd_zddSubset1.]

  Description []

  SideEffects [None]

  SeeAlso     []

******************************************************************************/
static DdNode *
zdd_subset1_aux(
  DdManager * zdd,
  DdNode * P,
  DdNode * zvar)
{
1009 1010 1011
    int         top_var, level;
    DdNode      *res, *t, *e;
    DdNode      *empty;
Alan Mishchenko committed
1012 1013 1014 1015 1016 1017 1018

    statLine(zdd);
    empty = DD_ZERO(zdd);

    /* Check cache. */
    res = cuddCacheLookup2Zdd(zdd, zdd_subset1_aux, P, zvar);
    if (res != NULL)
1019
        return(res);
Alan Mishchenko committed
1020 1021

    if (cuddIsConstant(P)) {
1022 1023 1024
        res = empty;
        cuddCacheInsert2(zdd, zdd_subset1_aux, P, zvar, res);
        return(res);
Alan Mishchenko committed
1025 1026 1027 1028 1029 1030 1031 1032
    }

    top_var = zdd->permZ[P->index];
    level = zdd->permZ[zvar->index];

    if (top_var > level) {
        res = empty;
    } else if (top_var == level) {
1033
        res = cuddT(P);
Alan Mishchenko committed
1034 1035
    } else {
        t = zdd_subset1_aux(zdd, cuddT(P), zvar);
1036 1037
        if (t == NULL) return(NULL);
        cuddRef(t);
Alan Mishchenko committed
1038
        e = zdd_subset1_aux(zdd, cuddE(P), zvar);
1039 1040 1041 1042 1043
        if (e == NULL) {
            Cudd_RecursiveDerefZdd(zdd, t);
            return(NULL);
        }
        cuddRef(e);
Alan Mishchenko committed
1044
        res = cuddZddGetNode(zdd, P->index, t, e);
1045 1046 1047 1048 1049 1050 1051
        if (res == NULL) {
            Cudd_RecursiveDerefZdd(zdd, t);
            Cudd_RecursiveDerefZdd(zdd, e);
            return(NULL);
        }
        cuddDeref(t);
        cuddDeref(e);
Alan Mishchenko committed
1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077
    }

    cuddCacheInsert2(zdd, zdd_subset1_aux, P, zvar, res);

    return(res);

} /* end of zdd_subset1_aux */


/**Function********************************************************************

  Synopsis [Performs the recursive step of Cudd_zddSubset0.]

  Description []

  SideEffects [None]

  SeeAlso     []

******************************************************************************/
static DdNode *
zdd_subset0_aux(
  DdManager * zdd,
  DdNode * P,
  DdNode * zvar)
{
1078 1079
    int         top_var, level;
    DdNode      *res, *t, *e;
Alan Mishchenko committed
1080 1081 1082 1083 1084 1085

    statLine(zdd);

    /* Check cache. */
    res = cuddCacheLookup2Zdd(zdd, zdd_subset0_aux, P, zvar);
    if (res != NULL)
1086
        return(res);
Alan Mishchenko committed
1087 1088

    if (cuddIsConstant(P)) {
1089 1090 1091
        res = P;
        cuddCacheInsert2(zdd, zdd_subset0_aux, P, zvar, res);
        return(res);
Alan Mishchenko committed
1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104
    }

    top_var = zdd->permZ[P->index];
    level = zdd->permZ[zvar->index];

    if (top_var > level) {
        res = P;
    }
    else if (top_var == level) {
        res = cuddE(P);
    }
    else {
        t = zdd_subset0_aux(zdd, cuddT(P), zvar);
1105 1106
        if (t == NULL) return(NULL);
        cuddRef(t);
Alan Mishchenko committed
1107
        e = zdd_subset0_aux(zdd, cuddE(P), zvar);
1108 1109 1110 1111 1112
        if (e == NULL) {
            Cudd_RecursiveDerefZdd(zdd, t);
            return(NULL);
        }
        cuddRef(e);
Alan Mishchenko committed
1113
        res = cuddZddGetNode(zdd, P->index, t, e);
1114 1115 1116 1117 1118 1119 1120
        if (res == NULL) {
            Cudd_RecursiveDerefZdd(zdd, t);
            Cudd_RecursiveDerefZdd(zdd, e);
            return(NULL);
        }
        cuddDeref(t);
        cuddDeref(e);
Alan Mishchenko committed
1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153
    }

    cuddCacheInsert2(zdd, zdd_subset0_aux, P, zvar, res);

    return(res);

} /* end of zdd_subset0_aux */


/**Function********************************************************************

  Synopsis    [Replaces variables with constants if possible (part of
  canonical form).]

  Description []

  SideEffects [None]

  SeeAlso     []

******************************************************************************/
static void
zddVarToConst(
  DdNode * f,
  DdNode ** gp,
  DdNode ** hp,
  DdNode * base,
  DdNode * empty)
{
    DdNode *g = *gp;
    DdNode *h = *hp;

    if (f == g) { /* ITE(F,F,H) = ITE(F,1,H) = F + H */
1154
        *gp = base;
Alan Mishchenko committed
1155 1156 1157
    }

    if (f == h) { /* ITE(F,G,F) = ITE(F,G,0) = F * G */
1158
        *hp = empty;
Alan Mishchenko committed
1159 1160 1161 1162
    }

} /* end of zddVarToConst */

1163

1164 1165
ABC_NAMESPACE_IMPL_END

1166