DiracMG3 / Circuit-Optimization-for-Hamiltonian-Simulation

Greedy algorithm based circuit optimization for Hamiltonian simulation.
0 stars 0 forks source link

Bug: measurement after transpilation level 3 #1

Open MattePalte opened 1 year ago

MattePalte commented 1 year ago

Environment

Requirements from https://zenodo.org/record/5780204#.ZAdittLMKAk version 2

qiskit == 0.23.5
pytket == 0.11.0
pyscf == 1.7.6
numpy == 1.20.0
networkx==2.5
commentjson==0.9.0
jupyter

What is happening?

The file real_system.py inserts the measurement on a circuit after its transpilation. However, the transpilation is done with the optimization_level=3 option, which means that the measurements plays an important role in the optimization. For example, OptimizeSwapBeforeMeasure is a pass that removes the swap gates before the measurement, leading to a non-equivalent circuit (See the doc regarding this level 3: here). In the line 39 of the current code, adding the measurement to qc1 after the transpilation prevents them from being used in the optimization and ultimately leads to a different circuit. See the different qasm of the generated code.

Original code: The measurements are placed naively in order.

barrier q[0],q[1],q[2],q[3],q[4],q[5],q[6],q[7],q[8],q[9],q[10],q[11],q[12],q[13];
measure q[0] -> meas[0];
measure q[1] -> meas[1];
measure q[2] -> meas[2];
measure q[3] -> meas[3];
measure q[4] -> meas[4];
measure q[5] -> meas[5];
measure q[6] -> meas[6];
measure q[7] -> meas[7];
measure q[8] -> meas[8];
measure q[9] -> meas[9];
measure q[10] -> meas[10];
measure q[11] -> meas[11];
measure q[12] -> meas[12];
measure q[13] -> meas[13];

Adding the measurement before transpilation: The measurement are optimized with level 3:

barrier q[4],q[3],q[2],q[1],q[0],q[5],q[6],q[7],q[8],q[9],q[10],q[13],q[12],q[11];
measure q[4] -> meas[0];   # DIFFERENT MAPPING
measure q[3] -> meas[1];   # DIFFERENT MAPPING
measure q[2] -> meas[2];
measure q[1] -> meas[3];   # DIFFERENT MAPPING
measure q[0] -> meas[4];   # DIFFERENT MAPPING
measure q[5] -> meas[5];
measure q[6] -> meas[6];
measure q[7] -> meas[7];
measure q[8] -> meas[8];
measure q[9] -> meas[9];
measure q[10] -> meas[10];
measure q[13] -> meas[11];  # DIFFERENT MAPPING
measure q[12] -> meas[12];
measure q[11] -> meas[13];  # DIFFERENT MAPPING

Note that the same problem happens with qc3 in the next lines.

How can we reproduce the issue?

I injected the alternative circuit in the code and I checked if the qasm codes are the same. Unfortunately it leads to different results. You can use the code below:

...
    qc1 = synth_qaoa1(a2, graph=graph, gamma=gamma, beta=beta)

    # AS PER API AND QISKIT DOCUMENTATION
    from copy import deepcopy
    qc1_alternative = deepcopy(qc1)
    qc1_alternative.measure_all()

    # TRANSPILATION
    qc1 = transpile(
        qc1, basis_gates=['u3', 'cx'],
        backend=backend, coupling_map=coup, optimization_level=3)

    # ALTERNATIVE: MEASUREMENT BEFORE TRANSPILATION
    qc1_alternative = transpile(
        qc1_alternative, basis_gates=['u3', 'cx'],
        backend=backend, coupling_map=coup, optimization_level=3)

    # ORIGINAL
    qc1.measure_all()

    # check if the ORIGINAL and the ALTERNATIVE are the same
    qasm_original = qc1.qasm()
    qasm_alternative = qc1_alternative.qasm()
    if qasm_original != qasm_alternative:
        print("Warning: qasm codes are different")
        print("Original:")
        print(qasm_original)
        print("Alternative:")
        print(qasm_alternative)
...

What should happen?

The two qasm codes should be the same, thus the optimization should consider also the measurements.

Any suggestions?

The program can be fixed by moving the measurement before the transpilation. Following the recommendation of Qiskit. See here

MattePalte commented 10 months ago

For completeness, I found the same issue in other points in the same file, namely at lines: 44, 58, 63.