Leaked source code of windows server 2003
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.

561 lines
15 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1997 - 1998
  6. //
  7. // File: gnodembn.cpp
  8. //
  9. //--------------------------------------------------------------------------
  10. //
  11. // GNODEMBN.CPP
  12. //
  13. #include <basetsd.h>
  14. #include <typeinfo.h>
  15. #include "gmobj.h"
  16. #include "cliqset.h"
  17. #include "clique.h"
  18. #include "algos.h"
  19. #include "domain.h"
  20. /*****************************************************************************************
  21. Cloning and cloning functions.
  22. There are two types of cloning member functions:
  23. 1) functions named "Clone", in which the new object is being
  24. asked to initialize itself from another existing object.
  25. This is not a copy constructor due to the complexity of timing
  26. chained construcions.
  27. 2) functions named "CloneNew", in which an existing object is being
  28. asked to participate in the construction of a new object.
  29. Functions of type #1 are straightforward, such as
  30. virtual void MODEL :: Clone ( MODEL & model );
  31. Here, a MODEL is being asked to clone or copy information from an existing
  32. network into itself. The object can place whatever restrictions it would like
  33. on such functions. For example, the MODEL class requires that the new MODEL
  34. object be entirely empty.
  35. Functions of type #2 are more complex, such as
  36. virtual GOBJMBN * GOBJMBN :: CloneNew ( MBNET & mbnetSelf,
  37. MBNET & mbnetNew,
  38. GOBJMBN * pgobjNew = NULL );
  39. In this case, there are references to the original and clone networks (MBNETs),
  40. and a pointer to the newly constructed object, which may be NULL. Consider a
  41. chain of inheritance such as:
  42. class OBJ;
  43. class SUB_OBJ : public OBJ;
  44. class SUB_SUB_OBJ : public SUB_OBJ;
  45. If a new SUB_SUB_OBJ is to be cloned from an existing one, an empty object must
  46. be constructed first. Then the CloneNew() function the original SUB_SUB_OBJ is
  47. called. At this point, there's a choice: does the SUB_SUB_OBJ perform all the
  48. initialization for all base classes, or should it defer data member cloning
  49. to its base classes? We use the latter approach, as C++ itself does for
  50. construction and destruction.
  51. So, at the top level of object cloning, the initial invocation of CloneNew() will
  52. usually have a NULL object pointer. Each CloneNew() function must check for this,
  53. and either create a new object, if allowed, or throw an exception. It will
  54. then call the CloneNew() function for its immediate ancestral base class using the
  55. new pointer. The ancestral CloneNew() function will see that there already is a
  56. pointer and simply use it.
  57. In other words, the Clone() member functions are simple "build yourself from
  58. another" commands. The CloneNew() functions collaborate with all ancestral base
  59. classes to correctly construct an object with interdependencies. Note that
  60. the semantics (source vs. target) are reversed.
  61. The bulk of the complexity in cloning an MBNET or MODEL (or subclass) arises from
  62. the internal string symbol table and the storage of references to strings throughout
  63. the set of associated objects.
  64. *****************************************************************************************/
  65. // MSRDEVBUG: This should not be required since it's pure virtual, but VC++ 5.0 gets confused.
  66. GOBJMBN :: ~ GOBJMBN ()
  67. {
  68. }
  69. GOBJMBN * GOBJMBN :: CloneNew (
  70. MODEL & modelSelf,
  71. MODEL & modelNew,
  72. GOBJMBN * pgobjNew )
  73. {
  74. // If we're expected to create the object, that's a no-no; throw an exception
  75. if ( pgobjNew == NULL )
  76. {
  77. ThrowInvalidClone( self );
  78. }
  79. // Update class-specific member variables
  80. pgobjNew->IMark() = IMark();
  81. pgobjNew->IType() = IType();
  82. // Convert and assign the name, if any
  83. if ( ZsrefName()->length() > 0 )
  84. {
  85. pgobjNew->SetName( modelNew.Mpsymtbl().intern( ZsrefName().Szc() ) ) ;
  86. }
  87. // Handle other variables
  88. pgobjNew->_vFlags = _vFlags;
  89. return pgobjNew;
  90. }
  91. GNODEMBN :: GNODEMBN()
  92. :_iTopLevel(-1)
  93. {
  94. IType() = 0;
  95. }
  96. GNODEMBN :: ~ GNODEMBN()
  97. {
  98. }
  99. GOBJMBN * GNODEMBN :: CloneNew (
  100. MODEL & modelSelf,
  101. MODEL & modelNew,
  102. GOBJMBN * pgobjNew )
  103. {
  104. GNODEMBN * pgnd = NULL;
  105. if ( pgobjNew == NULL )
  106. {
  107. pgnd = new GNODEMBN;
  108. }
  109. else
  110. {
  111. DynCastThrow( pgobjNew, pgnd );
  112. }
  113. ASSERT_THROW( GOBJMBN::CloneNew( modelSelf, modelNew, pgnd ),
  114. EC_INTERNAL_ERROR,
  115. "cloning failed to returned object pointer" );
  116. // Update class-specific member variables
  117. pgnd->_iTopLevel = _iTopLevel;
  118. pgnd->_ltProp.Clone( modelNew, modelSelf, _ltProp );
  119. pgnd->_ptPos = _ptPos;
  120. pgnd->_zsFullName = _zsFullName;
  121. pgnd->_clampIface = _clampIface;
  122. return pgnd;
  123. }
  124. GOBJMBN * GNODEMBND :: CloneNew (
  125. MODEL & modelSelf,
  126. MODEL & modelNew,
  127. GOBJMBN * pgobjNew )
  128. {
  129. GNODEMBND * pgndd = NULL;
  130. if ( pgobjNew == NULL )
  131. {
  132. pgndd = new GNODEMBND;
  133. }
  134. else
  135. {
  136. DynCastThrow( pgobjNew, pgndd );
  137. }
  138. ASSERT_THROW( GNODEMBN::CloneNew( modelSelf, modelNew, pgndd ),
  139. EC_INTERNAL_ERROR,
  140. "cloning failed to returned object pointer" );
  141. // Update class-specific member variables
  142. modelNew.Mpsymtbl().CloneVzsref( modelSelf.Mpsymtbl(), _vzsrState, pgndd->_vzsrState );
  143. return pgndd;
  144. }
  145. void GNODEMBN :: Visit ( bool bUpwards /* = true */ )
  146. {
  147. if ( IMark() )
  148. return;
  149. INT iMarkMax = 0;
  150. GNODENUM<GNODEMBN> benum( bUpwards );
  151. benum.SetETypeFollow( GEDGEMBN::ETPROB );
  152. for ( benum.Set( this );
  153. benum.PnodeCurrent();
  154. benum++ )
  155. {
  156. GNODEMBN * pgndbn = *benum;
  157. pgndbn->Visit( bUpwards );
  158. if ( pgndbn->IMark() > iMarkMax )
  159. iMarkMax = pgndbn->IMark();
  160. }
  161. IMark() = iMarkMax + 1;
  162. }
  163. //
  164. // Fill array with parent pointers (follow directed arcs)
  165. //
  166. // About network "expansion". When CI expansion occurs, nodes
  167. // affected are marked with the flag "EIBF_Expanded". This routine
  168. // normally does one of two things:
  169. //
  170. // If the node is expanded, only parents marked as "EIBF_Expansion"
  171. // are considered as real parents.
  172. //
  173. // If the node is not marked, only parents which are not marked as
  174. // "expansion" are considered.
  175. //
  176. // This can be overridden with the "bUseExpansion" flag, in which case
  177. // the original (pre-expansion) parents will be delivered.
  178. //
  179. void GNODEMBN :: GetParents (
  180. VPGNODEMBN & vpgnode, // Result array
  181. bool bIncludeSelf, // If true, place self as last entry in list
  182. bool bUseExpansion ) // If true, consider expansion information
  183. {
  184. // If requested, and if this node is part of network expansion, only
  185. // consider expansion parents. Otherwise, ignore them and only use real
  186. // parents.
  187. bool bOnlyUseExpansionParents =
  188. bUseExpansion && BFlag( EIBF_Expanded ) ;
  189. // Prepare to iterate over the parents
  190. GNODENUM<GNODEMBN> benumparent(true);
  191. benumparent.SetETypeFollow( GEDGEMBN::ETPROB );
  192. for ( benumparent.Set( this );
  193. benumparent.PnodeCurrent();
  194. benumparent++ )
  195. {
  196. GNODEMBN * pgndParent = *benumparent;
  197. bool bExpansion = pgndParent->BFlag( EIBF_Expansion );
  198. if ( bOnlyUseExpansionParents ^ bExpansion )
  199. continue;
  200. vpgnode.push_back( pgndParent );
  201. }
  202. if ( bIncludeSelf )
  203. vpgnode.push_back( this );
  204. }
  205. // Return the discrete dimension vector of this node if possible;
  206. // return false if any parent is not discrete.
  207. bool GNODEMBND :: BGetVimd (
  208. VIMD & vimd, // Array to fill
  209. bool bIncludeSelf, // Place self as last entry in list
  210. bool bUseExpansion ) // If expanded, use expansion only
  211. {
  212. // Get the parents according to the flags
  213. VPGNODEMBN vpgndParents;
  214. GetParents( vpgndParents, bIncludeSelf, bUseExpansion );
  215. // Prepare the result array
  216. vimd.resize( vpgndParents.size() );
  217. for ( int i = 0; i < vimd.size(); i++ )
  218. {
  219. // See if the next node is discrete; return false if not
  220. GNODEMBND * pgnddParent = dynamic_cast<GNODEMBND *> (vpgndParents[i]);
  221. if ( pgnddParent == NULL )
  222. return false;
  223. // Add to the dimension array
  224. assert( pgnddParent->IType() & FND_Discrete );
  225. vimd[i] = pgnddParent->CState();
  226. }
  227. return true;
  228. }
  229. // Fill array with child pointers (follow directed arcs)
  230. void GNODEMBN :: GetChildren ( VPGNODEMBN & vpgnode, bool bIncludeSelf )
  231. {
  232. // Prepare to iterate over the children
  233. GNODENUM<GNODEMBN> benumchild(false);
  234. benumchild.SetETypeFollow( GEDGEMBN::ETPROB );
  235. for ( benumchild.Set( this );
  236. benumchild.PnodeCurrent();
  237. benumchild++ )
  238. {
  239. vpgnode.push_back( *benumchild );
  240. }
  241. if ( bIncludeSelf )
  242. vpgnode.push_back( this );
  243. }
  244. // Fill array with neighbors (follow undirected arcs)
  245. void GNODEMBN :: GetNeighbors ( VPGNODEMBN & vpgnode, bool bIncludeSelf )
  246. {
  247. // Iterate over all connections to the source node.
  248. // That is, arcs in either direction.
  249. GNODENUM_UNDIR gnenumUndir;
  250. // Initialize the iterator
  251. for ( gnenumUndir = this;
  252. gnenumUndir.PnodeCurrent();
  253. gnenumUndir++ )
  254. {
  255. vpgnode.push_back( *gnenumUndir );
  256. }
  257. if ( bIncludeSelf )
  258. vpgnode.push_back( this );
  259. }
  260. int GNODEMBN :: IParent ( GNODEMBN * pgndmb, bool bReverse )
  261. {
  262. // Prepare to iterate over the parents
  263. GNODENUM<GNODEMBN> benumparent( true, ! bReverse );
  264. benumparent.SetETypeFollow( GEDGEMBN::ETPROB );
  265. int iParent = 0;
  266. for ( benumparent.Set(this);
  267. benumparent.PnodeCurrent();
  268. benumparent++, iParent++ )
  269. {
  270. if ( *benumparent == pgndmb )
  271. return iParent;
  272. }
  273. return -1;
  274. }
  275. int GNODEMBN :: IChild ( GNODEMBN * pgndmb, bool bReverse )
  276. {
  277. // Prepare to iterate over the children
  278. GNODENUM<GNODEMBN> benumchild( false, ! bReverse );
  279. benumchild.SetETypeFollow( GEDGEMBN::ETPROB );
  280. int iChild = 0;
  281. for ( benumchild.Set(this);
  282. benumchild.PnodeCurrent();
  283. benumchild++ )
  284. {
  285. if ( *benumchild == pgndmb )
  286. return iChild;
  287. }
  288. return -1;
  289. }
  290. bool GNODEMBN :: BIsNeighbor ( GNODEMBN * pgndmb )
  291. {
  292. GNODENUM_UNDIR gnenumUndir;
  293. for ( gnenumUndir = this;
  294. gnenumUndir.PnodeCurrent();
  295. gnenumUndir++ )
  296. {
  297. if ( *gnenumUndir == pgndmb )
  298. return true;
  299. }
  300. return false;
  301. }
  302. void GNODEMBN :: GetVtknpd ( VTKNPD & vtknpd, bool bUseExpansion )
  303. {
  304. VPGNODEMBN vpgnodeParent;
  305. GetParents(vpgnodeParent, false, bUseExpansion);
  306. vtknpd.clear();
  307. vtknpd.push_back( TKNPD(DTKN_PD) );
  308. vtknpd.push_back( TKNPD( ZsrefName() ) );
  309. for ( int ip = 0; ip < vpgnodeParent.size(); ip++ )
  310. {
  311. if ( ip > 0 )
  312. vtknpd.push_back( TKNPD(DTKN_AND) );
  313. else
  314. vtknpd.push_back( TKNPD(DTKN_COND) );
  315. vtknpd.push_back( TKNPD(vpgnodeParent[ip]->ZsrefName()) );
  316. }
  317. }
  318. bool GNODEMBN :: BMatchTopology (
  319. MBNET & mbnet,
  320. const VTKNPD & vtknpd,
  321. VPGNODEMBN * pvpgnode )
  322. {
  323. // Guarantee that the descriptor is of the form "p(X|...)"
  324. if ( vtknpd.size() < 2
  325. || vtknpd[0] != TKNPD(DTKN_PD)
  326. || ! vtknpd[1].BStr() )
  327. throw GMException( EC_INV_PD, "invalid token description on PD");
  328. VTKNPD vtknpdSelf;
  329. GetVtknpd( vtknpdSelf );
  330. if ( vtknpdSelf == vtknpd )
  331. return true;
  332. #ifdef _DEBUG
  333. {
  334. ZSTR zs1 = vtknpd.ZstrSignature(0);
  335. ZSTR zs2 = vtknpdSelf.ZstrSignature(0);
  336. cout << "\nGNODEMBN::BMatchTopology mismatch: "
  337. << "\n\tExpected "
  338. << zs1
  339. << "\n\tComputed "
  340. << zs2
  341. ;
  342. }
  343. #endif
  344. return false;
  345. }
  346. void GNODEMBN :: Dump ()
  347. {
  348. cout << "\t(toplev: "
  349. << ITopLevel()
  350. << "): "
  351. << ZsrefName().Szc();
  352. int iParent = 0;
  353. GNODENUM<GNODEMBN> benumparent(true);
  354. benumparent.SetETypeFollow( GEDGEMBN::ETPROB );
  355. for ( benumparent.Set(this);
  356. benumparent.PnodeCurrent();
  357. benumparent++ )
  358. {
  359. GNODEMBN * pgndbnParent = *benumparent;
  360. if ( iParent++ == 0 )
  361. cout << ", parents: ";
  362. cout << pgndbnParent->ZsrefName().Szc()
  363. << ',';
  364. }
  365. }
  366. GNODEMBND :: GNODEMBND ()
  367. {
  368. IType() = FND_Valid | FND_Discrete ;
  369. }
  370. GNODEMBND :: ~ GNODEMBND ()
  371. {
  372. ClearDist();
  373. }
  374. void GNODEMBND :: Dump ()
  375. {
  376. GNODEMBN::Dump();
  377. if ( BHasDist() && Bndist().Edist() != BNDIST::ED_NONE )
  378. {
  379. cout << "\n\tprobability distribution of "
  380. << ZsrefName().Szc()
  381. << ": ";
  382. Bndist().Dump();
  383. }
  384. }
  385. // Find the distribution for this node recorded in the belief network's
  386. // distribution map.
  387. void GNODEMBND :: SetDist ( MBNET & mbnet )
  388. {
  389. ClearDist();
  390. // Construct the token array describing the distribution
  391. VTKNPD vtknpd;
  392. GetVtknpd( vtknpd );
  393. // Locate that distribution in the belief network's map
  394. MPPD::iterator itmppd = mbnet.Mppd().find( vtknpd );
  395. ASSERT_THROW( itmppd != mbnet.Mppd().end(),
  396. EC_INTERNAL_ERROR,
  397. "missing distribution for node" );
  398. // Set this node to use that distribution
  399. _refbndist = (*itmppd).second;
  400. assert( BHasDist() );
  401. }
  402. // Bind the given distribution this node
  403. void GNODEMBND :: SetDist ( BNDIST * pbndist )
  404. {
  405. #ifdef _DEBUG
  406. if ( pbndist )
  407. {
  408. // Check that the last dimension is the correct size.
  409. int cDims = pbndist->VimdDim().size();
  410. assert( pbndist->VimdDim()[cDims-1] == CState() );
  411. }
  412. #endif
  413. _refbndist = pbndist;
  414. }
  415. // Check that the dimensionality of the distribution matches that of
  416. // the node itself according to the dag topology.
  417. bool GNODEMBND :: BCheckDistDense ()
  418. {
  419. // Get the array of parents
  420. VPGNODEMBN vpgndParents;
  421. GetParents( vpgndParents );
  422. VIMD vimd( vpgndParents.size() + 1 );
  423. for ( int idim = 0; idim < vimd.size() - 1; idim++ )
  424. {
  425. GNODEMBND * pgndd;
  426. assert( vpgndParents[idim] );
  427. DynCastThrow( vpgndParents[idim], pgndd );
  428. vimd[idim] = pgndd->CState();
  429. }
  430. vimd[idim] = CState();
  431. MDVCPD & mdv = Bndist().Mdvcpd();
  432. return mdv.VimdDim() == vimd;
  433. }
  434. void GNODEMBND :: SetDomain ( const GOBJMBN_DOMAIN & gobjrdom )
  435. {
  436. // Copy the state names from the domain to the variable
  437. const RDOMAIN & rdom = gobjrdom.Domain();
  438. RDOMAIN::const_iterator itdm = rdom.begin();
  439. _vzsrState.resize( rdom.size() );
  440. for ( int i = 0; itdm != rdom.end(); itdm++ )
  441. {
  442. const RANGEDEF & rdef = *itdm;
  443. _vzsrState[i++] = rdef.ZsrName();
  444. }
  445. _zsrDomain = gobjrdom.ZsrefName();
  446. }
  447. //
  448. // Usage of this function without a new object implies that the
  449. // subclassed target object does not correctly support "CloneNew".
  450. // Throw a cloning exception in this case.
  451. //
  452. GEDGEMBN * GEDGEMBN :: CloneNew (
  453. MODEL & modelSelf,
  454. MODEL & modelNew,
  455. GOBJMBN * pgobjmbnSource,
  456. GOBJMBN * pgobjmbnSink,
  457. GEDGEMBN * pgedgeNew )
  458. {
  459. if ( pgedgeNew == NULL )
  460. {
  461. ThrowInvalidClone( self );
  462. }
  463. pgedgeNew->_vFlags = _vFlags;
  464. return pgedgeNew;
  465. }
  466. GEDGEMBN * GEDGEMBN_PROB :: CloneNew (
  467. MODEL & modelSelf,
  468. MODEL & modelNew,
  469. GOBJMBN * pgobjmbnSource,
  470. GOBJMBN * pgobjmbnSink,
  471. GEDGEMBN * pgdegeNew )
  472. {
  473. assert( EType() == ETPROB );
  474. GNODEMBN * pgndSource;
  475. GNODEMBN * pgndSink;
  476. DynCastThrow( pgobjmbnSource, pgndSource );
  477. DynCastThrow( pgobjmbnSink, pgndSink );
  478. GEDGEMBN_PROB * pgedge = new GEDGEMBN_PROB( pgndSource, pgndSink );
  479. ASSERT_THROW( GEDGEMBN::CloneNew( modelSelf, modelNew, pgndSource, pgndSink, pgedge ),
  480. EC_INTERNAL_ERROR,
  481. "cloning failed to returned object pointer" );
  482. return pgedge;
  483. }
  484. bool BNWALKER :: BSelect ( GNODEMBN * pgn )
  485. {
  486. return true;
  487. }
  488. bool BNWALKER :: BMark ( GNODEMBN * pgn )
  489. {
  490. return true;
  491. }