Loading python/py-qcor.cpp +43 −1 Original line number Diff line number Diff line Loading @@ -81,7 +81,9 @@ class KernelArgDictToHeterogeneousMap { // Add type name to this list to support receiving from Python. using PyHeterogeneousMapTypes = xacc::Variant<bool, int, double, std::string, std::vector<int>, std::shared_ptr<qcor::Optimizer>, std::vector<double>, std::vector<std::vector<double>>>; std::vector<std::pair<int, int>>, std::shared_ptr<qcor::Optimizer>, std::vector<double>, std::vector<std::vector<double>>>; using PyHeterogeneousMap = std::map<std::string, PyHeterogeneousMapTypes>; // Helper to convert a Python *dict* (as a map of variants) into a native Loading Loading @@ -448,6 +450,46 @@ PYBIND11_MODULE(_pyqcor, m) { py::arg("name"), py::arg("p") = PyHeterogeneousMap(), "Set the QPU backend."); m.def( "set_opt_level", [](int level) { xacc::internal_compiler::__opt_level = level; }, py::arg("level"), "Set QCOR runtime optimization level."); m.def( "add_pass", [](const std::string &pass_name) { // Note: we expect __user_opt_passes to be a comma-separated list of // pass names. if (xacc::internal_compiler::__user_opt_passes.empty()) { xacc::internal_compiler::__user_opt_passes = pass_name; } else { xacc::internal_compiler::__user_opt_passes += ("," + pass_name); } }, py::arg("pass_name"), "Add an optimization pass to be run by the PassManager."); m.def( "get_placement_names", []() { std::vector<std::string> result; auto ir_transforms = xacc::getServices<xacc::IRTransformation>(); for (const auto &plugin : ir_transforms) { if (plugin->type() == xacc::IRTransformationType::Placement) { result.emplace_back(plugin->name()); } } return result; }, "Get names of all available placement plugins."); m.def( "set_placement", [](const std::string &placement_name) { xacc::internal_compiler::__placement_name = placement_name; }, py::arg("placement_name"), "Set the placement strategy."); m.def("qalloc", &::qalloc, py::return_value_policy::reference, ""); py::class_<xacc::internal_compiler::qreg>(m, "qreg", "") .def("size", &xacc::internal_compiler::qreg::size, "") Loading python/qcor.in.py +4 −1 Original line number Diff line number Diff line import sys import sys, atexit if '@QCOR_APPEND_PLUGIN_PATH@': sys.argv += ['__internal__add__plugin__path', '@QCOR_APPEND_PLUGIN_PATH@'] Loading @@ -24,6 +24,9 @@ MethodType = types.MethodType # i.e. multiple kernels all declared in global scope don't have this issue. # Hence, to be safe, we cache all the QJIT objects ever created until QCOR module is unloaded. QJIT_OBJ_CACHE = [] @atexit.register def clear_qjit_cache(): QJIT_OBJ_CACHE = [] PauliOperator = xacc.quantum.PauliOperator FermionOperator = xacc.quantum.FermionOperator Loading python/tests/CMakeLists.txt +25 −4 Original line number Diff line number Diff line Loading @@ -5,11 +5,25 @@ add_test (NAME qcor_quasimo_python_bindings set_tests_properties(qcor_quasimo_python_bindings PROPERTIES ENVIRONMENT "PYTHONPATH=${CMAKE_INSTALL_PREFIX}:$ENV{PYTHONPATH}") add_test (NAME qcor_simple_kernel_jit_python COMMAND ${Python_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test_kernel_jit.py add_test (NAME qcor_python_jit_simple COMMAND ${Python_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test_jit_simple.py WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} ) set_tests_properties(qcor_simple_kernel_jit_python set_tests_properties(qcor_python_jit_simple PROPERTIES ENVIRONMENT "PYTHONPATH=${CMAKE_INSTALL_PREFIX}:$ENV{PYTHONPATH}") add_test (NAME qcor_python_jit_nested_kernels COMMAND ${Python_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test_jit_nested.py WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} ) set_tests_properties(qcor_python_jit_nested_kernels PROPERTIES ENVIRONMENT "PYTHONPATH=${CMAKE_INSTALL_PREFIX}:$ENV{PYTHONPATH}") add_test (NAME qcor_python_jit_decompose COMMAND ${Python_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test_jit_decompose.py WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} ) set_tests_properties(qcor_python_jit_decompose PROPERTIES ENVIRONMENT "PYTHONPATH=${CMAKE_INSTALL_PREFIX}:$ENV{PYTHONPATH}") add_test (NAME qcor_test_qcor_spec_api Loading @@ -25,3 +39,10 @@ add_test (NAME qcor_kernel_ftqc_python ) set_tests_properties(qcor_kernel_ftqc_python PROPERTIES ENVIRONMENT "PYTHONPATH=${CMAKE_INSTALL_PREFIX}:$ENV{PYTHONPATH}") add_test (NAME qcor_python_jit_pass_manager COMMAND ${Python_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test_jit_pass_manager.py WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} ) set_tests_properties(qcor_python_jit_pass_manager PROPERTIES ENVIRONMENT "PYTHONPATH=${CMAKE_INSTALL_PREFIX}:$ENV{PYTHONPATH}") No newline at end of file python/tests/test_jit_decompose.py 0 → 100644 +170 −0 Original line number Diff line number Diff line import unittest from qcor import * # Import Python math with alias import math as myMathMod # Some global variables for testing MY_PI = 3.1416 class TestKernelJIT(unittest.TestCase): def test_as_unitary(self): try: import numpy as np except: print('No numpy, cant run test_as_unitary') return @qjit def dansatz(q : qreg, x : float): X(q[0]) Ry(q[1], x) CX(q[1], q[0]) u_mat = dansatz.as_unitary_matrix(qalloc(2), .59) H = -2.1433 * X(0) * X(1) - 2.1433 * \ Y(0) * Y(1) + .21829 * Z(0) - 6.125 * Z(1) + 5.907 Hmat = H.to_numpy() # Compute |psi> = U |0> zero_state = np.array([1., 0., 0., 0.]) final_state = np.dot(u_mat, np.transpose(zero_state)) # Compute E = <psi| H |psi> energy = np.dot(final_state, np.dot(Hmat,final_state)) print(energy) self.assertAlmostEqual(energy, -1.74, places=1) def test_rewrite_decompose(self): try: import numpy as np except: print('No numpy, cant run test_rewrite_decompose') return set_qpu('qpp', {'shots':1024}) @qjit def foo(q : qreg): for i in range(q.size()): X(q[i]) with decompose(q) as ccnot: ccnot = np.eye(8) ccnot[6,6] = 0.0 ccnot[7,7] = 0.0 ccnot[6,7] = 1.0 ccnot[7,6] = 1.0 for i in range(q.size()): Measure(q[i]) print(foo.src) q = qalloc(3) foo(q) counts = q.counts() self.assertTrue('110' in counts) self.assertTrue(counts['110'] == 1024) @qjit def all_x(q : qreg): with decompose(q) as x_kron: sx = np.array([[0, 1],[1, 0]]) x_kron = np.kron(np.kron(sx,sx),sx) for i in range(q.size()): Measure(q[i]) print(all_x.src) q = qalloc(3) all_x(q) counts = q.counts() print(counts) self.assertTrue('111' in counts) self.assertTrue(counts['111'] == 1024) @qjit def try_two_decompose(q : qreg): for i in range(q.size()): X(q[i]) with decompose(q) as ccnot: ccnot = numpy.eye(8) ccnot[6,6] = 0.0 ccnot[7,7] = 0.0 ccnot[6,7] = 1.0 ccnot[7,6] = 1.0 # should have 110 with decompose(q) as x_kron: sx = np.array([[0, 1],[1, 0]]) x_kron = np.kron(np.kron(sx,sx),sx) # Should have flipped the bits for i in range(q.size()): Measure(q[i]) print(try_two_decompose.src) q = qalloc(3) try_two_decompose(q) counts = q.counts() print(counts) self.assertTrue('001' in counts) self.assertTrue(counts['001'] == 1024) def test_more_decompose(self): try: import numpy as np except: print('No numpy, cant run test_more_decompose') return set_qpu('qpp', {'shots':1024}) @qjit def random_2qbit(q : qreg): with decompose(q, kak) as random_unitary: a = np.random.rand(4,4) qm, r = np.linalg.qr(a, mode='complete') random_unitary = qm for i in range(q.size()): Measure(q[i]) print(random_2qbit.src) q = qalloc(2) print(random_2qbit.extract_composite(q).toString()) @qjit def random_1qbit(q : qreg): with decompose(q, z_y_z) as random_unitary: random_unitary, _ = np.linalg.qr(np.random.rand(2,2), mode='complete') for i in range(q.size()): Measure(q[i]) print(random_1qbit.get_internal_src()) q = qalloc(2) print(random_1qbit.get_syntax_handler_src()) print(random_1qbit.extract_composite(q).toString()) # def test_decompose_param(self): # set_qpu('qpp') # @qjit # def ansatz(q : qreg, x : List[float]): # X(q[0]) # with decompose(q, kak) as u: # from scipy.sparse.linalg import expm # from openfermion.ops import QubitOperator # from openfermion.transforms import get_sparse_operator # qop = QubitOperator('X0 Y1') - QubitOperator('Y0 X1') # qubit_sparse = get_sparse_operator(qop) # u = expm(0.5j * x[0] * qubit_sparse).todense() # H = -2.1433 * X(0) * X(1) - 2.1433 * \ # Y(0) * Y(1) + .21829 * Z(0) - 6.125 * Z(1) + 5.907 # o = createObjectiveFunction(ansatz, H, 1, {'gradient-strategy':'central', 'step':1e-1}) # opt = createOptimizer('nlopt', {'initial-parameters':[.5], 'maxeval':10, 'algorithm':'l-bfgs'}) # results = opt.optimize(o) # print("WE ARE DONE") # self.assertAlmostEqual(results[0], -1.74, places=1) if __name__ == '__main__': unittest.main() No newline at end of file python/tests/test_kernel_jit.py→python/tests/test_jit_nested.py +206 −0 Original line number Diff line number Diff line Loading @@ -6,303 +6,6 @@ import math as myMathMod # Some global variables for testing MY_PI = 3.1416 class TestKernelJIT(unittest.TestCase): def test_as_unitary(self): try: import numpy as np except: print('No numpy, cant run test_as_unitary') return @qjit def dansatz(q : qreg, x : float): X(q[0]) Ry(q[1], x) CX(q[1], q[0]) u_mat = dansatz.as_unitary_matrix(qalloc(2), .59) H = -2.1433 * X(0) * X(1) - 2.1433 * \ Y(0) * Y(1) + .21829 * Z(0) - 6.125 * Z(1) + 5.907 Hmat = H.to_numpy() # Compute |psi> = U |0> zero_state = np.array([1., 0., 0., 0.]) final_state = np.dot(u_mat, np.transpose(zero_state)) # Compute E = <psi| H |psi> energy = np.dot(final_state, np.dot(Hmat,final_state)) print(energy) self.assertAlmostEqual(energy, -1.74, places=1) def test_rewrite_decompose(self): try: import numpy as np except: print('No numpy, cant run test_rewrite_decompose') return set_qpu('qpp', {'shots':1024}) @qjit def foo(q : qreg): for i in range(q.size()): X(q[i]) with decompose(q) as ccnot: ccnot = np.eye(8) ccnot[6,6] = 0.0 ccnot[7,7] = 0.0 ccnot[6,7] = 1.0 ccnot[7,6] = 1.0 for i in range(q.size()): Measure(q[i]) print(foo.src) q = qalloc(3) foo(q) counts = q.counts() self.assertTrue('110' in counts) self.assertTrue(counts['110'] == 1024) @qjit def all_x(q : qreg): with decompose(q) as x_kron: sx = np.array([[0, 1],[1, 0]]) x_kron = np.kron(np.kron(sx,sx),sx) for i in range(q.size()): Measure(q[i]) print(all_x.src) q = qalloc(3) all_x(q) counts = q.counts() print(counts) self.assertTrue('111' in counts) self.assertTrue(counts['111'] == 1024) @qjit def try_two_decompose(q : qreg): for i in range(q.size()): X(q[i]) with decompose(q) as ccnot: ccnot = numpy.eye(8) ccnot[6,6] = 0.0 ccnot[7,7] = 0.0 ccnot[6,7] = 1.0 ccnot[7,6] = 1.0 # should have 110 with decompose(q) as x_kron: sx = np.array([[0, 1],[1, 0]]) x_kron = np.kron(np.kron(sx,sx),sx) # Should have flipped the bits for i in range(q.size()): Measure(q[i]) print(try_two_decompose.src) q = qalloc(3) try_two_decompose(q) counts = q.counts() print(counts) self.assertTrue('001' in counts) self.assertTrue(counts['001'] == 1024) def test_more_decompose(self): try: import numpy as np except: print('No numpy, cant run test_more_decompose') return set_qpu('qpp', {'shots':1024}) @qjit def random_2qbit(q : qreg): with decompose(q, kak) as random_unitary: a = np.random.rand(4,4) qm, r = np.linalg.qr(a, mode='complete') random_unitary = qm for i in range(q.size()): Measure(q[i]) print(random_2qbit.src) q = qalloc(2) print(random_2qbit.extract_composite(q).toString()) @qjit def random_1qbit(q : qreg): with decompose(q, z_y_z) as random_unitary: random_unitary, _ = np.linalg.qr(np.random.rand(2,2), mode='complete') for i in range(q.size()): Measure(q[i]) print(random_1qbit.get_internal_src()) q = qalloc(2) print(random_1qbit.get_syntax_handler_src()) print(random_1qbit.extract_composite(q).toString()) # def test_decompose_param(self): # set_qpu('qpp') # @qjit # def ansatz(q : qreg, x : List[float]): # X(q[0]) # with decompose(q, kak) as u: # from scipy.sparse.linalg import expm # from openfermion.ops import QubitOperator # from openfermion.transforms import get_sparse_operator # qop = QubitOperator('X0 Y1') - QubitOperator('Y0 X1') # qubit_sparse = get_sparse_operator(qop) # u = expm(0.5j * x[0] * qubit_sparse).todense() # H = -2.1433 * X(0) * X(1) - 2.1433 * \ # Y(0) * Y(1) + .21829 * Z(0) - 6.125 * Z(1) + 5.907 # o = createObjectiveFunction(ansatz, H, 1, {'gradient-strategy':'central', 'step':1e-1}) # opt = createOptimizer('nlopt', {'initial-parameters':[.5], 'maxeval':10, 'algorithm':'l-bfgs'}) # results = opt.optimize(o) # print("WE ARE DONE") # self.assertAlmostEqual(results[0], -1.74, places=1) def test_simple_bell(self): set_qpu('qpp', {'shots':1024}) @qjit def bell(q : qreg): H(q[0]) CX(q[0], q[1]) for i in range(q.size()): Measure(q[i]) # Allocate 2 qubits q = qalloc(2) # Run the bell experiment bell(q) # Print the results q.print() self.assertAlmostEqual(q.exp_val_z(), 1.0, places=1) counts = q.counts() self.assertEqual(len(counts), 2) self.assertTrue('00' in counts) self.assertTrue('11' in counts) def test_assignment(self): set_qpu('qpp', {'shots':1024}) @qjit def varAssignKernel(q : qreg): # Simple value assignment angle = 3.14/4.0 Rx(q[0], angle) CX(q[0], q[1]) for i in range(q.size()): Measure(q[i]) # Allocate 2 qubits q = qalloc(2) # Run the bell experiment varAssignKernel(q) # Print the results q.print() counts = q.counts() self.assertEqual(len(counts), 2) self.assertTrue('00' in counts) self.assertTrue('11' in counts) # Angle less than Pi/2 => 00 more than 11 self.assertTrue(counts['00'] > counts['11']) def test_globalVar(self): set_qpu('qpp', {'shots':1024}) @qjit def kernelUseGlobals(q : qreg): Rx(q[0], MY_PI) CX(q[0], q[1]) for i in range(q.size()): Measure(q[i]) # Allocate 2 qubits q = qalloc(2) # Run the bell experiment kernelUseGlobals(q) # Print the results q.print() counts = q.counts() # Pi pulse -> X gate self.assertTrue(counts['11'] > 1000) def test_ModuleConstants(self): set_qpu('qpp', {'shots':1024}) @qjit def kernelUseConstants(q : qreg): # Use math.pi constant Rx(q[0], myMathMod.pi/2) CX(q[0], q[1]) for i in range(q.size()): Measure(q[i]) # Allocate 2 qubits q = qalloc(2) # Run the bell experiment kernelUseConstants(q) # Print the results q.print() counts = q.counts() self.assertEqual(len(counts), 2) self.assertTrue('00' in counts) self.assertTrue('11' in counts) def test_exp_i_theta(self): @qjit def kernelExpVar(q : qreg, theta: float): exponent_op = X(0) * Y(1) - Y(0) * X(1) exp_i_theta(q, theta, exponent_op) # Allocate 2 qubits q = qalloc(2) theta = 1.234 # Validate exp_i_theta expansion comp = kernelExpVar.extract_composite(q, theta) self.assertEqual(comp.nInstructions(), 14) # Test of edge case where the first statement is a for loop def test_for_loop(self): @qjit def testFor(q : qreg): for i in range(q.size()): H(q[i]) q = qalloc(5) comp = testFor.extract_composite(q) self.assertEqual(comp.nInstructions(), 5) def test_for_loop_enumerate(self): set_qpu('qpp') @qjit def ansatz(q: qreg, x: List[float], exp_args: List[FermionOperator]): X(q[0]) for i, exp_arg in enumerate(exp_args): exp_i_theta(q, x[i], exp_args[i]) exp_args = [adag(0) * a(1) - adag(1)*a(0), adag(0)*a(2) - adag(2)*a(0)] H = createOperator('5.907 - 2.1433 X0X1 - 2.1433 Y0Y1 + .21829 Z0 - 6.125 Z1 + 9.625 - 9.625 Z2 - 3.91 X1 X2 - 3.91 Y1 Y2') energy = ansatz.observe(H, qalloc(3), [0.7118083109334505, 0.27387413138588135], exp_args) self.assertAlmostEqual(energy, -2.044, places=1) def test_multiple_kernels(self): @qjit Loading Loading @@ -499,37 +202,5 @@ class TestKernelJIT(unittest.TestCase): self.assertAlmostEqual((float)(comp.getInstruction(2).getParameter(0)), -1.234) self.assertEqual(comp.getInstruction(3).name(), "CNOT") # Test conditional if..elif..else rewrite def test_if_clause(self): @qjit def test_if_stmt(q : qreg, flag: int): H(q[0]) if flag == 0: X(q[0]) elif flag == 1: Y(q[0]) elif flag == 2: Z(q[0]) else: T(q[0]) q = qalloc(2) # Examine the circuit QASM with various values of flag comp0 = test_if_stmt.extract_composite(q, 0) comp1 = test_if_stmt.extract_composite(q, 1) comp2 = test_if_stmt.extract_composite(q, 2) comp3 = test_if_stmt.extract_composite(q, 3) self.assertEqual(comp0.nInstructions(), 2) self.assertEqual(comp1.nInstructions(), 2) self.assertEqual(comp2.nInstructions(), 2) self.assertEqual(comp3.nInstructions(), 2) self.assertEqual(comp0.getInstruction(1).name(), "X") self.assertEqual(comp1.getInstruction(1).name(), "Y") self.assertEqual(comp2.getInstruction(1).name(), "Z") self.assertEqual(comp3.getInstruction(1).name(), "T") if __name__ == '__main__': unittest.main() No newline at end of file Loading
python/py-qcor.cpp +43 −1 Original line number Diff line number Diff line Loading @@ -81,7 +81,9 @@ class KernelArgDictToHeterogeneousMap { // Add type name to this list to support receiving from Python. using PyHeterogeneousMapTypes = xacc::Variant<bool, int, double, std::string, std::vector<int>, std::shared_ptr<qcor::Optimizer>, std::vector<double>, std::vector<std::vector<double>>>; std::vector<std::pair<int, int>>, std::shared_ptr<qcor::Optimizer>, std::vector<double>, std::vector<std::vector<double>>>; using PyHeterogeneousMap = std::map<std::string, PyHeterogeneousMapTypes>; // Helper to convert a Python *dict* (as a map of variants) into a native Loading Loading @@ -448,6 +450,46 @@ PYBIND11_MODULE(_pyqcor, m) { py::arg("name"), py::arg("p") = PyHeterogeneousMap(), "Set the QPU backend."); m.def( "set_opt_level", [](int level) { xacc::internal_compiler::__opt_level = level; }, py::arg("level"), "Set QCOR runtime optimization level."); m.def( "add_pass", [](const std::string &pass_name) { // Note: we expect __user_opt_passes to be a comma-separated list of // pass names. if (xacc::internal_compiler::__user_opt_passes.empty()) { xacc::internal_compiler::__user_opt_passes = pass_name; } else { xacc::internal_compiler::__user_opt_passes += ("," + pass_name); } }, py::arg("pass_name"), "Add an optimization pass to be run by the PassManager."); m.def( "get_placement_names", []() { std::vector<std::string> result; auto ir_transforms = xacc::getServices<xacc::IRTransformation>(); for (const auto &plugin : ir_transforms) { if (plugin->type() == xacc::IRTransformationType::Placement) { result.emplace_back(plugin->name()); } } return result; }, "Get names of all available placement plugins."); m.def( "set_placement", [](const std::string &placement_name) { xacc::internal_compiler::__placement_name = placement_name; }, py::arg("placement_name"), "Set the placement strategy."); m.def("qalloc", &::qalloc, py::return_value_policy::reference, ""); py::class_<xacc::internal_compiler::qreg>(m, "qreg", "") .def("size", &xacc::internal_compiler::qreg::size, "") Loading
python/qcor.in.py +4 −1 Original line number Diff line number Diff line import sys import sys, atexit if '@QCOR_APPEND_PLUGIN_PATH@': sys.argv += ['__internal__add__plugin__path', '@QCOR_APPEND_PLUGIN_PATH@'] Loading @@ -24,6 +24,9 @@ MethodType = types.MethodType # i.e. multiple kernels all declared in global scope don't have this issue. # Hence, to be safe, we cache all the QJIT objects ever created until QCOR module is unloaded. QJIT_OBJ_CACHE = [] @atexit.register def clear_qjit_cache(): QJIT_OBJ_CACHE = [] PauliOperator = xacc.quantum.PauliOperator FermionOperator = xacc.quantum.FermionOperator Loading
python/tests/CMakeLists.txt +25 −4 Original line number Diff line number Diff line Loading @@ -5,11 +5,25 @@ add_test (NAME qcor_quasimo_python_bindings set_tests_properties(qcor_quasimo_python_bindings PROPERTIES ENVIRONMENT "PYTHONPATH=${CMAKE_INSTALL_PREFIX}:$ENV{PYTHONPATH}") add_test (NAME qcor_simple_kernel_jit_python COMMAND ${Python_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test_kernel_jit.py add_test (NAME qcor_python_jit_simple COMMAND ${Python_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test_jit_simple.py WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} ) set_tests_properties(qcor_simple_kernel_jit_python set_tests_properties(qcor_python_jit_simple PROPERTIES ENVIRONMENT "PYTHONPATH=${CMAKE_INSTALL_PREFIX}:$ENV{PYTHONPATH}") add_test (NAME qcor_python_jit_nested_kernels COMMAND ${Python_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test_jit_nested.py WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} ) set_tests_properties(qcor_python_jit_nested_kernels PROPERTIES ENVIRONMENT "PYTHONPATH=${CMAKE_INSTALL_PREFIX}:$ENV{PYTHONPATH}") add_test (NAME qcor_python_jit_decompose COMMAND ${Python_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test_jit_decompose.py WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} ) set_tests_properties(qcor_python_jit_decompose PROPERTIES ENVIRONMENT "PYTHONPATH=${CMAKE_INSTALL_PREFIX}:$ENV{PYTHONPATH}") add_test (NAME qcor_test_qcor_spec_api Loading @@ -25,3 +39,10 @@ add_test (NAME qcor_kernel_ftqc_python ) set_tests_properties(qcor_kernel_ftqc_python PROPERTIES ENVIRONMENT "PYTHONPATH=${CMAKE_INSTALL_PREFIX}:$ENV{PYTHONPATH}") add_test (NAME qcor_python_jit_pass_manager COMMAND ${Python_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test_jit_pass_manager.py WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} ) set_tests_properties(qcor_python_jit_pass_manager PROPERTIES ENVIRONMENT "PYTHONPATH=${CMAKE_INSTALL_PREFIX}:$ENV{PYTHONPATH}") No newline at end of file
python/tests/test_jit_decompose.py 0 → 100644 +170 −0 Original line number Diff line number Diff line import unittest from qcor import * # Import Python math with alias import math as myMathMod # Some global variables for testing MY_PI = 3.1416 class TestKernelJIT(unittest.TestCase): def test_as_unitary(self): try: import numpy as np except: print('No numpy, cant run test_as_unitary') return @qjit def dansatz(q : qreg, x : float): X(q[0]) Ry(q[1], x) CX(q[1], q[0]) u_mat = dansatz.as_unitary_matrix(qalloc(2), .59) H = -2.1433 * X(0) * X(1) - 2.1433 * \ Y(0) * Y(1) + .21829 * Z(0) - 6.125 * Z(1) + 5.907 Hmat = H.to_numpy() # Compute |psi> = U |0> zero_state = np.array([1., 0., 0., 0.]) final_state = np.dot(u_mat, np.transpose(zero_state)) # Compute E = <psi| H |psi> energy = np.dot(final_state, np.dot(Hmat,final_state)) print(energy) self.assertAlmostEqual(energy, -1.74, places=1) def test_rewrite_decompose(self): try: import numpy as np except: print('No numpy, cant run test_rewrite_decompose') return set_qpu('qpp', {'shots':1024}) @qjit def foo(q : qreg): for i in range(q.size()): X(q[i]) with decompose(q) as ccnot: ccnot = np.eye(8) ccnot[6,6] = 0.0 ccnot[7,7] = 0.0 ccnot[6,7] = 1.0 ccnot[7,6] = 1.0 for i in range(q.size()): Measure(q[i]) print(foo.src) q = qalloc(3) foo(q) counts = q.counts() self.assertTrue('110' in counts) self.assertTrue(counts['110'] == 1024) @qjit def all_x(q : qreg): with decompose(q) as x_kron: sx = np.array([[0, 1],[1, 0]]) x_kron = np.kron(np.kron(sx,sx),sx) for i in range(q.size()): Measure(q[i]) print(all_x.src) q = qalloc(3) all_x(q) counts = q.counts() print(counts) self.assertTrue('111' in counts) self.assertTrue(counts['111'] == 1024) @qjit def try_two_decompose(q : qreg): for i in range(q.size()): X(q[i]) with decompose(q) as ccnot: ccnot = numpy.eye(8) ccnot[6,6] = 0.0 ccnot[7,7] = 0.0 ccnot[6,7] = 1.0 ccnot[7,6] = 1.0 # should have 110 with decompose(q) as x_kron: sx = np.array([[0, 1],[1, 0]]) x_kron = np.kron(np.kron(sx,sx),sx) # Should have flipped the bits for i in range(q.size()): Measure(q[i]) print(try_two_decompose.src) q = qalloc(3) try_two_decompose(q) counts = q.counts() print(counts) self.assertTrue('001' in counts) self.assertTrue(counts['001'] == 1024) def test_more_decompose(self): try: import numpy as np except: print('No numpy, cant run test_more_decompose') return set_qpu('qpp', {'shots':1024}) @qjit def random_2qbit(q : qreg): with decompose(q, kak) as random_unitary: a = np.random.rand(4,4) qm, r = np.linalg.qr(a, mode='complete') random_unitary = qm for i in range(q.size()): Measure(q[i]) print(random_2qbit.src) q = qalloc(2) print(random_2qbit.extract_composite(q).toString()) @qjit def random_1qbit(q : qreg): with decompose(q, z_y_z) as random_unitary: random_unitary, _ = np.linalg.qr(np.random.rand(2,2), mode='complete') for i in range(q.size()): Measure(q[i]) print(random_1qbit.get_internal_src()) q = qalloc(2) print(random_1qbit.get_syntax_handler_src()) print(random_1qbit.extract_composite(q).toString()) # def test_decompose_param(self): # set_qpu('qpp') # @qjit # def ansatz(q : qreg, x : List[float]): # X(q[0]) # with decompose(q, kak) as u: # from scipy.sparse.linalg import expm # from openfermion.ops import QubitOperator # from openfermion.transforms import get_sparse_operator # qop = QubitOperator('X0 Y1') - QubitOperator('Y0 X1') # qubit_sparse = get_sparse_operator(qop) # u = expm(0.5j * x[0] * qubit_sparse).todense() # H = -2.1433 * X(0) * X(1) - 2.1433 * \ # Y(0) * Y(1) + .21829 * Z(0) - 6.125 * Z(1) + 5.907 # o = createObjectiveFunction(ansatz, H, 1, {'gradient-strategy':'central', 'step':1e-1}) # opt = createOptimizer('nlopt', {'initial-parameters':[.5], 'maxeval':10, 'algorithm':'l-bfgs'}) # results = opt.optimize(o) # print("WE ARE DONE") # self.assertAlmostEqual(results[0], -1.74, places=1) if __name__ == '__main__': unittest.main() No newline at end of file
python/tests/test_kernel_jit.py→python/tests/test_jit_nested.py +206 −0 Original line number Diff line number Diff line Loading @@ -6,303 +6,6 @@ import math as myMathMod # Some global variables for testing MY_PI = 3.1416 class TestKernelJIT(unittest.TestCase): def test_as_unitary(self): try: import numpy as np except: print('No numpy, cant run test_as_unitary') return @qjit def dansatz(q : qreg, x : float): X(q[0]) Ry(q[1], x) CX(q[1], q[0]) u_mat = dansatz.as_unitary_matrix(qalloc(2), .59) H = -2.1433 * X(0) * X(1) - 2.1433 * \ Y(0) * Y(1) + .21829 * Z(0) - 6.125 * Z(1) + 5.907 Hmat = H.to_numpy() # Compute |psi> = U |0> zero_state = np.array([1., 0., 0., 0.]) final_state = np.dot(u_mat, np.transpose(zero_state)) # Compute E = <psi| H |psi> energy = np.dot(final_state, np.dot(Hmat,final_state)) print(energy) self.assertAlmostEqual(energy, -1.74, places=1) def test_rewrite_decompose(self): try: import numpy as np except: print('No numpy, cant run test_rewrite_decompose') return set_qpu('qpp', {'shots':1024}) @qjit def foo(q : qreg): for i in range(q.size()): X(q[i]) with decompose(q) as ccnot: ccnot = np.eye(8) ccnot[6,6] = 0.0 ccnot[7,7] = 0.0 ccnot[6,7] = 1.0 ccnot[7,6] = 1.0 for i in range(q.size()): Measure(q[i]) print(foo.src) q = qalloc(3) foo(q) counts = q.counts() self.assertTrue('110' in counts) self.assertTrue(counts['110'] == 1024) @qjit def all_x(q : qreg): with decompose(q) as x_kron: sx = np.array([[0, 1],[1, 0]]) x_kron = np.kron(np.kron(sx,sx),sx) for i in range(q.size()): Measure(q[i]) print(all_x.src) q = qalloc(3) all_x(q) counts = q.counts() print(counts) self.assertTrue('111' in counts) self.assertTrue(counts['111'] == 1024) @qjit def try_two_decompose(q : qreg): for i in range(q.size()): X(q[i]) with decompose(q) as ccnot: ccnot = numpy.eye(8) ccnot[6,6] = 0.0 ccnot[7,7] = 0.0 ccnot[6,7] = 1.0 ccnot[7,6] = 1.0 # should have 110 with decompose(q) as x_kron: sx = np.array([[0, 1],[1, 0]]) x_kron = np.kron(np.kron(sx,sx),sx) # Should have flipped the bits for i in range(q.size()): Measure(q[i]) print(try_two_decompose.src) q = qalloc(3) try_two_decompose(q) counts = q.counts() print(counts) self.assertTrue('001' in counts) self.assertTrue(counts['001'] == 1024) def test_more_decompose(self): try: import numpy as np except: print('No numpy, cant run test_more_decompose') return set_qpu('qpp', {'shots':1024}) @qjit def random_2qbit(q : qreg): with decompose(q, kak) as random_unitary: a = np.random.rand(4,4) qm, r = np.linalg.qr(a, mode='complete') random_unitary = qm for i in range(q.size()): Measure(q[i]) print(random_2qbit.src) q = qalloc(2) print(random_2qbit.extract_composite(q).toString()) @qjit def random_1qbit(q : qreg): with decompose(q, z_y_z) as random_unitary: random_unitary, _ = np.linalg.qr(np.random.rand(2,2), mode='complete') for i in range(q.size()): Measure(q[i]) print(random_1qbit.get_internal_src()) q = qalloc(2) print(random_1qbit.get_syntax_handler_src()) print(random_1qbit.extract_composite(q).toString()) # def test_decompose_param(self): # set_qpu('qpp') # @qjit # def ansatz(q : qreg, x : List[float]): # X(q[0]) # with decompose(q, kak) as u: # from scipy.sparse.linalg import expm # from openfermion.ops import QubitOperator # from openfermion.transforms import get_sparse_operator # qop = QubitOperator('X0 Y1') - QubitOperator('Y0 X1') # qubit_sparse = get_sparse_operator(qop) # u = expm(0.5j * x[0] * qubit_sparse).todense() # H = -2.1433 * X(0) * X(1) - 2.1433 * \ # Y(0) * Y(1) + .21829 * Z(0) - 6.125 * Z(1) + 5.907 # o = createObjectiveFunction(ansatz, H, 1, {'gradient-strategy':'central', 'step':1e-1}) # opt = createOptimizer('nlopt', {'initial-parameters':[.5], 'maxeval':10, 'algorithm':'l-bfgs'}) # results = opt.optimize(o) # print("WE ARE DONE") # self.assertAlmostEqual(results[0], -1.74, places=1) def test_simple_bell(self): set_qpu('qpp', {'shots':1024}) @qjit def bell(q : qreg): H(q[0]) CX(q[0], q[1]) for i in range(q.size()): Measure(q[i]) # Allocate 2 qubits q = qalloc(2) # Run the bell experiment bell(q) # Print the results q.print() self.assertAlmostEqual(q.exp_val_z(), 1.0, places=1) counts = q.counts() self.assertEqual(len(counts), 2) self.assertTrue('00' in counts) self.assertTrue('11' in counts) def test_assignment(self): set_qpu('qpp', {'shots':1024}) @qjit def varAssignKernel(q : qreg): # Simple value assignment angle = 3.14/4.0 Rx(q[0], angle) CX(q[0], q[1]) for i in range(q.size()): Measure(q[i]) # Allocate 2 qubits q = qalloc(2) # Run the bell experiment varAssignKernel(q) # Print the results q.print() counts = q.counts() self.assertEqual(len(counts), 2) self.assertTrue('00' in counts) self.assertTrue('11' in counts) # Angle less than Pi/2 => 00 more than 11 self.assertTrue(counts['00'] > counts['11']) def test_globalVar(self): set_qpu('qpp', {'shots':1024}) @qjit def kernelUseGlobals(q : qreg): Rx(q[0], MY_PI) CX(q[0], q[1]) for i in range(q.size()): Measure(q[i]) # Allocate 2 qubits q = qalloc(2) # Run the bell experiment kernelUseGlobals(q) # Print the results q.print() counts = q.counts() # Pi pulse -> X gate self.assertTrue(counts['11'] > 1000) def test_ModuleConstants(self): set_qpu('qpp', {'shots':1024}) @qjit def kernelUseConstants(q : qreg): # Use math.pi constant Rx(q[0], myMathMod.pi/2) CX(q[0], q[1]) for i in range(q.size()): Measure(q[i]) # Allocate 2 qubits q = qalloc(2) # Run the bell experiment kernelUseConstants(q) # Print the results q.print() counts = q.counts() self.assertEqual(len(counts), 2) self.assertTrue('00' in counts) self.assertTrue('11' in counts) def test_exp_i_theta(self): @qjit def kernelExpVar(q : qreg, theta: float): exponent_op = X(0) * Y(1) - Y(0) * X(1) exp_i_theta(q, theta, exponent_op) # Allocate 2 qubits q = qalloc(2) theta = 1.234 # Validate exp_i_theta expansion comp = kernelExpVar.extract_composite(q, theta) self.assertEqual(comp.nInstructions(), 14) # Test of edge case where the first statement is a for loop def test_for_loop(self): @qjit def testFor(q : qreg): for i in range(q.size()): H(q[i]) q = qalloc(5) comp = testFor.extract_composite(q) self.assertEqual(comp.nInstructions(), 5) def test_for_loop_enumerate(self): set_qpu('qpp') @qjit def ansatz(q: qreg, x: List[float], exp_args: List[FermionOperator]): X(q[0]) for i, exp_arg in enumerate(exp_args): exp_i_theta(q, x[i], exp_args[i]) exp_args = [adag(0) * a(1) - adag(1)*a(0), adag(0)*a(2) - adag(2)*a(0)] H = createOperator('5.907 - 2.1433 X0X1 - 2.1433 Y0Y1 + .21829 Z0 - 6.125 Z1 + 9.625 - 9.625 Z2 - 3.91 X1 X2 - 3.91 Y1 Y2') energy = ansatz.observe(H, qalloc(3), [0.7118083109334505, 0.27387413138588135], exp_args) self.assertAlmostEqual(energy, -2.044, places=1) def test_multiple_kernels(self): @qjit Loading Loading @@ -499,37 +202,5 @@ class TestKernelJIT(unittest.TestCase): self.assertAlmostEqual((float)(comp.getInstruction(2).getParameter(0)), -1.234) self.assertEqual(comp.getInstruction(3).name(), "CNOT") # Test conditional if..elif..else rewrite def test_if_clause(self): @qjit def test_if_stmt(q : qreg, flag: int): H(q[0]) if flag == 0: X(q[0]) elif flag == 1: Y(q[0]) elif flag == 2: Z(q[0]) else: T(q[0]) q = qalloc(2) # Examine the circuit QASM with various values of flag comp0 = test_if_stmt.extract_composite(q, 0) comp1 = test_if_stmt.extract_composite(q, 1) comp2 = test_if_stmt.extract_composite(q, 2) comp3 = test_if_stmt.extract_composite(q, 3) self.assertEqual(comp0.nInstructions(), 2) self.assertEqual(comp1.nInstructions(), 2) self.assertEqual(comp2.nInstructions(), 2) self.assertEqual(comp3.nInstructions(), 2) self.assertEqual(comp0.getInstruction(1).name(), "X") self.assertEqual(comp1.getInstruction(1).name(), "Y") self.assertEqual(comp2.getInstruction(1).name(), "Z") self.assertEqual(comp3.getInstruction(1).name(), "T") if __name__ == '__main__': unittest.main() No newline at end of file