Esempio n. 1
0
def test_eval():
    x = Parameter('x')
    assert substitute(x, {x: 5}) == 5

    y = Parameter('y')
    assert substitute(x + y, {x: 5, y: 6}) == 11
    assert substitute(x + y, {x: 5}) == 5 + y
    assert substitute(quil_exp(x), {y: 5}) != np.exp(5)
    assert substitute(quil_exp(x), {x: 5}) == np.exp(5)

    assert np.isclose(substitute(quil_sin(x * x**2 / y), {
        x: 5.0,
        y: 10.0
    }), np.sin(12.5))
    assert np.isclose(substitute(quil_sqrt(x), {
        x: 5.0,
        y: 10.0
    }), np.sqrt(5.0))
    assert np.isclose(substitute(quil_cis(x), {
        x: 5.0,
        y: 10.0
    }), np.exp(1j * 5.0))
    assert np.isclose(substitute(x - y, {x: 5.0, y: 10.0}), -5.)

    assert substitute(quil_cis(x), {y: 5}) == quil_cis(x)
    assert np.allclose(substitute_array([quil_sin(x), quil_cos(x)], {x: 5}),
                       [np.sin(5), np.cos(5)])
Esempio n. 2
0
def test_def_gate_with_variables():
    # Note that technically the RX gate includes -i instead of just i but this messes a bit with the test since
    # it's not smart enough to figure out that -1*i == -i
    theta = Parameter('theta')
    rx = np.array([[quil_cos(theta / 2), 1j * quil_sin(theta / 2)],
                   [1j * quil_sin(theta / 2), quil_cos(theta / 2)]])

    defgate = 'DEFGATE RX(%theta):\n' \
              '    COS(%theta/2), i*SIN(%theta/2)\n' \
              '    i*SIN(%theta/2), COS(%theta/2)\n\n'

    parse_equals(defgate, DefGate('RX', rx, [theta]))
Esempio n. 3
0
def test_def_gate_with_parameters():
    theta = Parameter('theta')
    rx = np.array([[quil_cos(theta / 2), -1j * quil_sin(theta / 2)],
                   [-1j * quil_sin(theta / 2), quil_cos(theta / 2)]])

    p = Program().defgate("RX", rx, [theta])
    assert p.out() == 'DEFGATE RX(%theta):\n' \
                      '    COS(%theta/2), -i*SIN(%theta/2)\n' \
                      '    -i*SIN(%theta/2), COS(%theta/2)\n\n'

    dg = DefGate('MY_RX', rx, [theta])
    MY_RX = dg.get_constructor()
    p = Program().inst(MY_RX(np.pi)(0))
    assert p.out() == 'MY_RX(pi) 0\n'
Esempio n. 4
0
def _apply_function(func, arg):
    # type: (QuilParser.FunctionContext, Any) -> Any
    if isinstance(arg, Expression):
        if func.SIN():
            return quil_sin(arg)
        elif func.COS():
            return quil_cos(arg)
        elif func.SQRT():
            return quil_sqrt(arg)
        elif func.EXP():
            return quil_exp(arg)
        elif func.CIS():
            return quil_cis(arg)
        else:
            raise RuntimeError("Unexpected function to apply: " +
                               func.getText())
    else:
        if func.SIN():
            return sin(arg)
        elif func.COS():
            return cos(arg)
        elif func.SQRT():
            return sqrt(arg)
        elif func.EXP():
            return exp(arg)
        elif func.CIS():
            return cos(arg) + complex(0, 1) * sin(arg)
        else:
            raise RuntimeError("Unexpected function to apply: " +
                               func.getText())
 def to_pyquil(e: Expr) -> Union[float, Expression]:
     if isinstance(e, Number):
         return float(e)
     elif isinstance(e, Symbol):
         return MemoryReference(str(e))
     elif isinstance(e, sin):
         return quil_sin(to_pyquil(e))
     elif isinstance(e, cos):
         return quil_cos(to_pyquil(e))
     elif isinstance(e, Add):
         args = [to_pyquil(a) for a in e.args]
         acc = args[0]
         for a in args[1:]:
             acc += a
         return acc
     elif isinstance(e, Mul):
         args = [to_pyquil(a) for a in e.args]
         acc = args[0]
         for a in args[1:]:
             acc *= a
         return acc
     elif isinstance(e, Pow):
         args = Pow_(to_pyquil(e.base),
                     to_pyquil(e.exp))  # type: ignore
     elif e == pi:
         return math.pi
     else:
         raise NotImplementedError(
             "Sympy expression could not be converted to a Quil expression: "
             + str(e))
