//------------------------------------------------------------------------------
CPotential* CSoftMaxCPD::ConvertWithEvidenceToTabularPotential(
    const CEvidence* pEvidence, int flagSumOnMixtureNode ) const
{
    //need to convert to potential and after that add evidence
    CPotential* potWithoutEv = ConvertToTabularPotential(pEvidence);
    CPotential* potWithEvid = potWithoutEv->ShrinkObservedNodes(pEvidence);
    delete potWithoutEv;
    return potWithEvid;
}
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;
    }
}
//-----------------------------------------------------------------------------
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;
            
        }
    }
}