Esempio n. 1
0
def cphase_symbols_to_sqrt_iswap(a, b, turns):
    """Version of cphase_to_sqrt_iswap that works with symbols.

    Note that the formulae contained below will need to be flattened
    into a sweep before serializing.
    """
    theta = sympy.Mod(turns, 2.0) * sympy.pi

    # -1 if theta > pi.  Adds a hacky fudge factor so theta=pi is not 0
    sign = sympy.sign(sympy.pi - theta + 1e-9)

    # For sign = 1: theta. For sign = -1, 2pi-theta
    theta_prime = (sympy.pi - sign * sympy.pi) + sign * theta

    phi = sympy.asin(np.sqrt(2) * sympy.sin(theta_prime / 4))
    xi = sympy.atan(sympy.tan(phi) / np.sqrt(2))

    yield ops.rz(sign * 0.5 * theta_prime).on(a)
    yield ops.rz(sign * 0.5 * theta_prime).on(b)
    yield ops.rx(xi).on(a)
    yield ops.X(b)**(-sign * 0.5)
    yield SQRT_ISWAP_INV(a, b)
    yield ops.rx(-2 * phi).on(a)
    yield SQRT_ISWAP(a, b)
    yield ops.rx(xi).on(a)
    yield ops.X(b)**(sign * 0.5)
def _init_ops(data: Dict[str, Any]) -> 'cirq.OP_TREE':
    if 'init' not in data:
        return []
    init = data['init']
    if not isinstance(init, List):
        raise ValueError(f'Circuit JSON init must be a list but was {init!r}.')
    init_ops = []
    for i in range(len(init)):
        state = init[i]
        q = devices.LineQubit(i)
        if state == 0:
            pass
        elif state == 1:
            init_ops.append(ops.X(q))
        elif state == '+':
            init_ops.append(ops.ry(np.pi / 2).on(q))
        elif state == '-':
            init_ops.append(ops.ry(-np.pi / 2).on(q))
        elif state == 'i':
            init_ops.append(ops.rx(-np.pi / 2).on(q))
        elif state == '-i':
            init_ops.append(ops.rx(np.pi / 2).on(q))
        else:
            raise ValueError(f'Unrecognized init state: {state!r}')
    return ops.Moment(init_ops)
def decompose_phased_iswap_into_syc_precomputed(theta: float, a: ops.Qid,
                                                b: ops.Qid) -> ops.OP_TREE:
    """Decompose PhasedISwap into sycamore gates using precomputed coefficients.

    This should only be called if the Gate has a phase_exponent of .25. If the
    gate has an exponent of 1, decompose_phased_iswap_into_syc should be used
    instead. Converting PhasedISwap gates to Sycamore is not supported if
    neither of these constraints are satisfied.

    This synthesize a PhasedISwap in terms of four sycamore gates.  This
    compilation converts the gate into a circuit involving two CZ gates, which
    themselves are each represented as two Sycamore gates and single-qubit
    rotations

    Args:
        theta: rotation parameter
        a: First qubit id to operate on
        b: Second qubit id to operate on
    Returns:
        a Cirq program implementing the Phased ISWAP gate

    """

    yield ops.PhasedXPowGate(phase_exponent=0.41175161497166024,
                             exponent=0.5653807577895922).on(a)
    yield ops.PhasedXPowGate(phase_exponent=1.0, exponent=0.5).on(b),
    yield (ops.Z**0.7099892314883478).on(b),
    yield (ops.Z**0.6746023442550453).on(a),
    yield SycamoreGate().on(a, b)
    yield ops.PhasedXPowGate(phase_exponent=-0.5154334589432878,
                             exponent=0.5228733015013345).on(b)
    yield ops.PhasedXPowGate(phase_exponent=0.06774925307475355).on(a)
    yield SycamoreGate().on(a, b),
    yield ops.PhasedXPowGate(phase_exponent=-0.5987667922766213,
                             exponent=0.4136540654256824).on(a)
    yield (ops.Z**-0.9255092746611595).on(b)
    yield (ops.Z**-1.333333333333333).on(a)
    yield ops.rx(-theta).on(a)
    yield ops.rx(-theta).on(b)

    yield ops.PhasedXPowGate(phase_exponent=0.5678998743900456,
                             exponent=0.5863459345743176).on(a)
    yield ops.PhasedXPowGate(phase_exponent=0.3549946157441739).on(b)
    yield SycamoreGate().on(a, b)
    yield ops.PhasedXPowGate(phase_exponent=-0.5154334589432878,
                             exponent=0.5228733015013345).on(b)
    yield ops.PhasedXPowGate(phase_exponent=0.06774925307475355).on(a)
    yield SycamoreGate().on(a, b)
    yield ops.PhasedXPowGate(phase_exponent=-0.8151665352515929,
                             exponent=0.8906746535691492).on(a)
    yield ops.PhasedXPowGate(phase_exponent=-0.07449072533884049,
                             exponent=0.5).on(b)
    yield (ops.Z**-0.9255092746611595).on(b)
    yield (ops.Z**-0.9777346353961884).on(a)
Esempio n. 4
0
    def convert_one(self, op: ops.Operation) -> ops.OP_TREE:
        """Convert a single (one- or two-qubit) operation into ion trap native gates.

        Args:
            op: The gate operation to be converted.

        Returns:
            The desired operations implemented with ion trap gates.

        Raises:
            TypeError: If the operation cannot be converted.
        """

        # Known gate name
        if not isinstance(op, ops.GateOperation):
            raise TypeError(f"{op!r} is not a gate operation.")

        if op in self.gateset:
            return [op]
        # one choice of known Hadamard gate decomposition
        if isinstance(op.gate, ops.HPowGate) and op.gate.exponent == 1:
            return [
                ops.rx(np.pi).on(op.qubits[0]),
                ops.ry(-1 * np.pi / 2).on(op.qubits[0])
            ]
        # one choice of known CNOT gate decomposition
        if isinstance(op.gate, ops.CNotPowGate) and op.gate.exponent == 1:
            return [
                ops.ry(np.pi / 2).on(op.qubits[0]),
                ms(np.pi / 4).on(op.qubits[0], op.qubits[1]),
                ops.rx(-1 * np.pi / 2).on(op.qubits[0]),
                ops.rx(-1 * np.pi / 2).on(op.qubits[1]),
                ops.ry(-1 * np.pi / 2).on(op.qubits[0]),
            ]
        # Known matrix
        mat = protocols.unitary(op, None) if len(op.qubits) <= 2 else None
        if mat is not None and len(op.qubits) == 1:
            gates = transformers.single_qubit_matrix_to_phased_x_z(mat)
            return [g.on(op.qubits[0]) for g in gates]
        if mat is not None and len(op.qubits) == 2:
            return two_qubit_matrix_to_ion_operations(op.qubits[0],
                                                      op.qubits[1], mat)

        if self.ignore_failures:
            return [op]

        raise TypeError("Don't know how to work with {!r}. "
                        "It isn't a native Ion Trap operation, "
                        "a 1 or 2 qubit gate with a known unitary, "
                        "or composite.".format(op.gate))
