/*!
 *  \brief Insert a nes set of primitives in the super set.
 *  \param inPrimitiveSet Inserted primitive set.
 */
void GP::PrimitiveSuperSet::insert(GP::PrimitiveSet::Handle inPrimitiveSet, bool inReplace)
{
	Beagle_StackTraceBeginM();
	mPrimitSets.push_back(inPrimitiveSet);
	for(unsigned int i=0; i<inPrimitiveSet->size(); ++i) addPrimitive((*inPrimitiveSet)[i], inReplace);
	Beagle_StackTraceEndM("void GP::PrimitiveSuperSet::insert(GP::PrimitiveSet::Handle inPrimitiveSet)");
}
/*!
 *  \brief Main routine for the function symbolic regression problem.
 *  \param argc Number of arguments on the command-line.
 *  \param argv Arguments on the command-line.
 *  \return Return value of the program.
 *  \ingroup SymbReg
 */
int main(int argc, char *argv[]) {
	try {
		// 1: Build primitives.
		GP::PrimitiveSet::Handle lSet = new GP::PrimitiveSet;
		lSet->insert(new GP::Add);
		lSet->insert(new GP::Subtract);
		lSet->insert(new GP::Multiply);
		lSet->insert(new GP::Divide);
		//lSet->insert(new GP::Sin);
		//lSet->insert(new GP::Cos);
		//lSet->insert(new GP::Exp);
		//lSet->insert(new GP::Log);
		lSet->insert(new GP::TokenT<Double>("X"));
		//lSet->insert(new GP::TokenT<Double>("Pi", Double(M_PI)));
		//lSet->insert(new GP::EphemeralDouble);
		// 2: Build a system.
		GP::System::Handle lSystem = new GP::System(lSet);
		// 3: Build evaluation operator.
		SymbRegEvalOp::Handle lEvalOp = new SymbRegEvalOp;
		// 4: Build an evolver and a vivarium.
#ifdef WITHOUT_MPI
		GP::Evolver::Handle lEvolver = new GP::Evolver(lEvalOp);
#else
		MPI::GP::Evolver::Handle lEvolver = new MPI::GP::Evolver(lEvalOp);
#endif
		GP::Vivarium::Handle lVivarium = new GP::Vivarium;
		// 5: Initialize and evolve the vivarium.
		lEvolver->initialize(lSystem, argc, argv);
		lEvolver->evolve(lVivarium);
	}
	catch(Exception& inException) {
		inException.terminate();
	}
	catch(exception& inException) {
		cerr << "Standard exception catched:" << endl;
		cerr << inException.what() << endl << flush;
		return 1;
	}
	catch(...) {
		cerr << "Unknown exception catched!" << endl << flush;
		return 1;
	}
	return 0;
}
/*!
 *  \brief Read a primitive super set from a XML subtree.
 *  \param inIter XML iterator used to read the super set from.
 *  \param ioSystem Evolutionary system.
 *  \throw Beagle::IOException If size atribute not present.
 */
void GP::PrimitiveSuperSet::readWithSystem(PACC::XML::ConstIterator inIter, Beagle::System& ioSystem)
{
	Beagle_StackTraceBeginM();
	if((inIter->getType()!=PACC::XML::eData) || (inIter->getValue()!="GP-PrimitiveSuperSet"))
		throw Beagle_IOExceptionNodeM(*inIter, "tag <GP-PrimitiveSuperSet> expected!");
	const Factory& lFactory = ioSystem.getFactory();
	Context::Alloc::Handle lContextAlloc =
	    castHandleT<Context::Alloc>(lFactory.getConceptAllocator("Context"));
	GP::Context::Handle lGPContext =
	    castHandleT<GP::Context>(lContextAlloc->allocate());
	lGPContext->setSystemHandle(System::Handle(&ioSystem));
	GP::PrimitiveSet::Alloc::Handle lPrimitSetsAlloc =
		castHandleT<GP::PrimitiveSet::Alloc>(lFactory.getConceptAllocator("GP-PrimitiveSet"));
	mPrimitSets.clear();
	for(PACC::XML::ConstIterator lChild=inIter->getFirstChild(); lChild; ++lChild) {
		if((lChild->getType()==PACC::XML::eData) && (lChild->getValue()=="GP-PrimitiveSet")) {
			GP::PrimitiveSet::Handle lPrimitSet =
				castHandleT<GP::PrimitiveSet>(lPrimitSetsAlloc->allocate());
			lPrimitSet->readWithContext(lChild, *lGPContext);
			mPrimitSets.push_back(lPrimitSet);
		}
	}
	Beagle_StackTraceEndM("void GP::PrimitiveSuperSet::readWithSystem(PACC::XML::ConstIterator inIter, Beagle::System& ioSystem)");
}
/*!
 *  \brief Main routine for the even-6 parity problem.
 *  \param argc Number of arguments on the command-line.
 *  \param argv Arguments on the command-line.
 *  \return Return value of the program.
 *  \ingroup Parity
 */
