// Copyright 2014 BVLC and contributors.

#include <algorithm>
#include <vector>

#include "caffe/layer.hpp"
#include "caffe/vision_layers.hpp"

using std::min;

namespace caffe {

	const float kBNLL_THRESHOLD = 50.;

	template <typename Dtype>
	Dtype BNLLLayer<Dtype>::Forward_cpu(const vector<Blob<Dtype>*>& bottom,
		vector<Blob<Dtype>*>* top) {
			const Dtype* bottom_data = bottom[0]->cpu_data();
			Dtype* top_data = (*top)[0]->mutable_cpu_data();
			const int count = bottom[0]->count();
			for (int i = 0; i < count; ++i) {
				top_data[i] = bottom_data[i] > 0 ?
					bottom_data[i] + log(1. + exp(-bottom_data[i])) :
					log(1. + exp(bottom_data[i]));
			}
			return Dtype(0);
	}

	template <typename Dtype>
	void BNLLLayer<Dtype>::Backward_cpu(const vector<Blob<Dtype>*>& top,
		const bool propagate_down,
		vector<Blob<Dtype>*>* bottom) {
			if (propagate_down) {
				const Dtype* bottom_data = (*bottom)[0]->cpu_data();
				const Dtype* top_diff = top[0]->cpu_diff();
				Dtype* bottom_diff = (*bottom)[0]->mutable_cpu_diff();
				const int count = (*bottom)[0]->count();
				Dtype expval;
				for (int i = 0; i < count; ++i) {
					expval = exp(min(bottom_data[i], Dtype(kBNLL_THRESHOLD)));
					bottom_diff[i] = top_diff[i] * expval / (expval + 1.);
				}
			}
	}


	INSTANTIATE_CLASS(BNLLLayer);


}  // namespace caffe
