def from_matrix(mat: np.array) -> 'QasmUGate': pre_phase, rotation, post_phase = linalg.deconstruct_single_qubit_matrix_into_angles(mat) return QasmUGate( rotation / np.pi, post_phase / np.pi, pre_phase / np.pi, )
def _deconstruct_single_qubit_matrix_into_gate_turns( mat: np.ndarray) -> Tuple[float, float, float]: """Breaks down a 2x2 unitary into gate parameters. Args: mat: The 2x2 unitary matrix to break down. Returns: A tuple containing the amount to rotate around an XY axis, the phase of that axis, and the amount to phase around Z. All results will be in fractions of a whole turn, with values canonicalized into the range [-0.5, 0.5). """ pre_phase, rotation, post_phase = ( linalg.deconstruct_single_qubit_matrix_into_angles(mat)) # Figure out parameters of the actual gates we will do. tau = 2 * np.pi xy_turn = rotation / tau xy_phase_turn = 0.25 - pre_phase / tau total_z_turn = (post_phase + pre_phase) / tau # Normalize turns into the range [-0.5, 0.5). return (_signed_mod_1(xy_turn), _signed_mod_1(xy_phase_turn), _signed_mod_1(total_z_turn))
def _deconstruct_single_qubit_matrix_into_gate_turns( mat: np.ndarray) -> Tuple[float, float, float]: """Breaks down a 2x2 unitary into gate parameters. Args: mat: The 2x2 unitary matrix to break down. Returns: A tuple containing the amount to rotate around an XY axis, the phase of that axis, and the amount to phase around Z. All results will be in fractions of a whole turn, with values canonicalized into the range [-0.5, 0.5). """ pre_phase, rotation, post_phase = ( linalg.deconstruct_single_qubit_matrix_into_angles(mat)) # Figure out parameters of the actual gates we will do. tau = 2 * np.pi xy_turn = rotation / tau xy_phase_turn = 0.25 - pre_phase / tau total_z_turn = (post_phase + pre_phase) / tau # Normalize turns into the range [-0.5, 0.5). return (_signed_mod_1(xy_turn), _signed_mod_1(xy_phase_turn), _signed_mod_1(total_z_turn))
def single_qubit_matrix_to_pauli_rotations( mat: np.ndarray, atol: float = 0 ) -> List[Tuple[ops.Pauli, float]]: """Implements a single-qubit operation with few rotations. Args: mat: The 2x2 unitary matrix of the operation to implement. atol: A limit on the amount of absolute error introduced by the construction. Returns: A list of (Pauli, half_turns) tuples that, when applied in order, perform the desired operation. """ def is_clifford_rotation(half_turns): return near_zero_mod(half_turns, 0.5, atol=atol) def to_quarter_turns(half_turns): return round(2 * half_turns) % 4 def is_quarter_turn(half_turns): return is_clifford_rotation(half_turns) and to_quarter_turns(half_turns) % 2 == 1 def is_half_turn(half_turns): return is_clifford_rotation(half_turns) and to_quarter_turns(half_turns) == 2 def is_no_turn(half_turns): return is_clifford_rotation(half_turns) and to_quarter_turns(half_turns) == 0 # Decompose matrix z_rad_before, y_rad, z_rad_after = linalg.deconstruct_single_qubit_matrix_into_angles(mat) z_ht_before = z_rad_before / np.pi - 0.5 m_ht = y_rad / np.pi m_pauli: ops.Pauli = ops.X z_ht_after = z_rad_after / np.pi + 0.5 # Clean up angles if is_clifford_rotation(z_ht_before): if (is_quarter_turn(z_ht_before) or is_quarter_turn(z_ht_after)) ^ ( is_half_turn(m_ht) and is_no_turn(z_ht_before - z_ht_after) ): z_ht_before += 0.5 z_ht_after -= 0.5 m_pauli = ops.Y if is_half_turn(z_ht_before) or is_half_turn(z_ht_after): z_ht_before -= 1 z_ht_after += 1 m_ht = -m_ht if is_no_turn(m_ht): z_ht_before += z_ht_after z_ht_after = 0 elif is_half_turn(m_ht): z_ht_after -= z_ht_before z_ht_before = 0 # Generate operations rotation_list = [(ops.Z, z_ht_before), (m_pauli, m_ht), (ops.Z, z_ht_after)] return [(pauli, ht) for pauli, ht in rotation_list if not is_no_turn(ht)]
def from_matrix(mat: np.ndarray) -> 'cirq.PhasedXZGate': pre_phase, rotation, post_phase = linalg.deconstruct_single_qubit_matrix_into_angles( mat) pre_phase /= np.pi post_phase /= np.pi rotation /= np.pi pre_phase -= 0.5 post_phase += 0.5 return PhasedXZGate(x_exponent=rotation, axis_phase_exponent=-pre_phase, z_exponent=post_phase + pre_phase)._canonical()
def single_qubit_matrix_to_ops(mat, qubit): # Decompose matrix z_rad_before, y_rad, z_rad_after = ( linalg.deconstruct_single_qubit_matrix_into_angles(mat)) z_ht_before = z_rad_before / np.pi - 0.5 m_ht = y_rad / np.pi m_pauli = ops.Pauli.X z_ht_after = z_rad_after / np.pi + 0.5 # Clean up angles if is_clifford_rotation(z_ht_before): if is_quarter_turn(z_ht_before) or is_quarter_turn(z_ht_after): z_ht_before += 0.5 z_ht_after -= 0.5 m_pauli = ops.Pauli.Y if is_half_turn(z_ht_before) or is_half_turn(z_ht_after): z_ht_before -= 1 z_ht_after += 1 m_ht = -m_ht if is_no_turn(m_ht): z_ht_before += z_ht_after z_ht_after = 0 elif is_half_turn(m_ht): z_ht_after -= z_ht_before z_ht_before = 0 # Generate operations rotation_list = [(ops.Pauli.Z, z_ht_before), (m_pauli, m_ht), (ops.Pauli.Z, z_ht_after)] is_clifford_list = [ is_clifford_rotation(ht) for pauli, ht in rotation_list ] op_list = [ rotation_to_clifford_op(pauli, qubit, ht) if is_clifford else rotation_to_non_clifford_op(pauli, qubit, ht) for is_clifford, (pauli, ht) in zip(is_clifford_list, rotation_list) ] # Merge adjacent Clifford gates for i in reversed(range(len(op_list) - 1)): if is_clifford_list[i] and is_clifford_list[i + 1]: op_list[i] = op_list[i].gate.merged_with( op_list[i + 1].gate)(qubit) is_clifford_list.pop(i + 1) op_list.pop(i + 1) # Yield non-identity ops for is_clifford, op in zip(is_clifford_list, op_list): if is_clifford and op.gate == ops.CliffordGate.I: continue yield op
def single_qubit_matrix_to_ops(mat, qubit): # Decompose matrix z_rad_before, y_rad, z_rad_after = ( linalg.deconstruct_single_qubit_matrix_into_angles(mat)) z_ht_before = z_rad_before / np.pi - 0.5 m_ht = y_rad / np.pi m_pauli = ops.Pauli.X z_ht_after = z_rad_after / np.pi + 0.5 # Clean up angles if is_clifford_rotation(z_ht_before): if is_quarter_turn(z_ht_before) or is_quarter_turn(z_ht_after): z_ht_before += 0.5 z_ht_after -= 0.5 m_pauli = ops.Pauli.Y if is_half_turn(z_ht_before) or is_half_turn(z_ht_after): z_ht_before -= 1 z_ht_after += 1 m_ht = -m_ht if is_no_turn(m_ht): z_ht_before += z_ht_after z_ht_after = 0 elif is_half_turn(m_ht): z_ht_after -= z_ht_before z_ht_before = 0 # Generate operations rotation_list = [ (ops.Pauli.Z, z_ht_before), (m_pauli, m_ht), (ops.Pauli.Z, z_ht_after)] is_clifford_list = [is_clifford_rotation(ht) for pauli, ht in rotation_list] op_list = [rotation_to_clifford_op(pauli, qubit, ht) if is_clifford else rotation_to_non_clifford_op(pauli, qubit, ht) for is_clifford, (pauli, ht) in zip(is_clifford_list, rotation_list)] # Merge adjacent Clifford gates for i in reversed(range(len(op_list) - 1)): if is_clifford_list[i] and is_clifford_list[i+1]: op_list[i] = op_list[i].gate.merged_with(op_list[i+1].gate )(qubit) is_clifford_list.pop(i+1) op_list.pop(i+1) # Yield non-identity ops for is_clifford, op in zip(is_clifford_list, op_list): if is_clifford and op.gate == ops.CliffordGate.I: continue yield op
def from_matrix(mat: np.array) -> 'QasmUGate': pre_phase, rotation, post_phase = ( linalg.deconstruct_single_qubit_matrix_into_angles(mat)) return QasmUGate(pre_phase/np.pi, rotation/np.pi, post_phase/np.pi)
def single_qubit_matrix_to_pauli_rotations( mat: np.ndarray, tolerance: float = 0 ) -> List[Tuple[ops.Pauli, float]]: """Implements a single-qubit operation with few rotations. Args: mat: The 2x2 unitary matrix of the operation to implement. tolerance: A limit on the amount of error introduced by the construction. Returns: A list of (Pauli, half_turns) tuples that, when applied in order, perform the desired operation. """ tol = linalg.Tolerance(atol=tolerance) def is_clifford_rotation(half_turns): return tol.all_near_zero_mod(half_turns, 0.5) def to_quarter_turns(half_turns): return round(2 * half_turns) % 4 def is_quarter_turn(half_turns): return (is_clifford_rotation(half_turns) and to_quarter_turns(half_turns) % 2 == 1) def is_half_turn(half_turns): return (is_clifford_rotation(half_turns) and to_quarter_turns(half_turns) == 2) def is_no_turn(half_turns): return (is_clifford_rotation(half_turns) and to_quarter_turns(half_turns) == 0) # Decompose matrix z_rad_before, y_rad, z_rad_after = ( linalg.deconstruct_single_qubit_matrix_into_angles(mat)) z_ht_before = z_rad_before / np.pi - 0.5 m_ht = y_rad / np.pi m_pauli = ops.Pauli.X z_ht_after = z_rad_after / np.pi + 0.5 # Clean up angles if is_clifford_rotation(z_ht_before): if ((is_quarter_turn(z_ht_before) or is_quarter_turn(z_ht_after)) ^ (is_half_turn(m_ht) and is_no_turn(z_ht_before-z_ht_after))): z_ht_before += 0.5 z_ht_after -= 0.5 m_pauli = ops.Pauli.Y if is_half_turn(z_ht_before) or is_half_turn(z_ht_after): z_ht_before -= 1 z_ht_after += 1 m_ht = -m_ht if is_no_turn(m_ht): z_ht_before += z_ht_after z_ht_after = 0 elif is_half_turn(m_ht): z_ht_after -= z_ht_before z_ht_before = 0 # Generate operations rotation_list = [ (ops.Pauli.Z, z_ht_before), (m_pauli, m_ht), (ops.Pauli.Z, z_ht_after)] return [(pauli, ht) for pauli, ht in rotation_list if not is_no_turn(ht)]
def single_qubit_matrix_to_gates(mat: np.ndarray, tolerance: float = 0 ) -> List[ops.SingleQubitGate]: """Implements a single-qubit operation with few gates. Args: mat: The 2x2 unitary matrix of the operation to implement. tolerance: A limit on the amount of error introduced by the construction. Returns: A list of gates that, when applied in order, perform the desired operation. """ tol = linalg.Tolerance(atol=tolerance) def is_clifford_rotation(half_turns): return tol.all_near_zero_mod(half_turns, 0.5) def to_quarter_turns(half_turns): return round(2 * half_turns) % 4 def is_quarter_turn(half_turns): return (is_clifford_rotation(half_turns) and to_quarter_turns(half_turns) % 2 == 1) def is_half_turn(half_turns): return (is_clifford_rotation(half_turns) and to_quarter_turns(half_turns) == 2) def is_no_turn(half_turns): return (is_clifford_rotation(half_turns) and to_quarter_turns(half_turns) == 0) # Decompose matrix z_rad_before, y_rad, z_rad_after = ( linalg.deconstruct_single_qubit_matrix_into_angles(mat)) z_ht_before = z_rad_before / np.pi - 0.5 m_ht = y_rad / np.pi m_gate = ops.X # type: ops.Gate z_ht_after = z_rad_after / np.pi + 0.5 # Clean up angles if is_clifford_rotation(z_ht_before): if ((is_quarter_turn(z_ht_before) or is_quarter_turn(z_ht_after)) ^ (is_half_turn(m_ht) and is_no_turn(z_ht_before - z_ht_after))): z_ht_before += 0.5 z_ht_after -= 0.5 m_gate = ops.Y if is_half_turn(z_ht_before) or is_half_turn(z_ht_after): z_ht_before -= 1 z_ht_after += 1 m_ht = -m_ht if is_no_turn(m_ht): z_ht_before += z_ht_after z_ht_after = 0 elif is_half_turn(m_ht): z_ht_after -= z_ht_before z_ht_before = 0 # Generate operations rotation_list = [(ops.Z, z_ht_before), (m_gate, m_ht), (ops.Z, z_ht_after)] return [gate**ht for gate, ht in rotation_list if not is_no_turn(ht)]