393 lines
9.2 KiB
C++
393 lines
9.2 KiB
C++
//+-------------------------------------------------------------------------
|
|
//
|
|
// 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 );
|
|
}
|
|
}
|
|
|