// Copyright 2014 BVLC and contributors.

#include <algorithm>
#include <cmath>
#include <cfloat>
#include <vector>
#include <fstream>

#include "caffe/layer.hpp"
#include "caffe/vision_layers.hpp"
#include "caffe/util/math_functions.hpp"
#include "caffe/util/io.hpp"

using std::max;
using namespace std;

namespace caffe {

template <typename Dtype>
void SoftHingeLossLayer<Dtype>::FurtherSetUp(
  const vector<Blob<Dtype>*>& bottom, vector<Blob<Dtype>*>* top) {
  LOG(INFO) << "bottom[0]->num():" << bottom[0]->num() << ", bottom[0]->channels():" << bottom[0]->channels()
		  << ", bottom[0]->height():" << bottom[0]->height() << ", bottom[0]->width():" << bottom[0]->width();
  M_ = bottom[0]->num();
}

template <typename Dtype>
void SoftHingeLossLayer<Dtype>::Forward_cpu(const vector<Blob<Dtype>*>& bottom,
    vector<Blob<Dtype>*>* top) {
  int count = bottom[0]->count();
  const Dtype* dist_data = bottom[0]->cpu_data();
  const Dtype* label = bottom[1]->cpu_data();
  //const Dtype* label2 = bottom[2]->cpu_data();
  //Dtype* bottom_data = (*bottom)[0]->mutable_cpu_diff();
  Dtype loss=0;
  M_ = bottom[0]->num();
  for (int i=0;i<M_;i++){
	  //CHECK_EQ(label[i],label2[i]);
	  Dtype dloss=0;
	  //if (i%10==0)
	  //{
	//	  LOG(INFO) << "distance:" << dist_data[i];
	 // }
	  //dloss=log(1+exp(dist_data[i]*label[i]));
	  if (dist_data[i]*label[i]>20)
	  {
		  dloss=dist_data[i]*label[i];
	  }else{
		  dloss=log(1+exp(dist_data[i]*label[i]));
	  }
	  //if (i%10==0)
	  //{
	//	  LOG(INFO) << "dloss[" << i << "]=" << dloss << ",dist=" << dist_data[i] << ",label=" << label[i];
	 // }
	  loss=loss+dloss;
  }
  (*top)[0]->mutable_cpu_data()[0] = loss;
}

template <typename Dtype>
void SoftHingeLossLayer<Dtype>::Backward_cpu(const vector<Blob<Dtype>*>& top,
		const vector<bool>& propagate_down, vector<Blob<Dtype>*>* bottom) {
	const Dtype* label=(*bottom)[1]->cpu_data();
	//const Dtype* label2 = (*bottom)[2]->cpu_data();
	Dtype* bottom_diff=(*bottom)[0]->mutable_cpu_diff();
	const Dtype* dist_data=(*bottom)[0]->cpu_data();
	for (int i=0;i<M_;i++){
		Dtype scales=1-1/(1+exp(label[i]*dist_data[i]));
		//CHECK_EQ(label[i],label2[i]);
		scales=scales*label[i];
		//if (i%400==0)
		//{
		//	LOG(INFO) << "diff_distance:" << dist_data[i] << ", label:" << label[i] << ", label2:" << label2[i] << ", scales:" << scales;
		//}
		bottom_diff[i]=scales;
	}
}

INSTANTIATE_CLASS(SoftHingeLossLayer);

}  // namespace caffe
