From 3ed853ac10a4accd3b81d6eca5cfef62f1f22389 Mon Sep 17 00:00:00 2001 From: kevin-tian Date: Thu, 20 Jul 2023 17:37:19 -0400 Subject: [PATCH 1/4] copying updates from terra/10148 --- qiskit_ibm_provider/qpy/binary_io/circuits.py | 135 +++++++++++++++++- qiskit_ibm_provider/qpy/common.py | 2 +- qiskit_ibm_provider/qpy/formats.py | 11 ++ 3 files changed, 146 insertions(+), 2 deletions(-) diff --git a/qiskit_ibm_provider/qpy/binary_io/circuits.py b/qiskit_ibm_provider/qpy/binary_io/circuits.py index 920435c1b..0694fb66f 100644 --- a/qiskit_ibm_provider/qpy/binary_io/circuits.py +++ b/qiskit_ibm_provider/qpy/binary_io/circuits.py @@ -20,6 +20,7 @@ import uuid import warnings +from collections import defaultdict import numpy as np from qiskit import circuit as circuit_mod @@ -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 @@ -813,6 +815,135 @@ 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): + 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): + 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. @@ -887,6 +1018,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] @@ -1020,5 +1152,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 diff --git a/qiskit_ibm_provider/qpy/common.py b/qiskit_ibm_provider/qpy/common.py index 22a1fa42a..a78b712d8 100644 --- a/qiskit_ibm_provider/qpy/common.py +++ b/qiskit_ibm_provider/qpy/common.py @@ -21,7 +21,7 @@ from . import formats -QPY_VERSION = 7 +QPY_VERSION = 8 ENCODE = "utf8" diff --git a/qiskit_ibm_provider/qpy/formats.py b/qiskit_ibm_provider/qpy/formats.py index c99336980..6f0f09278 100644 --- a/qiskit_ibm_provider/qpy/formats.py +++ b/qiskit_ibm_provider/qpy/formats.py @@ -275,3 +275,14 @@ 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) From 569b4e01bf0d0dec5b1377247faf4cfe0749e87e Mon Sep 17 00:00:00 2001 From: kevin-tian Date: Thu, 20 Jul 2023 17:41:31 -0400 Subject: [PATCH 2/4] updates from terra/10376 --- qiskit_ibm_provider/qpy/binary_io/circuits.py | 1 + 1 file changed, 1 insertion(+) diff --git a/qiskit_ibm_provider/qpy/binary_io/circuits.py b/qiskit_ibm_provider/qpy/binary_io/circuits.py index 0694fb66f..558ee9a0f 100644 --- a/qiskit_ibm_provider/qpy/binary_io/circuits.py +++ b/qiskit_ibm_provider/qpy/binary_io/circuits.py @@ -300,6 +300,7 @@ def _read_instruction( # type: ignore[no-untyped-def] "UCRXGate", "UCRYGate", "UCRZGate", + "DiagonalGate", }: gate = gate_class(params) else: From 1616729e55267c8ffd00d2bd8510ef5daf83c192 Mon Sep 17 00:00:00 2001 From: kevin-tian Date: Thu, 20 Jul 2023 17:43:07 -0400 Subject: [PATCH 3/4] fix lint --- qiskit_ibm_provider/qpy/binary_io/circuits.py | 29 ++++++++++++++----- qiskit_ibm_provider/qpy/formats.py | 8 ++++- 2 files changed, 28 insertions(+), 9 deletions(-) diff --git a/qiskit_ibm_provider/qpy/binary_io/circuits.py b/qiskit_ibm_provider/qpy/binary_io/circuits.py index 558ee9a0f..d66228d29 100644 --- a/qiskit_ibm_provider/qpy/binary_io/circuits.py +++ b/qiskit_ibm_provider/qpy/binary_io/circuits.py @@ -816,7 +816,8 @@ 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): + +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)) @@ -873,10 +874,14 @@ def _write_layout(file_obj, circuit): ) ) _write_registers( - file_obj, list(extra_registers), [x for bits in extra_registers.values() for x in bits] + 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) + reg_name_bytes = ( + None if register is None else register.name.encode(common.ENCODE) + ) file_obj.write( struct.pack( formats.INITIAL_LAYOUT_BIT_PACK, @@ -892,7 +897,7 @@ def _write_layout(file_obj, circuit): file_obj.write(struct.pack("!I", i)) -def _read_layout(file_obj, circuit): +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)) ) @@ -914,11 +919,15 @@ def _read_layout(file_obj, circuit): 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) + 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)) + 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: @@ -937,10 +946,14 @@ def _read_layout(file_obj, circuit): 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]) + 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)} + 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) diff --git a/qiskit_ibm_provider/qpy/formats.py b/qiskit_ibm_provider/qpy/formats.py index 6f0f09278..912433d8d 100644 --- a/qiskit_ibm_provider/qpy/formats.py +++ b/qiskit_ibm_provider/qpy/formats.py @@ -278,7 +278,13 @@ LAYOUT = namedtuple( "LAYOUT", - ["exists", "initial_layout_size", "input_mapping_size", "final_layout_size", "extra_registers"], + [ + "exists", + "initial_layout_size", + "input_mapping_size", + "final_layout_size", + "extra_registers", + ], ) LAYOUT_PACK = "!?iiiI" LAYOUT_SIZE = struct.calcsize(LAYOUT_PACK) From e56fdeccc5bf735592ecae0de21eb8ee79b27aab Mon Sep 17 00:00:00 2001 From: kevin-tian Date: Thu, 20 Jul 2023 17:44:12 -0400 Subject: [PATCH 4/4] update terra version --- requirements.txt | 2 +- setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/requirements.txt b/requirements.txt index 121b38d47..e93987474 100644 --- a/requirements.txt +++ b/requirements.txt @@ -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 diff --git a/setup.py b/setup.py index 2b6dcd3c9..b57236b1f 100644 --- a/setup.py +++ b/setup.py @@ -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",