00001 
00019 #include "cloud.h"
00020 
00021 
00022 static int CacheOperNum = 4;
00023 
00024 
00025 static int CacheLogRatioDefault[4] = {
00026         2, 
00027         8, 
00028         8, 
00029         8  
00030 };
00031 
00032 
00033 static int CacheSize[4] = {
00034         2, 
00035         2, 
00036         2, 
00037         2  
00038 };
00039 
00043 
00044 
00045 static CloudNode * cloudMakeNode( CloudManager * dd, CloudVar v, CloudNode * t, CloudNode * e );
00046 static void        cloudCacheAllocate( CloudManager * dd, CloudOper oper );
00047 
00051 
00066 CloudManager * Cloud_Init( int nVars, int nBits )
00067 {
00068         CloudManager * dd;
00069         int i;
00070         int clk1, clk2;
00071 
00072         assert( nVars <= 100000 );
00073         assert( nBits < 32 );
00074 
00075         
00076         if ( nBits == 0 )
00077                 nBits = CLOUD_NODE_BITS;
00078 
00079         
00080         dd = CALLOC( CloudManager, 1 );
00081         dd->nMemUsed          += sizeof(CloudManager);
00082 
00083         
00084         dd->nVars             = nVars;              
00085         
00086         dd->bitsNode          = nBits;              
00087         for ( i = 0; i < CacheOperNum; i++ )
00088                 dd->bitsCache[i]  = nBits - CacheLogRatioDefault[i];
00089         
00090         dd->shiftUnique       = 8*sizeof(unsigned) - (nBits + 1); 
00091         for ( i = 0; i < CacheOperNum; i++ )
00092                 dd->shiftCache[i] = 8*sizeof(unsigned) - dd->bitsCache[i];
00093         
00094         dd->nNodesAlloc       = (1 << (nBits + 1)); 
00095         dd->nNodesLimit       = (1 << nBits);       
00096 
00097         
00098 clk1 = clock();
00099         dd->tUnique           = CALLOC( CloudNode, dd->nNodesAlloc );
00100         dd->nMemUsed         += sizeof(CloudNode) * dd->nNodesAlloc;
00101 clk2 = clock();
00102 
00103 
00104         
00105         dd->nSignCur          = 1;
00106         dd->tUnique[0].s      = dd->nSignCur;
00107         dd->tUnique[0].v      = CLOUD_CONST_INDEX;
00108         dd->tUnique[0].e      = CLOUD_VOID;
00109         dd->tUnique[0].t      = CLOUD_VOID;
00110         dd->one               = dd->tUnique;
00111         dd->zero              = Cloud_Not(dd->one);
00112         dd->nNodesCur         = 1;
00113 
00114         
00115         dd->pNodeStart        = dd->tUnique + 1;
00116         dd->pNodeEnd          = dd->tUnique + dd->nNodesAlloc;
00117 
00118         
00119         dd->vars              = ALLOC( CloudNode *, dd->nVars );
00120         dd->nMemUsed         += sizeof(CloudNode *) * dd->nVars;
00121         for ( i = 0; i < dd->nVars; i++ )
00122                 dd->vars[i]   = cloudMakeNode( dd, i, dd->one, dd->zero );
00123 
00124         return dd;
00125 };
00126 
00140 void Cloud_Quit( CloudManager * dd )
00141 {
00142         int i;
00143     FREE( dd->ppNodes );
00144         free( dd->tUnique ); 
00145         free( dd->vars ); 
00146         for ( i = 0; i < 4; i++ )
00147                 FREE( dd->tCaches[i] );
00148         free( dd ); 
00149 }
00150 
00162 void Cloud_Restart( CloudManager * dd )
00163 {
00164     int i;
00165     assert( dd->one->s == dd->nSignCur );
00166     dd->nSignCur++;
00167     dd->one->s++;
00168         for ( i = 0; i < dd->nVars; i++ )
00169                 dd->vars[i]->s++;
00170     dd->nNodesCur = 1 + dd->nVars;
00171 }
00172 
00191 void Cloud_CacheAllocate( CloudManager * dd, CloudOper oper, int logratio )
00192 {
00193         assert( logratio > 0 );            
00194         assert( logratio < dd->bitsNode ); 
00195 
00196         if ( logratio )
00197         {
00198                 dd->bitsCache[oper]  = dd->bitsNode - logratio;
00199                 dd->shiftCache[oper] = 8*sizeof(unsigned) - dd->bitsCache[oper];
00200         }
00201         cloudCacheAllocate( dd, oper );
00202 }
00203 
00215 void cloudCacheAllocate( CloudManager * dd, CloudOper oper )
00216 {
00217         int nCacheEntries = (1 << dd->bitsCache[oper]);
00218 
00219         if ( CacheSize[oper] == 1 )
00220         {
00221                 dd->tCaches[oper] = (CloudCacheEntry2 *)CALLOC( CloudCacheEntry1, nCacheEntries );
00222                 dd->nMemUsed     += sizeof(CloudCacheEntry1) * nCacheEntries;
00223         }
00224         else if ( CacheSize[oper] == 2 )
00225         {
00226                 dd->tCaches[oper] = (CloudCacheEntry2 *)CALLOC( CloudCacheEntry2, nCacheEntries );
00227                 dd->nMemUsed     += sizeof(CloudCacheEntry2) * nCacheEntries;
00228         }
00229         else if ( CacheSize[oper] == 3 )
00230         {
00231                 dd->tCaches[oper] = (CloudCacheEntry2 *)CALLOC( CloudCacheEntry3, nCacheEntries );
00232                 dd->nMemUsed     += sizeof(CloudCacheEntry3) * nCacheEntries;
00233         }
00234 }
00235 
00236 
00237 
00250 CloudNode * Cloud_MakeNode( CloudManager * dd, CloudVar v, CloudNode * t, CloudNode * e )
00251 {
00252         CloudNode * pRes;
00253         CLOUD_ASSERT(t); 
00254         CLOUD_ASSERT(e);
00255     assert( v < Cloud_V(t) && v < Cloud_V(e) );       
00256     if ( Cloud_IsComplement(t) )
00257     {
00258         pRes = cloudMakeNode( dd, v, Cloud_Not(t), Cloud_Not(e) );
00259         if ( pRes != CLOUD_VOID )
00260             pRes = Cloud_Not(pRes);            
00261     }
00262     else
00263         pRes = cloudMakeNode( dd, v, t, e );
00264     return pRes;
00265 }
00266 
00279 CloudNode * cloudMakeNode( CloudManager * dd, CloudVar v, CloudNode * t, CloudNode * e )
00280 {
00281         CloudNode * entryUnique;
00282 
00283         CLOUD_ASSERT(t); 
00284         CLOUD_ASSERT(e);
00285 
00286         assert( ((int)v) >= 0 && ((int)v) < dd->nVars );  
00287     assert( v < Cloud_V(t) && v < Cloud_V(e) );       
00288         assert( !Cloud_IsComplement(t) );                 
00289 
00290         
00291         assert( t && e );
00292 
00293         
00294         entryUnique = dd->tUnique + cloudHashCudd3(v, t, e, dd->shiftUnique);
00295         while ( entryUnique->s == dd->nSignCur )
00296         {
00297                 
00298                 if ( entryUnique->v == v && entryUnique->t == t && entryUnique->e == e )
00299                 { 
00300                         dd->nUniqueHits++;
00301                         return entryUnique;  
00302                 }
00303                 
00304                 if ( ++entryUnique - dd->tUnique == dd->nNodesAlloc )
00305                         entryUnique = dd->tUnique + 1;
00306                 
00307                 dd->nUniqueSteps++;
00308         }
00309         dd->nUniqueMisses++;
00310 
00311         
00312         if ( ++dd->nNodesCur == dd->nNodesLimit ) 
00313         { 
00314                 printf( "Cloud needs restart!\n" );
00315 
00316 
00317                 return CLOUD_VOID;
00318         }
00319         
00320         entryUnique->s   = dd->nSignCur;
00321         entryUnique->v   = v;
00322         entryUnique->t   = t;
00323         entryUnique->e   = e;
00324         return entryUnique;  
00325 }
00326 
00327 
00339 CloudNode * cloudBddAnd( CloudManager * dd, CloudNode * f, CloudNode * g )
00340 {
00341         CloudNode * F, * G, * r;
00342         CloudCacheEntry2 * cacheEntry;
00343         CloudNode * fv, * fnv, * gv, * gnv, * t, * e;
00344         CloudVar  var;
00345 
00346         assert( f <= g );
00347 
00348         
00349         F = Cloud_Regular(f);
00350         G = Cloud_Regular(g);
00351         if ( F == G )
00352         {
00353                 if ( f == g )
00354                         return f;
00355                 else
00356                         return dd->zero;
00357         }
00358         if ( F == dd->one )
00359         {
00360                 if ( f == dd->one )
00361                         return g;
00362                 else
00363                         return f;
00364         }
00365 
00366         
00367         cacheEntry = dd->tCaches[CLOUD_OPER_AND] + cloudHashCudd2(f, g, dd->shiftCache[CLOUD_OPER_AND]);
00368 
00369         r = cloudCacheLookup2( cacheEntry, dd->nSignCur, f, g );
00370         if ( r != CLOUD_VOID )
00371         {
00372                 dd->nCacheHits++;
00373                 return r;
00374         }
00375         dd->nCacheMisses++;
00376 
00377 
00378         
00379         if ( cloudV(F) <= cloudV(G) )
00380         {
00381                 var = cloudV(F);
00382                 if ( Cloud_IsComplement(f) )
00383                 {
00384                         fnv = Cloud_Not(cloudE(F));
00385                         fv  = Cloud_Not(cloudT(F));
00386                 }
00387                 else
00388                 {
00389                         fnv = cloudE(F);
00390                         fv  = cloudT(F);
00391                 }
00392         }
00393         else
00394         {
00395                 var = cloudV(G);
00396                 fv  = fnv = f;
00397         }
00398 
00399         if ( cloudV(G) <= cloudV(F) )
00400         {
00401                 if ( Cloud_IsComplement(g) )
00402                 {
00403                         gnv = Cloud_Not(cloudE(G));
00404                         gv  = Cloud_Not(cloudT(G));
00405                 }
00406                 else
00407                 {
00408                         gnv = cloudE(G);
00409                         gv  = cloudT(G);
00410                 }
00411         }
00412         else
00413         {
00414                 gv = gnv = g;
00415         }
00416 
00417         if ( fv <= gv )
00418                 t = cloudBddAnd( dd, fv, gv );
00419         else
00420                 t = cloudBddAnd( dd, gv, fv );
00421 
00422         if ( t == CLOUD_VOID )
00423                 return CLOUD_VOID;
00424 
00425         if ( fnv <= gnv )
00426                 e = cloudBddAnd( dd, fnv, gnv );
00427         else
00428                 e = cloudBddAnd( dd, gnv, fnv );
00429 
00430         if ( e == CLOUD_VOID )
00431                 return CLOUD_VOID;
00432 
00433         if ( t == e )
00434                 r = t;
00435         else
00436         {
00437                 if ( Cloud_IsComplement(t) )
00438                 {
00439                         r = cloudMakeNode( dd, var, Cloud_Not(t), Cloud_Not(e) );
00440                         if ( r == CLOUD_VOID )
00441                                 return CLOUD_VOID;
00442                         r = Cloud_Not(r);
00443                 }
00444                 else
00445                 {
00446                         r = cloudMakeNode( dd, var, t, e );
00447                         if ( r == CLOUD_VOID )
00448                                 return CLOUD_VOID;
00449                 }
00450         }
00451         cloudCacheInsert2( cacheEntry, dd->nSignCur, f, g, r );
00452         return r;
00453 }
00454 
00466 static inline CloudNode * cloudBddAnd_gate( CloudManager * dd, CloudNode * f, CloudNode * g )
00467 {
00468         if ( f <= g )
00469                 return cloudBddAnd(dd,f,g);
00470         else
00471                 return cloudBddAnd(dd,g,f);
00472 }
00473 
00485 CloudNode * Cloud_bddAnd( CloudManager * dd, CloudNode * f, CloudNode * g )
00486 {
00487     if ( Cloud_Regular(f) == CLOUD_VOID || Cloud_Regular(g) == CLOUD_VOID )
00488         return CLOUD_VOID;
00489         CLOUD_ASSERT(f);
00490         CLOUD_ASSERT(g);
00491         if ( dd->tCaches[CLOUD_OPER_AND] == NULL )
00492                 cloudCacheAllocate( dd, CLOUD_OPER_AND );
00493         return cloudBddAnd_gate( dd, f, g );
00494 }
00495 
00507 CloudNode * Cloud_bddOr( CloudManager * dd, CloudNode * f, CloudNode * g )
00508 {
00509         CloudNode * res;
00510     if ( Cloud_Regular(f) == CLOUD_VOID || Cloud_Regular(g) == CLOUD_VOID )
00511         return CLOUD_VOID;
00512         CLOUD_ASSERT(f);
00513         CLOUD_ASSERT(g);
00514         if ( dd->tCaches[CLOUD_OPER_AND] == NULL )
00515                 cloudCacheAllocate( dd, CLOUD_OPER_AND );
00516         res = cloudBddAnd_gate( dd, Cloud_Not(f), Cloud_Not(g) );
00517         res = Cloud_NotCond( res, res != CLOUD_VOID );
00518         return res;
00519 }
00520 
00532 CloudNode * Cloud_bddXor( CloudManager * dd, CloudNode * f, CloudNode * g )
00533 {
00534         CloudNode * t0, * t1, * r;
00535     if ( Cloud_Regular(f) == CLOUD_VOID || Cloud_Regular(g) == CLOUD_VOID )
00536         return CLOUD_VOID;
00537         CLOUD_ASSERT(f);
00538         CLOUD_ASSERT(g);
00539         if ( dd->tCaches[CLOUD_OPER_AND] == NULL )
00540                 cloudCacheAllocate( dd, CLOUD_OPER_AND );
00541         t0 = cloudBddAnd_gate( dd, f, Cloud_Not(g) );
00542         if ( t0 == CLOUD_VOID )
00543                 return CLOUD_VOID;
00544         t1 = cloudBddAnd_gate( dd, Cloud_Not(f), g );
00545         if ( t1 == CLOUD_VOID )
00546                 return CLOUD_VOID;
00547         r  = Cloud_bddOr( dd, t0, t1 );
00548         return r;
00549 }
00550 
00551 
00552 
00565 static void cloudClearMark( CloudManager * dd, CloudNode * n )
00566 {
00567         if ( !cloudNodeIsMarked(n) )
00568                 return;
00569         
00570         cloudNodeUnmark(n);
00571         if ( cloudIsConstant(n) )
00572                 return;
00573         cloudClearMark( dd, cloudT(n) );
00574         cloudClearMark( dd, Cloud_Regular(cloudE(n)) );
00575 }
00576 
00590 static void cloudSupport( CloudManager * dd, CloudNode * n, int * support )
00591 {
00592         if ( cloudIsConstant(n) || cloudNodeIsMarked(n) )
00593                 return;
00594         
00595         cloudNodeMark(n);
00596         support[cloudV(n)] = 1;
00597         cloudSupport( dd, cloudT(n), support );
00598         cloudSupport( dd, Cloud_Regular(cloudE(n)), support );
00599 }
00600 
00614 CloudNode * Cloud_Support( CloudManager * dd, CloudNode * n )
00615 {
00616         CloudNode * res;
00617         int * support, i;
00618 
00619         CLOUD_ASSERT(n);
00620 
00621         
00622         support = CALLOC( int, dd->nVars );
00623 
00624         
00625         cloudSupport( dd, Cloud_Regular(n), support );
00626         cloudClearMark( dd, Cloud_Regular(n) );
00627 
00628         
00629         res = dd->one;
00630         for ( i = dd->nVars - 1; i >= 0; i-- ) 
00631                 if ( support[i] == 1 )
00632                 {
00633                         res = Cloud_bddAnd( dd, res, dd->vars[i] );
00634                         if ( res == CLOUD_VOID )
00635                                 break;
00636                 }
00637         FREE( support );
00638         return res;
00639 }
00640 
00654 int Cloud_SupportSize( CloudManager * dd, CloudNode * n )
00655 {
00656         int * support, i, count;
00657 
00658         CLOUD_ASSERT(n);
00659 
00660         
00661         support = CALLOC( int, dd->nVars );
00662 
00663         
00664         cloudSupport( dd, Cloud_Regular(n), support );
00665         cloudClearMark( dd, Cloud_Regular(n) );
00666 
00667         
00668         count = 0;
00669         for ( i = 0; i < dd->nVars; i++ )
00670         {
00671                 if ( support[i] == 1 )
00672                         count++;
00673         }
00674 
00675         FREE( support );
00676         return count;
00677 }
00678 
00679 
00690 static int cloudDagSize( CloudManager * dd, CloudNode * n )
00691 {
00692         int tval, eval;
00693         if ( cloudNodeIsMarked(n) )
00694                 return 0;
00695         
00696         cloudNodeMark(n);
00697         if ( cloudIsConstant(n) )
00698                 return 1;
00699         tval = cloudDagSize( dd, cloudT(n) );
00700         eval = cloudDagSize( dd, Cloud_Regular(cloudE(n)) );
00701         return tval + eval + 1;
00702 
00703 }
00704 
00717 int Cloud_DagSize( CloudManager * dd, CloudNode * n )
00718 {
00719         int res;
00720         res = cloudDagSize( dd, Cloud_Regular( n ) );
00721         cloudClearMark( dd, Cloud_Regular( n ) );
00722         return res;
00723 
00724 }
00725 
00726 
00737 static int Cloud_DagCollect_rec( CloudManager * dd, CloudNode * n, int * pCounter )
00738 {
00739         int tval, eval;
00740         if ( cloudNodeIsMarked(n) )
00741                 return 0;
00742         
00743         cloudNodeMark(n);
00744         if ( cloudIsConstant(n) )
00745     {
00746         dd->ppNodes[(*pCounter)++] = n;
00747                 return 1;
00748     }
00749         tval = Cloud_DagCollect_rec( dd, cloudT(n), pCounter );
00750         eval = Cloud_DagCollect_rec( dd, Cloud_Regular(cloudE(n)), pCounter );
00751     dd->ppNodes[(*pCounter)++] = n;
00752         return tval + eval + 1;
00753 
00754 }
00755 
00768 int Cloud_DagCollect( CloudManager * dd, CloudNode * n )
00769 {
00770         int res, Counter = 0;
00771     if ( dd->ppNodes == NULL )
00772         dd->ppNodes = ALLOC( CloudNode *, dd->nNodesLimit );
00773         res = Cloud_DagCollect_rec( dd, Cloud_Regular( n ), &Counter );
00774         cloudClearMark( dd, Cloud_Regular( n ) );
00775     assert( res == Counter );
00776         return res;
00777 
00778 }
00779 
00792 int Cloud_SharingSize( CloudManager * dd, CloudNode ** pn, int nn )
00793 {
00794         int res, i;
00795         res = 0;
00796         for ( i = 0; i < nn; i++ )
00797                 res += cloudDagSize( dd, Cloud_Regular( pn[i] ) );
00798         for ( i = 0; i < nn; i++ )
00799                 cloudClearMark( dd, Cloud_Regular( pn[i] ) );
00800         return res;
00801 }
00802 
00803 
00813 CloudNode * Cloud_GetOneCube( CloudManager * dd, CloudNode * bFunc )
00814 {
00815         CloudNode * bFunc0, * bFunc1, * res;
00816 
00817         if ( Cloud_IsConstant(bFunc) )
00818                 return bFunc;
00819 
00820         
00821         if ( Cloud_IsComplement(bFunc) )
00822         {
00823                 bFunc0 = Cloud_Not( cloudE(bFunc) );
00824                 bFunc1 = Cloud_Not( cloudT(bFunc) );
00825         }
00826         else
00827         {
00828                 bFunc0 = cloudE(bFunc);
00829                 bFunc1 = cloudT(bFunc);
00830         }
00831 
00832         
00833         res = Cloud_GetOneCube( dd, bFunc0 );
00834         if ( res == CLOUD_VOID )
00835                 return CLOUD_VOID;
00836 
00837         if ( res != dd->zero )
00838         {
00839                 res = Cloud_bddAnd( dd, res, Cloud_Not(dd->vars[Cloud_V(bFunc)]) );
00840         }
00841         else
00842         {
00843                 
00844                 res = Cloud_GetOneCube( dd, bFunc1 );
00845                 if ( res == CLOUD_VOID )
00846                         return CLOUD_VOID;
00847                 assert( res != dd->zero );
00848                 res = Cloud_bddAnd( dd, res, dd->vars[Cloud_V(bFunc)] );
00849         }
00850         return res;
00851 }
00852 
00862 void Cloud_bddPrint( CloudManager * dd, CloudNode * Func )
00863 {
00864         CloudNode * Cube;
00865         int fFirst = 1;
00866 
00867         if ( Func == dd->zero )
00868                 printf( "Constant 0." );
00869         else if ( Func == dd->one )
00870                 printf( "Constant 1." );
00871         else
00872         {
00873                 while ( 1 )
00874                 {
00875                         Cube = Cloud_GetOneCube( dd, Func );
00876                         if ( Cube == CLOUD_VOID || Cube == dd->zero )
00877                                 break;
00878                         if ( fFirst )           fFirst = 0;
00879                         else                            printf( " + " );
00880                         Cloud_bddPrintCube( dd, Cube );
00881                         Func = Cloud_bddAnd( dd, Func, Cloud_Not(Cube) );
00882                 } 
00883         }
00884         printf( "\n" );
00885 }
00886 
00896 void Cloud_bddPrintCube( CloudManager * dd, CloudNode * bCube )
00897 {
00898         CloudNode * bCube0, * bCube1;
00899 
00900         assert( !Cloud_IsConstant(bCube) );
00901         while ( 1 )
00902         {
00903                 
00904                 if ( Cloud_IsConstant(bCube) )
00905                         break;
00906 
00907                 
00908                 if ( Cloud_IsComplement(bCube) )
00909                 {
00910                         bCube0 = Cloud_Not( cloudE(bCube) );
00911                         bCube1 = Cloud_Not( cloudT(bCube) );
00912                 }
00913                 else
00914                 {
00915                         bCube0 = cloudE(bCube);
00916                         bCube1 = cloudT(bCube);
00917                 }
00918 
00919                 if ( bCube0 != dd->zero )
00920                 {
00921                         assert( bCube1 == dd->zero );
00922                         printf( "[%d]'", cloudV(bCube) );
00923                         bCube = bCube0;
00924                 }
00925                 else
00926                 {
00927                         assert( bCube1 != dd->zero );
00928                         printf( "[%d]", cloudV(bCube) );
00929                         bCube = bCube1;
00930                 }
00931         }
00932 }
00933 
00934 
00946 void Cloud_PrintInfo( CloudManager * dd )
00947 {
00948     if ( dd == NULL ) return;
00949         printf( "The number of unique table nodes allocated = %12d.\n", dd->nNodesAlloc );
00950         printf( "The number of unique table nodes present   = %12d.\n", dd->nNodesCur );
00951         printf( "The number of unique table hits            = %12d.\n", dd->nUniqueHits );
00952         printf( "The number of unique table misses          = %12d.\n", dd->nUniqueMisses );
00953         printf( "The number of unique table steps           = %12d.\n", dd->nUniqueSteps );
00954         printf( "The number of cache hits                   = %12d.\n", dd->nCacheHits );
00955         printf( "The number of cache misses                 = %12d.\n", dd->nCacheMisses );
00956         printf( "The current signature                      = %12d.\n", dd->nSignCur );
00957         printf( "The total memory in use                    = %12d.\n", dd->nMemUsed );
00958 }
00959 
00971 void Cloud_PrintHashTable( CloudManager * dd )
00972 {
00973         int i;
00974 
00975         for ( i = 0; i < dd->nNodesAlloc; i++ )
00976                 if ( dd->tUnique[i].v == CLOUD_CONST_INDEX )
00977                         printf( "-" );
00978                 else
00979                         printf( "+" );
00980         printf( "\n" );
00981 }
00982 
00983 
00987