Esempio n. 5
0
def test_from_braket_parameterized_single_qubit_gates(qubit_index):
    braket_circuit = BKCircuit()
    pgates = [
        braket_gates.Rx,
        braket_gates.Ry,
        braket_gates.Rz,
        braket_gates.PhaseShift,
    ]
    angles = np.random.RandomState(11).random(len(pgates))
    instructions = [
        Instruction(rot(a), target=qubit_index)
        for rot, a in zip(pgates, angles)
    ]
    for instr in instructions:
        braket_circuit.add_instruction(instr)
    cirq_circuit = from_braket(braket_circuit)

    for i, op in enumerate(cirq_circuit.all_operations()):
        assert np.allclose(instructions[i].operator.to_matrix(),
                           protocols.unitary(op))

    qubit = LineQubit(qubit_index)
    expected_cirq_circuit = Circuit(
        ops.rx(angles[0]).on(qubit),
        ops.ry(angles[1]).on(qubit),
        ops.rz(angles[2]).on(qubit),
        ops.Z.on(qubit)**(angles[3] / np.pi),
    )
    assert _equal(cirq_circuit,
                  expected_cirq_circuit,
                  require_qubit_equality=True)
Esempio n. 6
0
 def _decompose_single_qubit_operation(self, op: 'cirq.Operation', _: int) -> DecomposeResult:
     if isinstance(op.gate, ops.HPowGate) and op.gate.exponent == 1:
         return [ops.rx(np.pi).on(op.qubits[0]), ops.ry(-1 * np.pi / 2).on(op.qubits[0])]
     if protocols.has_unitary(op):
         gates = transformers.single_qubit_matrix_to_phased_x_z(protocols.unitary(op))
         return [g.on(op.qubits[0]) for g in gates]
     return NotImplemented
Esempio n. 7
0
def test_non_identity_scale_1q():
    """Tests that when scale factor = 1, the circuit is the
    same.
    """
    qreg = LineQubit.range(3)
    circ = Circuit([ops.rx(np.pi * 1.0).on_each(qreg)],
                   [ops.ry(np.pi * 1.0).on(qreg[0])])
    np.random.seed(42)
    stretch = 2
    base_noise = 0.001
    noises = np.random.normal(loc=0.0,
                              scale=np.sqrt((stretch - 1) * base_noise),
                              size=(4, ))
    np.random.seed(42)

    scaled = scale_parameters(circ,
                              scale_factor=stretch,
                              sigma=base_noise,
                              seed=42)
    result = []
    for moment in scaled:
        for op in moment.operations:
            gate = deepcopy(op.gate)
            param = gate.exponent
            result.append(param * np.pi - np.pi)
    assert np.all(np.isclose(result - noises, 0))
def rzz(theta: float, q0: ops.Qid, q1: ops.Qid) -> ops.OP_TREE:
    """Generate exp(-1j * theta * zz) from Sycamore gates.

    Args:
        theta: rotation parameter
        q0: First qubit id to operate on
        q1: Second qubit id to operate on
    Returns:
        a Cirq program implementing the Ising gate
    rtype:
        cirq.OP_Tree
    """
    phi = -np.pi / 24
    c_phi = np.cos(2 * phi)
    target_unitary = scipy.linalg.expm(-1j * theta * UNITARY_ZZ)

    if abs(np.cos(theta)) > c_phi:
        c2 = abs(np.sin(theta)) / c_phi
    else:
        c2 = abs(np.cos(theta)) / c_phi

    # Prepare program that has same Schmidt coeffs as exp(1j theta ZZ)
    program = circuits.Circuit(google.SYC.on(q0, q1),
                               ops.rx(2 * np.arccos(c2)).on(q1),
                               google.SYC.on(q0, q1))

    yield create_corrected_circuit(target_unitary, program, q0, q1)
Esempio n. 9
0
def _cphase_symbols_to_sqrt_iswap(a: 'cirq.Qid',
                                  b: 'cirq.Qid',
                                  turns: 'cirq.TParamVal',
                                  use_sqrt_iswap_inv: bool = True):
    """Implements `cirq.CZ(a, b) ** turns` using two √iSWAPs and single qubit rotations.

    Output unitary:
        [[1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
         [0, 0, 0, g]]
    where:
        g = exp(i·π·t).

    Args:
        a: The first qubit.
        b: The second qubit.
        turns: The rotational angle (t) that specifies the gate, where
            g = exp(i·π·t/2).
        use_sqrt_iswap_inv: If True, `cirq.SQRT_ISWAP_INV` is used instead of `cirq.SQRT_ISWAP`.

    Yields:
        A `cirq.OP_TREE` representing the decomposition.
    """
    theta = sympy.Mod(turns, 2.0) * sympy.pi

    # -1 if theta > pi.  Adds a hacky fudge factor so theta=pi is not 0
    sign = sympy.sign(sympy.pi - theta + 1e-9)

    # For sign = 1: theta. For sign = -1, 2pi-theta
    theta_prime = (sympy.pi - sign * sympy.pi) + sign * theta

    phi = sympy.asin(np.sqrt(2) * sympy.sin(theta_prime / 4))
    xi = sympy.atan(sympy.tan(phi) / np.sqrt(2))

    yield ops.rz(sign * 0.5 * theta_prime).on(a)
    yield ops.rz(sign * 0.5 * theta_prime).on(b)
    yield ops.rx(xi).on(a)
    yield ops.X(b)**(-sign * 0.5)
    yield _sqrt_iswap_inv(a, b, use_sqrt_iswap_inv)
    yield ops.rx(-2 * phi).on(a)
    yield ops.Z(a)
    yield _sqrt_iswap_inv(a, b, use_sqrt_iswap_inv)
    yield ops.Z(a)
    yield ops.rx(xi).on(a)
    yield ops.X(b)**(sign * 0.5)
