def decompose_to_target_gateset(self, op: 'cirq.Operation', moment_idx: int) -> DecomposeResult: if not 1 <= protocols.num_qubits(op) <= 2: return self._decompose_multi_qubit_operation(op, moment_idx) if protocols.num_qubits(op) == 1: return self._decompose_single_qubit_operation(op, moment_idx) new_optree = self._decompose_two_qubit_operation(op, moment_idx) if new_optree is NotImplemented or new_optree is None: return new_optree new_optree = [*ops.flatten_to_ops_or_moments(new_optree)] op_untagged = op.untagged old_optree = ([*op_untagged.circuit] if isinstance(op_untagged, circuits.CircuitOperation) and self._intermediate_result_tag in op.tags else [op]) old_2q_gate_count = sum(1 for o in ops.flatten_to_ops(old_optree) if len(o.qubits) == 2) new_2q_gate_count = sum(1 for o in ops.flatten_to_ops(new_optree) if len(o.qubits) == 2) switch_to_new = (any( protocols.num_qubits(op) == 2 and op not in self for op in ops.flatten_to_ops(old_optree)) or new_2q_gate_count < old_2q_gate_count) if switch_to_new: return new_optree mapped_old_optree: List['cirq.OP_TREE'] = [] for old_op in ops.flatten_to_ops(old_optree): if old_op in self: mapped_old_optree.append(old_op) else: decomposed_op = self._decompose_single_qubit_operation( old_op, moment_idx) if decomposed_op is None or decomposed_op is NotImplemented: return NotImplemented mapped_old_optree.append(decomposed_op) return mapped_old_optree
def _translate_cirq_operation_to_braket_instruction( op: cirq_ops.Operation, ) -> List[Instruction]: """Converts the Cirq operation to an equivalent Braket instruction or list of instructions. Args: op: Cirq operation to convert. Raises: ValueError: If the operation cannot be converted to Braket. """ nqubits = protocols.num_qubits(op) if nqubits == 1: return _translate_one_qubit_cirq_operation_to_braket_instruction(op) elif nqubits == 2: return _translate_two_qubit_cirq_operation_to_braket_instruction(op) elif nqubits == 3: qubits = [q.x for q in op.qubits] if op == cirq_ops.TOFFOLI.on(*op.qubits): return [Instruction(braket_gates.CCNot(), qubits)] elif op == cirq_ops.FREDKIN.on(*op.qubits): return [Instruction(braket_gates.CSwap(), qubits)] else: _raise_cirq_to_braket_error(op) # Unsupported gates. else: _raise_cirq_to_braket_error(op)
def assert_has_consistent_apply_unitary(val: Any, *, qubit_count: Optional[int] = None, atol: float = 1e-8) -> None: """Tests whether a value's _apply_unitary_ is correct. Contrasts the effects of the value's `_apply_unitary_` with the matrix returned by the value's `_unitary_` method. Args: val: The value under test. Should have a `__pow__` method. qubit_count: Usually inferred. The number of qubits the value acts on. This argument isn't needed if the gate has a unitary matrix or implements `cirq.SingleQubitGate`/`cirq.TwoQubitGate`/ `cirq.ThreeQubitGate`. atol: Absolute error tolerance. """ expected = protocols.unitary(val, default=None) qubit_counts = [ qubit_count, # Only fall back to using the unitary size if num_qubits or qid_shape # protocols are not defined. protocols.num_qubits(val, default=expected.shape[0].bit_length() - 1 if expected is not None else None), _infer_qubit_count(val) ] qubit_counts = [e for e in qubit_counts if e is not None] if not qubit_counts: raise NotImplementedError( 'Failed to infer qubit count of <{!r}>. Specify it.'.format(val)) assert len(set(qubit_counts)) == 1, ( 'Inconsistent qubit counts from different methods: {}'.format( qubit_counts)) n = cast(int, qubit_counts[0]) qid_shape = protocols.qid_shape(val, default=(2, ) * n) eye = linalg.eye_tensor((2, ) + qid_shape, dtype=np.complex128) actual = protocols.apply_unitary( unitary_value=val, args=protocols.ApplyUnitaryArgs(target_tensor=eye, available_buffer=np.ones_like(eye) * float('nan'), axes=list(range(1, n + 1))), default=None) # If you don't have a unitary, you shouldn't be able to apply a unitary. if expected is None: assert actual is None else: expected = np.kron(np.eye(2), expected) # If you applied a unitary, it should match the one you say you have. if actual is not None: np.testing.assert_allclose(actual.reshape((np.prod( (2, ) + qid_shape, dtype=int), ) * 2), expected, atol=atol)
def route_circuit(circuit: circuits.Circuit, device_graph: nx.Graph, *, algo_name: Optional[str] = None, router: Optional[Callable[..., SwapNetwork]] = None, **kwargs) -> SwapNetwork: """Routes a circuit on a given device. Args: circuit: The circuit to route. device_graph: The device's graph, in which each vertex is a qubit and each edge indicates the ability to do an operation on those qubits. algo_name: The name of a routing algorithm. Must be in ROUTERS. router: The function that actually does the routing. **kwargs: Arguments to pass to the routing algorithm. Exactly one of algo_name and router must be specified. """ if any(protocols.num_qubits(op) > 2 for op in circuit.all_operations()): raise ValueError('Can only route circuits with operations that act on' ' at most 2 qubits.') if len(list(circuit.all_qubits())) > device_graph.number_of_nodes(): raise ValueError('Number of logical qubits is greater than number' ' of physical qubits.') if not (algo_name is None or router is None): raise ValueError( 'At most one of algo_name or router can be specified.') if algo_name is not None: router = ROUTERS[algo_name] elif router is None: raise ValueError(f'No routing algorithm specified.') return router(circuit, device_graph, **kwargs)
def __init__( self, gate: Union[Type[raw_types.Gate], raw_types.Gate], *, name: Optional[str] = None, description: Optional[str] = None, max_parallel_allowed: Optional[int] = None, ) -> None: """Inits ParallelGateFamily Args: gate: The gate which can act in parallel. It can be a python `type` inheriting from `cirq.Gate` or a non-parameterized instance of a `cirq.Gate`. If an instance of `cirq.ParallelGate` is passed, then the corresponding `gate.sub_gate` is used. name: The name of the gate family. description: Human readable description of the gate family. max_parallel_allowed: The maximum number of qubits on which a given gate `g` can act on. If None, then any number of qubits are allowed. """ if isinstance(gate, parallel_gate.ParallelGate): if not max_parallel_allowed: max_parallel_allowed = protocols.num_qubits(gate) gate = cast(parallel_gate.ParallelGate, gate).sub_gate self._max_parallel_allowed = max_parallel_allowed super().__init__(gate, name=name, description=description)
def _predicate(self, gate: raw_types.Gate) -> bool: if (self._max_parallel_allowed is not None and protocols.num_qubits(gate) > self._max_parallel_allowed): return False gate = gate.sub_gate if isinstance( gate, parallel_gate.ParallelGate) else gate return super()._predicate(gate)
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 assert_has_consistent_qid_shape(val: Any) -> None: """Tests whether a value's `_qid_shape_` and `_num_qubits_` are correct and consistent. Verifies that the entries in the shape are all positive integers and the length of shape equals `_num_qubits_` (and also equals `len(qubits)` if `val` has `qubits`. Args: val: The value under test. Should have `_qid_shape_` and/or `num_qubits_` methods. Can optionally have a `qubits` property. """ default = (-1, ) qid_shape = protocols.qid_shape(val, default) num_qubits = protocols.num_qubits(val, default) if qid_shape is default or num_qubits is default: return # Nothing to check assert all( d >= 1 for d in qid_shape), f'Not all entries in qid_shape are positive: {qid_shape}' assert ( len(qid_shape) == num_qubits ), f'Length of qid_shape and num_qubits disagree: {qid_shape}, {num_qubits}' if isinstance(val, ops.Operation): assert num_qubits == len( val.qubits ), f'Length of num_qubits and val.qubits disagrees: {num_qubits}, {len(val.qubits)}'
def state_vector_has_stabilizer(state_vector: np.ndarray, stabilizer: DensePauliString) -> bool: """Checks that the state_vector is stabilized by the given stabilizer. The stabilizer should not modify the value of the state_vector, up to the global phase. Args: state_vector: An input state vector. Is not mutated by this function. stabilizer: A potential stabilizer of the above state_vector as a DensePauliString. Returns: Whether the stabilizer stabilizes the supplied state. """ qubits = LineQubit.range(protocols.num_qubits(stabilizer)) args = state_vector_simulation_state.StateVectorSimulationState( available_buffer=np.empty_like(state_vector), qubits=qubits, prng=np.random.RandomState(), initial_state=state_vector.copy(), dtype=state_vector.dtype, ) protocols.act_on(stabilizer, args, qubits) return np.allclose(args.target_tensor, state_vector)
def _commutes_(self, other: Any, atol: Union[int, float] = 1e-8 ) -> Union[bool, NotImplementedType]: if (isinstance(other, ops.Gate) and isinstance(other, ops.InterchangeableQubitsGate) and protocols.num_qubits(other) == 2): return True return NotImplemented
def assert_pauli_expansion_is_consistent_with_unitary(val: Any) -> None: """Checks Pauli expansion against unitary matrix.""" # Check to see if the protocol is supported without doing a fallback # to unitary, otherwise the test is vacuous. method = getattr(val, '_pauli_expansion_', None) if method is None: return pauli_expansion = protocols.pauli_expansion(val, default=None) if pauli_expansion is None: return unitary = protocols.unitary(val, None) if unitary is None: return num_qubits = protocols.num_qubits(val, default=unitary.shape[0].bit_length() - 1) basis = operator_spaces.kron_bases(operator_spaces.PAULI_BASIS, repeat=num_qubits) recovered_unitary = operator_spaces.matrix_from_basis_coefficients( pauli_expansion, basis) assert np.allclose(unitary, recovered_unitary, rtol=0, atol=1e-12)
def _strat_act_from_single_qubit_decompose( self, val: Any, qubits: Sequence['cirq.Qid'] ) -> bool: if num_qubits(val) == 1: if not has_unitary(val): return NotImplemented u = unitary(val) clifford_gate = SingleQubitCliffordGate.from_unitary(u) if clifford_gate is not None: # Gather the effective unitary applied so as to correct for the # global phase later. final_unitary = np.eye(2) for axis, quarter_turns in clifford_gate.decompose_rotation(): gate = axis ** (quarter_turns / 2) self._strat_apply_gate(gate, qubits) final_unitary = np.matmul(unitary(gate), final_unitary) # Find the entry with the largest magnitude in the input unitary. k = max(np.ndindex(*u.shape), key=lambda t: abs(u[t])) # Correct the global phase that wasn't conserved in the above # decomposition. self._state.apply_global_phase(u[k] / final_unitary[k]) return True return NotImplemented
def _strat_act_on_stabilizer_ch_form_from_single_qubit_decompose( val: Any, args: 'cirq.ActOnStabilizerCHFormArgs') -> bool: if num_qubits(val) == 1: if not has_unitary(val): return NotImplemented u = unitary(val) clifford_gate = SingleQubitCliffordGate.from_unitary(u) if clifford_gate is not None: # Gather the effective unitary applied so as to correct for the # global phase later. final_unitary = np.eye(2) for axis, quarter_turns in clifford_gate.decompose_rotation(): gate = None # type: Optional[cirq.Gate] if axis == pauli_gates.X: gate = common_gates.XPowGate(exponent=quarter_turns / 2) assert gate._act_on_(args) elif axis == pauli_gates.Y: gate = common_gates.YPowGate(exponent=quarter_turns / 2) assert gate._act_on_(args) else: assert axis == pauli_gates.Z gate = common_gates.ZPowGate(exponent=quarter_turns / 2) assert gate._act_on_(args) final_unitary = np.matmul(unitary(gate), final_unitary) # Find the entry with the largest magnitude in the input unitary. k = max(np.ndindex(*u.shape), key=lambda t: abs(u[t])) # Correct the global phase that wasn't conserved in the above # decomposition. args.state.omega *= u[k] / final_unitary[k] return True return NotImplemented
def _translate_cirq_operation_to_braket_instruction( op: cirq_ops.Operation, ) -> List[Instruction]: """Converts the Cirq operation to an equivalent Braket instruction or list of instructions. Args: op: Cirq operation to convert. Raises: ValueError: If the operation cannot be converted to Braket. """ nqubits = protocols.num_qubits(op) if nqubits == 1: return _translate_one_qubit_cirq_operation_to_braket_instruction(op) elif nqubits == 2: return _translate_two_qubit_cirq_operation_to_braket_instruction(op) elif nqubits == 3: qubits = [q.x for q in op.qubits] if isinstance(op.gate, cirq_ops.TOFFOLI): return [Instruction(braket_gates.CCNot(), qubits)] elif isinstance(op.gate, cirq_ops.FREDKIN): return [Instruction(braket_gates.CSwap(), qubits)] # Unsupported gates. else: raise ValueError( f"Unable to convert {op} to Braket. If you think this is a bug, " "you can open an issue on the Mitiq GitHub at" " https://github.com/unitaryfund/mitiq.")
def can_merge_moment(m: 'cirq.Moment'): return all( protocols.num_qubits(op) == 1 and protocols.has_unitary(op) and tags_to_ignore.isdisjoint(op.tags) for op in m )
def state_vector_has_stabilizer(state_vector: np.ndarray, stabilizer: DensePauliString) -> bool: """Checks that the state_vector is stabilized by the given stabilizer. The stabilizer should not modify the value of the state_vector, up to the global phase. Args: state_vector: An input state vector. Is not mutated by this function. stabilizer: A potential stabilizer of the above state_vector as a DensePauliString. Returns: Whether the stabilizer stabilizes the supplied state. """ args = act_on_state_vector_args.ActOnStateVectorArgs( target_tensor=state_vector.copy(), available_buffer=np.empty_like(state_vector), axes=range(protocols.num_qubits(stabilizer)), prng=np.random.RandomState(), log_of_measurement_results={}, ) protocols.act_on(stabilizer, args) return np.allclose(args.target_tensor, state_vector)
def assert_has_consistent_qid_shape(val: Any, qubit_count: Optional[int] = None) -> None: """Tests whether a value's `_qid_shape_` and `_num_qubits_` are correct and consistent. Verifies that the entries in the shape are all positive integers and the length of shape equals `_num_qubits_` (and also equals `len(qubits)` if `val` has `qubits`. Args: val: The value under test. Should have `_qid_shape_` and/or `num_qubits_` methods. Can optionally have a `qubits` property. qubit_count: The expected number of qubits val should use. """ default = (-1,) qid_shape = protocols.qid_shape(val, default) num_qubits = protocols.num_qubits(val, default) if qid_shape is default or num_qubits is default: return # Nothing to check assert all(d >= 1 for d in qid_shape), ( f'Not all entries in qid_shape are positive: {qid_shape}') assert len(qid_shape) == num_qubits, ( f'Length of qid_shape and num_qubits disagree: {qid_shape}, ' f'{num_qubits}') if qubit_count is not None: assert qubit_count == num_qubits, ( f'Expected qubits and num_qubits disagree: {qubit_count}, ' f'{num_qubits}') infer_qubit_count = _infer_qubit_count(val) if infer_qubit_count is not None: assert infer_qubit_count == num_qubits, ( f'Length of qubits and num_qubits disagree: {infer_qubit_count}, ' f'{num_qubits}')
def build_entangling_layers( qubits: Sequence[devices.GridQubit], two_qubit_gate: ops.Gate ) -> List[ops.Moment]: """Builds a sequence of gates that entangle all pairs of qubits on a grid. The qubits are restricted to be physically on a square grid with distinct row and column indices (not every node of the grid needs to have a qubit). To entangle all pairs of qubits, a user-specified two-qubit gate is applied between each and every pair of qubit that are next to each other. In general, a total of four sets of parallel operations are needed to perform all possible two-qubit gates. We proceed as follows: The first layer applies two-qubit gates to qubits (i, j) and (i, j + 1) where i is any integer and j is an even integer. The second layer applies two-qubit gates to qubits (i, j) and (i + 1, j) where i is an even integer and j is any integer. The third layer applies two-qubit gates to qubits (i, j) and (i, j + 1) where i is any integer and j is an odd integer. The fourth layer applies two-qubit gates to qubits (i, j) and (i + 1, j) where i is an odd integer and j is any integer. After the layers are built as above, any empty layer is ejected.: Cycle 1: Cycle 2: q00 ── q01 q02 ── q03 q00 q01 q02 q03 | | | | q10 ── q11 q12 ── q13 q10 q11 q12 q13 q20 ── q21 q22 ── q23 q20 q21 q22 q23 | | | | q30 ── q31 q32 ── q33 q30 q31 q32 q33 Cycle 3: Cycle 4: q00 q01 ── q02 q03 q00 q01 q02 q03 q10 q11 ── q12 q13 q10 q11 q12 q13 | | | | q20 q21 ── q22 q23 q20 q21 q22 q23 q30 q31 ── q32 q33 q30 q31 q32 q33 Args: qubits: The grid qubits included in the entangling operations. two_qubit_gate: The two-qubit gate to be applied between all neighboring pairs of qubits. Returns: A list of ops.Moment, with a maximum length of 4. Each ops.Moment includes two-qubit gates which can be performed at the same time. Raises: ValueError: two-qubit gate is not used. """ if protocols.num_qubits(two_qubit_gate) != 2: raise ValueError('Input must be a two-qubit gate') interaction_sequence = _default_interaction_sequence(qubits) return [ ops.Moment([two_qubit_gate(q_a, q_b) for (q_a, q_b) in pairs]) for pairs in interaction_sequence ]
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 validate_args(self, qubits: Sequence[Qid]) -> None: """Checks if this gate can be applied to the given qubits. By default checks if input is of type Qid and qubit count. Child classes can override. Args: qubits: The collection of qubits to potentially apply the gate to. Throws: ValueError: The gate can't be applied to the qubits. """ if len(qubits) != protocols.num_qubits(self): raise ValueError('Wrong number of qubits for <{!r}>. ' 'Expected {} qubits but got <{!r}>.'.format( self, protocols.num_qubits(self), qubits)) if any([not isinstance(qubit, Qid) for qubit in qubits]): raise ValueError('Gate was called with type different than Qid.')
def _strat_has_stabilizer_effect_from_unitary(val: Any) -> Optional[bool]: """Attempts to infer whether val has stabilizer effect from its unitary. Returns whether unitary of `val` normalizes the Pauli group. Works only for 2x2 unitaries. """ # Do not try this strategy if there is no unitary or if the number of # qubits is not 1 since that would be expensive. if not protocols.has_unitary(val) or protocols.num_qubits(val) != 1: return None unitary = protocols.unitary(val) return SingleQubitCliffordGate.from_unitary(unitary) is not None
def assert_act_on_clifford_tableau_effect_matches_unitary(val: Any) -> None: """Checks that act_on with CliffordTableau generates stabilizers that stabilize the final state vector. Does not work with Operations or Gates expecting non-qubit Qids.""" # pylint: disable=unused-variable __tracebackhide__ = True # pylint: enable=unused-variable num_qubits_val = protocols.num_qubits(val) if not protocols.has_unitary(val) or \ protocols.qid_shape(val) != (2,) * num_qubits_val: return None qubits = LineQubit.range(protocols.num_qubits(val) * 2) qubit_map = {qubit: i for i, qubit in enumerate(qubits)} circuit = Circuit() for i in range(num_qubits_val): circuit.append([ common_gates.H(qubits[i]), common_gates.CNOT(qubits[i], qubits[-i - 1]) ]) if hasattr(val, "on"): circuit.append(val.on(*qubits[:num_qubits_val])) else: circuit.append(val.with_qubits(*qubits[:num_qubits_val])) tableau = _final_clifford_tableau(circuit, qubit_map) if tableau is None: return None state_vector = np.reshape(final_state_vector(circuit, qubit_order=qubits), protocols.qid_shape(qubits)) assert all( state_vector_has_stabilizer(state_vector, stab) for stab in tableau.stabilizers()), ( "act_on clifford tableau is not consistent with " "final_state_vector simulation.\n\nval: {!r}".format(val))
def preprocess_transformers(self) -> List['cirq.TRANSFORMER']: """List of transformers which should be run before decomposing individual operations.""" return [ _create_transformer_with_kwargs( expand_composite.expand_composite, no_decomp=lambda op: protocols.num_qubits(op) <= self.num_qubits, ), _create_transformer_with_kwargs( merge_k_qubit_gates.merge_k_qubit_unitaries, k=self.num_qubits, rewriter=lambda op: op.with_tags(self._intermediate_result_tag), ), ]
def state_vector_has_stabilizer(state_vector: np.ndarray, stabilizer: DensePauliString) -> bool: """Checks that the stabilizer does not modify the value of the state_vector, including the global phase. Does not mutate the input state_vector.""" args = act_on_state_vector_args.ActOnStateVectorArgs( target_tensor=state_vector.copy(), available_buffer=np.empty_like(state_vector), axes=range(protocols.num_qubits(stabilizer)), prng=np.random.RandomState(), log_of_measurement_results={}) protocols.act_on(stabilizer, args) return np.allclose(args.target_tensor, state_vector)
def _known_gate_with_no_decomposition(val: Any): """Checks whether `val` is a known gate with no default decomposition to default gateset.""" if isinstance(val, ops.MatrixGate): return protocols.qid_shape(val) not in [(2, ), (2, ) * 2, (2, ) * 3] if isinstance(val, ops.BaseDensePauliString) and not protocols.has_unitary(val): return True if isinstance(val, ops.ControlledGate): if protocols.is_parameterized(val): return True if isinstance( val.sub_gate, ops.MatrixGate) and protocols.num_qubits(val.sub_gate) > 1: return True if val.control_qid_shape != (2, ) * val.num_controls(): return True return _known_gate_with_no_decomposition(val.sub_gate) return False
def _strat_act_from_single_qubit_decompose( self, val: Any, qubits: Sequence['cirq.Qid'] ) -> bool: if num_qubits(val) == 1: if not has_unitary(val): return NotImplemented u = unitary(val) gate_and_phase = SingleQubitCliffordGate.from_unitary_with_global_phase(u) if gate_and_phase is not None: clifford_gate, global_phase = gate_and_phase # Apply gates. for gate in clifford_gate.decompose_gate(): self._strat_apply_gate(gate, qubits) # Apply global phase. self._state.apply_global_phase(global_phase) return True return NotImplemented
def with_qubits(self, *new_qubits: 'cirq.Qid') -> 'CircuitOperation': """Returns a copy of this operation with an updated qubit mapping. Args: new_qubits: A list of qubits to target. Qubits in this list are matched to qubits in the circuit following default qubit order, ignoring any existing qubit map. Returns: A copy of this operation targeting `new_qubits`. Raises: ValueError: `new_qubits` has a different number of qubits than this operation. """ expected = protocols.num_qubits(self.circuit) if len(new_qubits) != expected: raise ValueError(f'Expected {expected} qubits, got {len(new_qubits)}.') return self.with_qubit_mapping(dict(zip(self.qubits, new_qubits)))
def _strat_act_on_clifford_tableau_from_single_qubit_decompose( val: Any, args: 'cirq.ActOnCliffordTableauArgs', qubits: Sequence['cirq.Qid'] ) -> bool: if num_qubits(val) == 1: if not has_unitary(val): return NotImplemented u = unitary(val) clifford_gate = SingleQubitCliffordGate.from_unitary(u) if clifford_gate is not None: for axis, quarter_turns in clifford_gate.decompose_rotation(): if axis == pauli_gates.X: common_gates.XPowGate(exponent=quarter_turns / 2)._act_on_(args, qubits) elif axis == pauli_gates.Y: common_gates.YPowGate(exponent=quarter_turns / 2)._act_on_(args, qubits) else: assert axis == pauli_gates.Z common_gates.ZPowGate(exponent=quarter_turns / 2)._act_on_(args, qubits) return True return NotImplemented
def __pow__(self, power): if power == 1: return self if power == -1: # HACK: break cycle from cirq.devices import line_qubit decomposed = protocols.decompose_once_with_qubits( self, qubits=line_qubit.LineQubit.range(protocols.num_qubits(self)), default=None) if decomposed is None: return NotImplemented inverse_decomposed = protocols.inverse(decomposed, None) if inverse_decomposed is None: return NotImplemented return _InverseCompositeGate(self) return NotImplemented
def entanglement_fidelity(operation: 'cirq.SupportsKraus') -> float: r"""Returns entanglement fidelity of a given quantum channel. Entanglement fidelity $F_e$ of a quantum channel $E: L(H) \to L(H)$ is the overlap between the maximally entangled state $|\phi\rangle = \frac{1}{\sqrt{dim H}} \sum_i|i\rangle|i\rangle$ and the state obtained by sending one half of $|\phi\rangle$ through the channel $E$, i.e. $$ F_e = \langle\phi|(E \otimes I)(|\phi\rangle\langle\phi|)|\phi\rangle $$ where $I: L(H) \to L(H)$ is the identity map. Args: operation: Quantum channel whose entanglement fidelity is to be computed. Returns: Entanglement fidelity of the channel represented by operation. """ f = 0.0 for k in protocols.kraus(operation): f += np.abs(np.trace(k)) ** 2 n_qubits = protocols.num_qubits(operation) return float(f / 4**n_qubits)