jcmgray / quimb

A python library for quantum information and many-body calculations including tensor networks.
http://quimb.readthedocs.io
Other
455 stars 107 forks source link

DivisionByZero on contracting scalar TensorNetwork to path-info #231

Closed pavoljuhas closed 2 months ago

pavoljuhas commented 2 months ago

What happened?

After upgrading to quimb-1.8.0 Cirq unit tests started failing with DivisionByZero error. I have tracked this down to the TensorNetwork.contract(get="path-info") which may get called with a tensor network consisting of a single scalar tensor. Please see the example below. The same code passes without a problem with quimb-1.6.0.

What did you expect to happen?

TensorNetwork.contract would return a PathInfo object as in version 1.6.0.

Minimal Complete Verifiable Example

from quimb.tensor import Tensor, TensorNetwork

tnscalar = TensorNetwork([Tensor()])
path_info = tnscalar.contract(get="path-info")

Relevant log output

Traceback (most recent call last):
  File "/home/user/tmp/tnscalar.py", line 4, in <module>
    path_info = tnscalar.contract(get="path-info")
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/tmp/venv/py312/lib/python3.12/site-packages/quimb/tensor/tensor_core.py", line 8586, in contract
    return tensor_contract(*self.tensor_map.values(), **opts)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/tmp/venv/py312/lib/python3.12/site-packages/quimb/tensor/tensor_core.py", line 262, in tensor_contract
    return _tensor_contract_get_other(
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/tmp/venv/py312/lib/python3.12/site-packages/quimb/tensor/tensor_core.py", line 167, in _tensor_contract_get_other
    pathinfo = array_contract_pathinfo(
               ^^^^^^^^^^^^^^^^^^^^^^^^
  File "/tmp/venv/py312/lib/python3.12/site-packages/quimb/tensor/contraction.py", line 329, in array_contract_pathinfo
    return oe.contract_path(eq, *shapes, shapes=True, optimize=path)[1]
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/tmp/venv/py312/lib/python3.12/site-packages/opt_einsum/contract.py", line 327, in contract_path
    path_print = PathInfo(contraction_list, input_subscripts, output_subscript, indices, path, scale_list, naive_cost,
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/tmp/venv/py312/lib/python3.12/site-packages/opt_einsum/contract.py", line 38, in __init__
    self.speedup = self.naive_cost / self.opt_cost
                   ~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~
decimal.DivisionByZero: [<class 'decimal.DivisionByZero'>]

Anything else we need to know?

No response

Environment

jcmgray commented 2 months ago

Thanks for raising the issue. Yes the problem is that quimb has moved to contengra for all contraction related functionality. And the 'proper' path which cotengra calculates for a scalar contraction is the empty sequence, i.e. eq="->" which requires no ops, and triggers this error.

I'll either fix this opt_einsum side or put in a guard somewhere in quimb.

Also note in general I'd recommend using the cotengra.ContractionTree object now for inspecting contractions - it calculates all the relevant quantities lazily and a bit more efficiently.

jcmgray commented 2 months ago

I've just put in an explicit catch for this, and will release a new version soon.

pavoljuhas commented 1 month ago

Thank you!