/*******************************************************************************
 * DIANNE  - Framework for distributed artificial neural networks
 * Copyright (C) 2015  iMinds - IBCN - UGent
 *
 * This file is part of DIANNE.
 *
 * DIANNE is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero 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 Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Contributors:
 *     Tim Verbelen, Steven Bohez
 *******************************************************************************/
package be.iminds.iot.dianne.nn.module.layer;

import java.util.UUID;

import be.iminds.iot.dianne.api.nn.module.AbstractModule;
import be.iminds.iot.dianne.tensor.Tensor;

public class Zeropad extends AbstractModule {

	private final int[] padding;
	
	public Zeropad(final int... padding){
		super();
		this.padding = padding;
	}
	
	public Zeropad(UUID id, final int... padding){
		super(id);
		this.padding = padding;
	}

	private int[] inputDims;
	private int[] ranges;
	
	@Override
	protected void forward() {
		inputDims = input.dims();
		int[] outputDims = new int[inputDims.length];
		// apply padding from back to front ... 2d padding on 3d tensor means padding the last 2 dims
		ranges = new int[outputDims.length*2];
		for(int i=0;i<outputDims.length;i++){
			int pad = padding.length > i ? padding[padding.length-1-i] : 0;
			outputDims[outputDims.length-1-i] = inputDims[outputDims.length-1-i] + 2*pad;
			
			ranges[(outputDims.length-1-i)*2] = pad;
			ranges[(outputDims.length-1-i)*2 + 1] = inputDims[outputDims.length-1-i];
		}
		if(output==null){
			output = new Tensor(outputDims);
		}
		output.reshape(outputDims);
		output.fill(0.0f);
		
		Tensor narrowed = output.narrow(ranges); 
		input.copyInto(narrowed);
	}

	@Override
	protected void backward() {
		if(gradInput == null){
			gradInput = new Tensor(inputDims);
		}
		gradInput.reshape(inputDims);
		Tensor narrowed = gradOutput.narrow(ranges);
		narrowed.copyInto(gradInput);
	}

}

@@ -1328,217 +1328,533 @@
 ;%0A%09%09
-this.padding = padding;%0A%09%7D%0A%09%0A%09public Zeropad(UUID id, final int... padding)%7B%0A%09%09super(id);%0A%09%09this.padding = padding;%0A%09%7D%0A%0A%09private int%5B%5D inputDims;%0A%09private int%5B%5D ranges;%0A%09%0A%09@Override%0A%09protected void forward() %7B
+for(int i = 0;i%3Cpadding.length;i++)%7B%0A%09%09%09if(padding%5Bi%5D!=0)%7B%0A%09%09%09%09this.padding = padding;%0A%09%09%09%09return;%0A%09%09%09%7D%0A%09%09%7D%0A%09%09this.padding = null;%0A%09%7D%0A%09%0A%09public Zeropad(UUID id, final int... padding)%7B%0A%09%09super(id);%0A%09%09for(int i = 0;i%3Cpadding.length;i++)%7B%0A%09%09%09if(padding%5Bi%5D!=0)%7B%0A%09%09%09%09this.padding = padding;%0A%09%09%09%09return;%0A%09%09%09%7D%0A%09%09%7D%0A%09%09this.padding = null;%0A%09%7D%0A%0A%09private int%5B%5D inputDims;%0A%09private int%5B%5D ranges;%0A%09%0A%09@Override%0A%09protected void forward() %7B%0A%09%09// pass through if no padding specified%0A%09%09if(padding == null)%7B%0A%09%09%09output = input;%0A%09%09%09return;%0A%09%09%7D%0A%09%09
 %0A%09%09i
@@ -2610,16 +2610,124 @@
 ard() %7B%0A
+%09%09// pass through if no padding specified%0A%09%09if(padding==null)%7B%0A%09%09%09gradInput = gradOutput;%0A%09%09%09return;%0A%09%09%7D%0A%09%09%0A
 %09%09if(gra

pass through if all padding parameters = 0