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.

564 lines
14 KiB

  1. //
  2. // MODULE: BN.cpp
  3. //
  4. // PURPOSE: implementation of the CBeliefNetwork class
  5. //
  6. // PROJECT: Generic Troubleshooter DLL for Microsoft AnswerPoint
  7. //
  8. // COMPANY: Saltmine Creative, Inc. (206)-284-7511 [email protected]
  9. //
  10. // AUTHOR: Joe Mabel
  11. //
  12. // ORIGINAL DATE: 8-31-98
  13. //
  14. // NOTES:
  15. // 1. Based on old apgtsdtg.cpp
  16. // 2. all methods (except constructor/destructor) must LOCKOBJECT around code that uses BNTS.
  17. // BNTS has "state". These functions are all written so that they make no assumptions about
  18. // state on entry, presenting the calling class with a stateless object.
  19. // 3. In theory, we could have separate locking for the cache independent of locking
  20. // CBeliefNetwork. The idea would be that if you needed only the cache to get your
  21. // inference, you wouldn't have to wait for access to BNTS.
  22. // >>>(ignore for V3.0) This is one of our best bets if performance is not good enough. JM 9/29/98
  23. //
  24. // Version Date By Comments
  25. //---------------------------------------------------------------------
  26. // V3.0 8-31-98 JM
  27. //
  28. #include "stdafx.h"
  29. #include "propnames.h"
  30. #include "BN.h"
  31. #include "CharConv.h"
  32. #include "event.h"
  33. #ifdef LOCAL_TROUBLESHOOTER
  34. #include "CHMFileReader.h"
  35. #else
  36. #include "fileread.h"
  37. #endif
  38. //////////////////////////////////////////////////////////////////////
  39. // Construction/Destruction
  40. //////////////////////////////////////////////////////////////////////
  41. CBeliefNetwork::CBeliefNetwork(LPCTSTR path)
  42. :
  43. CDSCReader( CPhysicalFileReader::makeReader( path ) ),
  44. m_bInitialized(false),
  45. m_bSnifferIntegration(false)
  46. {
  47. }
  48. CBeliefNetwork::~CBeliefNetwork()
  49. {
  50. }
  51. void CBeliefNetwork::Initialize()
  52. {
  53. LOCKOBJECT();
  54. if (! m_bInitialized)
  55. {
  56. BNTS * pbnts = pBNTS();
  57. if (pbnts)
  58. {
  59. m_bSnifferIntegration = false;
  60. ///////////////////////////////////////////////////////////////////
  61. // Does not matter for online TS (list is empty on initialization),
  62. // but for local TS m_Cache can contain cache data read from file.
  63. //m_Cache.Clear();
  64. ///////////////////////////////////////////////////////////////////
  65. m_arrnidProblem.clear();
  66. m_arrNodeTypeAll.clear();
  67. // loop through nodes looking for problem nodes and build local problem node array
  68. // also, determine if any node has a property which implies the intent of
  69. // integrating with a sniffer.
  70. int acnid= CNode();
  71. for (NID anid=0; anid < acnid; anid++)
  72. {
  73. if (pbnts->BNodeSetCurrent(anid))
  74. {
  75. ESTDLBL albl = pbnts->ELblNode(); // type of node (information/problem/fixable etc)
  76. try
  77. {
  78. if (albl == ESTDLBL_problem)
  79. m_arrnidProblem.push_back(anid);
  80. m_arrNodeTypeAll.push_back(SNodeType(anid, albl));
  81. }
  82. catch (exception& x)
  83. {
  84. CString str;
  85. // Note STL exception in event log.
  86. CBuildSrcFileLinenoStr SrcLoc( __FILE__, __LINE__ );
  87. CEvent::ReportWFEvent( SrcLoc.GetSrcFileLineStr(),
  88. SrcLoc.GetSrcFileLineStr(),
  89. CCharConversion::ConvertACharToString(x.what(), str),
  90. _T(""),
  91. EV_GTS_STL_EXCEPTION );
  92. }
  93. #ifdef LOCAL_TROUBLESHOOTER
  94. LPCTSTR psz;
  95. if (pbnts->BNodePropItemStr(H_NODE_DCT_STR, 0)
  96. && (psz = pbnts->SzcResult()) != NULL
  97. && *psz)
  98. {
  99. // There's a non-null property which only makes sense for a sniffer
  100. // integration, so we assume that's what they've got in mind.
  101. m_bSnifferIntegration = true;
  102. }
  103. #endif
  104. }
  105. }
  106. m_bInitialized = true;
  107. }
  108. }
  109. UNLOCKOBJECT();
  110. }
  111. // Access the relevant BNTS
  112. // Calling function should have a lock before calling this (although probably harmless
  113. // is it doesn't!)
  114. BNTS * CBeliefNetwork::pBNTS()
  115. {
  116. if (!IsRead())
  117. return NULL;
  118. return &m_Network;
  119. };
  120. // clear all node states
  121. // We can't use BNTS::Clear() because that actually throws away the model itself.
  122. void CBeliefNetwork::ResetNodes(const CBasisForInference & BasisForInference)
  123. {
  124. LOCKOBJECT();
  125. BNTS * pbnts = pBNTS();
  126. if (pbnts)
  127. {
  128. int cnid = BasisForInference.size();
  129. // Set all node states to NIL in BNTS storage
  130. for (UINT i = 0; i < cnid; i++)
  131. {
  132. pbnts->BNodeSetCurrent(BasisForInference[i].nid());
  133. pbnts->BNodeSet(-1, false); // Nil value
  134. }
  135. }
  136. UNLOCKOBJECT();
  137. }
  138. // Associate states with nodes.
  139. // INPUT BasisForInference
  140. // Note that all states must be valid states for the nodes, not (say) ST_UNKNOWN.
  141. // Caller's responsibility.
  142. bool CBeliefNetwork::SetNodes(const CBasisForInference & BasisForInference)
  143. {
  144. LOCKOBJECT();
  145. BNTS * pbnts = pBNTS();
  146. bool bOK = true;
  147. if (pbnts)
  148. {
  149. int nNodes = BasisForInference.size();
  150. for (int i= 0; i<nNodes; i++)
  151. {
  152. pbnts->BNodeSetCurrent(BasisForInference[i].nid());
  153. if (!pbnts->BNodeSet(BasisForInference[i].state(), false))
  154. bOK = false; // failed to set state. This should never happen on valid
  155. // user query.
  156. }
  157. }
  158. UNLOCKOBJECT();
  159. return bOK;
  160. }
  161. // OUTPUT Recommendations: list of recommendations
  162. // RETURN:
  163. // RS_OK = SUCCESS. Note that Recommendations can return empty if there is nothing to recommend.
  164. // RS_Impossible = Recommendations will return empty.
  165. // RS_Broken = Recommendations will return empty.
  166. int CBeliefNetwork::GetRecommendations(
  167. const CBasisForInference & BasisForInference,
  168. CRecommendations & Recommendations)
  169. {
  170. int ret = RS_OK;
  171. LOCKOBJECT();
  172. Initialize();
  173. Recommendations.clear();
  174. // see if we've already cached a result for this state of the world
  175. if (m_Cache.FindCacheItem(BasisForInference, Recommendations))
  176. {
  177. // Great. We have a cache hit & return values have been filled in.
  178. m_countCacheHit.Increment();
  179. }
  180. else
  181. {
  182. m_countCacheMiss.Increment();
  183. BNTS * pbnts = pBNTS();
  184. if (pbnts)
  185. {
  186. SetNodes(BasisForInference);
  187. if (pbnts->BImpossible())
  188. ret = RS_Impossible;
  189. else if ( ! pbnts->BGetRecommendations())
  190. ret = RS_Broken;
  191. else
  192. {
  193. try
  194. {
  195. const int cnid = pbnts->CInt(); // Recommendation count
  196. if (cnid > 0)
  197. {
  198. // At least one recommendation
  199. const int *pInt = pbnts->RgInt();
  200. for (int i=0; i<cnid; i++)
  201. Recommendations.push_back(pInt[i]);
  202. }
  203. // We've got our return values together, but before we return, cache them.
  204. m_Cache.AddCacheItem(BasisForInference, Recommendations);
  205. }
  206. catch (exception& x)
  207. {
  208. CString str;
  209. // Note STL exception in event log.
  210. CBuildSrcFileLinenoStr SrcLoc( __FILE__, __LINE__ );
  211. CEvent::ReportWFEvent( SrcLoc.GetSrcFileLineStr(),
  212. SrcLoc.GetSrcFileLineStr(),
  213. CCharConversion::ConvertACharToString(x.what(), str),
  214. _T(""),
  215. EV_GTS_STL_EXCEPTION );
  216. }
  217. }
  218. ResetNodes(BasisForInference);
  219. }
  220. }
  221. UNLOCKOBJECT();
  222. return ret;
  223. }
  224. // return the number of nodes in the model
  225. int CBeliefNetwork::CNode ()
  226. {
  227. int ret = 0;
  228. LOCKOBJECT();
  229. BNTS * pbnts = pBNTS();
  230. if (pbnts)
  231. ret = pbnts->CNode();
  232. UNLOCKOBJECT();
  233. return ret;
  234. }
  235. // Return the index of a node given its symbolic name
  236. int CBeliefNetwork::INode (LPCTSTR szNodeName)
  237. {
  238. int ret = -1;
  239. LOCKOBJECT();
  240. BNTS * pbnts = pBNTS();
  241. if (pbnts)
  242. ret = pbnts->INode(szNodeName);
  243. UNLOCKOBJECT();
  244. return ret;
  245. }
  246. // OUTPUT *parrnid - refernce to array of NIDs of all problem nodes
  247. // RETURN number of values in *parrnid
  248. int CBeliefNetwork::GetProblemArray(vector<NID>* &parrnid)
  249. {
  250. int ret = 0;
  251. LOCKOBJECT();
  252. Initialize();
  253. parrnid = &m_arrnidProblem;
  254. ret = m_arrnidProblem.size();
  255. UNLOCKOBJECT();
  256. return ret;
  257. }
  258. // OUTPUT arrOut - refernce to array of NIDs of all nodes, that have type listed in arrTypeInclude
  259. // RETURN number of values in arrOut
  260. int CBeliefNetwork::GetNodeArrayIncludeType(vector<NID>& arrOut, const vector<ESTDLBL>& arrTypeInclude)
  261. {
  262. int ret = 0;
  263. LOCKOBJECT();
  264. arrOut.clear();
  265. Initialize();
  266. for (vector<SNodeType>::iterator i = m_arrNodeTypeAll.begin(); i < m_arrNodeTypeAll.end(); i++)
  267. {
  268. for (vector<ESTDLBL>::const_iterator j = arrTypeInclude.begin(); j < arrTypeInclude.end(); j++)
  269. if (i->Type == *j)
  270. break;
  271. if (j != arrTypeInclude.end())
  272. arrOut.push_back(i->Nid);
  273. }
  274. ret = arrOut.size();
  275. UNLOCKOBJECT();
  276. return ret;
  277. }
  278. // OUTPUT arrOut - refernce to array of NIDs of all nodes, that do NOT have type listed in arrTypeExclude
  279. // RETURN number of values in arrOut
  280. int CBeliefNetwork::GetNodeArrayExcludeType(vector<NID>& arrOut, const vector<ESTDLBL>& arrTypeExclude)
  281. {
  282. int ret = 0;
  283. LOCKOBJECT();
  284. arrOut.clear();
  285. Initialize();
  286. for (vector<SNodeType>::iterator i = m_arrNodeTypeAll.begin(); i < m_arrNodeTypeAll.end(); i++)
  287. {
  288. for (vector<ESTDLBL>::const_iterator j = arrTypeExclude.begin(); j < arrTypeExclude.end(); j++)
  289. if (i->Type == *j)
  290. break;
  291. if (j == arrTypeExclude.end())
  292. arrOut.push_back(i->Nid);
  293. }
  294. ret = arrOut.size();
  295. UNLOCKOBJECT();
  296. return ret;
  297. }
  298. // ----------------------------------------
  299. // simple properties
  300. // ----------------------------------------
  301. // return a STRING property of the net
  302. CString CBeliefNetwork::GetNetPropItemStr(LPCTSTR szPropName)
  303. {
  304. CString strRet;
  305. LOCKOBJECT();
  306. BNTS * pbnts = pBNTS();
  307. if (!pbnts)
  308. return CString(_T(""));
  309. if (pbnts->BNetPropItemStr(szPropName, 0))
  310. strRet = pbnts->SzcResult();
  311. UNLOCKOBJECT();
  312. return strRet;
  313. }
  314. // return a REAL property of the net
  315. bool CBeliefNetwork::GetNetPropItemNum(LPCTSTR szPropName, double& numOut)
  316. {
  317. bool bRet = false;
  318. LOCKOBJECT();
  319. BNTS * pbnts = pBNTS();
  320. if (!pbnts)
  321. return false;
  322. bRet = pbnts->BNetPropItemReal(szPropName, 0, numOut) ? true : false;
  323. UNLOCKOBJECT();
  324. return bRet;
  325. }
  326. // return a STRING property of a node or state
  327. // For most properties, state is irrelevant, and default of 0 is the appropriate input.
  328. // However, if there are per-state values, passing in the appropriate state number
  329. // will get you the appropriate value.
  330. CString CBeliefNetwork::GetNodePropItemStr(NID nid, LPCTSTR szPropName, IST state /*= 0 */)
  331. {
  332. CString strRet;
  333. LOCKOBJECT();
  334. BNTS * pbnts = pBNTS();
  335. if (pbnts && pbnts->BNodeSetCurrent(nid))
  336. {
  337. if (pbnts->BNodePropItemStr(szPropName, state))
  338. strRet = pbnts->SzcResult();
  339. }
  340. UNLOCKOBJECT();
  341. return strRet;
  342. }
  343. // $MAINT - This function is not currently used in any of the troubleshooters. RAB-19991103.
  344. // return a REAL property of a node or state
  345. // For most properties, state is irrelevant, and default of 0 is the appropriate input.
  346. // However, if there are per-state values, passing in the appropriate state number
  347. // will get you the appropriate value.
  348. bool CBeliefNetwork::GetNodePropItemNum(NID nid, LPCTSTR szPropName, double& numOut, IST state /*= 0*/)
  349. {
  350. bool bRet = false;
  351. LOCKOBJECT();
  352. BNTS * pbnts = pBNTS();
  353. if (pbnts && pbnts->BNodeSetCurrent(nid))
  354. {
  355. bRet = pbnts->BNodePropItemReal(szPropName, state, numOut) ? true : false;
  356. }
  357. UNLOCKOBJECT();
  358. return bRet;
  359. }
  360. CString CBeliefNetwork::GetNodeSymName(NID nid)
  361. {
  362. CString strRet;
  363. LOCKOBJECT();
  364. BNTS * pbnts = pBNTS();
  365. if (pbnts && pbnts->BNodeSetCurrent(nid))
  366. {
  367. pbnts->NodeSymName();
  368. strRet = pbnts->SzcResult();
  369. }
  370. UNLOCKOBJECT();
  371. return strRet;
  372. }
  373. CString CBeliefNetwork::GetNodeFullName(NID nid)
  374. {
  375. CString strRet;
  376. LOCKOBJECT();
  377. BNTS * pbnts = pBNTS();
  378. if (pbnts && pbnts->BNodeSetCurrent(nid))
  379. {
  380. pbnts->NodeFullName();
  381. strRet = pbnts->SzcResult();
  382. }
  383. UNLOCKOBJECT();
  384. return strRet;
  385. }
  386. CString CBeliefNetwork::GetStateName(NID nid, IST state)
  387. {
  388. CString strRet;
  389. LOCKOBJECT();
  390. BNTS * pbnts = pBNTS();
  391. if (pbnts && pbnts->BNodeSetCurrent(nid))
  392. {
  393. pbnts->NodeStateName(state);
  394. strRet = pbnts->SzcResult();
  395. }
  396. UNLOCKOBJECT();
  397. return strRet;
  398. }
  399. // ----------------------------------------
  400. // "multiline" properties
  401. // these date back to when there was a 255-byte limit on STRING and longer strings
  402. // had to be represented by ARRAY OF STRING, later concatenated.
  403. // Backward compatibility still needed.
  404. // ----------------------------------------
  405. // Append a NET property (for Belief Network as a whole, not for one
  406. // particular node) to str.
  407. // INPUT szPropName - Property name
  408. // INPUT szFormat - string to format each successive line. Should contain one %s, otherwise
  409. // constant text.
  410. CString CBeliefNetwork::GetMultilineNetProp(LPCTSTR szPropName, LPCTSTR szFormat)
  411. {
  412. CString strRet;
  413. LOCKOBJECT();
  414. BNTS * pbnts = pBNTS();
  415. if (pbnts)
  416. {
  417. CString strTxt;
  418. for (int i = 0; pbnts->BNetPropItemStr(szPropName, i); i++)
  419. {
  420. strTxt.Format( szFormat, pbnts->SzcResult());
  421. strRet += strTxt;
  422. }
  423. }
  424. UNLOCKOBJECT();
  425. return strRet;
  426. }
  427. // Like GetMultilineNetProp, but for a NODE property item, for one particular node.
  428. // INPUT/OUTPUT str - string to append to
  429. // INPUT item - Property name
  430. // INPUT szFormat - string to format each successive line. Should contain one %s, otherwise
  431. // constant text.
  432. CString CBeliefNetwork::GetMultilineNodeProp(NID nid, LPCTSTR szPropName, LPCTSTR szFormat)
  433. {
  434. CString strRet;
  435. LOCKOBJECT();
  436. BNTS * pbnts = pBNTS();
  437. if (pbnts && pbnts->BNodeSetCurrent(nid))
  438. {
  439. CString strTxt;
  440. for (int i = 0; pbnts->BNodePropItemStr(szPropName, i); i++)
  441. {
  442. strTxt.Format( szFormat, pbnts->SzcResult());
  443. strRet += strTxt;
  444. }
  445. }
  446. UNLOCKOBJECT();
  447. return strRet;
  448. }
  449. int CBeliefNetwork::GetCountOfStates(NID nid)
  450. {
  451. int ret = 0;
  452. LOCKOBJECT();
  453. BNTS * pbnts = pBNTS();
  454. if (pbnts && pbnts->BNodeSetCurrent(nid))
  455. ret = pbnts->INodeCst();
  456. UNLOCKOBJECT();
  457. return ret;
  458. }
  459. // returns true only for NIDs valid in the context of an abstract belief network.
  460. // Doesn't know about troubleshooter-specific stuff like nidService.
  461. bool CBeliefNetwork::IsValidNID(NID nid)
  462. {
  463. return ( nid < CNode() );
  464. }
  465. bool CBeliefNetwork::IsCauseNode(NID nid)
  466. {
  467. bool ret = false;
  468. LOCKOBJECT();
  469. BNTS * pbnts = pBNTS();
  470. if (pbnts && pbnts->BNodeSetCurrent(nid))
  471. {
  472. ESTDLBL lbl = pbnts->ELblNode();
  473. ret= (lbl == ESTDLBL_fixobs || lbl == ESTDLBL_fixunobs || lbl == ESTDLBL_unfix);
  474. }
  475. UNLOCKOBJECT();
  476. return ret;
  477. }
  478. bool CBeliefNetwork::IsProblemNode(NID nid)
  479. {
  480. bool ret = false;
  481. LOCKOBJECT();
  482. BNTS * pbnts = pBNTS();
  483. if (pbnts && pbnts->BNodeSetCurrent(nid))
  484. {
  485. ret= (pbnts->ELblNode() == ESTDLBL_problem);
  486. }
  487. UNLOCKOBJECT();
  488. return ret;
  489. }
  490. bool CBeliefNetwork::IsInformationalNode(NID nid)
  491. {
  492. bool ret = false;
  493. LOCKOBJECT();
  494. BNTS * pbnts = pBNTS();
  495. if (pbnts && pbnts->BNodeSetCurrent(nid))
  496. {
  497. ret= (pbnts->ELblNode() == ESTDLBL_info);
  498. }
  499. UNLOCKOBJECT();
  500. return ret;
  501. }
  502. bool CBeliefNetwork::UsesSniffer()
  503. {
  504. bool ret = false;
  505. LOCKOBJECT();
  506. Initialize();
  507. ret = m_bSnifferIntegration;
  508. UNLOCKOBJECT();
  509. return ret;
  510. }