Repository: deepjavalibrary/djl
Pull request #2280 (2023-01-03 05:08:56)

[ci] Replace jacoc root report with aggregation report plugin
## Description ##

Brief description of what this PR is about

- If this change is a backward incompatible change, why must this change be made?
- Interesting edge cases to note here



Patch:
diff --git a/.github/workflows/continuous.yml b/.github/workflows/continuous.yml
index 42f4c7ce3..5cfa1503e 100644
--- a/.github/workflows/continuous.yml
+++ b/.github/workflows/continuous.yml
@@ -85,7 +85,7 @@ jobs:
           ./gradlew -Dai.djl.default_engine=OnnxRuntime :integration:test
           ./gradlew :integration:clean
       - name: Build with Gradle
-        run: ./gradlew build jRR jRV
+        run: ./gradlew build :jacoco:testCodeCoverageReport
       - name: Upload test results
         uses: actions/upload-artifact@v3
         if: always()
@@ -97,7 +97,7 @@ jobs:
       - name: upload to codecov
         uses: codecov/codecov-action@v3
         with:
-          files: ./build/reports/jacoco/jacocoRootReport/jacocoRootReport.xml
+          files: ./jacoco/build/reports/jacoco/testCodeCoverageReport/testCodeCoverageReport.xml
           fail_ci_if_error: false
           path_to_write_report: ./codecov_report.txt
 
diff --git a/.github/workflows/nightly_publish.yml b/.github/workflows/nightly_publish.yml
index 037bdc580..ce66e9b49 100644
--- a/.github/workflows/nightly_publish.yml
+++ b/.github/workflows/nightly_publish.yml
@@ -35,7 +35,7 @@ jobs:
       - name: check disk space
         run: df -h
       - name: Build with Gradle
-        run: ./gradlew -Dnightly=true build jRR jRV
+        run: ./gradlew -Dnightly=true build :jacoco:testCodeCoverageReport
       - name: Upload test results
         uses: actions/upload-artifact@v3
         if: always()
