def _define(self): theta = self.params[0] q = QuantumRegister(self.num_qubits, "q") qc = QuantumCircuit(q, name=self.name) for i in range(self.num_qubits): for j in range(i + 1, self.num_qubits): qc._append(RXXGate(theta), [q[i], q[j]], []) self.definition = qc
def _check_embodiments(self): """ Checks that `self.embodiments` is populated with legal circuit embodiments: the key-value pair (angle, circuit) satisfies Operator(circuit) approx RXX(angle).to_matrix(). """ for angle, embodiment in self.embodiments.items(): actual = Operator(RXXGate(angle)) purported = Operator(embodiment) if average_gate_fidelity(actual, purported) < 1 - EPSILON: raise QiskitError( f"RXX embodiment provided for angle {angle} disagrees with RXXGate({angle})" )
def _choose_kak_gate(basis_gates): """Choose the first available 2q gate to use in the KAK decomposition.""" kak_gate_names = { 'cx': CXGate(), 'cz': CZGate(), 'iswap': iSwapGate(), 'rxx': RXXGate(pi / 2), } kak_gate = None kak_gates = set(basis_gates or []).intersection(kak_gate_names.keys()) if kak_gates: kak_gate = kak_gate_names[kak_gates.pop()] return kak_gate
def _choose_kak_gate(basis_gates): """Choose the first available 2q gate to use in the KAK decomposition.""" kak_gate_names = { "cx": CXGate(), "cz": CZGate(), "iswap": iSwapGate(), "rxx": RXXGate(pi / 2), "ecr": ECRGate(), } kak_gate = None kak_gates = set(basis_gates or []).intersection(kak_gate_names.keys()) if kak_gates: kak_gate = kak_gate_names[kak_gates.pop()] return kak_gate
def __init__(self, num_qubits: int, theta: Union[List[List[float]], np.ndarray]) -> None: """Create a new Global Mølmer–Sørensen (GMS) gate. Args: num_qubits: width of gate. theta: a num_qubits x num_qubits symmetric matrix of interaction angles for each qubit pair. The upper triangle is considered. """ super().__init__(num_qubits, name="gms") if not isinstance(theta, list): theta = [theta] * int((num_qubits ** 2 - 1) / 2) gms = QuantumCircuit(num_qubits, name="gms") for i in range(self.num_qubits): for j in range(i + 1, self.num_qubits): gms.append(RXXGate(theta[i][j]), [i, j]) self.append(gms.to_gate(), self.qubits)
def level_3_pass_manager( pass_manager_config: PassManagerConfig) -> PassManager: """Level 3 pass manager: heavy optimization by noise adaptive qubit mapping and gate cancellation using commutativity rules and unitary synthesis. This pass manager applies the user-given initial layout. If none is given, a search for a perfect layout (i.e. one that satisfies all 2-qubit interactions) is conducted. If no such layout is found, and device calibration information is available, the circuit is mapped to the qubits with best readouts and to CX gates with highest fidelity. The pass manager then transforms the circuit to match the coupling constraints. It is then unrolled to the basis, and any flipped cx directions are fixed. Finally, optimizations in the form of commutative gate cancellation, resynthesis of two-qubit unitary blocks, and redundant reset removal are performed. Note: In simulators where ``coupling_map=None``, only the unrolling and optimization stages are done. Args: pass_manager_config: configuration of the pass manager. Returns: a level 3 pass manager. Raises: TranspilerError: if the passmanager config is invalid. """ basis_gates = pass_manager_config.basis_gates coupling_map = pass_manager_config.coupling_map initial_layout = pass_manager_config.initial_layout layout_method = pass_manager_config.layout_method or 'dense' routing_method = pass_manager_config.routing_method or 'stochastic' translation_method = pass_manager_config.translation_method or 'translator' seed_transpiler = pass_manager_config.seed_transpiler backend_properties = pass_manager_config.backend_properties # 1. Unroll to 1q or 2q gates _unroll3q = Unroll3qOrMore() # 2. Layout on good qubits if calibration info available, otherwise on dense links _given_layout = SetLayout(initial_layout) def _choose_layout_condition(property_set): return not property_set['layout'] _choose_layout_1 = CSPLayout(coupling_map, call_limit=10000, time_limit=60) if layout_method == 'trivial': _choose_layout_2 = TrivialLayout(coupling_map) elif layout_method == 'dense': _choose_layout_2 = DenseLayout(coupling_map, backend_properties) elif layout_method == 'noise_adaptive': _choose_layout_2 = NoiseAdaptiveLayout(backend_properties) elif layout_method == 'sabre': _choose_layout_2 = SabreLayout(coupling_map, max_iterations=4, seed=seed_transpiler) else: raise TranspilerError("Invalid layout method %s." % layout_method) # 3. Extend dag/layout with ancillas using the full coupling map _embed = [ FullAncillaAllocation(coupling_map), EnlargeWithAncilla(), ApplyLayout() ] # 4. Swap to fit the coupling map _swap_check = CheckMap(coupling_map) def _swap_condition(property_set): return not property_set['is_swap_mapped'] _swap = [BarrierBeforeFinalMeasurements()] if routing_method == 'basic': _swap += [BasicSwap(coupling_map)] elif routing_method == 'stochastic': _swap += [ StochasticSwap(coupling_map, trials=200, seed=seed_transpiler) ] elif routing_method == 'lookahead': _swap += [LookaheadSwap(coupling_map, search_depth=5, search_width=6)] elif routing_method == 'sabre': _swap += [ SabreSwap(coupling_map, heuristic='decay', seed=seed_transpiler) ] else: raise TranspilerError("Invalid routing method %s." % routing_method) # 5. Unroll to the basis if translation_method == 'unroller': _unroll = [Unroller(basis_gates)] elif translation_method == 'translator': from qiskit.circuit.equivalence_library import SessionEquivalenceLibrary as sel _unroll = [ UnrollCustomDefinitions(sel, basis_gates), BasisTranslator(sel, basis_gates) ] else: raise TranspilerError("Invalid translation method %s." % translation_method) # 6. Fix any CX direction mismatch _direction_check = [CheckCXDirection(coupling_map)] def _direction_condition(property_set): return not property_set['is_direction_mapped'] _direction = [CXDirection(coupling_map)] # 8. Optimize iteratively until no more change in depth. Removes useless gates # after reset and before measure, commutes gates and optimizes continguous blocks. _depth_check = [Depth(), FixedPoint('depth')] def _opt_control(property_set): return not property_set['depth_fixed_point'] _reset = [RemoveResetInZeroState()] _meas = [OptimizeSwapBeforeMeasure(), RemoveDiagonalGatesBeforeMeasure()] # Choose the first available 2q gate to use in the KAK decomposition. from qiskit.circuit.library.standard_gates import iSwapGate, CXGate, CZGate, RXXGate kak_gate_names = { 'iswap': iSwapGate(), 'cx': CXGate(), 'cz': CZGate(), 'rxx': RXXGate(math.pi / 2) } kak_gate = None kak_gates = set(basis_gates or []).intersection(kak_gate_names.keys()) if kak_gates: kak_gate = kak_gate_names[kak_gates.pop()] _opt = [ Collect2qBlocks(), ConsolidateBlocks(kak_basis_gate=kak_gate), Optimize1qGates(basis_gates), CommutativeCancellation() ] # Build pass manager pm3 = PassManager() pm3.append(_unroll3q) if coupling_map: pm3.append(_given_layout) pm3.append(_choose_layout_1, condition=_choose_layout_condition) pm3.append(_choose_layout_2, condition=_choose_layout_condition) pm3.append(_embed) pm3.append(_reset + _meas) pm3.append(_swap_check) pm3.append(_swap, condition=_swap_condition) pm3.append(_depth_check + _opt + _unroll, do_while=_opt_control) if coupling_map and not coupling_map.is_symmetric: pm3.append(_direction_check) pm3.append(_direction, condition=_direction_condition) pm3.append(_reset) return pm3
def decompose_xxyy_into_xxyy_xx(a_target, b_target, a_source, b_source, interaction): """ Consumes a target canonical interaction CAN(a_target, b_target) and source interactions CAN(a1, b1), CAN(a2), then manufactures a circuit identity of the form CAN(a_target, b_target) = (Zr, Zs) CAN(a_source, b_source) (Zu, Zv) CAN(interaction) (Zx, Zy). Returns the 6-tuple (r, s, u, v, x, y). """ cplus, cminus = np.cos(a_source + b_source), np.cos(a_source - b_source) splus, sminus = np.sin(a_source + b_source), np.sin(a_source - b_source) ca, sa = np.cos(interaction), np.sin(interaction) uplusv = (1 / 2 * safe_arccos( cminus**2 * ca**2 + sminus**2 * sa**2 - np.cos(a_target - b_target)**2, 2 * cminus * ca * sminus * sa, )) uminusv = (1 / 2 * safe_arccos( cplus**2 * ca**2 + splus**2 * sa**2 - np.cos(a_target + b_target)**2, 2 * cplus * ca * splus * sa, )) u, v = (uplusv + uminusv) / 2, (uplusv - uminusv) / 2 # NOTE: the target matrix is phase-free middle_matrix = reduce( np.dot, [ RXXGate(2 * a_source).to_matrix() @ RYYGate( 2 * b_source).to_matrix(), np.kron(RZGate(2 * u).to_matrix(), RZGate(2 * v).to_matrix()), RXXGate(2 * interaction).to_matrix(), ], ) phase_solver = np.array([ [ 1 / 4, 1 / 4, 1 / 4, 1 / 4, ], [ 1 / 4, -1 / 4, -1 / 4, 1 / 4, ], [ 1 / 4, 1 / 4, -1 / 4, -1 / 4, ], [ 1 / 4, -1 / 4, 1 / 4, -1 / 4, ], ]) inner_phases = [ np.angle(middle_matrix[0, 0]), np.angle(middle_matrix[1, 1]), np.angle(middle_matrix[1, 2]) + np.pi / 2, np.angle(middle_matrix[0, 3]) + np.pi / 2, ] r, s, x, y = np.dot(phase_solver, inner_phases) # If there's a phase discrepancy, need to conjugate by an extra Z/2 (x) Z/2. generated_matrix = reduce( np.dot, [ np.kron(RZGate(2 * r).to_matrix(), RZGate(2 * s).to_matrix()), middle_matrix, np.kron(RZGate(2 * x).to_matrix(), RZGate(2 * y).to_matrix()), ], ) if (abs(np.angle(generated_matrix[3, 0]) - np.pi / 2) < 0.01 and a_target > b_target) or ( abs(np.angle(generated_matrix[3, 0]) + np.pi / 2) < 0.01 and a_target < b_target): x += np.pi / 4 y += np.pi / 4 r -= np.pi / 4 s -= np.pi / 4 return r, s, u, v, x, y
from qiskit.circuit.library.standard_gates import ( iSwapGate, CXGate, CZGate, RXXGate, RZXGate, ECRGate, ) from qiskit.transpiler.passes.synthesis import plugin from qiskit.providers.models import BackendProperties KAK_GATE_NAMES = { "cx": CXGate(), "cz": CZGate(), "iswap": iSwapGate(), "rxx": RXXGate(pi / 2), "ecr": ECRGate(), "rzx": RZXGate(pi / 4), # typically pi/6 is also available } def _choose_kak_gate(basis_gates): """Choose the first available 2q gate to use in the KAK decomposition.""" kak_gate = None kak_gates = set(basis_gates or []).intersection(KAK_GATE_NAMES.keys()) if kak_gates: kak_gate = KAK_GATE_NAMES[kak_gates.pop()] return kak_gate