The source code and dockerfile for the GSW2024 AI Lab.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
This repo is archived. You can view files and clone it, but cannot push or open issues/pull-requests.

2957 lines
78 KiB

4 weeks ago
  1. /**
  2. @file
  3. @ingroup nanotrav
  4. @brief A very simple reachability analysis program.
  5. @author Fabio Somenzi
  6. @copyright@parblock
  7. Copyright (c) 1995-2015, Regents of the University of Colorado
  8. All rights reserved.
  9. Redistribution and use in source and binary forms, with or without
  10. modification, are permitted provided that the following conditions
  11. are met:
  12. Redistributions of source code must retain the above copyright
  13. notice, this list of conditions and the following disclaimer.
  14. Redistributions in binary form must reproduce the above copyright
  15. notice, this list of conditions and the following disclaimer in the
  16. documentation and/or other materials provided with the distribution.
  17. Neither the name of the University of Colorado nor the names of its
  18. contributors may be used to endorse or promote products derived from
  19. this software without specific prior written permission.
  20. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  21. "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  22. LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  23. FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  24. COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  25. INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  26. BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  27. LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  28. CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29. LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  30. ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  31. POSSIBILITY OF SUCH DAMAGE.
  32. @endparblock
  33. */
  34. #include "cuddInt.h"
  35. #include "ntr.h"
  36. /*---------------------------------------------------------------------------*/
  37. /* Constant declarations */
  38. /*---------------------------------------------------------------------------*/
  39. #define NTR_MAX_DEP_SIZE 20
  40. /*---------------------------------------------------------------------------*/
  41. /* Stucture declarations */
  42. /*---------------------------------------------------------------------------*/
  43. /*---------------------------------------------------------------------------*/
  44. /* Type declarations */
  45. /*---------------------------------------------------------------------------*/
  46. /*---------------------------------------------------------------------------*/
  47. /* Variable declarations */
  48. /*---------------------------------------------------------------------------*/
  49. static char const *onames[] = {"T", "R"}; /**< names of functions to be dumped */
  50. static double *signatures; /**< signatures for all variables */
  51. static BnetNetwork *staticNet; /**< pointer to network used by qsort
  52. ** comparison function */
  53. static DdNode **staticPart; /**< pointer to parts used by qsort
  54. ** comparison function */
  55. /*---------------------------------------------------------------------------*/
  56. /* Macro declarations */
  57. /*---------------------------------------------------------------------------*/
  58. /** \cond */
  59. /*---------------------------------------------------------------------------*/
  60. /* Static function prototypes */
  61. /*---------------------------------------------------------------------------*/
  62. static DdNode * makecube (DdManager *dd, DdNode **x, int n);
  63. static void ntrInitializeCount (BnetNetwork *net, NtrOptions *option);
  64. static void ntrCountDFS (BnetNetwork *net, BnetNode *node);
  65. static DdNode * ntrImage (DdManager *dd, NtrPartTR *TR, DdNode *from, NtrOptions *option);
  66. static DdNode * ntrPreimage (DdManager *dd, NtrPartTR *T, DdNode *from);
  67. static DdNode * ntrChooseFrom (DdManager *dd, DdNode *neW, DdNode *reached, NtrOptions *option);
  68. static DdNode * ntrUpdateReached (DdManager *dd, DdNode *oldreached, DdNode *to);
  69. static int ntrLatchDependencies (DdManager *dd, DdNode *reached, BnetNetwork *net, NtrOptions *option);
  70. static NtrPartTR * ntrEliminateDependencies (DdManager *dd, NtrPartTR *TR, DdNode **states, NtrOptions *option);
  71. static int ntrUpdateQuantificationSchedule (DdManager *dd, NtrPartTR *T);
  72. static int ntrSignatureCompare (int * ptrX, int * ptrY);
  73. static int ntrSignatureCompare2 (int * ptrX, int * ptrY);
  74. static int ntrPartCompare (int * ptrX, int * ptrY);
  75. static char ** ntrAllocMatrix (int nrows, int ncols);
  76. static void ntrFreeMatrix (char **matrix);
  77. static void ntrPermuteParts (DdNode **a, DdNode **b, int *comesFrom, int *goesTo, int size);
  78. static void ntrIncreaseRef(void * e, void * arg);
  79. static void ntrDecreaseRef(void * e, void * arg);
  80. /** \endcond */
  81. /*---------------------------------------------------------------------------*/
  82. /* Definition of exported functions */
  83. /*---------------------------------------------------------------------------*/
  84. /**
  85. @brief Builds DDs for a network outputs and next state functions.
  86. @details The method is really brain-dead, but it is very simple.
  87. Some inputs to the network may be shared with another network whose
  88. DDs have already been built. In this case we want to share the DDs
  89. as well.
  90. @return 1 in case of success; 0 otherwise.
  91. @sideeffect the dd fields of the network nodes are modified. Uses the
  92. count fields of the nodes.
  93. */
  94. int
  95. Ntr_buildDDs(
  96. BnetNetwork * net /**< network for which DDs are to be built */,
  97. DdManager * dd /**< %DD manager */,
  98. NtrOptions * option /**< option structure */,
  99. BnetNetwork * net2 /**< companion network with which inputs may be shared */)
  100. {
  101. int pr = option->verb;
  102. int result;
  103. int i;
  104. BnetNode *node, *node2;
  105. /* If some inputs or present state variables are shared with
  106. ** another network, we initialize their BDDs from that network.
  107. */
  108. if (net2 != NULL) {
  109. for (i = 0; i < net->npis; i++) {
  110. if (!st_lookup(net->hash,net->inputs[i],(void **)&node)) {
  111. return(0);
  112. }
  113. if (!st_lookup(net2->hash,net->inputs[i],(void **)&node2)) {
  114. /* This input is not shared. */
  115. result = Bnet_BuildNodeBDD(dd,node,net->hash,
  116. option->locGlob,option->nodrop);
  117. if (result == 0) return(0);
  118. } else {
  119. if (node2->dd == NULL) return(0);
  120. node->dd = node2->dd;
  121. Cudd_Ref(node->dd);
  122. node->var = node2->var;
  123. node->active = node2->active;
  124. }
  125. }
  126. for (i = 0; i < net->nlatches; i++) {
  127. if (!st_lookup(net->hash,net->latches[i][1],(void **)&node)) {
  128. return(0);
  129. }
  130. if (!st_lookup(net2->hash,net->latches[i][1],(void **)&node2)) {
  131. /* This present state variable is not shared. */
  132. result = Bnet_BuildNodeBDD(dd,node,net->hash,
  133. option->locGlob,option->nodrop);
  134. if (result == 0) return(0);
  135. } else {
  136. if (node2->dd == NULL) return(0);
  137. node->dd = node2->dd;
  138. Cudd_Ref(node->dd);
  139. node->var = node2->var;
  140. node->active = node2->active;
  141. }
  142. }
  143. } else {
  144. /* First assign variables to inputs if the order is provided.
  145. ** (Either in the .blif file or in an order file.)
  146. */
  147. if (option->ordering == PI_PS_FROM_FILE) {
  148. /* Follow order given in input file. First primary inputs
  149. ** and then present state variables.
  150. */
  151. for (i = 0; i < net->npis; i++) {
  152. if (!st_lookup(net->hash,net->inputs[i],(void **)&node)) {
  153. return(0);
  154. }
  155. result = Bnet_BuildNodeBDD(dd,node,net->hash,
  156. option->locGlob,option->nodrop);
  157. if (result == 0) return(0);
  158. }
  159. for (i = 0; i < net->nlatches; i++) {
  160. if (!st_lookup(net->hash,net->latches[i][1],(void **)&node)) {
  161. return(0);
  162. }
  163. result = Bnet_BuildNodeBDD(dd,node,net->hash,
  164. option->locGlob,option->nodrop);
  165. if (result == 0) return(0);
  166. }
  167. } else if (option->ordering == PI_PS_GIVEN) {
  168. result = Bnet_ReadOrder(dd,option->orderPiPs,net,option->locGlob,
  169. option->nodrop);
  170. if (result == 0) return(0);
  171. } else {
  172. result = Bnet_DfsVariableOrder(dd,net);
  173. if (result == 0) return(0);
  174. }
  175. }
  176. /* At this point the BDDs of all primary inputs and present state
  177. ** variables have been built. */
  178. /* Currently noBuild doesn't do much. */
  179. if (option->noBuild == TRUE)
  180. return(1);
  181. if (option->locGlob == BNET_LOCAL_DD) {
  182. node = net->nodes;
  183. while (node != NULL) {
  184. result = Bnet_BuildNodeBDD(dd,node,net->hash,BNET_LOCAL_DD,TRUE);
  185. if (result == 0) {
  186. return(0);
  187. }
  188. if (pr > 2) {
  189. (void) fprintf(stdout,"%s",node->name);
  190. Cudd_PrintDebug(dd,node->dd,Cudd_ReadSize(dd),pr);
  191. }
  192. node = node->next;
  193. }
  194. } else { /* option->locGlob == BNET_GLOBAL_DD */
  195. /* Create BDDs with DFS from the primary outputs and the next
  196. ** state functions. If the inputs had not been ordered yet,
  197. ** this would result in a DFS order for the variables.
  198. */
  199. ntrInitializeCount(net,option);
  200. if (option->node != NULL &&
  201. option->closestCube == FALSE && option->dontcares == FALSE) {
  202. if (!st_lookup(net->hash,option->node,(void **)&node)) {
  203. return(0);
  204. }
  205. result = Bnet_BuildNodeBDD(dd,node,net->hash,BNET_GLOBAL_DD,
  206. option->nodrop);
  207. if (result == 0) return(0);
  208. } else {
  209. if (option->stateOnly == FALSE) {
  210. for (i = 0; i < net->npos; i++) {
  211. if (!st_lookup(net->hash,net->outputs[i],(void **)&node)) {
  212. continue;
  213. }
  214. result = Bnet_BuildNodeBDD(dd,node,net->hash,
  215. BNET_GLOBAL_DD,option->nodrop);
  216. if (result == 0) return(0);
  217. if (option->progress) {
  218. (void) fprintf(stdout,"%s\n",node->name);
  219. }
  220. #if 0
  221. Cudd_PrintDebug(dd,node->dd,net->ninputs,option->verb);
  222. #endif
  223. }
  224. }
  225. for (i = 0; i < net->nlatches; i++) {
  226. if (!st_lookup(net->hash,net->latches[i][0],(void **)&node)) {
  227. continue;
  228. }
  229. result = Bnet_BuildNodeBDD(dd,node,net->hash,BNET_GLOBAL_DD,
  230. option->nodrop);
  231. if (result == 0) return(0);
  232. if (option->progress) {
  233. (void) fprintf(stdout,"%s\n",node->name);
  234. }
  235. #if 0
  236. Cudd_PrintDebug(dd,node->dd,net->ninputs,option->verb);
  237. #endif
  238. }
  239. }
  240. /* Make sure all inputs have a DD and dereference the DDs of
  241. ** the nodes that are not reachable from the outputs.
  242. */
  243. for (i = 0; i < net->npis; i++) {
  244. if (!st_lookup(net->hash,net->inputs[i],(void **)&node)) {
  245. return(0);
  246. }
  247. result = Bnet_BuildNodeBDD(dd,node,net->hash,BNET_GLOBAL_DD,
  248. option->nodrop);
  249. if (result == 0) return(0);
  250. if (node->count == -1) Cudd_RecursiveDeref(dd,node->dd);
  251. }
  252. for (i = 0; i < net->nlatches; i++) {
  253. if (!st_lookup(net->hash,net->latches[i][1],(void **)&node)) {
  254. return(0);
  255. }
  256. result = Bnet_BuildNodeBDD(dd,node,net->hash,BNET_GLOBAL_DD,
  257. option->nodrop);
  258. if (result == 0) return(0);
  259. if (node->count == -1) Cudd_RecursiveDeref(dd,node->dd);
  260. }
  261. /* Dispose of the BDDs of the internal nodes if they have not
  262. ** been dropped already.
  263. */
  264. if (option->nodrop == TRUE) {
  265. for (node = net->nodes; node != NULL; node = node->next) {
  266. if (node->dd != NULL && node->count != -1 &&
  267. (node->type == BNET_INTERNAL_NODE ||
  268. node->type == BNET_INPUT_NODE ||
  269. node->type == BNET_PRESENT_STATE_NODE)) {
  270. Cudd_RecursiveDeref(dd,node->dd);
  271. if (node->type == BNET_INTERNAL_NODE) node->dd = NULL;
  272. }
  273. }
  274. }
  275. }
  276. return(1);
  277. } /* end of Ntr_buildDDs */
  278. /**
  279. @brief Builds the transition relation for a network.
  280. @return a pointer to the transition relation structure if
  281. successful; NULL otherwise.
  282. @sideeffect None
  283. */
  284. NtrPartTR *
  285. Ntr_buildTR(
  286. DdManager * dd /**< manager */,
  287. BnetNetwork * net /**< network */,
  288. NtrOptions * option /**< options */,
  289. int image /**< image type: monolithic ... */)
  290. {
  291. NtrPartTR *TR;
  292. DdNode *T, *delta, *support, *scan, *tmp, *preiabs, *prepabs;
  293. DdNode **part, **absicubes, **abspcubes, **nscube, *mnscube;
  294. DdNode **x, **y;
  295. DdNode **pi;
  296. int i;
  297. int xlevel;
  298. BnetNode *node;
  299. int *schedule;
  300. int depth = 0;
  301. /* Initialize transition relation structure. */
  302. TR = ALLOC(NtrPartTR,1);
  303. if (TR == NULL) goto endgame;
  304. TR->nlatches = net->nlatches;
  305. if (image == NTR_IMAGE_MONO) {
  306. TR->nparts = 1;
  307. } else if (image == NTR_IMAGE_PART || image == NTR_IMAGE_CLIP ||
  308. image == NTR_IMAGE_DEPEND) {
  309. TR->nparts = net->nlatches;
  310. } else {
  311. (void) fprintf(stderr,"Unrecognized image method (%d). Using part.\n",
  312. image);
  313. TR->nparts = net->nlatches;
  314. }
  315. TR->factors = Ntr_InitHeap(TR->nlatches);
  316. if (TR->factors == NULL) goto endgame;
  317. /* Allocate arrays for present state and next state variables. */
  318. TR->x = x = ALLOC(DdNode *,TR->nlatches);
  319. if (x == NULL) goto endgame;
  320. TR->y = y = ALLOC(DdNode *,TR->nlatches);
  321. if (y == NULL) goto endgame;
  322. /* Allocate array for primary input variables. */
  323. pi = ALLOC(DdNode *,net->npis);
  324. if (pi == NULL) goto endgame;
  325. /* Allocate array for partitioned transition relation. */
  326. part = ALLOC(DdNode *,net->nlatches);
  327. if (part == NULL) goto endgame;
  328. /* Allocate array of next state cubes. */
  329. nscube = ALLOC(DdNode *,net->nlatches);
  330. if (nscube == NULL) goto endgame;
  331. /* Allocate array for quantification schedule and initialize it. */
  332. schedule = ALLOC(int,Cudd_ReadSize(dd));
  333. if (schedule == NULL) goto endgame;
  334. for (i = 0; i < Cudd_ReadSize(dd); i++) {
  335. schedule[i] = -1;
  336. }
  337. /* Create partitioned transition relation from network. */
  338. TR->xw = Cudd_ReadOne(dd);
  339. Cudd_Ref(TR->xw);
  340. for (i = 0; i < net->nlatches; i++) {
  341. if (!st_lookup(net->hash,net->latches[i][1],(void **)&node)) {
  342. goto endgame;
  343. }
  344. x[i] = node->dd;
  345. Cudd_Ref(x[i]);
  346. /* Add present state variable to cube TR->xw. */
  347. tmp = Cudd_bddAnd(dd,TR->xw,x[i]);
  348. if (tmp == NULL) return(NULL); Cudd_Ref(tmp);
  349. Cudd_RecursiveDeref(dd,TR->xw);
  350. TR->xw = tmp;
  351. /* Create new y variable immediately above the x variable. */
  352. xlevel = Cudd_ReadPerm(dd,x[i]->index);
  353. y[i] = Cudd_bddNewVarAtLevel(dd,xlevel);
  354. Cudd_Ref(y[i]);
  355. /* Initialize cube of next state variables for this part. */
  356. nscube[i] = y[i];
  357. Cudd_Ref(nscube[i]);
  358. /* Group present and next state variable if so requested. */
  359. if (option->groupnsps != NTR_GROUP_NONE) {
  360. int method = option->groupnsps == NTR_GROUP_DEFAULT ?
  361. MTR_DEFAULT : MTR_FIXED;
  362. if (Cudd_MakeTreeNode(dd,y[i]->index,2,method) == NULL)
  363. goto endgame;
  364. }
  365. /* Get next state function and create transition relation part. */
  366. if (!st_lookup(net->hash,net->latches[i][0],(void **)&node)) {
  367. goto endgame;
  368. }
  369. delta = node->dd;
  370. if (image != NTR_IMAGE_DEPEND) {
  371. part[i] = Cudd_bddXnor(dd,delta,y[i]);
  372. if (part[i] == NULL) goto endgame;
  373. } else {
  374. part[i] = delta;
  375. }
  376. Cudd_Ref(part[i]);
  377. /* Collect scheduling info for this delta. At the end of this loop
  378. ** schedule[i] == j means that the variable of index i does not
  379. ** appear in any part with index greater than j, unless j == -1,
  380. ** in which case the variable appears in no part.
  381. */
  382. support = Cudd_Support(dd,delta);
  383. Cudd_Ref(support);
  384. scan = support;
  385. while (!Cudd_IsConstant(scan)) {
  386. schedule[scan->index] = i;
  387. scan = Cudd_T(scan);
  388. }
  389. Cudd_RecursiveDeref(dd,support);
  390. }
  391. /* Collect primary inputs. */
  392. for (i = 0; i < net->npis; i++) {
  393. if (!st_lookup(net->hash,net->inputs[i],(void **)&node)) {
  394. goto endgame;
  395. }
  396. pi[i] = node->dd;
  397. tmp = Cudd_bddAnd(dd,TR->xw,pi[i]);
  398. if (tmp == NULL) goto endgame; Cudd_Ref(tmp);
  399. Cudd_RecursiveDeref(dd,TR->xw);
  400. TR->xw = tmp;
  401. }
  402. /* Build abstraction cubes. First primary input variables that go
  403. ** in the abstraction cubes for both monolithic and partitioned
  404. ** transition relations. */
  405. absicubes = ALLOC(DdNode *, net->nlatches);
  406. if (absicubes == NULL) goto endgame;
  407. abspcubes = ALLOC(DdNode *, net->nlatches);
  408. if (abspcubes == NULL) goto endgame;
  409. for (i = 0; i < net->nlatches; i++) {
  410. absicubes[i] = Cudd_ReadOne(dd);
  411. Cudd_Ref(absicubes[i]);
  412. }
  413. preiabs = Cudd_ReadOne(dd);
  414. Cudd_Ref(preiabs);
  415. for (i = 0; i < net->npis; i++) {
  416. int j = pi[i]->index;
  417. int k = schedule[j];
  418. if (k >= 0) {
  419. tmp = Cudd_bddAnd(dd,absicubes[k],pi[i]);
  420. if (tmp == NULL) return(NULL); Cudd_Ref(tmp);
  421. Cudd_RecursiveDeref(dd,absicubes[k]);
  422. absicubes[k] = tmp;
  423. } else {
  424. tmp = Cudd_bddAnd(dd,preiabs,pi[i]);
  425. if (tmp == NULL) return(NULL); Cudd_Ref(tmp);
  426. Cudd_RecursiveDeref(dd,preiabs);
  427. preiabs = tmp;
  428. }
  429. }
  430. FREE(pi);
  431. /* Build preimage abstraction cubes from image abstraction cubes. */
  432. for (i = 0; i < net->nlatches; i++) {
  433. abspcubes[i] = Cudd_bddAnd(dd,absicubes[i],nscube[i]);
  434. if (abspcubes[i] == NULL) return(NULL);
  435. Cudd_Ref(abspcubes[i]);
  436. }
  437. Cudd_Ref(prepabs = preiabs);
  438. /* For partitioned transition relations we add present state variables
  439. ** to the image abstraction cubes. */
  440. if (image != NTR_IMAGE_MONO) {
  441. for (i = 0; i < net->nlatches; i++) {
  442. int j = x[i]->index;
  443. int k = schedule[j];
  444. if (k >= 0) {
  445. tmp = Cudd_bddAnd(dd,absicubes[k],x[i]);
  446. if (tmp == NULL) return(NULL); Cudd_Ref(tmp);
  447. Cudd_RecursiveDeref(dd,absicubes[k]);
  448. absicubes[k] = tmp;
  449. } else {
  450. tmp = Cudd_bddAnd(dd,preiabs,x[i]);
  451. if (tmp == NULL) return(NULL); Cudd_Ref(tmp);
  452. Cudd_RecursiveDeref(dd,preiabs);
  453. preiabs = tmp;
  454. }
  455. }
  456. }
  457. FREE(schedule);
  458. if (image != NTR_IMAGE_MONO) {
  459. TR->part = part;
  460. TR->icube = absicubes;
  461. TR->pcube = abspcubes;
  462. TR->nscube = nscube;
  463. TR->preiabs = preiabs;
  464. TR->prepabs = prepabs;
  465. return(TR);
  466. }
  467. /* Here we are building a monolithic TR. */
  468. /* Reinitialize the cube of variables to be quantified before
  469. ** image computation. */
  470. Cudd_RecursiveDeref(dd,preiabs);
  471. preiabs = Cudd_ReadOne(dd);
  472. Cudd_Ref(preiabs);
  473. if (option->imageClip != 1.0) {
  474. depth = (int) ((double) Cudd_ReadSize(dd) * option->imageClip);
  475. }
  476. /* Collapse transition relation. */
  477. T = Cudd_ReadOne(dd);
  478. Cudd_Ref(T);
  479. mnscube = Cudd_ReadOne(dd);
  480. Cudd_Ref(mnscube);
  481. for (i = 0; i < net->nlatches; i++) {
  482. /* Eliminate the primary inputs that do not appear in other parts. */
  483. if (depth != 0) {
  484. tmp = Cudd_bddClippingAndAbstract(dd,T,part[i],absicubes[i],
  485. depth,option->approx);
  486. } else {
  487. tmp = Cudd_bddAndAbstract(dd,T,part[i],absicubes[i]);
  488. }
  489. Cudd_Ref(tmp);
  490. Cudd_RecursiveDeref(dd,T);
  491. Cudd_RecursiveDeref(dd,part[i]);
  492. Cudd_RecursiveDeref(dd,absicubes[i]);
  493. Cudd_RecursiveDeref(dd,abspcubes[i]);
  494. if (option->threshold >= 0) {
  495. if (option->approx) {
  496. T = Cudd_RemapOverApprox(dd,tmp,2*net->nlatches,
  497. option->threshold,option->quality);
  498. } else {
  499. T = Cudd_RemapUnderApprox(dd,tmp,2*net->nlatches,
  500. option->threshold,option->quality);
  501. }
  502. } else {
  503. T = tmp;
  504. }
  505. if (T == NULL) return(NULL);
  506. Cudd_Ref(T);
  507. Cudd_RecursiveDeref(dd,tmp);
  508. /* Add the next state variables of this part to the cube of all
  509. ** next state variables. */
  510. tmp = Cudd_bddAnd(dd,mnscube,nscube[i]);
  511. if (tmp == NULL) return(NULL);
  512. Cudd_Ref(tmp);
  513. Cudd_RecursiveDeref(dd,mnscube);
  514. mnscube = tmp;
  515. Cudd_RecursiveDeref(dd,nscube[i]);
  516. (void) printf("@"); fflush(stdout);
  517. }
  518. (void) printf("\n");
  519. #if 0
  520. (void) printf("T"); Cudd_PrintDebug(dd,T,2*net->nlatches,2);
  521. #endif
  522. /* Clean up. */
  523. FREE(absicubes);
  524. FREE(abspcubes);
  525. FREE(part);
  526. FREE(nscube);
  527. TR->part = part = ALLOC(DdNode *,1);
  528. if (part == NULL) goto endgame;
  529. part[0] = T;
  530. /* Build cube of x (present state) variables for abstraction. */
  531. TR->icube = absicubes = ALLOC(DdNode *,1);
  532. if (absicubes == NULL) goto endgame;
  533. absicubes[0] = makecube(dd,x,TR->nlatches);
  534. if (absicubes[0] == NULL) return(0);
  535. Cudd_Ref(absicubes[0]);
  536. /* Build cube of y (next state) variables for abstraction. */
  537. TR->pcube = abspcubes = ALLOC(DdNode *,1);
  538. if (abspcubes == NULL) goto endgame;
  539. abspcubes[0] = makecube(dd,y,TR->nlatches);
  540. if (abspcubes[0] == NULL) return(0);
  541. Cudd_Ref(abspcubes[0]);
  542. TR->preiabs = preiabs;
  543. TR->prepabs = prepabs;
  544. TR->nscube = ALLOC(DdNode *,1);
  545. if (TR->nscube == NULL) return(NULL);
  546. TR->nscube[0] = mnscube;
  547. return(TR);
  548. endgame:
  549. return(NULL);
  550. } /* end of Ntr_buildTR */
  551. /**
  552. @brief Frees the transition relation for a network.
  553. @sideeffect None
  554. */
  555. void
  556. Ntr_freeTR(
  557. DdManager * dd,
  558. NtrPartTR * TR)
  559. {
  560. int i;
  561. for (i = 0; i < TR->nlatches; i++) {
  562. Cudd_RecursiveDeref(dd,TR->x[i]);
  563. Cudd_RecursiveDeref(dd,TR->y[i]);
  564. }
  565. FREE(TR->x);
  566. FREE(TR->y);
  567. for (i = 0; i < TR->nparts; i++) {
  568. Cudd_RecursiveDeref(dd,TR->part[i]);
  569. Cudd_RecursiveDeref(dd,TR->icube[i]);
  570. Cudd_RecursiveDeref(dd,TR->pcube[i]);
  571. Cudd_RecursiveDeref(dd,TR->nscube[i]);
  572. }
  573. FREE(TR->part);
  574. FREE(TR->icube);
  575. FREE(TR->pcube);
  576. FREE(TR->nscube);
  577. Cudd_RecursiveDeref(dd,TR->preiabs);
  578. Cudd_RecursiveDeref(dd,TR->prepabs);
  579. Cudd_RecursiveDeref(dd,TR->xw);
  580. Ntr_HeapForeach(TR->factors, ntrDecreaseRef, dd);
  581. Ntr_FreeHeap(TR->factors);
  582. FREE(TR);
  583. return;
  584. } /* end of Ntr_freeTR */
  585. /**
  586. @brief Makes a copy of a transition relation.
  587. @return a pointer to the copy if successful; NULL otherwise.
  588. @sideeffect None
  589. @see Ntr_buildTR Ntr_freeTR
  590. */
  591. NtrPartTR *
  592. Ntr_cloneTR(
  593. NtrPartTR *TR)
  594. {
  595. NtrPartTR *T;
  596. int nparts, nlatches, i;
  597. T = ALLOC(NtrPartTR,1);
  598. if (T == NULL) return(NULL);
  599. nparts = T->nparts = TR->nparts;
  600. nlatches = T->nlatches = TR->nlatches;
  601. T->part = ALLOC(DdNode *,nparts);
  602. if (T->part == NULL) {
  603. FREE(T);
  604. return(NULL);
  605. }
  606. T->icube = ALLOC(DdNode *,nparts);
  607. if (T->icube == NULL) {
  608. FREE(T->part);
  609. FREE(T);
  610. return(NULL);
  611. }
  612. T->pcube = ALLOC(DdNode *,nparts);
  613. if (T->pcube == NULL) {
  614. FREE(T->icube);
  615. FREE(T->part);
  616. FREE(T);
  617. return(NULL);
  618. }
  619. T->x = ALLOC(DdNode *,nlatches);
  620. if (T->x == NULL) {
  621. FREE(T->pcube);
  622. FREE(T->icube);
  623. FREE(T->part);
  624. FREE(T);
  625. return(NULL);
  626. }
  627. T->y = ALLOC(DdNode *,nlatches);
  628. if (T->y == NULL) {
  629. FREE(T->x);
  630. FREE(T->pcube);
  631. FREE(T->icube);
  632. FREE(T->part);
  633. FREE(T);
  634. return(NULL);
  635. }
  636. T->nscube = ALLOC(DdNode *,nparts);
  637. if (T->nscube == NULL) {
  638. FREE(T->y);
  639. FREE(T->x);
  640. FREE(T->pcube);
  641. FREE(T->icube);
  642. FREE(T->part);
  643. FREE(T);
  644. return(NULL);
  645. }
  646. T->factors = Ntr_HeapClone(TR->factors);
  647. if (T->factors == NULL) {
  648. FREE(T->nscube);
  649. FREE(T->y);
  650. FREE(T->x);
  651. FREE(T->pcube);
  652. FREE(T->icube);
  653. FREE(T->part);
  654. FREE(T);
  655. return(NULL);
  656. }
  657. Ntr_HeapForeach(T->factors, ntrIncreaseRef, NULL);
  658. for (i = 0; i < nparts; i++) {
  659. T->part[i] = TR->part[i];
  660. Cudd_Ref(T->part[i]);
  661. T->icube[i] = TR->icube[i];
  662. Cudd_Ref(T->icube[i]);
  663. T->pcube[i] = TR->pcube[i];
  664. Cudd_Ref(T->pcube[i]);
  665. T->nscube[i] = TR->nscube[i];
  666. Cudd_Ref(T->nscube[i]);
  667. }
  668. T->preiabs = TR->preiabs;
  669. Cudd_Ref(T->preiabs);
  670. T->prepabs = TR->prepabs;
  671. Cudd_Ref(T->prepabs);
  672. T->xw = TR->xw;
  673. Cudd_Ref(T->xw);
  674. for (i = 0; i < nlatches; i++) {
  675. T->x[i] = TR->x[i];
  676. Cudd_Ref(T->x[i]);
  677. T->y[i] = TR->y[i];
  678. Cudd_Ref(T->y[i]);
  679. }
  680. return(T);
  681. } /* end of Ntr_cloneTR */
  682. /**
  683. @brief Poor man's traversal procedure.
  684. @details Based on the monolithic transition relation.
  685. @return 1 in case of success; 0 otherwise.
  686. @sideeffect None
  687. @see Ntr_ClosureTrav
  688. */
  689. int
  690. Ntr_Trav(
  691. DdManager * dd /**< %DD manager */,
  692. BnetNetwork * net /**< network */,
  693. NtrOptions * option /**< options */)
  694. {
  695. NtrPartTR *TR; /* Transition relation */
  696. DdNode *init; /* initial state(s) */
  697. DdNode *from;
  698. DdNode *to;
  699. DdNode *reached;
  700. DdNode *neW;
  701. DdNode *one, *zero;
  702. int depth;
  703. int retval;
  704. int pr = option->verb;
  705. unsigned int initReord = Cudd_ReadReorderings(dd);
  706. if (option->traverse == FALSE || net->nlatches == 0) return(1);
  707. (void) printf("Building transition relation. Time = %s\n",
  708. util_print_time(util_cpu_time() - option->initialTime));
  709. one = Cudd_ReadOne(dd);
  710. zero = Cudd_Not(one);
  711. /* Build transition relation and initial states. */
  712. TR = Ntr_buildTR(dd,net,option,option->image);
  713. if (TR == NULL) return(0);
  714. retval = Cudd_SetVarMap(dd,TR->x,TR->y,TR->nlatches);
  715. if (retval == 0) return(0);
  716. (void) printf("Transition relation: %d parts %d latches %d nodes\n",
  717. TR->nparts, TR->nlatches,
  718. Cudd_SharingSize(TR->part, TR->nparts));
  719. (void) printf("Traversing. Time = %s\n",
  720. util_print_time(util_cpu_time() - option->initialTime));
  721. init = Ntr_initState(dd,net,option);
  722. if (init == NULL) return(0);
  723. /* Initialize From. */
  724. Cudd_Ref(from = init);
  725. (void) printf("S0"); Cudd_PrintDebug(dd,from,TR->nlatches,pr);
  726. /* Initialize Reached. */
  727. Cudd_Ref(reached = from);
  728. /* Start traversal. */
  729. for (depth = 0; ; depth++) {
  730. /* Image computation. */
  731. to = ntrImage(dd,TR,from,option);
  732. if (to == NULL) {
  733. Cudd_RecursiveDeref(dd,reached);
  734. Cudd_RecursiveDeref(dd,from);
  735. return(0);
  736. }
  737. Cudd_RecursiveDeref(dd,from);
  738. /* Find new states. */
  739. neW = Cudd_bddAnd(dd,to,Cudd_Not(reached));
  740. if (neW == NULL) {
  741. Cudd_RecursiveDeref(dd,reached);
  742. Cudd_RecursiveDeref(dd,to);
  743. return(0);
  744. }
  745. Cudd_Ref(neW);
  746. Cudd_RecursiveDeref(dd,to);
  747. /* Check for convergence. */
  748. if (neW == zero) break;
  749. /* Dump current reached states if requested. */
  750. if (option->store == depth) {
  751. int ok = Dddmp_cuddBddStore(dd, NULL, reached, NULL,
  752. NULL, DDDMP_MODE_TEXT, DDDMP_VARIDS,
  753. option->storefile, NULL);
  754. if (ok == 0) return(0);
  755. (void) printf("Storing reached in %s after %i iterations.\n",
  756. option->storefile, depth);
  757. break;
  758. }
  759. /* Update reached. */
  760. reached = ntrUpdateReached(dd,reached,neW);
  761. if (reached == NULL) {
  762. Cudd_RecursiveDeref(dd,neW);
  763. return(0);
  764. }
  765. /* Prepare for new iteration. */
  766. from = ntrChooseFrom(dd,neW,reached,option);
  767. if (from == NULL) {
  768. Cudd_RecursiveDeref(dd,reached);
  769. Cudd_RecursiveDeref(dd,neW);
  770. return(0);
  771. }
  772. Cudd_RecursiveDeref(dd,neW);
  773. (void) printf("From[%d]",depth+1);
  774. Cudd_PrintDebug(dd,from,TR->nlatches,pr);
  775. (void) printf("Reached[%d]",depth+1);
  776. Cudd_PrintDebug(dd,reached,TR->nlatches,pr);
  777. if (pr > 0) {
  778. if (!Cudd_ApaPrintMinterm(stdout, dd, reached, TR->nlatches))
  779. return(0);
  780. if (!Cudd_ApaPrintMintermExp(stdout, dd, reached, TR->nlatches, 6))
  781. return(0);
  782. } else {
  783. (void) printf("\n");
  784. }
  785. }
  786. /* Print out result. */
  787. (void) printf("depth = %d\n", depth);
  788. (void) printf("R"); Cudd_PrintDebug(dd,reached,TR->nlatches,pr);
  789. /* Dump to file if requested. */
  790. if (option->bdddump) {
  791. DdNode *dfunc[2]; /* addresses of the functions to be dumped */
  792. char *onames[2]; /* names of the functions to be dumped */
  793. dfunc[0] = TR->part[0]; onames[0] = (char *) "T";
  794. dfunc[1] = reached; onames[1] = (char *) "R";
  795. retval = Bnet_bddArrayDump(dd, net, option->dumpfile, dfunc,
  796. onames, 2, option->dumpFmt);
  797. if (retval == 0) return(0);
  798. }
  799. if (option->depend) {
  800. retval = ntrLatchDependencies(dd, reached, net, option);
  801. if (retval == -1) return(0);
  802. (void) printf("%d latches are redundant\n", retval);
  803. }
  804. /* Clean up. */
  805. Cudd_RecursiveDeref(dd,reached);
  806. Cudd_RecursiveDeref(dd,neW);
  807. Cudd_RecursiveDeref(dd,init);
  808. Ntr_freeTR(dd,TR);
  809. if (Cudd_ReadReorderings(dd) > initReord) {
  810. (void) printf("Order at the end of reachability analysis\n");
  811. retval = Bnet_PrintOrder(net,dd);
  812. if (retval == 0) return(0);
  813. }
  814. return(1);
  815. } /* end of Ntr_Trav */
  816. /**
  817. @brief Computes the SCCs of the STG.
  818. @details Computes the strongly connected components of the state
  819. transition graph. Only the first 10 SCCs are computed.
  820. @return 1 in case of success; 0 otherwise.
  821. @sideeffect None
  822. @see Ntr_Trav
  823. */
  824. int
  825. Ntr_SCC(
  826. DdManager * dd /**< %DD manager */,
  827. BnetNetwork * net /**< network */,
  828. NtrOptions * option /**< options */)
  829. {
  830. NtrPartTR *TR; /* Transition relation */
  831. DdNode *init; /* initial state(s) */
  832. DdNode *from;
  833. DdNode *to;
  834. DdNode *reached, *reaching;
  835. DdNode *neW;
  836. DdNode *one, *zero;
  837. DdNode *states, *scc;
  838. DdNode *tmp = NULL;
  839. DdNode *SCCs[10];
  840. int depth;
  841. int nscc = 0;
  842. int retval;
  843. int pr = option->verb;
  844. int i;
  845. if (option->scc == FALSE || net->nlatches == 0) return(1);
  846. (void) printf("Building transition relation. Time = %s\n",
  847. util_print_time(util_cpu_time() - option->initialTime));
  848. one = Cudd_ReadOne(dd);
  849. zero = Cudd_Not(one);
  850. /* Build transition relation and initial states. */
  851. TR = Ntr_buildTR(dd,net,option,option->image);
  852. if (TR == NULL) return(0);
  853. retval = Cudd_SetVarMap(dd,TR->x,TR->y,TR->nlatches);
  854. if (retval == 0) return(0);
  855. (void) printf("Transition relation: %d parts %d latches %d nodes\n",
  856. TR->nparts, TR->nlatches,
  857. Cudd_SharingSize(TR->part, TR->nparts));
  858. (void) printf("Computing SCCs. Time = %s\n",
  859. util_print_time(util_cpu_time() - option->initialTime));
  860. /* Consider all SCCs, including those not reachable. */
  861. states = one;
  862. Cudd_Ref(states);
  863. while (states != zero) {
  864. if (nscc == 0) {
  865. tmp = Ntr_initState(dd,net,option);
  866. if (tmp == NULL) return(0);
  867. init = Cudd_bddPickOneMinterm(dd,tmp,TR->x,TR->nlatches);
  868. } else {
  869. init = Cudd_bddPickOneMinterm(dd,states,TR->x,TR->nlatches);
  870. }
  871. if (init == NULL) return(0);
  872. Cudd_Ref(init);
  873. if (nscc == 0) {
  874. Cudd_RecursiveDeref(dd,tmp);
  875. }
  876. /* Initialize From. */
  877. Cudd_Ref(from = init);
  878. (void) printf("S0"); Cudd_PrintDebug(dd,from,TR->nlatches,pr);
  879. /* Initialize Reached. */
  880. Cudd_Ref(reached = from);
  881. /* Start forward traversal. */
  882. for (depth = 0; ; depth++) {
  883. /* Image computation. */
  884. to = ntrImage(dd,TR,from,option);
  885. if (to == NULL) {
  886. return(0);
  887. }
  888. Cudd_RecursiveDeref(dd,from);
  889. /* Find new states. */
  890. tmp = Cudd_bddAnd(dd,to,states);
  891. if (tmp == NULL) return(0); Cudd_Ref(tmp);
  892. Cudd_RecursiveDeref(dd,to);
  893. neW = Cudd_bddAnd(dd,tmp,Cudd_Not(reached));
  894. if (neW == NULL) return(0); Cudd_Ref(neW);
  895. Cudd_RecursiveDeref(dd,tmp);
  896. /* Check for convergence. */
  897. if (neW == zero) break;
  898. /* Update reached. */
  899. reached = ntrUpdateReached(dd,reached,neW);
  900. if (reached == NULL) {
  901. return(0);
  902. }
  903. /* Prepare for new iteration. */
  904. from = ntrChooseFrom(dd,neW,reached,option);
  905. if (from == NULL) {
  906. return(0);
  907. }
  908. Cudd_RecursiveDeref(dd,neW);
  909. (void) printf("From[%d]",depth+1);
  910. Cudd_PrintDebug(dd,from,TR->nlatches,pr);
  911. (void) printf("Reached[%d]",depth+1);
  912. Cudd_PrintDebug(dd,reached,TR->nlatches,pr);
  913. if (pr <= 0) {
  914. (void) printf("\n");
  915. }
  916. }
  917. Cudd_RecursiveDeref(dd,neW);
  918. /* Express reached in terms of y variables. This allows us to
  919. ** efficiently test for termination during the backward traversal. */
  920. tmp = Cudd_bddVarMap(dd,reached);
  921. if (tmp == NULL) return(0);
  922. Cudd_Ref(tmp);
  923. Cudd_RecursiveDeref(dd,reached);
  924. reached = tmp;
  925. /* Initialize from and reaching. */
  926. from = Cudd_bddVarMap(dd,init);
  927. Cudd_Ref(from);
  928. (void) printf("S0"); Cudd_PrintDebug(dd,from,TR->nlatches,pr);
  929. Cudd_Ref(reaching = from);
  930. /* Start backward traversal. */
  931. for (depth = 0; ; depth++) {
  932. /* Preimage computation. */
  933. to = ntrPreimage(dd,TR,from);
  934. if (to == NULL) {
  935. return(0);
  936. }
  937. Cudd_RecursiveDeref(dd,from);
  938. /* Find new states. */
  939. tmp = Cudd_bddAnd(dd,to,reached);
  940. if (tmp == NULL) return(0); Cudd_Ref(tmp);
  941. Cudd_RecursiveDeref(dd,to);
  942. neW = Cudd_bddAnd(dd,tmp,Cudd_Not(reaching));
  943. if (neW == NULL) return(0); Cudd_Ref(neW);
  944. Cudd_RecursiveDeref(dd,tmp);
  945. /* Check for convergence. */
  946. if (neW == zero) break;
  947. /* Update reaching. */
  948. reaching = ntrUpdateReached(dd,reaching,neW);
  949. if (reaching == NULL) {
  950. return(0);
  951. }
  952. /* Prepare for new iteration. */
  953. from = ntrChooseFrom(dd,neW,reaching,option);
  954. if (from == NULL) {
  955. return(0);
  956. }
  957. Cudd_RecursiveDeref(dd,neW);
  958. (void) printf("From[%d]",depth+1);
  959. Cudd_PrintDebug(dd,from,TR->nlatches,pr);
  960. (void) printf("Reaching[%d]",depth+1);
  961. Cudd_PrintDebug(dd,reaching,TR->nlatches,pr);
  962. if (pr <= 0) {
  963. (void) printf("\n");
  964. }
  965. }
  966. scc = Cudd_bddAnd(dd,reached,reaching);
  967. if (scc == NULL) {
  968. return(0);
  969. }
  970. Cudd_Ref(scc);
  971. SCCs[nscc] = Cudd_bddVarMap(dd,scc);
  972. if (SCCs[nscc] == NULL) return(0);
  973. Cudd_Ref(SCCs[nscc]);
  974. Cudd_RecursiveDeref(dd,scc);
  975. /* Print out result. */
  976. (void) printf("SCC[%d]",nscc);
  977. Cudd_PrintDebug(dd,SCCs[nscc],TR->nlatches,pr);
  978. tmp = Cudd_bddAnd(dd,states,Cudd_Not(SCCs[nscc]));
  979. if (tmp == NULL) {
  980. return(0);
  981. }
  982. Cudd_Ref(tmp);
  983. Cudd_RecursiveDeref(dd,states);
  984. states = tmp;
  985. Cudd_RecursiveDeref(dd,reached);
  986. Cudd_RecursiveDeref(dd,reaching);
  987. Cudd_RecursiveDeref(dd,neW);
  988. Cudd_RecursiveDeref(dd,init);
  989. nscc++;
  990. if (nscc > 9) break;
  991. }
  992. if (states != zero) {
  993. (void) fprintf(stdout,"More than 10 SCCs. Only the first 10 are computed.\n");
  994. }
  995. /* Dump to file if requested. */
  996. if (option->bdddump) {
  997. char *sccnames[10]; /* names of the SCCs */
  998. sccnames[0] = (char *) "SCC0";
  999. sccnames[1] = (char *) "SCC1";
  1000. sccnames[2] = (char *) "SCC2";
  1001. sccnames[3] = (char *) "SCC3";
  1002. sccnames[4] = (char *) "SCC4";
  1003. sccnames[5] = (char *) "SCC5";
  1004. sccnames[6] = (char *) "SCC6";
  1005. sccnames[7] = (char *) "SCC7";
  1006. sccnames[8] = (char *) "SCC8";
  1007. sccnames[9] = (char *) "SCC9";
  1008. retval = Bnet_bddArrayDump(dd, net, option->dumpfile, SCCs,
  1009. sccnames, nscc, option->dumpFmt);
  1010. if (retval == 0) return(0);
  1011. }
  1012. /* Verify that the SCCs form a partition of the universe. */
  1013. scc = zero;
  1014. Cudd_Ref(scc);
  1015. for (i = 0; i < nscc; i++) {
  1016. assert(Cudd_bddLeq(dd,SCCs[i],Cudd_Not(scc)));
  1017. tmp = Cudd_bddOr(dd,SCCs[i],scc);
  1018. if (tmp == NULL) return(0);
  1019. Cudd_Ref(tmp);
  1020. Cudd_RecursiveDeref(dd,scc);
  1021. scc = tmp;
  1022. Cudd_RecursiveDeref(dd,SCCs[i]);
  1023. }
  1024. assert(scc == Cudd_Not(states));
  1025. /* Clean up. */
  1026. Cudd_RecursiveDeref(dd,scc);
  1027. Cudd_RecursiveDeref(dd,states);
  1028. Ntr_freeTR(dd,TR);
  1029. return(1);
  1030. } /* end of Ntr_SCC */
  1031. /**
  1032. @brief Transitive closure traversal procedure.
  1033. @details Traversal procedure based on the transitive closure of the
  1034. transition relation.
  1035. @return 1 in case of success; 0 otherwise.
  1036. @sideeffect None
  1037. @see Ntr_Trav
  1038. */
  1039. int
  1040. Ntr_ClosureTrav(
  1041. DdManager * dd /**< %DD manager */,
  1042. BnetNetwork * net /**< network */,
  1043. NtrOptions * option /**< options */)
  1044. {
  1045. DdNode *init;
  1046. DdNode *T;
  1047. NtrPartTR *TR;
  1048. int retval;
  1049. int pr = option->verb; /* verbosity level */
  1050. DdNode *dfunc[2]; /* addresses of the functions to be dumped */
  1051. char *onames[2]; /* names of the functions to be dumped */
  1052. DdNode *reached, *reachedy, *reachedx;
  1053. /* Traverse if requested and if the circuit is sequential. */
  1054. if (option->closure == FALSE || net->nlatches == 0) return(1);
  1055. TR = Ntr_buildTR(dd,net,option,NTR_IMAGE_MONO);
  1056. if (TR == NULL) return(0);
  1057. (void) printf("TR"); Cudd_PrintDebug(dd,TR->part[0],2*TR->nlatches,pr);
  1058. T = Ntr_TransitiveClosure(dd,TR,option);
  1059. if (T == NULL) return(0);
  1060. Cudd_Ref(T);
  1061. (void) printf("TC"); Cudd_PrintDebug(dd,T,2*TR->nlatches,pr);
  1062. init = Ntr_initState(dd,net,option);
  1063. if (init == NULL) return(0);
  1064. (void) printf("S0"); Cudd_PrintDebug(dd,init,TR->nlatches,pr);
  1065. /* Image computation. */
  1066. if (option->closureClip != 1.0) {
  1067. int depth = (int) ((double) Cudd_ReadSize(dd) * option->closureClip);
  1068. reachedy = Cudd_bddClippingAndAbstract(dd,T,init,TR->icube[0],
  1069. depth,option->approx);
  1070. } else {
  1071. reachedy = Cudd_bddAndAbstract(dd,T,init,TR->icube[0]);
  1072. }
  1073. if (reachedy == NULL) return(0);
  1074. Cudd_Ref(reachedy);
  1075. /* Express in terms of present state variables. */
  1076. reachedx = Cudd_bddSwapVariables(dd,reachedy,TR->x,TR->y,TR->nlatches);
  1077. if (reachedx == NULL) return(0);
  1078. Cudd_Ref(reachedx);
  1079. Cudd_RecursiveDeref(dd,reachedy);
  1080. /* Add initial state. */
  1081. reached = Cudd_bddOr(dd,reachedx,init);
  1082. if (reached == NULL) return(0);
  1083. Cudd_Ref(reached);
  1084. Cudd_RecursiveDeref(dd,reachedx);
  1085. /* Print out result. */
  1086. (void) printf("R"); Cudd_PrintDebug(dd,reached,TR->nlatches,pr);
  1087. /* Dump to file if requested. */
  1088. if (option->bdddump) {
  1089. dfunc[0] = T; onames[0] = (char *) "TC";
  1090. dfunc[1] = reached; onames[1] = (char *) "R";
  1091. retval = Bnet_bddArrayDump(dd, net, option->dumpfile, dfunc,
  1092. onames, 2, option->dumpFmt);
  1093. if (retval == 0) return(0);
  1094. }
  1095. /* Clean up. */
  1096. Cudd_RecursiveDeref(dd,reached);
  1097. Cudd_RecursiveDeref(dd,init);
  1098. Cudd_RecursiveDeref(dd,T);
  1099. Ntr_freeTR(dd,TR);
  1100. return(1);
  1101. } /* end of Ntr_ClosureTrav */
  1102. /**
  1103. @brief Builds the transitive closure of a transition relation.
  1104. @details Uses a simple squaring algorithm.
  1105. @return a %BDD if successful; NULL otherwise.
  1106. @sideeffect None
  1107. */
  1108. DdNode *
  1109. Ntr_TransitiveClosure(
  1110. DdManager * dd,
  1111. NtrPartTR * TR,
  1112. NtrOptions * option)
  1113. {
  1114. DdNode *T,*oldT,*Txz,*Tzy,*Tred,*square,*zcube;
  1115. DdNode **z;
  1116. int i;
  1117. int depth = 0;
  1118. int ylevel;
  1119. int done;
  1120. if (option->image != NTR_IMAGE_MONO) return(NULL);
  1121. /* Create array of auxiliary variables. */
  1122. z = ALLOC(DdNode *,TR->nlatches);
  1123. if (z == NULL)
  1124. return(NULL);
  1125. for (i = 0; i < TR->nlatches; i++) {
  1126. ylevel = Cudd_ReadIndex(dd,TR->y[i]->index);
  1127. z[i] = Cudd_bddNewVarAtLevel(dd,ylevel);
  1128. if (z[i] == NULL)
  1129. return(NULL);
  1130. }
  1131. /* Build cube of auxiliary variables. */
  1132. zcube = makecube(dd,z,TR->nlatches);
  1133. if (zcube == NULL) return(NULL);
  1134. Cudd_Ref(zcube);
  1135. if (option->closureClip != 1.0) {
  1136. depth = (int) ((double) Cudd_ReadSize(dd) * option->imageClip);
  1137. }
  1138. T = TR->part[0];
  1139. Cudd_Ref(T);
  1140. for (i = 0; ; i++) {
  1141. if (option->threshold >= 0) {
  1142. if (option->approx) {
  1143. Tred = Cudd_RemapOverApprox(dd,T,TR->nlatches*2,
  1144. option->threshold,
  1145. option->quality);
  1146. } else {
  1147. Tred = Cudd_RemapUnderApprox(dd,T,TR->nlatches*2,
  1148. option->threshold,
  1149. option->quality);
  1150. }
  1151. } else {
  1152. Tred = T;
  1153. }
  1154. if (Tred == NULL) return(NULL);
  1155. Cudd_Ref(Tred);
  1156. /* Express T in terms of z and y variables. */
  1157. Tzy = Cudd_bddSwapVariables(dd,Tred,TR->x,z,TR->nlatches);
  1158. if (Tzy == NULL) return(NULL);
  1159. Cudd_Ref(Tzy);
  1160. /* Express T in terms of x and z variables. */
  1161. Txz = Cudd_bddSwapVariables(dd,Tred,TR->y,z,TR->nlatches);
  1162. if (Txz == NULL) return(NULL);
  1163. Cudd_Ref(Txz);
  1164. Cudd_RecursiveDeref(dd,Tred);
  1165. /* Square */
  1166. if (depth == 0) {
  1167. square = Cudd_bddAndAbstract(dd,Txz,Tzy,zcube);
  1168. } else {
  1169. square = Cudd_bddClippingAndAbstract(dd,Txz,Tzy,zcube,depth,
  1170. option->approx);
  1171. }
  1172. if (square == NULL) return(NULL);
  1173. Cudd_Ref(square);
  1174. Cudd_RecursiveDeref(dd,Tzy);
  1175. Cudd_RecursiveDeref(dd,Txz);
  1176. oldT = T;
  1177. T = Cudd_bddOr(dd,square,TR->part[0]);
  1178. if (T == NULL) return(NULL);
  1179. Cudd_Ref(T);
  1180. Cudd_RecursiveDeref(dd,square);
  1181. done = T == oldT;
  1182. Cudd_RecursiveDeref(dd,oldT);
  1183. if (done) break;
  1184. (void) fprintf(stdout,"@"); fflush(stdout);
  1185. }
  1186. (void) fprintf(stdout, "\n");
  1187. Cudd_RecursiveDeref(dd,zcube);
  1188. Cudd_Deref(T);
  1189. FREE(z);
  1190. return(T);
  1191. } /* end of Ntr_TransitiveClosure */
  1192. /**
  1193. @brief Builds the %BDD of the initial state(s).
  1194. @return a %BDD if successful; NULL otherwise.
  1195. @sideeffect None
  1196. */
  1197. DdNode *
  1198. Ntr_initState(
  1199. DdManager * dd,
  1200. BnetNetwork * net,
  1201. NtrOptions * option)
  1202. {
  1203. DdNode *res, *x, *w, *one;
  1204. BnetNode *node;
  1205. int i;
  1206. if (option->load) {
  1207. res = Dddmp_cuddBddLoad(dd, DDDMP_VAR_MATCHIDS, NULL, NULL, NULL,
  1208. DDDMP_MODE_DEFAULT, option->loadfile, NULL);
  1209. } else {
  1210. one = Cudd_ReadOne(dd);
  1211. Cudd_Ref(res = one);
  1212. if (net->nlatches == 0) return(res);
  1213. for (i = 0; i < net->nlatches; i++) {
  1214. if (!st_lookup(net->hash,net->latches[i][1],(void **)&node)) {
  1215. goto endgame;
  1216. }
  1217. x = node->dd;
  1218. switch (net->latches[i][2][0]) {
  1219. case '0':
  1220. w = Cudd_bddAnd(dd,res,Cudd_Not(x));
  1221. break;
  1222. case '1':
  1223. w = Cudd_bddAnd(dd,res,x);
  1224. break;
  1225. default: /* don't care */
  1226. w = res;
  1227. break;
  1228. }
  1229. if (w == NULL) {
  1230. Cudd_RecursiveDeref(dd,res);
  1231. return(NULL);
  1232. }
  1233. Cudd_Ref(w);
  1234. Cudd_RecursiveDeref(dd,res);
  1235. res = w;
  1236. }
  1237. }
  1238. return(res);
  1239. endgame:
  1240. return(NULL);
  1241. } /* end of Ntr_initState */
  1242. /**
  1243. @brief Reads a state cube from a file or creates a random one.
  1244. @return a pointer to the %BDD of the sink nodes if successful; NULL
  1245. otherwise.
  1246. @sideeffect None
  1247. */
  1248. DdNode *
  1249. Ntr_getStateCube(
  1250. DdManager * dd,
  1251. BnetNetwork * net,
  1252. char * filename,
  1253. int pr)
  1254. {
  1255. FILE *fp;
  1256. DdNode *cube;
  1257. DdNode *w;
  1258. char *state;
  1259. int i;
  1260. int err;
  1261. BnetNode *node;
  1262. DdNode *x;
  1263. char c[2];
  1264. cube = Cudd_ReadOne(dd);
  1265. if (net->nlatches == 0) {
  1266. Cudd_Ref(cube);
  1267. return(cube);
  1268. }
  1269. state = ALLOC(char,net->nlatches+1);
  1270. if (state == NULL)
  1271. return(NULL);
  1272. state[net->nlatches] = 0;
  1273. if (filename == NULL) {
  1274. /* Pick one random minterm. */
  1275. for (i = 0; i < net->nlatches; i++) {
  1276. state[i] = (char) ((Cudd_Random(dd) & 0x2000) ? '1' : '0');
  1277. }
  1278. } else {
  1279. if ((fp = fopen(filename,"r")) == NULL) {
  1280. (void) fprintf(stderr,"Unable to open %s\n",filename);
  1281. return(NULL);
  1282. }
  1283. /* Read string from file. Allow arbitrary amount of white space. */
  1284. for (i = 0; !feof(fp); i++) {
  1285. err = fscanf(fp, "%1s", c);
  1286. state[i] = c[0];
  1287. if (err == EOF || i == net->nlatches - 1) {
  1288. break;
  1289. } else if (err != 1 || strchr("012xX-", c[0]) == NULL ) {
  1290. FREE(state);
  1291. return(NULL);
  1292. }
  1293. }
  1294. err = fclose(fp);
  1295. if (err == EOF) {
  1296. FREE(state);
  1297. return(NULL);
  1298. }
  1299. }
  1300. /* Echo the chosen state(s). */
  1301. if (pr > 0) {(void) fprintf(stdout,"%s\n", state);}
  1302. Cudd_Ref(cube);
  1303. for (i = 0; i < net->nlatches; i++) {
  1304. if (!st_lookup(net->hash,net->latches[i][1],(void **)&node)) {
  1305. Cudd_RecursiveDeref(dd,cube);
  1306. FREE(state);
  1307. return(NULL);
  1308. }
  1309. x = node->dd;
  1310. switch (state[i]) {
  1311. case '0':
  1312. w = Cudd_bddAnd(dd,cube,Cudd_Not(x));
  1313. break;
  1314. case '1':
  1315. w = Cudd_bddAnd(dd,cube,x);
  1316. break;
  1317. default: /* don't care */
  1318. w = cube;
  1319. break;
  1320. }
  1321. if (w == NULL) {
  1322. Cudd_RecursiveDeref(dd,cube);
  1323. FREE(state);
  1324. return(NULL);
  1325. }
  1326. Cudd_Ref(w);
  1327. Cudd_RecursiveDeref(dd,cube);
  1328. cube = w;
  1329. }
  1330. FREE(state);
  1331. return(cube);
  1332. } /* end of Ntr_getStateCube */
  1333. /**
  1334. @brief Poor man's outer envelope computation.
  1335. @details Based on the monolithic transition relation.
  1336. @return 1 in case of success; 0 otherwise.
  1337. @sideeffect None
  1338. */
  1339. int
  1340. Ntr_Envelope(
  1341. DdManager * dd /**< %DD manager */,
  1342. NtrPartTR * TR /**< transition relation */,
  1343. FILE * dfp /**< pointer to file for %DD dump */,
  1344. NtrOptions * option /**< program options */)
  1345. {
  1346. DdNode **x; /* array of x variables */
  1347. DdNode **y; /* array of y variables */
  1348. int ns; /* number of x and y variables */
  1349. DdNode *dfunc[2]; /* addresses of the functions to be dumped */
  1350. DdNode *envelope, *oldEnvelope;
  1351. DdNode *one;
  1352. int depth;
  1353. int retval;
  1354. int pr = option->verb;
  1355. int dumpFmt = option->dumpFmt;
  1356. x = TR->x;
  1357. y = TR->y;
  1358. ns = TR->nlatches;
  1359. one = Cudd_ReadOne(dd);
  1360. retval = Cudd_SetVarMap(dd,x,y,ns);
  1361. if (retval == 0) return(0);
  1362. /* Initialize From. */
  1363. envelope = one;
  1364. if (envelope == NULL) return(0);
  1365. Cudd_Ref(envelope);
  1366. (void) printf("S0"); Cudd_PrintDebug(dd,envelope,ns,pr);
  1367. /* Start traversal. */
  1368. for (depth = 0; ; depth++) {
  1369. oldEnvelope = envelope;
  1370. /* Image computation. */
  1371. envelope = ntrImage(dd,TR,oldEnvelope,option);
  1372. if (envelope == NULL) {
  1373. Cudd_RecursiveDeref(dd,oldEnvelope);
  1374. return(0);
  1375. }
  1376. /* Check for convergence. */
  1377. if (envelope == oldEnvelope) break;
  1378. /* Prepare for new iteration. */
  1379. Cudd_RecursiveDeref(dd,oldEnvelope);
  1380. (void) fprintf(stdout,"Envelope[%d]%s",depth+1,(pr>0)? "" : "\n");
  1381. if (pr > 0 ) {
  1382. Cudd_PrintSummary(dd, envelope, ns, 1 /* exponential format */);
  1383. }
  1384. }
  1385. /* Clean up. */
  1386. Cudd_RecursiveDeref(dd,oldEnvelope);
  1387. /* Print out result. */
  1388. (void) printf("depth = %d\n", depth);
  1389. (void) printf("Envelope"); Cudd_PrintDebug(dd,envelope,ns,pr);
  1390. /* Write dump file if requested. */
  1391. if (dfp != NULL) {
  1392. dfunc[0] = TR->part[0];
  1393. dfunc[1] = envelope;
  1394. if (dumpFmt == 1) {
  1395. retval = Cudd_DumpBlif(dd,2,dfunc,NULL,(char const * const *)onames,NULL,dfp,0);
  1396. } else if (dumpFmt == 2) {
  1397. retval = Cudd_DumpDaVinci(dd,2,dfunc,NULL,
  1398. (char const * const *)onames,dfp);
  1399. } else if (dumpFmt == 3) {
  1400. retval = Cudd_DumpDDcal(dd,2,dfunc,NULL,
  1401. (char const * const *)onames,dfp);
  1402. } else if (dumpFmt == 4) {
  1403. retval = Cudd_DumpFactoredForm(dd,2,dfunc,NULL,
  1404. (char const * const *)onames,dfp);
  1405. } else if (dumpFmt == 5) {
  1406. retval = Cudd_DumpBlif(dd,2,dfunc,NULL,
  1407. (char const * const *)onames,NULL,dfp,1);
  1408. } else {
  1409. retval = Cudd_DumpDot(dd,2,dfunc,NULL,
  1410. (char const * const *)onames,dfp);
  1411. }
  1412. if (retval != 1) {
  1413. (void) fprintf(stderr,"abnormal termination\n");
  1414. return(0);
  1415. }
  1416. fclose(dfp);
  1417. }
  1418. /* Clean up. */
  1419. Cudd_RecursiveDeref(dd,envelope);
  1420. return(1);
  1421. } /* end of Ntr_Envelope */
  1422. /**
  1423. @brief Maximum 0-1 flow between source and sink states.
  1424. @return 1 in case of success; 0 otherwise.
  1425. @sideeffect Creates two new sets of variables.
  1426. */
  1427. int
  1428. Ntr_maxflow(
  1429. DdManager * dd,
  1430. BnetNetwork * net,
  1431. NtrOptions * option)
  1432. {
  1433. DdNode **x = NULL;
  1434. DdNode **y = NULL;
  1435. DdNode **z = NULL;
  1436. DdNode *E = NULL;
  1437. DdNode *F = NULL;
  1438. DdNode *cut = NULL;
  1439. DdNode *sx = NULL;
  1440. DdNode *ty = NULL;
  1441. DdNode *tx = NULL;
  1442. int n;
  1443. int pr;
  1444. int ylevel;
  1445. int i;
  1446. double flow;
  1447. int result = 0;
  1448. NtrPartTR *TR;
  1449. n = net->nlatches;
  1450. pr = option->verb;
  1451. TR = Ntr_buildTR(dd,net,option,NTR_IMAGE_MONO);
  1452. if (TR == NULL)
  1453. goto endgame;
  1454. E = TR->part[0];
  1455. x = TR->x;
  1456. y = TR->y;
  1457. /* Create array of auxiliary variables. */
  1458. z = ALLOC(DdNode *,n);
  1459. if (z == NULL)
  1460. goto endgame;
  1461. for (i = 0; i < n; i++) {
  1462. ylevel = Cudd_ReadIndex(dd,y[i]->index);
  1463. z[i] = Cudd_bddNewVarAtLevel(dd,ylevel);
  1464. if (z[i] == NULL)
  1465. goto endgame;
  1466. Cudd_Ref(z[i]);
  1467. }
  1468. /* Create BDDs for source and sink. */
  1469. sx = Ntr_initState(dd,net,option);
  1470. if (sx == NULL)
  1471. goto endgame;
  1472. if (pr > 0) (void) fprintf(stdout, "Sink(s): ");
  1473. tx = Ntr_getStateCube(dd,net,option->sinkfile,pr);
  1474. if (tx == NULL)
  1475. goto endgame;
  1476. ty = Cudd_bddSwapVariables(dd,tx,x,y,n);
  1477. if (ty == NULL)
  1478. goto endgame;
  1479. Cudd_Ref(ty);
  1480. Cudd_RecursiveDeref(dd,tx);
  1481. tx = NULL;
  1482. flow = Ntr_maximum01Flow(dd, sx, ty, E, &F, &cut, x, y, z, n, pr);
  1483. if (flow >= 0.0)
  1484. result = 1;
  1485. if (pr >= 0) {
  1486. (void) fprintf(stdout,"Maximum flow = %g\n", flow);
  1487. (void) fprintf(stdout,"E"); Cudd_PrintDebug(dd,E,2*n,pr);
  1488. (void) fprintf(stdout,"F"); Cudd_PrintDebug(dd,F,2*n,pr);
  1489. (void) fprintf(stdout,"cut"); Cudd_PrintDebug(dd,cut,2*n,pr);
  1490. }
  1491. endgame:
  1492. /* Clean up. */
  1493. if (TR != NULL) Ntr_freeTR(dd,TR);
  1494. for (i = 0; i < n; i++) {
  1495. if (z != NULL && z[i] != NULL) Cudd_RecursiveDeref(dd,z[i]);
  1496. }
  1497. if (z != NULL) FREE(z);
  1498. if (F != NULL) Cudd_RecursiveDeref(dd,F);
  1499. if (cut != NULL) Cudd_RecursiveDeref(dd,cut);
  1500. if (sx != NULL) Cudd_RecursiveDeref(dd,sx);
  1501. if (ty != NULL) Cudd_RecursiveDeref(dd,ty);
  1502. return(result);
  1503. } /* end of Ntr_Maxflow */
  1504. /*---------------------------------------------------------------------------*/
  1505. /* Definition of internal functions */
  1506. /*---------------------------------------------------------------------------*/
  1507. /*---------------------------------------------------------------------------*/
  1508. /* Definition of static functions */
  1509. /*---------------------------------------------------------------------------*/
  1510. /**
  1511. @brief Builds a positive cube of all the variables in x.
  1512. @return a %BDD for the cube if successful; NULL otherwise.
  1513. @sideeffect None
  1514. */
  1515. static DdNode *
  1516. makecube(
  1517. DdManager * dd,
  1518. DdNode ** x,
  1519. int n)
  1520. {
  1521. DdNode *res, *w, *one;
  1522. int i;
  1523. one = Cudd_ReadOne(dd);
  1524. Cudd_Ref(res = one);
  1525. for (i = n-1; i >= 0; i--) {
  1526. w = Cudd_bddAnd(dd,res,x[i]);
  1527. if (w == NULL) {
  1528. Cudd_RecursiveDeref(dd,res);
  1529. return(NULL);
  1530. }
  1531. Cudd_Ref(w);
  1532. Cudd_RecursiveDeref(dd,res);
  1533. res = w;
  1534. }
  1535. Cudd_Deref(res);
  1536. return(res);
  1537. } /* end of makecube */
  1538. /**
  1539. @brief Initializes the count fields used to drop DDs.
  1540. @details Before actually building the BDDs, we perform a DFS from
  1541. the outputs to initialize the count fields of the nodes. The
  1542. initial value of the count field will normally coincide with the
  1543. fanout of the node. However, if there are nodes with no path to any
  1544. primary output or next state variable, then the initial value of
  1545. count for some nodes will be less than the fanout. For primary
  1546. outputs and next state functions we add 1, so that we will never try
  1547. to free their DDs. The count fields of the nodes that are not
  1548. reachable from the outputs are set to -1.
  1549. @sideeffect Changes the count fields of the network nodes. Uses the
  1550. visited fields.
  1551. */
  1552. static void
  1553. ntrInitializeCount(
  1554. BnetNetwork * net,
  1555. NtrOptions * option)
  1556. {
  1557. BnetNode *node;
  1558. int i;
  1559. if (option->node != NULL &&
  1560. option->closestCube == FALSE && option->dontcares == FALSE) {
  1561. if (!st_lookup(net->hash,option->node,(void **)&node)) {
  1562. (void) fprintf(stdout, "Warning: node %s not found!\n",
  1563. option->node);
  1564. } else {
  1565. ntrCountDFS(net,node);
  1566. node->count++;
  1567. }
  1568. } else {
  1569. if (option->stateOnly == FALSE) {
  1570. for (i = 0; i < net->npos; i++) {
  1571. if (!st_lookup(net->hash,net->outputs[i],(void **)&node)) {
  1572. (void) fprintf(stdout,
  1573. "Warning: output %s is not driven!\n",
  1574. net->outputs[i]);
  1575. continue;
  1576. }
  1577. ntrCountDFS(net,node);
  1578. node->count++;
  1579. }
  1580. }
  1581. for (i = 0; i < net->nlatches; i++) {
  1582. if (!st_lookup(net->hash,net->latches[i][0],(void **)&node)) {
  1583. (void) fprintf(stdout,
  1584. "Warning: latch input %s is not driven!\n",
  1585. net->outputs[i]);
  1586. continue;
  1587. }
  1588. ntrCountDFS(net,node);
  1589. node->count++;
  1590. }
  1591. }
  1592. /* Clear visited flags. */
  1593. node = net->nodes;
  1594. while (node != NULL) {
  1595. if (node->visited == 0) {
  1596. node->count = -1;
  1597. } else {
  1598. node->visited = 0;
  1599. }
  1600. node = node->next;
  1601. }
  1602. } /* end of ntrInitializeCount */
  1603. /**
  1604. @brief Does a DFS from a node setting the count field.
  1605. @sideeffect Changes the count and visited fields of the nodes it
  1606. visits.
  1607. @see ntrLevelDFS
  1608. */
  1609. static void
  1610. ntrCountDFS(
  1611. BnetNetwork * net,
  1612. BnetNode * node)
  1613. {
  1614. int i;
  1615. BnetNode *auxnd;
  1616. node->count++;
  1617. if (node->visited == 1) {
  1618. return;
  1619. }
  1620. node->visited = 1;
  1621. for (i = 0; i < node->ninp; i++) {
  1622. if (!st_lookup(net->hash, node->inputs[i], (void **)&auxnd)) {
  1623. exit(2);
  1624. }
  1625. ntrCountDFS(net,auxnd);
  1626. }
  1627. } /* end of ntrCountDFS */
  1628. /**
  1629. @brief Computes the image of a set given a transition relation.
  1630. @details The image is returned in terms of the present state
  1631. variables; its reference count is already increased.
  1632. @return a pointer to the result if successful; NULL otherwise.
  1633. @sideeffect None
  1634. @see Ntr_Trav
  1635. */
  1636. static DdNode *
  1637. ntrImage(
  1638. DdManager * dd,
  1639. NtrPartTR * TR,
  1640. DdNode * from,
  1641. NtrOptions * option)
  1642. {
  1643. int i;
  1644. DdNode *image;
  1645. DdNode *to;
  1646. NtrPartTR *T;
  1647. int depth = 0;
  1648. if (option->image == NTR_IMAGE_CLIP) {
  1649. depth = (int) ((double) Cudd_ReadSize(dd) * option->imageClip);
  1650. }
  1651. /* Existentially quantify the present state variables that are not
  1652. ** in the support of any next state function. */
  1653. image = Cudd_bddExistAbstract(dd,from,TR->preiabs);
  1654. if (image == NULL) return(NULL);
  1655. Cudd_Ref(image);
  1656. if (option->image == NTR_IMAGE_DEPEND) {
  1657. /* Simplify the transition relation based on dependencies
  1658. ** and build the conjuncts from the deltas. */
  1659. T = ntrEliminateDependencies(dd,TR,&image,option);
  1660. } else {
  1661. T = TR;
  1662. }
  1663. if (T == NULL) return(NULL);
  1664. for (i = 0; i < T->nparts; i++) {
  1665. #if 0
  1666. (void) printf(" Intermediate product[%d]: %d nodes\n",
  1667. i,Cudd_DagSize(image));
  1668. #endif
  1669. if (option->image == NTR_IMAGE_CLIP) {
  1670. to = Cudd_bddClippingAndAbstract(dd,T->part[i],image,T->icube[i],
  1671. depth,option->approx);
  1672. } else {
  1673. to = Cudd_bddAndAbstract(dd,T->part[i],image,T->icube[i]);
  1674. }
  1675. if (to == NULL) return(NULL);
  1676. Cudd_Ref(to);
  1677. if (option->image == NTR_IMAGE_DEPEND) {
  1678. /* Extract dependencies from intermediate product. */
  1679. DdNode *abs, *positive, *absabs, *phi, *exnor, *tmp;
  1680. abs = Cudd_bddExistAbstract(dd,to,T->xw);
  1681. if (abs == NULL) return(NULL); Cudd_Ref(abs);
  1682. if (Cudd_bddVarIsDependent(dd,abs,T->nscube[i]) &&
  1683. Cudd_EstimateCofactor(dd,abs,T->nscube[i]->index,1) <=
  1684. T->nlatches) {
  1685. int retval, sizex;
  1686. positive = Cudd_Cofactor(dd,abs,T->nscube[i]);
  1687. if (positive == NULL) return(NULL); Cudd_Ref(positive);
  1688. absabs = Cudd_bddExistAbstract(dd,abs,T->nscube[i]);
  1689. if (absabs == NULL) return(NULL); Cudd_Ref(absabs);
  1690. Cudd_RecursiveDeref(dd,abs);
  1691. phi = Cudd_bddLICompaction(dd,positive,absabs);
  1692. if (phi == NULL) return(NULL); Cudd_Ref(phi);
  1693. Cudd_RecursiveDeref(dd,positive);
  1694. Cudd_RecursiveDeref(dd,absabs);
  1695. exnor = Cudd_bddXnor(dd,T->nscube[i],phi);
  1696. if (exnor == NULL) return(NULL); Cudd_Ref(exnor);
  1697. Cudd_RecursiveDeref(dd,phi);
  1698. sizex = Cudd_DagSize(exnor);
  1699. (void) printf("new factor of %d nodes\n", sizex);
  1700. retval = Ntr_HeapInsert(T->factors,exnor,sizex);
  1701. if (retval == 0) return(NULL);
  1702. tmp = Cudd_bddExistAbstract(dd,to,T->nscube[i]);
  1703. if (tmp == NULL) return(NULL); Cudd_Ref(tmp);
  1704. Cudd_RecursiveDeref(dd,to);
  1705. to = tmp;
  1706. } else {
  1707. Cudd_RecursiveDeref(dd,abs);
  1708. }
  1709. }
  1710. Cudd_RecursiveDeref(dd,image);
  1711. image = to;
  1712. }
  1713. if (option->image == NTR_IMAGE_DEPEND) {
  1714. int size1, size2;
  1715. DdNode *factor1, *factor2, *tmp;
  1716. int retval;
  1717. size1 = Cudd_DagSize(image);
  1718. retval = Ntr_HeapInsert(T->factors,image,size1);
  1719. if (retval == 0) return(NULL);
  1720. (void) printf("Merging %d factors. Independent image: %d nodes\n",
  1721. Ntr_HeapCount(T->factors), size1);
  1722. while (Ntr_HeapCount(T->factors) > 1) {
  1723. retval = Ntr_HeapExtractMin(T->factors,&factor1,&size1);
  1724. if (retval == 0) return(NULL);
  1725. retval = Ntr_HeapExtractMin(T->factors,&factor2,&size2);
  1726. if (retval == 0) return(NULL);
  1727. tmp = Cudd_bddAnd(dd,factor1,factor2);
  1728. if (tmp == NULL) return(NULL); Cudd_Ref(tmp);
  1729. size1 = Cudd_DagSize(tmp);
  1730. (void) printf("new factor %d nodes\n", size1);
  1731. Cudd_RecursiveDeref(dd,factor1);
  1732. Cudd_RecursiveDeref(dd,factor2);
  1733. retval = Ntr_HeapInsert(T->factors,tmp,size1);
  1734. if (retval == 0) return(NULL);
  1735. }
  1736. retval = Ntr_HeapExtractMin(T->factors,&image,&size1);
  1737. if (retval == 0) return(NULL);
  1738. Ntr_freeTR(dd,T);
  1739. }
  1740. /* Express image in terms of x variables. */
  1741. to = Cudd_bddVarMap(dd,image);
  1742. if (to == NULL) {
  1743. Cudd_RecursiveDeref(dd,image);
  1744. return(NULL);
  1745. }
  1746. Cudd_Ref(to);
  1747. Cudd_RecursiveDeref(dd,image);
  1748. return(to);
  1749. } /* end of ntrImage */
  1750. /**
  1751. @brief Computes the preimage of a set given a transition relation.
  1752. @details The preimage is returned in terms of the next state
  1753. variables; its reference count is already increased.
  1754. @return a pointer to the result if successful; NULL otherwise.
  1755. @sideeffect None
  1756. @see ntrImage Ntr_SCC
  1757. */
  1758. static DdNode *
  1759. ntrPreimage(
  1760. DdManager * dd,
  1761. NtrPartTR * T,
  1762. DdNode * from)
  1763. {
  1764. int i;
  1765. DdNode *preimage;
  1766. DdNode *to;
  1767. /* Existentially quantify the present state variables that are not
  1768. ** in the support of any next state function. */
  1769. preimage = Cudd_bddExistAbstract(dd,from,T->prepabs);
  1770. if (preimage == NULL) return(NULL);
  1771. Cudd_Ref(preimage);
  1772. for (i = 0; i < T->nparts; i++) {
  1773. #if 0
  1774. (void) printf(" Intermediate product[%d]: %d nodes\n",
  1775. i,Cudd_DagSize(preimage));
  1776. #endif
  1777. to = Cudd_bddAndAbstract(dd,T->part[i],preimage,T->pcube[i]);
  1778. if (to == NULL) return(NULL);
  1779. Cudd_Ref(to);
  1780. Cudd_RecursiveDeref(dd,preimage);
  1781. preimage = to;
  1782. }
  1783. /* Express preimage in terms of x variables. */
  1784. to = Cudd_bddVarMap(dd,preimage);
  1785. if (to == NULL) {
  1786. Cudd_RecursiveDeref(dd,preimage);
  1787. return(NULL);
  1788. }
  1789. Cudd_Ref(to);
  1790. Cudd_RecursiveDeref(dd,preimage);
  1791. return(to);
  1792. } /* end of ntrPreimage */
  1793. /**
  1794. @brief Chooses the initial states for a BFS step.
  1795. @details The reference count of the result is already incremented.
  1796. @return a pointer to the chose set if successful; NULL otherwise.
  1797. @sideeffect none
  1798. @see Ntr_Trav
  1799. */
  1800. static DdNode *
  1801. ntrChooseFrom(
  1802. DdManager * dd,
  1803. DdNode * neW,
  1804. DdNode * reached,
  1805. NtrOptions * option)
  1806. {
  1807. DdNode *min, *c;
  1808. int threshold;
  1809. switch (option->from) {
  1810. case NTR_FROM_NEW:
  1811. Cudd_Ref(neW);
  1812. return(neW);
  1813. case NTR_FROM_REACHED:
  1814. Cudd_Ref(reached);
  1815. return(reached);
  1816. case NTR_FROM_RESTRICT:
  1817. c = Cudd_bddOr(dd, neW, Cudd_Not(reached));
  1818. if (c == NULL) return(NULL);
  1819. Cudd_Ref(c);
  1820. min = Cudd_bddRestrict(dd,neW,c);
  1821. if (min == NULL) {
  1822. Cudd_RecursiveDeref(dd, c);
  1823. return(NULL);
  1824. }
  1825. Cudd_Ref(min);
  1826. Cudd_RecursiveDeref(dd, c);
  1827. return(min);
  1828. case NTR_FROM_COMPACT:
  1829. c = Cudd_bddOr(dd, neW, Cudd_Not(reached));
  1830. if (c == NULL) return(NULL);
  1831. Cudd_Ref(c);
  1832. min = Cudd_bddLICompaction(dd,neW,c);
  1833. if (min == NULL) {
  1834. Cudd_RecursiveDeref(dd, c);
  1835. return(NULL);
  1836. }
  1837. Cudd_Ref(min);
  1838. Cudd_RecursiveDeref(dd, c);
  1839. return(min);
  1840. case NTR_FROM_SQUEEZE:
  1841. min = Cudd_bddSqueeze(dd,neW,reached);
  1842. if (min == NULL) return(NULL);
  1843. Cudd_Ref(min);
  1844. return(min);
  1845. case NTR_FROM_UNDERAPPROX:
  1846. threshold = (option->threshold < 0) ? 0 : option->threshold;
  1847. min = Cudd_RemapUnderApprox(dd,neW,Cudd_SupportSize(dd,neW),
  1848. threshold,option->quality);
  1849. if (min == NULL) return(NULL);
  1850. Cudd_Ref(min);
  1851. return(min);
  1852. case NTR_FROM_OVERAPPROX:
  1853. threshold = (option->threshold < 0) ? 0 : option->threshold;
  1854. min = Cudd_RemapOverApprox(dd,neW,Cudd_SupportSize(dd,neW),
  1855. threshold,option->quality);
  1856. if (min == NULL) return(NULL);
  1857. Cudd_Ref(min);
  1858. return(min);
  1859. default:
  1860. return(NULL);
  1861. }
  1862. } /* end of ntrChooseFrom */
  1863. /**
  1864. @brief Updates the reached states after a traversal step.
  1865. @details The reference count of the result is already incremented.
  1866. @return a pointer to the new reached set if successful; NULL
  1867. otherwise.
  1868. @sideeffect The old reached set is dereferenced.
  1869. @see Ntr_Trav
  1870. */
  1871. static DdNode *
  1872. ntrUpdateReached(
  1873. DdManager * dd /**< manager */,
  1874. DdNode * oldreached /**< old reached state set */,
  1875. DdNode * to /**< result of last image computation */)
  1876. {
  1877. DdNode *reached;
  1878. reached = Cudd_bddOr(dd,oldreached,to);
  1879. if (reached == NULL) {
  1880. Cudd_RecursiveDeref(dd,oldreached);
  1881. return(NULL);
  1882. }
  1883. Cudd_Ref(reached);
  1884. Cudd_RecursiveDeref(dd,oldreached);
  1885. return(reached);
  1886. } /* end of ntrUpdateReached */
  1887. /**
  1888. @brief Analyzes the reached states after traversal to find
  1889. dependent latches.
  1890. @details The algorithm is greedy and determines a local optimum, not
  1891. a global one.
  1892. @return the number of latches that can be eliminated because they
  1893. are stuck at a constant value or are dependent on others if
  1894. successful; -1 otherwise.
  1895. @see Ntr_Trav
  1896. */
  1897. static int
  1898. ntrLatchDependencies(
  1899. DdManager *dd,
  1900. DdNode *reached,
  1901. BnetNetwork *net,
  1902. NtrOptions *option)
  1903. {
  1904. int i;
  1905. int howMany; /* number of latches that can be eliminated */
  1906. DdNode *var, *newreached, *abs, *positive, *phi;
  1907. char *name;
  1908. BnetNode *node;
  1909. int initVars, finalVars;
  1910. double initStates, finalStates;
  1911. DdNode **roots;
  1912. char **onames;
  1913. int howManySmall = 0;
  1914. int *candidates;
  1915. double minStates;
  1916. int totalVars;
  1917. (void) printf("Analyzing latch dependencies\n");
  1918. roots = ALLOC(DdNode *, net->nlatches);
  1919. if (roots == NULL) return(-1);
  1920. onames = ALLOC(char *, net->nlatches);
  1921. if (onames == NULL) return(-1);
  1922. candidates = ALLOC(int,net->nlatches);
  1923. if (candidates == NULL) return(-1);
  1924. for (i = 0; i < net->nlatches; i++) {
  1925. candidates[i] = i;
  1926. }
  1927. /* The signatures of the variables in a function are the number
  1928. ** of minterms of the positive cofactors with respect to the
  1929. ** variables themselves. */
  1930. newreached = reached;
  1931. Cudd_Ref(newreached);
  1932. signatures = Cudd_CofMinterm(dd,newreached);
  1933. if (signatures == NULL) return(-1);
  1934. /* We now extract a positive quantity which is higher for those
  1935. ** variables that are closer to being essential. */
  1936. totalVars = Cudd_ReadSize(dd);
  1937. minStates = signatures[totalVars];
  1938. #if 0
  1939. (void) printf("Raw signatures (minStates = %g)\n", minStates);
  1940. for (i = 0; i < net->nlatches; i++) {
  1941. int j = candidates[i];
  1942. if (!st_lookup(net->hash,net->latches[j][1],(void **)&node)) {
  1943. return(-1);
  1944. }
  1945. (void) printf("%s -> %g\n", node->name, signatures[node->dd->index]);
  1946. }
  1947. #endif
  1948. for (i = 0; i < totalVars; i++) {
  1949. double z = signatures[i] / minStates - 1.0;
  1950. signatures[i] = (z >= 0.0) ? z : -z; /* make positive */
  1951. }
  1952. staticNet = net;
  1953. util_qsort(candidates,net->nlatches,sizeof(int),
  1954. (DD_QSFP)ntrSignatureCompare2);
  1955. #if 0
  1956. (void) printf("Cooked signatures\n");
  1957. for (i = 0; i < net->nlatches; i++) {
  1958. int j = candidates[i];
  1959. if (!st_lookup(net->hash,net->latches[j][1],(void **)&node)) {
  1960. return(-1);
  1961. }
  1962. (void) printf("%s -> %g\n", node->name, signatures[node->dd->index]);
  1963. }
  1964. #endif
  1965. FREE(signatures);
  1966. /* Extract simple dependencies. */
  1967. for (i = 0; i < net->nlatches; i++) {
  1968. int j = candidates[i];
  1969. if (!st_lookup(net->hash,net->latches[j][1],(void **)&node)) {
  1970. return(-1);
  1971. }
  1972. var = node->dd;
  1973. name = node->name;
  1974. if (Cudd_bddVarIsDependent(dd,newreached,var)) {
  1975. positive = Cudd_Cofactor(dd,newreached,var);
  1976. if (positive == NULL) return(-1); Cudd_Ref(positive);
  1977. abs = Cudd_bddExistAbstract(dd,newreached,var);
  1978. if (abs == NULL) return(-1); Cudd_Ref(abs);
  1979. phi = Cudd_bddLICompaction(dd,positive,abs);
  1980. if (phi == NULL) return(-1); Cudd_Ref(phi);
  1981. Cudd_RecursiveDeref(dd,positive);
  1982. if (Cudd_DagSize(phi) < NTR_MAX_DEP_SIZE) {
  1983. if (Cudd_bddLeq(dd,newreached,var)) {
  1984. (void) printf("%s is stuck at 1\n",name);
  1985. } else if (Cudd_bddLeq(dd,newreached,Cudd_Not(var))) {
  1986. (void) printf("%s is stuck at 0\n",name);
  1987. } else {
  1988. (void) printf("%s depends on the other variables\n",name);
  1989. }
  1990. roots[howManySmall] = phi;
  1991. onames[howManySmall] = util_strsav(name);
  1992. Cudd_RecursiveDeref(dd,newreached);
  1993. newreached = abs;
  1994. howManySmall++;
  1995. candidates[i] = -1; /* do not reconsider */
  1996. } else {
  1997. Cudd_RecursiveDeref(dd,abs);
  1998. Cudd_RecursiveDeref(dd,phi);
  1999. }
  2000. } else {
  2001. candidates[i] = -1; /* do not reconsider */
  2002. }
  2003. }
  2004. /* Now remove remaining dependent variables. */
  2005. howMany = howManySmall;
  2006. for (i = 0; i < net->nlatches; i++) {
  2007. int j = candidates[i];
  2008. if (j == -1) continue;
  2009. if (!st_lookup(net->hash,net->latches[j][1],(void **)&node)) {
  2010. return(-1);
  2011. }
  2012. var = node->dd;
  2013. name = node->name;
  2014. if (Cudd_bddVarIsDependent(dd,newreached,var)) {
  2015. if (Cudd_bddLeq(dd,newreached,var)) {
  2016. (void) printf("%s is stuck at 1\n",name);
  2017. } else if (Cudd_bddLeq(dd,newreached,Cudd_Not(var))) {
  2018. (void) printf("%s is stuck at 0\n",name);
  2019. } else {
  2020. (void) printf("%s depends on the other variables\n",name);
  2021. }
  2022. abs = Cudd_bddExistAbstract(dd,newreached,var);
  2023. if (abs == NULL) return(-1); Cudd_Ref(abs);
  2024. Cudd_RecursiveDeref(dd,newreached);
  2025. newreached = abs;
  2026. howMany++;
  2027. }
  2028. }
  2029. FREE(candidates);
  2030. if (howManySmall > 0 && option->verb > 1) {
  2031. if (!Bnet_bddArrayDump(dd,net,(char *)"-",roots,onames,howManySmall,1))
  2032. return(-1);
  2033. }
  2034. for (i = 0; i < howManySmall; i++) {
  2035. Cudd_RecursiveDeref(dd,roots[i]);
  2036. FREE(onames[i]);
  2037. }
  2038. FREE(roots);
  2039. FREE(onames);
  2040. initVars = net->nlatches;
  2041. initStates = Cudd_CountMinterm(dd,reached,initVars);
  2042. finalVars = initVars - howMany;
  2043. finalStates = Cudd_CountMinterm(dd,newreached,finalVars);
  2044. if (initStates != finalStates) {
  2045. (void) printf("Error: the number of states changed from %g to %g\n",
  2046. initStates, finalStates);
  2047. return(-1);
  2048. }
  2049. (void) printf("new reached");
  2050. Cudd_PrintDebug(dd,newreached,finalVars,option->verb);
  2051. Cudd_RecursiveDeref(dd,newreached);
  2052. return(howMany);
  2053. } /* end of ntrLatchDependencies */
  2054. /**
  2055. @brief Eliminates dependent variables from a transition relation.
  2056. @return a simplified copy of the given transition relation if
  2057. successful; NULL otherwise.
  2058. @sideeffect The modified set of states is returned as a side effect.
  2059. @see ntrImage
  2060. */
  2061. static NtrPartTR *
  2062. ntrEliminateDependencies(
  2063. DdManager *dd,
  2064. NtrPartTR *TR,
  2065. DdNode **states,
  2066. NtrOptions *option)
  2067. {
  2068. NtrPartTR *T; /* new TR without dependent vars */
  2069. int pr = option->verb;
  2070. int i, j;
  2071. int howMany = 0; /* number of latches that can be eliminated */
  2072. DdNode *var, *newstates, *abs, *positive, *phi;
  2073. DdNode *support, *scan, *tmp;
  2074. int finalSize; /* size of the TR after substitutions */
  2075. int nvars; /* vars in the support of the state set */
  2076. int *candidates; /* vars to be considered for elimination */
  2077. int totalVars;
  2078. double minStates;
  2079. /* Initialize the new transition relation by copying the old one. */
  2080. T = Ntr_cloneTR(TR);
  2081. if (T == NULL) return(NULL);
  2082. /* Find and rank the candidate variables. */
  2083. newstates = *states;
  2084. Cudd_Ref(newstates);
  2085. support = Cudd_Support(dd,newstates);
  2086. if (support == NULL) {
  2087. Cudd_RecursiveDeref(dd,newstates);
  2088. Ntr_freeTR(dd,T);
  2089. return(NULL);
  2090. }
  2091. Cudd_Ref(support);
  2092. nvars = Cudd_DagSize(support) - 1;
  2093. candidates = ALLOC(int,nvars);
  2094. if (candidates == NULL) {
  2095. Cudd_RecursiveDeref(dd,support);
  2096. Cudd_RecursiveDeref(dd,newstates);
  2097. Ntr_freeTR(dd,T);
  2098. return(NULL);
  2099. }
  2100. scan = support;
  2101. for (i = 0; i < nvars; i++) {
  2102. candidates[i] = scan->index;
  2103. scan = Cudd_T(scan);
  2104. }
  2105. Cudd_RecursiveDeref(dd,support);
  2106. /* The signatures of the variables in a function are the number
  2107. ** of minterms of the positive cofactors with respect to the
  2108. ** variables themselves. */
  2109. signatures = Cudd_CofMinterm(dd,newstates);
  2110. if (signatures == NULL) {
  2111. FREE(candidates);
  2112. Cudd_RecursiveDeref(dd,newstates);
  2113. Ntr_freeTR(dd,T);
  2114. return(NULL);
  2115. }
  2116. /* We now extract a positive quantity which is higher for those
  2117. ** variables that are closer to being essential. */
  2118. totalVars = Cudd_ReadSize(dd);
  2119. minStates = signatures[totalVars];
  2120. for (i = 0; i < totalVars; i++) {
  2121. double z = signatures[i] / minStates - 1.0;
  2122. signatures[i] = (z < 0.0) ? -z : z; /* make positive */
  2123. }
  2124. /* Sort candidates in decreasing order of signature. */
  2125. util_qsort(candidates,nvars,sizeof(int), (DD_QSFP)ntrSignatureCompare);
  2126. FREE(signatures);
  2127. /* Now process the candidates in the given order. */
  2128. for (i = 0; i < nvars; i++) {
  2129. var = Cudd_bddIthVar(dd,candidates[i]);
  2130. if (Cudd_bddVarIsDependent(dd,newstates,var)) {
  2131. abs = Cudd_bddExistAbstract(dd,newstates,var);
  2132. if (abs == NULL) return(NULL); Cudd_Ref(abs);
  2133. positive = Cudd_Cofactor(dd,newstates,var);
  2134. if (positive == NULL) return(NULL); Cudd_Ref(positive);
  2135. phi = Cudd_bddLICompaction(dd,positive,abs);
  2136. if (phi == NULL) return(NULL); Cudd_Ref(phi);
  2137. Cudd_RecursiveDeref(dd,positive);
  2138. #if 0
  2139. if (pr > 0) {
  2140. (void) printf("Phi");
  2141. Cudd_PrintDebug(dd,phi,T->nlatches,pr);
  2142. }
  2143. #endif
  2144. if (Cudd_DagSize(phi) < NTR_MAX_DEP_SIZE) {
  2145. howMany++;
  2146. for (j = 0; j < T->nparts; j++) {
  2147. tmp = Cudd_bddCompose(dd,T->part[j],phi,candidates[i]);
  2148. if (tmp == NULL) return(NULL); Cudd_Ref(tmp);
  2149. Cudd_RecursiveDeref(dd,T->part[j]);
  2150. T->part[j] = tmp;
  2151. }
  2152. Cudd_RecursiveDeref(dd,newstates);
  2153. newstates = abs;
  2154. } else {
  2155. Cudd_RecursiveDeref(dd,abs);
  2156. }
  2157. Cudd_RecursiveDeref(dd,phi);
  2158. }
  2159. }
  2160. FREE(candidates);
  2161. if (pr > 0) {
  2162. finalSize = Cudd_SharingSize(T->part,T->nparts);
  2163. (void) printf("Eliminated %d vars. Transition function %d nodes.\n",
  2164. howMany,finalSize);
  2165. }
  2166. if (!ntrUpdateQuantificationSchedule(dd,T)) return(NULL);
  2167. /* Quantify out of states variables that no longer appear in any part. */
  2168. Cudd_RecursiveDeref(dd,*states);
  2169. *states = Cudd_bddExistAbstract(dd,newstates,T->preiabs);
  2170. if (*states == NULL) {
  2171. Cudd_RecursiveDeref(dd,newstates);
  2172. return(NULL);
  2173. }
  2174. Cudd_Ref(*states);
  2175. Cudd_RecursiveDeref(dd,newstates);
  2176. return(T);
  2177. } /* end of ntrEliminateDependencies */
  2178. /**
  2179. @brief Updates the quantification schedule of a transition relation.
  2180. @return 1 if successful; 0 otherwise.
  2181. @sideeffect None
  2182. @see ntrEliminateDependencies
  2183. */
  2184. static int
  2185. ntrUpdateQuantificationSchedule(
  2186. DdManager *dd,
  2187. NtrPartTR *T)
  2188. {
  2189. int i, j, k;
  2190. int *schedule;
  2191. DdNode *one, *support, *scan, *var, *tmp;
  2192. char **matrix;
  2193. int *position, *row;
  2194. char *flags;
  2195. int nparts, nvars;
  2196. int extracted;
  2197. #if 0
  2198. int schedcost;
  2199. #endif
  2200. nparts = T->nparts;
  2201. nvars = Cudd_ReadSize(dd);
  2202. one = Cudd_ReadOne(dd);
  2203. /* Reinitialize the abstraction cubes. */
  2204. Cudd_RecursiveDeref(dd,T->preiabs);
  2205. T->preiabs = one;
  2206. Cudd_Ref(one);
  2207. for (i = 0; i < nparts; i++) {
  2208. Cudd_RecursiveDeref(dd,T->icube[i]);
  2209. T->icube[i] = one;
  2210. Cudd_Ref(one);
  2211. }
  2212. /* Initialize row permutations to the identity. */
  2213. position = ALLOC(int,nparts);
  2214. if (position == NULL) return(0);
  2215. for (i = 0; i < nparts; i++) {
  2216. position[i] = i;
  2217. }
  2218. /* Sort parts so that parts that differ only
  2219. ** in the index of the next state variable are contiguous. */
  2220. staticPart = T->part;
  2221. util_qsort(position,nparts,sizeof(int), (DD_QSFP)ntrPartCompare);
  2222. /* Extract repeated parts. */
  2223. extracted = 0;
  2224. for (i = 0; i < nparts - 1; i += j) {
  2225. int pi, pij;
  2226. DdNode *eq;
  2227. j = 1;
  2228. pi = position[i];
  2229. eq = one;
  2230. Cudd_Ref(eq);
  2231. pij = position[i+j];
  2232. while (Cudd_Regular(staticPart[pij]) == Cudd_Regular(staticPart[pi])) {
  2233. int comple = staticPart[pij] != staticPart[pi];
  2234. DdNode *xnor = Cudd_bddXnor(dd,T->nscube[pi],
  2235. Cudd_NotCond(T->nscube[pij],comple));
  2236. if (xnor == NULL) return(0); Cudd_Ref(xnor);
  2237. tmp = Cudd_bddAnd(dd,xnor,eq);
  2238. if (tmp == NULL) return(0); Cudd_Ref(tmp);
  2239. Cudd_RecursiveDeref(dd,xnor);
  2240. Cudd_RecursiveDeref(dd,eq);
  2241. eq = tmp;
  2242. Cudd_RecursiveDeref(dd,T->part[pij]);
  2243. Cudd_RecursiveDeref(dd,T->icube[pij]);
  2244. Cudd_RecursiveDeref(dd,T->pcube[pij]);
  2245. Cudd_RecursiveDeref(dd,T->nscube[pij]);
  2246. T->part[pij] = NULL;
  2247. j++;
  2248. if (i+j == nparts) break;
  2249. pij = position[i+j];
  2250. }
  2251. if (eq != one) {
  2252. int retval = Ntr_HeapInsert(T->factors,eq,Cudd_DagSize(eq));
  2253. if (retval == 0) return(0);
  2254. extracted += j - 1;
  2255. } else {
  2256. Cudd_RecursiveDeref(dd,eq);
  2257. }
  2258. }
  2259. /* Compact the part array by removing extracted parts. */
  2260. for (i = 0, j = 0; i < nparts; i++) {
  2261. if (T->part[i] != NULL) {
  2262. T->part[j] = T->part[i];
  2263. T->icube[j] = T->icube[i];
  2264. T->pcube[j] = T->pcube[i];
  2265. T->nscube[j] = T->nscube[i];
  2266. j++;
  2267. }
  2268. }
  2269. nparts = T->nparts -= extracted;
  2270. (void) printf("Extracted %d repeated parts in %d factors.\n",
  2271. extracted, Ntr_HeapCount(T->factors));
  2272. /* Build the support matrix. Each row corresponds to a part of the
  2273. ** transition relation; each column corresponds to a variable in
  2274. ** the manager. A 1 in position (i,j) means that Part i depends
  2275. ** on Variable j. */
  2276. matrix = ntrAllocMatrix(nparts,nvars);
  2277. if (matrix == NULL) return(0);
  2278. /* Allocate array for quantification schedule and initialize it. */
  2279. schedule = ALLOC(int,nvars);
  2280. if (schedule == NULL) return(0);
  2281. for (i = 0; i < nvars; i++) {
  2282. schedule[i] = -1;
  2283. }
  2284. /* Collect scheduling info for this part. At the end of this loop
  2285. ** schedule[i] == j means that the variable of index i does not
  2286. ** appear in any part with index greater than j, unless j == -1,
  2287. ** in which case the variable appears in no part.
  2288. */
  2289. for (i = 0; i < nparts; i++) {
  2290. support = Cudd_Support(dd,T->part[i]);
  2291. if (support == NULL) return(0); Cudd_Ref(support);
  2292. scan = support;
  2293. while (!Cudd_IsConstant(scan)) {
  2294. int index = scan->index;
  2295. schedule[index] = i;
  2296. matrix[i][index] = 1;
  2297. scan = Cudd_T(scan);
  2298. }
  2299. Cudd_RecursiveDeref(dd,support);
  2300. }
  2301. #if 0
  2302. (void) printf("Initial schedule:");
  2303. schedcost = 0;
  2304. for (i = 0; i < nvars; i++) {
  2305. (void) printf(" %d", schedule[i]);
  2306. if (schedule[i] != -1) schedcost += schedule[i];
  2307. }
  2308. (void) printf("\nCost = %d\n", schedcost);
  2309. #endif
  2310. /* Initialize direct and inverse row permutations to the identity
  2311. ** permutation. */
  2312. row = ALLOC(int,nparts);
  2313. if (row == NULL) return(0);
  2314. for (i = 0; i < nparts; i++) {
  2315. position[i] = row[i] = i;
  2316. }
  2317. /* Sift the matrix. */
  2318. flags = ALLOC(char,nvars);
  2319. if (flags == NULL) return(0);
  2320. for (i = 0; i < nparts; i++) {
  2321. int cost = 0; /* cost of moving the row */
  2322. int bestcost = 0;
  2323. int posn = position[i];
  2324. int bestposn = posn;
  2325. /* Sift up. */
  2326. /* Initialize the flags to one is for the variables that are
  2327. ** currently scheduled to be quantified after this part gets
  2328. ** multiplied. When we cross a row of a part that depends on
  2329. ** a variable whose flag is 1, we know that the row being sifted
  2330. ** is no longer responsible for that variable. */
  2331. for (k = 0; k < nvars; k++) {
  2332. flags[k] = (char) (schedule[k] == i);
  2333. }
  2334. for (j = posn - 1; j >= 0; j--) {
  2335. for (k = 0; k < nvars; k++) {
  2336. if (schedule[k] == row[j]) {
  2337. cost++;
  2338. } else {
  2339. flags[k] &= (matrix[row[j]][k] == 0);
  2340. cost -= flags[k];
  2341. }
  2342. }
  2343. if (cost < bestcost) {
  2344. bestposn = j;
  2345. bestcost = cost;
  2346. }
  2347. }
  2348. /* Sift down. */
  2349. /* Reinitialize the flags. (We are implicitly undoing the sift
  2350. ** down step.) */
  2351. for (k = 0; k < nvars; k++) {
  2352. flags[k] = (char) (schedule[k] == i);
  2353. }
  2354. for (j = posn + 1; j < nparts; j++) {
  2355. for (k = 0; k < nvars; k++) {
  2356. if (schedule[k] == row[j]) {
  2357. flags[k] |= (matrix[i][k] == 1);
  2358. cost -= flags[k] == 0;
  2359. } else {
  2360. cost += flags[k];
  2361. }
  2362. }
  2363. if (cost < bestcost) {
  2364. bestposn = j;
  2365. bestcost = cost;
  2366. }
  2367. }
  2368. /* Move to best position. */
  2369. if (bestposn < posn) {
  2370. for (j = posn; j >= bestposn; j--) {
  2371. k = row[j];
  2372. if (j > 0) row[j] = row[j-1];
  2373. position[k]++;
  2374. }
  2375. } else {
  2376. for (j = posn; j <= bestposn; j++) {
  2377. k = row[j];
  2378. if (j < nparts - 1) row[j] = row[j+1];
  2379. position[k]--;
  2380. }
  2381. }
  2382. position[i] = bestposn;
  2383. row[bestposn] = i;
  2384. /* Fix the schedule. */
  2385. for (k = 0; k < nvars; k++) {
  2386. if (matrix[i][k] == 1) {
  2387. if (position[schedule[k]] < bestposn) {
  2388. schedule[k] = i;
  2389. } else {
  2390. for (j = nparts - 1; j >= position[i]; j--) {
  2391. if (matrix[row[j]][k] == 1) break;
  2392. }
  2393. schedule[k] = row[j];
  2394. }
  2395. }
  2396. }
  2397. }
  2398. ntrFreeMatrix(matrix);
  2399. FREE(flags);
  2400. /* Update schedule to account for the permutation. */
  2401. for (i = 0; i < nvars; i++) {
  2402. if (schedule[i] >= 0) {
  2403. schedule[i] = position[schedule[i]];
  2404. }
  2405. }
  2406. /* Sort parts. */
  2407. ntrPermuteParts(T->part,T->nscube,row,position,nparts);
  2408. FREE(position);
  2409. FREE(row);
  2410. #if 0
  2411. (void) printf("New schedule:");
  2412. schedcost = 0;
  2413. for (i = 0; i < nvars; i++) {
  2414. (void) printf(" %d", schedule[i]);
  2415. if (schedule[i] != -1) schedcost += schedule[i];
  2416. }
  2417. (void) printf("\nCost = %d\n", schedcost);
  2418. #endif
  2419. /* Mark the next state varibles so that they do not go in the
  2420. ** abstraction cubes. */
  2421. for (i = 0; i < T->nlatches; i++) {
  2422. schedule[T->y[i]->index] = -2;
  2423. }
  2424. /* Rebuild the cubes from the schedule. */
  2425. for (i = 0; i < nvars; i++) {
  2426. k = schedule[i];
  2427. var = Cudd_bddIthVar(dd,i);
  2428. if (k >= 0) {
  2429. tmp = Cudd_bddAnd(dd,T->icube[k],var);
  2430. if (tmp == NULL) return(0); Cudd_Ref(tmp);
  2431. Cudd_RecursiveDeref(dd,T->icube[k]);
  2432. T->icube[k] = tmp;
  2433. } else if (k != -2) {
  2434. tmp = Cudd_bddAnd(dd,T->preiabs,var);
  2435. if (tmp == NULL) return(0); Cudd_Ref(tmp);
  2436. Cudd_RecursiveDeref(dd,T->preiabs);
  2437. T->preiabs = tmp;
  2438. }
  2439. }
  2440. FREE(schedule);
  2441. /* Build the conjuncts. */
  2442. for (i = 0; i < nparts; i++) {
  2443. tmp = Cudd_bddXnor(dd,T->nscube[i],T->part[i]);
  2444. if (tmp == NULL) return(0); Cudd_Ref(tmp);
  2445. Cudd_RecursiveDeref(dd,T->part[i]);
  2446. T->part[i] = tmp;
  2447. }
  2448. return(1);
  2449. } /* end of ntrUpdateQuantificationSchedule */
  2450. /**
  2451. @brief Comparison function used by qsort.
  2452. @details Used to order the variables according to their signatures.
  2453. @sideeffect None
  2454. */
  2455. static int
  2456. ntrSignatureCompare(
  2457. int * ptrX,
  2458. int * ptrY)
  2459. {
  2460. if (signatures[*ptrY] > signatures[*ptrX]) return(1);
  2461. if (signatures[*ptrY] < signatures[*ptrX]) return(-1);
  2462. return(0);
  2463. } /* end of ntrSignatureCompare */
  2464. /**
  2465. @brief Comparison function used by qsort.
  2466. @details Used to order the variables according to their signatures.
  2467. @sideeffect None
  2468. */
  2469. static int
  2470. ntrSignatureCompare2(
  2471. int * ptrX,
  2472. int * ptrY)
  2473. {
  2474. BnetNode *node;
  2475. int x,y;
  2476. if (!st_lookup(staticNet->hash,staticNet->latches[*ptrX][1],(void**)&node)) {
  2477. return(0);
  2478. }
  2479. x = node->dd->index;
  2480. if (!st_lookup(staticNet->hash,staticNet->latches[*ptrY][1],(void**)&node)) {
  2481. return(0);
  2482. }
  2483. y = node->dd->index;
  2484. if (signatures[x] < signatures[y]) return(1);
  2485. if (signatures[x] > signatures[y]) return(-1);
  2486. return(0);
  2487. } /* end of ntrSignatureCompare2 */
  2488. /**
  2489. @brief Comparison function used by qsort.
  2490. @details Used to order the parts according to their %BDD addresses.
  2491. @sideeffect None
  2492. */
  2493. static int
  2494. ntrPartCompare(
  2495. int * ptrX,
  2496. int * ptrY)
  2497. {
  2498. if (staticPart[*ptrY] > staticPart[*ptrX]) return(1);
  2499. if (staticPart[*ptrY] < staticPart[*ptrX]) return(-1);
  2500. return(0);
  2501. } /* end of ntrPartCompare */
  2502. /**
  2503. @brief Allocates a matrix of char's.
  2504. @return a pointer to the matrix if successful; NULL otherwise.
  2505. @sideeffect None
  2506. */
  2507. static char **
  2508. ntrAllocMatrix(
  2509. int nrows,
  2510. int ncols)
  2511. {
  2512. int i;
  2513. char **matrix;
  2514. matrix = ALLOC(char *,nrows);
  2515. if (matrix == NULL) return(NULL);
  2516. matrix[0] = ALLOC(char,nrows * ncols);
  2517. if (matrix[0] == NULL) {
  2518. FREE(matrix);
  2519. return(NULL);
  2520. }
  2521. for (i = 1; i < nrows; i++) {
  2522. matrix[i] = matrix[i-1] + ncols;
  2523. }
  2524. for (i = 0; i < nrows * ncols; i++) {
  2525. matrix[0][i] = 0;
  2526. }
  2527. return(matrix);
  2528. } /* end of ntrAllocMatrix */
  2529. /**
  2530. @brief Frees a matrix of char's.
  2531. @sideeffect None
  2532. */
  2533. static void
  2534. ntrFreeMatrix(
  2535. char **matrix)
  2536. {
  2537. FREE(matrix[0]);
  2538. FREE(matrix);
  2539. return;
  2540. } /* end of ntrFreeMatrix */
  2541. /**
  2542. @brief Sorts parts according to given permutation.
  2543. @sideeffect The permutation arrays are turned into the identity
  2544. permutations.
  2545. */
  2546. static void
  2547. ntrPermuteParts(
  2548. DdNode **a,
  2549. DdNode **b,
  2550. int *comesFrom,
  2551. int *goesTo,
  2552. int size)
  2553. {
  2554. int i, j;
  2555. DdNode *tmp;
  2556. for (i = 0; i < size; i++) {
  2557. if (comesFrom[i] == i) continue;
  2558. j = comesFrom[i];
  2559. tmp = a[i]; a[i] = a[j]; a[j] = tmp;
  2560. tmp = b[i]; b[i] = b[j]; b[j] = tmp;
  2561. comesFrom[goesTo[i]] = j;
  2562. comesFrom[i] = i;
  2563. goesTo[j] = goesTo[i];
  2564. goesTo[i] = i;
  2565. }
  2566. return;
  2567. } /* end of ntrPermuteParts */
  2568. /**
  2569. @brief Calls Cudd_Ref on its first argument.
  2570. */
  2571. static void
  2572. ntrIncreaseRef(
  2573. void * e,
  2574. void * arg)
  2575. {
  2576. DdNode * node = (DdNode *) e;
  2577. (void) arg; /* avoid warning */
  2578. Cudd_Ref(node);
  2579. } /* end of ntrIncreaseRef */
  2580. /**
  2581. @brief Calls Cudd_RecursiveDeref on its first argument.
  2582. */
  2583. static void
  2584. ntrDecreaseRef(
  2585. void * e,
  2586. void * arg)
  2587. {
  2588. DdNode * node = (DdNode *) e;
  2589. DdManager * dd = (DdManager *) arg;
  2590. Cudd_RecursiveDeref(dd, node);
  2591. } /* end of ntrIncreaseRef */