diff --git a/api/src/main/java/ai/djl/ndarray/NDArrays.java b/api/src/main/java/ai/djl/ndarray/NDArrays.java
index b73c20278..304b80393 100644
--- a/api/src/main/java/ai/djl/ndarray/NDArrays.java
+++ b/api/src/main/java/ai/djl/ndarray/NDArrays.java
@@ -199,7 +199,7 @@ public final class NDArrays {
      * @return the boolean {@link NDArray} for element-wise "Equals" comparison
      */
     public static NDArray eq(Number n, NDArray a) {
-        return a.eq(n);
+        return eq(a, n);
     }
 
     /**
@@ -264,7 +264,7 @@ public final class NDArrays {
      * @return the boolean {@link NDArray} for element-wise "Not equals" comparison
      */
     public static NDArray neq(Number n, NDArray a) {
-        return a.neq(n);
+        return neq(a, n);
     }
 
     /**
diff --git a/api/src/main/java/ai/djl/ndarray/NDUtils.java b/api/src/main/java/ai/djl/ndarray/NDUtils.java
index c84489554..13e882d04 100644
--- a/api/src/main/java/ai/djl/ndarray/NDUtils.java
+++ b/api/src/main/java/ai/djl/ndarray/NDUtils.java
@@ -23,7 +23,7 @@ public final class NDUtils {
     private NDUtils() {}
 
     /**
-     * Get {@link Shape} of the empty {@link NDArray} after applying reduction operations.
+     * Returns {@link Shape} of the empty {@link NDArray} after applying reduction operations.
      *
      * @param shape input shape
      * @param axis axis to apply reduction
diff --git a/build.gradle b/build.gradle
index ba56a4a96..5ce8fd603 100644
--- a/build.gradle
+++ b/build.gradle
@@ -109,6 +109,5 @@ configure(javaProjects()) {
 }
 
 apply from: file("${rootProject.projectDir}/tools/gradle/publish.gradle")
-apply from: file("${rootProject.projectDir}/tools/gradle/jacoco.gradle")
 apply from: file("${rootProject.projectDir}/tools/gradle/release.gradle")
 apply from: file("${rootProject.projectDir}/tools/gradle/stats.gradle")
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 479a1a678..148be97e9 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
@@ -412,9 +412,10 @@ public class MxNDArray extends NativeResource<Pointer> implements LazyNDArray {
     /** {@inheritDoc} */
     @Override
     public boolean contentEquals(Number number) {
-        if (number == null) {
+        if (number == null || getDataType().isBoolean()) {
             return false;
         }
+
         try (NDArray result = eq(number)) {
             return result.all().getBoolean();
         }
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 de96b24f2..db91f276e 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
@@ -401,7 +401,7 @@ public class PtNDArray extends NativeResource<Long> implements NDArray {
     /** {@inheritDoc} */
     @Override
     public boolean contentEquals(Number number) {
-        return JniUtils.contentEqual(this, (PtNDArray) manager.create(number));
+        return contentEquals(manager.create(number));
     }
 
     /** {@inheritDoc} */
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 f19c754ac..7265cf534 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
@@ -311,7 +311,7 @@ public class TfNDArray extends NativeResource<TFE_TensorHandle> implements NDArr
     /** {@inheritDoc} */
     @Override
     public boolean contentEquals(Number number) {
-        if (number == null) {
+        if (number == null || getDataType().isBoolean()) {
             return false;
         }
         try (NDArray result = eq(number)) {
diff --git a/jacoco/build.gradle b/jacoco/build.gradle
new file mode 100644
index 000000000..418e7857c
--- /dev/null
+++ b/jacoco/build.gradle
@@ -0,0 +1,69 @@
+plugins {
+    id "base"
+    id "jacoco-report-aggregation"
+}
+
+repositories {
+    mavenCentral()
+}
+
+dependencies {
+    jacocoAggregation project(":api")
+    jacocoAggregation project(":basicdataset")
+    jacocoAggregation project(":engines:dlr:dlr-engine")
+    jacocoAggregation project(":engines:dlr:dlr-native")
+    jacocoAggregation project(":engines:ml:xgboost")
+    jacocoAggregation project(":engines:ml:lightgbm")
+    jacocoAggregation project(":engines:mxnet:mxnet-engine")
+    jacocoAggregation project(":engines:mxnet:mxnet-model-zoo")
+    jacocoAggregation project(":engines:mxnet:native")
+    jacocoAggregation project(":engines:onnxruntime:onnxruntime-android")
+    jacocoAggregation project(":engines:onnxruntime:onnxruntime-engine")
+    jacocoAggregation project(":engines:paddlepaddle:paddlepaddle-engine")
+    jacocoAggregation project(":engines:paddlepaddle:paddlepaddle-model-zoo")
+    jacocoAggregation project(":engines:paddlepaddle:paddlepaddle-native")
+    jacocoAggregation project(":engines:pytorch:pytorch-engine")
+    jacocoAggregation project(":engines:pytorch:pytorch-jni")
+    jacocoAggregation project(":engines:pytorch:pytorch-model-zoo")
+    jacocoAggregation project(":engines:pytorch:pytorch-native")
+    jacocoAggregation project(":engines:tensorflow:tensorflow-api")
+    jacocoAggregation project(":engines:tensorflow:tensorflow-engine")
+    jacocoAggregation project(":engines:tensorflow:tensorflow-model-zoo")
+    jacocoAggregation project(":engines:tensorflow:tensorflow-native")
+    jacocoAggregation project(":engines:tflite:tflite-engine")
+    jacocoAggregation project(":engines:tflite:tflite-native")
+    jacocoAggregation project(":examples")
+    jacocoAggregation project(":extensions:audio")
+    jacocoAggregation project(":extensions:fasttext")
+    jacocoAggregation project(":extensions:hadoop")
+    jacocoAggregation project(":extensions:opencv")
+    jacocoAggregation project(":extensions:sentencepiece")
+    jacocoAggregation project(":extensions:tokenizers")
+    jacocoAggregation project(":extensions:tablesaw")
+    jacocoAggregation project(":extensions:timeseries")
+    jacocoAggregation project(":extensions:spark")
+    jacocoAggregation project(":integration")
+    jacocoAggregation project(":model-zoo")
+}
+
+reporting {
+    reports {
+        testCodeCoverageReport(JacocoCoverageReport) {
+            testType = TestSuiteType.UNIT_TEST
+        }
+    }
+}
+
+tasks.named("check") {
+    dependsOn tasks.named("testCodeCoverageReport", JacocoReport)
+}
+
+testCodeCoverageReport {
+    classDirectories.setFrom(files(classDirectories.files.collect {
+        fileTree(dir: it, exclude: [
+                "org/tensorflow/lite/**",
+                "ai/djl/integration/**",
+                "ai/djl/examples/**"
+        ])
+    }))
+}
diff --git a/settings.gradle b/settings.gradle
index 0a19a5045..8b741d598 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -40,5 +40,6 @@ include ':extensions:spark'
 include ':integration'
 include ':model-zoo'
 include ':testing'
+include ':jacoco'
 
 
diff --git a/tools/gradle/check.gradle b/tools/gradle/check.gradle
index e3511e182..4bf78c6b3 100644
--- a/tools/gradle/check.gradle
+++ b/tools/gradle/check.gradle
@@ -56,7 +56,7 @@ tasks.withType(Checkstyle) {
 
 apply plugin: 'jacoco'
 jacoco {
-    toolVersion = "0.8.7"
+    toolVersion = "0.8.8"
 }
 jacocoTestReport {
     reports {
diff --git a/tools/gradle/jacoco.gradle b/tools/gradle/jacoco.gradle
deleted file mode 100644
index 5eb909d5c..000000000
--- a/tools/gradle/jacoco.gradle
+++ /dev/null
@@ -1,63 +0,0 @@
-apply plugin: 'jacoco'
-
-def jacocoProjects = subprojects.findAll {
-    if ([":engines:mxnet:jnarator"].contains(it.getPath())) {
-        return false
-    }
-    return new File(it.projectDir, "src/test/java").exists()
-}
-
-task jacocoMergeTestData(type: JacocoMerge) {
-    jacocoProjects.each { p ->
-        dependsOn(p.test, p.jacocoTestReport)
-        executionData p.tasks.withType(Test)
-    }
-}
-
-def exclusions = [":examples", ":integration", ":engines:tensorrt", ":djl-zero"]
-
-task jacocoRootReport(type: JacocoReport) {
-    dependsOn jacocoMergeTestData
-    description = 'Generates an aggregate report from all subprojects'
-
-    jacocoProjects.each { p ->
-        if (!exclusions.contains(p.getPath())) {
-            additionalSourceDirs.from files((Set<File>) p.sourceSets.main.allJava.srcDirs)
-            sourceDirectories.from files((Set<File>) p.sourceSets.main.allSource.srcDirs)
-            classDirectories.from files((FileCollection) p.sourceSets.main.output)
-            additionalClassDirs((FileCollection) p.sourceSets.main.output)
-        }
-    }
-    executionData.from = files(jacocoProjects.jacocoTestReport.executionData).filter { f -> f.exists() }
-
-    reports {
-        xml.required = true
-        html.required = true
-    }
-}
-
-task jacocoRootVerification(type: JacocoCoverageVerification) {
-    dependsOn jacocoMergeTestData
-
-    jacocoProjects.each { p ->
-        if (!exclusions.contains(p.getPath())) {
-            additionalSourceDirs.from files((Set<File>) p.sourceSets.main.allJava.srcDirs)
-            sourceDirectories.from files((Set<File>) p.sourceSets.main.allSource.srcDirs)
-            classDirectories.from files((FileCollection) p.sourceSets.main.output)
-            additionalClassDirs((FileCollection) p.sourceSets.main.output)
-        }
-    }
-    executionData.from = files(jacocoProjects.jacocoTestReport.executionData).filter { f -> f.exists() }
-
-    violationRules {
-        rule {
-            limit {
-                if (Boolean.getBoolean("nightly")) {
-                    minimum = 0.70
-                } else {
-                    minimum = 0.65
-                }
-            }
-        }
-    }
-}


Test patch:
diff --git a/api/src/test/java/ai/djl/ndarray/NDUtilsTest.java b/api/src/test/java/ai/djl/ndarray/NDUtilsTest.java
new file mode 100644
index 000000000..2925f9343
--- /dev/null
+++ b/api/src/test/java/ai/djl/ndarray/NDUtilsTest.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance
+ * with the License. A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0/
+ *
+ * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES
+ * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions
+ * and limitations under the License.
+ */
+package ai.djl.ndarray;
+
+import ai.djl.ndarray.types.Shape;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+public class NDUtilsTest {
+
+    @Test
+    public void testGetShape() {
+        Shape shape = new Shape(1, 2, 3);
+        Shape result = NDUtils.getShapeFromEmptyNDArrayForReductionOp(shape, 1);
+        Shape expected = new Shape(1, 3);
+        Assert.assertEquals(result, expected);
+
+        Shape empty = new Shape(0, 1);
+        Assert.assertThrows(() -> NDUtils.getShapeFromEmptyNDArrayForReductionOp(empty, 0));
+    }
+}
diff --git a/extensions/opencv/src/test/java/ai/djl/opencv/OpenCVImageFactoryTest.java b/extensions/opencv/src/test/java/ai/djl/opencv/OpenCVImageFactoryTest.java
index cb0d4dc52..eda79cb45 100644
--- a/extensions/opencv/src/test/java/ai/djl/opencv/OpenCVImageFactoryTest.java
+++ b/extensions/opencv/src/test/java/ai/djl/opencv/OpenCVImageFactoryTest.java
@@ -122,15 +122,8 @@ public class OpenCVImageFactoryTest {
             }
 
             Assert.assertThrows(
-                    IOException.class,
-                    () -> {
-                        factory.fromFile(Paths.get("nonexist.jpg"));
-                    });
-            Assert.assertThrows(
-                    IOException.class,
-                    () -> {
-                        factory.fromUrl("file:build.gradle");
-                    });
+                    IOException.class, () -> factory.fromFile(Paths.get("nonexist.jpg")));
+            Assert.assertThrows(IOException.class, () -> factory.fromUrl("file:build.gradle"));
         }
     }
 
diff --git a/extensions/sentencepiece/src/test/java/ai/djl/sentencepiece/SpTokenizerTest.java b/extensions/sentencepiece/src/test/java/ai/djl/sentencepiece/SpTokenizerTest.java
index 32f443d72..4821609ed 100644
--- a/extensions/sentencepiece/src/test/java/ai/djl/sentencepiece/SpTokenizerTest.java
+++ b/extensions/sentencepiece/src/test/java/ai/djl/sentencepiece/SpTokenizerTest.java
@@ -118,22 +118,14 @@ public class SpTokenizerTest {
     }
 
     @Test
-    public void testModelNotFound() throws IOException {
+    public void testModelNotFound() {
         TestRequirements.notWindows();
 
-        Assert.assertThrows(
-                () -> {
-                    new SpTokenizer(Paths.get("build/test/non-exists"));
-                });
+        Assert.assertThrows(() -> new SpTokenizer(Paths.get("build/test/non-exists")));
 
         Assert.assertThrows(
-                () -> {
-                    new SpTokenizer(Paths.get("build/test/sp_model"), "non-exists.model");
-                });
+                () -> new SpTokenizer(Paths.get("build/test/sp_model"), "non-exists.model"));
 
-        Assert.assertThrows(
-                () -> {
-                    new SpTokenizer(Paths.get("build/test/sp_model"), "non-exists");
-                });
+        Assert.assertThrows(() -> new SpTokenizer(Paths.get("build/test/sp_model"), "non-exists"));
     }
 }
diff --git a/integration/src/main/java/ai/djl/integration/tests/ndarray/NDArrayElementArithmeticOpTest.java b/integration/src/main/java/ai/djl/integration/tests/ndarray/NDArrayElementArithmeticOpTest.java
index 278943eb9..cb1d3b6ce 100644
--- a/integration/src/main/java/ai/djl/integration/tests/ndarray/NDArrayElementArithmeticOpTest.java
+++ b/integration/src/main/java/ai/djl/integration/tests/ndarray/NDArrayElementArithmeticOpTest.java
@@ -51,7 +51,6 @@ public class NDArrayElementArithmeticOpTest {
         } else {
             // other cases only apply to non inplace test
             // test NDArray with scalar
-            x1 = 10f;
             x2 = 5f;
             float y = arithmeticOp.apply(x1, x2);
             array1 = manager.create(new float[] {x1, x1});
@@ -168,6 +167,10 @@ public class NDArrayElementArithmeticOpTest {
             result = NDArrays.addi(lhs, 2);
             NDArray expected = manager.create(new float[] {3f, 4f, 5f, 6f});
             Assertions.assertInPlaceEquals(result, expected, lhs);
+            lhs = manager.create(new float[] {1f, 2f, 3f, 4f});
+            result = NDArrays.addi(2, lhs);
+            Assertions.assertInPlaceEquals(result, expected, lhs);
+
             testScalarCornerCase(manager, NDArrays::add, Float::sum, false);
             testScalarCornerCase(manager, NDArrays::addi, Float::sum, true);
         }
@@ -182,6 +185,9 @@ public class NDArrayElementArithmeticOpTest {
             Assert.assertNotEquals(
                     result, addend, "None in-place operation returned in-place result");
 
+            result = NDArrays.add(1, addend);
+            Assert.assertEquals(result, addendum);
+
             result = NDArrays.addi(addend, addendum);
             NDArray expected = manager.create(new float[] {3f, 5f, 7f, 9f});
             Assertions.assertInPlaceEquals(result, expected, addend);
@@ -192,6 +198,15 @@ public class NDArrayElementArithmeticOpTest {
                 manager.create(new float[] {2, 2, 2, 2}, new Shape(2, 2))
             };
 
+            Assert.assertThrows(() -> NDArrays.add(addend));
+
+            Assert.assertThrows(
+                    () ->
+                            NDArrays.add(
+                                    addend,
+                                    manager.ones(new Shape(2)),
+                                    manager.ones(new Shape(3))));
+
             NDArray addAll = NDArrays.add(toAddAll);
             Assert.assertNotEquals(
                     addAll, toAddAll[0], "None in-place operation returned in-place result");
@@ -307,11 +322,17 @@ public class NDArrayElementArithmeticOpTest {
         try (NDManager manager = NDManager.newBaseManager()) {
             NDArray multiplicand = manager.create(new float[] {6, 9, -12, 15, 0});
             NDArray result = NDArrays.mul(multiplicand, 3);
-            NDArray inPlaceResult = NDArrays.muli(multiplicand, 3);
             NDArray expected = manager.create(new float[] {18, 27, -36, 45, 0});
-            Assert.assertEquals(
-                    result, expected, "Scalar multiplication: Incorrect value in result ndarray");
+            Assert.assertEquals(result, expected);
+            result = NDArrays.mul(3, multiplicand);
+            Assert.assertEquals(result, expected);
+
+            NDArray inPlaceResult = NDArrays.muli(multiplicand, 3);
             Assertions.assertInPlaceEquals(inPlaceResult, expected, multiplicand);
+            multiplicand = manager.create(new float[] {6, 9, -12, 15, 0});
+            inPlaceResult = NDArrays.muli(3, multiplicand);
+            Assertions.assertInPlaceEquals(inPlaceResult, expected, multiplicand);
+
             testScalarCornerCase(manager, NDArrays::mul, (x, y) -> x * y, false);
             testScalarCornerCase(manager, NDArrays::muli, (x, y) -> x * y, true);
         }
@@ -430,7 +451,7 @@ public class NDArrayElementArithmeticOpTest {
             NDArray lhs = manager.create(new float[] {5, 10, -3, 4, 2, 7}, new Shape(2, 3));
             NDArray rhs = manager.create(new float[] {2, 9, 3}, new Shape(3, 1));
             NDArray expected = manager.create(new float[] {91, 47}, new Shape(2, 1));
-            Assert.assertEquals(lhs.matMul(rhs), expected);
+            Assert.assertEquals(NDArrays.matMul(lhs, rhs), expected);
             // 3D * 2D
             lhs = manager.arange(24f).reshape(2, 3, 4);
             rhs = manager.arange(12f).reshape(4, 3);
@@ -627,8 +648,8 @@ public class NDArrayElementArithmeticOpTest {
     public void testPowScalar() {
         try (NDManager manager = NDManager.newBaseManager()) {
             NDArray array = manager.create(new float[] {6, 0, -1, 5, 2}, new Shape(1, 5));
-            NDArray result = array.pow(2);
-            NDArray inPlaceResult = array.powi(2);
+            NDArray result = NDArrays.pow(array, 2);
+            NDArray inPlaceResult = NDArrays.powi(array, 2);
             NDArray expected = manager.create(new float[] {36, 0, 1, 25, 4}, new Shape(1, 5));
             Assertions.assertAlmostEquals(result, expected);
             Assertions.assertInPlaceAlmostEquals(inPlaceResult, expected, array);
diff --git a/integration/src/main/java/ai/djl/integration/tests/ndarray/NDArrayElementComparisonOpTest.java b/integration/src/main/java/ai/djl/integration/tests/ndarray/NDArrayElementComparisonOpTest.java
index dc6ffc874..6842cc5de 100644
--- a/integration/src/main/java/ai/djl/integration/tests/ndarray/NDArrayElementComparisonOpTest.java
+++ b/integration/src/main/java/ai/djl/integration/tests/ndarray/NDArrayElementComparisonOpTest.java
@@ -28,24 +28,36 @@ public class NDArrayElementComparisonOpTest {
         try (NDManager manager = NDManager.newBaseManager()) {
             NDArray array1 = manager.create(new float[] {1f, 2f});
             NDArray array2 = manager.create(new float[] {1f, 2f});
-            Assert.assertTrue(array1.contentEquals(array2));
+            Assert.assertTrue(NDArrays.shapeEquals(array1, array2));
+            Assert.assertTrue(NDArrays.contentEquals(array1, array2));
+            Assert.assertFalse(NDArrays.neq(array1, array2).getBoolean(0));
             array1 = manager.ones(new Shape(2, 3));
             array2 = manager.ones(new Shape(1, 3));
             Assert.assertFalse(array1.contentEquals(array2));
 
             // test scalar
+            Assert.assertFalse(NDArrays.contentEquals(null, 1));
+
             array1 = manager.create(5f);
             array2 = manager.create(5f);
             Assert.assertTrue(array1.contentEquals(array2));
+            Assert.assertTrue(NDArrays.contentEquals(array1, 5f));
+            Assert.assertTrue(NDArrays.eq(5f, array1).all().getBoolean());
+            Assert.assertFalse(NDArrays.neq(5f, array1).all().getBoolean());
+
             array1 = manager.create(3);
             array2 = manager.create(4);
             Assert.assertFalse(array1.contentEquals(array2));
 
             // different data type
-            array1 = manager.create(4f);
-            array2 = manager.create(4);
+            array1 = manager.create(1f);
+            array2 = manager.create(1d);
             Assert.assertFalse(array1.contentEquals(array2));
 
+            // boolean type
+            array1 = manager.create(true);
+            Assert.assertFalse(NDArrays.contentEquals(array1, 1));
+
             // test zero dim vs zero dim
             array1 = manager.create(new Shape(4, 0));
             array2 = manager.create(new Shape(4, 0));
@@ -171,6 +183,9 @@ public class NDArrayElementComparisonOpTest {
             NDArray result = NDArrays.gt(array, 2);
             NDArray expected = manager.create(new boolean[] {false, false, false, false, true});
             Assert.assertEquals(result, expected, "greater_scalar: Incorrect comparison");
+            result = NDArrays.gt(2, array);
+            Assert.assertTrue(result.getBoolean(0));
+
             array =
                     manager.create(
                             new float[] {2f, 3f, -5f, 2f, 5f, 10f, 20123f, -355f},
@@ -241,6 +256,9 @@ public class NDArrayElementComparisonOpTest {
             NDArray result = NDArrays.gte(array, 2);
             NDArray expected = manager.create(new boolean[] {false, true, true, true});
             Assert.assertEquals(result, expected, "greater_equals_scalar: Incorrect comparison");
+            result = NDArrays.gte(2, array);
+            Assert.assertTrue(result.getBoolean(0));
+
             array = manager.create(new float[] {3f, 2f, 2f, 4f, 5f, 3f}, new Shape(3, 2));
             result = NDArrays.gte(array, 3f);
             expected =
@@ -308,6 +326,9 @@ public class NDArrayElementComparisonOpTest {
             NDArray result = NDArrays.lt(array, 2);
             NDArray expected = manager.create(new boolean[] {true, false, false, false, false});
             Assert.assertEquals(result, expected, "lesser_scalar: Incorrect comparison");
+            result = NDArrays.lt(2, array);
+            Assert.assertFalse(result.getBoolean(0));
+
             array =
                     manager.create(
                             new float[] {2.2322f, 2.3222f, 2.3333f, 2.2222f}, new Shape(2, 2));
@@ -386,6 +407,9 @@ public class NDArrayElementComparisonOpTest {
                                 true, true, true, true, true, false, false, false, false, false
                             });
             Assert.assertEquals(result, expected);
+            result = NDArrays.lte(2, array);
+            Assert.assertFalse(result.getBoolean(0));
+
             array = manager.create(new float[] {0.1f, 0.2f, 0.3f, 0.4f}, new Shape(2, 2, 1));
             result = NDArrays.lte(array, 0.2f);
             expected = manager.create(new boolean[] {true, true, false, false}, new Shape(2, 2, 1));
@@ -446,33 +470,25 @@ public class NDArrayElementComparisonOpTest {
     public void testMaximumScalar() {
         try (NDManager manager = NDManager.newBaseManager()) {
             NDArray array = manager.arange(10.0f);
-            NDArray result = array.maximum(4.0f);
+            NDArray result = NDArrays.maximum(4f, array);
             NDArray expected = manager.create(new float[] {4f, 4f, 4f, 4f, 4f, 5f, 6f, 7f, 8f, 9f});
             Assert.assertEquals(result, expected);
-            result = NDArrays.maximum(array, 4f);
-            Assert.assertEquals(result, expected);
 
             array = manager.create(new float[] {0.1f, 0.2f, 0.3f, 0.4f}, new Shape(2, 2, 1));
-            result = array.maximum(0.2f);
+            result = NDArrays.maximum(0.2f, array);
             expected = manager.create(new float[] {0.2f, 0.2f, 0.3f, 0.4f}, new Shape(2, 2, 1));
             Assert.assertEquals(result, expected);
-            result = NDArrays.maximum(array, 0.2f);
-            Assert.assertEquals(result, expected);
 
             // test scalar
             array = manager.create(3.9999f);
-            result = array.maximum(4.0f);
+            result = NDArrays.maximum(4f, array);
             expected = manager.create(4f);
             Assert.assertEquals(result, expected);
-            result = NDArrays.maximum(array, 4f);
-            Assert.assertEquals(result, expected);
 
             // test zero-dim
             array = manager.create(new Shape(2, 0, 3, 0, 1, 0));
-            result = array.maximum(2f);
-            expected = manager.create(new Shape(2, 0, 3, 0, 1, 0));
-            Assert.assertEquals(result, expected);
             result = NDArrays.maximum(array, 2f);
+            expected = manager.create(new Shape(2, 0, 3, 0, 1, 0));
             Assert.assertEquals(result, expected);
         }
     }
@@ -482,47 +498,37 @@ public class NDArrayElementComparisonOpTest {
         try (NDManager manager = NDManager.newBaseManager()) {
             NDArray array1 = manager.create(new float[] {1f, 2f, 3f, 4f, 5f});
             NDArray array2 = manager.create(new float[] {5f, 4f, 3f, 2f, 1f});
-            NDArray result = array1.maximum(array2);
+            NDArray result = NDArrays.maximum(array1, array2);
             NDArray expected = manager.create(new float[] {5f, 4f, 3f, 4f, 5f});
             Assert.assertEquals(result, expected);
-            result = NDArrays.maximum(array1, array2);
-            Assert.assertEquals(result, expected);
 
             array1 = manager.arange(10.0f).reshape(new Shape(2, 5));
             array2 = manager.create(new float[] {4f, 5f}, new Shape(2, 1));
-            result = array1.maximum(array2);
+            result = NDArrays.maximum(array1, array2);
             expected =
                     manager.create(
                             new float[] {4f, 4f, 4f, 4f, 4f, 5f, 6f, 7f, 8f, 9f}, new Shape(2, 5));
             Assert.assertEquals(result, expected);
-            result = NDArrays.maximum(array1, array2);
-            Assert.assertEquals(result, expected);
 
             // test scalar with scalar
             array1 = manager.create(0f);
             array2 = manager.create(1f);
-            result = array1.maximum(array2);
-            expected = manager.create(1f);
-            Assert.assertEquals(result, expected);
             result = NDArrays.maximum(array1, array2);
+            expected = manager.create(1f);
             Assert.assertEquals(result, expected);
 
             // test NDArray with scalar
             array1 = manager.create(3f);
             array2 = manager.create(new float[] {3f, 3f, 3f, 2f}, new Shape(2, 2));
-            result = array1.maximum(array2);
-            expected = manager.ones(new Shape(2, 2)).mul(3);
-            Assert.assertEquals(result, expected);
             result = NDArrays.maximum(array1, array2);
+            expected = manager.ones(new Shape(2, 2)).mul(3);
             Assert.assertEquals(result, expected);
 
             // test zero-dim with zero-dim
             array1 = manager.create(new Shape(0, 0, 1));
             array2 = manager.create(new Shape(1, 0, 0));
-            result = array1.maximum(array2);
-            expected = manager.create(new Shape(0, 0, 0));
-            Assert.assertEquals(result, expected);
             result = NDArrays.maximum(array1, array2);
+            expected = manager.create(new Shape(0, 0, 0));
             Assert.assertEquals(result, expected);
         }
     }
@@ -531,33 +537,25 @@ public class NDArrayElementComparisonOpTest {
     public void testMinimumScalar() {
         try (NDManager manager = NDManager.newBaseManager()) {
             NDArray array = manager.arange(10.0f);
-            NDArray result = array.minimum(4f);
+            NDArray result = NDArrays.minimum(4f, array);
             NDArray expected = manager.create(new float[] {0f, 1f, 2f, 3f, 4f, 4f, 4f, 4f, 4f, 4f});
             Assert.assertEquals(result, expected);
-            result = NDArrays.minimum(array, 4f);
-            Assert.assertEquals(result, expected);
 
             array = manager.create(new float[] {0.1f, 0.2f, 0.3f, 0.4f}, new Shape(2, 2, 1));
-            result = array.minimum(0.2f);
-            expected = manager.create(new float[] {0.1f, 0.2f, 0.2f, 0.2f}, new Shape(2, 2, 1));
-            Assert.assertEquals(result, expected);
             result = NDArrays.minimum(array, 0.2f);
+            expected = manager.create(new float[] {0.1f, 0.2f, 0.2f, 0.2f}, new Shape(2, 2, 1));
             Assert.assertEquals(result, expected);
 
             // test scalar
             array = manager.create(3.9999f);
-            result = array.minimum(4f);
-            expected = manager.create(3.9999f);
-            Assert.assertEquals(result, expected);
             result = NDArrays.minimum(array, 4f);
+            expected = manager.create(3.9999f);
             Assert.assertEquals(result, expected);
 
             // test zero-dim
             array = manager.create(new Shape(1, 0));
-            result = array.minimum(2f);
-            expected = manager.create(new Shape(1, 0));
-            Assert.assertEquals(result, expected);
             result = NDArrays.minimum(array, 2f);
+            expected = manager.create(new Shape(1, 0));
             Assert.assertEquals(result, expected);
         }
     }
@@ -567,47 +565,37 @@ public class NDArrayElementComparisonOpTest {
         try (NDManager manager = NDManager.newBaseManager()) {
             NDArray array1 = manager.create(new float[] {1f, 2f, 3f, 4f, 5f});
             NDArray array2 = manager.create(new float[] {5f, 4f, 3f, 2f, 1f});
-            NDArray result = array1.minimum(array2);
+            NDArray result = NDArrays.minimum(array1, array2);
             NDArray expected = manager.create(new float[] {1f, 2f, 3f, 2f, 1f});
             Assert.assertEquals(result, expected);
-            result = NDArrays.minimum(array1, array2);
-            Assert.assertEquals(result, expected);
 
             array1 = manager.arange(10.0f).reshape(new Shape(2, 5));
             array2 = manager.create(new float[] {4f, 5f}, new Shape(2, 1));
-            result = array1.minimum(array2);
+            result = NDArrays.minimum(array1, array2);
             expected =
                     manager.create(
                             new float[] {0f, 1f, 2f, 3f, 4f, 5f, 5f, 5f, 5f, 5f}, new Shape(2, 5));
             Assert.assertEquals(result, expected);
-            result = NDArrays.minimum(array1, array2);
-            Assert.assertEquals(result, expected);
 
             // test scalar with scalar
             array1 = manager.create(0f);
             array2 = manager.create(1f);
-            result = array1.minimum(array2);
-            expected = manager.create(0f);
-            Assert.assertEquals(result, expected);
             result = NDArrays.minimum(array1, array2);
+            expected = manager.create(0f);
             Assert.assertEquals(result, expected);
 
             // test NDArray with scalar
             array1 = manager.create(3f);
             array2 = manager.create(new float[] {3f, 3f, 3f, 2f}, new Shape(2, 2));
-            result = array1.minimum(array2);
-            expected = manager.create(new float[] {3f, 3f, 3f, 2f}, new Shape(2, 2));
-            Assert.assertEquals(result, expected);
             result = NDArrays.minimum(array1, array2);
+            expected = manager.create(new float[] {3f, 3f, 3f, 2f}, new Shape(2, 2));
             Assert.assertEquals(result, expected);
 
             // test zero-dim with zero-dim
             array1 = manager.create(new Shape(0, 0, 1));
             array2 = manager.create(new Shape(1, 0, 0));
-            result = array1.minimum(array2);
-            expected = manager.create(new Shape(0, 0, 0));
-            Assert.assertEquals(result, expected);
             result = NDArrays.minimum(array1, array2);
+            expected = manager.create(new Shape(0, 0, 0));
             Assert.assertEquals(result, expected);
         }
     }
diff --git a/integration/src/main/java/ai/djl/integration/tests/ndarray/NDArrayOtherOpTest.java b/integration/src/main/java/ai/djl/integration/tests/ndarray/NDArrayOtherOpTest.java
index 814ec62f7..663044695 100644
--- a/integration/src/main/java/ai/djl/integration/tests/ndarray/NDArrayOtherOpTest.java
+++ b/integration/src/main/java/ai/djl/integration/tests/ndarray/NDArrayOtherOpTest.java
@@ -316,8 +316,12 @@ public class NDArrayOtherOpTest {
             NDArray array = manager.create(new float[][] {{1, 2, 3}, {4, 5, 6}});
             NDArray sequenceLength = manager.create(new float[] {1, 2});
             NDArray expected = manager.create(new float[][] {{1, 0, 0}, {4, 5, 0}});
-            Assert.assertEquals(array.sequenceMask(sequenceLength), expected);
-            Assert.assertEquals(NDArrays.sequenceMask(array, sequenceLength), expected);
+            NDArray result = NDArrays.sequenceMask(array, sequenceLength);
+            Assert.assertEquals(result, expected);
+
+            result = NDArrays.sequenceMask(array, sequenceLength, -1f);
+            expected = manager.create(new float[][] {{1, -1, -1}, {4, 5, -1}});
+            Assert.assertEquals(result, expected);
 
             // test zero dimension
             array = manager.create(new Shape(1, 0, 0));
@@ -841,7 +845,7 @@ public class NDArrayOtherOpTest {
             // test 1-D
             NDArray array = manager.create(new float[] {0f, 0.5f, -1f});
             NDArray expected = manager.create(new float[] {0f, 0.4769f, Float.NEGATIVE_INFINITY});
-            Assertions.assertAlmostEquals(array.erfinv(), expected);
+            Assertions.assertAlmostEquals(NDArrays.erfinv(array), expected);
             // test 3-D
             array = manager.linspace(-1.0f, 1.0f, 9).reshape(3, 1, 3);
             expected =
diff --git a/integration/src/main/java/ai/djl/integration/tests/ndarray/NDArrayShapesManipulationOpTest.java b/integration/src/main/java/ai/djl/integration/tests/ndarray/NDArrayShapesManipulationOpTest.java
index 50709beed..dae21cb79 100644
--- a/integration/src/main/java/ai/djl/integration/tests/ndarray/NDArrayShapesManipulationOpTest.java
+++ b/integration/src/main/java/ai/djl/integration/tests/ndarray/NDArrayShapesManipulationOpTest.java
@@ -180,6 +180,8 @@ public class NDArrayShapesManipulationOpTest {
     @Test
     public void testStack() {
         try (NDManager manager = NDManager.newBaseManager()) {
+            Assert.assertThrows(() -> NDArrays.stack(new NDList()));
+
             NDArray array1 = manager.create(new float[] {1f, 2f});
             NDArray array2 = manager.create(new float[] {3f, 4f});
 
@@ -239,15 +241,14 @@ public class NDArrayShapesManipulationOpTest {
         try (NDManager manager = NDManager.newBaseManager()) {
             NDArray array1 = manager.create(new float[] {1f});
             NDArray array2 = manager.create(new float[] {2f});
+
             NDArray expected = manager.create(new float[] {1f, 2f});
-            Assert.assertEquals(NDArrays.concat(new NDList(array1, array2), 0), expected);
-            Assert.assertEquals(array1.concat(array2), expected);
+            Assert.assertEquals(NDArrays.concat(new NDList(array1, array2)), expected);
 
             array1 = manager.create(new float[] {1f, 2f, 3f, 4f}, new Shape(2, 2));
             array2 = manager.create(new float[] {5f, 6f, 7f, 8f}, new Shape(2, 2));
             expected = manager.create(new float[] {1f, 2f, 3f, 4f, 5f, 6f, 7, 8f}, new Shape(4, 2));
             Assert.assertEquals(NDArrays.concat(new NDList(array1, array2)), expected);
-            Assert.assertEquals(array1.concat(array2), expected);
             expected =
                     manager.create(new float[] {1f, 2f, 5f, 6f, 3f, 4f, 7f, 8f}, new Shape(2, 4));
             Assert.assertEquals(NDArrays.concat(new NDList(array1, array2), 1), expected);
@@ -258,10 +259,8 @@ public class NDArrayShapesManipulationOpTest {
             // zero-dim
             array1 = manager.create(new Shape(0, 1));
             expected = manager.create(new Shape(0, 1));
-            Assert.assertEquals(array1.concat(array1), expected);
             Assert.assertEquals(NDArrays.concat(new NDList(array1, array1)), expected);
             expected = manager.create(new Shape(0, 2));
-            Assert.assertEquals(array1.concat(array1, 1), expected);
             Assert.assertEquals(NDArrays.concat(new NDList(array1, array1), 1), expected);
 
             // scalar
@@ -271,8 +270,12 @@ public class NDArrayShapesManipulationOpTest {
 
             // one array
             array1 = manager.ones(new Shape(2, 2));
-            expected = manager.ones(new Shape(2, 2));
-            Assert.assertEquals(NDArrays.concat(new NDList(array1)), expected);
+            Assert.assertEquals(NDArrays.concat(new NDList(array1)), array1);
+
+            Assert.assertThrows(() -> NDArrays.concat(new NDList()));
+
+            NDList list = new NDList(manager.ones(new Shape(2)), manager.ones(new Shape(3, 1)));
+            Assert.assertThrows(() -> NDArrays.concat(list));
         }
     }