1818from qiskit .transpiler .passes .basis import BasisTranslator , UnrollCustomDefinitions
1919from qiskit .circuit .equivalence_library import SessionEquivalenceLibrary as sel
2020
21- from . import ControlledGate , Gate , QuantumRegister , QuantumCircuit
22- from ._utils import _ctrl_state_to_int
23-
24-
25- def control (
26- operation : Gate | ControlledGate ,
27- num_ctrl_qubits : int | None = 1 ,
28- label : str | None = None ,
29- ctrl_state : str | int | None = None ,
30- ) -> ControlledGate :
31- """Return controlled version of gate using controlled rotations. This function
32- first checks the name of the operation to see if it knows of a method from which
33- to generate a controlled version. Currently, these are ``x``, ``rx``, ``ry``, and ``rz``.
34- If a method is not directly known, it calls the unroller to convert to `u1`, `u3`,
35- and `cx` gates.
36-
37- Args:
38- operation: The gate used to create the ControlledGate.
39- num_ctrl_qubits: The number of controls to add to gate (default=1).
40- label: An optional gate label.
41- ctrl_state: The control state in decimal or as
42- a bitstring (e.g. '111'). If specified as a bitstring the length
43- must equal num_ctrl_qubits, MSB on left. If None, use
44- 2**num_ctrl_qubits-1.
45-
46- Returns:
47- Controlled version of gate.
48-
49- Raises:
50- CircuitError: gate contains non-gate in definition
51- """
52- from math import pi
53-
54- # pylint: disable=cyclic-import
55- from qiskit .circuit import controlledgate
56-
57- ctrl_state = _ctrl_state_to_int (ctrl_state , num_ctrl_qubits )
58-
59- q_control = QuantumRegister (num_ctrl_qubits , name = "control" )
60- q_target = QuantumRegister (operation .num_qubits , name = "target" )
61- q_ancillae = None # TODO: add
62- controlled_circ = QuantumCircuit (q_control , q_target , name = f"c_{ operation .name } " )
63- if isinstance (operation , controlledgate .ControlledGate ):
64- original_ctrl_state = operation .ctrl_state
65- global_phase = 0
66- if operation .name == "x" or (
67- isinstance (operation , controlledgate .ControlledGate ) and operation .base_gate .name == "x"
68- ):
69- controlled_circ .mcx (q_control [:] + q_target [:- 1 ], q_target [- 1 ], q_ancillae )
70- if operation .definition is not None and operation .definition .global_phase :
71- global_phase += operation .definition .global_phase
72- else :
73- basis = ["p" , "u" , "x" , "z" , "rx" , "ry" , "rz" , "cx" ]
74- if isinstance (operation , controlledgate .ControlledGate ):
75- operation = operation .to_mutable ()
76- operation .ctrl_state = None
77- unrolled_gate = _unroll_gate (operation , basis_gates = basis )
78- if unrolled_gate .definition .global_phase :
79- global_phase += unrolled_gate .definition .global_phase
80-
81- definition = unrolled_gate .definition
82- bit_indices = {
83- bit : index
84- for bits in [definition .qubits , definition .clbits ]
85- for index , bit in enumerate (bits )
86- }
87-
88- for instruction in definition .data :
89- gate , qargs = instruction .operation , instruction .qubits
90- if gate .name == "x" :
91- controlled_circ .mcx (q_control , q_target [bit_indices [qargs [0 ]]], q_ancillae )
92- elif gate .name == "rx" :
93- controlled_circ .mcrx (
94- gate .definition .data [0 ].operation .params [0 ],
95- q_control ,
96- q_target [bit_indices [qargs [0 ]]],
97- use_basis_gates = False ,
98- )
99- elif gate .name == "ry" :
100- controlled_circ .mcry (
101- gate .definition .data [0 ].operation .params [0 ],
102- q_control ,
103- q_target [bit_indices [qargs [0 ]]],
104- q_ancillae ,
105- mode = "noancilla" ,
106- use_basis_gates = False ,
107- )
108- elif gate .name == "rz" :
109- controlled_circ .mcrz (
110- gate .definition .data [0 ].operation .params [0 ],
111- q_control ,
112- q_target [bit_indices [qargs [0 ]]],
113- use_basis_gates = False ,
114- )
115- continue
116- elif gate .name == "p" :
117- from qiskit .circuit .library import MCPhaseGate
118-
119- controlled_circ .append (
120- MCPhaseGate (gate .params [0 ], num_ctrl_qubits ),
121- q_control [:] + [q_target [bit_indices [qargs [0 ]]]],
122- )
123- elif gate .name == "cx" :
124- controlled_circ .mcx (
125- q_control [:] + [q_target [bit_indices [qargs [0 ]]]],
126- q_target [bit_indices [qargs [1 ]]],
127- q_ancillae ,
128- )
129- elif gate .name == "u" :
130- theta , phi , lamb = gate .params
131- if num_ctrl_qubits == 1 :
132- if theta == 0 and phi == 0 :
133- controlled_circ .cp (lamb , q_control [0 ], q_target [bit_indices [qargs [0 ]]])
134- else :
135- controlled_circ .cu (
136- theta , phi , lamb , 0 , q_control [0 ], q_target [bit_indices [qargs [0 ]]]
137- )
138- else :
139- if phi == - pi / 2 and lamb == pi / 2 :
140- controlled_circ .mcrx (
141- theta , q_control , q_target [bit_indices [qargs [0 ]]], use_basis_gates = True
142- )
143- elif phi == 0 and lamb == 0 :
144- controlled_circ .mcry (
145- theta ,
146- q_control ,
147- q_target [bit_indices [qargs [0 ]]],
148- q_ancillae ,
149- use_basis_gates = True ,
150- )
151- elif theta == 0 and phi == 0 :
152- controlled_circ .mcp (lamb , q_control , q_target [bit_indices [qargs [0 ]]])
153- else :
154- controlled_circ .mcp (lamb , q_control , q_target [bit_indices [qargs [0 ]]])
155- controlled_circ .mcry (
156- theta ,
157- q_control ,
158- q_target [bit_indices [qargs [0 ]]],
159- q_ancillae ,
160- use_basis_gates = True ,
161- )
162- controlled_circ .mcp (phi , q_control , q_target [bit_indices [qargs [0 ]]])
163- elif gate .name == "z" :
164- controlled_circ .h (q_target [bit_indices [qargs [0 ]]])
165- controlled_circ .mcx (q_control , q_target [bit_indices [qargs [0 ]]], q_ancillae )
166- controlled_circ .h (q_target [bit_indices [qargs [0 ]]])
167- else :
168- raise CircuitError (f"gate contains non-controllable instructions: { gate .name } " )
169- if gate .definition is not None and gate .definition .global_phase :
170- global_phase += gate .definition .global_phase
171- # apply controlled global phase
172- if global_phase :
173- if len (q_control ) < 2 :
174- controlled_circ .p (global_phase , q_control )
175- else :
176- controlled_circ .mcp (global_phase , q_control [:- 1 ], q_control [- 1 ])
177- if isinstance (operation , controlledgate .ControlledGate ):
178- operation .ctrl_state = original_ctrl_state
179- new_num_ctrl_qubits = num_ctrl_qubits + operation .num_ctrl_qubits
180- new_ctrl_state = operation .ctrl_state << num_ctrl_qubits | ctrl_state
181- base_name = operation .base_gate .name
182- base_gate = operation .base_gate
183- else :
184- new_num_ctrl_qubits = num_ctrl_qubits
185- new_ctrl_state = ctrl_state
186- base_name = operation .name
187- base_gate = operation
188- # In order to maintain some backward compatibility with gate names this
189- # uses a naming convention where if the number of controls is <=2 the gate
190- # is named like "cc<base_gate.name>", else it is named like
191- # "c<num_ctrl_qubits><base_name>".
192- if new_num_ctrl_qubits > 2 :
193- ctrl_substr = f"c{ new_num_ctrl_qubits :d} "
194- else :
195- ctrl_substr = ("{0}" * new_num_ctrl_qubits ).format ("c" )
196- new_name = f"{ ctrl_substr } { base_name } "
197- cgate = controlledgate .ControlledGate (
198- new_name ,
199- controlled_circ .num_qubits ,
200- operation .params ,
201- label = label ,
202- num_ctrl_qubits = new_num_ctrl_qubits ,
203- definition = controlled_circ ,
204- ctrl_state = new_ctrl_state ,
205- base_gate = base_gate ,
206- )
207- return cgate
21+ from . import QuantumRegister , QuantumCircuit
20822
20923
21024def _gate_to_circuit (operation ):
@@ -216,16 +30,3 @@ def _gate_to_circuit(operation):
21630 qc = QuantumCircuit (qr , name = operation .name )
21731 qc .append (operation , qr )
21832 return qc
219-
220-
221- def _unroll_gate (operation , basis_gates ):
222- """Unrolls a gate, possibly composite, to the target basis"""
223- circ = _gate_to_circuit (operation )
224- pm = PassManager (
225- [
226- UnrollCustomDefinitions (sel , basis_gates = basis_gates ),
227- BasisTranslator (sel , target_basis = basis_gates ),
228- ]
229- )
230- opqc = pm .run (circ )
231- return opqc .to_gate ()
0 commit comments