Repository: intel/ipex-llm
Pull request: Big dl#1115 Refine the toString() method for too large tensor
## What changes were proposed in this pull request?
If the tensor is too large, then only print part of it. (The contents are same with those printed from NumPy)

## How was this patch tested?
Test on some points.

1. val t = new DenseTensor[Float](1000).rand()
    println(t)
-------------------------Output will be-------------------------------
0.31882846
0.27059832
0.47964677
...
0.143129
0.4585869
0.7567896
[com.intel.analytics.bigdl.tensor.DenseTensor$mcF$sp of size 1000]

2. val s = new DenseTensor[Float](50, 50).rand()
    println(s)
---------------------------Output will be-------------------------------
0.9922911	0.1426482	0.34074357	...	0.9727572	0.63005745	0.106146224	
0.81868696	0.14900155	0.9119468	...	0.86367595	0.6193689	0.58570814	
0.8759203	0.4241887	0.40965104	...	0.49404338	0.528191	0.5897284	
...
0.6348343	0.70855916	0.6432477	...	0.8958019	0.54827046	0.84172016	
0.37151724	0.5005789	0.79125535	...	0.959473	0.8967095	0.41540074	
0.8393575	0.69347286	0.8194691	...	0.7552088	0.26430452	0.97799337	
[com.intel.analytics.bigdl.tensor.DenseTensor$mcF$sp of size 50x50]

3. val r = new DenseTensor[Float](2, 10, 50, 50).rand()
    println(r)

--------------------------------Output will be--------------------------------
(1,1,.,.) =
0.73664373	0.34091425	0.98170805	...	0.8734967	0.30591485	0.6041885	
0.5533396	0.6519595	0.36616018	...	0.03467839	0.9403061	0.1334226	
0.252234	0.8014631	0.10771228	...	0.24624784	0.22296661	0.61899537	
...
0.074877694	0.067801684	0.32675606	...	0.39381966	0.83774465	0.80479425	
0.14464994	0.67632943	0.044578206	...	0.40657818	0.8946445	0.48762897	
0.7326204	0.2623877	0.015385442	...	0.5244157	0.74487567	0.012629892	

(1,2,.,.) =
0.18756303	0.7422631	0.6417133	...	0.3830414	0.28951985	0.49429882	
0.98394424	0.020360265	0.17214741	...	0.10670485	0.29255602	0.07435192	
0.8332161	0.48181537	0.27788094	...	0.3443003	0.30889684	0.89243	
...
0.9644475	0.30875626	0.69045025	...	0.39485425	0.7625152	0.09252178	
0.26298398	0.4969669	0.07713879	...	0.80841815	0.9741975	0.26329386	
0.67099196	0.48931068	0.51119703	...	0.057189953	0.6529609	0.39838597	

...	

(1,9,.,.) =
0.27920187	0.4189118	0.17097268	...	0.7138378	0.04508589	0.9249899	
0.98274016	0.8560273	0.43862543	...	0.59864974	0.29078966	0.07068535	
0.8205789	0.91314095	0.79748714	...	0.5311188	0.36906698	0.032715008	
...
0.3195497	0.8347495	0.056868065	...	0.4850416	0.5301016	0.47103566	
0.07938534	0.71218055	0.10777827	...	0.38422576	0.6564963	0.21980266	
0.33414745	0.16883859	0.07406452	...	0.45196363	0.16715409	0.05988618	

(1,10,.,.) =
0.045783	0.9128971	0.54818946	...	0.7530877	0.5996848	0.5945334	
0.5159364	0.5193663	0.39760882	...	0.3548471	0.5781682	0.40564004	
0.24972008	0.25078306	0.95838845	...	0.489688	0.7540317	0.9013912	
...
0.48254606	0.18095767	0.5746312	...	0.5164861	0.50949466	0.5915085	
0.035040047	0.14677846	0.66221595	...	0.3921793	0.9606486	0.75896925	
0.25878987	0.680814	0.61653596	...	0.6832254	0.8271756	0.036464904	

(2,1,.,.) =
0.51512724	0.85686964	0.4084656	...	0.7788231	0.17165376	0.576268	
0.5506615	0.036746435	0.8039694	...	0.739184	0.63463557	0.29164702	
0.63812965	0.81216455	0.74780273	...	0.76588625	0.419554	0.7539209	
...
0.27764234	0.21818687	0.5466596	...	0.7095426	0.09723987	0.07939362	
0.40429887	0.9068113	0.64557946	...	0.5921543	0.96021247	0.1525444	
0.7686338	0.48241535	0.59231794	...	0.9656395	0.88699424	0.6092012	

