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)])
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]))
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'
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))
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}
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)
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)])
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
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)'
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), )
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", [
( 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"),
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), }, )
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