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;
}
bool CSamplingInfEngine::
ConvertingFamilyToPot( int node, const CEvidence* pEv )
{
    bool ret = false;
    CPotential* potToSample = m_potsToSampling[node];
    Normalization(potToSample);
    int i;
    if( !IsAllNdsTab() )
    {
	
	if( GetModel()->GetModelType() == mtBNet )
	{
	    
	    for( i = 0; i < m_environment[node].size(); i++ )
	    {            
		int num = m_environment[node][i];
		CPotential *pot1 = static_cast< CCPD* >( m_currentFactors[ num ] )
		    ->ConvertWithEvidenceToPotential(pEv);
		CPotential *pot2 = pot1->Marginalize(&node, 1);
		delete pot1;
		*potToSample *= *pot2;
		delete pot2;
	    }
	}
	
	else
	{
	    for( i = 0; i < m_environment[node].size(); i++ )
	    {
		int num = m_environment[node][i];
		CPotential *pot1 = static_cast< CPotential* >( m_currentFactors[ num ] )
		    ->ShrinkObservedNodes(pEv);
		CPotential *pot2 = pot1->Marginalize(&node, 1);
		delete pot1;
		*potToSample *= *pot2;
		delete pot2;
	    }
	}
	
    }
    else
    {
	
	CMatrix< float > *pMatToSample;
	pMatToSample = static_cast<CTabularDistribFun*>(potToSample->GetDistribFun())
	    ->GetMatrix(matTable);
	
	intVector dims;
	intVector vls;
	intVector domain;
	
	for( i = 0; i < m_environment[node].size(); i++ )
	{            
	    int num = m_environment[node][i];
	    m_currentFactors[ num ]->GetDomain(&domain);
	    GetObsDimsWithVls( domain, node, pEv, &dims, &vls); 
	    CMatrix< float > *pMat;
	    pMat = static_cast<CTabularDistribFun*>(m_currentFactors[ num ]->
		GetDistribFun())->GetMatrix(matTable);
	    pMat->ReduceOp( &dims.front(), dims.size(), 2, &vls.front(),
		pMatToSample, PNL_ACCUM_TYPE_MUL );
	    dims.clear();
	    vls.clear();
	    domain.clear();
	    
	}
    }
    
    //check for non zero elements
    CMatrix<float> *pMat;
    if( potToSample->GetDistributionType()==dtTabular )
    {	
	pMat = potToSample->GetDistribFun()->GetMatrix(matTable);
    }
    else
    {
	CGaussianDistribFun* pDistr = static_cast<CGaussianDistribFun*>(potToSample->GetDistribFun());
	if(pDistr->GetMomentFormFlag())
	{
	    pMat = pDistr->GetMatrix(matCovariance);
	}
	else
	{
	    pMat = pDistr->GetMatrix(matK);

	}
    }
    CMatrixIterator<float>* iter = pMat->InitIterator();
    for( iter; pMat->IsValueHere( iter ); pMat->Next(iter) )
    {
	
	if(*(pMat->Value( iter )) > FLT_EPSILON)
	{
	    ret = true;
	    break;
	}
    }
    delete iter;
    return ret;
}
int CJtreeInfEngine::GetDataForMargAndMult(const int source, const int sink,
					   pnl::CNumericDenseMatrix< float > **sorceMatrix, int **dims_to_keep,
					   int &num_dims_to_keep, pnl::CNumericDenseMatrix< float > **sepMatrix, 
					   pnl::CNumericDenseMatrix< float > **sinkMatrix, int **dims_to_mul,
					   int &num_dims_to_mul)
{
    // bad-args check
    PNL_CHECK_RANGES(source, 0, m_pJTree->GetNumberOfNodes() - 1);
    PNL_CHECK_RANGES(sink, 0, m_pJTree->GetNumberOfNodes() - 1);
    // bad-args check end

    if (source == sink)
    {
	PNL_THROW(CInvalidOperation, " source and sink should differ ");
    }
    if (!m_pJTree->GetGraph()->IsExistingEdge(source, sink))
    {
	PNL_THROW(CInvalidOperation, " there is no edge between source and sink");
    }

    CPotential *potSource = m_pJTree->GetNodePotential(source),
	*potSink   = m_pJTree->GetNodePotential(sink);

    int numNdsInSourceDom, numNdsInSinkDom;
    const int *sourceDom, *sinkDom;
    potSource->GetDomain(&numNdsInSourceDom, &sourceDom);
    potSink->GetDomain(&numNdsInSinkDom, &sinkDom);

    CPotential *potSep = m_pJTree->GetSeparatorPotential(source, sink);
    int numNdsInSepDom;
    const int *sepDom;
    potSep->GetDomain(&numNdsInSepDom, &sepDom);

    EDistributionType sepDistType = potSep->GetDistributionType();

    num_dims_to_keep = numNdsInSepDom;
    *dims_to_keep = new int [num_dims_to_keep];

    int* pEquivPos;
    for (int i = 0; i < numNdsInSepDom; i++)
    {
	pEquivPos = (int*)std::find(sourceDom, sourceDom + numNdsInSourceDom, sepDom[i]);
	if (pEquivPos != sourceDom + numNdsInSourceDom)
	{
	    (*dims_to_keep)[i] = (pEquivPos - sourceDom);
	}
	else 
	{
	    PNL_THROW( CInconsistentSize, "small domain isn't subset of domain")
		return 0;
	}
	//check that pSmallDom is m_Domain's subset
    }
    switch (sepDistType)
    {
    case dtTabular:
	{
	    CDistribFun *sepDistrFun = potSep -> GetDistribFun();
	    CDistribFun *sourceDistrFun = potSource -> GetDistribFun();
	    CDistribFun *sinkDistrFun = potSink -> GetDistribFun();
	    if (!sourceDistrFun->IsValid())
	    {
		PNL_THROW( CInconsistentType, "MarginalizeData is invalid" )
	    }

	    //check if distribution of potSource is Unit Function - do nothing
	    if(sourceDistrFun->IsDistributionSpecific())
	    {
		return 0;
	    }

	    if ( sepDistrFun->IsDistributionSpecific() )
	    {
		sepDistrFun->SetUnitValue(0);
	    }


	    *sorceMatrix = static_cast<CNumericDenseMatrix<float> *>(sourceDistrFun->
		GetMatrix(matTable));
	    *sepMatrix = static_cast<CNumericDenseMatrix<float> *>(sepDistrFun->
		GetMatrix(matTable));

	    EDistributionType dtsink = sinkDistrFun->GetDistributionType();
	    if ((dtsink != dtTabular) && (dtsink != dtScalar))
	    {
		PNL_THROW(CInvalidOperation, "we can multiply only tabulars")
	    }

	    int location;
	    num_dims_to_mul = numNdsInSepDom;
	    *dims_to_mul = new int [num_dims_to_mul];

	    for (int i = 0; i < numNdsInSepDom; i++)
	    {
		location = 
		    std::find(sinkDom, sinkDom + numNdsInSinkDom, sepDom[i]) - sinkDom;
		if (location < numNdsInSinkDom)
		{
		    (*dims_to_mul)[i] = location;
		}
	    }

	    if(sinkDistrFun->IsDistributionSpecific())
	    {
		sinkDistrFun->SetUnitValue(0);
		floatVector *aValue = 
		    (floatVector *)((CDenseMatrix<float>*)sinkDistrFun->
		    GetMatrix(matTable))->GetVector();
		aValue->assign(aValue->size(), 1.0f);
	    }

	    *sinkMatrix = static_cast<CNumericDenseMatrix<float>*>(sinkDistrFun->
		GetMatrix(matTable));

	    break;
	}
    case dtScalar:
	{
	    // propagate isn't need
	    return 0;
	}
    default:
	{
	    PNL_THROW(CNotImplemented, "we have only Tabular now");
	    return 0;
	}
    }

    if (numNdsInSepDom == 0)
    {
	PNL_THROW(COutOfRange, "domain size should be positive");
    }
    return 1;
}