[SYSTEMML-1076] [SYSTEMML-1077] Handle empty blocks in maxpool and maxpool_backward
diff --git a/src/main/java/org/apache/sysml/hops/ConvolutionOp.java b/src/main/java/org/apache/sysml/hops/ConvolutionOp.java
index c010de6..dae2f82 100644
--- a/src/main/java/org/apache/sysml/hops/ConvolutionOp.java
+++ b/src/main/java/org/apache/sysml/hops/ConvolutionOp.java
@@ -242,7 +242,7 @@
 			case MAX_POOLING:
 			{
 				ret = new long[3];
-				ret[0] = params.N;
+				ret[0] = getInput().get(0)._dim1;
 				ret[1] = getExtractedVal(params.C, params.P, params.Q);
 				ret[2] = -1;
 				break;
@@ -250,32 +250,32 @@
 			case MAX_POOLING_BACKWARD:
 			{
 				ret = new long[3];
-				ret[0] = params.N;
-				ret[1] = getExtractedVal(params.C, params.H, params.W);
+				ret[0] = getInput().get(0)._dim1;
+				ret[1] = getInput().get(0)._dim2;
 				ret[2] = -1;
 				break;
 			}
 			case DIRECT_CONV2D:
 			{
 				ret = new long[3];
-				ret[0] = params.N;
-				ret[1] = getExtractedVal(params.K, params.P, params.Q);
+				ret[0] = getInput().get(0)._dim1;
+				ret[1] = getExtractedVal(getInput().get(1)._dim1, params.P, params.Q);
 				ret[2] = -1;
 				break;
 			}
 			case DIRECT_CONV2D_BACKWARD_FILTER:
 			{
 				ret = new long[3];
-				ret[0] = params.K;
-				ret[1] = getExtractedVal(params.C, params.R, params.S);
+				ret[0] = getInput().get(1)._dim1;
+				ret[1] = getInput().get(1)._dim2;
 				ret[2] = -1;
 				break;
 			}
 			case DIRECT_CONV2D_BACKWARD_DATA:
 			{
 				ret = new long[3];
-				ret[0] = params.N;
-				ret[1] = getExtractedVal(params.C, params.H, params.W);
+				ret[0] = getInput().get(0)._dim1;
+				ret[1] = getInput().get(0)._dim2;
 				ret[2] = -1;
 				break;
 			}
@@ -408,36 +408,36 @@
 		{
 			case MAX_POOLING:
 			{	
-				_dim1 = params.N;
+				_dim1 = getInput().get(0)._dim1;
 				_dim2 = getExtractedVal(params.C, params.P, params.Q);
 				_nnz = -1; // cannot infer stats
 				break;
 			}
 			case MAX_POOLING_BACKWARD:
 			{
-				_dim1 = params.N;
-				_dim2 = getExtractedVal(params.C, params.H, params.W);
+				_dim1 = getInput().get(0)._dim1;
+				_dim2 = getInput().get(0)._dim2;
 				_nnz = -1;
 				break;
 			}
 			case DIRECT_CONV2D:
 			{
-				_dim1 = params.N;
-				_dim2 = getExtractedVal(params.K, params.P, params.Q);
+				_dim1 = getInput().get(0)._dim1;
+				_dim2 = getExtractedVal(getInput().get(1)._dim1, params.P, params.Q);
 				_nnz = -1; // cannot infer stats
 				break;
 			}
 			case DIRECT_CONV2D_BACKWARD_DATA:
 			{
-				_dim1 = params.N;
-				_dim2 = getExtractedVal(params.C, params.H, params.W);
+				_dim1 = getInput().get(0)._dim1;
+				_dim2 = getInput().get(0)._dim2;
 				_nnz = -1; // cannot infer stats
 				break;
 			}
 			case DIRECT_CONV2D_BACKWARD_FILTER:
 			{
-				_dim1 = params.K;
-				_dim2 = getExtractedVal(params.C, params.R, params.S);
+				_dim1 = getInput().get(1)._dim1;
+				_dim2 = getInput().get(1)._dim2;
 				_nnz = -1; // cannot infer stats
 				break;
 			}
diff --git a/src/main/java/org/apache/sysml/parser/BuiltinFunctionExpression.java b/src/main/java/org/apache/sysml/parser/BuiltinFunctionExpression.java
index bf31347..0ab2511 100644
--- a/src/main/java/org/apache/sysml/parser/BuiltinFunctionExpression.java
+++ b/src/main/java/org/apache/sysml/parser/BuiltinFunctionExpression.java
@@ -24,6 +24,7 @@
 import java.util.HashSet;
 
 import org.apache.sysml.parser.LanguageException.LanguageErrorCodes;
+import org.apache.sysml.runtime.util.ConvolutionUtils;
 
 public class BuiltinFunctionExpression extends DataIdentifier 
 {
@@ -1121,14 +1122,57 @@
 			// conv2d_backward_filter and conv2d_backward_data
 			Expression input = _args[0];			// For conv2d_backward_filter, this is input and for conv2d_backward_data, this is filter
 			
+			Expression filter = null;
 			if(!(this.getOpCode() == BuiltinFunctionOp.MAX_POOL || this.getOpCode() == BuiltinFunctionOp.AVG_POOL)) {
-				Expression filter = _args[1];			// For conv2d_backward functions, this is dout
+				filter = _args[1];			// For conv2d_backward functions, this is dout
 				checkMatrixParam(filter);
 			}
 			output.setDataType(DataType.MATRIX);
 			output.setValueType(ValueType.DOUBLE);
 			output.setBlockDimensions(input.getOutput().getRowsInBlock(), input.getOutput().getColumnsInBlock());
-			  			
+			// stride1, stride2, padding1, padding2, numImg, numChannels, imgSize, imgSize, 
+ 			// filter_shape1=1, filter_shape2=1, filterSize/poolSize1, filterSize/poolSize1
+ 			if(this.getOpCode() == BuiltinFunctionOp.MAX_POOL_BACKWARD ||
+ 					this.getOpCode() == BuiltinFunctionOp.CONV2D_BACKWARD_DATA) {
+ 				output.setDimensions(input.getOutput().getDim1(), input.getOutput().getDim2());
+ 			}
+ 			else if(this.getOpCode() == BuiltinFunctionOp.CONV2D_BACKWARD_FILTER) {
+ 				output.setDimensions(filter.getOutput().getDim1(), filter.getOutput().getDim2());
+ 			}
+ 			else if(this.getOpCode() == BuiltinFunctionOp.CONV2D || this.getOpCode() == BuiltinFunctionOp.MAX_POOL) {
+ 				try {
+ 					int start = 1;
+ 					if(this.getOpCode() == BuiltinFunctionOp.CONV2D) {
+ 						start = 2;
+ 					}
+ 					long stride_h = (long) getDoubleValue(_args[start++]);
+ 					long stride_w = (long) getDoubleValue(_args[start++]);
+ 					long pad_h = (long) getDoubleValue(_args[start++]);
+ 					long pad_w = (long) getDoubleValue(_args[start++]); 
+ 					start++;
+ 					long C = (long) getDoubleValue(_args[start++]);
+ 					long H = (long) getDoubleValue(_args[start++]);
+ 					long W = (long) getDoubleValue(_args[start++]);
+ 					long K = -1;
+ 					if(this.getOpCode() == BuiltinFunctionOp.CONV2D) {
+ 						K = (long) getDoubleValue(_args[start]);
+ 					}
+ 					start++; start++;
+ 					long R = (long) getDoubleValue(_args[start++]);
+ 					long S = (long) getDoubleValue(_args[start++]);
+ 					long P = ConvolutionUtils.getP(H, R, stride_h, pad_h);
+ 					long Q = ConvolutionUtils.getP(W, S, stride_w, pad_w);
+ 					if(this.getOpCode() == BuiltinFunctionOp.CONV2D)
+ 						output.setDimensions(input.getOutput().getDim1(), K*P*Q);
+ 					else
+ 						output.setDimensions(input.getOutput().getDim1(), C*P*Q);
+ 				}
+ 				catch(Exception e) {
+ 					output.setDimensions(input.getOutput().getDim1(), -1); // To make sure that output dimensions are not incorrect
+ 				}
+ 			}
+ 			else
+ 				throw new LanguageException("Unsupported op: " + this.getOpCode());
 			checkMatrixParam(input);
 			break;
 		}
diff --git a/src/main/java/org/apache/sysml/runtime/instructions/cp/ConvolutionCPInstruction.java b/src/main/java/org/apache/sysml/runtime/instructions/cp/ConvolutionCPInstruction.java
index 3885720..91c74f0 100644
--- a/src/main/java/org/apache/sysml/runtime/instructions/cp/ConvolutionCPInstruction.java
+++ b/src/main/java/org/apache/sysml/runtime/instructions/cp/ConvolutionCPInstruction.java
@@ -188,8 +188,8 @@
 				// without somewhat expensive HashMap checks
 				outputBlock = getDenseOutputBlock(ec, N, C*P*Q, true);
 				params.setReuseNonZeroedOutput(_reuseNonZeroedOutput);
+				LibMatrixDNN.maxpooling(matBlock, outputBlock, params);
 			}
-			LibMatrixDNN.maxpooling(matBlock, outputBlock, params);
 		}
 		else if (instOpcode.equalsIgnoreCase("maxpooling_backward")) {
 			MatrixBlock dout = ec.getMatrixInput(_in2.getName());
@@ -201,8 +201,8 @@
 				// without somewhat expensive HashMap checks
 				outputBlock = getDenseOutputBlock(ec, N, C*H*W, false);
 				params.setReuseNonZeroedOutput(_reuseNonZeroedOutput);
+				LibMatrixDNN.maxpooling_backward(matBlock, dout, outputBlock, params);
 			}