Esempio n. 10
0
def cphase_to_sqrt_iswap(a, b, turns):
    """Implement a C-Phase gate using two sqrt ISWAP gates and single-qubit
    operations. The circuit is equivalent to cirq.CZPowGate(exponent=turns).

    Output unitary:
    [1   0   0   0],
    [0   1   0   0],
    [0   0   1   0],
    [0   0   0   e^{i turns pi}].

    Args:
        a: the first qubit
        b: the second qubit
        turns: Exponent specifying the evolution time in number of rotations.
    """
    theta = (turns % 2) * np.pi
    if 0 <= theta <= np.pi:
        sign = 1.
        theta_prime = theta
    elif np.pi < theta < 2 * np.pi:
        sign = -1.
        theta_prime = 2 * np.pi - theta

    if np.isclose(theta, np.pi):
        # If we are close to pi, just set values manually to avoid possible
        # numerical errors with arcsin of greater than 1.0 (Ahem, Windows).
        phi = np.pi / 2
        xi = np.pi / 2
    else:
        phi = np.arcsin(np.sqrt(2) * np.sin(theta_prime / 4))
        xi = np.arctan(np.tan(phi) / np.sqrt(2))

    yield ops.rz(sign * 0.5 * theta_prime).on(a)
    yield ops.rz(sign * 0.5 * theta_prime).on(b)
    yield ops.rx(xi).on(a)
    yield ops.X(b)**(-sign * 0.5)
    yield SQRT_ISWAP_INV(a, b)
    yield ops.rx(-2 * phi).on(a)
    yield SQRT_ISWAP(a, b)

    yield ops.rx(xi).on(a)
    yield ops.X(b)**(sign * 0.5)
    # Corrects global phase
    yield ops.GlobalPhaseOperation(np.exp(sign * theta_prime * 0.25j))
Esempio n. 11
0
def _decompose_xx_yy_into_two_fsims_ignoring_single_qubit_ops(
    *,
    qubits: Sequence['cirq.Qid'],
    fsim_gate: 'cirq.FSimGate',
    canonical_x_kak_coefficient: float,
    canonical_y_kak_coefficient: float,
    atol: float = 1e-8,
) -> List['cirq.Operation']:
    x = canonical_x_kak_coefficient
    y = canonical_y_kak_coefficient
    assert 0 <= y <= x <= np.pi / 4

    eta = np.sin(x) ** 2 * np.cos(y) ** 2 + np.cos(x) ** 2 * np.sin(y) ** 2
    xi = abs(np.sin(2 * x) * np.sin(2 * y))

    t = fsim_gate.phi / 2
    kappa = np.sin(fsim_gate.theta) ** 2 - np.sin(t) ** 2
    s_sum = (eta - np.sin(t) ** 2) / kappa
    s_dif = 0.5 * xi / kappa

    a_dif = _sticky_0_to_1(s_sum + s_dif, atol=atol)
    a_sum = _sticky_0_to_1(s_sum - s_dif, atol=atol)
    if a_dif is None or a_sum is None:
        raise ValueError(
            f'Failed to synthesize XX^{x/np.pi}·YY^{y/np.pi} from two '
            f'{fsim_gate!r} separated by single qubit operations.'
        )

    x_dif = np.arcsin(np.sqrt(a_dif))
    x_sum = np.arcsin(np.sqrt(a_sum))

    x_a = x_sum + x_dif
    x_b = x_dif - x_sum

    a, b = qubits
    return [
        fsim_gate(a, b),
        ops.rz(t + np.pi).on(a),
        ops.rz(t).on(b),
        ops.rx(x_a).on(a),
        ops.rx(x_b).on(b),
        fsim_gate(a, b),
    ]
Esempio n. 12
0
def _translate_one_qubit_braket_instruction_to_cirq_operation(
    instr: Instruction,
) -> List[cirq_ops.Operation]:
    """Converts the one-qubit braket instruction to Cirq.

    Args:
        instr: One-qubit Braket instruction to convert.

    Raises:
        ValueError: If the instruction cannot be converted to Cirq.
    """
    qubits = [LineQubit(int(qubit)) for qubit in instr.target]
    gate = instr.operator

    # One-qubit non-parameterized gates.
    if isinstance(gate, braket_gates.I):
        return [cirq_ops.I.on(*qubits)]
    elif isinstance(gate, braket_gates.X):
        return [cirq_ops.X.on(*qubits)]
    elif isinstance(gate, braket_gates.Y):
        return [cirq_ops.Y.on(*qubits)]
    elif isinstance(gate, braket_gates.Z):
        return [cirq_ops.Z.on(*qubits)]
    elif isinstance(gate, braket_gates.H):
        return [cirq_ops.H.on(*qubits)]
    elif isinstance(gate, braket_gates.S):
        return [cirq_ops.S.on(*qubits)]
    elif isinstance(gate, braket_gates.Si):
        return [protocols.inverse(cirq_ops.S.on(*qubits))]
    elif isinstance(gate, braket_gates.T):
        return [cirq_ops.T.on(*qubits)]
    elif isinstance(gate, braket_gates.Ti):
        return [protocols.inverse(cirq_ops.T.on(*qubits))]
    elif isinstance(gate, braket_gates.V):
        return [cirq_ops.X.on(*qubits) ** 0.5]
    elif isinstance(gate, braket_gates.Vi):
        return [cirq_ops.X.on(*qubits) ** -0.5]

    # One-qubit parameterized gates.
    elif isinstance(gate, braket_gates.Rx):
        return [cirq_ops.rx(gate.angle).on(*qubits)]
    elif isinstance(gate, braket_gates.Ry):
        return [cirq_ops.ry(gate.angle).on(*qubits)]
    elif isinstance(gate, braket_gates.Rz):
        return [cirq_ops.rz(gate.angle).on(*qubits)]
    elif isinstance(gate, braket_gates.PhaseShift):
        return [cirq_ops.Z.on(*qubits) ** (gate.angle / np.pi)]

    else:
        _raise_braket_to_cirq_error(instr)

    return None  # type: ignore[return-value]  # pragma: no cover
