00001
00059 #include "util.h"
00060 #include "cuddInt.h"
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082 #ifndef lint
00083 static char rcsid[] DD_UNUSED = "$Id: cuddMatMult.c,v 1.17 2004/08/13 18:04:50 fabio Exp $";
00084 #endif
00085
00086
00087
00088
00089
00090
00093
00094
00095
00096
00097 static DdNode * addMMRecur (DdManager *dd, DdNode *A, DdNode *B, int topP, int *vars);
00098 static DdNode * addTriangleRecur (DdManager *dd, DdNode *f, DdNode *g, int *vars, DdNode *cube);
00099 static DdNode * cuddAddOuterSumRecur (DdManager *dd, DdNode *M, DdNode *r, DdNode *c);
00100
00104
00105
00106
00107
00127 DdNode *
00128 Cudd_addMatrixMultiply(
00129 DdManager * dd,
00130 DdNode * A,
00131 DdNode * B,
00132 DdNode ** z,
00133 int nz)
00134 {
00135 int i, nvars, *vars;
00136 DdNode *res;
00137
00138
00139 nvars = dd->size;
00140 vars = ALLOC(int,nvars);
00141 if (vars == NULL) {
00142 dd->errorCode = CUDD_MEMORY_OUT;
00143 return(NULL);
00144 }
00145 for (i = 0; i < nvars; i++) {
00146 vars[i] = 0;
00147 }
00148 for (i = 0; i < nz; i++) {
00149 vars[z[i]->index] = 1;
00150 }
00151
00152 do {
00153 dd->reordered = 0;
00154 res = addMMRecur(dd,A,B,-1,vars);
00155 } while (dd->reordered == 1);
00156 FREE(vars);
00157 return(res);
00158
00159 }
00160
00161
00180 DdNode *
00181 Cudd_addTimesPlus(
00182 DdManager * dd,
00183 DdNode * A,
00184 DdNode * B,
00185 DdNode ** z,
00186 int nz)
00187 {
00188 DdNode *w, *cube, *tmp, *res;
00189 int i;
00190 tmp = Cudd_addApply(dd,Cudd_addTimes,A,B);
00191 if (tmp == NULL) return(NULL);
00192 Cudd_Ref(tmp);
00193 Cudd_Ref(cube = DD_ONE(dd));
00194 for (i = nz-1; i >= 0; i--) {
00195 w = Cudd_addIte(dd,z[i],cube,DD_ZERO(dd));
00196 if (w == NULL) {
00197 Cudd_RecursiveDeref(dd,tmp);
00198 return(NULL);
00199 }
00200 Cudd_Ref(w);
00201 Cudd_RecursiveDeref(dd,cube);
00202 cube = w;
00203 }
00204 res = Cudd_addExistAbstract(dd,tmp,cube);
00205 if (res == NULL) {
00206 Cudd_RecursiveDeref(dd,tmp);
00207 Cudd_RecursiveDeref(dd,cube);
00208 return(NULL);
00209 }
00210 Cudd_Ref(res);
00211 Cudd_RecursiveDeref(dd,cube);
00212 Cudd_RecursiveDeref(dd,tmp);
00213 Cudd_Deref(res);
00214 return(res);
00215
00216 }
00217
00218
00238 DdNode *
00239 Cudd_addTriangle(
00240 DdManager * dd,
00241 DdNode * f,
00242 DdNode * g,
00243 DdNode ** z,
00244 int nz)
00245 {
00246 int i, nvars, *vars;
00247 DdNode *res, *cube;
00248
00249 nvars = dd->size;
00250 vars = ALLOC(int, nvars);
00251 if (vars == NULL) {
00252 dd->errorCode = CUDD_MEMORY_OUT;
00253 return(NULL);
00254 }
00255 for (i = 0; i < nvars; i++) vars[i] = -1;
00256 for (i = 0; i < nz; i++) vars[z[i]->index] = i;
00257 cube = Cudd_addComputeCube(dd, z, NULL, nz);
00258 if (cube == NULL) {
00259 FREE(vars);
00260 return(NULL);
00261 }
00262 cuddRef(cube);
00263
00264 do {
00265 dd->reordered = 0;
00266 res = addTriangleRecur(dd, f, g, vars, cube);
00267 } while (dd->reordered == 1);
00268 if (res != NULL) cuddRef(res);
00269 Cudd_RecursiveDeref(dd,cube);
00270 if (res != NULL) cuddDeref(res);
00271 FREE(vars);
00272 return(res);
00273
00274 }
00275
00276
00291 DdNode *
00292 Cudd_addOuterSum(
00293 DdManager *dd,
00294 DdNode *M,
00295 DdNode *r,
00296 DdNode *c)
00297 {
00298 DdNode *res;
00299
00300 do {
00301 dd->reordered = 0;
00302 res = cuddAddOuterSumRecur(dd, M, r, c);
00303 } while (dd->reordered == 1);
00304 return(res);
00305
00306 }
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00328 static DdNode *
00329 addMMRecur(
00330 DdManager * dd,
00331 DdNode * A,
00332 DdNode * B,
00333 int topP,
00334 int * vars)
00335 {
00336 DdNode *zero,
00337 *At,
00338 *Ae,
00339 *Bt,
00340 *Be,
00341 *t,
00342 *e,
00343 *scaled,
00344 *add_scale,
00345 *res;
00346 int i;
00347 double scale;
00348 int index;
00349 CUDD_VALUE_TYPE value;
00350 unsigned int topA, topB, topV;
00351 DD_CTFP cacheOp;
00352
00353 statLine(dd);
00354 zero = DD_ZERO(dd);
00355
00356 if (A == zero || B == zero) {
00357 return(zero);
00358 }
00359
00360 if (cuddIsConstant(A) && cuddIsConstant(B)) {
00361
00362
00363
00364
00365
00366 value = cuddV(A) * cuddV(B);
00367 for (i = 0; i < dd->size; i++) {
00368 if (vars[i]) {
00369 if (dd->perm[i] > topP) {
00370 value *= (CUDD_VALUE_TYPE) 2;
00371 }
00372 }
00373 }
00374 res = cuddUniqueConst(dd, value);
00375 return(res);
00376 }
00377
00378
00379
00380
00381
00382
00383 if (A > B) {
00384 DdNode *tmp = A;
00385 A = B;
00386 B = tmp;
00387 }
00388
00389 topA = cuddI(dd,A->index); topB = cuddI(dd,B->index);
00390 topV = ddMin(topA,topB);
00391
00392 cacheOp = (DD_CTFP) addMMRecur;
00393 res = cuddCacheLookup2(dd,cacheOp,A,B);
00394 if (res != NULL) {
00395
00396
00397
00398
00399
00400
00401 if (res == zero) return(res);
00402 scale = 1.0;
00403 for (i = 0; i < dd->size; i++) {
00404 if (vars[i]) {
00405 if (dd->perm[i] > topP && (unsigned) dd->perm[i] < topV) {
00406 scale *= 2;
00407 }
00408 }
00409 }
00410 if (scale > 1.0) {
00411 cuddRef(res);
00412 add_scale = cuddUniqueConst(dd,(CUDD_VALUE_TYPE)scale);
00413 if (add_scale == NULL) {
00414 Cudd_RecursiveDeref(dd, res);
00415 return(NULL);
00416 }
00417 cuddRef(add_scale);
00418 scaled = cuddAddApplyRecur(dd,Cudd_addTimes,res,add_scale);
00419 if (scaled == NULL) {
00420 Cudd_RecursiveDeref(dd, add_scale);
00421 Cudd_RecursiveDeref(dd, res);
00422 return(NULL);
00423 }
00424 cuddRef(scaled);
00425 Cudd_RecursiveDeref(dd, add_scale);
00426 Cudd_RecursiveDeref(dd, res);
00427 res = scaled;
00428 cuddDeref(res);
00429 }
00430 return(res);
00431 }
00432
00433
00434 if (topV == topA) {
00435 At = cuddT(A);
00436 Ae = cuddE(A);
00437 } else {
00438 At = Ae = A;
00439 }
00440 if (topV == topB) {
00441 Bt = cuddT(B);
00442 Be = cuddE(B);
00443 } else {
00444 Bt = Be = B;
00445 }
00446
00447 t = addMMRecur(dd, At, Bt, (int)topV, vars);
00448 if (t == NULL) return(NULL);
00449 cuddRef(t);
00450 e = addMMRecur(dd, Ae, Be, (int)topV, vars);
00451 if (e == NULL) {
00452 Cudd_RecursiveDeref(dd, t);
00453 return(NULL);
00454 }
00455 cuddRef(e);
00456
00457 index = dd->invperm[topV];
00458 if (vars[index] == 0) {
00459
00460
00461
00462
00463 res = (t == e) ? t : cuddUniqueInter(dd,index,t,e);
00464 if (res == NULL) {
00465 Cudd_RecursiveDeref(dd, t);
00466 Cudd_RecursiveDeref(dd, e);
00467 return(NULL);
00468 }
00469 cuddRef(res);
00470 cuddDeref(t);
00471 cuddDeref(e);
00472 } else {
00473
00474
00475
00476 res = cuddAddApplyRecur(dd,Cudd_addPlus,t,e);
00477 if (res == NULL) {
00478 Cudd_RecursiveDeref(dd, t);
00479 Cudd_RecursiveDeref(dd, e);
00480 return(NULL);
00481 }
00482 cuddRef(res);
00483 Cudd_RecursiveDeref(dd, t);
00484 Cudd_RecursiveDeref(dd, e);
00485 }
00486
00487 cuddCacheInsert2(dd,cacheOp,A,B,res);
00488
00489
00490
00491
00492
00493
00494
00495 if (res != zero) {
00496 scale = 1.0;
00497 for (i = 0; i < dd->size; i++) {
00498 if (vars[i]) {
00499 if (dd->perm[i] > topP && (unsigned) dd->perm[i] < topV) {
00500 scale *= 2;
00501 }
00502 }
00503 }
00504 if (scale > 1.0) {
00505 add_scale = cuddUniqueConst(dd,(CUDD_VALUE_TYPE)scale);
00506 if (add_scale == NULL) {
00507 Cudd_RecursiveDeref(dd, res);
00508 return(NULL);
00509 }
00510 cuddRef(add_scale);
00511 scaled = cuddAddApplyRecur(dd,Cudd_addTimes,res,add_scale);
00512 if (scaled == NULL) {
00513 Cudd_RecursiveDeref(dd, res);
00514 Cudd_RecursiveDeref(dd, add_scale);
00515 return(NULL);
00516 }
00517 cuddRef(scaled);
00518 Cudd_RecursiveDeref(dd, add_scale);
00519 Cudd_RecursiveDeref(dd, res);
00520 res = scaled;
00521 }
00522 }
00523 cuddDeref(res);
00524 return(res);
00525
00526 }
00527
00528
00539 static DdNode *
00540 addTriangleRecur(
00541 DdManager * dd,
00542 DdNode * f,
00543 DdNode * g,
00544 int * vars,
00545 DdNode *cube)
00546 {
00547 DdNode *fv, *fvn, *gv, *gvn, *t, *e, *res;
00548 CUDD_VALUE_TYPE value;
00549 int top, topf, topg, index;
00550
00551 statLine(dd);
00552 if (f == DD_PLUS_INFINITY(dd) || g == DD_PLUS_INFINITY(dd)) {
00553 return(DD_PLUS_INFINITY(dd));
00554 }
00555
00556 if (cuddIsConstant(f) && cuddIsConstant(g)) {
00557 value = cuddV(f) + cuddV(g);
00558 res = cuddUniqueConst(dd, value);
00559 return(res);
00560 }
00561 if (f < g) {
00562 DdNode *tmp = f;
00563 f = g;
00564 g = tmp;
00565 }
00566
00567 if (f->ref != 1 || g->ref != 1) {
00568 res = cuddCacheLookup(dd, DD_ADD_TRIANGLE_TAG, f, g, cube);
00569 if (res != NULL) {
00570 return(res);
00571 }
00572 }
00573
00574 topf = cuddI(dd,f->index); topg = cuddI(dd,g->index);
00575 top = ddMin(topf,topg);
00576
00577 if (top == topf) {fv = cuddT(f); fvn = cuddE(f);} else {fv = fvn = f;}
00578 if (top == topg) {gv = cuddT(g); gvn = cuddE(g);} else {gv = gvn = g;}
00579
00580 t = addTriangleRecur(dd, fv, gv, vars, cube);
00581 if (t == NULL) return(NULL);
00582 cuddRef(t);
00583 e = addTriangleRecur(dd, fvn, gvn, vars, cube);
00584 if (e == NULL) {
00585 Cudd_RecursiveDeref(dd, t);
00586 return(NULL);
00587 }
00588 cuddRef(e);
00589
00590 index = dd->invperm[top];
00591 if (vars[index] < 0) {
00592 res = (t == e) ? t : cuddUniqueInter(dd,index,t,e);
00593 if (res == NULL) {
00594 Cudd_RecursiveDeref(dd, t);
00595 Cudd_RecursiveDeref(dd, e);
00596 return(NULL);
00597 }
00598 cuddDeref(t);
00599 cuddDeref(e);
00600 } else {
00601 res = cuddAddApplyRecur(dd,Cudd_addMinimum,t,e);
00602 if (res == NULL) {
00603 Cudd_RecursiveDeref(dd, t);
00604 Cudd_RecursiveDeref(dd, e);
00605 return(NULL);
00606 }
00607 cuddRef(res);
00608 Cudd_RecursiveDeref(dd, t);
00609 Cudd_RecursiveDeref(dd, e);
00610 cuddDeref(res);
00611 }
00612
00613 if (f->ref != 1 || g->ref != 1) {
00614 cuddCacheInsert(dd, DD_ADD_TRIANGLE_TAG, f, g, cube, res);
00615 }
00616
00617 return(res);
00618
00619 }
00620
00621
00634 static DdNode *
00635 cuddAddOuterSumRecur(
00636 DdManager *dd,
00637 DdNode *M,
00638 DdNode *r,
00639 DdNode *c)
00640 {
00641 DdNode *P, *R, *Mt, *Me, *rt, *re, *ct, *ce, *Rt, *Re;
00642 int topM, topc, topr;
00643 int v, index;
00644
00645 statLine(dd);
00646
00647 if (r == DD_PLUS_INFINITY(dd) || c == DD_PLUS_INFINITY(dd)) return(M);
00648
00649 if (cuddIsConstant(c) && cuddIsConstant(r)) {
00650 R = cuddUniqueConst(dd,Cudd_V(c)+Cudd_V(r));
00651 cuddRef(R);
00652 if (cuddIsConstant(M)) {
00653 if (cuddV(R) <= cuddV(M)) {
00654 cuddDeref(R);
00655 return(R);
00656 } else {
00657 Cudd_RecursiveDeref(dd,R);
00658 return(M);
00659 }
00660 } else {
00661 P = Cudd_addApply(dd,Cudd_addMinimum,R,M);
00662 cuddRef(P);
00663 Cudd_RecursiveDeref(dd,R);
00664 cuddDeref(P);
00665 return(P);
00666 }
00667 }
00668
00669
00670 R = cuddCacheLookup(dd,DD_ADD_OUT_SUM_TAG,M,r,c);
00671 if (R != NULL) return(R);
00672
00673 topM = cuddI(dd,M->index); topr = cuddI(dd,r->index);
00674 topc = cuddI(dd,c->index);
00675 v = ddMin(topM,ddMin(topr,topc));
00676
00677
00678 if (topM == v) { Mt = cuddT(M); Me = cuddE(M); } else { Mt = Me = M; }
00679 if (topr == v) { rt = cuddT(r); re = cuddE(r); } else { rt = re = r; }
00680 if (topc == v) { ct = cuddT(c); ce = cuddE(c); } else { ct = ce = c; }
00681
00682
00683 Rt = cuddAddOuterSumRecur(dd,Mt,rt,ct);
00684 if (Rt == NULL) return(NULL);
00685 cuddRef(Rt);
00686 Re = cuddAddOuterSumRecur(dd,Me,re,ce);
00687 if (Re == NULL) {
00688 Cudd_RecursiveDeref(dd, Rt);
00689 return(NULL);
00690 }
00691 cuddRef(Re);
00692 index = dd->invperm[v];
00693 R = (Rt == Re) ? Rt : cuddUniqueInter(dd,index,Rt,Re);
00694 if (R == NULL) {
00695 Cudd_RecursiveDeref(dd, Rt);
00696 Cudd_RecursiveDeref(dd, Re);
00697 return(NULL);
00698 }
00699 cuddDeref(Rt);
00700 cuddDeref(Re);
00701
00702
00703 cuddCacheInsert(dd,DD_ADD_OUT_SUM_TAG,M,r,c,R);
00704
00705 return(R);
00706
00707 }