Esempio n. 6
0
def test_contained_parameters():
    x = Parameter("x")
    assert _contained_parameters(x) == {x}

    y = Parameter("y")
    assert _contained_parameters(x + y) == {x, y}

    assert _contained_parameters(x ** y ** quil_sin(x * y * 4)) == {x, y}
Esempio n. 7
0
def test_converting_parametrized_custom_gate_to_pyquil_adds_its_definition_to_program(
):
    x, y, theta = sympy.symbols("x, y, theta")
    # Clearly, the below gate is not unitary. For the purpose of this test
    # it does not matter though.
    custom_gate = CustomGate(
        sympy.Matrix([
            [sympy.cos(x + y), sympy.sin(theta), 0, 0],
            [-sympy.sin(theta), sympy.cos(x + y), 0, 0],
            [0, 0, sympy.sqrt(x), sympy.exp(y)],
            [0, 0, 1.0, sympy.I],
        ]),
        (0, 2),
        "my_gate",
    )

    program = pyquil.Program()
    convert_to_pyquil(custom_gate, program)

    quil_x = pyquil.quil.Parameter("x")
    quil_y = pyquil.quil.Parameter("y")
    quil_theta = pyquil.quil.Parameter("theta")

    expected_pyquil_matrix = np.array([
        [
            quilatom.quil_cos(quil_x + quil_y),
            quilatom.quil_sin(quil_theta), 0, 0
        ],
        [
            -quilatom.quil_sin(quil_theta),
            quilatom.quil_cos(quil_x + quil_y), 0, 0
        ],
        [0, 0, quilatom.quil_sqrt(quil_x),
         quilatom.quil_exp(quil_y)],
        [0, 0, 1.0, 1j],
    ])

    # Note: we cannot replace this with a single assertion. This is because
    # the order of custom_gate.symbolic_params is not known.
    gate_definition = program.defined_gates[0]
    assert len(program.defined_gates) == 1
    assert len(gate_definition.parameters) == 3
    assert set(gate_definition.parameters) == {quil_x, quil_y, quil_theta}
    assert np.array_equal(gate_definition.matrix, expected_pyquil_matrix)
Esempio n. 8
0
def test_substitute_memory_reference():
    x_0 = MemoryReference("x", 0, declared_size=2)
    x_1 = MemoryReference("x", 1, declared_size=2)

    # complete substitutions

    assert substitute(x_0, {x_0: 5}) == 5

    assert substitute(x_0 + x_1, {x_0: +5, x_1: -5}) == 0
    assert substitute(x_0 - x_1, {x_0: +5, x_1: -5}) == 10
    assert substitute(x_0 * x_1, {x_0: +5, x_1: -5}) == -25
    assert substitute(x_0 / x_1, {x_0: +5, x_1: -5}) == -1

    assert substitute(x_0 * x_0**2 / x_1, {x_0: 5, x_1: 10}) == 12.5

    assert np.isclose(substitute(quil_exp(x_0), {x_0: 5, x_1: 10}), np.exp(5))
    assert np.isclose(substitute(quil_sin(x_0), {x_0: 5, x_1: 10}), np.sin(5))
    assert np.isclose(substitute(quil_cos(x_0), {x_0: 5, x_1: 10}), np.cos(5))
    assert np.isclose(substitute(quil_sqrt(x_0), {
        x_0: 5,
        x_1: 10
    }), np.sqrt(5))
    assert np.isclose(substitute(quil_cis(x_0), {
        x_0: 5,
        x_1: 10
    }), np.exp(1j * 5.0))

    # incomplete substitutions

    y = MemoryReference("y", 0, declared_size=1)
    z = MemoryReference("z", 0, declared_size=1)

    assert substitute(y + z, {y: 5}) == 5 + z

    assert substitute(quil_cis(z), {y: 5}) == quil_cis(z)

    # array substitution pass-through

    a = MemoryReference("a", 0, declared_size=1)

    assert np.allclose(substitute_array([quil_sin(a), quil_cos(a)], {a: 5}),
                       [np.sin(5), np.cos(5)])