int main(int argc, char *argv[])
{
	try {

		// Build primitives
		GP::PrimitiveSuperSet::Handle lSuperSet = new GP::PrimitiveSuperSet;
		lSuperSet->addPrimitive(new GP::BitwiseAnd("AND"), true);
		lSuperSet->addPrimitive(new GP::BitwiseOr("OR"), true);
		lSuperSet->addPrimitive(new GP::BitwiseNand("NAND"), true);
		lSuperSet->addPrimitive(new GP::BitwiseNor("NOR"), true);
		lSuperSet->addPrimitive(new GP::BitwiseNot("NOT"), true);
		lSuperSet->addPrimitive(new GP::BitwiseXor("XOR"), true);
		lSuperSet->addPrimitive(new GP::ADF(GP::Invoker::eGenerator, GP::Primitive::eAny, "ADFP", "ARGP"));
		lSuperSet->addPrimitive(new GP::ArgumentT<Int>(GP::Argument::eCaching, GP::Argument::eGenerator, "ARGP"));
		GP::PrimitiveSet::Handle lSet = new GP::PrimitiveSet;
		lSet->insert(new GP::BitwiseAnd("AND"));
		lSet->insert(new GP::BitwiseOr("OR"));
		lSet->insert(new GP::BitwiseNand("NAND"));
		lSet->insert(new GP::BitwiseNor("NOR"));
		for (unsigned int i=0; i<ParitySizeM; i++) {
			lSet->insert(new GP::TokenT<Int>(std::string("IN")+uint2str(i)));
		}
		lSuperSet->insert(lSet);

		// Build a system
		System::Handle lSystem = new System;

		// Set GP package
		lSystem->addPackage(new GP::PackageBase(lSuperSet));
		lSystem->addPackage(new GP::PackageConstrained);

		// Set fitness evaluation operator allocator
		lSystem->setEvaluationOp("ParityEvalOp", new ParityFastEvalOp::Alloc);

		// Initialize the evolver
		Evolver::Handle lEvolver = new Evolver;
		lEvolver->initialize(lSystem, argc, argv);

		// Create population
		Vivarium::Handle lVivarium = new Vivarium;

		// Launch evolution
		lEvolver->evolve(lVivarium, lSystem);

	} catch(Exception& inException) {
		inException.terminate();
	} catch(exception& inException) {
		cerr << "Standard exception caught:" << endl;
		cerr << inException.what() << endl << flush;
		return 1;
	} catch(...) {
		cerr << "Unknown exception caught!" << endl << flush;
		return 1;
	}
	return 0;
}
int main(int argc, char *argv[]) {
    try {

        // 1: Build primitives.
        GP::PrimitiveSet::Handle lSet = new GP::PrimitiveSet(&(typeid(RootReturn)));

        lSet->insert(new ThreeTanksEmbryo);

        lSet->insert(new ReplaceR);
        //		lSet->insert(new ReplaceC);
        //		lSet->insert(new ReplaceI);

        lSet->insert(new AddSwitch);
        lSet->insert(new AddR);
        //		lSet->insert(new AddC);
        //		lSet->insert(new AddI);

        lSet->insert(new InsertJ01);
        lSet->insert(new InsertJ10);

        lSet->insert(new EndBond);
        //lSet->insert(new EndEph);
        lSet->insert(new EndNode);
        lSet->insert(new EndJct);

        lSet->insert(new GP::MultiplyT<Double>);
        lSet->insert(new GP::DivideT<Double>);
        lSet->insert(new GP::AddT<Double>);
        lSet->insert(new GP::SubtractT<Double>);
        lSet->insert(new GP::EphemeralDouble);


        // 2: Build a system.
        BGContext::Alloc::Handle lContextAlloc = new BGContext::Alloc;

        GP::System::Handle lSystem = new GP::System(lSet,lContextAlloc);

        // 3: Build evaluation operator.
        ThreeTanksEvalOp::Handle lEvalOp = new ThreeTanksEvalOp;

        // 4: Build an evolver and a vivarium.
        TreeSTag::Alloc::Handle lTreeAlloc = new TreeSTag::Alloc;
        //GP::Tree::Alloc::Handle lTreeAlloc = new GP::Tree::Alloc;
        BGFitness::Alloc::Handle lFitAlloc = new BGFitness::Alloc;
        GP::Vivarium::Handle lVivarium = new GP::Vivarium(lTreeAlloc,lFitAlloc);

        GP::Evolver::Handle lEvolver = new GP::Evolver(lEvalOp);
        lEvolver->initialize(lSystem, argc, argv);

        //Read individual from file
        ostringstream lFilename;
        lFilename << "individual-best153.xml";

        GP::Individual::Handle lIndividual = new GP::Individual(lTreeAlloc);
        lIndividual->readFromFile(lFilename.str(), *lSystem);

        BGContext::Handle lContext = castHandleT<BGContext>(lSystem->getContextAllocator().allocate());
        lContext->setSystemHandle(lSystem);
        lContext->setIndividualHandle(lIndividual);
        lContext->setIndividualIndex(0);

        BGFitness::Handle lFitness = castHandleT<BGFitness>(lEvalOp->evaluate(*lIndividual,*lContext));

        //TreeSTag::Handle lTree = castHandleT<TreeSTag>((*lIndividual)[0]);
        GrowingHybridBondGraph::Handle lBondGraph = castHandleT<GrowingHybridBondGraph>(lFitness->getBondGraph());
        //lBondGraph->simplify();
        lBondGraph->plotGraph("bondgraph.svg",false);

        cout << "\nResulting fitness: " << endl;
        cout << lFitness->serialize() << endl;

    }

    catch(Exception& inException) {
        inException.terminate();
    }
    catch(exception& inException) {
        cerr << "Standard exception catched:" << endl;
        cerr << inException.what() << endl << flush;
        return 1;
    }
    catch(...) {
        cerr << "Unknown exception catched!" << endl << flush;
        return 1;
    }

    return 0;
}