WindowsXP-SP1/enduser/troubleshoot/bn/testinfo.cpp
2020-09-30 16:53:49 +02:00

416 lines
10 KiB
C++

//+-------------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (C) Microsoft Corporation, 1997 - 1997
//
// File: testinfo.cpp
//
//--------------------------------------------------------------------------
//
// testinfo.cpp: test file generation
//
#include "testinfo.h"
////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////
/*
Test inference and optionally Write an inference output file.
The format is the same as the program DXTEST, which uses the older DXC32.DLL.
The format is:
$COMPLETE << Indicates a complete pass without instantiations
Alternator,0,0.99 << One record for each state of each node, alphabetically,
Alternator,1,0.01 with either the full or symbolic name (fSymName)
Battery,0,0.9927
Battery,1,0.0073
Charge Delivered,0,0.95934
Charge Delivered,1,0.0406603
... << Similar records for all other nodes
...
$INSTANTIATE,Alternator,0 << Indicates a node clamped to a state
Alternator,0,1
Alternator,1,0
Battery,0,0.9927
...
...
$PROBLEMINST,Engine Start,1 << Indicates a PD node instantiated
$UTILITY,Node Name,3.14159 << Indicates an entropic utility record (fUtil)
...
$RECOMEND,Node Name,-122.2222 << Indicates a troubleshooting recommendations record (fTSUtil)
...
This routine is used to compare both timings and numerical results with the older
software. The "fOutputFile" flag indicates whether an output file should be
written. The "fPassCountMask" indicates how many times the loop should be performed;
this value is defaulted to 1.
The logic works as follows:
for each pass
for 1 + each problem-defining (PD) node
for each non-PD node
if no non-PD node is instantiated
print $COMPLETE
else
print $INSTANTIATE and data about instantiated node
for each state of each non-PD node
print the name, state and value (belief)
print utilities if required
print recommendations if required
end for each state of each non-PD node
advance to the next state of the next node
unclamp previous node/sate
clamp (next) node to next state
end for eacn non-PD node
advance to the next state of the next PD node
end for each problem-defining node
end for each pass
Note that each pass is set up so that all the uninstantiated values are printed first.
*/
////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////
inline
SZC TESTINFO :: SzcNdName ( GNODEMBN * pgnd )
{
return FCtl() & fSymName
? pgnd->ZsrefName().Szc()
: pgnd->ZsFullName().Szc();
}
inline
SZC TESTINFO :: SzcNdName ( ZSREF zsSymName )
{
if ( FCtl() & fSymName )
return zsSymName.Szc();
GNODEMBN * pgnd;
DynCastThrow( Mbnet().PgobjFind( zsSymName ), pgnd );
return SzcNdName( pgnd );
}
void TESTINFO :: GetUtilities ()
{
// Compute the utilities
MbUtil()();
if ( ! Postream() )
return;
const VZSREF & vzsrNodes = MbUtil().VzsrefNodes();
const VLREAL & vlrUtil = MbUtil().VlrValues();
for ( int ind = 0; ind < vzsrNodes.size(); ind++ )
{
SZC szcName = SzcNdName( vzsrNodes[ind] );
Ostream()
<< "$UTILITY,"
<< szcName
<< ","
<< vlrUtil[ind]
<< "\n";
_clOut++;
}
}
void TESTINFO :: GetTSUtilities ()
{
if ( ! MbRecom().BReady() )
return; // Invalid state for recommendations
// Compute the utilities
MbRecom()();
if ( ! Postream() )
return;
const VZSREF & vzsrNodes = MbRecom().VzsrefNodes();
const VLREAL & vlrUtil = MbRecom().VlrValues();
for ( int ind = 0; ind < vzsrNodes.size(); ind++ )
{
SZC szcName = SzcNdName( vzsrNodes[ind] );
Ostream()
<< "$RECOMMEND,"
<< szcName
<< ","
<< vlrUtil[ind]
<< "\n";
_clOut++;
}
}
// Get the beliefs for the nodes in the given map; write data records if stream given
void TESTINFO :: GetBeliefs ()
{
MDVCPD mdvBel;
// Prepare to check for impossible states of information
GOBJMBN_CLIQSET * pCliqueSet = NULL;
if ( BFlag( fImpossible ) )
pCliqueSet = dynamic_cast<GOBJMBN_CLIQSET *>(&InferEng());
// See if this state of information is impossible
bool bIsImposs = pCliqueSet != NULL
&& pCliqueSet->BImpossible();
for ( MPSTRPND::iterator mpit = Mpstrpnd().begin();
mpit != Mpstrpnd().end();
mpit++ )
{
GNODEMBND * pgndd = (*mpit).second;
int cState = pgndd->CState();
if ( ! bIsImposs )
{
InferEng().GetBelief( pgndd, mdvBel );
assert( cState == mdvBel.size() );
}
if ( Postream() )
{
SZC szcName = SzcNdName( pgndd );
for ( int ist = 0; ist < cState; ist++ )
{
Ostream() << szcName << "," << ist << ",";
if ( bIsImposs )
Ostream() << _rImposs;
else
Ostream() << mdvBel[ist];
Ostream() << "\n";
_clOut++;
}
}
}
if ( BFlag( fUtil ) )
{
GetUtilities();
}
else
if ( BFlag( fTSUtil ) )
{
GetTSUtilities();
}
#ifdef _DEBUG
if ( Postream() )
Ostream().flush();
#endif
}
void TESTINFO :: InferTest ()
{
bool bOutput = Postream() != NULL;
int cPass = FCtl() & fPassCountMask;
// Is network expanded?
bool bExpanded = Mbnet().BFlag( EIBF_Expanded );
PROPMGR propmgr( Mbnet() ); // Property manager
int iLblProblem = propmgr.ILblToUser( ESTDLBL_problem );
ZSREF zsrPropTypeLabel = propmgr.ZsrPropType( ESTDP_label );
MPSTRPND & mpstrpnd = Mpstrpnd(); // Map of strings to node ptrs
MPSTRPND mpstrpndProblem; // Map of PD nodes
for ( int inode = 0; inode < Mbnet().CNameMax(); inode++ )
{
GOBJMBN * pgobj = Mbnet().PgobjFindByIndex( inode );
if ( ! pgobj )
continue;
GNODEMBND * pgndd = dynamic_cast<GNODEMBND *>(pgobj);
if ( ! pgndd )
continue;
SZC szcName = FCtl() & fSymName
? pgndd->ZsrefName().Szc()
: pgndd->ZsFullName().Szc();
// See if this is a problem-defining node
PROPMBN * propLbl = pgndd->LtProp().PFind( zsrPropTypeLabel );
if ( propLbl && propLbl->Real() == iLblProblem )
{
// Put PD nodes into separate map
mpstrpndProblem[szcName] = pgndd;
}
// If the network is expanded, use only regular nodes
if ( (! bExpanded) || ! pgndd->BFlag( EIBF_Expansion ) )
{
mpstrpnd[szcName] = pgndd;
}
}
for ( int iPass = 0; iPass < cPass; iPass++ )
{
int iProb = -1;
int iProbState = 0;
int cProbState = 0;
GNODEMBND * pgnddProblem = NULL;
MPSTRPND::iterator mpitPd = mpstrpndProblem.begin();
MPSTRPND::iterator mpitPdEnd = mpstrpndProblem.end();
for (;;)
{
// After 1st cycle, advance the problem state of the PD node
if ( pgnddProblem )
{
ZSTR zsNamePD;
CLAMP clampProblemState(true, iProbState, true);
InferEng().EnterEvidence( pgnddProblem, clampProblemState );
if ( FCtl() & fSymName )
zsNamePD = pgnddProblem->ZsrefName();
else
zsNamePD = pgnddProblem->ZsFullName();
if ( bOutput )
{
Ostream() << "$PROBLEMINST,"
<< zsNamePD.Szc()
<< ","
<< iProbState
<< "\n";
_clOut++;
}
}
MPSTRPND::iterator mpit = mpstrpnd.begin();
MPSTRPND::iterator mpend = mpstrpnd.end();
int cpnd = mpstrpnd.size();
for ( int inid = -1; inid < cpnd; inid++ )
{
GNODEMBND * pgndd = NULL;
ZSTR zsName;
int cst = 0; // Cause inner loop to run once on first cycle
if ( inid >= 0 )
{
pgndd = (*mpit++).second;
if ( FCtl() & fSymName )
zsName = pgndd->ZsrefName();
else
zsName = pgndd->ZsFullName();
cst = pgndd->CState();
}
for ( int ist = -1; ist < cst; ist++ )
{
if ( ist < 0 )
{
// The first time through, print all the beliefs
// with no instantiations; do nothing on later cycles.
if ( pgndd != NULL )
continue;
if ( bOutput )
{
Ostream() << "$COMPLETE\n";
_clOut++;
}
}
else
{
CLAMP clampState(true, ist, true);
InferEng().EnterEvidence( pgndd, clampState );
if ( bOutput )
{
Ostream() << "$INSTANTIATE,"
<< zsName.Szc()
<< ","
<< ist
<< "\n";
_clOut++;
}
}
GetBeliefs();
}
if ( pgndd )
{
// Clear the instantitation of this node.
InferEng().EnterEvidence( pgndd, CLAMP() );
}
}
// If this is the last abnormal state for this problem node,
// advance to the next node.
if ( ++iProbState >= cProbState )
{
// Unclamp the last problem node, if any
if ( pgnddProblem )
InferEng().EnterEvidence( pgnddProblem, CLAMP() );
// Move on to the next PD node
if ( mpitPd == mpitPdEnd )
break;
pgnddProblem = (*mpitPd++).second;
cProbState = pgnddProblem->CState();
// Reset to 1st problem state
iProbState = 1;
}
}
}
}
// Return a displayable string of the current options settings
ZSTR TESTINFO :: ZsOptions ( ULONG fFlag )
{
static
struct
{
ULONG _f; // Bit flag
SZC _szc; // Option name
}
vOptMap [] =
{
{ fVerbose, "verbose" },
{ fCliquing, "clique" },
{ fInference, "infer" },
{ fMulti, "multipass" },
{ fOutputFile, "outfile" },
{ fShowTime, "times" },
{ fSaveDsc, "dscout" },
{ fPause, "pause" },
{ fSymName, "symname" },
{ fExpand, "expand" },
{ fClone, "clone" },
{ fUtil, "utilities" },
{ fReg, "registry" },
{ fTSUtil, "recommend" },
{ fInferStats, "inferstats"},
{ fImpossible, "impossible"},
{ 0, "" }
};
ZSTR zs;
ULONG cpass = fFlag & fPassCountMask;
fFlag &= ~ fPassCountMask;
for ( int i = 0; vOptMap[i]._f != 0; i++ )
{
if ( fFlag & vOptMap[i]._f )
{
if ( zs.length() > 0 )
zs += ',';
zs += vOptMap[i]._szc;
}
}
if ( fFlag & fMulti )
{
if ( zs.length() > 0 )
zs += ",";
zs.FormatAppend("passes=%d", cpass);
}
return zs;
}