import os
import filecmp
import unittest
import numpy as np
from openql import openql as ql
from utils import file_compare

curdir = os.path.dirname(os.path.realpath(__file__))
output_dir = os.path.join(curdir, 'test_output')

class Test_bugs(unittest.TestCase):
    @classmethod
    def setUp(self):
        ql.initialize()
        ql.set_option('output_dir', output_dir)
        ql.set_option('use_default_gates', 'yes')
        ql.set_option('log_level', 'LOG_WARNING')

    # @unittest.expectedFailure
    # @unittest.skip
    def test_typecast(self):
        sweep_points = [1,2]
        num_circuits = 1
        num_qubits = 2
        platf = ql.Platform("starmon", 'cc_light')
        p = ql.Program('test_bug', platf, num_qubits)
        p.set_sweep_points(sweep_points)
        k = ql.Kernel('kernel1', platf, num_qubits)

        qubit = 1

        k.identity(np.int(qubit))
        k.identity(np.int32(qubit))
        k.identity(np.int64(qubit))

        k.identity(np.uint(qubit))
        k.identity(np.uint32(qubit))
        k.identity(np.uint64(qubit))

        # add the kernel to the program
        p.add_kernel(k)


    # relates to https://github.com/QE-Lab/OpenQL/issues/171
    # various runs of compiles were generating different results or in the best
    # case strange errors. So multiple (NCOMPILES) runs of compile are executed
    # to make sure there is no error and output generated in all these runs is same
    # JvS: more likely, it also had to do with the classical register allocator
    # depending on stuff like Python's garbage collection to free a register.
    # The register numbers have to be hardcoded now for that reason.
    def test_stateful_behavior(self):
        ql.set_option('optimize', 'no')
        ql.set_option('scheduler', 'ALAP')

        platform = ql.Platform("myPlatform", 'cc_light')

        sweep_points = [1]
        nqubits = 3
        nregs = 3

        p = ql.Program("statelessProgram", platform, nqubits, nregs)
        p.set_sweep_points(sweep_points)
        k = ql.Kernel("aKernel", platform, nqubits, nregs)

        k.prepz(0)
        k.gate('rx180', [0])
        k.measure(0)

        rd = ql.CReg(0)
        rs1 = ql.CReg(1)
        rs2 = ql.CReg(2)

        k.classical(rs1, ql.Operation(3))
        k.classical(rs1, ql.Operation(4))
        k.classical(rd, ql.Operation(rs1, '+', rs2))

        p.add_kernel(k)

        NCOMPILES=50
        QISA_fn = os.path.join(output_dir, p.name+'_last.qasm')
        for i in range(NCOMPILES):
            p.compile()
            self.setUpClass()
            QISA_fn_i = os.path.join(output_dir, p.name+'_'+str(i)+'_last.qasm')
            os.rename(QISA_fn,QISA_fn_i)

        for i in range(NCOMPILES-1):
            QISA_fn_1 = os.path.join(output_dir, p.name+'_'+str(i)+'_last.qasm')
            QISA_fn_2 = os.path.join(output_dir, p.name+'_'+str(i+1)+'_last.qasm')
            self.assertTrue( file_compare(QISA_fn_1, QISA_fn_2))

# Unclear how this test works.
# When clear, enable it again.
# Now it fails, not clear how to repair, so it is disabled.
#    def test_empty_infinite_loop(self):
#        name = 'empty_infinite_loop'
#        in_fn = 'test_' + name + '.cq'
#        out_fn = 'test_output/' + name + '_out.cq'
#        gold_fn = 'golden/' + name + '_out.cq'
#        ql.initialize()
#        #ql.set_option('log_level', 'LOG_DEBUG')
#        ql.compile(in_fn)
#        self.assertTrue(file_compare(out_fn, gold_fn))

if __name__ == '__main__':
    unittest.main()

