OpenQASM3 Transport Roundtrip

This tutorial shows how to serialize a QPP HamiltonianGate circuit to an OpenQASM3-compatible transport format and load it back into an executable QPP circuit.

The transport helpers are:

  • dumps_qpp_openqasm3

  • loads_qpp_openqasm3

Imports

We import the QPP gate classes, OpenQASM3 transport helpers, and a local sampler backend.

[1]:
"""OpenQASM3 transport roundtrip tutorial."""

from qiskit.circuit import QuantumCircuit
from qiskit_pasqal_provider.providers.gate import (
    HamiltonianGate,
    InterpolatePoints,
    dumps_qpp_openqasm3,
    loads_qpp_openqasm3,
)
from qiskit_pasqal_provider.providers.provider import PasqalProvider
from qiskit_pasqal_provider.providers.sampler import SamplerV2

Build The Original Program

Create a circuit with one Pasqal analog HamiltonianGate.

[2]:
coords = [[0, 0], [3, 5.2], [6, 0], [9, -5.2], [9, 5.2], [12, 0]]
times = [0, 0.2, 0.8, 1]
ampl = InterpolatePoints(values=[0, 4, 4, 0], times=times)
det = InterpolatePoints(values=[-10, -10, -5, -5], times=times)

qc = QuantumCircuit(len(coords))
qc.append(HamiltonianGate(ampl, det, 0.0, coords), qc.qubits)
print(qc)
     ┌─────┐
q_0: ┤0    ├
     │     │
q_1: ┤1    ├
     │     │
q_2: ┤2    ├
     │  Hg │
q_3: ┤3    ├
     │     │
q_4: ┤4    ├
     │     │
q_5: ┤5    ├
     └─────┘

Run Original Program

Run the original circuit first so we have a baseline before conversion.

[3]:
sampler = SamplerV2(PasqalProvider().get_backend("qutip"))
original_result = sampler.run([qc], shots=100).result()
print(original_result[0].data.counts)
Counter({'000000': 31, '001000': 17, '000010': 12, '000001': 9, '100000': 9, '000100': 7, '010000': 7, '010001': 4, '100100': 1, '100010': 1, '001010': 1, '010100': 1})

Serialize The Sequence To OpenQASM3 Transport Format

Serialize the circuit to OpenQASM3 transport format and inspect the content.

[4]:
QASM_PROGRAM = dumps_qpp_openqasm3(qc)
print("\n".join(QASM_PROGRAM.splitlines()[:8]))
OPENQASM 3.0;
include "stdgates.inc";
gate HG(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25, p26, p27, p28, p29, p30, p31, p32, p33, p34, p35, p36, p37, p38, p39) q0, q1, q2, q3, q4, q5 {}
qubit[6] q;
HG(1.0, 6.0, 1.0, 0, 0, 1000.0, 4.0, 4.0, 0, 4.0, 4.0, 0, -6.5, -0.8666666666666667, -3.5, 4.333333333333334, -0.5, -0.8666666666666667, 2.5, -6.066666666666666, 2.5, 4.333333333333334, 5.5, -0.8666666666666667, 0, 4.0, 4.0, 0, 0, 0.2, 0.8, 1.0, -10.0, -10.0, -5.0, -5.0, 0, 0.2, 0.8, 1.0) q[0], q[1], q[2], q[3], q[4], q[5];

Run Restored Program

Run the restored circuit. Both circuits should execute, and should have the same probability distribution.

[5]:
restored = loads_qpp_openqasm3(QASM_PROGRAM)
print("original:", qc.num_qubits, qc.count_ops())
print("restored:", restored.num_qubits, restored.count_ops())
restored_result = sampler.run([restored], shots=100).result()
print(restored_result[0].data.counts)
original: 6 OrderedDict({'HG': 1})
restored: 6 OrderedDict({'HG': 1})
Counter({'000000': 33, '001000': 16, '000001': 9, '000010': 9, '100000': 8, '000100': 7, '010000': 7, '100001': 3, '010001': 3, '100010': 2, '010100': 1, '000110': 1, '100110': 1})