Commit 6ee0a8a3 authored by Nguyen, Thien Minh's avatar Nguyen, Thien Minh
Browse files

Attempts to fix sporadic segfault on exit



- Split the python JIT test into multiple files per category (simple, nested, or decompose) so that we can debug easily.

- Explicitly clear the QJIT python cache on exit.

Signed-off-by: Nguyen, Thien Minh's avatarThien Nguyen <nguyentm@ornl.gov>
parent e839afbb
import sys
import sys, atexit
if '@QCOR_APPEND_PLUGIN_PATH@':
sys.argv += ['__internal__add__plugin__path', '@QCOR_APPEND_PLUGIN_PATH@']
......@@ -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
......
......@@ -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
......
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
......@@ -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
......@@ -497,39 +200,7 @@ class TestKernelJIT(unittest.TestCase):
self.assertEqual(comp.getInstruction(2).name(), "Rx")
# Check angle -> -angle
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")
self.assertEqual(comp.getInstruction(3).name(), "CNOT")
if __name__ == '__main__':
unittest.main()
\ No newline at end of file
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_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