-			LibMatrixDNN.maxpooling_backward(matBlock, dout, outputBlock, params);
 			ec.releaseMatrixInput(_in2.getName());
 		}
 		else if (instOpcode.equalsIgnoreCase("conv2d")) {
diff --git a/src/main/java/org/apache/sysml/runtime/matrix/data/LibMatrixDNN.java b/src/main/java/org/apache/sysml/runtime/matrix/data/LibMatrixDNN.java
index e785112..cbb846c 100644
--- a/src/main/java/org/apache/sysml/runtime/matrix/data/LibMatrixDNN.java
+++ b/src/main/java/org/apache/sysml/runtime/matrix/data/LibMatrixDNN.java
@@ -735,13 +735,15 @@
 		outputBlock.setNonZeros(params.outputNNZ.get());
 	}
 
-	private static void doPooling(int n, int c, ConvolutionParameters params) {
+	private static void doPooling(int n, int c, ConvolutionParameters params) throws DMLRuntimeException {
 		double [] inputArray = null;
 		if (!params.input1.isInSparseFormat())
 			inputArray = params.input1.getDenseBlock();
 		double [] outputArray = null;
 		if (!params.output.isInSparseFormat())
 			outputArray = params.output.getDenseBlock();
+		else
+			throw new DMLRuntimeException("Expected the output to be allocated in dense format");
 		
 		long tmpNNZ = 0;
 		for (int p = 0; p < params.P; p++) {