Repository: deepjavalibrary/djl
Pull request #2152 (2022-11-10 17:48:36)

add cumprod operator
## Description ##

Add cumprod for sd

codecov-commenter: # [Codecov](https://codecov.io/gh/deepjavalibrary/djl/pull/2152?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deepjavalibrary) Report
Base: **72.08**% // Head: **71.45**% // Decreases project coverage by **`-0.63%`** :warning:
> Coverage data is based on head [(`a167f45`)](https://codecov.io/gh/deepjavalibrary/djl/pull/2152?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deepjavalibrary) compared to base [(`bb5073f`)](https://codecov.io/gh/deepjavalibrary/djl/commit/bb5073f7ffc33f1883621fc1783dbb01e70b418f?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deepjavalibrary).
> Patch coverage: 72.03% of modified lines in pull request are covered.

<details><summary>Additional details and impacted files</summary>


```diff
@@             Coverage Diff              @@
##             master    #2152      +/-   ##
============================================
- Coverage     72.08%   71.45%   -0.64%     
- Complexity     5126     6327    +1201     
============================================
  Files           473      625     +152     
  Lines         21970    27928    +5958     
  Branches       2351     3011     +660     
============================================
+ Hits          15838    19957    +4119     
- Misses         4925     6507    +1582     
- Partials       1207     1464     +257     
```


| [Impacted Files](https://codecov.io/gh/deepjavalibrary/djl/pull/2152?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deepjavalibrary) | Coverage Δ | |
|---|---|---|
| [api/src/main/java/ai/djl/modality/cv/Image.java](https://codecov.io/gh/deepjavalibrary/djl/pull/2152/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deepjavalibrary#diff-YXBpL3NyYy9tYWluL2phdmEvYWkvZGpsL21vZGFsaXR5L2N2L0ltYWdlLmphdmE=) | `69.23% <ø> (-4.11%)` | :arrow_down: |
| [...rc/main/java/ai/djl/modality/cv/MultiBoxPrior.java](https://codecov.io/gh/deepjavalibrary/djl/pull/2152/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deepjavalibrary#diff-YXBpL3NyYy9tYWluL2phdmEvYWkvZGpsL21vZGFsaXR5L2N2L011bHRpQm94UHJpb3IuamF2YQ==) | `76.00% <ø> (ø)` | |
| [...rc/main/java/ai/djl/modality/cv/output/Joints.java](https://codecov.io/gh/deepjavalibrary/djl/pull/2152/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deepjavalibrary#diff-YXBpL3NyYy9tYWluL2phdmEvYWkvZGpsL21vZGFsaXR5L2N2L291dHB1dC9Kb2ludHMuamF2YQ==) | `71.42% <ø> (ø)` | |
| [.../main/java/ai/djl/modality/cv/output/Landmark.java](https://codecov.io/gh/deepjavalibrary/djl/pull/2152/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deepjavalibrary#diff-YXBpL3NyYy9tYWluL2phdmEvYWkvZGpsL21vZGFsaXR5L2N2L291dHB1dC9MYW5kbWFyay5qYXZh) | `100.00% <ø> (ø)` | |
| [...main/java/ai/djl/modality/cv/output/Rectangle.java](https://codecov.io/gh/deepjavalibrary/djl/pull/2152/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deepjavalibrary#diff-YXBpL3NyYy9tYWluL2phdmEvYWkvZGpsL21vZGFsaXR5L2N2L291dHB1dC9SZWN0YW5nbGUuamF2YQ==) | `72.41% <0.00%> (ø)` | |
| [...i/djl/modality/cv/translator/BigGANTranslator.java](https://codecov.io/gh/deepjavalibrary/djl/pull/2152/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deepjavalibrary#diff-YXBpL3NyYy9tYWluL2phdmEvYWkvZGpsL21vZGFsaXR5L2N2L3RyYW5zbGF0b3IvQmlnR0FOVHJhbnNsYXRvci5qYXZh) | `21.42% <0.00%> (-5.24%)` | :arrow_down: |
| [.../modality/cv/translator/ImageFeatureExtractor.java](https://codecov.io/gh/deepjavalibrary/djl/pull/2152/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deepjavalibrary#diff-YXBpL3NyYy9tYWluL2phdmEvYWkvZGpsL21vZGFsaXR5L2N2L3RyYW5zbGF0b3IvSW1hZ2VGZWF0dXJlRXh0cmFjdG9yLmphdmE=) | `0.00% <0.00%> (ø)` | |
| [.../ai/djl/modality/cv/translator/YoloTranslator.java](https://codecov.io/gh/deepjavalibrary/djl/pull/2152/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deepjavalibrary#diff-YXBpL3NyYy9tYWluL2phdmEvYWkvZGpsL21vZGFsaXR5L2N2L3RyYW5zbGF0b3IvWW9sb1RyYW5zbGF0b3IuamF2YQ==) | `27.77% <0.00%> (+18.95%)` | :arrow_up: |
| [...modality/cv/translator/wrapper/FileTranslator.java](https://codecov.io/gh/deepjavalibrary/djl/pull/2152/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deepjavalibrary#diff-YXBpL3NyYy9tYWluL2phdmEvYWkvZGpsL21vZGFsaXR5L2N2L3RyYW5zbGF0b3Ivd3JhcHBlci9GaWxlVHJhbnNsYXRvci5qYXZh) | `44.44% <ø> (ø)` | |
| [...y/cv/translator/wrapper/InputStreamTranslator.java](https://codecov.io/gh/deepjavalibrary/djl/pull/2152/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deepjavalibrary#diff-YXBpL3NyYy9tYWluL2phdmEvYWkvZGpsL21vZGFsaXR5L2N2L3RyYW5zbGF0b3Ivd3JhcHBlci9JbnB1dFN0cmVhbVRyYW5zbGF0b3IuamF2YQ==) | `44.44% <ø> (ø)` | |
| ... and [559 more](https://codecov.io/gh/deepjavalibrary/djl/pull/2152/diff?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deepjavalibrary) | |

Help us with your feedback. Take ten seconds to tell us [how you rate us](https://about.codecov.io/nps?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deepjavalibrary). Have a feature suggestion? [Share it here.](https://app.codecov.io/gh/feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deepjavalibrary)

</details>

[:umbrella: View full report at Codecov](https://codecov.io/gh/deepjavalibrary/djl/pull/2152?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deepjavalibrary).   
:loudspeaker: Do you have feedback about the report comment? [Let us know in this issue](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deepjavalibrary).


Patch:
diff --git a/api/src/main/java/ai/djl/ndarray/NDArray.java b/api/src/main/java/ai/djl/ndarray/NDArray.java
index c7509b268..434e62542 100644
--- a/api/src/main/java/ai/djl/ndarray/NDArray.java
+++ b/api/src/main/java/ai/djl/ndarray/NDArray.java
@@ -2586,6 +2586,27 @@ public interface NDArray extends NDResource, BytesSupplier {
      */
     NDArray sum(int[] axes, boolean keepDims);
 
+    /**
+     * Returns the cumulative product of elements of input in the dimension dim. For example, if
+     * input is a vector of size N, the result will also be a vector of size N, with elements. [x1,
+     * x1 * x2, x1 * x2 *x3 ...]
+     *
+     * @param axis the axis along which to operate
+     * @return the cumulative product of this
+     */
+    NDArray cumProd(int axis);
+
+    /**
+     * Returns the cumulative product of elements of input in the dimension dim. For example, if
+     * input is a vector of size N, the result will also be a vector of size N, with elements. [x1,
+     * x1 * x2, x1 * x2 *x3 ...]
+     *
+     * @param axis the axis along which to operate
+     * @param dataType the datatype of the output
+     * @return the cumulative product of this
+     */
+    NDArray cumProd(int axis, DataType dataType);
+
     /**
      * Returns the product of this {@code NDArray}.
      *
diff --git a/api/src/main/java/ai/djl/ndarray/NDArrayAdapter.java b/api/src/main/java/ai/djl/ndarray/NDArrayAdapter.java
index e6190dbf5..1e9a4a486 100644
--- a/api/src/main/java/ai/djl/ndarray/NDArrayAdapter.java
+++ b/api/src/main/java/ai/djl/ndarray/NDArrayAdapter.java
@@ -750,6 +750,18 @@ public abstract class NDArrayAdapter implements NDArray {
         return getAlternativeArray().sum(axes, keepDims);
     }
 
+    /** {@inheritDoc} */
+    @Override
+    public NDArray cumProd(int axis) {
+        return getAlternativeArray().cumProd(axis);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public NDArray cumProd(int axis, DataType dataType) {
+        return getAlternativeArray().cumProd(axis);
+    }
+
     /** {@inheritDoc} */
     @Override
     public NDArray prod() {
diff --git a/engines/mxnet/mxnet-engine/src/main/java/ai/djl/mxnet/engine/MxNDArray.java b/engines/mxnet/mxnet-engine/src/main/java/ai/djl/mxnet/engine/MxNDArray.java
index 1a89500e4..fef0a915e 100644
--- a/engines/mxnet/mxnet-engine/src/main/java/ai/djl/mxnet/engine/MxNDArray.java
+++ b/engines/mxnet/mxnet-engine/src/main/java/ai/djl/mxnet/engine/MxNDArray.java
@@ -995,6 +995,18 @@ public class MxNDArray extends NativeResource<Pointer> implements LazyNDArray {
         return manager.invoke("_np_sum", this, params);
     }
 
+    /** {@inheritDoc} */
+    @Override
+    public NDArray cumProd(int axis) {
+        throw new UnsupportedOperationException("Not supported by MXNet");
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public NDArray cumProd(int axis, DataType dataType) {
+        throw new UnsupportedOperationException("Not supported by MXNet");
+    }
+
     /** {@inheritDoc} */
     @Override
     public NDArray prod() {
diff --git a/engines/pytorch/pytorch-engine/src/main/java/ai/djl/pytorch/engine/PtNDArray.java b/engines/pytorch/pytorch-engine/src/main/java/ai/djl/pytorch/engine/PtNDArray.java
index f7f876bde..cf2f35f96 100644
--- a/engines/pytorch/pytorch-engine/src/main/java/ai/djl/pytorch/engine/PtNDArray.java
+++ b/engines/pytorch/pytorch-engine/src/main/java/ai/djl/pytorch/engine/PtNDArray.java
@@ -924,6 +924,18 @@ public class PtNDArray extends NativeResource<Long> implements NDArray {
         return JniUtils.sum(this, Arrays.stream(axes).mapToLong(i -> i).toArray(), keepDims);
     }
 
+    /** {@inheritDoc} */
+    @Override
+    public NDArray cumProd(int axis) {
+        return JniUtils.cumProd(this, axis, null);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public NDArray cumProd(int axis, DataType dataType) {
+        return JniUtils.cumProd(this, axis, dataType);
+    }
+
     /** {@inheritDoc} */
     @Override
     public PtNDArray prod() {
diff --git a/engines/pytorch/pytorch-engine/src/main/java/ai/djl/pytorch/jni/JniUtils.java b/engines/pytorch/pytorch-engine/src/main/java/ai/djl/pytorch/jni/JniUtils.java
index 725c912b3..862833d44 100644
--- a/engines/pytorch/pytorch-engine/src/main/java/ai/djl/pytorch/jni/JniUtils.java
+++ b/engines/pytorch/pytorch-engine/src/main/java/ai/djl/pytorch/jni/JniUtils.java
@@ -851,6 +851,16 @@ public final class JniUtils {
                 PyTorchLibrary.LIB.torchSum(ndArray.getHandle(), dims, keepDim));
     }
 
+    public static PtNDArray cumProd(PtNDArray ndArray, long dim, DataType dataType) {
+        int dtPosition = -1;
+        if (dataType != null) {
+            dtPosition = dataType.ordinal();
+        }
+        return new PtNDArray(
+                ndArray.getManager(),
+                PyTorchLibrary.LIB.torchCumProd(ndArray.getHandle(), dim, dtPosition));
+    }
+
     public static PtNDArray prod(PtNDArray ndArray) {
         return new PtNDArray(
                 ndArray.getManager(), PyTorchLibrary.LIB.torchProd(ndArray.getHandle()));
diff --git a/engines/pytorch/pytorch-engine/src/main/java/ai/djl/pytorch/jni/PyTorchLibrary.java b/engines/pytorch/pytorch-engine/src/main/java/ai/djl/pytorch/jni/PyTorchLibrary.java
index fc1f3f315..381712390 100644
--- a/engines/pytorch/pytorch-engine/src/main/java/ai/djl/pytorch/jni/PyTorchLibrary.java
+++ b/engines/pytorch/pytorch-engine/src/main/java/ai/djl/pytorch/jni/PyTorchLibrary.java
@@ -238,6 +238,8 @@ final class PyTorchLibrary {
 
     native long torchSum(long handle, long[] dim, boolean keepDim);
 
+    native long torchCumProd(long handle, long dim, int dtype);
+
     native long torchProd(long handle);
 
     native long torchProd(long handle, long dim, boolean keepDim);
diff --git a/engines/pytorch/pytorch-native/src/main/native/ai_djl_pytorch_jni_PyTorchLibrary_torch_reduction.cc b/engines/pytorch/pytorch-native/src/main/native/ai_djl_pytorch_jni_PyTorchLibrary_torch_reduction.cc
index b2ca63c4d..6b1abb8ce 100644
--- a/engines/pytorch/pytorch-native/src/main/native/ai_djl_pytorch_jni_PyTorchLibrary_torch_reduction.cc
+++ b/engines/pytorch/pytorch-native/src/main/native/ai_djl_pytorch_jni_PyTorchLibrary_torch_reduction.cc
@@ -132,6 +132,20 @@ JNIEXPORT jlong JNICALL Java_ai_djl_pytorch_jni_PyTorchLibrary_torchSum__J_3JZ(
   API_END_RETURN()
 }
 
+JNIEXPORT jlong JNICALL Java_ai_djl_pytorch_jni_PyTorchLibrary_torchCumProd
+  (JNIEnv * env, jobject jthis, jlong jhandle, jlong jdim, jint jdtype) {
+  API_BEGIN()
+  const auto* tensor_ptr = reinterpret_cast<torch::Tensor*>(jhandle);
+  if (jdtype == -1) {
+      const auto* result_ptr = new torch::Tensor(tensor_ptr->cumprod(jdim));
+      return reinterpret_cast<uintptr_t>(result_ptr);
+  } else {
+      const auto* result_ptr = new torch::Tensor(tensor_ptr->cumprod(jdim, utils::GetScalarTypeFromDType(jdtype)));
+      return reinterpret_cast<uintptr_t>(result_ptr);
+  }
+  API_END_RETURN()
+}
+
 JNIEXPORT jlong JNICALL Java_ai_djl_pytorch_jni_PyTorchLibrary_torchProd__J(JNIEnv* env, jobject jthis, jlong jhandle) {
   API_BEGIN()
   const auto* tensor_ptr = reinterpret_cast<torch::Tensor*>(jhandle);
diff --git a/engines/tensorflow/tensorflow-engine/src/main/java/ai/djl/tensorflow/engine/TfNDArray.java b/engines/tensorflow/tensorflow-engine/src/main/java/ai/djl/tensorflow/engine/TfNDArray.java
index 86d968922..bd785b3fe 100644
--- a/engines/tensorflow/tensorflow-engine/src/main/java/ai/djl/tensorflow/engine/TfNDArray.java
+++ b/engines/tensorflow/tensorflow-engine/src/main/java/ai/djl/tensorflow/engine/TfNDArray.java
@@ -1009,6 +1009,18 @@ public class TfNDArray extends NativeResource<TFE_TensorHandle> implements NDArr
         }
     }
 
+    /** {@inheritDoc} */
+    @Override
+    public NDArray cumProd(int axis) {
+        throw new UnsupportedOperationException("Not implemented");
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public NDArray cumProd(int axis, DataType dataType) {
+        throw new UnsupportedOperationException("Not implemented");
+    }
+
     /** {@inheritDoc} */
     @Override
     public NDArray prod() {


Test patch:
diff --git a/integration/src/main/java/ai/djl/integration/tests/ndarray/NDArrayReductionOpTest.java b/integration/src/main/java/ai/djl/integration/tests/ndarray/NDArrayReductionOpTest.java
index 2987ae031..4e2d3d501 100644
--- a/integration/src/main/java/ai/djl/integration/tests/ndarray/NDArrayReductionOpTest.java
+++ b/integration/src/main/java/ai/djl/integration/tests/ndarray/NDArrayReductionOpTest.java
@@ -14,6 +14,7 @@ package ai.djl.integration.tests.ndarray;
 
 import ai.djl.ndarray.NDArray;
 import ai.djl.ndarray.NDManager;
+import ai.djl.ndarray.types.DataType;
 import ai.djl.ndarray.types.Shape;
 
 import org.testng.Assert;
@@ -106,6 +107,21 @@ public class NDArrayReductionOpTest {
         }
     }
 
+    @Test
+    public void testCumProd() {
+        try (NDManager manager = NDManager.newBaseManager()) {
+            NDArray array = manager.create(new int[] {1, 2, 3, 4});
+            NDArray expected = manager.create(new long[] {1, 2, 6, 24});
+            Assert.assertEquals(array.cumProd(0), expected);
+
+            NDArray expectedInt = manager.create(new int[] {1, 2, 6, 24});
+            Assert.assertEquals(array.cumProd(0, array.getDataType()), expectedInt);
+
+            NDArray expectedFloat = manager.create(new float[] {1f, 2f, 6f, 24f});
+            Assert.assertEquals(array.cumProd(0, DataType.FLOAT32), expectedFloat);
+        }
+    }
+
     @Test
     public void testProd() {
         try (NDManager manager = NDManager.newBaseManager()) {