Esempio n. 9
0
 def apply_fun(self, fun, arg):
     if fun == "SIN":
         return quil_sin(arg) if isinstance(arg, Expression) else np.sin(arg)
     if fun == "COS":
         return quil_cos(arg) if isinstance(arg, Expression) else np.cos(arg)
     if fun == "SQRT":
         return quil_sqrt(arg) if isinstance(arg, Expression) else np.sqrt(arg)
     if fun == "EXP":
         return quil_exp(arg) if isinstance(arg, Expression) else np.exp(arg)
     if fun == "CIS":
         return quil_cis(arg) if isinstance(arg, Expression) else np.cos(arg) + 1j * np.sin(arg)
def u3_replacement(theta: float, phi: float, lam: float):
    """ implemented with a custom gate """

    # implemented with two X90 pulse: https://arxiv.org/pdf/1707.03429.pdf
    # p = Program()
    # p += RZ(phi + 3*np.pi, 0)
    # p += RX(np.pi/2, 0)
    # p += RZ(np.pi + theta, 0)
    # p += RX(np.pi/2, 0)
    # p += RZ(lam, 0)
    # formula from https://qiskit.org/documentation/stubs/qiskit.circuit.library.U3Gate.html (13.07.2020) gives wrong results
    # p = Program()
    # p += RZ(phi - np.pi/2, 0)
    # p += RX(np.pi/2, 0)
    # p += RZ(np.pi - theta, 0)
    # p += RX(np.pi/2, 0)
    # p += RZ(lam - np.pi/2, 0)

    theta_param = Parameter('theta')
    phi_param = Parameter('phi')
    lam_param = Parameter('lam')
    matrix = np.array(
        [[
            quil_cos(theta_param / 2),
            -quil_exp(1j * lam_param) * quil_sin(theta_param / 2)
        ],
         [
             quil_exp(1j * phi_param) * quil_sin(theta_param / 2),
             quil_exp(1j * (phi_param + lam_param)) * quil_cos(theta_param / 2)
         ]])
    definition = DefGate('U3', matrix, [theta_param, phi_param, lam_param])
    U3 = definition.get_constructor()
    p = Program()
    p += definition
    p += U3(theta, phi, lam)(0)

    return p
Esempio n. 11
0
def test_expression_to_string():
    x = Parameter('x')
    assert str(x) == '%x'

    y = Parameter('y')
    assert str(y) == '%y'

    assert str(x + y) == '%x + %y'
    assert str(3 * x + y) == '3*%x + %y'
    assert str(3 * (x + y)) == '3*(%x + %y)'

    assert str(x + y + 2) == '%x + %y + 2'
    assert str(x - y - 2) == '%x - %y - 2'
    assert str(x - (y - 2)) == '%x - (%y - 2)'

    assert str((x + y) - 2) == '%x + %y - 2'
    assert str(x + (y - 2)) == '%x + %y - 2'

    assert str(x**y**2) == '%x^%y^2'
    assert str(x**(y**2)) == '%x^%y^2'
    assert str((x**y)**2) == '(%x^%y)^2'

    assert str(quil_sin(x)) == 'SIN(%x)'
    assert str(3 * quil_sin(x + y)) == '3*SIN(%x + %y)'
Esempio n. 12
0
def example_pyquil_program():
    quil_theta = pyquil.quil.Parameter("theta")

    u_gate_definition = pyquil.quil.DefGate(
        "U", [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, -1j], [0, 0, -1j, 0]])

    v_gate_definition = pyquil.quil.DefGate(
        "V",
        [
            [quilatom.quil_cos(quil_theta),
             quilatom.quil_sin(quil_theta)],
            [-quilatom.quil_sin(quil_theta),
             quilatom.quil_cos(quil_theta)],
        ],
        [quil_theta],
    )

    # The below methods for getting constructors differ, because behaviours of
    # get_constructors differs depending on whether custom gate has
    # parameters or not.
    u_gate_constructor = u_gate_definition.get_constructor()
    v_gate_constructor = v_gate_definition.get_constructor()(quil_theta)

    return pyquil.Program(
        pyquil.quil.Declare("theta", "REAL"),
        v_gate_definition,
        u_gate_definition,
        v_gate_constructor(0),
        pyquil.gates.X(0),
        pyquil.gates.Y(1),
        pyquil.gates.Z(3),
        pyquil.gates.SWAP(0, 2).controlled(1),
        u_gate_constructor(1, 3).dagger(),
        pyquil.gates.RX(np.pi, 2),
        pyquil.gates.CNOT(1, 3),
    )
