Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 9ad4941

Browse files
committedJun 17, 2025·
Preliminary functionizations of notebooks for fullstack, subcirc, and vanilla MCFE
1 parent 57c7853 commit 9ad4941

File tree

6 files changed

+739
-577
lines changed

6 files changed

+739
-577
lines changed
 

‎pygsti/circuits/circuit.py

Lines changed: 101 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4014,12 +4014,18 @@ def from_qiskit(cls, circuit,
40144014
40154015
Returns
40164016
-------
4017-
pygsti_circuit
4018-
A pyGSTi Circuit instance equivalent to the specified Qiskit one.
4017+
Tuple:
4018+
pygsti_circuit
4019+
A pyGSTi Circuit instance equivalent to the specified Qiskit one.
4020+
4021+
Dict {qiskit_qubit_idx, pyGSTi_qubit}
40194022
"""
40204023

40214024
try:
40224025
import qiskit
4026+
if qiskit.__version__ != '1.1.1':
4027+
print("warning: Circuit class method 'from_qiskit()' is designed for qiskit version 1.1.1 and may not \
4028+
function properly for your qiskit version, which is " + qiskit.__version__)
40234029
except ImportError:
40244030
raise ImportError("Qiskit is required for this operation, and it does not appear to be installed.")
40254031

@@ -4044,15 +4050,18 @@ def from_qiskit(cls, circuit,
40444050

40454051
#ensure all of these have a conversion available.
40464052
if qubit_conversion is not None:
4047-
if isinstance(qubit_conversion, dict):
4048-
unmapped_qubits = set(qubits).difference(set(qubit_conversion.keys()))
4049-
assert len(unmapped_qubits) == 0, f'Missing Qiskit to pygsti conversions for some qubits: {unmapped_qubits} '
4053+
unmapped_qubits = set(qubits).difference(set(qubit_conversion.keys()))
4054+
assert len(unmapped_qubits) == 0, f'Missing Qiskit to pygsti conversions for some qubits: {unmapped_qubits}'
4055+
4056+
qubit_idx_conversion = {i: qubit_conversion[circuit.qbit_argument_conversion(i)[0]] for i in range(circuit.num_qubits)}
40504057

40514058
#if it is None, build a default mapping.
40524059
else:
40534060
#default mapping is the identify mapping: qubit i in the Qiskit circuit maps to qubit i in the pyGSTi circuit
40544061
qubit_conversion = {circuit.qbit_argument_conversion(i)[0]: f'Q{i}' for i in range(circuit.num_qubits)} # in Qiskit 1.1.1, the method is called qbit_argument_conversion. In Qiskit >=1.2 (as far as Noah can tell), the method is called _qbit_argument_conversion.
40554062

4063+
qubit_idx_conversion = {i: f'Q{i}' for i in range(circuit.num_qubits)}
4064+
40564065
# for i in range(circuit.num_qubits):
40574066

40584067
# qubit_conversion = {i: f'Q{i}' for i in qiskit_qubits}
@@ -4091,9 +4100,11 @@ def from_qiskit(cls, circuit,
40914100
num_qubits = instruction.operation.num_qubits
40924101
# instruction_qubit_indices = [qubit._index for qubit in instruction.qubits]
40934102
params = instruction.operation.params
4094-
# print(name)
4095-
# print(num_qubits)
4096-
# print(params)
4103+
4104+
if verbose:
4105+
print(name)
4106+
print(num_qubits)
4107+
print(params)
40974108

40984109
pygsti_gate_qubits = [qubit_conversion[qubit] for qubit in instruction.qubits]
40994110

@@ -4102,7 +4113,11 @@ def from_qiskit(cls, circuit,
41024113
continue
41034114

41044115
if name == 'barrier':
4105-
_warnings.warn('skipping barrier')
4116+
next_index = max(layer_indices[qubit] for qubit in pygsti_gate_qubits)
4117+
for qubit in pygsti_gate_qubits:
4118+
layer_indices[qubit] = next_index
4119+
4120+
# _warnings.warn('skipping barrier')
41064121
continue
41074122

41084123
pygsti_gate_name = qiskit_to_gate_name_mapping[name][0]
@@ -4146,7 +4161,7 @@ def from_qiskit(cls, circuit,
41464161

41474162
circuit = cls(pygsti_circ_layers, line_labels=line_labels)
41484163

4149-
return circuit
4164+
return (circuit, qubit_idx_conversion)
41504165

41514166

41524167

@@ -4317,6 +4332,81 @@ def convert_to_quil(self,
43174332

43184333
return quil
43194334

4335+
4336+
def convert_to_qiskit(self, num_qubits=None,
4337+
qubit_conversion=None,
4338+
gatename_conversion=None,
4339+
block_between_layers=True,
4340+
qubits_to_measure=None,
4341+
):
4342+
4343+
try:
4344+
import qiskit
4345+
except ImportError:
4346+
raise ImportError("Qiskit is required for this operation, and it does not appear to be installed.")
4347+
4348+
depth = self.depth
4349+
4350+
if num_qubits is None:
4351+
num_qubits = self.width
4352+
4353+
if qubit_conversion is None:
4354+
qubit_conversion = {label: label for label in self.line_labels}
4355+
elif qubit_conversion == 'remove-Q':
4356+
qubit_conversion = {label: int(label[1:]) for label in self.line_labels}
4357+
4358+
4359+
qiskit_qc = qiskit.QuantumCircuit(num_qubits)
4360+
4361+
qiskit_gate_conversion = _itgs.standard_gatenames_qiskit_conversions()
4362+
4363+
for i in range(depth):
4364+
layer = self.layer_label(i).components
4365+
for gate in layer:
4366+
qiskit_gate, is_standard_gate = qiskit_gate_conversion[gate.name]
4367+
# pseudo-code
4368+
qiskit_qubits = [qubit_conversion[qubit] for qubit in gate.qubits]
4369+
4370+
# if qiskit_version >= 2.0:
4371+
# if is_standard_gate:
4372+
# qiskit_qc._append_standard_gate(qiskit_gate, qiskit_qubits, gate.args)
4373+
# else:
4374+
# qiskit_qc.append(qiskit_gate(gate.args), gate.qubits, copy=False)
4375+
4376+
qiskit_qc.append(qiskit_gate(*(gate.args)), qiskit_qubits, copy=False)
4377+
4378+
if block_between_layers:
4379+
qiskit_qc.barrier()
4380+
4381+
4382+
if qubits_to_measure is not None:
4383+
if isinstance(qubits_to_measure, str):
4384+
if qubits_to_measure == 'all':
4385+
qiskit_qc.measure_all()
4386+
4387+
elif qubits_to_measure == 'active':
4388+
qiskit_qubits_to_measure = [v for v in qubit_conversion.values()]
4389+
new_creg = qiskit_qc._create_creg(len(qiskit_qubits_to_measure), "meas")
4390+
qiskit_qc.add_register(new_creg)
4391+
qiskit_qc.barrier()
4392+
qiskit_qc.measure(qiskit_qubits_to_measure, new_creg)
4393+
4394+
else:
4395+
raise ValueError(f"unknown string option for 'qubits_to_measure': {qubits_to_measure}")
4396+
4397+
elif isinstance(qubits_to_measure, list):
4398+
qiskit_qubits_to_measure = [qubit_conversion[qubit] for qubit in qubits_to_measure]
4399+
new_creg = qiskit_qc._create_creg(len(qiskit_qubits_to_measure), "meas")
4400+
qiskit_qc.add_register(new_creg)
4401+
qiskit_qc.barrier()
4402+
qiskit_qc.measure(qiskit_qubits_to_measure, new_creg)
4403+
4404+
else:
4405+
raise ValueError(f"could not parse argument for 'qubits_to_measure': {qubits_to_measure}")
4406+
4407+
return qiskit_qc
4408+
4409+
43204410
def convert_to_openqasm(self, num_qubits=None,
43214411
standard_gates_version='u3',
43224412
gatename_conversion=None, qubit_conversion=None,
@@ -4453,7 +4543,7 @@ def convert_to_openqasm(self, num_qubits=None,
44534543
if openqasmlist_for_gate is None:
44544544
# Try to look up the operation in mapping dict instead
44554545
openqasmfn_for_gate = gateargs_map.get(gate.name, None)
4456-
assert openqasmfn_for_gate is not None, "Could not look up {} as qasm list or func" % gate.name
4546+
assert openqasmfn_for_gate is not None, f"Could not look up {gate.name} as qasm list or func"
44574547
openqasmlist_for_gate = openqasmfn_for_gate(gate.args)
44584548

44594549
openqasm_for_gate = ''

0 commit comments

Comments
 (0)
Please sign in to comment.