Esempio n. 13
0
def _translate_one_qubit_braket_instruction_to_cirq_operation(
    instr: Instruction, ) -> List["cirq.Operation"]:
    """Converts the one-qubit braket instruction to Cirq.

    Args:
        instr: One-qubit Braket instruction to convert.

    Raises:
        ValueError: If the instruction cannot be converted to Cirq.
    """
    qubits = [LineQubit(int(qubit)) for qubit in instr.target]
    gate = instr.operator

    # One-qubit non-parameterized gates.
    if isinstance(gate, braket_gates.I):
        return [cirq_ops.I.on(*qubits)]
    elif isinstance(gate, braket_gates.X):
        return [cirq_ops.X.on(*qubits)]
    elif isinstance(gate, braket_gates.Y):
        return [cirq_ops.Y.on(*qubits)]
    elif isinstance(gate, braket_gates.Z):
        return [cirq_ops.Z.on(*qubits)]
    elif isinstance(gate, braket_gates.H):
        return [cirq_ops.H.on(*qubits)]
    elif isinstance(gate, braket_gates.S):
        return [cirq_ops.S.on(*qubits)]
    elif isinstance(gate, braket_gates.Si):
        return [cirq_ops.S.on(*qubits)**-1.0]
    elif isinstance(gate, braket_gates.T):
        return [cirq_ops.T.on(*qubits)]
    elif isinstance(gate, braket_gates.Ti):
        return [cirq_ops.T.on(*qubits)**-1.0]
    elif isinstance(gate, braket_gates.V):
        return [cirq_ops.X.on(*qubits)**0.5]
    elif isinstance(gate, braket_gates.Vi):
        return [cirq_ops.X.on(*qubits)**-0.5]

    # One-qubit parameterized gates.
    elif isinstance(gate, braket_gates.Rx):
        return [cirq_ops.rx(gate.angle).on(*qubits)]
    elif isinstance(gate, braket_gates.Ry):
        return [cirq_ops.ry(gate.angle).on(*qubits)]
    elif isinstance(gate, braket_gates.Rz):
        return [cirq_ops.rz(gate.angle).on(*qubits)]
    elif isinstance(gate, braket_gates.PhaseShift):
        return [cirq_ops.Z.on(*qubits)**(gate.angle / np.pi)]

    else:
        raise ValueError(
            f"Unable to convert the instruction {instr} to Cirq. If you think "
            "this is a bug, you can open an issue on the Mitiq GitHub at "
            "https://github.com/unitaryfund/mitiq.")
Esempio n. 14
0
def test_circuit_from_quil():
    q0, q1, q2 = LineQubit.range(3)
    cirq_circuit = Circuit([
        I(q0),
        I(q1),
        I(q2),
        X(q0),
        Y(q1),
        Z(q2),
        H(q0),
        S(q1),
        T(q2),
        Z(q0)**(1 / 8),
        Z(q1)**(1 / 8),
        Z(q2)**(1 / 8),
        rx(np.pi / 2)(q0),
        ry(np.pi / 2)(q1),
        rz(np.pi / 2)(q2),
        CZ(q0, q1),
        CNOT(q1, q2),
        cphase(np.pi / 2)(q0, q1),
        cphase00(np.pi / 2)(q1, q2),
        cphase01(np.pi / 2)(q0, q1),
        cphase10(np.pi / 2)(q1, q2),
        ISWAP(q0, q1),
        pswap(np.pi / 2)(q1, q2),
        SWAP(q0, q1),
        xy(np.pi / 2)(q1, q2),
        CCNOT(q0, q1, q2),
        CSWAP(q0, q1, q2),
        MeasurementGate(1, key="ro[0]")(q0),
        MeasurementGate(1, key="ro[1]")(q1),
        MeasurementGate(1, key="ro[2]")(q2),
    ])
    # build the same Circuit, using Quil
    quil_circuit = circuit_from_quil(QUIL_PROGRAM)
    # test Circuit equivalence
    assert cirq_circuit == quil_circuit

    pyquil_circuit = Program(QUIL_PROGRAM)
    # drop declare and measures, get Program unitary
    pyquil_unitary = program_unitary(pyquil_circuit[1:-3], n_qubits=3)
    # fix qubit order convention
    cirq_circuit_swapped = Circuit(SWAP(q0, q2), cirq_circuit[:-1],
                                   SWAP(q0, q2))
    # get Circuit unitary
    cirq_unitary = cirq_circuit_swapped.unitary()
    # test unitary equivalence
    assert np.isclose(pyquil_unitary, cirq_unitary).all()
def generate_all_single_qubit_rotation_cell_makers() -> Iterator[CellMaker]:

    # Fixed single qubit rotations.
    yield _gate("H", ops.H)
    yield _gate("X", ops.X)
    yield _gate("Y", ops.Y)
    yield _gate("Z", ops.Z)
    yield _gate("X^½", ops.X**(1 / 2))
    yield _gate("X^⅓", ops.X**(1 / 3))
    yield _gate("X^¼", ops.X**(1 / 4))
    yield _gate("X^⅛", ops.X**(1 / 8))
    yield _gate("X^⅟₁₆", ops.X**(1 / 16))
    yield _gate("X^⅟₃₂", ops.X**(1 / 32))
    yield _gate("X^-½", ops.X**(-1 / 2))
    yield _gate("X^-⅓", ops.X**(-1 / 3))
    yield _gate("X^-¼", ops.X**(-1 / 4))
    yield _gate("X^-⅛", ops.X**(-1 / 8))
    yield _gate("X^-⅟₁₆", ops.X**(-1 / 16))
    yield _gate("X^-⅟₃₂", ops.X**(-1 / 32))
    yield _gate("Y^½", ops.Y**(1 / 2))
    yield _gate("Y^⅓", ops.Y**(1 / 3))
    yield _gate("Y^¼", ops.Y**(1 / 4))
    yield _gate("Y^⅛", ops.Y**(1 / 8))
    yield _gate("Y^⅟₁₆", ops.Y**(1 / 16))
    yield _gate("Y^⅟₃₂", ops.Y**(1 / 32))
    yield _gate("Y^-½", ops.Y**(-1 / 2))
    yield _gate("Y^-⅓", ops.Y**(-1 / 3))
    yield _gate("Y^-¼", ops.Y**(-1 / 4))
    yield _gate("Y^-⅛", ops.Y**(-1 / 8))
    yield _gate("Y^-⅟₁₆", ops.Y**(-1 / 16))
    yield _gate("Y^-⅟₃₂", ops.Y**(-1 / 32))
    yield _gate("Z^½", ops.Z**(1 / 2))
    yield _gate("Z^⅓", ops.Z**(1 / 3))
    yield _gate("Z^¼", ops.Z**(1 / 4))
    yield _gate("Z^⅛", ops.Z**(1 / 8))
    yield _gate("Z^⅟₁₆", ops.Z**(1 / 16))
    yield _gate("Z^⅟₃₂", ops.Z**(1 / 32))
    yield _gate("Z^⅟₆₄", ops.Z**(1 / 64))
    yield _gate("Z^⅟₁₂₈", ops.Z**(1 / 128))
    yield _gate("Z^-½", ops.Z**(-1 / 2))
    yield _gate("Z^-⅓", ops.Z**(-1 / 3))
    yield _gate("Z^-¼", ops.Z**(-1 / 4))
    yield _gate("Z^-⅛", ops.Z**(-1 / 8))
    yield _gate("Z^-⅟₁₆", ops.Z**(-1 / 16))

    # Dynamic single qubit rotations.
    yield _gate("X^t", ops.X**sympy.Symbol('t'))
    yield _gate("Y^t", ops.Y**sympy.Symbol('t'))
    yield _gate("Z^t", ops.Z**sympy.Symbol('t'))
    yield _gate("X^-t", ops.X**-sympy.Symbol('t'))
    yield _gate("Y^-t", ops.Y**-sympy.Symbol('t'))
    yield _gate("Z^-t", ops.Z**-sympy.Symbol('t'))
    yield _gate("e^iXt", ops.rx(2 * sympy.pi * sympy.Symbol('t')))
    yield _gate("e^iYt", ops.ry(2 * sympy.pi * sympy.Symbol('t')))
    yield _gate("e^iZt", ops.rz(2 * sympy.pi * sympy.Symbol('t')))
    yield _gate("e^-iXt", ops.rx(-2 * sympy.pi * sympy.Symbol('t')))
    yield _gate("e^-iYt", ops.ry(-2 * sympy.pi * sympy.Symbol('t')))
    yield _gate("e^-iZt", ops.rz(-2 * sympy.pi * sympy.Symbol('t')))

    # Formulaic single qubit rotations.
    yield _formula_gate("X^ft", "sin(pi*t)", lambda e: ops.X**e)
    yield _formula_gate("Y^ft", "sin(pi*t)", lambda e: ops.Y**e)
    yield _formula_gate("Z^ft", "sin(pi*t)", lambda e: ops.Z**e)
    yield _formula_gate("Rxft", "pi*t*t", ops.rx)
    yield _formula_gate("Ryft", "pi*t*t", ops.ry)
    yield _formula_gate("Rzft", "pi*t*t", ops.rz)
