// Copyright 2014 BVLC and contributors.

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

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

using std::max;

namespace caffe {

template <typename Dtype>
void PairDataLayer<Dtype>::LayerSetUp(
  const vector<Blob<Dtype>*>& bottom, vector<Blob<Dtype>*>* top) {
	/*CHECK_EQ(bottom[0]->num(), bottom[1]->num())
		      << "The data and label should have the same number.";*/
}

template <typename Dtype>
void PairDataLayer<Dtype>::Reshape(const vector<Blob<Dtype>*>& bottom,
      vector<Blob<Dtype>*>* top) {
	int N=bottom.size();
	for (int i=0;i<N-1;i++) {
		(*top)[i]->Reshape(bottom[i]->num(), bottom[N-1]->channels(), bottom[N-1]->height(), bottom[N-1]->width());//data1;
	}
}

template <typename Dtype>
void PairDataLayer<Dtype>::Forward_cpu(const vector<Blob<Dtype>*>& bottom,
    vector<Blob<Dtype>*>* top) {
	int N=bottom.size();
	int dim=bottom[N-1]->count()/bottom[N-1]->num();
	const Dtype* bottom_data=bottom[N-1]->cpu_data();
	for (int i=0;i<bottom.size()-1;i++) {
		const Dtype* pairlabel=bottom[i]->cpu_data();
		Dtype* top_data=(*top)[i]->mutable_cpu_data();
		for (int j=0;j<(*top)[i]->num();j++) {
			caffe_copy(dim, bottom_data+bottom[N-1]->offset(int(pairlabel[j])), top_data+(*top)[i]->offset(j));;
		}
	}
}

template <typename Dtype>
void PairDataLayer<Dtype>::Backward_cpu(const vector<Blob<Dtype>*>& top,
		const vector<bool>& propagate_down, vector<Blob<Dtype>*>* bottom) {
	int N=bottom->size();
	int dim=(*bottom)[N-1]->count()/(*bottom)[N-1]->num();
		Dtype* bottom_diff=(*bottom)[N-1]->mutable_cpu_diff();
		caffe_set((*bottom)[N-1]->count(), Dtype(0), bottom_diff);
		for (int i=0;i<top.size();i++) {
			const Dtype* pairlabel=(*bottom)[i]->cpu_data();
			const Dtype* top_diff=top[i]->cpu_diff();
			for (int j=0;j<top[i]->num();j++) {
				caffe_axpy(dim, Dtype(1), top_diff+top[i]->offset(j), bottom_diff+(*bottom)[N-1]->offset(int(pairlabel[j])));;
			}
		}
}

#ifdef CPU_ONLY
STUB_GPU(PairDataLayer);
#endif

INSTANTIATE_CLASS(PairDataLayer);

}  // namespace caffe
