/*
    Copyright (C) 2011 Brendon J. Brewer
    This file is part of DNest, the Diffusive Nested Sampler.

    DNest is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    DNest is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with DNest.  If not, see <http://www.gnu.org/licenses/>.
*/


#include "Model.h"
#include "RandomNumberGenerator.h"
#include "Utils.h"
#include <cmath>
#include <iostream>

using namespace std;
namespace DNest
{

	Model::~Model()
	{
	}

	void Model::fromPrior()
	{
		logl.tieBreaker = randomU();
	}

	double Model::perturb()
	{
		double logHastings = 0;
		logl.tieBreaker += pow(10.0, 1.0 - 6*randomU());
		logl.tieBreaker = mod(logl.tieBreaker, 1.0);
		return logHastings;
	}

	void Model::update()
	{
		Model* proposal = this->clone();
		double logH = proposal->perturb();
		if(proposal->logl.tieBreaker == this->logl.tieBreaker)
			cerr<<"# WARNING: tieBreaker unchanged."<<endl;

		double logPAccept = logH + proposal->logl.logl - logl.logl;
		if(logPAccept > 0.0)
			logPAccept = 0.0;
		if(randomU() <= exp(logPAccept))
			this->copyFrom(proposal);

		delete proposal;
	}

	bool Model::update(const LikelihoodType& cutoff)
	{
		bool accepted = false;

		Model* proposal = this->clone();
		double logH = proposal->perturb();
		if(proposal->logl.tieBreaker == this->logl.tieBreaker)
			cerr<<"# WARNING: tieBreaker unchanged."<<endl;

		if(logH > 0.0)
			logH = 0.0;
		if(randomU() <= exp(logH) && cutoff < proposal->logl)
		{
			this->copyFrom(proposal);
			accepted = true;
		}
		delete proposal;

		return accepted;
	}

	void Model::explore(const LikelihoodType& cutoff, int numSteps)
	{
		for(int i=0; i<numSteps; i++)
			update(cutoff);
	}

	void Model::print(ostream& out) const
	{
		out<<' ';
	}

	LikelihoodType Model::getLogLikelihood() const
	{
		return logl;
	}
}