Esempio n. 16
0
class QasmParser:
    """Parser for QASM strings.

    Example:

        qasm = "OPENQASM 2.0; qreg q1[2]; CX q1[0], q1[1];"
        parsedQasm = QasmParser().parse(qasm)
    """
    def __init__(self):
        self.parser = yacc.yacc(module=self, debug=False, write_tables=False)
        self.circuit = Circuit()
        self.qregs: Dict[str, int] = {}
        self.cregs: Dict[str, int] = {}
        self.qelibinc = False
        self.lexer = QasmLexer()
        self.supported_format = False
        self.parsedQasm: Optional[Qasm] = None
        self.qubits: Dict[str, ops.Qid] = {}
        self.functions = {
            'sin': np.sin,
            'cos': np.cos,
            'tan': np.tan,
            'exp': np.exp,
            'ln': np.log,
            'sqrt': np.sqrt,
            'acos': np.arccos,
            'atan': np.arctan,
            'asin': np.arcsin,
        }

        self.binary_operators = {
            '+': operator.add,
            '-': operator.sub,
            '*': operator.mul,
            '/': operator.truediv,
            '^': operator.pow,
        }

    basic_gates: Dict[str, QasmGateStatement] = {
        'CX':
        QasmGateStatement(qasm_gate='CX',
                          cirq_gate=CX,
                          num_params=0,
                          num_args=2),
        'U':
        QasmGateStatement(
            qasm_gate='U',
            num_params=3,
            num_args=1,
            # QasmUGate expects half turns
            cirq_gate=(lambda params: QasmUGate(*[p / np.pi for p in params])),
        ),
    }

    qelib_gates = {
        'rx':
        QasmGateStatement(qasm_gate='rx',
                          cirq_gate=(lambda params: ops.rx(params[0])),
                          num_params=1,
                          num_args=1),
        'ry':
        QasmGateStatement(qasm_gate='ry',
                          cirq_gate=(lambda params: ops.ry(params[0])),
                          num_params=1,
                          num_args=1),
        'rz':
        QasmGateStatement(qasm_gate='rz',
                          cirq_gate=(lambda params: ops.rz(params[0])),
                          num_params=1,
                          num_args=1),
        'id':
        QasmGateStatement(qasm_gate='id',
                          cirq_gate=ops.IdentityGate(1),
                          num_params=0,
                          num_args=1),
        'u1':
        QasmGateStatement(
            qasm_gate='u1',
            cirq_gate=(lambda params: QasmUGate(0, 0, params[0] / np.pi)),
            num_params=1,
            num_args=1,
        ),
        'u2':
        QasmGateStatement(
            qasm_gate='u2',
            cirq_gate=(lambda params: QasmUGate(0.5, params[0] / np.pi, params[
                1] / np.pi)),
            num_params=2,
            num_args=1,
        ),
        'u3':
        QasmGateStatement(
            qasm_gate='u3',
            num_params=3,
            num_args=1,
            cirq_gate=(lambda params: QasmUGate(*[p / np.pi for p in params])),
        ),
        'x':
        QasmGateStatement(qasm_gate='x',
                          num_params=0,
                          num_args=1,
                          cirq_gate=ops.X),
        'y':
        QasmGateStatement(qasm_gate='y',
                          num_params=0,
                          num_args=1,
                          cirq_gate=ops.Y),
        'z':
        QasmGateStatement(qasm_gate='z',
                          num_params=0,
                          num_args=1,
                          cirq_gate=ops.Z),
        'h':
        QasmGateStatement(qasm_gate='h',
                          num_params=0,
                          num_args=1,
                          cirq_gate=ops.H),
        's':
        QasmGateStatement(qasm_gate='s',
                          num_params=0,
                          num_args=1,
                          cirq_gate=ops.S),
        't':
        QasmGateStatement(qasm_gate='t',
                          num_params=0,
                          num_args=1,
                          cirq_gate=ops.T),
        'cx':
        QasmGateStatement(qasm_gate='cx',
                          cirq_gate=CX,
                          num_params=0,
                          num_args=2),
        'cy':
        QasmGateStatement(qasm_gate='cy',
                          cirq_gate=ops.ControlledGate(ops.Y),
                          num_params=0,
                          num_args=2),
        'cz':
        QasmGateStatement(qasm_gate='cz',
                          cirq_gate=ops.CZ,
                          num_params=0,
                          num_args=2),
        'ch':
        QasmGateStatement(qasm_gate='ch',
                          cirq_gate=ops.ControlledGate(ops.H),
                          num_params=0,
                          num_args=2),
        'swap':
        QasmGateStatement(qasm_gate='swap',
                          cirq_gate=ops.SWAP,
                          num_params=0,
                          num_args=2),
        'cswap':
        QasmGateStatement(qasm_gate='cswap',
                          num_params=0,
                          num_args=3,
                          cirq_gate=ops.CSWAP),
        'ccx':
        QasmGateStatement(qasm_gate='ccx',
                          num_params=0,
                          num_args=3,
                          cirq_gate=ops.CCX),
        'sdg':
        QasmGateStatement(qasm_gate='sdg',
                          num_params=0,
                          num_args=1,
                          cirq_gate=ops.S**-1),
        'tdg':
        QasmGateStatement(qasm_gate='tdg',
                          num_params=0,
                          num_args=1,
                          cirq_gate=ops.T**-1),
    }

    all_gates = {**basic_gates, **qelib_gates}

    tokens = QasmLexer.tokens
    start = 'start'

    precedence = (
        ('left', '+', '-'),
        ('left', '*', '/'),
        ('right', '^'),
    )

    def p_start(self, p):
        """start : qasm"""
        p[0] = p[1]

    def p_qasm_format_only(self, p):
        """qasm : format"""
        self.supported_format = True
        p[0] = Qasm(self.supported_format, self.qelibinc, self.qregs,
                    self.cregs, self.circuit)

    def p_qasm_no_format_specified_error(self, p):
        """qasm : QELIBINC
        | circuit"""
        if self.supported_format is False:
            raise QasmException("Missing 'OPENQASM 2.0;' statement")

    def p_qasm_include(self, p):
        """qasm : qasm QELIBINC"""
        self.qelibinc = True
        p[0] = Qasm(self.supported_format, self.qelibinc, self.qregs,
                    self.cregs, self.circuit)

    def p_qasm_circuit(self, p):
        """qasm : qasm circuit"""
        p[0] = Qasm(self.supported_format, self.qelibinc, self.qregs,
                    self.cregs, p[2])

    def p_format(self, p):
        """format : FORMAT_SPEC"""
        if p[1] != "2.0":
            raise QasmException(
                "Unsupported OpenQASM version: {}, "
                "only 2.0 is supported currently by Cirq".format(p[1]))

    # circuit : new_reg circuit
    #         | gate_op circuit
    #         | measurement circuit
    #         | empty

    def p_circuit_reg(self, p):
        """circuit : new_reg circuit"""
        p[0] = self.circuit

    def p_circuit_gate_or_measurement(self, p):
        """circuit :  circuit gate_op
        |  circuit measurement"""
        self.circuit.append(p[2])
        p[0] = self.circuit

    def p_circuit_empty(self, p):
        """circuit : empty"""
        p[0] = self.circuit

    # qreg and creg

    def p_new_reg(self, p):
        """new_reg : QREG ID '[' NATURAL_NUMBER ']' ';'
        | CREG ID '[' NATURAL_NUMBER ']' ';'"""
        name, length = p[2], p[4]
        if name in self.qregs.keys() or name in self.cregs.keys():
            raise QasmException("{} is already defined at line {}".format(
                name, p.lineno(2)))
        if length == 0:
            raise QasmException(
                "Illegal, zero-length register '{}' at line {}".format(
                    name, p.lineno(4)))
        if p[1] == "qreg":
            self.qregs[name] = length
        else:
            self.cregs[name] = length
        p[0] = (name, length)

    # gate operations
    # gate_op : ID qargs
    #         | ID ( params ) qargs

    def p_gate_op_no_params(self, p):
        """gate_op :  ID qargs"""
        self._resolve_gate_operation(p[2], gate=p[1], p=p, params=[])

    def p_gate_op_with_params(self, p):
        """gate_op :  ID '(' params ')' qargs"""
        self._resolve_gate_operation(args=p[5], gate=p[1], p=p, params=p[3])

    def _resolve_gate_operation(self, args: List[List[ops.Qid]], gate: str,
                                p: Any, params: List[float]):
        gate_set = self.basic_gates if not self.qelibinc else self.all_gates
        if gate not in gate_set.keys():
            msg = 'Unknown gate "{}" at line {}{}'.format(
                gate,
                p.lineno(1),
                ", did you forget to include qelib1.inc?"
                if not self.qelibinc else "",
            )
            raise QasmException(msg)
        p[0] = gate_set[gate].on(args=args, params=params, lineno=p.lineno(1))

    # params : parameter ',' params
    #        | parameter

    def p_params_multiple(self, p):
        """params : expr ',' params"""
        p[3].insert(0, p[1])
        p[0] = p[3]

    def p_params_single(self, p):
        """params : expr """
        p[0] = [p[1]]

    # expr : term
    #            | func '(' expression ')' """
    #            | binary_op
    #            | unary_op

    def p_expr_term(self, p):
        """expr : term"""
        p[0] = p[1]

    def p_expr_parens(self, p):
        """expr : '(' expr ')'"""
        p[0] = p[2]

    def p_expr_function_call(self, p):
        """expr : ID '(' expr ')'"""
        func = p[1]
        if func not in self.functions.keys():
            raise QasmException(
                "Function not recognized: '{}' at line {}".format(
                    func, p.lineno(1)))
        p[0] = self.functions[func](p[3])

    def p_expr_unary(self, p):
        """expr : '-' expr
        | '+' expr"""
        if p[1] == '-':
            p[0] = -p[2]
        else:
            p[0] = p[2]

    def p_expr_binary(self, p):
        """expr : expr '*' expr
        | expr '/' expr
        | expr '+' expr
        | expr '-' expr
        | expr '^' expr
        """
        p[0] = self.binary_operators[p[2]](p[1], p[3])

    def p_term(self, p):
        """term : NUMBER
        | NATURAL_NUMBER
        | PI"""
        p[0] = p[1]

    # qargs : qarg ',' qargs
    #      | qarg ';'

    def p_args_multiple(self, p):
        """qargs : qarg ',' qargs"""
        p[3].insert(0, p[1])
        p[0] = p[3]

    def p_args_single(self, p):
        """qargs : qarg ';'"""
        p[0] = [p[1]]

    # qarg : ID
    #     | ID '[' NATURAL_NUMBER ']'

    def p_quantum_arg_register(self, p):
        """qarg : ID """
        reg = p[1]
        if reg not in self.qregs.keys():
            raise QasmException(
                'Undefined quantum register "{}" at line {}'.format(
                    reg, p.lineno(1)))
        qubits = []
        for idx in range(self.qregs[reg]):
            arg_name = self.make_name(idx, reg)
            if arg_name not in self.qubits.keys():
                self.qubits[arg_name] = NamedQubit(arg_name)
            qubits.append(self.qubits[arg_name])
        p[0] = qubits

    # carg : ID
    #     | ID '[' NATURAL_NUMBER ']'

    def p_classical_arg_register(self, p):
        """carg : ID """
        reg = p[1]
        if reg not in self.cregs.keys():
            raise QasmException(
                'Undefined classical register "{}" at line {}'.format(
                    reg, p.lineno(1)))

        p[0] = [self.make_name(idx, reg) for idx in range(self.cregs[reg])]

    def make_name(self, idx, reg):
        return str(reg) + "_" + str(idx)

    def p_quantum_arg_bit(self, p):
        """qarg : ID '[' NATURAL_NUMBER ']' """
        reg = p[1]
        idx = p[3]
        arg_name = self.make_name(idx, reg)
        if reg not in self.qregs.keys():
            raise QasmException(
                'Undefined quantum register "{}" at line {}'.format(
                    reg, p.lineno(1)))
        size = self.qregs[reg]
        if idx >= size:
            raise QasmException('Out of bounds qubit index {} '
                                'on register {} of size {} '
                                'at line {}'.format(idx, reg, size,
                                                    p.lineno(1)))
        if arg_name not in self.qubits.keys():
            self.qubits[arg_name] = NamedQubit(arg_name)
        p[0] = [self.qubits[arg_name]]

    def p_classical_arg_bit(self, p):
        """carg : ID '[' NATURAL_NUMBER ']' """
        reg = p[1]
        idx = p[3]
        arg_name = self.make_name(idx, reg)
        if reg not in self.cregs.keys():
            raise QasmException(
                'Undefined classical register "{}" at line {}'.format(
                    reg, p.lineno(1)))

        size = self.cregs[reg]
        if idx >= size:
            raise QasmException('Out of bounds bit index {} '
                                'on classical register {} of size {} '
                                'at line {}'.format(idx, reg, size,
                                                    p.lineno(1)))
        p[0] = [arg_name]

    # measurement operations
    # measurement : MEASURE qarg ARROW carg

    def p_measurement(self, p):
        """measurement : MEASURE qarg ARROW carg ';'"""
        qreg = p[2]
        creg = p[4]

        if len(qreg) != len(creg):
            raise QasmException(
                'mismatched register sizes {} -> {} for measurement '
                'at line {}'.format(len(qreg), len(creg), p.lineno(1)))

        p[0] = [
            ops.MeasurementGate(num_qubits=1, key=creg[i]).on(qreg[i])
            for i in range(len(qreg))
        ]

    def p_error(self, p):
        if p is None:
            raise QasmException('Unexpected end of file')

        raise QasmException("""Syntax error: '{}'
{}
at line {}, column {}""".format(p.value, self.debug_context(p), p.lineno,
                                self.find_column(p)))

    def find_column(self, p):
        line_start = self.qasm.rfind('\n', 0, p.lexpos) + 1
        return (p.lexpos - line_start) + 1

    def p_empty(self, p):
        """empty :"""

    def parse(self, qasm: str) -> Qasm:
        if self.parsedQasm is None:
            self.qasm = qasm
            self.lexer.input(self.qasm)
            self.parsedQasm = self.parser.parse(lexer=self.lexer)
        return self.parsedQasm

    def debug_context(self, p):
        debug_start = max(self.qasm.rfind('\n', 0, p.lexpos) + 1, p.lexpos - 5)
        debug_end = min(self.qasm.find('\n', p.lexpos, p.lexpos + 5),
                        p.lexpos + 5)

        return ("..." + self.qasm[debug_start:debug_end] + "\n" +
                (" " * (3 + p.lexpos - debug_start)) + "^")
