def _fix_single_qubit_gates_around_kak_interaction( *, desired: 'cirq.KakDecomposition', operations: List['cirq.Operation'], qubits: Sequence['cirq.Qid'], ) -> Iterator['cirq.Operation']: """Adds single qubit operations to complete a desired interaction. Args: desired: The kak decomposition of the desired operation. qubits: The pair of qubits that is being operated on. operations: A list of operations that composes into the desired kak interaction coefficients, but may not have the desired before/after single qubit operations or the desired global phase. Returns: A list of operations whose kak decomposition approximately equals the desired kak decomposition. """ actual = linalg.kak_decomposition(circuits.Circuit(operations)) def dag(a: np.ndarray) -> np.ndarray: return np.transpose(np.conjugate(a)) for k in range(2): g = ops.MatrixGate( dag(actual.single_qubit_operations_before[k]) @ desired.single_qubit_operations_before[k]) yield g(qubits[k]) yield from operations for k in range(2): g = ops.MatrixGate(desired.single_qubit_operations_after[k] @ dag( actual.single_qubit_operations_after[k])) yield g(qubits[k]) yield ops.GlobalPhaseOperation(desired.global_phase / actual.global_phase)
def _decompose_(self, qubits): from cirq import ops a, b = qubits return [ ops.GlobalPhaseOperation(self.global_phase), ops.MatrixGate(self.single_qubit_operations_before[0]).on(a), ops.MatrixGate(self.single_qubit_operations_before[1]).on(b), np.exp(1j * ops.X(a) * ops.X(b) * self.interaction_coefficients[0]), np.exp(1j * ops.Y(a) * ops.Y(b) * self.interaction_coefficients[1]), np.exp(1j * ops.Z(a) * ops.Z(b) * self.interaction_coefficients[2]), ops.MatrixGate(self.single_qubit_operations_after[0]).on(a), ops.MatrixGate(self.single_qubit_operations_after[1]).on(b), ]
def map_func(op: 'cirq.Operation', _) -> 'cirq.OP_TREE': op_untagged = op.untagged if ( deep and isinstance(op_untagged, circuits.CircuitOperation) and merged_circuit_op_tag not in op.tags ): return op_untagged.replace( circuit=_rewrite_merged_k_qubit_unitaries( op_untagged.circuit, context=context, k=k, rewriter=rewriter, merged_circuit_op_tag=merged_circuit_op_tag, ).freeze() ).with_tags(*op.tags) if not (protocols.num_qubits(op) <= k and protocols.has_unitary(op)): return op if rewriter: return rewriter( cast(circuits.CircuitOperation, op_untagged) if merged_circuit_op_tag in op.tags else circuits.CircuitOperation(circuits.FrozenCircuit(op)) ) return ops.MatrixGate(protocols.unitary(op)).on(*op.qubits)
def test_to_braket_raises_on_unsupported_gates(): for num_qubits in range(3, 5): print(num_qubits) qubits = [LineQubit(int(qubit)) for qubit in range(num_qubits)] op = ops.MatrixGate(_rotation_of_pi_over_7(num_qubits)).on(*qubits) circuit = Circuit(op) with pytest.raises(ValueError): to_braket(circuit)
def map_func(op: 'cirq.Operation', _) -> 'cirq.OP_TREE': if not (protocols.num_qubits(op) <= k and protocols.has_unitary(op)): return op if rewriter: return rewriter( cast(circuits.CircuitOperation, op.untagged ) if merged_circuit_op_tag in op.tags else circuits. CircuitOperation(circuits.FrozenCircuit(op))) return ops.MatrixGate(protocols.unitary(op)).on(*op.qubits)
def _decompose_single_ctrl(matrix: np.ndarray, control: 'cirq.Qid', target: 'cirq.Qid') -> List['cirq.Operation']: """Decomposes controlled gate with one control. See [1], chapter 5.1. """ a, b, c, delta = _decompose_abc(matrix) result = [ ops.ZPowGate(exponent=delta / np.pi).on(control), ops.MatrixGate(c).on(target), ops.CNOT.on(control, target), ops.MatrixGate(b).on(target), ops.CNOT.on(control, target), ops.MatrixGate(a).on(target), ] # Remove no-ops. result = [g for g in result if not _is_identity(unitary(g))] return result
def _rewrite(self, operations: List[ops.Operation]) -> Optional[ops.OP_TREE]: if not operations: return None q = operations[0].qubits[0] # Custom rewriter? if self._rewriter is not None: return self._rewriter(operations) unitary = linalg.dot(*(protocols.unitary(op) for op in operations[::-1])) # Custom synthesizer? if self._synthesizer is not None: return self._synthesizer(q, unitary) # Just use the default. return ops.MatrixGate(unitary).on(q)
def _register_custom_gate(gate_json: Any, registry: Dict[str, CellMaker]): if not isinstance(gate_json, Dict): raise ValueError( f'Custom gate json must be a dictionary.\n' f'Custom gate json={gate_json!r}.' ) if 'id' not in gate_json: raise ValueError( f'Custom gate json must have an id key.\n' f'Custom gate json={gate_json!r}.' ) identifier = gate_json['id'] if identifier in registry: raise ValueError(f'Custom gate with duplicate identifier: {identifier!r}') if 'matrix' in gate_json and 'circuit' in gate_json: raise ValueError( f'Custom gate json cannot have both a matrix and a circuit.\n' f'Custom gate json={gate_json!r}.' ) if 'matrix' in gate_json: if not isinstance(gate_json['matrix'], str): raise ValueError( f'Custom gate matrix json must be a string.\n' f'Custom gate json={gate_json!r}.' ) gate = ops.MatrixGate(parse_matrix(gate_json['matrix'])) registry[identifier] = CellMaker( identifier=identifier, size=gate.num_qubits(), maker=lambda args: gate(*args.qubits[::-1]), ) elif 'circuit' in gate_json: comp = _parse_cols_into_composite_cell(gate_json['circuit'], registry) registry[identifier] = CellMaker( identifier=identifier, size=comp.height, maker=lambda args: comp.with_line_qubits_mapped_to(list(args.qubits)), ) else: raise ValueError( f'Custom gate json must have a matrix or a circuit.\n' f'Custom gate json={gate_json!r}.' )
def decompose_multi_controlled_rotation( matrix: np.ndarray, controls: List['cirq.Qid'], target: 'cirq.Qid') -> List['cirq.Operation']: """Implements action of multi-controlled unitary gate. Returns a sequence of operations, which is equivalent to applying single-qubit gate with matrix `matrix` on `target`, controlled by `controls`. Result is guaranteed to consist exclusively of 1-qubit, CNOT and CCNOT gates. If matrix is special unitary, result has length `O(len(controls))`. Otherwise result has length `O(len(controls)**2)`. References: [1] Barenco, Bennett et al. Elementary gates for quantum computation. 1995. https://arxiv.org/pdf/quant-ph/9503016.pdf Args: matrix - 2x2 numpy unitary matrix (of real or complex dtype). controls - control qubits. targets - target qubits. Returns: A list of operations which, applied in a sequence, are equivalent to applying `MatrixGate(matrix).on(target).controlled_by(*controls)`. """ assert is_unitary(matrix) assert matrix.shape == (2, 2) if len(controls) == 0: return [ops.MatrixGate(matrix).on(target)] elif len(controls) == 1: return _decompose_single_ctrl(matrix, controls[0], target) elif is_special_unitary(matrix): return _decompose_su(matrix, controls, target) else: return _decompose_recursive(matrix, 1.0, controls, target, [])