Commit 4c87e13d authored by Mccaskey, Alex's avatar Mccaskey, Alex
Browse files

adding tester for kernelbuilder work. added invoke() method to call previous qjit kernels

parent 30706ae1
Loading
Loading
Loading
Loading
Loading
+25 −13
Original line number Diff line number Diff line
@@ -33,6 +33,15 @@ FermionOperator = xacc.quantum.FermionOperator
FLOAT_REF = typing.NewType('value', float)
INT_REF = typing.NewType('value', int)

typing_to_simple_map = {'<class \'_pyqcor.qreg\'>': 'qreg',
                            '<class \'float\'>': 'float', 'typing.List[float]': 'List[float]',
                            '<class \'int\'>': 'int', 'typing.List[int]': 'List[int]',
                            '<class \'_pyxacc.quantum.PauliOperator\'>': 'PauliOperator',
                            '<class \'_pyxacc.quantum.FermionOperator\'>': 'FermionOperator',
                            'typing.List[typing.Tuple[int, int]]': 'List[Tuple[int,int]]',
                            'typing.List[_pyxacc.quantum.PauliOperator]': 'List[PauliOperator]',
                            'typing.List[_pyxacc.quantum.FermionOperator]': 'List[FermionOperator]'}

# Need to add a few extra header paths 
# for the clang code-gen mechanism. Mac OS X will 
# need QCOR_EXTRA_HEADERS, all will need the 
@@ -723,9 +732,18 @@ class KernelBuilder(object):
        self.qjit_str += self.TAB+"{} = _internal_python_createObservable(\"{}\", \"{}\")\n".format(op_var_name, op_type, op_str)
        self.qjit_str += self.TAB+'exp_i_theta({}, {}, {})\n'.format(self.qreg_name, params_str, op_var_name)

    def invoke(self, kernel_function : qjit):
        arg_names, _, _, _, _, _, type_annotations = inspect.getfullargspec(
            kernel_function)
        args_dict = {k:v for k,v in kernel_function.type_annotations.items() if str(typing_to_simple_map[str(v)]) != 'qreg'}
        self.kernel_args = {**args_dict, **self.kernel_args}
        self.qjit_str+= self.TAB+'{}({}, {})\n'.format(kernel_function.kernel_name(), self.qreg_name, ','.join(list(self.kernel_args.keys())))

    def from_qasm(self, qasm_str):
        xacc_ir = xacc.getCompiler('staq').compile(qasm_str).getComposites()[0]
        pyxasm = xacc.getCompiler('pyxasm').translate(xacc_ir, {'qreg_name':self.qreg_name, 'tab_prepend':self.TAB})
        pyxasm = xacc.getCompiler('pyxasm').translate(xacc_ir)
        pyxasm = pyxasm.replace('__translate_qrg__', self.qreg_name)
        pyxasm = '\n'.join(self.TAB+line for line in pyxasm.split('\n'))
        processed_str = pyxasm        
        self.qjit_str += processed_str

@@ -776,21 +794,15 @@ class KernelBuilder(object):

    def create(self):
        # print(self.qjit_str)
        allowed_type_map = {'<class \'_pyqcor.qreg\'>': 'qreg',
                                     '<class \'float\'>': 'float', 'typing.List[float]': 'List[float]',
                                     '<class \'int\'>': 'int', 'typing.List[int]': 'List[int]',
                                     '<class \'_pyxacc.quantum.PauliOperator\'>': 'PauliOperator',
                                     '<class \'_pyxacc.quantum.FermionOperator\'>': 'FermionOperator',
                                     'typing.List[typing.Tuple[int, int]]': 'List[Tuple[int,int]]',
                                     'typing.List[_pyxacc.quantum.PauliOperator]': 'List[PauliOperator]',
                                     'typing.List[_pyxacc.quantum.FermionOperator]': 'List[FermionOperator]'}

        kernel_name = '__internal_qjit_kernelbuilder_kernel_'+str(uuid.uuid4()).replace('-','_')
        if inspect.stack()[-1].code_context is not None:
            kernel_name = inspect.stack()[-1].code_context[0].split(' = ')[0]
        for element in inspect.stack():
            if len(element.code_context) and element.code_context[0] != None:
                if '.create()' in element.code_context[0]:
                    kernel_name = element.code_context[0].strip().split(' = ')[0]

        # FIXME optionally add , if we have kernel_args
        args_str = 'q : qreg'+ (', ' if len(self.kernel_args) else '') + ', '.join(k+' : '+allowed_type_map[str(v)] for k,v in self.kernel_args.items())
        args_str = 'q : qreg'+ (', ' if len(self.kernel_args) else '') + ', '.join(k+' : '+typing_to_simple_map[str(v)] for k,v in self.kernel_args.items())
        func = 'def {}({}):\n'.format(kernel_name, args_str)+self.qjit_str
        # print(func)
        result = globals()
