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: default avatarThien Nguyen <nguyentm@ornl.gov>
parent e839afbb
Loading
Loading
Loading
Loading
+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@']
@@ -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 
+17 −3
Original line number Diff line number Diff line
@@ -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
+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
+206 −0
Original line number Diff line number Diff line
@@ -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
@@ -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
+180 −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_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)

    # 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