/*
        Create a simple Bayesian Network and use Learning method.
        Alvaro Marin - alvaro@rigel.deusto.es
        Abril 2005.     
*/

#include "stdio.h"
#include "pnl_dll.hpp"
#include "cvsvd.h"

PNL_USING

void printBayesianNetwork( CBNet *netbay )
{
                
        const CFactor *pCPD;
        const CNumericDenseMatrix *pMatForCPD;
        const float *dataCPD;
        int numOfEl; 
        int f; 

        // Get information from learned model (number of factors)
        int nFactors = netbay->GetNumberOfFactors();
  
        for( f = 0; f < nFactors; f++ )
        {
                std::cout<GetFactor(f);
                pMatForCPD = static_cast *>(pCPD->GetMatrix(matTable));
                pMatForCPD->GetRawData( &numOfEl, &dataCPD );
                int j;
                for( j = 0; j < numOfEl; j++ )
                {
                        std::cout<<" "<AddNodes(numOfNds);
	pGraph->AddEdge(0,1,1);
	pGraph->AddEdge(0,2,1);
	pGraph->AddEdge(1,3,1);
	pGraph->AddEdge(2,3,1);
	
	pGraph->Dump();

	CNodeType *nodeTypes = new CNodeType [4];
	nodeTypes[0].SetType(1, 2);
	nodeTypes[1].SetType(1, 2);
	nodeTypes[2].SetType(1, 2);
	nodeTypes[3].SetType(1, 2);
	
	int *nodeAssociation = new int[numOfNds];
	for ( int i = 0; i < numOfNds; i++ )
    	{
        	nodeAssociation[i] = i;
    	}

	CBNet *pBNet;
	try{
		pBNet = CBNet::Create( numOfNds, numOfNds /*NumOfNodeTypes*/, nodeTypes, nodeAssociation, pGraph );
	}
	catch (pnl::CException ex)
  	{
		printf("[PNL] EXCEPTION %d: %s\n",ex.GetCode(),ex.GetMessage());
  	}	

	float table0[] = { 0.5f, 0.5f }; 
	float table1[] = { 0.5f, 0.5f }; 
	float table2[] = { 0.5f, 0.5f }; 
	float table3[] = { 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f };
	
	float* table[] = { table0, table1, table2, table3 }; 
		
	// Factor == CPD == Celda. Vamos alojando los CPD (Conditional Probabilistic Distribution) en cada Factor
	for( int i = 0; i < numOfNds; ++i ) 
	{ 
		pBNet->AllocFactor(i); 
		CFactor* pFactor = pBNet->GetFactor(i); 
		pFactor->AllocMatrix( table[i], matTable );			
	}

	printf("\n[PNL] pBNet created.\n");
	printBayesianNetwork(pBNet);
	
	getchar();

	return pBNet;
}




int learnProcedureFromArchive(CBNet *pBNetAux){

	// Create the evidences vector
	pEvidencesVector evVec;		

	CEMLearningEngine *pLearn;
	CModelDomain *pMD;
	
	pMD = pBNetAux->GetModelDomain();
	
	// Create learning engine. EM algorithm
  	pLearn = CEMLearningEngine::Create( pBNetAux );

	// Loading data from file 
  	const char * fname = "bayesian.data";
    
	if( ! CEvidence::Load(fname,  &evVec, pMD) )
  	{
  		printf("[PNL] ERROR. Can't open file with cases.\n");
	  	return 1;
  	}
	else
		printf("[PNL] File with cases loaded.\n");
	
	
	int numOfSamples = evVec.size();
  	std::cout<<"[PNL] Number of cases for learning = "< SetData only the first time! then, use AppendData ;)
  		pLearn->SetData( numOfSamples, &evVec.front() );
  		pLearn->Learn();
	}		
  	catch (pnl::CException ex)
  	{
		printf("[PNL] EXCEPTION %d: %s\n",ex.GetCode(),ex.GetMessage());
  	}		
    
	printBayesianNetwork(pBNetAux);
		  
  
	int ev;
	for( ev = 0; ev < evVec.size(); ev++ )
  	{
		delete (evVec[ev]);
 	}
 
	printf("[PNL] Learning process from archive completed.\n");

	return 0;
}



int main(int argc, char* argv[])
{
	
	printf("\n\nProceso de Inferencia.\n\nCrearemos la siguiente red bayesiana:\n\n");
	printf("    0\n   / \\\n  1   2\n   \\ / \n    3 \n\n");
	getchar();
	CBNet *pBNetAux=createBNet();
	learnProcedureFromArchive(pBNetAux);
	return 0;

}