ngnrsaa / qflex

Flexible Quantum Circuit Simulator (qFlex) implements an efficient tensor network, CPU-based simulator of large quantum circuits.
Apache License 2.0
97 stars 25 forks source link

Confusing error message when copying rank-0 tensors #284

Closed rmlarose closed 4 years ago

rmlarose commented 4 years ago

I'm trying to simulate a circuit through the Cirq interface without reading in files. I'm able to run qflex_cirq_example.py with no issues. I modified this to construct the same circuit and grid used in the rectangular 2x2 example (see inline comments in code below).

I find that the circuit and grid don't have to be read in from files, but when the ordering is not read in from a file, I get a memory leak.

The specific example I'm running (from the same directory as qflex_cirq_example.py) is below:

import sys
import os
sys.path.insert(
    1, os.path.realpath(os.path.dirname(os.path.realpath(__file__)) + '/../'))

import cirq

from qflexcirq.interface import (qflex_circuit, qflex_simulator, qflex_order, qflex_virtual_device)
from qflexcirq.ordering import order_circuit_simulation

if __name__ == "__main__":
    # Same grid as in config/grid/rectangular_2x2.txt
    grid = "1 1\n1 1"
    device = qflex_virtual_device.QFlexVirtualDevice(qflex_grid=grid)
    qubits = device.get_indexed_grid_qubits()
    qreg = list(qubits.values())

    # Same circuit as in config/circuits/rectangular_2x2_1-2-1.txt
    circ = cirq.Circuit([cirq.ops.H.on_each(*qreg)])
    for _ in range(2):
        circ.append([cirq.ops.T.on_each(*qreg)])
        circ.append([cirq.ops.CNOT.on(qreg[i], qreg[i + 1]) for i in (0, 2)])
        circ.append([cirq.ops.T.on_each(*qreg)])
        circ.append([cirq.ops.CNOT.on(qreg[i], qreg[i + 2]) for i in (0, 1)])
    circ.append([cirq.ops.H.on_each(*qreg)])

    # Reading in the file works
    # order = qflex_order.QFlexOrder.from_existing_file("../config/ordering/rectangular_2x2.txt")

    # Computing the order (not reading in the file) throws an error
    order_list = order_circuit_simulation.circuit_to_ordering(circ)
    order = qflex_order.QFlexOrder(order_list)

    qflex_circ = qflex_circuit.QFlexCircuit(cirq_circuit=circ, device=device, qflex_order=order)
    sim = qflex_simulator.QFlexSimulator()

    res = sim.compute_amplitudes(program=qflex_circ, bitstrings=["0000"])
    print("Result:", res)

The output of this code is:

ERROR (evaluate_circuit.cpp: EvaluateCircuit:232) --> Failed to call ContractGrid(). Error:
    [ERROR (contraction_utils.cpp: ContractGrid:637) --> Failed to call ContractGrid(). Error:
    [ERROR (tensor.cpp: _copy:109) --> Potential memory leak]]
Result: []

While if I uncomment the line

order = qflex_order.QFlexOrder.from_existing_file("../config/ordering/rectangular_2x2.txt")

and comment the next two lines, everything works fine and produces the expected output:

Result: [(1.7357669801487674e-08+0.2285532429814333j)]

The same error occurs when no explicit qflex_order argument is input to the QFlexCircuit.

95-martin-orion commented 4 years ago

Tracing down, the tensor::_copy() method reports a memory leak when trying to copy a tensor which has a non-null data pointer but no indices.

When running auto-ordering, it uses two cuts by default. On a 2x2 grid, it's possible that this produces a 1-qubit region, i.e. a zero-rank tensor. When qFlex attempts to copy this tensor, it hits the error above.

There are two steps to resolve this:

  1. If you don't actually want to use cuts (they don't help much on a 2x2 grid) specify max_cuts=0 in your circuit_to_ordering call.
  2. We should modify our behavior for copying rank-zero tensors, either by updating the error message (e.g. "This may indicate a one-qubit region") or by allowing copying of zero-rank tensors.
rmlarose commented 4 years ago

Setting max_cuts=0 in the call to circuit_to_ordering results in a different error with read_circuit.cpp:

ERROR (read_circuit.cpp: operator():230) --> Left hand side of pair not found: (0,0),(0,1).
Result: []

Setting max_cuts=1 works.