// 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>::Forward_gpu(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]->gpu_data();
	for (int i=0;i<bottom.size()-1;i++) {
		const Dtype* pairlabel=bottom[i]->cpu_data();
		Dtype* top_data=(*top)[i]->mutable_gpu_data();
		for (int j=0;j<(*top)[i]->num();j++) {
		if (pairlabel[j]>=bottom[N-1]->num()) {LOG(INFO) << pairlabel[j] << "," << bottom[N-1]->num();}
		if (j>=(*top)[i]->num()) {LOG(INFO) << j << "," << (*top)[i]->num();}
			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_gpu(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_gpu_diff();
		caffe_gpu_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]->gpu_diff();
			for (int j=0;j<top[i]->num();j++) {
				caffe_gpu_axpy(dim, Dtype(1), top_diff+top[i]->offset(j), bottom_diff+(*bottom)[N-1]->offset(int(pairlabel[j])));;
			}
		}
				/*Dtype* bottom_cpu_diff1 = (*bottom)[N-1]->mutable_cpu_diff();
		for (int i=0;i<(*bottom)[N-1]->count();i++)
		{
			bottom_cpu_diff1[i]=1;
		}*/
}

INSTANTIATE_CLASS(PairDataLayer);

}  // namespace caffe