def decompose_cphase_into_two_fsim(cphase_gate: 'cirq.CZPowGate',
                                   *,
                                   fsim_gate: 'cirq.FSimGate',
                                   qubits: Optional[
                                       Sequence['cirq.Qid']] = None,
                                   atol: float = 1e-8) -> 'cirq.OP_TREE':
    """Decomposes CZPowGate into two FSimGates.

    This function implements the decomposition described in section VII F I
    of https://arxiv.org/abs/1910.11333.

    The decomposition results in exactly two FSimGates and a few single-qubit
    rotations. It is feasible if and only if one of the following conditions
    is met:

        |sin(θ)| <= |sin(δ/4)| <= |sin(φ/2)|
        |sin(φ/2)| <= |sin(δ/4)| <= |sin(θ)|

    where:

         θ = fsim_gate.theta,
         φ = fsim_gate.phi,
         δ = -π * cphase_gate.exponent.

    Note that the gate parametrizations are non-injective. For the
    decomposition to be feasible it is sufficient that one of the
    parameter values which correspond to the provided gate satisfies
    the constraints. This function will find and use the appropriate
    value whenever it exists.

    The constraints above imply that certain FSimGates are not suitable
    for use in this decomposition regardless of the target CZPowGate. We
    reject such gates based on how close |sin(θ)| is to |sin(φ/2)|, see
    atol argument below.

    This implementation accounts for the global phase.

    Args:
        cphase_gate: The CZPowGate to synthesize.
        fsim_gate: The only two qubit gate that is permitted to appear in the
            output.
        qubits: The qubits to apply the resulting operations to. If not set,
            defaults `cirq.LineQubit.range(2)`.
        atol: Tolerance used to determine whether fsim_gate is valid. The gate
            is invalid if the squares of the sines of the theta angle and half
            the phi angle are too close.

    Returns:
        Operations equivalent to cphase_gate and consisting solely of two copies
        of fsim_gate and a few single-qubit rotations.

    Raises:
        ValueError under any of the following circumstances:
         * cphase_gate or fsim_gate is parametrized,
         * cphase_gate and fsim_gate do not satisfy the conditions above,
         * fsim_gate has invalid angles (see atol argument above),
         * incorrect number of qubits are provided.
    """
    if protocols.is_parameterized(cphase_gate):
        raise ValueError('Cannot decompose a parametrized gate.')
    if protocols.is_parameterized(fsim_gate):
        raise ValueError('Cannot decompose into a parametrized gate.')
    if qubits is None:
        qubits = devices.LineQubit.range(2)
    if len(qubits) != 2:
        raise ValueError(f'Expected a pair of qubits, but got {qubits!r}.')
    q0, q1 = qubits

    theta = fsim_gate.theta
    phi = fsim_gate.phi

    sin_half_phi = np.sin(phi / 2)
    cos_half_phi = np.cos(phi / 2)
    sin_theta = np.sin(theta)
    cos_theta = np.cos(theta)

    #
    # Step 1: find alpha
    #
    denominator = (sin_theta - sin_half_phi) * (sin_theta + sin_half_phi)
    if abs(denominator) < atol:
        raise ValueError(
            f'{fsim_gate} cannot be used to decompose CZPowGate because '
            'sin(theta)**2 is too close to sin(phi/2)**2 '
            f'(difference is {denominator}).')

    # Parametrization of CZPowGate by a real angle is a non-injective function
    # with the preimage of cphase_gate infinite. However, it is sufficient to
    # check just two of the angles against the constraints of the decomposition.
    canonical_delta = -np.pi * (cphase_gate.exponent % 2)
    for delta in (canonical_delta, canonical_delta + 2 * np.pi):
        sin_quarter_delta = np.sin(delta / 4)
        numerator = (sin_quarter_delta - sin_half_phi) * (sin_quarter_delta +
                                                          sin_half_phi)
        sin_alpha_squared = numerator / denominator
        if 0 <= sin_alpha_squared <= 1:
            break
    else:
        intervals = compute_cphase_exponents_for_fsim_decomposition(fsim_gate)
        raise ValueError(
            f'{cphase_gate} cannot be decomposed into two {fsim_gate}. Valid '
            f'intervals for canonical exponent of CZPowGate: {intervals}.')
    assert 0 <= sin_alpha_squared <= 1
    alpha = np.arcsin(np.sqrt(sin_alpha_squared))

    #
    # Step 2: find xi and eta
    #
    tan_alpha = np.tan(alpha)
    xi = np.arctan2(tan_alpha * cos_theta, cos_half_phi)
    eta = np.arctan2(tan_alpha * sin_theta, sin_half_phi)
    if delta < 0:
        eta += np.pi

    #
    # Step 3: synthesize output circuit
    #
    return (
        # Local X rotations to convert Γ1⊗I − iZ⊗Γ2 into exp(-i Z⊗Z δ/4)
        ops.rx(xi).on(q0),
        ops.rx(eta).on(q1),

        # Y(θ, φ) := exp(-i X⊗X θ/2) exp(-i Y⊗Y θ/2) exp(-i Z⊗Z φ/4)
        fsim_gate.on(q0, q1),
        ops.rz(phi / 2).on(q0),
        ops.rz(phi / 2).on(q1),
        ops.GlobalPhaseOperation(np.exp(1j * phi / 4)),

        # exp(i X1 α)
        ops.rx(-2 * alpha).on(q0),

        # Y(-θ, φ) := exp(i X⊗X θ/2) exp(i Y⊗Y θ/2) exp(-i Z⊗Z φ/4)
        ops.Z(q0),
        fsim_gate.on(q0, q1),
        ops.rz(phi / 2).on(q0),
        ops.rz(phi / 2).on(q1),
        ops.GlobalPhaseOperation(np.exp(1j * phi / 4)),
        ops.Z(q0),

        # Local X rotations to convert Γ1⊗I − iZ⊗Γ2 into exp(-i Z⊗Z δ/4)
        ops.rx(-eta).on(q1),
        ops.rx(xi).on(q0),

        # Local Z rotations to convert exp(-i Z⊗Z δ/4) into desired CPhase.
        ops.rz(-delta / 2).on(q0),
        ops.rz(-delta / 2).on(q1),
        ops.GlobalPhaseOperation(np.exp(-1j * delta / 4)),
    )
