jcmgray / quimb

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

How to use TN to simulate all the bit strings? #59

Closed weiT1993 closed 4 years ago

weiT1993 commented 4 years ago

Great tutorial on using TN to simulate one bit string from qasm circuits. I am wondering if there is a method to simulate all the bit strings of a circuit? I want to benchmark the runtime of quimb in simulating the entire circuit of different sizes. Much appreciated!

jcmgray commented 4 years ago

If you want the whole wavefunction then I would do something like this:

psi = circ.psi  # get the tensor network describing the full wavefunction
psi.full_simplify_()  # try and simplify the network
psi_dense = psi.to_dense(psi.site_inds, optimize=optimize)

The final step means contract the network into a single dense vector, with one dimension corresponding to the vectorization of all the physical site indices. Performance for complex circuits is going to be heavily dependent on the optimize kwarg, i.e. the opt_einsum path optimizer to use for this contraction. You could play with different backend kwargs as well.

On the other hand, if you mean unbiased random sampling of bitstrings without constructing the full wavefunction (or assuming anything about it), I'm not still entirely sure what the best approach here is - quimb doens't offer anything automatically at the moment!

weiT1993 commented 4 years ago

I ran this script to simulate all bit strings of the 10-qubit circuit example given in the tutorial.

import quimb as qu
import quimb.tensor as qtn
import random
from tqdm import tqdm

circ = qtn.Circuit(N=10, tags='PSI0')

# initial layer of hadamards
for i in range(10):
    circ.apply_gate('H', i, gate_round=0)

# 8 rounds of entangling gates
for r in range(1, 9):

    # even pairs
    for i in range(0, 10, 2):
        circ.apply_gate('CNOT', i, i + 1, gate_round=r)

    # Y-rotations
    for i in range(10):
        circ.apply_gate('RY', 1.234, i, gate_round=r)

    # odd pairs
    for i in range(1, 9, 2):
        circ.apply_gate('CZ', i, i + 1, gate_round=r)

# final layer of hadamards
for i in range(10):
    circ.apply_gate('H', i, gate_round=r + 1)
print(circ)

psi = circ.psi  # get the tensor network describing the full wavefunction
psi.full_simplify_()  # try and simplify the network
psi_dense = psi.to_dense(psi.site_inds, optimize='random_greedy')
print(psi_dense)

But I encountered this error:

ValueError: The index _77d5eb00001d9 appears more than twice! If this is intentionally a 'hyper' tensor network you will need to explicitly supply `output_inds` when contracting for example.
jcmgray commented 4 years ago

Ah yes this is because the full simplification introduces hyper-edges, so the output indices need to be specified to the contractor. Try this as the last lines:

psi = circ.psi  # get the tensor network describing the full wavefunction
psi.full_simplify_()  # try and simplify the network
T = psi.contract(all, optimize='random-greedy', output_inds=psi.site_inds)
T.to_dense(psi.site_inds)

I probably need to update the to_dense methods for the updated simplifications.

jcmgray commented 4 years ago

Another option would be to just use rank_simplify_ rather than full_simplify_!

weiT1993 commented 4 years ago

Thanks a lot. That solves it!