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.

678 lines
16 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1997 - 1998
  6. //
  7. // File: mbnetdsc.cpp
  8. //
  9. //--------------------------------------------------------------------------
  10. //
  11. // MBNETDSC.CPP: MBNETDSC functions
  12. //
  13. #include <basetsd.h>
  14. #include "gmobj.h"
  15. #include "bnparse.h"
  16. MBNETDSC :: MBNETDSC ()
  17. : _pfDsc(NULL)
  18. {
  19. }
  20. MBNETDSC :: ~ MBNETDSC ()
  21. {
  22. }
  23. static
  24. struct TKNFUNCMAP
  25. {
  26. BNDIST::EDIST ed;
  27. SZC szc;
  28. }
  29. rgTknFunc[] =
  30. {
  31. { BNDIST::ED_CI_MAX, "max" },
  32. { BNDIST::ED_CI_PLUS, "plus" },
  33. { BNDIST::ED_MAX, NULL } // must be last
  34. };
  35. SZC MBNETDSC :: SzcDist ( BNDIST::EDIST edist )
  36. {
  37. for ( int i = 0; rgTknFunc[i].szc; i++ )
  38. {
  39. if ( rgTknFunc[i].ed == edist )
  40. break;
  41. }
  42. return rgTknFunc[i].szc;
  43. }
  44. //
  45. // String-to-token translation.
  46. //
  47. struct TKNMAP
  48. {
  49. SZC _szc;
  50. TOKEN _token;
  51. };
  52. static TKNMAP rgTknStr[] =
  53. { // This table must be kept in alphabetic order
  54. "", tokenNil,
  55. "..", tokenRangeOp,
  56. "array", tokenArray,
  57. "as", tokenAs,
  58. "branch", tokenBranch,
  59. "choice", tokenWordChoice,
  60. "continuous", tokenContinuous,
  61. "creator", tokenCreator,
  62. "decisionGraph", tokenDecisionGraph,
  63. "default", tokenDefault,
  64. "discrete", tokenDiscrete,
  65. "distribution", tokenDistribution,
  66. "domain", tokenDomain,
  67. "for", tokenFor,
  68. "format", tokenFormat,
  69. "function", tokenFunction,
  70. "import", tokenImport,
  71. "is", tokenIs,
  72. "leaf", tokenLeaf,
  73. "leak", tokenLeak,
  74. "level", tokenLevel,
  75. "merge", tokenMerge,
  76. "multinoulli", tokenMultinoulli,
  77. "na", tokenNA,
  78. "name", tokenName,
  79. "named", tokenNamed,
  80. "network", tokenNetwork,
  81. "node", tokenNode,
  82. "of", tokenOf,
  83. "on", tokenOn,
  84. "parent", tokenParent,
  85. "position", tokenPosition,
  86. "probability", tokenProbability,
  87. "properties", tokenProperties,
  88. "property", tokenProperty,
  89. "real", tokenWordReal,
  90. "standard", tokenStandard,
  91. "state", tokenState,
  92. "string", tokenWordString,
  93. "type", tokenType,
  94. "version", tokenVersion,
  95. "vertex", tokenVertex,
  96. "with", tokenWith,
  97. NULL, tokenNil // must be last one
  98. };
  99. //
  100. // Map a string to a token (case-sensitive)
  101. //
  102. TOKEN MBNETDSC :: TokenFind ( SZC szc )
  103. {
  104. static bool bFirstTime = true;
  105. assert( szc != NULL );
  106. TKNMAP * ptknmap;
  107. if ( bFirstTime )
  108. {
  109. // Verify that the parser token table is in sequence
  110. bFirstTime = false;
  111. TKNMAP * ptknmapLast = NULL;
  112. for ( ptknmap = rgTknStr;
  113. ptknmap->_szc;
  114. ++ptknmap)
  115. {
  116. ASSERT_THROW( ptknmapLast == NULL
  117. || ::strcmp( ptknmapLast->_szc, ptknmap->_szc ) < 0,
  118. EC_INTERNAL_ERROR,
  119. "parser token table out of sequence" );
  120. ptknmapLast = ptknmap;
  121. }
  122. }
  123. for ( ptknmap = rgTknStr;
  124. ptknmap->_szc;
  125. ++ptknmap)
  126. {
  127. int i = ::strcmp(szc, ptknmap->_szc);
  128. if ( i > 0 )
  129. continue;
  130. if ( i == 0 )
  131. break;
  132. return tokenNil;
  133. }
  134. return ptknmap->_token;
  135. }
  136. //
  137. // Map a token to a string.
  138. //
  139. SZC MBNETDSC :: SzcTokenMap ( TOKEN tkn )
  140. {
  141. for ( TKNMAP * ptknmap = rgTknStr;
  142. ptknmap->_szc;
  143. ++ptknmap)
  144. {
  145. if ( ptknmap->_token == tkn )
  146. break;
  147. }
  148. return ptknmap->_szc;
  149. }
  150. bool MBNETDSC :: BParse ( SZC szcFn, FILE * pfErr )
  151. {
  152. if ( pfErr == NULL )
  153. pfErr = stderr;
  154. PARSIN_DSC flpIn;
  155. PARSOUT_STD flpOut(pfErr);
  156. DSCPARSER parser(self, flpIn, flpOut);
  157. UINT cError, cWarning;
  158. return parser.BInitOpen( szcFn )
  159. && parser.BParse( cError, cWarning );
  160. }
  161. void MBNETDSC :: Print ( FILE * pf )
  162. {
  163. if ( ! pf )
  164. pf = stdout;
  165. _pfDsc = pf;
  166. PrintHeaderBlock();
  167. PrintPropertyDeclarations();
  168. PrintDomains();
  169. PrintNodes();
  170. PrintTopologyAndDistributions();
  171. _pfDsc = NULL;
  172. }
  173. void MBNETDSC :: PrintDomains ()
  174. {
  175. MBNET::ITER mbnit( self, GOBJMBN::EBNO_VARIABLE_DOMAIN );
  176. GOBJMBN * pgmobj;
  177. ZSTR zstrRange;
  178. for ( ; pgmobj = *mbnit ; ++mbnit)
  179. {
  180. ZSREF zsrName = mbnit.ZsrCurrent();
  181. GOBJMBN_DOMAIN * pgdom;
  182. DynCastThrow( pgmobj, pgdom );
  183. fprintf( _pfDsc, "\ndomain %s\n{", zsrName.Szc() );
  184. const RDOMAIN & rdom = pgdom->Domain();
  185. RDOMAIN::const_iterator itdm = rdom.begin();
  186. for ( int i = 0; itdm != rdom.end(); i++ )
  187. {
  188. const RANGEDEF & rdef = *itdm;
  189. zstrRange.Reset();
  190. // If the range is a singleton and is the next integer,
  191. // just print it as-is.
  192. if ( ! rdef.BDiscrete() || rdef.IDiscrete() != i )
  193. {
  194. // Format the range operator and arguments
  195. if ( rdef.BDiscrete() )
  196. {
  197. zstrRange.Format( "%d", rdef.IDiscrete() );
  198. }
  199. else
  200. {
  201. if ( rdef.BLbound() )
  202. zstrRange.FormatAppend( "%g ", rdef.RLbound() );
  203. zstrRange.FormatAppend( "%s", SzcTokenMap(tokenRangeOp) );
  204. if ( rdef.BUbound() )
  205. zstrRange.FormatAppend( " %g", rdef.RUbound() );
  206. }
  207. zstrRange.FormatAppend(" : ");
  208. }
  209. fprintf( _pfDsc, "\n\t%s\"%s\"", zstrRange.Szc(), rdef.ZsrName().Szc() );
  210. if ( ++itdm != rdom.end() )
  211. fprintf( _pfDsc, "," );
  212. }
  213. fprintf( _pfDsc, "\n}\n" );
  214. }
  215. }
  216. void MBNETDSC :: PrintHeaderBlock()
  217. {
  218. fprintf(_pfDsc, "%s", SzcTokenMap(tokenNetwork) );
  219. if ( ZsNetworkID().length() > 0 )
  220. {
  221. fprintf(_pfDsc, " \"%s\"", ZsNetworkID().Szc() );
  222. }
  223. fprintf(_pfDsc, "\n{");
  224. if ( RVersion() >= 0.0 )
  225. {
  226. fprintf(_pfDsc, "\n\t%s is %g;",
  227. SzcTokenMap(tokenVersion),
  228. RVersion() );
  229. }
  230. if ( ZsCreator().length() > 0 )
  231. {
  232. fprintf(_pfDsc, "\n\t%s is \"%s\";",
  233. SzcTokenMap(tokenCreator),
  234. ZsCreator().Szc() );
  235. }
  236. if ( ZsFormat().length() > 0 )
  237. {
  238. fprintf(_pfDsc, "\n\t%s is \"%s\";",
  239. SzcTokenMap(tokenFormat),
  240. ZsFormat().Szc() );
  241. }
  242. fprintf( _pfDsc, "\n}\n\n" );
  243. }
  244. //
  245. // Regenerate the property type declarations.
  246. //
  247. // If any are marked "standard", generate the "import standard" declaration.
  248. // Generate explicit "import" declarations for any marked "persistent".
  249. //
  250. void MBNETDSC :: PrintPropertyDeclarations()
  251. {
  252. int cTypes = 0;
  253. MBNET::ITER mbnit( self, GOBJMBN::EBNO_PROP_TYPE );
  254. GOBJMBN * pgmobj;
  255. bool bImportStandard = false;
  256. for ( ; pgmobj = *mbnit ; ++mbnit)
  257. {
  258. ZSREF zsrName = mbnit.ZsrCurrent();
  259. GOBJPROPTYPE * pbnpt;
  260. DynCastThrow( pgmobj, pbnpt );
  261. if ( cTypes++ == 0 )
  262. {
  263. fprintf( _pfDsc, "%s\n{",
  264. SzcTokenMap(tokenProperties) );
  265. }
  266. assert( zsrName == pbnpt->ZsrefName() );
  267. // If this is a standard persistent property,
  268. // write the import declaration once
  269. if ( pbnpt->FPropType() & fPropStandard )
  270. {
  271. if ( ! bImportStandard )
  272. {
  273. // Write the "import" statement once
  274. fprintf( _pfDsc, "\n\timport standard;" );
  275. bImportStandard = true;
  276. }
  277. // Skip further processing of standard imported types
  278. continue;
  279. }
  280. // If this is a persistent property, write the import declaration
  281. if ( pbnpt->FPropType() & fPropPersist )
  282. {
  283. fprintf( _pfDsc, "\n\timport %s;", zsrName.Szc() );
  284. continue;
  285. }
  286. // User-declared (private, non-persistent) property
  287. fprintf( _pfDsc, "\n\ttype %s = ", zsrName.Szc() );
  288. if ( pbnpt->FPropType() & fPropArray )
  289. {
  290. fprintf( _pfDsc, "%s %s ",
  291. SzcTokenMap(tokenArray),
  292. SzcTokenMap(tokenOf) );
  293. }
  294. if ( pbnpt->FPropType() & fPropChoice )
  295. {
  296. fprintf( _pfDsc, "%s %s \n\t\t[",
  297. SzcTokenMap(tokenWordChoice),
  298. SzcTokenMap(tokenOf) );
  299. int cc = pbnpt->VzsrChoice().size();
  300. for ( int ic = 0; ic < cc; ic++ )
  301. {
  302. fprintf( _pfDsc, "%s", pbnpt->VzsrChoice()[ic].Szc() );
  303. if ( ic+1 < cc )
  304. fprintf( _pfDsc, "," );
  305. }
  306. fprintf( _pfDsc, "]" );
  307. }
  308. else
  309. if ( pbnpt->FPropType() & fPropString )
  310. {
  311. fprintf( _pfDsc, "%s", SzcTokenMap(tokenWordString) );
  312. }
  313. else
  314. {
  315. fprintf( _pfDsc, "%s", SzcTokenMap(tokenWordReal) );
  316. }
  317. if ( pbnpt->ZsrComment().Zstr().length() > 0 )
  318. {
  319. fprintf( _pfDsc, ",\n\t\t\"%s\"",
  320. pbnpt->ZsrComment().Szc() );
  321. }
  322. fprintf( _pfDsc, ";" );
  323. }
  324. if ( cTypes )
  325. {
  326. PrintPropertyList( LtProp() );
  327. fprintf( _pfDsc, "\n}\n" );
  328. }
  329. }
  330. void MBNETDSC :: PrintNodes()
  331. {
  332. MBNET::ITER mbnit( self, GOBJMBN::EBNO_NODE );
  333. GOBJMBN * pgmobj;
  334. GNODEMBN * pbnode;
  335. GNODEMBND * pbnoded;
  336. for ( ; pgmobj = *mbnit ; ++mbnit)
  337. {
  338. ZSREF zsrName = mbnit.ZsrCurrent();
  339. DynCastThrow( pgmobj, pbnode );
  340. assert( zsrName == pbnode->ZsrefName() );
  341. fprintf( _pfDsc, "\n%s %s\n{",
  342. SzcTokenMap(tokenNode),
  343. pbnode->ZsrefName().Szc() );
  344. if ( pbnode->ZsFullName().length() > 0 )
  345. {
  346. fprintf( _pfDsc, "\n\t%s = \"%s\";",
  347. SzcTokenMap(tokenName),
  348. pbnode->ZsFullName().Szc() );
  349. }
  350. pbnoded = dynamic_cast<GNODEMBND *>(pbnode);
  351. ASSERT_THROW( pbnoded, EC_NYI, "only discrete nodes supported" )
  352. // Print the type and states using a domain, if given
  353. if ( pbnoded->ZsrDomain().Zstr().length() > 0 )
  354. {
  355. // Explicit domain
  356. fprintf( _pfDsc, "\n\t%s = %s %s %s;",
  357. SzcTokenMap(tokenType),
  358. SzcTokenMap(tokenDiscrete),
  359. SzcTokenMap(tokenDomain),
  360. pbnoded->ZsrDomain().Szc() );
  361. }
  362. else
  363. {
  364. // Variable-specific state enumeration
  365. int cState = pbnoded->CState();
  366. fprintf( _pfDsc, "\n\t%s = %s[%d]\n\t{",
  367. SzcTokenMap(tokenType),
  368. SzcTokenMap(tokenDiscrete),
  369. cState );
  370. for ( int iState = 0; iState < cState; )
  371. {
  372. fprintf(_pfDsc, "\n\t\t\"%s\"",
  373. pbnoded->VzsrStates()[iState].Szc() );
  374. if ( ++iState < cState )
  375. fprintf( _pfDsc, "," );
  376. }
  377. fprintf( _pfDsc, "\n\t};\n" );
  378. }
  379. PTPOS pt = pbnode->PtPos();
  380. if ( pt._x != 0 || pt._y != 0 )
  381. {
  382. fprintf( _pfDsc, "\n\t%s = (%d, %d);",
  383. SzcTokenMap(tokenPosition),
  384. pt._x,
  385. pt._y );
  386. }
  387. PrintPropertyList( pbnode->LtProp() );
  388. fprintf( _pfDsc, "\n}\n");
  389. }
  390. }
  391. void MBNETDSC :: PrintPropertyList ( LTBNPROP & ltProp )
  392. {
  393. for ( LTBNPROP::iterator ltit = ltProp.begin();
  394. ltit != ltProp.end();
  395. ++ltit )
  396. {
  397. const PROPMBN & prop = *ltit;
  398. fprintf( _pfDsc, "\n\t%s = ",
  399. prop.ZsrPropType().Szc() );
  400. bool bArray = prop.FPropType() & fPropArray;
  401. if ( bArray )
  402. fprintf( _pfDsc, "[" );
  403. for ( int i = 0; i < prop.Count(); )
  404. {
  405. if ( prop.FPropType() & fPropChoice )
  406. {
  407. GOBJMBN * pgmobj = Mpsymtbl().find( prop.ZsrPropType() );
  408. assert( pgmobj );
  409. GOBJPROPTYPE * pbnpt;
  410. DynCastThrow( pgmobj, pbnpt );
  411. fprintf( _pfDsc, "%s",
  412. pbnpt->VzsrChoice()[(int) prop.Real(i)].Szc() );
  413. }
  414. else
  415. if ( prop.FPropType() & fPropString )
  416. {
  417. fprintf( _pfDsc, "\"%s\"",
  418. prop.Zsr(i).Szc() );
  419. }
  420. else
  421. {
  422. fprintf( _pfDsc, "%g",
  423. prop.Real(i) );
  424. }
  425. if ( ++i < prop.Count() )
  426. fprintf( _pfDsc, "," );
  427. }
  428. if ( bArray )
  429. fprintf( _pfDsc, "]" );
  430. fprintf( _pfDsc, ";" );
  431. }
  432. }
  433. //
  434. // Print network topology and probability distribution information for
  435. // all nodes.
  436. //
  437. // Note that distributions are stored in the distribution map
  438. // most of the time. However, during network expansion and inference
  439. // they are temporarly bound to their respective nodes (see 'BindDistributions').
  440. // For purposes of dumping the network at various stages, this logic
  441. // will print a bound distribution in preference to a mapped one.
  442. // If no distribution can be found, an error is generated as a comment into
  443. // the output file.
  444. //
  445. void MBNETDSC :: PrintTopologyAndDistributions()
  446. {
  447. MBNET::ITER mbnit( self, GOBJMBN::EBNO_NODE );
  448. GOBJMBN * pgmobj;
  449. VTKNPD vtknpd;
  450. for ( ; pgmobj = *mbnit ; ++mbnit)
  451. {
  452. ZSREF zsrName = mbnit.ZsrCurrent();
  453. GNODEMBN * pbnode;
  454. DynCastThrow( pgmobj, pbnode );
  455. pbnode->GetVtknpd( vtknpd );
  456. GNODEMBND * pbnoded = dynamic_cast<GNODEMBND *>(pbnode);
  457. if ( pbnoded == NULL )
  458. {
  459. // We don't have a clue as to how to print this node
  460. fprintf( _pfDsc,
  461. "\n\n// Error: unable to print distribution for non-discrete node \'%s\'",
  462. zsrName.Szc() );
  463. continue;
  464. }
  465. if ( pbnoded->BHasDist() )
  466. {
  467. // This node already has a bound distribution
  468. // Construct the token array describing the distribution
  469. ZSTR zsSig = vtknpd.ZstrSignature(1);
  470. fprintf( _pfDsc, "\n%s(%s)\t\n{",
  471. SzcTokenMap(tokenProbability),
  472. zsSig.Szc() );
  473. PrintDistribution( *pbnoded, pbnoded->Bndist() );
  474. fprintf( _pfDsc,"\n}\n");
  475. continue;
  476. }
  477. // Look the distribution up in the map
  478. // Cons-up "p(<node>|"
  479. VTKNPD vtknpdNode;
  480. vtknpdNode.push_back( TKNPD(DTKN_PD) );
  481. vtknpdNode.push_back( TKNPD( pbnode->ZsrefName() ) );
  482. // Find the distribution(s) with that signature; print the first one
  483. int cFound = 0;
  484. for ( MPPD::iterator mppdit = Mppd().lower_bound( vtknpdNode );
  485. mppdit != Mppd().end();
  486. ++mppdit )
  487. {
  488. const VTKNPD & vtknpdMap = (*mppdit).first;
  489. if ( vtknpdMap.size() < 2
  490. || vtknpdMap[0] != TKNPD(DTKN_PD)
  491. || ! vtknpdMap[1].BStr() )
  492. break;
  493. SZC szcNode = vtknpdMap[1].Szc();
  494. if ( pbnode->ZsrefName().Szc() != szcNode )
  495. break;
  496. if ( cFound++ == 0 )
  497. {
  498. ZSTR zsTopol = vtknpdMap.ZstrSignature(1);
  499. fprintf( _pfDsc, "\n%s(%s)\t\n{",
  500. SzcTokenMap(tokenProbability),
  501. zsTopol.Szc() );
  502. if ( vtknpd != vtknpdMap )
  503. {
  504. ZSTR zsSig = vtknpd.ZstrSignature();
  505. fprintf( _pfDsc,
  506. "\n\n\t// Error: required distribution is %s",
  507. zsSig.Szc() );
  508. }
  509. PrintDistribution( *pbnode, *(*mppdit).second );
  510. fprintf( _pfDsc,"\n}\n");
  511. }
  512. else
  513. {
  514. ZSTR zsSig = vtknpd.ZstrSignature();
  515. fprintf( _pfDsc,
  516. "\n\n// Warning: Superfluous distribution found for %s",
  517. zsSig.Szc() );
  518. }
  519. }
  520. if ( cFound > 0 )
  521. continue;
  522. // Print a warning into the DSC output file
  523. ZSTR zsSigFull = vtknpd.ZstrSignature();
  524. fprintf( _pfDsc,
  525. "\n\n// Error: Distribution missing for %s",
  526. zsSigFull.Szc() );
  527. // Construct the token array describing the distribution, but write
  528. // it as empty.
  529. ZSTR zsSig = vtknpd.ZstrSignature(1);
  530. fprintf( _pfDsc, "\n%s(%s);",
  531. SzcTokenMap(tokenProbability),
  532. zsSig.Szc() );
  533. }
  534. fflush( _pfDsc );
  535. }
  536. void MBNETDSC :: PrintDistribution ( GNODEMBN & gnode, BNDIST & bndist )
  537. {
  538. BNDIST::EDIST edist = bndist.Edist();
  539. switch ( edist )
  540. {
  541. case BNDIST::ED_CI_MAX:
  542. case BNDIST::ED_CI_PLUS:
  543. {
  544. SZC szcFunc = SzcDist( edist );
  545. assert( szcFunc );
  546. fprintf( _pfDsc, "\n\tfunction = %s;", szcFunc );
  547. // Fall through to handle as sparse
  548. }
  549. case BNDIST::ED_SPARSE:
  550. {
  551. const MPCPDD & dmp = bndist.Mpcpdd();
  552. int cEntries = dmp.size();
  553. for ( MPCPDD::const_iterator dmit = dmp.begin();
  554. dmit != dmp.end();
  555. ++dmit)
  556. {
  557. const VIMD & vimd = (*dmit).first;
  558. const VLREAL & vr = (*dmit).second;
  559. fprintf( _pfDsc, "\n\t");
  560. if ( vimd.size() == 0 )
  561. {
  562. if ( cEntries > 1 )
  563. fprintf( _pfDsc, "%s = ", SzcTokenMap(tokenDefault) );
  564. }
  565. else
  566. {
  567. fprintf( _pfDsc, "(");
  568. for ( int i = 0; i < vimd.size() ; )
  569. {
  570. fprintf( _pfDsc, "%d", vimd[i] );
  571. if ( ++i < vimd.size() )
  572. fprintf( _pfDsc, ", " );
  573. }
  574. fprintf( _pfDsc, ") = ");
  575. }
  576. for ( int ir = 0; ir < vr.size(); )
  577. {
  578. fprintf( _pfDsc, "%g", vr[ir] );
  579. if ( ++ir < vr.size() )
  580. fprintf( _pfDsc, ", " );
  581. }
  582. fprintf( _pfDsc, ";" );
  583. }
  584. break;
  585. }
  586. case BNDIST::ED_DENSE:
  587. {
  588. MDVCPD mdv = bndist.Mdvcpd();
  589. MDVCPD::Iterator itdd( mdv );
  590. int cDim = mdv.VimdDim().size();
  591. int cStates = mdv.VimdDim()[cDim -1];
  592. for ( int iState = 0; itdd.BNext(); iState++ )
  593. {
  594. const VIMD & vimd = itdd.Vitmd();
  595. if ( (iState % cStates) == 0 )
  596. {
  597. // Start a new row
  598. fprintf( _pfDsc, "\n\t" );
  599. // Prefix with parent instantations if necessary
  600. int cItems = vimd.size() - 1;
  601. if ( cItems )
  602. {
  603. fprintf( _pfDsc, "(" );
  604. for ( int i = 0; i < cItems ; )
  605. {
  606. fprintf( _pfDsc, "%d", vimd[i] );
  607. if ( ++i < cItems )
  608. fprintf( _pfDsc, ", " );
  609. }
  610. fprintf( _pfDsc, ") = ");
  611. }
  612. }
  613. REAL & r = itdd.Next();
  614. fprintf( _pfDsc, "%g%c ", r, ((iState+1) % cStates) ? ',' : ';' );
  615. }
  616. break;
  617. }
  618. default:
  619. THROW_ASSERT(EC_NYI, "PrintDistribution only implemented for sparse arrays");
  620. break;
  621. }
  622. }