Skip to content

Commit a711f5f

Browse files
committed
move for defs
1 parent 51c9a8b commit a711f5f

3 files changed

Lines changed: 213 additions & 208 deletions

File tree

qiskit/circuit/add_control.py

Lines changed: 1 addition & 200 deletions
Original file line numberDiff line numberDiff line change
@@ -18,193 +18,7 @@
1818
from qiskit.transpiler.passes.basis import BasisTranslator, UnrollCustomDefinitions
1919
from 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

21024
def _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

Comments
 (0)