Esempio n. 18
0
def _decomp_2sqrt_iswap_matrices(
    kak: 'cirq.KakDecomposition',
    atol: float = 1e-8,
) -> Tuple[Sequence[Tuple[np.ndarray, np.ndarray]], complex]:
    """Returns the single-qubit matrices for the 2-SQRT_ISWAP decomposition.

    Assumes canonical x, y, z and x >= y + |z| within tolerance.  For x, y, z
    that violate this inequality, three sqrt-iSWAP gates are required.

    References:
        Towards ultra-high fidelity quantum operations: SQiSW gate as a native
        two-qubit gate
        https://arxiv.org/abs/2105.06074
    """
    # Follows the if-branch of procedure DECOMP(U) in Algorithm 1 of the paper
    x, y, z = kak.interaction_coefficients
    b0, b1 = kak.single_qubit_operations_before
    a0, a1 = kak.single_qubit_operations_after

    # Computed gate parameters: Eq. 4, 6, 7, 8 of the paper
    # range limits added for robustness to numerical error
    def safe_arccos(v):
        return np.arccos(np.clip(v, -1, 1))

    def nonzero_sign(v):
        return -1 if v < 0 else 1

    _c = np.clip(
        np.sin(x + y - z) * np.sin(x - y + z) * np.sin(-x - y - z) * np.sin(-x + y + z), 0, 1
    )
    alpha = safe_arccos(np.cos(2 * x) - np.cos(2 * y) + np.cos(2 * z) + 2 * np.sqrt(_c))
    beta = safe_arccos(np.cos(2 * x) - np.cos(2 * y) + np.cos(2 * z) - 2 * np.sqrt(_c))
    # Don't need to limit this value because it will always be positive and the clip in the
    # following `safe_arccos` handles the cases where this could be slightly greater than 1.
    _4ccs = 4 * (np.cos(x) * np.cos(z) * np.sin(y)) ** 2  # Intermediate value
    gamma = safe_arccos(
        nonzero_sign(z)
        * np.sqrt(_4ccs / (_4ccs + np.clip(np.cos(2 * x) * np.cos(2 * y) * np.cos(2 * z), 0, 1)))
    )

    # Inner single-qubit gates: Fig. 4 of the paper
    # Gate angles here are multiplied by -2 to adjust for non-standard gate definitions in the paper
    c0 = (
        protocols.unitary(ops.rz(-gamma))
        @ protocols.unitary(ops.rx(-alpha))
        @ protocols.unitary(ops.rz(-gamma))
    )
    c1 = protocols.unitary(ops.rx(-beta))

    # Compute KAK on the decomposition to determine outer single-qubit gates
    # There is no known closed form solution for these gates
    u_sqrt_iswap = protocols.unitary(ops.SQRT_ISWAP)
    u = u_sqrt_iswap @ np.kron(c0, c1) @ u_sqrt_iswap  # Unitary of decomposition
    kak_fix = linalg.kak_decomposition(u, atol=atol / 10, rtol=0, check_preconditions=False)
    e0, e1 = kak_fix.single_qubit_operations_before
    d0, d1 = kak_fix.single_qubit_operations_after

    return [  # Pairs of single-qubit unitaries, SQRT_ISWAP between each is implied
        (e0.T.conj() @ b0, e1.T.conj() @ b1),
        (c0, c1),
        (a0 @ d0.T.conj(), a1 @ d1.T.conj()),
    ], kak.global_phase / kak_fix.global_phase
Esempio n. 19
0
# See the License for the specific language governing permissions and
# limitations under the License.
"""
IQM's Valkmusa quantum architecture.
"""
from math import pi as PI
from typing import Optional

from cirq import ops

from .iqm_device import IQMDevice

PI_2 = PI / 2

# common gates used in gate decompositions
Lx = ops.rx(PI_2)
Lxi = ops.rx(-PI_2)
Ly = ops.ry(PI_2)
Lyi = ops.ry(-PI_2)
Lz = ops.rz(PI_2)
Lzi = ops.rz(-PI_2)


class Valkmusa(IQMDevice):
    """IQM's two-qubit transmon device.

    The qubits are connected thus::

      QB1 - QB2

    Each qubit can be rotated about any axis in the xy plane by an arbitrary angle.