void CGibbsSamplingInfEngine::
MarginalNodes( const int *queryIn, int querySz, int notExpandJPD )
{
  delete m_pQueryJPD;
  m_pQueryJPD = NULL;
  
  delete m_pPotMPE;
  m_pPotMPE = NULL;
  
  delete m_pEvidenceMPE;
  m_pEvidenceMPE = NULL;
  
  const CFactor *pFactor;
  CPotential *pPot =  NULL;
  int *begin1;
  int *end1;
  int *begin2;
  int *end2;
  
  intVector domainVec;
  intVector queryVec;
  intVector obsQueryVec;
  queryVec.reserve(querySz);
  obsQueryVec.reserve(querySz);
  int i;
  for( i = 0; i < querySz; i++ )
  {
    m_pEvidence->IsNodeObserved(queryIn[i]) ? 
      obsQueryVec.push_back(queryIn[i]):
    queryVec.push_back(queryIn[i]);
  }
  
  
  CPotential *tmpPot = NULL;
  
  if( queryVec.size() )
  {
    for( i = 0; i < m_queryFactors.size(); i++)     
    {
      
      domainVec.clear();
      pFactor = m_queryFactors[i];
      pFactor->GetDomain(&domainVec);
      begin1 = &domainVec.front();
      end1 = &domainVec.back() + 1;
      std::sort(begin1, end1);
      
      begin2 = &queryVec.front();
      end2 = &queryVec.back() + 1;
      std::sort(begin2, end2);
      
      if( std::includes(begin1, end1, begin2, end2) )
      {
        pPot = pFactor->ConvertStatisticToPot( (GetMaxTime()-GetBurnIn()-1)*GetNumStreams() );
        tmpPot = pPot->Marginalize( queryVec );
        delete pPot;
        break;
      }
      		   
    }
    if( !tmpPot )
    {
      PNL_THROW(CInvalidOperation, "Invalid query");
    }
  }
  delete m_pQueryJPD; 
  
  if( obsQueryVec.size() )
  {
    
    EDistributionType paramDistrType = 
      pnlDetermineDistributionType( GetModel()->GetModelDomain(), querySz, queryIn, m_pEvidence);
    
    
    CPotential *pQueryPot;
    switch( paramDistrType )
    {
    case dtTabular:
      {
        pQueryPot = CTabularPotential::CreateUnitFunctionDistribution(
          queryIn, querySz, m_pGraphicalModel->GetModelDomain() );
        break;
      }
      
    case dtGaussian:
      {
        pQueryPot = CGaussianPotential::CreateUnitFunctionDistribution(
          queryIn, querySz, m_pGraphicalModel->GetModelDomain()  );
        break;
      }
    case dtScalar:
      {
        pQueryPot = CScalarPotential::Create(
          queryIn, querySz, m_pGraphicalModel->GetModelDomain()  );
        break;
      }
    case dtCondGaussian:
      {
        PNL_THROW( CNotImplemented, "conditional gaussian factors" )
          break;
      }
    default:
      {
        PNL_THROW( CInconsistentType, "distribution type" )
      }
    }
    
    if( tmpPot)
    {
      (*pQueryPot) *= (*tmpPot);
      delete tmpPot;
    }
    
    if( m_bMaximize )
    {
      m_pPotMPE   = static_cast<CPotential*>
        ( pQueryPot->ExpandObservedNodes( m_pEvidence, 0) );
      
      m_pEvidenceMPE = m_pPotMPE->GetMPE();
    }
    else
    {
      m_pQueryJPD = static_cast<CPotential*>( pQueryPot->ExpandObservedNodes( m_pEvidence, 0) );
    }
    
    delete pQueryPot;
  }
void CJtreeInfEngine::
MarginalizeCliqueToQuery( int clqNum, int querySz, const int *query,
			 int notExpandJPD )
{
    // bad-args check
    PNL_CHECK_RANGES( clqNum, 0, m_pJTree->GetNumberOfNodes() - 1 );
    PNL_CHECK_RANGES( querySz, 1, m_pGraphicalModel->GetNumberOfNodes() );
    PNL_CHECK_IS_NULL_POINTER(query);
    // bad-args check end

    // Note: cant call expand() for potentials, which contain continuous
    // observed nodes in domain, cause those are to be expanded to 
    // mixture of gaussians, which we dont support right now.

    delete m_pQueryJPD;
    m_pQueryJPD = NULL;

    delete m_pPotMPE;
    m_pPotMPE = NULL;

    delete m_pEvidenceMPE;
    m_pEvidenceMPE = NULL;


    bool bExpandAllowed = true;

    CPotential* clqPotWithQuery = m_pJTree->GetNodePotential(clqNum);
    EDistributionType dtClqWithQuery = clqPotWithQuery->GetDistributionType();

    if( std::find_first_of( query, query + querySz,
	m_actuallyObsNodes.begin(),	m_actuallyObsNodes.end() )
	!= ( query + querySz ) )
    {
	const int *queryIt = query, *query_end = query + querySz;

	for( ; queryIt != query_end; ++queryIt )
	{
	    if( std::find( m_actuallyObsNodes.begin(),
		m_actuallyObsNodes.end(), *queryIt )
		!= m_actuallyObsNodes.end() )
	    {
		int shrNodebDiscrete = 
		    m_pGraphicalModel->GetNodeType(*queryIt)->IsDiscrete();
		if(((dtClqWithQuery == dtTabular)&&( !shrNodebDiscrete ))
		    ||(( dtClqWithQuery == dtGaussian )&&( shrNodebDiscrete )))
		{
		    bExpandAllowed = false;
		    break;
		}
	    }
	}
    }

    if( ( bExpandAllowed == false ) && ( notExpandJPD == false ) )
    {
	PNL_THROW( CAlgorithmicException,
	    " JPD expansion not possible technically " );
    }

    bExpandAllowed = notExpandJPD ? false : bExpandAllowed;

    CPotential *pMargJPot = clqPotWithQuery->Marginalize( query, querySz,
	m_bMaximize );

    if( bExpandAllowed )
    {
	CPotential *pExpObsJPot = pMargJPot->ExpandObservedNodes(m_pEvidence);

	if( m_bMaximize )
	{
	    if( pMargJPot->GetDistributionType() == dtScalar )
	    {
		m_pPotMPE = pExpObsJPot->GetNormalized();
		m_pEvidenceMPE = m_pPotMPE->GetMPE();
	    }
	    else
	    {
		m_pPotMPE      = pMargJPot->GetNormalized();
		m_pEvidenceMPE = m_pPotMPE->GetMPE();
	    }
	}
	else
	{
	    m_pQueryJPD = pExpObsJPot->GetNormalized();
	}

	delete pExpObsJPot;
    }
    else
    {
	if( m_bMaximize )
	{
	    m_pPotMPE      = pMargJPot->GetNormalized();
	    m_pEvidenceMPE = m_pPotMPE->GetMPE();
	}
	else
	{
	    m_pQueryJPD = pMargJPot->GetNormalized();
	}
    }
    if((!m_bMaximize)&&(m_pQueryJPD->GetDistributionType() == dtGaussian))
    {
	static_cast<CGaussianDistribFun*>(
	    m_pQueryJPD->GetDistribFun())->UpdateMomentForm();
    }
    if((m_bMaximize)&&(m_pPotMPE->GetDistributionType() == dtGaussian))
    {
	static_cast<CGaussianDistribFun*>(
	    m_pPotMPE->GetDistribFun())->UpdateMomentForm();
    }
    delete pMargJPot;
}