@@ -3974,6 +3974,159 @@ def from_cirq(cls, circuit, qubit_conversion=None, cirq_gate_conversion= None,
3974
3974
else :
3975
3975
return cls (circuit_layers )
3976
3976
3977
+ @classmethod
3978
+ def from_qiskit (cls , circuit , qubit_conversion = None , qiskit_gate_conversion = None , use_standard_gate_conversion_as_backup = True , allow_different_gates_in_same_layer = True ):
3979
+ """
3980
+ Converts and instantiates a pyGSTi Circuit object from a Qiskit QuantumCircuit object.
3981
+
3982
+ Parameters
3983
+ ----------
3984
+ circuit : Qiskit QuantumCircuit
3985
+ The Qiskit QuantumCircuit object to parse into a pyGSTi circuit.
3986
+
3987
+ qubit_conversion : dict, optional (default None)
3988
+ A dictionary specifying a mapping between Qiskit qubit indices and
3989
+ pyGSTi qubit labels (either integers or strings).
3990
+ If None, then a default mapping is created.
3991
+
3992
+ qiskit_gate_conversion : dict, optional (default None)
3993
+ If specified a dictionary with keys given by Qiskit gate objects,
3994
+ and values given by pyGSTi gate names which overrides the built-in
3995
+ conversion dictionary used by default.
3996
+
3997
+ use_standard_gate_conversion_as_backup : boolean (default True)
3998
+ Determines how the circuit conversion will be handled when the custom
3999
+ Qiskit gate conversion dict does not have an entry for the encountered
4000
+ gate. If True, this method will fall back on the standard conversions
4001
+ found in qiskit_gatenames_standard_conversions(). If False, the method
4002
+ will fail.
4003
+
4004
+ allow_different_gates_in_same_layer: boolean (default True)
4005
+ determines if gates with different names can be in the same layer.
4006
+ For instance, if a CZ gate and CX gate can both fit in the same layer,
4007
+ they will either be placed in the same layer (if True) or split into
4008
+ separate layers (if False).
4009
+
4010
+ Returns
4011
+ -------
4012
+ pygsti_circuit
4013
+ A pyGSTi Circuit instance equivalent to the specified Qiskit one.
4014
+ """
4015
+
4016
+ try :
4017
+ import qiskit
4018
+ except ImportError :
4019
+ raise ImportError ("Qiskit is required for this operation, and it does not appear to be installed." )
4020
+
4021
+ #mapping between cirq gates and pygsti gate names:
4022
+ if qiskit_gate_conversion is not None :
4023
+ if use_standard_gate_conversion_as_backup == True :
4024
+ qiskit_to_gate_name_mapping = _itgs .qiskit_gatenames_standard_conversions ()
4025
+ for key , value in qiskit_gate_conversion .items ():
4026
+ qiskit_to_gate_name_mapping [key ] = value
4027
+ else :
4028
+ qiskit_to_gate_name_mapping = qiskit_gate_conversion
4029
+ else :
4030
+ qiskit_to_gate_name_mapping = _itgs .qiskit_gatenames_standard_conversions ()
4031
+
4032
+ #get all of the qubits in the Qiskit circuit
4033
+ qubits = circuit .qubits
4034
+ qiskit_qubit_indices = []
4035
+ for qubit in qubits :
4036
+ qiskit_qubit_indices .append (qubit ._index )
4037
+
4038
+
4039
+ #ensure all of these have a conversion available.
4040
+ if qubit_conversion is not None :
4041
+ assert set (qiskit_qubit_indices ).issubset (set (qubit_conversion .keys ())), 'Missing Qiskit to pygsti conversions for some qubit label(s).'
4042
+ #if it is None, build a default mapping.
4043
+ else :
4044
+ #default mapping is the identify mapping: qubit i in the Qiskit circuit maps to qubit i in the pyGSTi circuit
4045
+ qubit_conversion = {i : f'Q{ i } ' for i in qiskit_qubit_indices }
4046
+
4047
+ line_labels = tuple (sorted ([qubit_conversion [qubit ] for qubit in qiskit_qubit_indices ]))
4048
+
4049
+ # print(qubit_conversion)
4050
+
4051
+ # print(line_labels)
4052
+
4053
+
4054
+ layer_indices = {}
4055
+ for line_label in line_labels :
4056
+ layer_indices [line_label ] = 0
4057
+
4058
+ instructions = circuit .data
4059
+
4060
+ pygsti_circ_layers = []
4061
+
4062
+ if allow_different_gates_in_same_layer == False :
4063
+ layer_names = []
4064
+
4065
+ for instruction in instructions :
4066
+ # print(layer_indices)
4067
+ if allow_different_gates_in_same_layer == False :
4068
+ assert len (pygsti_circ_layers ) == len (layer_names ), "there must be one layer name for each layer!"
4069
+
4070
+ # print(instruction)
4071
+ name = instruction .operation .name
4072
+ num_qubits = instruction .operation .num_qubits
4073
+ instruction_qubit_indices = [qubit ._index for qubit in instruction .qubits ]
4074
+ params = instruction .operation .params
4075
+ # print(name)
4076
+ # print(num_qubits)
4077
+ # print(params)
4078
+
4079
+ pygsti_qubits = [qubit_conversion [i ] for i in instruction_qubit_indices ]
4080
+
4081
+ if name == 'measure' or name == 'barrier' :
4082
+ _warnings .warn ('skipping measure or barrier' )
4083
+ continue
4084
+
4085
+ pygsti_gate_name = qiskit_to_gate_name_mapping [name ][0 ]
4086
+
4087
+ label = _Label (pygsti_gate_name , pygsti_qubits , args = params )
4088
+
4089
+
4090
+ #convert_qiskit_instruction_to_pygsti_label(name, qubits, params)
4091
+
4092
+ next_index = max (layer_indices [qubit ] for qubit in pygsti_qubits )
4093
+ # print(f'computed next index for {pygsti_gate_name} gate on lines {pygsti_qubits}: {next_index}')
4094
+
4095
+ if allow_different_gates_in_same_layer == True : #layers are not separated by the type of gate they contain
4096
+
4097
+ if next_index < len (pygsti_circ_layers ): #there is an existing layer in the circuit where the gate can be inserted
4098
+ pygsti_circ_layers [next_index ].append (label )
4099
+ # print(f"inserting {pygsti_gate_name} gate in layer {next_index} on lines {pygsti_qubits}")
4100
+ for pygsti_qubit in pygsti_qubits : #update where a gate on these qubits can be placed
4101
+ layer_indices [pygsti_qubit ] = next_index + 1
4102
+ else :
4103
+ # print(f"inserting {pygsti_gate_name} gate at end of circuit, which is layer {len(pygsti_circ_layers)} on lines {pygsti_qubits}")
4104
+ pygsti_circ_layers .append ([label ]) #need to append gate at the end of the circuit, thus creating a new layer
4105
+ for pygsti_qubit in pygsti_qubits :
4106
+ layer_indices [pygsti_qubit ] = len (pygsti_circ_layers )
4107
+
4108
+ else :
4109
+ for i in range (next_index , len (pygsti_circ_layers )): # searching for a layer where the gate can be inserted. Layer name needs to match the name of the gate being inserted
4110
+ if name == layer_names [i ]:
4111
+ # print(f'inserting gate {name} on qubits {qubits} in layer {i}')
4112
+ pygsti_circ_layers [i ].append (label )
4113
+ for pygsti_qubit in pygsti_qubits :
4114
+ layer_indices [pygsti_qubit ] = i + 1
4115
+ break
4116
+
4117
+ else : #no place to put the gate in the existing layers. New layer is added with corresponding name
4118
+ # print(f'inserting gate {name} on qubits {qubits} in layer {len(pygsti_circ_layers)}')
4119
+ pygsti_circ_layers .append ([label ])
4120
+ layer_names .append (name )
4121
+ for pygsti_qubit in pygsti_qubits :
4122
+ layer_indices [pygsti_qubit ] = len (pygsti_circ_layers )
4123
+
4124
+ circuit = cls (pygsti_circ_layers , line_labels = line_labels )
4125
+
4126
+ return circuit
4127
+
4128
+
4129
+
3977
4130
def convert_to_quil (self ,
3978
4131
num_qubits = None ,
3979
4132
gatename_conversion = None ,
0 commit comments