void CGaussianCPD::UpdateStatisticsEM( const CPotential *pMargPot,
		                     const CEvidence *pEvidence )
{
    if( !pMargPot )
    {
	PNL_THROW( CNULLPointer, "evidences" )//no corresp evidences
    }

    intVector obsPos;
    pMargPot->GetObsPositions(&obsPos);

    if( obsPos.size() && (this->GetDistribFun()->GetDistributionType() != dtCondGaussian) )
    {
	PNL_CHECK_IS_NULL_POINTER(pEvidence);
	CPotential *pExpandPot = pMargPot->ExpandObservedNodes(pEvidence, 0);
	m_CorrespDistribFun->UpdateStatisticsEM(pExpandPot->GetDistribFun(), pEvidence, 1.0f,
	    &m_Domain.front());
	delete pExpandPot;
    }
    else
    {
	m_CorrespDistribFun->UpdateStatisticsEM( pMargPot->GetDistribFun(), pEvidence, 1.0f,
	    &m_Domain.front() );
    }

}
float CJtreeInfEngine::GetLogLik() const
{
    if( m_norm == -1.0f )
    {
	PNL_THROW( CInvalidOperation, " can't call GetLogLik before calling inferences procedure collect" );
    }

    //////////////////////////////////////////////////////////////////////////
    float ll = 0.0f;

    intVector obsDomains;
    GetObservedDomains(m_pEvidence, &obsDomains);
    const CStaticGraphicalModel *pGrModel = GetModel();

    int i;
    for( i = 0; i < obsDomains.size(); i++ )
    {
	ll += pGrModel->GetFactor(obsDomains[i])->GetLogLik(m_pEvidence);
    }

    CPotential *pPot;
    int root = GetJTreeRootNode();
    pPot=m_pJTree->GetNodePotential(root);
    if( pPot->GetDistribFun()->GetDistributionType() == dtGaussian )
    {
	CGaussianDistribFun *pDistr = static_cast<CGaussianDistribFun *>(pPot->GetDistribFun());
	pDistr->UpdateMomentForm();
	float koeff = pDistr->GetCoefficient(0);
	ll += (float)log( koeff );
    }
    else
    {
	ll += m_norm < FLT_EPSILON ? (float)log( FLT_EPSILON ) : (float)log( m_norm );
    }

    return ll;
}
void CJtreeInfEngine::
DivideJTreeNodePotByDistribFun( int clqPotNum, const int *domain,
			       const CDistribFun *pDistrFun )
{
    // bad-args check
    PNL_CHECK_RANGES( clqPotNum, 0, m_pJTree->GetNumberOfNodes() - 1 );
    PNL_CHECK_IS_NULL_POINTER(domain);
    PNL_CHECK_IS_NULL_POINTER(pDistrFun);
    // bad-args check end

    CPotential *pNodePot = m_pJTree->GetNodePotential(clqPotNum);

    int       nodePotDomSz;
    const int *nodePotDomain;

    pNodePot->GetDomain( &nodePotDomSz, &nodePotDomain );

    pNodePot->GetDistribFun()->DivideInSelfData( nodePotDomain, domain,
	pDistrFun );
}
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;
}
//-----------------------------------------------------------------------------
CPotential* CSoftMaxCPD::ConvertWithEvidenceToGaussianPotential(
    const CEvidence* pEvidence,
    floatVector MeanContParents, 
    C2DNumericDenseMatrix<float>* CovContParents,
    const int *parentIndices,
    int flagSumOnMixtureNode ) const
{
    int SoftMaxSize = GetSoftMaxSize();
    if (SoftMaxSize != 2)
    {
        PNL_THROW(CNotImplemented, "It is not sigmoid");
    }
    else
    {
        if (m_CorrespDistribFun->GetDistributionType() == dtSoftMax)
        {
            CPotential* pot = ConvertToGaussianPotential(pEvidence, 
                m_CorrespDistribFun, MeanContParents, CovContParents);

            CPotential *pot2 = NULL;

            int domSize = pot->GetDomainSize();
            bool IsAllContUnobserved = true;
            const pConstNodeTypeVector* ntVec = pot->GetDistribFun()->GetNodeTypesVector();
            for( int i = 0; i < domSize-1; i++  )    
            {
              intVector Domain;
              pot->GetDomain(&Domain);
              int curNode =  Domain[i];
              if( (pEvidence->IsNodeObserved(curNode)))
              {
                if( !(*ntVec)[i]->IsDiscrete() )
                {
                  IsAllContUnobserved = false;
                }
              }
            }

            if ((pot->GetDomainSize() >= 3)&&(!IsAllContUnobserved))
            {
              pot2 = pot->ShrinkObservedNodes(pEvidence);
            }
            else
            {
              intVector Domain;
              pot->GetDomain(&Domain);
              pot2 = pot->Marginalize(&(Domain[0]), 1);
            }
            delete pot;
            return pot2;
        }
        else //it means m_CorrespDistribFun->GetDistributionType == dtCondSoftMax
        {
            int i;
            const CSoftMaxDistribFun* dtSM;

            dtSM = 
                static_cast<CCondSoftMaxDistribFun*>(m_CorrespDistribFun)->
                GetDistribution(parentIndices);
            
            intVector pObsNodes;
            pConstValueVector pObsValues;
            pConstNodeTypeVector pNodeTypes;
            pEvidence->GetObsNodesWithValues(&pObsNodes, &pObsValues, &pNodeTypes);
            
            int r = -1;
            for (i = 0; i < pObsNodes.size(); i++)
            {
                if (m_Domain[m_Domain.size()-1] == pObsNodes[i])
                {
                    r = pObsValues[i]->GetInt();
                    break;
                }
            }
            if (r == -1)
            {
                PNL_THROW(CNotImplemented, "Not exist evidence");
            }
            
            CDistribFun *gauFactData = const_cast<CSoftMaxDistribFun*>(dtSM)->
                ConvertCPDDistribFunToPotential(MeanContParents, CovContParents, r);
            
            intVector gauSubDomain;
            const CNodeType *nt;
            for(i = 0; i < m_Domain.size(); i++)
            {
                nt = GetModelDomain()->GetVariableType( m_Domain[i] );
                if(!(nt->IsDiscrete()))
                {
                    gauSubDomain.push_back(m_Domain[i]);
                }
            }
            
            intVector obsIndex;
            for( i = 0; i < gauSubDomain.size(); i++ )
            {
                if( pEvidence->IsNodeObserved(gauSubDomain[i]) )
                {
                    obsIndex.push_back( i );
                }
            }
            
            CGaussianPotential *resFactor = CGaussianPotential::Create(&gauSubDomain.front(), 
                gauSubDomain.size(), GetModelDomain());
            
            resFactor->SetDistribFun( gauFactData );


            CPotential *pot = NULL;

            int domSize = resFactor->GetDomainSize();
            bool IsAllContUnobserved = true;
            const pConstNodeTypeVector* ntVec = resFactor->GetDistribFun()->GetNodeTypesVector();
            for( i = 0; i < domSize-1; i++  )    
            {
              intVector Domain;
              resFactor->GetDomain(&Domain);
              int curNode =  Domain[i];
              if( (pEvidence->IsNodeObserved(curNode)))
              {
                if( !(*ntVec)[i]->IsDiscrete() )
                {
                  IsAllContUnobserved = false;
                }
              }
            }
            if ((resFactor->GetDomainSize() >= 3)&&(!IsAllContUnobserved))
            {
              pot = resFactor->ShrinkObservedNodes(pEvidence);
            }
            else
            {
              intVector Domain;
              resFactor->GetDomain(&Domain);
              pot = resFactor->Marginalize(&(Domain[0]), 1);
            }
            delete resFactor;
            
            delete gauFactData;
            return pot;
            
        }
    }
}
bool pnl::EqualResults(CJtreeInfEngine& eng1, CJtreeInfEngine& eng2,
		       float epsilon, int doPrint, int doFile, float *maxDiff)
{
    CJunctionTree *JTree1, *JTree2;
    JTree1 = eng1.GetJTree();
    JTree2 = eng2.GetJTree();
    int NumOfNds1 = JTree1->GetNumberOfNodes();
    int NumOfNds2 = JTree2->GetNumberOfNodes();
    int numOfNdsInClq;
    const int *clique;
    const floatVector *myVector;
    int node;

#if 0
    FILE *out;
    if (doFile)
    {
	out = fopen( "jtree1.out", "w" );

	for(node = 0; node < NumOfNds1; node++)
	{
	    JTree1->GetNodeContent(node, &numOfNdsInClq, &clique);
	    fprintf(out, "Nodes of clique %d :\n", node);
	    for (int i = 0; i < numOfNdsInClq; i++)
		fprintf(out, "%d   ", clique[i]);
	    CMatrix<float>* mat = NULL;
	    CPotential* p = JTree1->GetNodePotential(node);
	    mat = p->GetDistribFun()->GetMatrix(matTable);
	    CNumericDenseMatrix<float>* myMatrix = 
		static_cast<CNumericDenseMatrix<float>*>(mat->ConvertToDense());
	    fprintf(out,"\nMatrix of potential of clique %d:\n", node);
	    myVector = (myMatrix)->GetVector();
	    for(int j = 0; j < myVector->size(); j++)
	    {
		fprintf(out,"%f   ",(*myVector)[j]);
	    }
	    fprintf(out,"\n\n");
	}
	fclose( out );

	out = fopen( "jtree2.out", "w" );

	for(node = 0; node < NumOfNds2; node++)
	{
	    JTree2->GetNodeContent(node, &numOfNdsInClq, &clique);
	    fprintf(out, "Nodes of clique %d :\n", node);
	    for (int i = 0; i < numOfNdsInClq; i++)
		fprintf(out, "%d   ", clique[i]);
	    CMatrix<float>* mat = JTree2->GetNodePotential(node)->
		GetDistribFun()->GetMatrix(matTable);
	    CNumericDenseMatrix<float>* myMatrix = 
		static_cast<CNumericDenseMatrix<float>*>(mat->ConvertToDense());
	    fprintf(out,"\nMatrix of potential of clique %d:\n", node);
	    const floatVector *myVector = (myMatrix)->GetVector();
	    for(int j = 0; j < myVector->size(); j++)
	    {
		fprintf(out,"%f   ",(*myVector)[j]);
	    }
	    fprintf(out,"\n\n");
	}
	fclose( out );
    }
#endif

    bool res = 1;
    if (NumOfNds1 != NumOfNds2) 
	res = 0;
    CDistribFun* distrib1;
    if (maxDiff)
    {
	*maxDiff = 0;
    }
    float maxDifference;
    for(node = 0; node < NumOfNds1; node++)
    {
	distrib1 = JTree1->GetNodePotential(node)->GetDistribFun();
	if (!(distrib1->IsEqual(JTree2->GetNodePotential(node)->
	    GetDistribFun(), epsilon, 1, &maxDifference)))
	{
	    res = 0;
	    if (maxDiff && (*maxDiff < maxDifference))
	    {
		*maxDiff = maxDifference;
	    }
#if 0
	    if (doPrint) 
		printf("clique %d:  notOK  maxDiff = %.6f\n", node, maxDifference);
#endif
	}
	else
	{
#if 0
	    if (doPrint)
		printf("clique %d:  OK\n", node);
#endif
	}
    }
    return res;
}