+6 −0
Original line number Diff line number Diff line
@@ -19,6 +19,12 @@ set_tests_properties(qcor_python_jit_simple
#set_tests_properties(qcor_python_jit_nested_kernels
#   PROPERTIES ENVIRONMENT "PYTHONPATH=${CMAKE_INSTALL_PREFIX}:$ENV{PYTHONPATH}")

#add_test (NAME qcor_python_kernel_builder
# COMMAND ${Python_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test_kernel_builder.py 
# WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
#set_tests_properties(qcor_python_kernel_builder
#   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}
+155 −0
Original line number Diff line number Diff line
import unittest
from qcor import *

class TestKernelBuilder(unittest.TestCase):
    def test_simple_bell(self):
        set_qpu('qpp', {'shots':100})
        builder = KernelBuilder()
        builder.h(0)
        for i in range(5):
            builder.cnot(i, i+1)
        builder.measure_all()
        ghz_6 = builder.create()
        q = qalloc(6)
        ghz_6(q)
        counts = q.counts()
        print(counts)
        self.assertTrue('111111' in counts)
        self.assertTrue('000000' in counts)
        self.assertTrue(len(counts) == 2)
    
    def test_variational_spec(self):
        set_qpu('qpp')
        builder = KernelBuilder()

        builder.x(0)
        builder.ry(1, 't')
        builder.cnot(1, 0) 

        ansatz = builder.create()

        H = -2.1433 * X(0) * X(1) - 2.1433 * \
            Y(0) * Y(1) + .21829 * Z(0) - 6.125 * Z(1) + 5.907

        n_params = 1
        obj = createObjectiveFunction(ansatz, H, n_params)

        # evaluate at a concrete set of params
        vqe_energy = obj([.59])
        self.assertAlmostEqual(vqe_energy, -1.74, places=1)


        # Run full optimization
        optimizer = createOptimizer('nlopt')
        results = optimizer.optimize(obj)
        self.assertAlmostEqual(results[0], -1.74, places=1)
    
    def test_from_qasm(self):
        set_qpu('qpp', {'shots':100})
        src = '''OPENQASM 2.0;
include "qelib1.inc";
qreg q[3];
creg c[3];
h q[0];
cx q[0],q[1];
cx q[1],q[2];
measure q[0] -> c[0];
measure q[1] -> c[1];
measure q[2] -> c[2];
'''
        builder = KernelBuilder()
        builder.from_qasm(src)
        test_from_qasm = builder.create()

        q = qalloc(3)
        test_from_qasm(q)
        counts = q.counts()
        self.assertTrue('111' in counts)
        self.assertTrue('000' in counts)
        self.assertTrue(len(counts) == 2)

    
    # def test_synthesis(self):
    def test_exp(self):
        exponent_op = adag(0) * a(1) - adag(1) * a(0)

        builder = KernelBuilder()
        builder.x(0)
        builder.exp('theta', exponent_op)
        ansatz = builder.create()
        # Define the hamiltonian
        H = -2.1433 * X(0) * X(1) - 2.1433 * Y(0) * Y(1) + .21829 * Z(0) - 6.125 * Z(1) + 5.907
        # Create the ObjectiveFunction, specify central finite diff gradient
        obj = createObjectiveFunction(ansatz, H, 1, {'gradient-strategy':'central', 'step':1e-1})
        # create the lbfgs optimizer
        optimizer = createOptimizer('nlopt', {'algorithm':'l-bfgs', 'ftol':1e-3})
        results = optimizer.optimize(obj)
        self.assertAlmostEqual(results[0], -1.74, places=1)

    def test_synthesis(self):
        set_qpu('qpp', {'shots':100})
        try:
           import numpy as np
        except:
            print('No numpy, cant run test_synthesis')
            return

        ccnot = np.eye(8)
        ccnot[6,6] = 0.0
        ccnot[7,7] = 0.0
        ccnot[6,7] = 1.0
        ccnot[7,6] = 1.0

        # Synthesize the CCNOT kernel 
        # using the KernelBuilder
        builder = KernelBuilder()
        [builder.x(i) for i in range(3)]
        builder.synthesize(unitary=ccnot)
        builder.measure(range(3))
        ccnot_circuit = builder.create()    

        q = qalloc(3)
        ccnot_circuit(q)
        counts = q.counts()
        self.assertTrue(len(counts) == 1)
        self.assertTrue('110' in counts)

    def test_call_previous_kernels(self):
        builder = KernelBuilder()

        builder.x(0)
        builder.ry(1, 't')
        builder.cnot(1, 0) 
        ansatz = builder.create()

        @qjit
        def x0x1(q : qreg, t:float):
            ansatz(q, t)
            H(q[0])
            H(q[1])
            Measure(q[0])
            Measure(q[1])

        q = qalloc(2)
        x0x1(q, 2.2)
        self.assertAlmostEqual(q.exp_val_z(), .8085, places=1)

        b = KernelBuilder()
        b.invoke(ansatz)
        b.h(0)
        b.h(1)
        b.measure_all()
        test = b.create()

        q = qalloc(2)
        test(q, 2.2)
        self.assertAlmostEqual(q.exp_val_z(), .8085, places=1)







if __name__ == '__main__':
  unittest.main()
 No newline at end of file