/*
 * Rbm.hpp
 *
 *  Created on: 21.09.2014
 *      Author: jens
 */

#ifndef RBM_HPP_
#define RBM_HPP_

#include "Weights.hpp"
#include <cmath>
#include <Eigen/Dense>

using namespace Eigen;

class Rbm
{
public:
	struct Params
	{
		Params()
		: m_weightDecay(0.0)
		, m_learningRate(0.1)
		, m_momentum(0.5)
		, m_doRaoBlackwell(true)
		, m_doSampleVisible(false)
		, m_doSampleBatch(false)
		, m_numGibbs(1)
		{
		}
		
		double m_weightDecay;
		double m_learningRate;
		double m_momentum;
		bool m_doRaoBlackwell;
		bool m_doSampleVisible;
		bool m_doSampleBatch;
		size_t m_numGibbs;
	};
	
	Rbm(Weights &weights, const MatrixXd &batch);
	~Rbm();
	MatrixXd sample(MatrixXd const &src);
	void sample(MatrixXd &dst, MatrixXd const &src);
	static MatrixXd probsLogistic(MatrixXd const &src);
	static RowVectorXd probsLogistic(RowVectorXd const &src);
	void sampleGaussian(MatrixXd &dst, MatrixXd const &src);
	void sampleGaussian(MatrixXd &srcDst);
	static MatrixXd normalizeData(MatrixXd const &src);
	void train(size_t numEpochs, size_t miniBatchSize, bool &doStop);
	double getProgress() const;
	void toHidden(RowVectorXd &h, RowVectorXd const &v);
	void toVisible(RowVectorXd &v, RowVectorXd const &h);
	void setWeightDecay(double value);
	void setDoRaoBlackwell(bool flag);
	void setDoSampleVisible(bool flag);
	void setDoSampleBatch(bool flag);
	void setNumGibbs(size_t value);
	void setMuWeights(double value);
	void setMomentum(double value);
	MatrixXd const& getHiddenBatch();
	MatrixXd const& getBatch();
	void updateHiddenBatch();
	Params const& params();
	
private:
	Weights &m_w;
	MatrixXd const &m_batch;
	MatrixXd m_h;
	noise_gen_t m_noise;
	double m_progress;
	Params m_params;
	void noiseGaussian(MatrixXd &dst);
	void noiseUniform(MatrixXd &dst);
	
protected:
	virtual void onProgressChanged()
	{
	}
	
	virtual void onParamsChanged()
	{
	}
};

#endif /* RBM_HPP_ */
