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.
 
 
 
 
 
 

392 lines
9.2 KiB

//+-------------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (C) Microsoft Corporation, 1997 - 1998
//
// File: margiter.cpp
//
//--------------------------------------------------------------------------
//
// margiter.cpp: compiled marginals iterators
//
#include <basetsd.h>
#include <math.h>
#include "basics.h"
#include "gmobj.h"
#include "marginals.h"
#include "margiter.h"
#include "algos.h"
#include "parmio.h"
LEAK_VAR_DEF(VMARGSUB)
LEAK_VAR_DEF(MARGSUBREF)
//
// Construct a VMARGSUB from a marginals iterator
//
VMARGSUB :: VMARGSUB ( MARGINALS::Iterator & itMarg )
: _iSearchPass(0)
{
itMarg.Reset();
resize( itMarg.IEnd() );
for ( int i = 0; itMarg.BNext() ; i++)
{
int ix = itMarg.IndxUpd();
self[i] = ix;
}
LEAK_VAR_UPD(1)
}
VMARGSUB :: ~ VMARGSUB ()
{
LEAK_VAR_UPD(-1)
}
void VMARGSUB :: NoRef ()
{
delete this;
}
MARGSUBREF :: MARGSUBREF ( VMARGSUB * pvmsub, int cSize )
: _pvmsub( NULL ),
_cSize( -1 )
{
SetVmsub( pvmsub, cSize );
LEAK_VAR_UPD(1)
}
MARGSUBREF :: MARGSUBREF ( const MARGSUBREF & msubr )
: _pvmsub( NULL ),
_cSize( -1 )
{
self = msubr;
LEAK_VAR_UPD(1)
}
MARGSUBREF & MARGSUBREF :: operator = ( const MARGSUBREF & msubr )
{
SetVmsub( msubr._pvmsub, msubr.CSize() );
return self;
}
void MARGSUBREF :: SetVmsub ( VMARGSUB * pvmsub, int cSize )
{
if ( _pvmsub )
{
_pvmsub->Unbind();
_pvmsub = NULL;
}
if ( pvmsub )
{
_cSize = cSize > 0 ? cSize : pvmsub->size();
pvmsub->Bind();
_pvmsub = pvmsub;
}
else
{
_cSize = 0;
}
}
MARGSUBREF :: ~ MARGSUBREF ()
{
SetVmsub( NULL );
LEAK_VAR_UPD(-1)
}
bool MARGSUBREF :: operator == ( const MARGSUBREF & msr ) const
{
return _pvmsub == msr._pvmsub && _cSize == msr._cSize;
}
bool MARGSUBREF :: operator != ( const MARGSUBREF & msr ) const
{
return !(self == msr);
}
LTMARGSUBREF :: LTMARGSUBREF ()
: _iSearchPass(0),
_cArrays(0),
_cArrayTotalSize(0),
_cSubRefs(0)
{
}
void LTMARGSUBREF :: Dump ()
{
#ifdef DUMP
cout << "\n\nLTMARGSUBREF::~ LTMARGSUBREF: "
<< "\n\tTotal search passes to create marginals iterators = "
<< _iSearchPass
<< "\n\tTotal arrays = "
<< _cArrays
<< "\n\tTotal array size = "
<< _cArrayTotalSize
<< "\n\tTotal marg iterator references = "
<< _cSubRefs
;
cout.flush();
#endif
}
// Iterate over the list looking for a match
MARGSUBREF * LTMARGSUBREF :: PmsubrAdd ( MARGINALS::Iterator & itMarg )
{
// Bump the search pass
_iSearchPass++;
// Get the minimum number of elements
int cMin = itMarg.IEnd();
MARGSUBREF * pmsubrBest = NULL;
MARGSUBREF * pmsubrNew = NULL;
// Search the list for the longest matching subscript array
// in the pool.
for ( LTMSUBR::iterator itlt = _ltmsubr.begin();
itlt != _ltmsubr.end();
itlt++ )
{
MARGSUBREF & msubr = (*itlt);
VMARGSUB & vmsub = msubr.Vmsub();
if ( vmsub.ISearchPass() == _iSearchPass )
continue; // We've already looked at this one
// Mark this VMARGSUB as having been checked in this pass
vmsub.ISearchPass() = _iSearchPass;
// Prepare to search it
itMarg.Reset();
for ( int i = 0; itMarg.BNext() && i < vmsub.size() ; i++ )
{
int ia = vmsub[i];
int ib = itMarg.IndxUpd();
if ( ia != ib )
break;
}
// If we made it to the end of the array, we found one.
if ( i != cMin )
continue; // Mismatch somewhere
// See if it's the best (longest) found so far
if ( pmsubrBest == NULL )
{
pmsubrBest = & msubr;
}
else
if ( pmsubrBest->Vmsub().size() < vmsub.size()
|| ( pmsubrBest->Vmsub().size() == vmsub.size()
&& pmsubrBest->CSize() == cMin ) )
{
pmsubrBest = & msubr;
}
}
// If "pmsubrBest" != NULL, we found at least one matching array.
// Now see if we can find an exact match: a MARGSUBREF which has
// the same base array and the same length as what we want.
if ( pmsubrBest )
{
// If the "best" one doesn't match our size, find one that does
if ( pmsubrBest->CSize() != cMin )
{
for ( itlt = _ltmsubr.begin();
itlt != _ltmsubr.end();
itlt++ )
{
MARGSUBREF & msubr = (*itlt);
if ( msubr.Pvmsub() == pmsubrBest->Pvmsub()
&& msubr.CSize() == cMin )
{
pmsubrBest = & msubr;
break;
}
}
}
// See if now have and exact match
if ( pmsubrBest->CSize() == cMin )
{
// Exact match: best array and same length
pmsubrNew = pmsubrBest;
}
else
{
// Well, we know which array to use, but we have
// to create a new MARGSUBREF for it
_ltmsubr.push_back( MARGSUBREF( pmsubrBest->Pvmsub(), cMin ) );
pmsubrNew = & _ltmsubr.back();
_cSubRefs++;
}
}
else
{
// There does NOT appear to be a viable array in the ensemble,
// so we have to create a new one and a MARGSUBREF for it.
VMARGSUB * pvmsub = new VMARGSUB( itMarg );
_cArrays++;
_cArrayTotalSize += cMin;
_ltmsubr.push_back( MARGSUBREF( pvmsub, cMin ) );
pmsubrNew = & _ltmsubr.back();
_cSubRefs++;
// At this point we have a new array which may be a superset of
// some other array already in the pool. Walk through the list
// of MARGSUBREFs and change any references whose base arrays
// are subsets of this new one to point to the new array.
// Bump the search pass
_iSearchPass++;
for ( itlt = _ltmsubr.begin();
itlt != _ltmsubr.end();
itlt++ )
{
MARGSUBREF & msubr = (*itlt);
if ( & msubr == pmsubrNew )
continue;
VMARGSUB & vmsub = msubr.Vmsub();
if ( vmsub.ISearchPass() == _iSearchPass )
continue; // We've already looked at this one
// Mark this VMARGSUB as having been checked in this pass
vmsub.ISearchPass() = _iSearchPass;
if ( & vmsub == pvmsub || vmsub.size() > pvmsub->size() )
continue; // Old array is larger; not a subset
// See if the old array is a subset
for ( int i = 0; i < vmsub.size(); i++ )
{
int ia = vmsub[i];
int ib = (*pvmsub)[i];
if ( ia != ib )
break;
}
if ( i == vmsub.size() )
{
assert( vmsub.size() != pvmsub->size() );
// The subset is identical. Change all refs that point to it.
VMARGSUB * pvmsubDefunct = msubr.Pvmsub();
for ( LTMSUBR::iterator itlt2 = _ltmsubr.begin();
itlt2 != _ltmsubr.end();
itlt2++ )
{
MARGSUBREF & msubr2 = (*itlt2);
if ( msubr2.Pvmsub() == pvmsubDefunct )
{
// If the array is about to disappear, do the bookkeepping
if ( pvmsubDefunct->CRef() <= 1 )
{
_cArrays--;
_cArrayTotalSize -= pvmsubDefunct->size();
}
// Convert this reference to a reference to our new array
msubr2.SetVmsub( pvmsub, msubr2.CSize() );
}
}
}
}
}
pmsubrNew->Bind();
return pmsubrNew;
}
void LTMARGSUBREF :: Release ( MARGSUBREF * pmsubr )
{
if ( pmsubr == NULL )
return;
pmsubr->Unbind();
if ( pmsubr->CRef() > 0 )
return;
LTMSUBR::iterator itlt = find( _ltmsubr.begin(), _ltmsubr.end(), *pmsubr );
assert( itlt != _ltmsubr.end() );
_cSubRefs--;
MARGSUBREF & msubr = (*itlt);
if ( msubr.Vmsub().CRef() <= 1 )
{
_cArrays--;
_cArrayTotalSize -= msubr.Vmsub().size();
}
_ltmsubr.erase(itlt);
}
// The global subscript array reference list
LTMARGSUBREF MARGSUBITER :: _ltmargsubr;
MARGSUBITER :: MARGSUBITER ()
:_pmsubr( NULL ),
_pmargSelf( NULL )
{
}
MARGSUBITER :: ~ MARGSUBITER ()
{
_ltmargsubr.Release( _pmsubr );
}
void MARGSUBITER :: Build ( MARGINALS & margSelf, MARGINALS & margSubset )
{
assert( margSelf.size() >= margSubset.size() );
assert( _pmsubr == NULL && _pmargSelf == NULL );
_pmargSelf = & margSelf;
// Build the pseudo-dimension descriptor.
VSIMD vsimdMarg = margSelf.VsimdSubset( margSubset.Vpgnd() );
// Construct the slice which governs the missing dimensions
MDVSLICE mdvs( vsimdMarg );
MARGINALS::Iterator itSubset( margSubset, mdvs );
// Find or construct a MARGSUBITER to match
_pmsubr = _ltmargsubr.PmsubrAdd( itSubset );
}
// Build the iterator for a clique and a node
void MARGSUBITER :: Build ( MARGINALS & margSelf, GNODEMBND * pgndd )
{
assert( _pmsubr == NULL && _pmargSelf == NULL );
_pmargSelf = & margSelf;
// Construct a dummy marginalization target
MDVCPD distd;
MARGINALS::ResizeDistribution( pgndd, distd );
// Get the pseudo-dimension descriptor for this node
VSIMD vsimdMarg = margSelf.VsimdFromNode( pgndd );
// Construct the slice which governs the missing dimensions
MDVSLICE mdvs( vsimdMarg );
MARGINALS::Iterator itSelf( margSelf );
MARGINALS::Iterator itSubset( distd, mdvs );
// Find or construct a MARGSUBITER to match
_pmsubr = _ltmargsubr.PmsubrAdd( itSubset );
}
// Verify subscripts
void MARGSUBITER :: Test ( MARGINALS & margSubset )
{
assert( _pmsubr && _pmargSelf );
assert( _pmargSelf->size() > margSubset.size() );
// Build the pseudo-dimension descriptor.
VSIMD vsimdMarg = _pmargSelf->VsimdSubset( margSubset.Vpgnd() );
// Construct the slice which governs the missing dimensions
MDVSLICE mdvs( vsimdMarg );
MARGINALS::Iterator itSubset( margSubset, mdvs );
MARGINALS::Iterator itSelf( *_pmargSelf );
int isub = 0;
VINT & vintSub = _pmsubr->VintSub();
int cEnd = _pmsubr->CSize();
for ( int iself = 0; itSelf.BNext(); iself++ )
{
int isubSelf = itSelf.IndxUpd();
int isubSubset = itSubset.IndxUpd();
assert( isubSelf == iself );
int isubTest = vintSub[iself];
assert( isubTest == isubSubset && iself < cEnd );
}
}