Skip to content
This repository has been archived by the owner on Jul 24, 2024. It is now read-only.

Commit

Permalink
Copy qpy updates from terra/0.24.2 (#676)
Browse files Browse the repository at this point in the history
* copying updates from terra/10148

* updates from terra/10376

* fix lint

* update terra version
  • Loading branch information
kt474 committed Jul 24, 2023
1 parent 16b0da2 commit 0da5f61
Show file tree
Hide file tree
Showing 5 changed files with 168 additions and 4 deletions.
149 changes: 148 additions & 1 deletion qiskit_ibm_provider/qpy/binary_io/circuits.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import uuid
import warnings

from collections import defaultdict
import numpy as np

from qiskit import circuit as circuit_mod
Expand All @@ -34,6 +35,7 @@
from qiskit.extensions import quantum_initializer
from qiskit.quantum_info.operators import SparsePauliOp
from qiskit.synthesis import evolution as evo_synth
from qiskit.transpiler.layout import Layout, TranspileLayout
from .. import common, formats, type_keys
from . import value, schedules

Expand Down Expand Up @@ -298,6 +300,7 @@ def _read_instruction( # type: ignore[no-untyped-def]
"UCRXGate",
"UCRYGate",
"UCRZGate",
"DiagonalGate",
}:
gate = gate_class(params)
else:
Expand Down Expand Up @@ -814,6 +817,148 @@ def _write_registers(file_obj, in_circ_regs, full_bits): # type: ignore[no-unty
return len(in_circ_regs) + len(out_circ_regs)


def _write_layout(file_obj, circuit): # type: ignore[no-untyped-def]
if circuit.layout is None:
# Write a null header if there is no layout present
file_obj.write(struct.pack(formats.LAYOUT_PACK, False, -1, -1, -1, 0))
return
initial_size = -1
input_qubit_mapping = {}
initial_layout_array = []
extra_registers = defaultdict(list)
if circuit.layout.initial_layout is not None:
initial_size = len(circuit.layout.initial_layout)
layout_mapping = circuit.layout.initial_layout.get_physical_bits()
for i in range(circuit.num_qubits):
qubit = layout_mapping[i]
input_qubit_mapping[qubit] = i
if qubit._register is not None or qubit._index is not None:
if qubit._register not in circuit.qregs:
extra_registers[qubit._register].append(qubit)
initial_layout_array.append((qubit._index, qubit._register))
else:
initial_layout_array.append((None, None))
input_qubit_size = -1
input_qubit_mapping_array = []
if circuit.layout.input_qubit_mapping is not None:
input_qubit_size = len(circuit.layout.input_qubit_mapping)
input_qubit_mapping_array = [None] * input_qubit_size
layout_mapping = circuit.layout.initial_layout.get_virtual_bits()
for qubit, index in circuit.layout.input_qubit_mapping.items():
if (
getattr(qubit, "_register", None) is not None
and getattr(qubit, "_index", None) is not None
):
if qubit._register not in circuit.qregs:
extra_registers[qubit._register].append(qubit)
input_qubit_mapping_array[index] = layout_mapping[qubit]
else:
input_qubit_mapping_array[index] = layout_mapping[qubit]
final_layout_size = -1
final_layout_array = []
if circuit.layout.final_layout is not None:
final_layout_size = len(circuit.layout.final_layout)
final_layout_physical = circuit.layout.final_layout.get_physical_bits()
for i in range(circuit.num_qubits):
virtual_bit = final_layout_physical[i]
final_layout_array.append(circuit.find_bit(virtual_bit).index)

file_obj.write(
struct.pack(
formats.LAYOUT_PACK,
True,
initial_size,
input_qubit_size,
final_layout_size,
len(extra_registers),
)
)
_write_registers(
file_obj,
list(extra_registers),
[x for bits in extra_registers.values() for x in bits],
)
for index, register in initial_layout_array:
reg_name_bytes = (
None if register is None else register.name.encode(common.ENCODE)
)
file_obj.write(
struct.pack(
formats.INITIAL_LAYOUT_BIT_PACK,
-1 if index is None else index,
-1 if reg_name_bytes is None else len(reg_name_bytes),
)
)
if reg_name_bytes is not None:
file_obj.write(reg_name_bytes)
for i in input_qubit_mapping_array:
file_obj.write(struct.pack("!I", i))
for i in final_layout_array:
file_obj.write(struct.pack("!I", i))


def _read_layout(file_obj, circuit): # type: ignore[no-untyped-def]
header = formats.LAYOUT._make(
struct.unpack(formats.LAYOUT_PACK, file_obj.read(formats.LAYOUT_SIZE))
)
if not header.exists:
return
registers = {
name: QuantumRegister(len(v[1]), name)
for name, v in _read_registers_v4(file_obj, header.extra_registers)["q"].items()
}
initial_layout = None
initial_layout_virtual_bits = []
for _ in range(header.initial_layout_size):
virtual_bit = formats.INITIAL_LAYOUT_BIT._make(
struct.unpack(
formats.INITIAL_LAYOUT_BIT_PACK,
file_obj.read(formats.INITIAL_LAYOUT_BIT_SIZE),
)
)
if virtual_bit.index == -1 and virtual_bit.register_size == -1:
qubit = Qubit()
else:
register_name = file_obj.read(virtual_bit.register_size).decode(
common.ENCODE
)
if register_name in registers:
qubit = registers[register_name][virtual_bit.index]
else:
register = next(
filter(lambda x, name=register_name: x.name == name, circuit.qregs)
)
qubit = register[virtual_bit.index]
initial_layout_virtual_bits.append(qubit)
if initial_layout_virtual_bits:
initial_layout = Layout.from_qubit_list(initial_layout_virtual_bits)
input_qubit_mapping = None
input_qubit_mapping_array = []
for _ in range(header.input_mapping_size):
input_qubit_mapping_array.append(
struct.unpack("!I", file_obj.read(struct.calcsize("!I")))[0]
)
if input_qubit_mapping_array:
input_qubit_mapping = {}
physical_bits = initial_layout.get_physical_bits()
for index, bit in enumerate(input_qubit_mapping_array):
input_qubit_mapping[physical_bits[bit]] = index
final_layout = None
final_layout_array = []
for _ in range(header.final_layout_size):
final_layout_array.append(
struct.unpack("!I", file_obj.read(struct.calcsize("!I")))[0]
)

if final_layout_array:
layout_dict = {
circuit.qubits[bit]: index for index, bit in enumerate(final_layout_array)
}
final_layout = Layout(layout_dict)

circuit._layout = TranspileLayout(initial_layout, input_qubit_mapping, final_layout)


def write_circuit(file_obj, circuit, metadata_serializer=None): # type: ignore[no-untyped-def]
"""Write a single QuantumCircuit object in the file like object.
Expand Down Expand Up @@ -887,6 +1032,7 @@ def write_circuit(file_obj, circuit, metadata_serializer=None): # type: ignore[

# Write calibrations
_write_calibrations(file_obj, circuit.calibrations, metadata_serializer)
_write_layout(file_obj, circuit)


def read_circuit(file_obj, version, metadata_deserializer=None): # type: ignore[no-untyped-def]
Expand Down Expand Up @@ -1020,5 +1166,6 @@ def read_circuit(file_obj, version, metadata_deserializer=None): # type: ignore
f"as they weren't used in the circuit: {circ.name}",
UserWarning,
)

if version >= 8:
_read_layout(file_obj, circ)
return circ
2 changes: 1 addition & 1 deletion qiskit_ibm_provider/qpy/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

from . import formats

QPY_VERSION = 7
QPY_VERSION = 8
ENCODE = "utf8"


Expand Down
17 changes: 17 additions & 0 deletions qiskit_ibm_provider/qpy/formats.py
Original file line number Diff line number Diff line change
Expand Up @@ -275,3 +275,20 @@
MAP_ITEM = namedtuple("MAP_ITEM", ["key_size", "type", "size"])
MAP_ITEM_PACK = "!H1cH"
MAP_ITEM_SIZE = struct.calcsize(MAP_ITEM_PACK)

LAYOUT = namedtuple(
"LAYOUT",
[
"exists",
"initial_layout_size",
"input_mapping_size",
"final_layout_size",
"extra_registers",
],
)
LAYOUT_PACK = "!?iiiI"
LAYOUT_SIZE = struct.calcsize(LAYOUT_PACK)

INITIAL_LAYOUT_BIT = namedtuple("INITIAL_LAYOUT_BIT", ["index", "register_size"])
INITIAL_LAYOUT_BIT_PACK = "!ii"
INITIAL_LAYOUT_BIT_SIZE = struct.calcsize(INITIAL_LAYOUT_BIT_PACK)
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
qiskit-terra>=0.24.0
qiskit-terra>=0.24.2
requests>=2.19
requests_ntlm>=1.1.0
numpy>=1.13
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
import setuptools

REQUIREMENTS = [
"qiskit-terra>=0.24.0",
"qiskit-terra>=0.24.2",
"requests>=2.19",
"requests-ntlm>=1.1.0",
"numpy>=1.13",
Expand Down

0 comments on commit 0da5f61

Please sign in to comment.