/*
hCRF-light Library 1.0 (full version http://hcrf.sf.net)
Copyright (C) 2012 Yale Song (yalesong@mit.edu)

This program 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.

This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef GRADIENT_H
#define GRADIENT_H

#include <vector>
#include <assert.h>

#include "dataset.h"
#include "model.h"
#include "inferenceengine.h"
#include "featuregenerator.h"
#include "evaluator.h"

#ifdef _OPENMP
#include <omp.h>
#endif

class Gradient {
  public:
    Gradient(InferenceEngine* infEngine, FeatureGenerator* featureGen);
    Gradient(const Gradient&);
    Gradient& operator=(const Gradient&);
    virtual double computeGradient(dVector& vecGradient, Model* m, 
                                 DataSequence* X, bool bComputeMaxMargin=false) = 0;
    virtual double computeGradient(dVector& vecGradient, Model* m, 
                                 DataSet* X, bool bComputeMaxMargin=false);
    virtual ~Gradient();
	virtual void setMaxNumberThreads(int maxThreads);
	void setInferenceEngine(InferenceEngine* inEngine){pInfEngine = inEngine;}

  protected:
    InferenceEngine* pInfEngine;
    FeatureGenerator* pFeatureGen;
	featureVector *vecFeaturesMP;
	dVector *localGrads;
	int nbThreadsMP;
};
 
class GradientHCRF : public Gradient 
{
  public:
    GradientHCRF(InferenceEngine* infEngine, FeatureGenerator* featureGen);
    double computeGradient(dVector& vecGradient, Model* m, DataSequence* X, bool bComputeMaxMargin=false);
    using Gradient::computeGradient;
private:
	double computeGradientMLE(dVector& vecGradient, Model* m, DataSequence* X);
	double computeGradientMaxMargin(dVector& vecGradient, Model* m, DataSequence* X);
};

class GradientLDCRF : public Gradient 
{
  public:
    GradientLDCRF(InferenceEngine* infEngine, FeatureGenerator* featureGen);
    double computeGradient(dVector& vecGradient, Model* m, DataSequence* X, bool bComputeMaxMargin=false);
}; 

class GradientMVHCRF: public Gradient
{
public:
    GradientMVHCRF(InferenceEngine* infEngine, FeatureGenerator* featureGen);
    double computeGradient(dVector& vecGradient, Model* m, DataSequence* X, bool bComputeMaxMargin=false);
    using Gradient::computeGradient;

private:
	double computeGradientMLE(dVector& vecGradient, Model* m, DataSequence* X); 
};

class GradientMVLDCRF: public Gradient
{
public:
    GradientMVLDCRF(InferenceEngine* infEngine, FeatureGenerator* featureGen);
    double computeGradient(dVector& vecGradient, Model* m, DataSequence* X, bool bComputeMaxMargin=false);
    using Gradient::computeGradient;
private:
	double computeGradientMLE(dVector& vecGradient, Model* m, DataSequence* X); 
};
 
#endif
