fsmmin.cpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732
  1. /*
  2. * Copyright 2002 Adrian Thurston <thurston@complang.org>
  3. */
  4. /* This file is part of Ragel.
  5. *
  6. * Ragel is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 2 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * Ragel is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with Ragel; if not, write to the Free Software
  18. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  19. */
  20. #include "fsmgraph.h"
  21. #include "mergesort.h"
  22. int FsmAp::partitionRound( StateAp **statePtrs, MinPartition *parts, int numParts )
  23. {
  24. /* Need a mergesort object and a single partition compare. */
  25. MergeSort<StateAp*, PartitionCompare> mergeSort;
  26. PartitionCompare partCompare;
  27. /* For each partition. */
  28. for ( int p = 0; p < numParts; p++ ) {
  29. /* Fill the pointer array with the states in the partition. */
  30. StateList::Iter state = parts[p].list;
  31. for ( int s = 0; state.lte(); state++, s++ )
  32. statePtrs[s] = state;
  33. /* Sort the states using the partitioning compare. */
  34. int numStates = parts[p].list.length();
  35. mergeSort.sort( statePtrs, numStates );
  36. /* Assign the states into partitions based on the results of the sort. */
  37. int destPart = p, firstNewPart = numParts;
  38. for ( int s = 1; s < numStates; s++ ) {
  39. /* If this state differs from the last then move to the next partition. */
  40. if ( partCompare.compare( statePtrs[s-1], statePtrs[s] ) < 0 ) {
  41. /* The new partition is the next avail spot. */
  42. destPart = numParts;
  43. numParts += 1;
  44. }
  45. /* If the state is not staying in the first partition, then
  46. * transfer it to its destination partition. */
  47. if ( destPart != p ) {
  48. StateAp *state = parts[p].list.detach( statePtrs[s] );
  49. parts[destPart].list.append( state );
  50. }
  51. }
  52. /* Fix the partition pointer for all the states that got moved to a new
  53. * partition. This must be done after the states are transfered so the
  54. * result of the sort is not altered. */
  55. for ( int newPart = firstNewPart; newPart < numParts; newPart++ ) {
  56. StateList::Iter state = parts[newPart].list;
  57. for ( ; state.lte(); state++ )
  58. state->alg.partition = &parts[newPart];
  59. }
  60. }
  61. return numParts;
  62. }
  63. /**
  64. * \brief Minimize by partitioning version 1.
  65. *
  66. * Repeatedly tries to split partitions until all partitions are unsplittable.
  67. * Produces the most minimal FSM possible.
  68. */
  69. void FsmAp::minimizePartition1()
  70. {
  71. /* Need one mergesort object and partition compares. */
  72. MergeSort<StateAp*, InitPartitionCompare> mergeSort;
  73. InitPartitionCompare initPartCompare;
  74. /* Nothing to do if there are no states. */
  75. if ( stateList.length() == 0 )
  76. return;
  77. /*
  78. * First thing is to partition the states by final state status and
  79. * transition functions. This gives us an initial partitioning to work
  80. * with.
  81. */
  82. /* Make a array of pointers to states. */
  83. int numStates = stateList.length();
  84. StateAp** statePtrs = new StateAp*[numStates];
  85. /* Fill up an array of pointers to the states for easy sorting. */
  86. StateList::Iter state = stateList;
  87. for ( int s = 0; state.lte(); state++, s++ )
  88. statePtrs[s] = state;
  89. /* Sort the states using the array of states. */
  90. mergeSort.sort( statePtrs, numStates );
  91. /* An array of lists of states is used to partition the states. */
  92. MinPartition *parts = new MinPartition[numStates];
  93. /* Assign the states into partitions. */
  94. int destPart = 0;
  95. for ( int s = 0; s < numStates; s++ ) {
  96. /* If this state differs from the last then move to the next partition. */
  97. if ( s > 0 && initPartCompare.compare( statePtrs[s-1], statePtrs[s] ) < 0 ) {
  98. /* Move to the next partition. */
  99. destPart += 1;
  100. }
  101. /* Put the state into its partition. */
  102. statePtrs[s]->alg.partition = &parts[destPart];
  103. parts[destPart].list.append( statePtrs[s] );
  104. }
  105. /* We just moved all the states from the main list into partitions without
  106. * taking them off the main list. So clean up the main list now. */
  107. stateList.abandon();
  108. /* Split partitions. */
  109. int numParts = destPart + 1;
  110. while ( true ) {
  111. /* Test all partitions for splitting. */
  112. int newNum = partitionRound( statePtrs, parts, numParts );
  113. /* When no partitions can be split, stop. */
  114. if ( newNum == numParts )
  115. break;
  116. numParts = newNum;
  117. }
  118. /* Fuse states in the same partition. The states will end up back on the
  119. * main list. */
  120. fusePartitions( parts, numParts );
  121. /* Cleanup. */
  122. delete[] statePtrs;
  123. delete[] parts;
  124. }
  125. /* Split partitions that need splittting, decide which partitions might need
  126. * to be split as a result, continue until there are no more that might need
  127. * to be split. */
  128. int FsmAp::splitCandidates( StateAp **statePtrs, MinPartition *parts, int numParts )
  129. {
  130. /* Need a mergesort and a partition compare. */
  131. MergeSort<StateAp*, PartitionCompare> mergeSort;
  132. PartitionCompare partCompare;
  133. /* The lists of unsplitable (partList) and splitable partitions.
  134. * Only partitions in the splitable list are check for needing splitting. */
  135. PartitionList partList, splittable;
  136. /* Initially, all partitions are born from a split (the initial
  137. * partitioning) and can cause other partitions to be split. So any
  138. * partition with a state with a transition out to another partition is a
  139. * candidate for splitting. This will make every partition except possibly
  140. * partitions of final states split candidates. */
  141. for ( int p = 0; p < numParts; p++ ) {
  142. /* Assume not active. */
  143. parts[p].active = false;
  144. /* Look for a trans out of any state in the partition. */
  145. for ( StateList::Iter state = parts[p].list; state.lte(); state++ ) {
  146. /* If there is at least one transition out to another state then
  147. * the partition becomes splittable. */
  148. if ( state->outList.length() > 0 ) {
  149. parts[p].active = true;
  150. break;
  151. }
  152. }
  153. /* If it was found active then it goes on the splittable list. */
  154. if ( parts[p].active )
  155. splittable.append( &parts[p] );
  156. else
  157. partList.append( &parts[p] );
  158. }
  159. /* While there are partitions that are splittable, pull one off and try
  160. * to split it. If it splits, determine which partitions may now be split
  161. * as a result of the newly split partition. */
  162. while ( splittable.length() > 0 ) {
  163. MinPartition *partition = splittable.detachFirst();
  164. /* Fill the pointer array with the states in the partition. */
  165. StateList::Iter state = partition->list;
  166. for ( int s = 0; state.lte(); state++, s++ )
  167. statePtrs[s] = state;
  168. /* Sort the states using the partitioning compare. */
  169. int numStates = partition->list.length();
  170. mergeSort.sort( statePtrs, numStates );
  171. /* Assign the states into partitions based on the results of the sort. */
  172. MinPartition *destPart = partition;
  173. int firstNewPart = numParts;
  174. for ( int s = 1; s < numStates; s++ ) {
  175. /* If this state differs from the last then move to the next partition. */
  176. if ( partCompare.compare( statePtrs[s-1], statePtrs[s] ) < 0 ) {
  177. /* The new partition is the next avail spot. */
  178. destPart = &parts[numParts];
  179. numParts += 1;
  180. }
  181. /* If the state is not staying in the first partition, then
  182. * transfer it to its destination partition. */
  183. if ( destPart != partition ) {
  184. StateAp *state = partition->list.detach( statePtrs[s] );
  185. destPart->list.append( state );
  186. }
  187. }
  188. /* Fix the partition pointer for all the states that got moved to a new
  189. * partition. This must be done after the states are transfered so the
  190. * result of the sort is not altered. */
  191. int newPart;
  192. for ( newPart = firstNewPart; newPart < numParts; newPart++ ) {
  193. StateList::Iter state = parts[newPart].list;
  194. for ( ; state.lte(); state++ )
  195. state->alg.partition = &parts[newPart];
  196. }
  197. /* Put the partition we just split and any new partitions that came out
  198. * of the split onto the inactive list. */
  199. partition->active = false;
  200. partList.append( partition );
  201. for ( newPart = firstNewPart; newPart < numParts; newPart++ ) {
  202. parts[newPart].active = false;
  203. partList.append( &parts[newPart] );
  204. }
  205. if ( destPart == partition )
  206. continue;
  207. /* Now determine which partitions are splittable as a result of
  208. * splitting partition by walking the in lists of the states in
  209. * partitions that got split. Partition is the faked first item in the
  210. * loop. */
  211. MinPartition *causalPart = partition;
  212. newPart = firstNewPart - 1;
  213. while ( newPart < numParts ) {
  214. /* Loop all states in the causal partition. */
  215. StateList::Iter state = causalPart->list;
  216. for ( ; state.lte(); state++ ) {
  217. /* Walk all transition into the state and put the partition
  218. * that the from state is in onto the splittable list. */
  219. for ( TransInList::Iter trans = state->inList; trans.lte(); trans++ ) {
  220. MinPartition *fromPart = trans->fromState->alg.partition;
  221. if ( ! fromPart->active ) {
  222. fromPart->active = true;
  223. partList.detach( fromPart );
  224. splittable.append( fromPart );
  225. }
  226. }
  227. }
  228. newPart += 1;
  229. causalPart = &parts[newPart];
  230. }
  231. }
  232. return numParts;
  233. }
  234. /**
  235. * \brief Minimize by partitioning version 2 (best alg).
  236. *
  237. * Repeatedly tries to split partitions that may splittable until there are no
  238. * more partitions that might possibly need splitting. Runs faster than
  239. * version 1. Produces the most minimal fsm possible.
  240. */
  241. void FsmAp::minimizePartition2()
  242. {
  243. /* Need a mergesort and an initial partition compare. */
  244. MergeSort<StateAp*, InitPartitionCompare> mergeSort;
  245. InitPartitionCompare initPartCompare;
  246. /* Nothing to do if there are no states. */
  247. if ( stateList.length() == 0 )
  248. return;
  249. /*
  250. * First thing is to partition the states by final state status and
  251. * transition functions. This gives us an initial partitioning to work
  252. * with.
  253. */
  254. /* Make a array of pointers to states. */
  255. int numStates = stateList.length();
  256. StateAp** statePtrs = new StateAp*[numStates];
  257. /* Fill up an array of pointers to the states for easy sorting. */
  258. StateList::Iter state = stateList;
  259. for ( int s = 0; state.lte(); state++, s++ )
  260. statePtrs[s] = state;
  261. /* Sort the states using the array of states. */
  262. mergeSort.sort( statePtrs, numStates );
  263. /* An array of lists of states is used to partition the states. */
  264. MinPartition *parts = new MinPartition[numStates];
  265. /* Assign the states into partitions. */
  266. int destPart = 0;
  267. for ( int s = 0; s < numStates; s++ ) {
  268. /* If this state differs from the last then move to the next partition. */
  269. if ( s > 0 && initPartCompare.compare( statePtrs[s-1], statePtrs[s] ) < 0 ) {
  270. /* Move to the next partition. */
  271. destPart += 1;
  272. }
  273. /* Put the state into its partition. */
  274. statePtrs[s]->alg.partition = &parts[destPart];
  275. parts[destPart].list.append( statePtrs[s] );
  276. }
  277. /* We just moved all the states from the main list into partitions without
  278. * taking them off the main list. So clean up the main list now. */
  279. stateList.abandon();
  280. /* Split partitions. */
  281. int numParts = splitCandidates( statePtrs, parts, destPart+1 );
  282. /* Fuse states in the same partition. The states will end up back on the
  283. * main list. */
  284. fusePartitions( parts, numParts );
  285. /* Cleanup. */
  286. delete[] statePtrs;
  287. delete[] parts;
  288. }
  289. void FsmAp::initialMarkRound( MarkIndex &markIndex )
  290. {
  291. /* P and q for walking pairs. */
  292. StateAp *p = stateList.head, *q;
  293. /* Need an initial partition compare. */
  294. InitPartitionCompare initPartCompare;
  295. /* Walk all unordered pairs of (p, q) where p != q.
  296. * The second depth of the walk stops before reaching p. This
  297. * gives us all unordered pairs of states (p, q) where p != q. */
  298. while ( p != 0 ) {
  299. q = stateList.head;
  300. while ( q != p ) {
  301. /* If the states differ on final state status, out transitions or
  302. * any transition data then they should be separated on the initial
  303. * round. */
  304. if ( initPartCompare.compare( p, q ) != 0 )
  305. markIndex.markPair( p->alg.stateNum, q->alg.stateNum );
  306. q = q->next;
  307. }
  308. p = p->next;
  309. }
  310. }
  311. bool FsmAp::markRound( MarkIndex &markIndex )
  312. {
  313. /* P an q for walking pairs. Take note if any pair gets marked. */
  314. StateAp *p = stateList.head, *q;
  315. bool pairWasMarked = false;
  316. /* Need a mark comparison. */
  317. MarkCompare markCompare;
  318. /* Walk all unordered pairs of (p, q) where p != q.
  319. * The second depth of the walk stops before reaching p. This
  320. * gives us all unordered pairs of states (p, q) where p != q. */
  321. while ( p != 0 ) {
  322. q = stateList.head;
  323. while ( q != p ) {
  324. /* Should we mark the pair? */
  325. if ( !markIndex.isPairMarked( p->alg.stateNum, q->alg.stateNum ) ) {
  326. if ( markCompare.shouldMark( markIndex, p, q ) ) {
  327. markIndex.markPair( p->alg.stateNum, q->alg.stateNum );
  328. pairWasMarked = true;
  329. }
  330. }
  331. q = q->next;
  332. }
  333. p = p->next;
  334. }
  335. return pairWasMarked;
  336. }
  337. /**
  338. * \brief Minimize by pair marking.
  339. *
  340. * Decides if each pair of states is distinct or not. Uses O(n^2) memory and
  341. * should only be used on small graphs. Produces the most minmimal FSM
  342. * possible.
  343. */
  344. void FsmAp::minimizeStable()
  345. {
  346. /* Set the state numbers. */
  347. setStateNumbers( 0 );
  348. /* This keeps track of which pairs have been marked. */
  349. MarkIndex markIndex( stateList.length() );
  350. /* Mark pairs where final stateness, out trans, or trans data differ. */
  351. initialMarkRound( markIndex );
  352. /* While the last round of marking succeeded in marking a state
  353. * continue to do another round. */
  354. int modified = markRound( markIndex );
  355. while (modified)
  356. modified = markRound( markIndex );
  357. /* Merge pairs that are unmarked. */
  358. fuseUnmarkedPairs( markIndex );
  359. }
  360. bool FsmAp::minimizeRound()
  361. {
  362. /* Nothing to do if there are no states. */
  363. if ( stateList.length() == 0 )
  364. return false;
  365. /* Need a mergesort on approx compare and an approx compare. */
  366. MergeSort<StateAp*, ApproxCompare> mergeSort;
  367. ApproxCompare approxCompare;
  368. /* Fill up an array of pointers to the states. */
  369. StateAp **statePtrs = new StateAp*[stateList.length()];
  370. StateList::Iter state = stateList;
  371. for ( int s = 0; state.lte(); state++, s++ )
  372. statePtrs[s] = state;
  373. bool modified = false;
  374. /* Sort The list. */
  375. mergeSort.sort( statePtrs, stateList.length() );
  376. /* Walk the list looking for duplicates next to each other,
  377. * merge in any duplicates. */
  378. StateAp **pLast = statePtrs;
  379. StateAp **pState = statePtrs + 1;
  380. for ( int i = 1; i < stateList.length(); i++, pState++ ) {
  381. if ( approxCompare.compare( *pLast, *pState ) == 0 ) {
  382. /* Last and pState are the same, so fuse together. Move forward
  383. * with pState but not with pLast. If any more are identical, we
  384. * must */
  385. fuseEquivStates( *pLast, *pState );
  386. modified = true;
  387. }
  388. else {
  389. /* Last and this are different, do not set to merge them. Move
  390. * pLast to the current (it may be way behind from merging many
  391. * states) and pState forward one to consider the next pair. */
  392. pLast = pState;
  393. }
  394. }
  395. delete[] statePtrs;
  396. return modified;
  397. }
  398. /**
  399. * \brief Minmimize by an approximation.
  400. *
  401. * Repeatedly tries to find states with transitions out to the same set of
  402. * states on the same set of keys until no more identical states can be found.
  403. * Does not produce the most minimial FSM possible.
  404. */
  405. void FsmAp::minimizeApproximate()
  406. {
  407. /* While the last minimization round succeeded in compacting states,
  408. * continue to try to compact states. */
  409. while ( true ) {
  410. bool modified = minimizeRound();
  411. if ( ! modified )
  412. break;
  413. }
  414. }
  415. /* Remove states that have no path to them from the start state. Recursively
  416. * traverses the graph marking states that have paths into them. Then removes
  417. * all states that did not get marked. */
  418. void FsmAp::removeUnreachableStates()
  419. {
  420. /* Misfit accounting should be off and there should be no states on the
  421. * misfit list. */
  422. assert( !misfitAccounting && misfitList.length() == 0 );
  423. /* Mark all the states that can be reached
  424. * through the existing set of entry points. */
  425. markReachableFromHere( startState );
  426. for ( EntryMap::Iter en = entryPoints; en.lte(); en++ )
  427. markReachableFromHere( en->value );
  428. /* Delete all states that are not marked
  429. * and unmark the ones that are marked. */
  430. StateAp *state = stateList.head;
  431. while ( state ) {
  432. StateAp *next = state->next;
  433. if ( state->stateBits & STB_ISMARKED )
  434. state->stateBits &= ~ STB_ISMARKED;
  435. else {
  436. detachState( state );
  437. stateList.detach( state );
  438. delete state;
  439. }
  440. state = next;
  441. }
  442. }
  443. bool FsmAp::outListCovers( StateAp *state )
  444. {
  445. /* Must be at least one range to cover. */
  446. if ( state->outList.length() == 0 )
  447. return false;
  448. /* The first must start at the lower bound. */
  449. TransList::Iter trans = state->outList.first();
  450. if ( keyOps->minKey < trans->lowKey )
  451. return false;
  452. /* Loop starts at second el. */
  453. trans.increment();
  454. /* Loop checks lower against prev upper. */
  455. for ( ; trans.lte(); trans++ ) {
  456. /* Lower end of the trans must be one greater than the
  457. * previous' high end. */
  458. Key lowKey = trans->lowKey;
  459. lowKey.decrement();
  460. if ( trans->prev->highKey < lowKey )
  461. return false;
  462. }
  463. /* Require that the last range extends to the upper bound. */
  464. trans = state->outList.last();
  465. if ( trans->highKey < keyOps->maxKey )
  466. return false;
  467. return true;
  468. }
  469. /* Remove states that that do not lead to a final states. Works recursivly traversing
  470. * the graph in reverse (starting from all final states) and marking seen states. Then
  471. * removes states that did not get marked. */
  472. void FsmAp::removeDeadEndStates()
  473. {
  474. /* Misfit accounting should be off and there should be no states on the
  475. * misfit list. */
  476. assert( !misfitAccounting && misfitList.length() == 0 );
  477. /* Mark all states that have paths to the final states. */
  478. StateAp **st = finStateSet.data;
  479. int nst = finStateSet.length();
  480. for ( int i = 0; i < nst; i++, st++ )
  481. markReachableFromHereReverse( *st );
  482. /* Start state gets honorary marking. If the machine accepts nothing we
  483. * still want the start state to hang around. This must be done after the
  484. * recursive call on all the final states so that it does not cause the
  485. * start state in transitions to be skipped when the start state is
  486. * visited by the traversal. */
  487. startState->stateBits |= STB_ISMARKED;
  488. /* Delete all states that are not marked
  489. * and unmark the ones that are marked. */
  490. StateAp *state = stateList.head;
  491. while ( state != 0 ) {
  492. StateAp *next = state->next;
  493. if ( state->stateBits & STB_ISMARKED )
  494. state->stateBits &= ~ STB_ISMARKED;
  495. else {
  496. detachState( state );
  497. stateList.detach( state );
  498. delete state;
  499. }
  500. state = next;
  501. }
  502. }
  503. /* Remove states on the misfit list. To work properly misfit accounting should
  504. * be on when this is called. The detaching of a state will likely cause
  505. * another misfit to be collected and it can then be removed. */
  506. void FsmAp::removeMisfits()
  507. {
  508. while ( misfitList.length() > 0 ) {
  509. /* Get the first state. */
  510. StateAp *state = misfitList.head;
  511. /* Detach and delete. */
  512. detachState( state );
  513. /* The state was previously on the misfit list and detaching can only
  514. * remove in transitions so the state must still be on the misfit
  515. * list. */
  516. misfitList.detach( state );
  517. delete state;
  518. }
  519. }
  520. /* Fuse src into dest because they have been deemed equivalent states.
  521. * Involves moving transitions into src to go into dest and invoking
  522. * callbacks. Src is deleted detached from the graph and deleted. */
  523. void FsmAp::fuseEquivStates( StateAp *dest, StateAp *src )
  524. {
  525. /* This would get ugly. */
  526. assert( dest != src );
  527. /* Cur is a duplicate. We can merge it with trail. */
  528. inTransMove( dest, src );
  529. detachState( src );
  530. stateList.detach( src );
  531. delete src;
  532. }
  533. void FsmAp::fuseUnmarkedPairs( MarkIndex &markIndex )
  534. {
  535. StateAp *p = stateList.head, *nextP, *q;
  536. /* Definition: The primary state of an equivalence class is the first state
  537. * encounterd that belongs to the equivalence class. All equivalence
  538. * classes have primary state including equivalence classes with one state
  539. * in it. */
  540. /* For each unmarked pair merge p into q and delete p. q is always the
  541. * primary state of it's equivalence class. We wouldn't have landed on it
  542. * here if it were not, because it would have been deleted.
  543. *
  544. * Proof that q is the primaray state of it's equivalence class: Assume q
  545. * is not the primary state of it's equivalence class, then it would be
  546. * merged into some state that came before it and thus p would be
  547. * equivalent to that state. But q is the first state that p is equivalent
  548. * to so we have a contradiction. */
  549. /* Walk all unordered pairs of (p, q) where p != q.
  550. * The second depth of the walk stops before reaching p. This
  551. * gives us all unordered pairs of states (p, q) where p != q. */
  552. while ( p != 0 ) {
  553. nextP = p->next;
  554. q = stateList.head;
  555. while ( q != p ) {
  556. /* If one of p or q is a final state then mark. */
  557. if ( ! markIndex.isPairMarked( p->alg.stateNum, q->alg.stateNum ) ) {
  558. fuseEquivStates( q, p );
  559. break;
  560. }
  561. q = q->next;
  562. }
  563. p = nextP;
  564. }
  565. }
  566. void FsmAp::fusePartitions( MinPartition *parts, int numParts )
  567. {
  568. /* For each partition, fuse state 2, 3, ... into state 1. */
  569. for ( int p = 0; p < numParts; p++ ) {
  570. /* Assume that there will always be at least one state. */
  571. StateAp *first = parts[p].list.head, *toFuse = first->next;
  572. /* Put the first state back onto the main state list. Don't bother
  573. * removing it from the partition list first. */
  574. stateList.append( first );
  575. /* Fuse the rest of the state into the first. */
  576. while ( toFuse != 0 ) {
  577. /* Save the next. We will trash it before it is needed. */
  578. StateAp *next = toFuse->next;
  579. /* Put the state to be fused in to the first back onto the main
  580. * list before it is fuse. the graph. The state needs to be on
  581. * the main list for the detach from the graph to work. Don't
  582. * bother removing the state from the partition list first. We
  583. * need not maintain it. */
  584. stateList.append( toFuse );
  585. /* Now fuse to the first. */
  586. fuseEquivStates( first, toFuse );
  587. /* Go to the next that we saved before trashing the next pointer. */
  588. toFuse = next;
  589. }
  590. /* We transfered the states from the partition list into the main list without
  591. * removing the states from the partition list first. Clean it up. */
  592. parts[p].list.abandon();
  593. }
  594. }
  595. /* Merge neighboring transitions go to the same state and have the same
  596. * transitions data. */
  597. void FsmAp::compressTransitions()
  598. {
  599. for ( StateList::Iter st = stateList; st.lte(); st++ ) {
  600. if ( st->outList.length() > 1 ) {
  601. for ( TransList::Iter trans = st->outList, next = trans.next(); next.lte(); ) {
  602. Key nextLow = next->lowKey;
  603. nextLow.decrement();
  604. if ( trans->highKey == nextLow && trans->toState == next->toState &&
  605. CmpActionTable::compare( trans->actionTable, next->actionTable ) == 0 )
  606. {
  607. trans->highKey = next->highKey;
  608. st->outList.detach( next );
  609. detachTrans( next->fromState, next->toState, next );
  610. delete next;
  611. next = trans.next();
  612. }
  613. else {
  614. trans.increment();
  615. next.increment();
  616. }
  617. }
  618. }
  619. }
  620. }