(2,2,.,.) =
0.16694143	0.3446699	0.28314045	...	0.29856858	0.26359934	0.24301103	
0.4493327	0.1718516	0.1003243	...	0.8701953	0.5405458	0.7301564	
0.17642625	0.8255309	0.80489767	...	0.40970626	0.1851124	0.71890074	
...
0.83647084	0.124196544	0.8619636	...	0.16307464	0.8554219	0.8849782	
0.8299958	0.08265234	0.3267689	...	0.91398853	0.28121412	0.64596575	
0.27914056	0.79857266	0.6702896	...	0.8622594	0.23778655	0.98527116	

...

(2,9,.,.) =
0.94730943	0.41524965	0.58858955	...	0.11237109	0.87045974	0.48493406	
0.0808726	0.74816585	0.06544701	...	0.9358402	0.085241824	0.4649792	
0.472844	0.92728645	0.40462643	...	0.0040615564	0.0075219935	0.9630647	
...
0.018688973	0.14159247	0.27362025	...	0.9205142	0.05760701	0.0770698	
0.60336655	0.2017778	0.2945312	...	0.34238398	0.7294401	0.8612588	
0.6042019	0.3306946	0.8033564	...	0.61135495	0.630336	0.1765287	

(2,10,.,.) =
0.49018848	0.2677918	0.4911075	...	0.15417756	0.7357931	0.68804425	
0.7871515	0.3073748	0.28048676	...	0.3133077	0.3506843	0.6140712	
0.0773573	0.05727781	0.31386748	...	0.35580918	0.47945824	0.11913491	
...
0.43120247	0.4241725	0.8253099	...	0.03377753	0.6108334	0.84784967	
0.85712767	0.0033661362	0.37758645	...	0.21825576	0.24632587	0.7409523	
0.9838162	0.9686412	0.7255743	...	0.7174021	0.4708293	0.39709997	

[com.intel.analytics.bigdl.tensor.DenseTensor$mcF$sp of size 2x10x50x50]

## Related links or issues (optional)
fixed https://github.com/intel-analytics/BigDL/issues/1115



Problem statement:
When tensor is too large, only print a part of it in toString method
If the tensor is too large, the whole content of the tensor should not be print out. It's actually not so helpful, and create OOM error.

Here's an example in numpy:

```python
>>> np.ndarray(shape=(100000), dtype=float)
array([ 0.,  0.,  0., ...,  0.,  0.,  0.])
```

Hints from issue discussion:

Commit message: Refine the toString() method for too large tensor

(cherry picked from commit 76f7186)

