Repository: google/TensorNetwork

Issue:
Blocksparse REPL problems
Hi @mganahl , there appears to be some issues with the REPL w.r.t the Index class. For instance if I define:
```
i0 = Index(U1Charge([-1,1]), flow=False)
```
Then if I either evaluate `i0` in the REPL or try to `print(i0)` the return is simply `2`. So it appears that the REPL is set to return `i0.dim` when called, but I found this to be very confusing (I thought that I had made a mistake somewhere, and that `i0` was assigned to the integer value 2). Maybe this is not such a big deal if the Index class is going to be removed or hidden from the user, as we discussed could be an option.

Also, on a related note, it would be a great help if the REPL and print() for blocksparse tensors was more informative. At the moment only the class name is returned, but it would be useful to see the rank of the tensor, the dimension of its indices, its flows, its symmetry group(s) etc.  


Discussion:

Resolving patch:
diff --git a/tensornetwork/block_sparse/blocksparsetensor.py b/tensornetwork/block_sparse/blocksparsetensor.py
--- a/tensornetwork/block_sparse/blocksparsetensor.py
+++ b/tensornetwork/block_sparse/blocksparsetensor.py
@@ -391,6 +391,20 @@ def __rmul__(self, number: np.number) -> "ChargeArray":
   def __truediv__(self, number: np.number) -> "ChargeArray":
     raise NotImplementedError("__truediv__ not implemented for ChargeArray")
 
+  def __repr__(self):
+    if len(self._charges) > 0:
+      charge_types = self._charges[0].names
+    else:
+      charge_types = 'no charge types (scalar)'
+    output = 'BlockSparseTensor\n   shape: ' + repr(
+        self.shape
+    ) + '\n   charge types: ' + charge_types + '\n   dtype: ' + repr(
+        self.dtype.name) + '\n   flat flows: ' + repr(
+            self.flat_flows) + '\n   order: ' + repr(
+                self._order) + '\n   data:' + repr(self.data)
+
+    return output
+
   def item(self):
     if self.ndim == 0:
       if len(self.data) == 1:
@@ -505,7 +519,7 @@ def todense(self) -> np.ndarray:
     Map the sparse tensor to dense storage.
     
     """
-    if len(self.shape) == 0:
+    if self.ndim == 0:
       return self.data
     out = np.asarray(np.zeros(self.shape, dtype=self.dtype).flat)
     out[np.nonzero(
diff --git a/tensornetwork/block_sparse/charge.py b/tensornetwork/block_sparse/charge.py
--- a/tensornetwork/block_sparse/charge.py
+++ b/tensornetwork/block_sparse/charge.py
@@ -164,8 +164,8 @@ def degeneracies(self):
     return np.sum(exp1 == exp2, axis=0)
 
   def __repr__(self):
-    return str(
-        type(self)) + '\n' + 'charges: \n' + self.charges.__repr__() + '\n'
+    return 'BaseCharge object:' + '\n charge types: ' + self.names + '\n charges:' + str(
+        self.charges).replace('\n', '\n\t ') + '\n'
 
   def __iter__(self):
     return self.Iterator(self.unique_charges, self.charge_labels)
@@ -528,6 +528,10 @@ def isin(self, target_charges: Union[np.ndarray, "BaseCharge"]) -> np.ndarray:
 
     return np.isin(self.charge_labels, inds)
 
+  @property
+  def names(self):
+    return repr([ct.__new__(ct).__class__.__name__ for ct in self.charge_types])
+
 
 class U1Charge(BaseCharge):
   """Charge Class for the U1 symmetry group."""


Test patch: