CPotential*
CGaussianCPD::ConvertWithEvidenceToPotential(const CEvidence* pEvidence,
					     int flagSumOnMixtureNode )const
{
    if( m_CorrespDistribFun->GetDistributionType() == dtGaussian )
    {
	    //need to convert to potential and after that add evidence
	    CPotential* potWithoutEv = ConvertToPotential();
	    CPotential* potWithEvid = potWithoutEv->ShrinkObservedNodes(pEvidence);
	    delete potWithoutEv;
	    return potWithEvid;
    }
    else //it means m_CorrespDistribFun->GetDistributionType == dtCondGaussian
    {
        //need to enter discrete & continuous evidence separetly
        //before it create node types - if all nodes discrete
        //or there are only nodes of size 0 from continuous -
        // - result distribution type is Tabular
        
        //collect information for enter discrete evidence & continuous
        int domSize = m_Domain.size();
        intVector obsDiscreteIndex;
        obsDiscreteIndex.reserve( domSize );
        //observed discrete values put into int vector
        intVector obsDiscrVals;
        obsDiscrVals.reserve( domSize );
        //collect information about Gaussian observed indices
        intVector obsGauIndex;
        obsGauIndex.reserve( domSize );
        //continuous observed values into vector of matrices
        pnlVector<C2DNumericDenseMatrix<float>*> obsGauVals;
        obsGauVals.reserve( domSize );
        //create matrix to store observed value of node
        C2DNumericDenseMatrix<float>* obsSelfVal = NULL;
        //create vectors for storage temporary objects
        int i;
        int isTab;
        for( i = 0; i < domSize; i++ )
        {
            int curNum = m_Domain[i];
            if( pEvidence->IsNodeObserved(curNum) )
            {
                const CNodeType* nt = GetModelDomain()->GetVariableType( curNum );
                isTab = nt->IsDiscrete();
                if( isTab )
                {
                    obsDiscreteIndex.push_back( i );
                    obsDiscrVals.push_back( pEvidence->GetValue(curNum)->GetInt() );
                }
                else
                {
                    int contSize = nt->GetNodeSize();
                    //create matrices to call Enter continuous evidence
                    floatVector val;
                    val.resize(contSize);
                    const Value* vFromEv = pEvidence->GetValue(curNum);
                    for( int j = 0; j < contSize; j++ )
                    {
                        val[j] = vFromEv[j].GetFlt();
                    }
                    intVector dims;
                    dims.assign( 2, 1 );
                    dims[0] = contSize;
                    if( i == domSize - 1 )
                    {
                        obsSelfVal = C2DNumericDenseMatrix<float>::Create(
                            &dims.front(), &val.front());
                    }
                    else
                    {
                        //store only parent indices
                        obsGauIndex.push_back( i );
                        C2DNumericDenseMatrix<float>* obsGauVal =
                            C2DNumericDenseMatrix<float>::Create(
                            &dims.front(), &val.front() );
                        obsGauVals.push_back( obsGauVal );
                    }
                }
            }
        } //        for( i = 0; i < domSize; i++ )

        CModelDomain* pMD = GetModelDomain();
        
        CPotential* resPot = NULL;
        int isLastNodeObs = pEvidence->IsNodeObserved(m_Domain[m_Domain.size()-1]); 
        if( (obsDiscreteIndex.size() + obsGauIndex.size() == m_Domain.size()-1) && isLastNodeObs)
        {
            //result distribution is scalar
            obsDiscreteIndex.insert(obsDiscreteIndex.end(), obsGauIndex.begin(),
                obsGauIndex.end());
            //child node is observed
            obsDiscreteIndex.insert(obsDiscreteIndex.end(), domSize-1);  
            resPot = CScalarPotential::Create( m_Domain, GetModelDomain(), obsDiscreteIndex );
        }

        else
        {
            const CNodeType* nt;
            //if all discrete nodes are observed then distribution will be Gaussian (Bader - comment)
            int allDiscrObs = 1;
            int allContObs = 1;
            int i;
            int isTab;
            int isCon;
            for( i = 0; i < domSize; i++ )
            {
                int curNum = m_Domain[i];
                nt = GetModelDomain()->GetVariableType( curNum );
                isTab = nt->IsDiscrete();
                isCon = !(isTab);
                if( isTab )
                    if( !(pEvidence->IsNodeObserved(curNum)) )
                        allDiscrObs = 0;
                    if( isCon )
                        if( !(pEvidence->IsNodeObserved(curNum)) )
                            allContObs = 0;
            }
            if (allContObs && (!allDiscrObs) )
            {
                CCondGaussianDistribFun* withDiscrEv =
                    (static_cast<CCondGaussianDistribFun*>(m_CorrespDistribFun))->
                    EnterDiscreteEvidence(obsDiscreteIndex.size(),
                    &obsDiscreteIndex.front(), &obsDiscrVals.front(),
                    pMD->GetObsTabVarType() );
                
                CTabularDistribFun* resDistr = withDiscrEv->
                    EnterFullContinuousEvidence( obsGauIndex.size(),
                    &obsGauIndex.front(), obsSelfVal, &obsGauVals.front(),
                    pMD->GetObsGauVarType() );

                //need to unite gaussian and tabular observed index
                obsDiscreteIndex.insert(obsDiscreteIndex.end(), obsGauIndex.begin(),
                    obsGauIndex.end());
                //child node is observed
                obsDiscreteIndex.insert(obsDiscreteIndex.end(), domSize-1);
                resPot = CTabularPotential::Create(
                    &m_Domain.front(), m_Domain.size(), GetModelDomain(), NULL,
                    obsDiscreteIndex );
                resPot->SetDistribFun( resDistr );
                delete withDiscrEv;
                delete resDistr;
            }
            else
            {
                if (allDiscrObs && !allContObs)
                {
                    intVector discParents;
                    
                    for ( i = 0; i < m_Domain.size(); i++)
                    {
                        nt = GetModelDomain()->GetVariableType( m_Domain[i] );
                        if (nt->IsDiscrete())
                            discParents.push_back(m_Domain[i]);
                    }
                    
                    int *parentComb = new int [discParents.size()];
                    
                    intVector pObsNodes;
                    pConstValueVector pObsValues;
                    pConstNodeTypeVector pNodeTypes;
                    pEvidence->GetObsNodesWithValues(&pObsNodes, &pObsValues, &pNodeTypes);
                    
                    int j;
                    int location;
                    for ( j = 0; j < discParents.size(); j++)
                    {
                        location = 
                            std::find(pObsNodes.begin(), pObsNodes.end(), discParents[j]) 
                            - pObsNodes.begin();
                        parentComb[j] = pObsValues[location]->GetInt();
                    }
                    
                    const CGaussianDistribFun* resDistr = 
                        static_cast<CCondGaussianDistribFun*>(m_CorrespDistribFun)->GetDistribution(parentComb);
                    
                    CDistribFun* newResDistr = resDistr->ConvertCPDDistribFunToPot();

                    obsGauIndex.insert(obsGauIndex.end(), obsDiscreteIndex.begin(),
                        obsDiscreteIndex.end());
                    intVector gauSubDomain;
                    for( j = 0; j < m_Domain.size(); j++)
                    {
                        nt = GetModelDomain()->GetVariableType( m_Domain[j] );
                        if(!(nt->IsDiscrete()))
                            gauSubDomain.push_back(m_Domain[j]);
                    }
                    resPot = CGaussianPotential::Create( &gauSubDomain.front(), 
                        gauSubDomain.size(), GetModelDomain());
                    resPot->SetDistribFun( newResDistr );
                    delete newResDistr;
                    delete [] parentComb;
                }
                else
                {
                   //can enter discrete evidence first if all continuous nodes observed
                   //need to check if all them observed!
                    CCondGaussianDistribFun* withDiscrEv =
                        (static_cast<CCondGaussianDistribFun*>(m_CorrespDistribFun))->
                        EnterDiscreteEvidence(obsDiscreteIndex.size(),
                        &obsDiscreteIndex.front(), &obsDiscrVals.front(),
                        pMD->GetObsTabVarType() );
                    //need to enter continuous evidence
                    CTabularDistribFun* resDistr = withDiscrEv->
                        EnterFullContinuousEvidence( obsGauIndex.size(),
                        &obsGauIndex.front(), obsSelfVal, &obsGauVals.front(),
                        pMD->GetObsGauVarType() );
                    //need to unite gaussian and tabular observed index
                    obsDiscreteIndex.insert(obsDiscreteIndex.end(), obsGauIndex.begin(),
                        obsGauIndex.end());
                    //child node is observed
                    obsDiscreteIndex.insert(obsDiscreteIndex.end(), domSize-1);
                    resPot = CTabularPotential::Create(
                        &m_Domain.front(), m_Domain.size(), GetModelDomain(), NULL,
                        obsDiscreteIndex );
                    resPot->SetDistribFun( resDistr );
                    delete withDiscrEv;
                    delete resDistr;
                }
            }
        }
        delete obsSelfVal;
        for( i = 0; i < obsGauVals.size(); i++ )
        {
            delete obsGauVals[i];
        }
        return resPot;
    }
}
void CJtreeInfEngine::PropagateBetweenClqs(int source, int sink, bool isCollect)
{
    PNL_CHECK_RANGES( source, 0, m_pJTree->GetNumberOfNodes() - 1 );
    PNL_CHECK_RANGES( sink,   0, m_pJTree->GetNumberOfNodes() - 1 );

    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 ");
    }

    bool isDense = true;
    if(!m_pJTree->GetNodeType(source)->IsDiscrete() || !m_pJTree->GetNodeType(sink)->IsDiscrete())
    {
	isDense = false;
    }
    CPotential *potSource = m_pJTree->GetNodePotential(source),
	*potSink   = m_pJTree->GetNodePotential(sink);

    if(potSource->IsSparse() || potSink->IsSparse())
    {
	isDense = false;
    }

    // check that nodes source and sink are discrete
    if(isDense && !m_bMaximize)
    {
	pnl::CNumericDenseMatrix< float > *sorceMatrix, *sepMatrix, *sinkMatrix;
	int *dims_to_keep, *dims_to_mul;
	int num_dims_to_keep, num_dims_to_mul;

	if (GetDataForMargAndMult(source, sink, &sorceMatrix, &dims_to_keep,
	    num_dims_to_keep, &sepMatrix, &sinkMatrix, &dims_to_mul, num_dims_to_mul))
	{
	    DoPropagate(sorceMatrix, dims_to_keep,
		num_dims_to_keep, sepMatrix, sinkMatrix, dims_to_mul, num_dims_to_mul, isCollect);
	    delete [] dims_to_keep;
	    delete [] dims_to_mul;
	}
	else
	{
	    CPotential *potSink = m_pJTree->GetNodePotential(sink);
	    potSink->Normalize();
	}
    }
    else
    {
	int       numNdsInSepDom;
	const int *sepDom;

	int       numNdsInSDom;
	const int *sDom;
	potSource->GetDomain( &numNdsInSDom, &sDom );
	CPotential *potSep    = m_pJTree->GetSeparatorPotential( source, sink );

	CPotential *newPotSep, *updateRatio;

	potSep->GetDomain( &numNdsInSepDom, &sepDom );

	newPotSep = potSource->Marginalize( sepDom, numNdsInSepDom, m_bMaximize );

	updateRatio = newPotSep->Divide(potSep);

	*potSink *= *updateRatio;

	potSink->Normalize();

	potSep->SetDistribFun(newPotSep->GetDistribFun());

	delete newPotSep;
	delete updateRatio;
    }
}