Patch to review:
diff --git a/spark/dl/src/main/scala/com/intel/analytics/bigdl/tensor/DenseTensor.scala b/spark/dl/src/main/scala/com/intel/analytics/bigdl/tensor/DenseTensor.scala
index 7a4afa3f980..f55d4195004 100644
--- a/spark/dl/src/main/scala/com/intel/analytics/bigdl/tensor/DenseTensor.scala
+++ b/spark/dl/src/main/scala/com/intel/analytics/bigdl/tensor/DenseTensor.scala
@@ -1438,26 +1438,63 @@ private[tensor] class DenseTensor[@specialized T: ClassTag](
       case 0 => s"[${this.getClass.getName} with no dimension]"
       case 1 =>
         val sb = new StringBuilder
-        this.apply1(e => {
-          sb.append(e).append('\n')
-          e
-        })
+        if (this.size().product < 1000) {
+          this.apply1(e => {
+            sb.append(e).append('\n')
+            e
+          })
+        }
+        else {
+          var i = 0
+          this.apply1(e => {
+            i = i + 1
+            if (i < 3 || i > this.size(1) - 3) {
+              sb.append(e).append('\n')
+            }
+            else if (i == 3) sb.append(e).append("\n...\n")
+            e
+          })
+        }
 
         s"${sb}[${this.getClass.getName} of size ${this.size(1)}]"
       case 2 =>
         val sb = new StringBuilder
         val indexer = Array(0, 0)
-        var i = 1
-        while (i <= this.size(1)) {
-          var j = 1
-          while (j <= this.size(2)) {
-            indexer(0) = i
-            indexer(1) = j
-            sb.append(this.apply(indexer)).append('\t')
-            j += 1
+        if (this.size().product < 1000) {
+          var i = 1
+          while (i <= this.size(1)) {
+            var j = 1
+            while (j <= this.size(2)) {
+              indexer(0) = i
+              indexer(1) = j
+              sb.append(this.apply(indexer)).append('\t')
+              j += 1
+            }
+            sb.append('\n')
+            i += 1
+          }
+        }
+        else {
+          var i = 1
+          while (i <= this.size(1)) {
+            var j = 1
+            if (i <= 3 || i > this.size(1) - 3) {
+              while (j <= this.size(2)) {
+                indexer(0) = i
+                indexer(1) = j
+                if (j < 3 || j > this.size(2) - 3) {
+                  sb.append(this.apply(indexer)).append('\t')
+                }
+                else if (j == 3) {
+                  sb.append(this.apply(indexer)).append("\t...\t")
+                }
+                j += 1
+              }
+              sb.append('\n')
+              if (i == 3) sb.append("...\n")
+            }
+            i += 1
           }
-          sb.append('\n')
-          i += 1
         }
 
         s"${sb}[${this.getClass.getName} of size ${this.size(1)}x${this.size(2)}]"
@@ -1472,29 +1509,68 @@ private[tensor] class DenseTensor[@specialized T: ClassTag](
         val total = this.nElement()
         while (!done) {
           // print header
-          sb.append('(')
+
           var i = 0
-          while (i < _secLastDim) {
-            sb.append(indexer(i)).append(',')
-            i += 1
+          var needPrint = true
+          if (this.size.product > 1000) {
+            while (i < _secLastDim) {
+              if (indexer(i) <= 3 || indexer(i) > size(i) - 3) i += 1
+              else {
+                needPrint = false
+                i = _secLastDim
+              }
+            }
           }
-          sb.append(".,.) =\n")
 
-          // print current matrix
-          i = 1
-          while (i <= this.size(_secLastDim + 1)) {
-            var j = 1
-            while (j <= this.size(_lastDim + 1)) {
-              indexer(_lastDim) = j
-              indexer(_secLastDim) = i
-              sb.append(this.apply(indexer)).append('\t')
-              j += 1
+          if (needPrint) {
+            sb.append('(')
+            i = 0
+            while (i < _secLastDim) {
+              sb.append(indexer(i)).append(',')
+              i += 1
+            }
+            sb.append(".,.) =\n")
+
+            // print current matrix
+            i = 1
+            if (this.size(_secLastDim + 1) * this.size(_lastDim + 1) < 1000) {
+              while (i <= this.size(_secLastDim + 1)) {
+                var j = 1
+                while (j <= this.size(_lastDim + 1)) {
+                  indexer(_lastDim) = j
+                  indexer(_secLastDim) = i
+                  sb.append(this.apply(indexer)).append('\t')
+                  j += 1
+                }
+                sb.append('\n')
+                i += 1
+              }
             }
+            else {
+              while (i <= this.size(_secLastDim + 1)) {
+                var j = 1
+                if (i <= 3 || i > this.size(_secLastDim + 1) - 3) {
+                  while (j <= this.size(_lastDim + 1)) {
+                    indexer(_lastDim) = j
+                    indexer(_secLastDim) = i
+                    if (j < 3 || j > this.size(_lastDim + 1) - 3) {
+                      sb.append(this.apply(indexer)).append('\t')
+                    }
+                    else if (j == 3) {
+                      sb.append(this.apply(indexer)).append("\t...\t")
+                    }
+                    j += 1
+                  }
+                  sb.append('\n')
+                  if (i == 3) sb.append("...\n")
+                }
+                i += 1
+              }
+            }
+
             sb.append('\n')
-            i += 1
           }
 
-          sb.append('\n')
           indexer(d) = indexer(d) + 1
           while (d >= 0 && indexer(d) > size(d)) {
             indexer(d) = 1
diff --git a/spark/dl/src/test/scala/com/intel/analytics/bigdl/tensor/DenseTensorSpec.scala b/spark/dl/src/test/scala/com/intel/analytics/bigdl/tensor/DenseTensorSpec.scala
index 8719e55d96f..d96ba344871 100644
--- a/spark/dl/src/test/scala/com/intel/analytics/bigdl/tensor/DenseTensorSpec.scala
+++ b/spark/dl/src/test/scala/com/intel/analytics/bigdl/tensor/DenseTensorSpec.scala
@@ -299,7 +299,7 @@ class DenseTensorSpec extends FlatSpec with Matchers {
     t.valueAt(3) should be(3)
   }
 
-  "resise as" should "get the correct tensor" in {
+  "resize as" should "get the correct tensor" in {
     val t: Tensor[Double] = new DenseTensor[Double](3, 4)
     val t1: Tensor[Double] = new DenseTensor[Double](5, 5)
     val t2: Tensor[Double] = new DenseTensor[Double](2, 2)
@@ -487,6 +487,39 @@ class DenseTensorSpec extends FlatSpec with Matchers {
     println(t)
   }
 
+  "toString" should "be elegant if the tensor is too large" in {
+    val t = new DenseTensor[Float](1000)
+    var i = 0
+    t.apply1(v => {
+      i = i + 1; i
+    })
+    val OneD_STRING =
+      "1.0\n2.0\n3.0\n...\n998.0\n999.0\n1000.0\n" +
+        "[com.intel.analytics.bigdl.tensor.DenseTensor$mcF$sp of size 1000]"
+    t.toString should be(OneD_STRING)
+    val s = new DenseTensor[Float](50, 50)
+    i = 0
+    s.apply1(v => {
+      i = i + 1; i
+    })
+    val MATRIX_STRING =
+      "1.0\t2.0\t3.0\t...\t48.0\t49.0\t50.0\t\n" +
+        "51.0\t52.0\t53.0\t...\t98.0\t99.0\t100.0\t\n" +
+        "101.0\t102.0\t103.0\t...\t148.0\t149.0\t150.0\t\n" +
+        "...\n" +
+        "2351.0\t2352.0\t2353.0\t...\t2398.0\t2399.0\t2400.0\t\n" +
+        "2401.0\t2402.0\t2403.0\t...\t2448.0\t2449.0\t2450.0\t\n" +
+        "2451.0\t2452.0\t2453.0\t...\t2498.0\t2499.0\t2500.0\t\n" +
+        "[com.intel.analytics.bigdl.tensor.DenseTensor$mcF$sp of size 50x50]"
+    s.toString should be(MATRIX_STRING)
+    val r = new DenseTensor[Float](2, 10, 50, 50)
+    i = 0
+    r.apply1(v => {
+      i = i + 1; i
+    })
+    println(r)
+  }
+
   "squeeze" should "be correct" in {
     var t: Tensor[Double] = new DenseTensor[Double](3, 1, 2, 1)
     t.squeeze()


Code review comments:
diff_hunk: @@ -1438,26 +1438,63 @@ private[tensor] class DenseTensor[@specialized T: ClassTag](
       case 0 => s"[${this.getClass.getName} with no dimension]"
       case 1 =>
         val sb = new StringBuilder
-        this.apply1(e => {
-          sb.append(e).append('\n')
-          e
-        })
+        if (this.size().product < 1000) {
+          this.apply1(e => {
+            sb.append(e).append('\n')
+            e
+          })
+        }
+        else {
+          var i = 0
+          this.apply1(e => {
+            i = i + 1
+            if (i < 3 || i > this.size(1) - 3) {
+              sb.append(e).append('\n')
+            }
+            else if (i == 3) sb.append(e).append("\n...\n")
+            e
+          })
+        }
 
         s"${sb}[${this.getClass.getName} of size ${this.size(1)}]"
       case 2 =>
         val sb = new StringBuilder
         val indexer = Array(0, 0)
-        var i = 1
-        while (i <= this.size(1)) {
-          var j = 1
-          while (j <= this.size(2)) {
-            indexer(0) = i
-            indexer(1) = j
-            sb.append(this.apply(indexer)).append('\t')
-            j += 1
+        if (this.size().product < 1000) {
path: spark/dl/src/main/scala/com/intel/analytics/bigdl/tensor/DenseTensor.scala
text: @user1:
NEVER use any magic number in your code. You should make the 1000 configurable. This piece of code is hard to maintan!

diff_hunk: @@ -1438,26 +1438,63 @@ private[tensor] class DenseTensor[@specialized T: ClassTag](
       case 0 => s"[${this.getClass.getName} with no dimension]"
       case 1 =>
         val sb = new StringBuilder
-        this.apply1(e => {
-          sb.append(e).append('\n')
-          e
-        })
+        if (this.size().product < 1000) {
path: spark/dl/src/main/scala/com/intel/analytics/bigdl/tensor/DenseTensor.scala
text: @user1:
make the 1000 configurable. 

private val foldThreshold = System.getProperty("bigdl.tensor.fold", "1000").toString