windows-nt/Source/XPSP1/NT/enduser/troubleshoot/bn/model.cpp
2020-09-26 16:20:57 +08:00

338 lines
8.1 KiB
C++

//+-------------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (C) Microsoft Corporation, 1997 - 1998
//
// File: model.cpp
//
//--------------------------------------------------------------------------
//
// MODEL.CPP
//
#include <basetsd.h>
#include <string.h>
#include "basics.h"
#include "algos.h"
#include "gmprop.h"
#include "model.h"
#include "gmobj.h"
struct EC_STR
{
ECGM _ec;
SZC _szc;
};
static EC_STR vEcToStr [] =
{
#define GMERRORSTR
#include "errordef.h"
{ EC_OK, "no error" }
};
SZC MODEL :: SzcFromEc ( ECGM ec )
{
int cEc = UBOUND(vEcToStr);
for ( int i = 0; i < cEc; i++ )
{
if ( ec == vEcToStr[i]._ec )
return vEcToStr[i]._szc;
}
return NULL;
}
// Iterator class for MODELs
MODEL::ITER::ITER(MODEL& model, GOBJMBN::EBNOBJ eType)
: _eType(eType),
_model(model)
{
Reset();
}
MODEL::ITER::ITER(MODEL& model) : _model(model)
{
}
void MODEL::ITER::CreateNodeIterator()
{
_eType = GOBJMBN::EBNO_NODE;
Reset();
}
void MODEL::ITER :: Reset ()
{
_pCurrent = NULL;
_itsym = _model.Mpsymtbl().begin();
BNext();
}
bool MODEL::ITER :: BNext ()
{
while ( _itsym != _model.Mpsymtbl().end() )
{
_pCurrent = (*_itsym).second.Pobj();
_zsrCurrent = (*_itsym).first;
_itsym++;
if ( _pCurrent->EType() == _eType )
return true;
}
_pCurrent = NULL;
return false;
}
///////////////////////////////////////////////////////////////////////////
// MODEL naming commentary.
//
// Symbolic names in a belief network come in two types: names which users
// can enter (or edit into a DSC file) and those which they cannot.
//
// The basic (user-definable) symbolic name follows exactly the rules of
// standard 'C', except that periods ('.') are allowed inside a name.
//
// There is a need for generation of names which are clearly distinguishable
// from user-definable names; these are called "internal" names. The only
// difference is that the legal character set is extended to include the '$'
// (dollar sign) character as an alphabetic character (i.e., it can be the
// first character in a name).
//
///////////////////////////////////////////////////////////////////////////
// Return true if the character is legal in a name
bool MODEL :: BChLegal ( char ch, ECHNAME echnm, bool bInternal )
{
bool bOther = bInternal && ch == ChInternal();
bool bOkForC = echnm == ECHNM_First
? __iscsymf(ch)
: __iscsym(ch) || (echnm == ECHNM_Middle && ch == '.');
return bOther || bOkForC;
}
// Return true if the name is legal
bool MODEL :: BSzLegal ( SZC szcName, bool bInternal )
{
for ( int i = 0; szcName[i]; i++ )
{
ECHNAME echnm = i == 0
? ECHNM_First
: (szcName[i+1] ? ECHNM_Middle : ECHNM_Last);
if ( ! BChLegal( szcName[i], echnm, bInternal ) )
return false;
}
return true;
}
MODEL :: MODEL ()
: _pgrph(NULL),
_rVersion(-1.0)
{
// Allocate the GRPH graph object
SetPgraph(new GRPH);
assert( _pgrph );
//
// Define the table of known (early-defined) bit flags in this scope
//
#define MBN_GEN_BFLAGS_TABLE szcBitFlagNames
// Include the header to generate the strings
#include "mbnflags.h"
// Define the table of known bit flags.
for ( int i = 0; szcBitFlagNames[i]; i++ )
{
// Note: this automatically interns the names into the symbol table
IBFLAG ibf = Mpsymtbl().IAddBitFlag( szcBitFlagNames[i] );
}
}
MODEL :: ~ MODEL ()
{
// We must clear the graph and symbol table at this point, because their
// elements interreference via the names (ZSREFs) and pointers (REFPOBJs).
// The symbol table is cleared first, so that no stray references to GOBJMBNs
// exist when the graph object is nuked. Then the graph is cleared, so
// that embedded references to strings interned in the symbol table's string
// table will be removed.
Mpsymtbl().clear();
// Delete the graph
SetPgraph(NULL);
}
void MODEL :: SetPgraph ( GRPH * pgrph )
{
delete _pgrph;
_pgrph = pgrph;
}
// Add an unnamed element to the graph
void MODEL :: AddElem ( GELEMLNK * pgelm )
{
ASSERT_THROW( pgelm, EC_NULLP, "null ptr passed to MODEL::AddElem()" );
Pgraph()->AddElem( *pgelm );
}
// Test the name for duplicate; add if not, otherwise return false
bool MODEL :: BAddElem ( SZC szcName, GOBJMBN * pgobj )
{
if ( ::strlen( szcName ) == 0 )
return false; // Name missing
if ( Mpsymtbl().find( szcName ) )
return false; // duplicate name
AddElem( szcName, pgobj );
return true;
}
// Add a (possibly) named object to the graph and symbol table
void MODEL :: AddElem ( SZC szcName, GOBJMBN * pgelm )
{
if ( szcName != NULL && ::strlen(szcName) != 0 )
{
if ( Mpsymtbl().find( szcName ) )
throw GMException( EC_DUPLICATE_NAME, "attempt to add duplicate name to MBNET" );
Mpsymtbl().add( szcName, pgelm );
}
AddElem( pgelm );
}
void MODEL :: DeleteElem ( GOBJMBN * pgobj )
{
if ( pgobj->ZsrefName().Zstr().length() > 0 )
Mpsymtbl().remove( pgobj->ZsrefName() );
else
DeleteElem( (GELEMLNK *) pgobj );
}
void MODEL :: DeleteElem ( GELEMLNK * pgelem )
{
delete pgelem;
}
void MODEL :: Clone ( MODEL & model )
{
ASSERT_THROW( _pgrph->ChnColl().PgelemNext() == NULL,
EC_INVALID_CLONE,
"cannot clone into non-empty structure" );
// Clone the descriptive information
_rVersion = model._rVersion;
_zsFormat = model._zsFormat;
_zsCreator = model._zsCreator;
_zsNetworkID = model._zsNetworkID;
// Clone the symbol table
_mpsymtbl.Clone( model._mpsymtbl );
// Copy the network bit flags array
_vFlags = model._vFlags;
//
// Clone the actual contents of the network, object by object
//
{
// Create a map to correlate old object pointers to new object pointers
typedef map<GOBJMBN *, GOBJMBN *, less<GOBJMBN *> > MPPOBJPOBJ;
MPPOBJPOBJ mppobjpobj;
// Add the property types first, then all the node-like things
GELEMLNK * pgelm;
MODELENUM mdlenumNode( model );
for ( int icycle = 0; icycle < 2; icycle++ )
{
mdlenumNode.Reset(model.Grph());
while ( pgelm = mdlenumNode.PlnkelNext() )
{
// Check that it's a node (not an edge)
if ( ! pgelm->BIsEType( GELEM::EGELM_NODE ) )
continue;
GOBJMBN * pgobjmbn;
GOBJMBN * pgobjmbnNew = NULL;
DynCastThrow( pgelm, pgobjmbn );
// Clone property types on the first pass, all other nodeish things
// on the second.
if ( (icycle == 0) ^ (pgelm->EType() == GOBJMBN::EBNO_PROP_TYPE) )
continue;
pgobjmbnNew = pgobjmbn->CloneNew( model, self );
// If the object was cloned or allowed itself to be cloned,
// add it
if ( pgobjmbnNew )
{
assert( pgobjmbnNew->EType() == pgobjmbn->EType() );
mppobjpobj[ pgobjmbn ] = pgobjmbnNew;
// Add the object as named or unnamed
AddElem( pgobjmbnNew->ZsrefName(), pgobjmbnNew );
}
}
}
// Add all the edge-like things
MODELENUM mdlenumEdge( model );
while ( pgelm = mdlenumEdge.PlnkelNext() )
{
// Check that it's a edge (not a node)
if ( ! pgelm->BIsEType( GELEM::EGELM_EDGE ) )
continue;
GEDGEMBN * pgedge;
DynCastThrow( pgelm, pgedge );
GOBJMBN * pgobjmbnSource = pgedge->PobjSource();
GOBJMBN * pgobjmbnSink = pgedge->PobjSink();
assert( pgobjmbnSource && pgobjmbnSink );
GOBJMBN * pgobjmbnSourceNew = mppobjpobj[ pgobjmbnSource ];
GOBJMBN * pgobjmbnSinkNew = mppobjpobj[ pgobjmbnSink ];
assert( pgobjmbnSourceNew && pgobjmbnSinkNew );
GEDGEMBN * pgedgeNew = pgedge->CloneNew( model,
self,
pgobjmbnSourceNew,
pgobjmbnSinkNew );
assert( pgedgeNew );
AddElem( pgedgeNew );
}
}
// Clone the network property list
_ltProp.Clone( self, model, model._ltProp );
}
GOBJMBN * MODEL :: PgobjFind ( SZC szcName )
{
return Mpsymtbl().find(szcName);
}
void MPSYMTBL :: Clone ( const MPSYMTBL & mpsymtbl )
{
// Clone all the interned strings
_stszstr.Clone( mpsymtbl._stszstr );
// Clone the array of bit flag names
CloneVzsref( mpsymtbl, mpsymtbl._mpzsrbit, _mpzsrbit );
// All other symbol entries must be created from above
}
void MPSYMTBL :: CloneVzsref (
const MPSYMTBL & mpsymtbl,
const VZSREF & vzsrSource,
VZSREF & vzsrTarget )
{
vzsrTarget.resize( vzsrSource.size() );
for ( int i = 0; i < vzsrTarget.size(); i++ )
{
SZC szc = vzsrSource[i].Szc();
vzsrTarget[i] = intern(szc);
}
}