Esempio n. 13
0
def test_expression_to_string():
    x = Parameter("x")
    assert str(x) == "%x"

    y = Parameter("y")
    assert str(y) == "%y"

    assert str(x + y) == "%x + %y"
    assert str(3 * x + y) == "3*%x + %y"
    assert str(3 * (x + y)) == "3*(%x + %y)"

    assert str(x + y + 2) == "%x + %y + 2"
    assert str(x - y - 2) == "%x - %y - 2"
    assert str(x - (y - 2)) == "%x - (%y - 2)"

    assert str((x + y) - 2) == "%x + %y - 2"
    assert str(x + (y - 2)) == "%x + %y - 2"

    assert str(x ** y ** 2) == "%x^%y^2"
    assert str(x ** (y ** 2)) == "%x^%y^2"
    assert str((x ** y) ** 2) == "(%x^%y)^2"

    assert str(quil_sin(x)) == "SIN(%x)"
    assert str(3 * quil_sin(x + y)) == "3*SIN(%x + %y)"
        (quil.Parameter("x"), Symbol("x")),
        (quil.Parameter("x_1"), Symbol("x_1")),
    ],
)
def test_quil_parameters_are_converted_to_instance_of_symbol_with_correct_name(
    pyquil_parameter, expected_symbol
):
    assert expression_from_pyquil(pyquil_parameter) == expected_symbol


@pytest.mark.parametrize(
    "pyquil_function_call, expected_function_call",
    [
        (quilatom.quil_cos(2), FunctionCall("cos", (2,))),
        (
            quilatom.quil_sin(quil.Parameter("theta")),
            FunctionCall("sin", (Symbol("theta"),)),
        ),
        (quilatom.quil_exp(quil.Parameter("x")), FunctionCall("exp", (Symbol("x"),))),
        (quilatom.quil_sqrt(np.pi), FunctionCall("sqrt", (np.pi,))),
    ],
)
def test_pyquil_function_calls_are_converted_to_equivalent_function_call(
    pyquil_function_call, expected_function_call
):
    assert expression_from_pyquil(pyquil_function_call) == expected_function_call


