docs: public static int[] get3DOutputSize(INDArray inputData, int[] kernel, int[] strides, int[] padding,
                                          ConvolutionMode convolutionMode, int[] dilation, boolean isNCDHW) {
  
          // NCDHW vs. NDHWC
          int inD = (int) (isNCDHW ? inputData.size(2) : inputData.size(1));
          int inH = (int) (isNCDHW ? inputData.size(3) : inputData.size(2));
          int inW = (int) (isNCDHW ? inputData.size(4) : inputData.size(3));
  
          int[] eKernel = effectiveKernelSize(kernel, dilation);
          boolean atrous = (eKernel == kernel);
  
          // FIXME: int cast
          val inShape = new int[]{inD, inH, inW};
          validateShapes(ArrayUtil.toInts(inputData.shape()), eKernel, strides, padding, convolutionMode, dilation, inShape, atrous);
  
          if (convolutionMode == ConvolutionMode.Same) {
              int outD = (int) Math.ceil(inD / ((double) strides[0]));
              int outH = (int) Math.ceil(inH / ((double) strides[1]));
              int outW = (int) Math.ceil(inW / ((double) strides[2]));
  
              return new int[]{outD, outH, outW};
          }
  
          int outD = (inD - eKernel[0] + 2 * padding[0]) / strides[0] + 1;
          int outH = (inH - eKernel[1] + 2 * padding[1]) / strides[1] + 1;
          int outW = (inW - eKernel[2] + 2 * padding[2]) / strides[2] + 1;
  
          return new int[]{outD, outH, outW};
      }