Source code of Windows XP (NT5)
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.

742 lines
20 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1997 - 1998
  6. //
  7. // File: cliqwork.cpp
  8. //
  9. //--------------------------------------------------------------------------
  10. //
  11. // cliqwork.cpp
  12. //
  13. #include <basetsd.h>
  14. #include "cliqset.h"
  15. #include "clique.h"
  16. #include "cliqwork.h"
  17. #ifdef _DEBUG
  18. // #define DUMP
  19. #endif
  20. // Sort helper 'less' function for sorting arrays of node pointers into 'mark' sequence.
  21. class MARKSRTPGND : public binary_function<const GNODEMBN *, const GNODEMBN *, bool>
  22. {
  23. public:
  24. bool operator () (const GNODEMBN * pa, const GNODEMBN * pb) const
  25. { return pa->IMark() < pb->IMark() ; }
  26. };
  27. #ifdef _DEBUG
  28. static void seqchkVpnodeByMark (const VPGNODEMBN & vpgnd)
  29. {
  30. int imrk = INT_MIN;
  31. int imrk2;
  32. for ( int i = 0; i < vpgnd.size(); i++, imrk = imrk2)
  33. {
  34. imrk2 = vpgnd[i]->IMark();
  35. assert( imrk2 >= 0 );
  36. assert( imrk2 >= imrk );
  37. }
  38. }
  39. #endif
  40. // Sort the clique information array into topological sequence
  41. void CLIQSETWORK :: TopSortNodeCliqueInfo ()
  42. {
  43. sort( _vndcqInfo.begin(), _vndcqInfo.end() );
  44. }
  45. // Sort the given node pointer array in to "mark" (cliquing order) sequence
  46. void CLIQSETWORK :: MarkSortNodePtrArray ( VPGNODEMBN & vpgnd )
  47. {
  48. MARKSRTPGND marksorter;
  49. sort( vpgnd.begin(), vpgnd.end(), marksorter );
  50. #ifdef _DEBUG
  51. seqchkVpnodeByMark( vpgnd );
  52. #endif
  53. }
  54. // Establish an absolute ordering based upon the topological ordering
  55. void CLIQSETWORK :: RenumberNodesForCliquing ()
  56. {
  57. // Perform a topological sort of the network
  58. Model().TopSortNodes();
  59. MODEL::MODELENUM mdlenum( Model() );
  60. GELEMLNK * pgelm;
  61. _vndcqInfo.clear();
  62. // Collect all the nodes into a pointer array
  63. while ( pgelm = mdlenum.PlnkelNext() )
  64. {
  65. if ( pgelm->EType() != GOBJMBN::EBNO_NODE )
  66. continue;
  67. NDCQINFO ndcq;
  68. DynCastThrow( pgelm, ndcq._pgnd );
  69. _vndcqInfo.push_back( ndcq );
  70. }
  71. // Sort the array into topological sequence.
  72. TopSortNodeCliqueInfo();
  73. #ifdef _DEBUG
  74. int iTop = -1;
  75. #endif
  76. // Establish the total ordering based upon topological level.
  77. for ( int i = 0; i < _vndcqInfo.size() ; i++ )
  78. {
  79. GNODEMBN * pgnd = _vndcqInfo[i]._pgnd;
  80. assert( pgnd );
  81. #ifdef _DEBUG
  82. // Check sequence.
  83. assert( iTop <= pgnd->ITopLevel() );
  84. iTop = pgnd->ITopLevel();
  85. #endif
  86. pgnd->IMark() = i;
  87. }
  88. }
  89. void CLIQSETWORK :: PrepareForBuild ()
  90. {
  91. // Resize and initialize the work arrays
  92. int cCliques = _vvpgnd.size();
  93. _viParent.resize( cCliques );
  94. _viOrder.resize( cCliques );
  95. _viCNodesCommon.resize( cCliques );
  96. _viICliqCommon.resize( cCliques );
  97. _viOrdered.clear();
  98. for ( int iClique = 0; iClique < cCliques; iClique++ )
  99. {
  100. MarkSortNodePtrArray( _vvpgnd[iClique] );
  101. _viParent[iClique] = INT_MIN;
  102. _viOrder[iClique] = INT_MIN;
  103. _viCNodesCommon[iClique] = INT_MIN;
  104. _viICliqCommon[iClique] = INT_MIN;
  105. }
  106. }
  107. // Return the number of nodes in common between the two cliques
  108. int CLIQSETWORK :: CNodesCommon ( int iClique1, int iClique2 )
  109. {
  110. assert( iClique1 < _vvpgnd.size() && iClique2 < _vvpgnd.size() );
  111. return CNodesCommon( _vvpgnd[iClique1], _vvpgnd[iClique2] );
  112. }
  113. // Return the number of nodes in common between the two node lists
  114. int CLIQSETWORK :: CNodesCommon ( const VPGNODEMBN & vpgnd1, const VPGNODEMBN & vpgnd2 )
  115. {
  116. MARKSRTPGND marksorter;
  117. #ifdef _DEBUG
  118. seqchkVpnodeByMark( vpgnd1 );
  119. seqchkVpnodeByMark( vpgnd2 );
  120. #endif
  121. int cCommon = count_set_intersection( vpgnd1.begin(),
  122. vpgnd1.end(),
  123. vpgnd2.begin(),
  124. vpgnd2.end(),
  125. marksorter );
  126. return cCommon;
  127. }
  128. // Return the ordered index of a clique or -1 if not in the tree yet.
  129. inline
  130. int CLIQSETWORK :: IOrdered ( int iClique )
  131. {
  132. return ifind( _viOrdered, iClique );
  133. }
  134. // Update the "most common clique" info of iClique1 based upon iClique2. This is
  135. // used to count the number of nodes in common between a candidate clique and a
  136. // clique already in the tree.
  137. void CLIQSETWORK :: SetCNodeMaxCommon ( int iClique1, int iCliqueOrdered2 )
  138. {
  139. assert( iCliqueOrdered2 < _viOrdered.size() );
  140. int iClique2 = _viOrdered[iCliqueOrdered2];
  141. int cCommon = CNodesCommon( iClique1, iClique2 );
  142. if ( cCommon > _viCNodesCommon[iClique1] )
  143. {
  144. _viCNodesCommon[iClique1] = cCommon;
  145. _viICliqCommon[iClique1] = iCliqueOrdered2;
  146. }
  147. }
  148. //
  149. // Completely update the "most common clique" information for this clique.
  150. // This is necessary because cliques can change membership due to subsumption
  151. // during generation of the clique tree.
  152. // Return true if there is any overlap with a clique already in the tree.
  153. //
  154. bool CLIQSETWORK :: BUpdateCNodeMaxCommon ( int iClique )
  155. {
  156. assert( _viOrder[iClique] == INT_MIN );
  157. int & cNodesCommon = _viCNodesCommon[iClique];
  158. int & iCliqCommon = _viICliqCommon[iClique];
  159. cNodesCommon = INT_MIN;
  160. iCliqCommon = INT_MIN;
  161. for ( int iord = 0; iord < _viOrdered.size(); iord++ )
  162. {
  163. SetCNodeMaxCommon( iClique, iord );
  164. }
  165. return cNodesCommon > 0;
  166. }
  167. // Return true if clique 1 has more nodes in common with a clique that is already in
  168. // the tree than clique2. If they have the same number of nodes in common, return
  169. // true if clique 1 has fewer nodes than clique2.
  170. bool CLIQSETWORK :: BBetter ( int iClique1, int iClique2 )
  171. {
  172. assert( _viCNodesCommon[iClique1] >= 0 );
  173. assert( _viCNodesCommon[iClique2] >= 0 );
  174. if ( _viCNodesCommon[iClique1] != _viCNodesCommon[iClique2] )
  175. return _viCNodesCommon[iClique1] > _viCNodesCommon[iClique2];
  176. return _vvpgnd[iClique1].size() < _vvpgnd[iClique2].size();
  177. }
  178. // After building the cliques, topologically sort them and anchor each node
  179. // to the highest clique in the tree to which it belongs.
  180. void CLIQSETWORK :: SetTopologicalInfo ()
  181. {
  182. #ifdef DUMP
  183. DumpTree();
  184. #endif
  185. // First, set up the ordered parent information array
  186. int cCliqueOrdered = _viOrdered.size();
  187. assert( cCliqueOrdered > 0 );
  188. int cClique = _viOrder.size();
  189. _viParentOrdered.resize(cCliqueOrdered);
  190. for ( int icq = 0; icq < cCliqueOrdered; ++icq )
  191. {
  192. int iClique = _viOrdered[icq];
  193. assert( iClique < cClique && iClique >= 0 );
  194. int iCliqueParent = _viParent[iClique];
  195. assert( iCliqueParent < cClique && iCliqueParent >= 0 );
  196. assert( CNodesCommon( iClique, iCliqueParent ) > 0 );
  197. int iCliqueParentOrdered = IOrdered( iCliqueParent );
  198. assert( iCliqueParentOrdered < cCliqueOrdered && iCliqueParentOrdered >= 0 );
  199. _viParentOrdered[icq] = iCliqueParentOrdered;
  200. }
  201. // Next, follow each ordered clique's parentage to compute its topological level
  202. _viTopLevelOrdered.resize(cCliqueOrdered);
  203. int cTrees = 0;
  204. for ( icq = 0; icq < cCliqueOrdered; ++icq )
  205. {
  206. int icqParent = icq;
  207. // Follow until we get to a (the) root clique
  208. for ( int itop = 0; icqParent != _viParentOrdered[icqParent]; ++itop )
  209. {
  210. assert( itop < cCliqueOrdered );
  211. icqParent = _viParentOrdered[icqParent];
  212. }
  213. if ( itop == 0 )
  214. cTrees++ ;
  215. _viTopLevelOrdered[icq] = itop;
  216. }
  217. assert( cTrees == _cTrees );
  218. // Next, find each node's "family" clique. This is the smallest clique containing
  219. // it and its parents.
  220. VPGNODEMBN vpgnd;
  221. for ( int ind = 0 ; ind < _vndcqInfo.size(); ind++ )
  222. {
  223. NDCQINFO & ndcq = _vndcqInfo[ind];
  224. vpgnd.clear();
  225. // Get the "family" set and sort it for matching other cliques.
  226. ndcq._pgnd->GetFamily( vpgnd );
  227. MarkSortNodePtrArray( vpgnd );
  228. int cFamily = vpgnd.size();
  229. int cCommonSize = INT_MAX;
  230. int iCqCommon = -1;
  231. // Find the smallest clique containing the family
  232. for ( icq = 0; icq < cCliqueOrdered; ++icq )
  233. {
  234. const VPGNODEMBN & vpgndClique = _vvpgnd[ _viOrdered[icq] ];
  235. int cCqCommon = CNodesCommon( vpgnd, vpgndClique );
  236. // See if this clique contains the family and is smaller than any other.
  237. if ( cCqCommon == cFamily && vpgndClique.size() < cCommonSize )
  238. {
  239. iCqCommon = icq;
  240. }
  241. }
  242. assert( iCqCommon >= 0 );
  243. ndcq._iCliqOrdFamily = iCqCommon;
  244. // Now, find the highest clique in the tree containing this node.
  245. int itop = INT_MAX;
  246. int iCqTop = -1;
  247. for ( icq = 0; icq < cCliqueOrdered; ++icq )
  248. {
  249. const VPGNODEMBN & vpgndClique = _vvpgnd[ _viOrdered[icq] ];
  250. int ind = ifind( vpgndClique, ndcq._pgnd );
  251. if ( ind >= 0 && _viTopLevelOrdered[icq] < itop )
  252. {
  253. iCqTop = icq;
  254. itop = _viTopLevelOrdered[icq];
  255. }
  256. }
  257. assert( iCqTop >= 0 );
  258. ndcq._iCliqOrdSelf = iCqTop;
  259. }
  260. #ifdef DUMP
  261. DumpTopInfo();
  262. #endif
  263. }
  264. void CLIQSETWORK :: BuildCliques ()
  265. {
  266. // Prepare tables for junction tree construction
  267. PrepareForBuild() ;
  268. // Choose the zeroth arbitrarily as a starting point; set it as its own parent.
  269. // As we iterate over the array, we assign an ordering to cliques. If the clique has
  270. // already been ordered, its value in _viOrder will either >= 0 (order in clique tree)
  271. //
  272. _cTrees = 1;
  273. _viParent[0] = 0;
  274. _viOrder[0] = 0;
  275. _viOrdered.clear();
  276. _viOrdered.push_back(0);
  277. for (;;)
  278. {
  279. int iCliqueBest = INT_MAX; // Best clique found so far
  280. // Find a new clique that has the largest overlap with any of the cliques already in the tree.
  281. for ( int iClique = 0; iClique < _vvpgnd.size(); iClique++ )
  282. {
  283. int iord = _viOrder[iClique];
  284. if ( iord != INT_MIN )
  285. continue; // Clique has already been ordered or dealt with
  286. // Update the "most common clique already in tree" info between this clique
  287. // and all the cliques in the trees
  288. BUpdateCNodeMaxCommon( iClique );
  289. //MSRDEVBUG: SetCNodeMaxCommon( iClique, _viOrdered.size() - 1 );
  290. if ( iCliqueBest == INT_MAX )
  291. {
  292. // first time through the loop
  293. iCliqueBest = iClique;
  294. }
  295. else
  296. if ( BBetter( iClique, iCliqueBest ) )
  297. {
  298. // This clique has an overlap as large as any other yet found.
  299. iCliqueBest = iClique;
  300. }
  301. }
  302. // See if we're done
  303. if ( iCliqueBest == INT_MAX )
  304. break;
  305. // Get the ordered index and absolute index of the most common clique
  306. int iCliqueCommonOrdered = _viICliqCommon[iCliqueBest];
  307. assert( iCliqueCommonOrdered >= 0 && iCliqueCommonOrdered < _viOrdered.size() );
  308. int iCliqueCommon = _viOrdered[ iCliqueCommonOrdered ];
  309. assert( iCliqueCommon >= 0 );
  310. assert( iCliqueBest != iCliqueCommon );
  311. int cNodesCommon = _viCNodesCommon[iCliqueBest];
  312. assert( cNodesCommon <= _vvpgnd[iCliqueCommon].size() );
  313. assert( cNodesCommon <= _vvpgnd[iCliqueBest].size() );
  314. assert( cNodesCommon == CNodesCommon( iCliqueCommon, iCliqueBest ) ) ;
  315. // Index of clique to be added to ordered clique set
  316. int iCliqueNew = INT_MAX;
  317. // If the candidate clique has the same number of nodes in common with its most
  318. // common clique as that clique has members, then this clique is either identical
  319. // to or a superset of that clique.
  320. if ( cNodesCommon == _vvpgnd[iCliqueCommon].size() )
  321. {
  322. // New clique is superset of its most common clique.
  323. assert( cNodesCommon != 0 );
  324. assert( iCliqueCommon != iCliqueBest );
  325. assert( _vvpgnd[iCliqueCommon].size() < _vvpgnd[iCliqueBest].size() );
  326. // Assign this clique's node set to the previously ordered subset clique
  327. _vvpgnd[iCliqueCommon] = _vvpgnd[iCliqueBest] ;
  328. assert ( _vvpgnd[iCliqueCommon].size() == _vvpgnd[iCliqueBest].size() );
  329. // Leave the parent the same as it was
  330. iCliqueNew = iCliqueCommon;
  331. }
  332. else
  333. if ( cNodesCommon == 0 )
  334. {
  335. // This is the start of a new tree
  336. _cTrees++;
  337. // Self and parent are the same
  338. _viParent[iCliqueBest] = iCliqueNew = iCliqueBest;
  339. _viOrdered.push_back( iCliqueNew );
  340. }
  341. else
  342. if ( cNodesCommon != _vvpgnd[iCliqueBest].size() )
  343. {
  344. // New clique is child of existing clique.
  345. iCliqueNew = iCliqueBest;
  346. _viParent[iCliqueBest] = iCliqueCommon ;
  347. // Keep this clique by adding it to the ordered clique set.
  348. _viOrdered.push_back( iCliqueNew );
  349. }
  350. else
  351. {
  352. // Child is subset of parent; ignore by marking as "subsumed"
  353. iCliqueNew = - iCliqueCommon;
  354. }
  355. // Mark the clique as either ordered or subsumed.
  356. _viOrder[iCliqueBest] = iCliqueNew;
  357. }
  358. #ifdef DUMP
  359. cout << "\n\nBuild cliques; generated " << _cTrees << " clique trees\n\n";
  360. #endif
  361. }
  362. // Verify that the Running Intersection Property holds for this clique tree.
  363. bool CLIQSETWORK :: BCheckRIP ()
  364. {
  365. // Check that topological information has been generated
  366. assert( _viOrdered.size() == _viParentOrdered.size() );
  367. for ( int iCliqueOrdered = 0; iCliqueOrdered < _viOrdered.size(); iCliqueOrdered++ )
  368. {
  369. if ( ! BCheckRIP( iCliqueOrdered ) )
  370. return false;
  371. }
  372. return true;
  373. }
  374. // Verify that the Running Intersection Property holds for this clique.
  375. bool CLIQSETWORK :: BCheckRIP ( int iCliqueOrdered )
  376. {
  377. int iClique = _viOrdered[iCliqueOrdered];
  378. const VPGNODEMBN & vpgndClique = _vvpgnd[iClique];
  379. int iCliqueParent = _viParent[iClique];
  380. const VPGNODEMBN & vpgndCliqueParent = _vvpgnd[iCliqueParent];
  381. bool bRoot = iCliqueParent == iClique;
  382. // For every node in this clique, check that either:
  383. //
  384. // 1) this is a root clique, or
  385. // 2) the node is present in the parent clique.
  386. //
  387. // If this test fails, check that this is the "self" clique,
  388. // which is the highest clique in the tree in which the
  389. // node appears.
  390. //
  391. for ( int iNode = 0; iNode < vpgndClique.size(); iNode++ )
  392. {
  393. // Access the node information for this node
  394. GNODEMBN * pgnd = vpgndClique[iNode];
  395. if ( bRoot || ifind( vpgndCliqueParent, pgnd ) < 0 )
  396. {
  397. NDCQINFO & ndcq = _vndcqInfo[ pgnd->IMark() ];
  398. if ( ndcq._iCliqOrdSelf != iCliqueOrdered )
  399. {
  400. #ifdef _DEBUG
  401. cout << "RIP FAILURE: node "
  402. << ndcq._pgnd->ZsrefName().Szc()
  403. << " is in clique "
  404. << iCliqueOrdered
  405. << " but absent from "
  406. << _viParentOrdered[iCliqueOrdered]
  407. << "("
  408. << _viParent[iClique]
  409. << ")"
  410. ;
  411. #endif
  412. return false;
  413. }
  414. }
  415. }
  416. return true;
  417. }
  418. // Using the constructed tables, create the clique objects and
  419. // link them to each other and their member nodes.
  420. void CLIQSETWORK :: CreateTopology ()
  421. {
  422. _vpclq.resize( _viOrdered.size() ) ;
  423. for ( int i = 0; i < _vpclq.size(); )
  424. _vpclq[i++] = NULL;
  425. int iInferEngID = _cliqset._iInferEngID;
  426. int ccq = 0; // Total cliques created
  427. // Create all cliques. Iterate in topological order, creating
  428. // the cliques and linking them to their parents.
  429. for ( int itop = 0;; itop++)
  430. {
  431. int ccqLevel = 0; // Number of cliques added at this topological level
  432. for ( int icq = 0; icq < _viOrdered.size(); icq++ )
  433. {
  434. if ( _viTopLevelOrdered[icq] != itop )
  435. continue;
  436. GOBJMBN_CLIQUE * pclqParent = NULL;
  437. GOBJMBN_CLIQUE * pclqThis = NULL;
  438. int iParentOrdered = _viParentOrdered[icq];
  439. if ( iParentOrdered != icq )
  440. {
  441. // Get the parent clique pointer
  442. pclqParent = _vpclq[ iParentOrdered ];
  443. assert( pclqParent );
  444. }
  445. else
  446. {
  447. // Root cliques have toplevel zero
  448. assert( itop == 0 );
  449. }
  450. // Create the new clique and its edge to its parent clique (if any)
  451. pclqThis = _vpclq[icq] = new GOBJMBN_CLIQUE( icq, iInferEngID );
  452. Model().AddElem( pclqThis );
  453. if ( pclqParent )
  454. {
  455. // This is not a root clique; link it to its parent.
  456. Model().AddElem( new GEDGEMBN_SEPSET( pclqParent, pclqThis ) );
  457. }
  458. else
  459. {
  460. // This IS a root clique; mark it and link it to the clique set top.
  461. pclqThis->_bRoot = true;
  462. Model().AddElem( new GEDGEMBN_CLIQSET( & _cliqset, pclqThis ) );
  463. }
  464. ++_cliqset._cCliques;
  465. if ( pclqParent )
  466. {
  467. ++_cliqset._cSepsetArcs;
  468. }
  469. ccq++;
  470. ccqLevel++;
  471. }
  472. if ( ccqLevel == 0 )
  473. break; // No cliques added at this topological level: we're done
  474. }
  475. assert( ccq == _viOrdered.size() );
  476. // For each of the new cliques, add all members
  477. for ( i = 0; i < _vpclq.size(); i++ )
  478. {
  479. const VPGNODEMBN & vpgndMembers = _vvpgnd[ _viOrdered[i] ];
  480. for ( int ind = 0; ind < vpgndMembers.size(); ind++)
  481. {
  482. // Get the node pointer and the data pointer
  483. GNODEMBN * pgnd = vpgndMembers[ind];
  484. const NDCQINFO & ndcq = _vndcqInfo[ pgnd->IMark() ];
  485. assert( pgnd == ndcq._pgnd );
  486. int fRole = GEDGEMBN_CLIQ::NONE;
  487. if ( ndcq._iCliqOrdSelf == i )
  488. fRole |= GEDGEMBN_CLIQ::SELF;
  489. if ( ndcq._iCliqOrdFamily == i )
  490. fRole |= GEDGEMBN_CLIQ::FAMILY;
  491. Model().AddElem( new GEDGEMBN_CLIQ( _vpclq[i], pgnd, fRole ) );
  492. ++_cliqset._cCliqueMemberArcs;
  493. }
  494. }
  495. #ifdef _DEBUG
  496. for ( i = 0; i < _vpclq.size(); i++ )
  497. {
  498. const VPGNODEMBN & vpgndMembers = _vvpgnd[ _viOrdered[i] ];
  499. VPGNODEMBN vpgndMembers2;
  500. _vpclq[i]->GetMembers( vpgndMembers2 );
  501. assert( vpgndMembers2.size() == vpgndMembers.size() );
  502. MarkSortNodePtrArray( vpgndMembers2 );
  503. assert( vpgndMembers2 == vpgndMembers );
  504. // Exercise the topology by locating the "self" and "family" cliques
  505. for ( int imbr = 0; imbr < vpgndMembers.size(); imbr++ )
  506. {
  507. GNODEMBN * pgnd = vpgndMembers[imbr];
  508. GOBJMBN_CLIQUE * pCliqueFamily = _cliqset.PCliqueFromNode( pgnd, false );
  509. GOBJMBN_CLIQUE * pCliqueSelf = _cliqset.PCliqueFromNode( pgnd, false );
  510. assert( pCliqueFamily );
  511. assert( pCliqueSelf );
  512. }
  513. }
  514. #endif
  515. }
  516. void CLIQSETWORK :: DumpClique ( int iClique )
  517. {
  518. cout << "\tClique "
  519. << iClique
  520. << ':'
  521. << _vvpgnd[iClique]
  522. << "\n";
  523. cout.flush();
  524. }
  525. void CLIQSETWORK :: DumpCliques ()
  526. {
  527. for ( int iClique = 0; iClique < _vvpgnd.size(); ++iClique )
  528. {
  529. DumpClique( iClique );
  530. }
  531. }
  532. void CLIQSETWORK :: DumpTree ()
  533. {
  534. for ( int iCliqueOrd = 0; iCliqueOrd < _viOrdered.size(); ++iCliqueOrd )
  535. {
  536. int iClique = _viOrdered[iCliqueOrd];
  537. cout << "\tTree Clique "
  538. << iCliqueOrd
  539. << " ("
  540. << iClique
  541. << "), parent "
  542. << IOrdered( _viParent[iClique] )
  543. << " ("
  544. << _viParent[iClique]
  545. << "): "
  546. << _vvpgnd[iClique]
  547. << "\n";
  548. }
  549. cout.flush();
  550. }
  551. void CLIQSETWORK :: DumpTopInfo()
  552. {
  553. for ( int iCliqueOrd = 0; iCliqueOrd < _viOrdered.size(); ++iCliqueOrd )
  554. {
  555. cout << "\tTree Clique "
  556. << iCliqueOrd
  557. << " (" << _viOrdered[iCliqueOrd] << ")"
  558. << ", parent is "
  559. << _viParentOrdered[iCliqueOrd]
  560. << " (" << _viOrdered[_viParentOrdered[iCliqueOrd]] << ")"
  561. << ", top level is "
  562. << _viTopLevelOrdered[iCliqueOrd]
  563. << "\n";
  564. }
  565. for ( int ind = 0 ; ind < _vndcqInfo.size(); ind++ )
  566. {
  567. NDCQINFO & ndcq = _vndcqInfo[ind];
  568. cout << "\tNode ";
  569. cout.width( 20 );
  570. cout << ndcq._pgnd->ZsrefName().Szc()
  571. << "\tfamily is clique "
  572. << ndcq._iCliqOrdFamily
  573. << ", self is clique "
  574. << ndcq._iCliqOrdSelf
  575. << "\n";
  576. }
  577. cout.flush();
  578. }
  579. //
  580. // Estimate the total size of the structures necessary to support the
  581. // compute clique trees.
  582. //
  583. REAL CLIQSETWORK :: REstimatedSize ()
  584. {
  585. int cClique = 0;
  586. int cSepsetArc = 0;
  587. int cCliqsetArc = 0;
  588. size_t cMbrArc = 0;
  589. int cCliqueEntries = 0;
  590. int cFamEntries = 0;
  591. for ( int icq = 0; icq < _viOrdered.size(); icq++ )
  592. {
  593. cClique++;
  594. if ( icq != _viParentOrdered[icq] )
  595. {
  596. // Clique has a parent
  597. cSepsetArc++;
  598. }
  599. else
  600. {
  601. // Clique is root
  602. cCliqsetArc++;
  603. }
  604. // Account for clique membership arcs
  605. const VPGNODEMBN & vpgndMembers = _vvpgnd[ _viOrdered[icq] ];
  606. int cMbr = vpgndMembers.size();
  607. cMbrArc += vpgndMembers.size();
  608. // Compute the size of the joint table for this clique
  609. VIMD vimd(cMbr);
  610. GNODEMBND * pgndd;
  611. for ( int ind = 0; ind < vpgndMembers.size(); ind++)
  612. {
  613. // Get the discrete node pointer and the data pointer
  614. DynCastThrow( vpgndMembers[ind], pgndd );
  615. // Add to the clique's dimensionality
  616. vimd[ind] = pgndd->CState();
  617. const NDCQINFO & ndcq = _vndcqInfo[ pgndd->IMark() ];
  618. assert( pgndd == ndcq._pgnd );
  619. // If this is the edge to the "family" clique, it will
  620. // contain the reordered discrete conditional probabilities
  621. // for this node, so we must compute it size.
  622. if ( ndcq._iCliqOrdFamily == icq )
  623. {
  624. // This is the edge leading to this node's "family" clique
  625. VPGNODEMBN vpgndFamily; // List of parents and self
  626. pgndd->GetParents( vpgndFamily, true );
  627. GNODEMBND * pgnddFamily;
  628. int cStates = 1;
  629. for ( int ifam = 0; ifam < vpgndFamily.size(); ifam++ )
  630. {
  631. DynCastThrow( vpgndFamily[ifam], pgnddFamily );
  632. cStates *= pgnddFamily->CState();
  633. }
  634. cFamEntries += cStates;
  635. }
  636. }
  637. MDVSLICE mdvs( vimd );
  638. cCliqueEntries += mdvs._Totlen();
  639. }
  640. REAL rcb = 0;
  641. rcb += cClique * sizeof(GOBJMBN_CLIQUE);
  642. rcb += cSepsetArc * sizeof(GEDGEMBN_SEPSET);
  643. rcb += cCliqsetArc * sizeof(GEDGEMBN_CLIQSET);
  644. rcb += cMbrArc * sizeof(GEDGEMBN_CLIQ);
  645. rcb += cCliqueEntries * sizeof(REAL);
  646. rcb += cFamEntries * sizeof(REAL);
  647. #ifdef DUMP
  648. cout << "\nEstimated clique tree memory is " << rcb;
  649. #endif
  650. return rcb;
  651. }