@pytest.mark.parametrize(
    "pyquil_expression, expected_function_call",
    [
Esempio n. 15
0
 (
     sympy.cos(2 * sympy.Symbol("theta")),
     quilatom.quil_cos(2 * quil.Parameter("theta")),
 ),
 (
     sympy.exp(sympy.Symbol("x") - sympy.Symbol("y")),
     quilatom.quil_exp(quil.Parameter("x") - quil.Parameter("y")),
 ),
 (
     sympy.Add(
         sympy.cos(sympy.Symbol("phi")),
         sympy.I * sympy.sin(sympy.Symbol("phi")),
         evaluate=False,
     ),
     quilatom.quil_cos(quil.Parameter("phi"))
     + 1j * quilatom.quil_sin(quil.Parameter("phi")),
 ),
 (
     sympy.Add(
         sympy.Symbol("x"),
         sympy.Mul(sympy.Symbol("y"), (2 + 3j), evaluate=False),
         evaluate=False,
     ),
     quil.Parameter("x") + quil.Parameter("y") * (2 + 3j),
 ),
 (
     sympy.cos(sympy.sin(sympy.Symbol("tau"))),
     quilatom.quil_cos(quilatom.quil_sin(quil.Parameter("tau"))),
 ),
 (
     sympy.Symbol("x") / sympy.Symbol("y"),
Esempio n. 16
0
def add_gate_to_pyquil_program(pyquil_program, gate):
    """Add the definition of a gate to a pyquil Program object if the gate is
    not currently defined.

    Args:
        pyquil_program: pyquil.Program
            The input Program object to which the gate is going to be added.
        gate: Gate (core.circuit)
            The Gate object describing the gate to be added.

    Returns:
        A new pyquil.Program object with the definition of the new gate being added.
    """

    if gate.name in COMMON_GATES:  # if a gate is already included in pyquil
        return pyquil_program + gate.to_pyquil()  # do nothing
    elif gate.name in UNIQUE_GATES:  # if a gate is unique to a specific package
        if gate.name == "ZXZ":
            beta = pyquil.quilatom.Parameter("beta")
            gamma = pyquil.quilatom.Parameter("gamma")
            zxz_unitary = np.array([
                [
                    quil_cos(gamma / 2),
                    -quil_sin(beta) * quil_sin(gamma / 2) -
                    1j * quil_cos(beta) * quil_sin(gamma / 2),
                ],
                [
                    quil_sin(beta) * quil_sin(gamma / 2) -
                    1j * quil_cos(beta) * quil_sin(gamma / 2),
                    quil_cos(gamma / 2),
                ],
            ])
            zxz_def = pyquil.quilbase.DefGate("ZXZ", zxz_unitary,
                                              [beta, gamma])
            ZXZ = zxz_def.get_constructor()
            return (pyquil_program + zxz_def +
                    ZXZ(gate.params[0], gate.params[1])(gate.qubits[0].index))
        if gate.name == "RH":
            beta = pyquil.quilatom.Parameter("beta")
            phase_factor = quil_cos(beta / 2) + 1j * quil_sin(beta / 2)
            elem00 = quil_cos(
                beta / 2) - 1j * 1 / np.sqrt(2) * quil_sin(beta / 2)
            elem01 = -1j * 1 / np.sqrt(2) * quil_sin(beta / 2)
            elem10 = -1j * 1 / np.sqrt(2) * quil_sin(beta / 2)
            elem11 = quil_cos(
                beta / 2) + 1j * 1 / np.sqrt(2) * quil_sin(beta / 2)
            rh_unitary = np.array([
                [phase_factor * elem00, phase_factor * elem01],
                [phase_factor * elem10, phase_factor * elem11],
            ])
            rh_def = pyquil.quilbase.DefGate("RH", rh_unitary, [beta])
            RH = rh_def.get_constructor()
            return pyquil_program + rh_def + RH(gate.params[0])(
                gate.qubits[0].index)
        if gate.name == "XX":
            # Reference for XX implementation in cirq: https://github.com/quantumlib/Cirq/blob/a61e51b53612735e93b3bb8a7605030c499cd6c7/cirq/ops/parity_gates.py#L30
            # Reference for XX implementation in qiskit: https://qiskit.org/documentation/stubs/qiskit.circuit.library.RXXGate.html
            beta = pyquil.quilatom.Parameter("beta")
            elem_cos = quil_cos(beta)
            elem_sin = -1j * quil_sin(beta)
            xx_unitary = np.array([
                [elem_cos, 0, 0, elem_sin],
                [0, elem_cos, elem_sin, 0],
                [0, elem_sin, elem_cos, 0],
                [elem_sin, 0, 0, elem_cos],
            ])
            xx_def = pyquil.quilbase.DefGate("XX", xx_unitary, [beta])
            XX = xx_def.get_constructor()
            return (
                pyquil_program + xx_def +
                XX(gate.params[0])(gate.qubits[0].index, gate.qubits[1].index))
        if gate.name == "YY":
            # Reference for YY implementation in cirq: https://github.com/quantumlib/Cirq/blob/a61e51b53612735e93b3bb8a7605030c499cd6c7/cirq/ops/parity_gates.py#L142
            # Reference for YY implementation in qiskit: https://qiskit.org/documentation/stubs/qiskit.circuit.library.RYYGate.html
            beta = pyquil.quilatom.Parameter("beta")
            elem_cos = quil_cos(beta)
            elem_sin = 1j * quil_sin(beta)
            yy_unitary = np.array([
                [elem_cos, 0, 0, elem_sin],
                [0, elem_cos, -elem_sin, 0],
                [0, -elem_sin, elem_cos, 0],
                [elem_sin, 0, 0, elem_cos],
            ])
            yy_def = pyquil.quilbase.DefGate("YY", yy_unitary, [beta])
            YY = yy_def.get_constructor()
            return (
                pyquil_program + yy_def +
                YY(gate.params[0])(gate.qubits[0].index, gate.qubits[1].index))
        if gate.name == "ZZ":
            # Reference for ZZ implementation in cirq: https://github.com/quantumlib/Cirq/blob/a61e51b53612735e93b3bb8a7605030c499cd6c7/cirq/ops/parity_gates.py#L254
            # Reference for ZZ implementation in qiskit: https://qiskit.org/documentation/stubs/qiskit.circuit.library.RYYGate.html
            beta = pyquil.quilatom.Parameter("beta")
            elem_cos = quil_cos(beta)
            elem_sin = 1j * quil_sin(beta)
            zz_unitary = np.array([
                [elem_cos - elem_sin, 0, 0, 0],
                [0, elem_cos + elem_sin, 0, 0],
                [0, 0, elem_cos + elem_sin, 0],
                [0, 0, 0, elem_cos - elem_sin],
            ])
            zz_def = pyquil.quilbase.DefGate("ZZ", zz_unitary, [beta])
            ZZ = zz_def.get_constructor()
            return (
                pyquil_program + zz_def +
                ZZ(gate.params[0])(gate.qubits[0].index, gate.qubits[1].index))
        if gate.name == "XY":
            return pyquil_program + gate.to_pyquil()  # do nothing

        if gate.name == "U1ex":  # IBM U1ex gate (arXiv:1805.04340v1)
            alpha = pyquil.quilatom.Parameter("alpha")
            beta = pyquil.quilatom.Parameter("beta")
            elem_cos = quil_cos(beta)
            elem_sin = 1j * quil_sin(beta)
            unitary = [[1, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 1]]
            unitary[1][1] = quil_cos(alpha)
            unitary[2][2] = -quil_cos(alpha)
            unitary[2][1] = (quil_cos(beta) -
                             1j * quil_sin(beta)) * quil_sin(alpha)
            unitary[1][2] = (quil_cos(beta) +
                             1j * quil_sin(beta)) * quil_sin(alpha)
            u1ex_def = pyquil.quilbase.DefGate("U1ex", np.array(unitary),
                                               [alpha, beta])
            U1ex = u1ex_def.get_constructor()
            output_program = pyquil_program + U1ex(
                gate.params[0], gate.params[1])(gate.qubits[0].index,
                                                gate.qubits[1].index)
            gate_already_defined = False
            for gate_definition in pyquil_program.defined_gates:
                if gate_definition.name == "U1ex":
                    gate_already_defined = True
                    break
            if not gate_already_defined:
                output_program = output_program + u1ex_def
            return output_program
        if gate.name == "U2ex":  # IBM U2ex gate (arXiv:1805.04340v1)
            alpha = pyquil.quilatom.Parameter("alpha")
            unitary = [[1, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 1]]
            unitary[1][1] = quil_cos(2 * alpha)
            unitary[2][2] = quil_cos(2 * alpha)
            unitary[2][1] = -1j * quil_sin(2 * alpha)
            unitary[1][2] = -1j * quil_sin(2 * alpha)
            u2ex_def = pyquil.quilbase.DefGate("U2ex", np.array(unitary),
                                               [alpha])
            U2ex = u2ex_def.get_constructor()
            output_program = pyquil_program + U2ex(gate.params[0])(
                gate.qubits[0].index, gate.qubits[1].index)
            gate_already_defined = False
            for gate_definition in pyquil_program.defined_gates:
                if gate_definition.name == "U2ex":
                    gate_already_defined = True
                    break
            if not gate_already_defined:
                output_program = output_program + u1ex_def
            return output_program
        if gate.name == "MEASURE":
            reg_name = "r" + str(gate.qubits[0].index)

            ro = pyquil_program.declare(reg_name, "BIT", 1)
            return pyquil_program + MEASURE(gate.qubits[0].index, ro[0])
        if gate.name == "BARRIER":
            return pyquil_program
@expression_from_pyquil.register(quilatom.Add)
@expression_from_pyquil.register(quilatom.Sub)
@expression_from_pyquil.register(quilatom.Mul)
@expression_from_pyquil.register(quilatom.Div)
@expression_from_pyquil.register(quilatom.Pow)
def function_call_from_pyquil_binary_expression(expression):
    return FunctionCall(QUIL_BINARY_EXPRESSION_NAMES[type(expression)],
                        (expression_from_pyquil(expression.op1),
                         expression_from_pyquil(expression.op2)))


# Dialect defining conversion of intermediate expression tree to
# the expression based on quil functions/parameters.
# This is intended to be passed by a `dialect` argument of `translate_expression`.
QUIL_DIALECT = ExpressionDialect(
    symbol_factory=lambda symbol: pyquil.quil.Parameter(symbol.name),
    number_factory=lambda number: number,
    known_functions={
        "add": reduction(operator.add),
        "mul": reduction(operator.mul),
        "div": operator.truediv,
        "sub": operator.sub,
        "pow": operator.pow,
        "cos": quilatom.quil_cos,
        "sin": quilatom.quil_sin,
        "exp": quilatom.quil_exp,
        "sqrt": quilatom.quil_sqrt,
        "tan": lambda arg: quilatom.quil_sin(arg) / quilatom.quil_cos(arg),
    },
)
Esempio n. 18
0
def add_gate_to_pyquil_program(pyquil_program, gate):
    """Add the definition of a gate to a pyquil Program object if the gate is
    not currently defined.

    Args:
        pyquil_program: pyquil.Program
            The input Program object to which the gate is going to be added.
        gate: Gate (core.circuit)
            The Gate object describing the gate to be added.

    Returns:
        A new pyquil.Program object with the definition of the new gate being added.
    """

    if gate.name in COMMON_GATES:  # if a gate is already included in pyquil
        return pyquil_program + gate.to_pyquil()  # do nothing
    elif gate.name in UNIQUE_GATES:  # if a gate is unique to a specific package
        if gate.name == "ZXZ":
            beta = pyquil.quilatom.Parameter("beta")
            gamma = pyquil.quilatom.Parameter("gamma")
            zxz_unitary = np.array([
                [
                    quil_cos(gamma / 2),
                    -quil_sin(beta) * quil_sin(gamma / 2) -
                    1j * quil_cos(beta) * quil_sin(gamma / 2),
                ],
                [
                    quil_sin(beta) * quil_sin(gamma / 2) -
                    1j * quil_cos(beta) * quil_sin(gamma / 2),
                    quil_cos(gamma / 2),
                ],
            ])
            zxz_def = pyquil.quilbase.DefGate("ZXZ", zxz_unitary,
                                              [beta, gamma])
            ZXZ = zxz_def.get_constructor()
            return (pyquil_program + zxz_def +
                    ZXZ(gate.params[0], gate.params[1])(gate.qubits[0].index))
        if gate.name == "RH":
            beta = pyquil.quilatom.Parameter("beta")
            elem00 = quil_cos(
                beta / 2) - 1j * 1 / np.sqrt(2) * quil_sin(beta / 2)
            elem01 = -1j * 1 / np.sqrt(2) * quil_sin(beta / 2)
            elem10 = -1j * 1 / np.sqrt(2) * quil_sin(beta / 2)
            elem11 = quil_cos(
                beta / 2) + 1j * 1 / np.sqrt(2) * quil_sin(beta / 2)
            rh_unitary = np.array([[elem00, elem01], [elem10, elem11]])
            rh_def = pyquil.quilbase.DefGate("RH", rh_unitary, [beta])
            RH = rh_def.get_constructor()
            return pyquil_program + rh_def + RH(gate.params[0])(
                gate.qubits[0].index)
        if gate.name == "XX":  # XX gate (modified from XXPowGate in cirq)
            beta = pyquil.quilatom.Parameter("beta")
            elem_cos = quil_cos(beta)
            elem_sin = 1j * quil_sin(beta)
            xx_unitary = np.array([
                [elem_cos, 0, 0, elem_sin],
                [0, elem_cos, elem_sin, 0],
                [0, elem_sin, elem_cos, 0],
                [elem_sin, 0, 0, elem_cos],
            ])
            xx_def = pyquil.quilbase.DefGate("XX", xx_unitary, [beta])
            XX = xx_def.get_constructor()
            return (
                pyquil_program + xx_def +
                XX(gate.params[0])(gate.qubits[0].index, gate.qubits[1].index))
        if gate.name == "YY":  # YY gate (modified from XXPowGate in cirq)
            beta = pyquil.quilatom.Parameter("beta")
            elem_cos = quil_cos(beta)
            elem_sin = 1j * quil_sin(beta)
            yy_unitary = np.array([
                [elem_cos, 0, 0, elem_sin],
                [0, elem_cos, -elem_sin, 0],
                [0, -elem_sin, elem_cos, 0],
                [elem_sin, 0, 0, elem_cos],
            ])
            yy_def = pyquil.quilbase.DefGate("YY", yy_unitary, [beta])
            YY = yy_def.get_constructor()
            return (
                pyquil_program + yy_def +
                YY(gate.params[0])(gate.qubits[0].index, gate.qubits[1].index))
        if gate.name == "ZZ":  # ZZ gate (modified from XXPowGate in cirq)
            beta = pyquil.quilatom.Parameter("beta")
            elem_cos = quil_cos(beta)
            elem_sin = 1j * quil_sin(beta)
            zz_unitary = np.array([
                [elem_cos + elem_sin, 0, 0, 0],
                [0, elem_cos - elem_sin, 0, 0],
                [0, 0, elem_cos - elem_sin, 0],
                [0, 0, 0, elem_cos + elem_sin],
            ])
            zz_def = pyquil.quilbase.DefGate("ZZ", zz_unitary, [beta])
            ZZ = zz_def.get_constructor()
            return (
                pyquil_program + zz_def +
                ZZ(gate.params[0])(gate.qubits[0].index, gate.qubits[1].index))
        if gate.name == "U1ex":  # IBM U1ex gate (arXiv:1805.04340v1)
            alpha = pyquil.quilatom.Parameter("alpha")
            beta = pyquil.quilatom.Parameter("beta")
            elem_cos = quil_cos(beta)
            elem_sin = 1j * quil_sin(beta)
            unitary = [[1, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 1]]
            unitary[1][1] = quil_cos(alpha)
            unitary[2][2] = -quil_cos(alpha)
            unitary[2][1] = (quil_cos(beta) -
                             1j * quil_sin(beta)) * quil_sin(alpha)
            unitary[1][2] = (quil_cos(beta) +
                             1j * quil_sin(beta)) * quil_sin(alpha)
            u1ex_def = pyquil.quilbase.DefGate("U1ex", np.array(unitary),
                                               [alpha, beta])
            U1ex = u1ex_def.get_constructor()
            output_program = pyquil_program + U1ex(
                gate.params[0], gate.params[1])(gate.qubits[0].index,
                                                gate.qubits[1].index)
            gate_already_defined = False
            for gate_definition in pyquil_program.defined_gates:
                if gate_definition.name == "U1ex":
                    gate_already_defined = True
                    break
            if not gate_already_defined:
                output_program = output_program + u1ex_def
            return output_program
        if gate.name == "U2ex":  # IBM U2ex gate (arXiv:1805.04340v1)
            alpha = pyquil.quilatom.Parameter("alpha")
            unitary = [[1, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 1]]
            unitary[1][1] = quil_cos(2 * alpha)
            unitary[2][2] = quil_cos(2 * alpha)
            unitary[2][1] = -1j * quil_sin(2 * alpha)
            unitary[1][2] = -1j * quil_sin(2 * alpha)
            u2ex_def = pyquil.quilbase.DefGate("U2ex", np.array(unitary),
                                               [alpha])
            U2ex = u2ex_def.get_constructor()
            output_program = pyquil_program + U2ex(gate.params[0])(
                gate.qubits[0].index, gate.qubits[1].index)
            gate_already_defined = False
            for gate_definition in pyquil_program.defined_gates:
                if gate_definition.name == "U2ex":
                    gate_already_defined = True
                    break
            if not gate_already_defined:
                output_program = output_program + u1ex_def
            return output_program
        if gate.name == "MEASURE":
            reg_name = "r" + str(gate.qubits[0].index)

            ro = pyquil_program.declare(reg_name, "BIT", 1)
            return pyquil_program + MEASURE(gate.qubits[0].index, ro[0])
        if gate.name == "BARRIER":
            return pyquil_program