[((9, 13, 9, 48), 'os.path.join', 'os.path.join', ({(9, 26, 9, 32): 'curdir', (9, 34, 9, 47): '"""test_output"""'}, {}), "(curdir, 'test_output')", False, 'import os\n'), ((8, 25, 8, 51), 'os.path.realpath', 'os.path.realpath', ({(8, 42, 8, 50): '__file__'}, {}), '(__file__)', False, 'import os\n'), ((106, 4, 106, 19), 'unittest.main', 'unittest.main', ({}, {}), '()', False, 'import unittest\n'), ((14, 8, 14, 23), 'openql.openql.initialize', 'ql.initialize', ({}, {}), '()', True, 'from openql import openql as ql\n'), ((15, 8, 15, 47), 'openql.openql.set_option', 'ql.set_option', ({(15, 22, 15, 34): '"""output_dir"""', (15, 36, 15, 46): 'output_dir'}, {}), "('output_dir', output_dir)", True, 'from openql import openql as ql\n'), ((16, 8, 16, 49), 'openql.openql.set_option', 'ql.set_option', ({(16, 22, 16, 41): '"""use_default_gates"""', (16, 43, 16, 48): '"""yes"""'}, {}), "('use_default_gates', 'yes')", True, 'from openql import openql as ql\n'), ((17, 8, 17, 49), 'openql.openql.set_option', 'ql.set_option', ({(17, 22, 17, 33): '"""log_level"""', (17, 35, 17, 48): '"""LOG_WARNING"""'}, {}), "('log_level', 'LOG_WARNING')", True, 'from openql import openql as ql\n'), ((25, 16, 25, 50), 'openql.openql.Platform', 'ql.Platform', ({(25, 28, 25, 37): '"""starmon"""', (25, 39, 25, 49): '"""cc_light"""'}, {}), "('starmon', 'cc_light')", True, 'from openql import openql as ql\n'), ((26, 12, 26, 53), 'openql.openql.Program', 'ql.Program', ({(26, 23, 26, 33): '"""test_bug"""', (26, 35, 26, 40): 'platf', (26, 42, 26, 52): 'num_qubits'}, {}), "('test_bug', platf, num_qubits)", True, 'from openql import openql as ql\n'), ((28, 12, 28, 51), 'openql.openql.Kernel', 'ql.Kernel', ({(28, 22, 28, 31): '"""kernel1"""', (28, 33, 28, 38): 'platf', (28, 40, 28, 50): 'num_qubits'}, {}), "('kernel1', platf, num_qubits)", True, 'from openql import openql as ql\n'), ((52, 8, 52, 39), 'openql.openql.set_option', 'ql.set_option', ({(52, 22, 52, 32): '"""optimize"""', (52, 34, 52, 38): '"""no"""'}, {}), "('optimize', 'no')", True, 'from openql import openql as ql\n'), ((53, 8, 53, 42), 'openql.openql.set_option', 'ql.set_option', ({(53, 22, 53, 33): '"""scheduler"""', (53, 35, 53, 41): '"""ALAP"""'}, {}), "('scheduler', 'ALAP')", True, 'from openql import openql as ql\n'), ((55, 19, 55, 56), 'openql.openql.Platform', 'ql.Platform', ({(55, 31, 55, 43): '"""myPlatform"""', (55, 45, 55, 55): '"""cc_light"""'}, {}), "('myPlatform', 'cc_light')", True, 'from openql import openql as ql\n'), ((61, 12, 61, 68), 'openql.openql.Program', 'ql.Program', ({(61, 23, 61, 41): '"""statelessProgram"""', (61, 43, 61, 51): 'platform', (61, 53, 61, 60): 'nqubits', (61, 62, 61, 67): 'nregs'}, {}), "('statelessProgram', platform, nqubits, nregs)", True, 'from openql import openql as ql\n'), ((63, 12, 63, 58), 'openql.openql.Kernel', 'ql.Kernel', ({(63, 22, 63, 31): '"""aKernel"""', (63, 33, 63, 41): 'platform', (63, 43, 63, 50): 'nqubits', (63, 52, 63, 57): 'nregs'}, {}), "('aKernel', platform, nqubits, nregs)", True, 'from openql import openql as ql\n'), ((69, 13, 69, 23), 'openql.openql.CReg', 'ql.CReg', ({(69, 21, 69, 22): '0'}, {}), '(0)', True, 'from openql import openql as ql\n'), ((70, 14, 70, 24), 'openql.openql.CReg', 'ql.CReg', ({(70, 22, 70, 23): '1'}, {}), '(1)', True, 'from openql import openql as ql\n'), ((71, 14, 71, 24), 'openql.openql.CReg', 'ql.CReg', ({(71, 22, 71, 23): '2'}, {}), '(2)', True, 'from openql import openql as ql\n'), ((80, 18, 80, 63), 'os.path.join', 'os.path.join', ({(80, 31, 80, 41): 'output_dir', (80, 43, 80, 62): "p.name + '_last.qasm'"}, {}), "(output_dir, p.name + '_last.qasm')", False, 'import os\n'), ((32, 19, 32, 32), 'numpy.int', 'np.int', ({(32, 26, 32, 31): 'qubit'}, {}), '(qubit)', True, 'import numpy as np\n'), ((33, 19, 33, 34), 'numpy.int32', 'np.int32', ({(33, 28, 33, 33): 'qubit'}, {}), '(qubit)', True, 'import numpy as np\n'), ((34, 19, 34, 34), 'numpy.int64', 'np.int64', ({(34, 28, 34, 33): 'qubit'}, {}), '(qubit)', True, 'import numpy as np\n'), ((36, 19, 36, 33), 'numpy.uint', 'np.uint', ({(36, 27, 36, 32): 'qubit'}, {}), '(qubit)', True, 'import numpy as np\n'), ((37, 19, 37, 35), 'numpy.uint32', 'np.uint32', ({(37, 29, 37, 34): 'qubit'}, {}), '(qubit)', True, 'import numpy as np\n'), ((38, 19, 38, 35), 'numpy.uint64', 'np.uint64', ({(38, 29, 38, 34): 'qubit'}, {}), '(qubit)', True, 'import numpy as np\n'), ((73, 25, 73, 40), 'openql.openql.Operation', 'ql.Operation', ({(73, 38, 73, 39): '(3)'}, {}), '(3)', True, 'from openql import openql as ql\n'), ((74, 25, 74, 40), 'openql.openql.Operation', 'ql.Operation', ({(74, 38, 74, 39): '(4)'}, {}), '(4)', True, 'from openql import openql as ql\n'), ((75, 24, 75, 51), 'openql.openql.Operation', 'ql.Operation', ({(75, 37, 75, 40): 'rs1', (75, 42, 75, 45): '"""+"""', (75, 47, 75, 50): 'rs2'}, {}), "(rs1, '+', rs2)", True, 'from openql import openql as ql\n'), ((85, 12, 85, 40), 'os.rename', 'os.rename', ({(85, 22, 85, 29): 'QISA_fn', (85, 30, 85, 39): 'QISA_fn_i'}, {}), '(QISA_fn, QISA_fn_i)', False, 'import os\n'), ((90, 29, 90, 63), 'utils.file_compare', 'file_compare', ({(90, 42, 90, 51): 'QISA_fn_1', (90, 53, 90, 62): 'QISA_fn_2'}, {}), '(QISA_fn_1, QISA_fn_2)', False, 'from utils import file_compare\n')]