""" Module to test slice implementation. """

import numpy
from pythran.typing import List, NDArray

from pythran.tests import TestEnv

class TestSlice(TestEnv):

    """
    Unittest class for code using slices.

    We skip tests for None step as it is equivalent to 1.

    TODO : add tests for 1 == step (None as step)
    """

    def test_empty_slices(self):
        code = 'def empty_slices(x): return x[100:], x[100::2]'
        self.run_test(code, numpy.arange(90),
                      empty_slices=[NDArray[int,:]])

    def test_slice_combination1(self):
        """ Check for "all none" combination. """
        code = """
def slice_combination1(a):
    begin = {begin}
    end = {end}
    step = {step}
    return (a[::][begin:end:step],
            a[::-4][begin:end:step],
            a[::4][begin:end:step],
            a[87::-4][begin:end:step],
            a[1::4][begin:end:step],
            a[-3::-4][begin:end:step],
            a[-89::4][begin:end:step],
            a[88:1:-4][begin:end:step],
            a[1:88:4][begin:end:step],
            a[-2:1:-4][begin:end:step],
            a[-89:88:4][begin:end:step],
            a[88:-88:-4][begin:end:step],
            a[2:-1:4][begin:end:step],
            a[-1:-88:-4][begin:end:step],
            a[-88:-1:4][begin:end:step],
            a[:1:-4][begin:end:step],
            a[:87:4][begin:end:step],
            a[:-87:-4][begin:end:step],
            a[:-3:4][begin:end:step])
        """.format(begin=None, end=None, step=None)
        self.run_test(code, numpy.arange(90),
                      slice_combination1=[NDArray[int,:]])

    def test_slice_combination2(self):
        """ Check for positive step combination. """
        code = """
def slice_combination2(a):
    begin = {begin}
    end = {end}
    step = {step}
    return (a[::][begin:end:step],
            a[::-4][begin:end:step],
            a[::4][begin:end:step],
            a[87::-4][begin:end:step],
            a[1::4][begin:end:step],
            a[-3::-4][begin:end:step],
            a[-89::4][begin:end:step],
            a[88:1:-4][begin:end:step],
            a[1:88:4][begin:end:step],
            a[-2:1:-4][begin:end:step],
            a[-89:88:4][begin:end:step],
            a[88:-88:-4][begin:end:step],
            a[2:-1:4][begin:end:step],
            a[-1:-88:-4][begin:end:step],
            a[-88:-1:4][begin:end:step],
            a[:1:-4][begin:end:step],
            a[:87:4][begin:end:step],
            a[:-87:-4][begin:end:step],
            a[:-3:4][begin:end:step])
        """.format(begin=None, end=None, step=2)
        self.run_test(code, numpy.arange(90),
                      slice_combination2=[NDArray[int, :]])

    def test_slice_combination3(self):
        """ Check for negative step combination. """
        code = """
def slice_combination3(a):
    begin = {begin}
    end = {end}
    step = {step}
    return (a[::][begin:end:step])
# Reversing values with not continuous step is not implemented
#            a[::-4][begin:end:step],
#            a[::4][begin:end:step],
#            a[87::-4][begin:end:step],
#            a[1::4][begin:end:step],
#            a[-3::-4][begin:end:step],
#            a[-89::4][begin:end:step],
#            a[88:1:-4][begin:end:step],
#            a[1:88:4][begin:end:step],
#            a[-2:1:-4][begin:end:step],
#            a[-89:88:4][begin:end:step],
#            a[88:-88:-4][begin:end:step],
#            a[2:-1:4][begin:end:step],
#            a[-1:-88:-4][begin:end:step],
#            a[-88:-1:4][begin:end:step],
#            a[:1:-4][begin:end:step],
#            a[:87:4][begin:end:step],
#            a[:-87:-4][begin:end:step],
#            a[:-3:4][begin:end:step])
        """.format(begin=None, end=None, step=-2)
        self.run_test(code, numpy.arange(90),
                      slice_combination3=[NDArray[int, :]])

    def test_slice_combination4(self):
        """ Check for pos step/no begin/pos end combination. """
        code = """
def slice_combination4(a):
    begin = {begin}
    end = {end}
    step = {step}
    return (a[::][begin:end:step],
            a[::4][begin:end:step],
            a[87::-4][begin:end:step],
            a[1::4][begin:end:step],
            a[-3::-4][begin:end:step],
            a[-89::4][begin:end:step],
            a[88:1:-4][begin:end:step],
            a[1:88:4][begin:end:step],
            a[-2:1:-4][begin:end:step],
            a[-89:88:4][begin:end:step],
            a[88:-88:-4][begin:end:step],
            a[2:-1:4][begin:end:step],
            a[-1:-88:-4][begin:end:step],
            a[-88:-1:4][begin:end:step],
            a[:1:-4][begin:end:step],
            a[:87:4][begin:end:step],
            a[:-87:-4][begin:end:step],
            a[:-3:4][begin:end:step])
        """.format(begin=None, end=7, step=2)
        self.run_test(code, numpy.arange(90),
                      slice_combination4=[NDArray[int, :]])

    def test_slice_combination5(self):
        """ Check for pos step/no begin/neg end combination. """
        code = """
def slice_combination5(a):
    begin = {begin}
    end = {end}
    step = {step}
    return (a[::][begin:end:step])
# Not implementer for negative end
#            a[::4][begin:end:step],
#            a[87::-4][begin:end:step],
#            a[1::4][begin:end:step],
#            a[-3::-4][begin:end:step],
#            a[-89::4][begin:end:step],
#            a[88:1:-4][begin:end:step],
#            a[1:88:4][begin:end:step],
#            a[-2:1:-4][begin:end:step],
#            a[-89:88:4][begin:end:step],
#            a[88:-88:-4][begin:end:step],
#            a[2:-1:4][begin:end:step],
#            a[-1:-88:-4][begin:end:step],
#            a[-88:-1:4][begin:end:step],
#            a[:1:-4][begin:end:step],
#            a[:87:4][begin:end:step],
#            a[:-87:-4][begin:end:step],
#            a[:-3:4][begin:end:step])
        """.format(begin=None, end=-3, step=2)
        self.run_test(code, numpy.arange(90),
                      slice_combination5=[NDArray[int, :]])

    def test_slice_combination6(self):
        """ Check for pos step/pos begin/no end combination. """
        code = """
def slice_combination6(a):
    begin = {begin}
    end = {end}
    step = {step}
    return (a[::][begin:end:step],
            a[::4][begin:end:step],
            a[87::-4][begin:end:step],
            a[1::4][begin:end:step],
            a[-3::-4][begin:end:step],
            a[-89::4][begin:end:step],
            a[88:1:-4][begin:end:step],
            a[1:88:4][begin:end:step],
            a[-2:1:-4][begin:end:step],
            a[-89:88:4][begin:end:step],
            a[88:-88:-4][begin:end:step],
            a[2:-1:4][begin:end:step],
            a[-1:-88:-4][begin:end:step],
            a[-88:-1:4][begin:end:step],
            a[:1:-4][begin:end:step],
            a[:87:4][begin:end:step],
            a[:-87:-4][begin:end:step],
            a[:-3:4][begin:end:step])
        """.format(begin=2, end=None, step=2)
        self.run_test(code, numpy.arange(90),
                      slice_combination6=[NDArray[int, :]])

    def test_slice_combination7(self):
        """ Check for pos step/pos begin/pos end combination. """
        code = """
def slice_combination7(a):
    begin = {begin}
    end = {end}
    step = {step}
    return (a[::][begin:end:step],
            a[::4][begin:end:step],
            a[87::-4][begin:end:step],
            a[1::4][begin:end:step],
            a[-3::-4][begin:end:step],
            a[-89::4][begin:end:step],
            a[88:1:-4][begin:end:step],
            a[1:88:4][begin:end:step],
            a[-2:1:-4][begin:end:step],
            a[-89:88:4][begin:end:step],
            a[88:-88:-4][begin:end:step],
            a[2:-1:4][begin:end:step],
            a[-1:-88:-4][begin:end:step],
            a[-88:-1:4][begin:end:step],
            a[:1:-4][begin:end:step],
            a[:87:4][begin:end:step],
            a[:-87:-4][begin:end:step],
            a[:-3:4][begin:end:step])
        """.format(begin=2, end=9, step=2)
        self.run_test(code, numpy.arange(90),
                      slice_combination7=[NDArray[int, :]])

    def test_slice_combination8(self):
        """ Check for pos step/neg begin/no end combination. """
        code = """
def slice_combination8(a):
    begin = {begin}
    end = {end}
    step = {step}
    return (a[::][begin:end:step])
# Not implementer for negative begin
#            a[::4][begin:end:step],
#            a[87::-4][begin:end:step],
#            a[1::4][begin:end:step],
#            a[-3::-4][begin:end:step],
#            a[-89::4][begin:end:step],
#            a[88:1:-4][begin:end:step],
#            a[1:88:4][begin:end:step],
#            a[-2:1:-4][begin:end:step],
#            a[-89:88:4][begin:end:step],
#            a[88:-88:-4][begin:end:step],
#            a[2:-1:4][begin:end:step],
#            a[-1:-88:-4][begin:end:step],
#            a[-88:-1:4][begin:end:step],
#            a[:1:-4][begin:end:step],
#            a[:87:4][begin:end:step],
#            a[:-87:-4][begin:end:step],
#            a[:-3:4][begin:end:step])
        """.format(begin=-10, end=None, step=2)
        self.run_test(code, numpy.arange(90),
                      slice_combination8=[NDArray[int, :]])

    def test_step1slice_combination1(self):
        """ Check for "all none" combination. """
        code = """
def step1slice_combination1(a):
    begin = {begin}
    end = {end}
    step = {step}
    return (a[::][begin:end:step],
            a[::-1][begin:end:step],
            a[::1][begin:end:step],
            a[87::-1][begin:end:step],
            a[1::1][begin:end:step],
            a[-3::-1][begin:end:step],
            a[-89::1][begin:end:step],
            a[88:1:-1][begin:end:step],
            a[1:88:1][begin:end:step],
            a[-2:1:-1][begin:end:step],
            a[-89:88:1][begin:end:step],
            a[88:-88:-1][begin:end:step],
            a[2:-1:1][begin:end:step],
            a[-1:-88:-1][begin:end:step],
            a[-88:-1:1][begin:end:step],
            a[:1:-1][begin:end:step],
            a[:87:1][begin:end:step],
            a[:-87:-1][begin:end:step],
            a[:-3:1][begin:end:step])
        """.format(begin=None, end=None, step=None)
        self.run_test(code, numpy.arange(90),
                      step1slice_combination1=[NDArray[int, :]])

    def test_step1slice_combination2(self):
        """ Check for positive step combination. """
        code = """
def step1slice_combination2(a):
    begin = {begin}
    end = {end}
    step = {step}
    return (a[::][begin:end:step],
            a[::-1][begin:end:step],
            a[::1][begin:end:step],
            a[87::-1][begin:end:step],
            a[1::1][begin:end:step],
            a[-3::-1][begin:end:step],
            a[-89::1][begin:end:step],
            a[88:1:-1][begin:end:step],
            a[1:88:1][begin:end:step],
            a[-2:1:-1][begin:end:step],
            a[-89:88:1][begin:end:step],
            a[88:-88:-1][begin:end:step],
            a[2:-1:1][begin:end:step],
            a[-1:-88:-1][begin:end:step],
            a[-88:-1:1][begin:end:step],
            a[:1:-1][begin:end:step],
            a[:87:1][begin:end:step],
            a[:-87:-1][begin:end:step],
            a[:-3:1][begin:end:step])
        """.format(begin=None, end=None, step=2)
        self.run_test(code, numpy.arange(90),
        step1slice_combination2=[NDArray[int, :]])

    def test_step1slice_combination3(self):
        """ Check for negative step combination. """
        code = """
def step1slice_combination3(a):
    begin = {begin}
    end = {end}
    step = {step}
    return (a[::][begin:end:step],
            a[::-1][begin:end:step],
            a[::1][begin:end:step],
            a[87::-1][begin:end:step],
            a[1::1][begin:end:step],
            a[-3::-1][begin:end:step],
            a[-89::1][begin:end:step],
            a[88:1:-1][begin:end:step],
            a[1:88:1][begin:end:step],
            a[-2:1:-1][begin:end:step],
            a[-89:88:1][begin:end:step],
            a[88:-88:-1][begin:end:step],
            a[2:-1:1][begin:end:step],
            a[-1:-88:-1][begin:end:step],
            a[-2:-88:-1][begin:end:step],
            a[-88:-1:1][begin:end:step],
            a[:1:-1][begin:end:step],
            a[:87:1][begin:end:step],
            a[:-87:-1][begin:end:step],
            a[:-3:1][begin:end:step])
        """.format(begin=None, end=None, step=-2)
        self.run_test(code, numpy.arange(90),
        step1slice_combination3=[NDArray[int, :]])

    def test_step1slice_combination4(self):
        """ Check for pos step/no begin/pos end combination. """
        code = """
def step1slice_combination4(a):
    begin = {begin}
    end = {end}
    step = {step}
    return(a[::][begin:end:step],
           a[::1][begin:end:step],
           a[87::-1][begin:end:step],
           a[1::1][begin:end:step],
           a[-3::-1][begin:end:step],
           a[-89::1][begin:end:step],
           a[88:1:-1][begin:end:step],
           a[1:88:1][begin:end:step],
           a[-2:1:-1][begin:end:step],
           a[-89:88:1][begin:end:step],
           a[88:-88:-1][begin:end:step],
           a[2:-1:1][begin:end:step],
           a[-1:-88:-1][begin:end:step],
           a[-88:-1:1][begin:end:step],
           a[:1:-1][begin:end:step],
           a[:87:1][begin:end:step],
           a[:-87:-1][begin:end:step],
           a[:-3:1][begin:end:step])
        """.format(begin=None, end=7, step=2)
        self.run_test(code, numpy.arange(90),
        step1slice_combination4=[NDArray[int, :]])

    def test_step1slice_combination5(self):
        """ Check for pos step/no begin/neg end combination. """
        code = """
def step1slice_combination5(a):
    begin = {begin}
    end = {end}
    step = {step}
    return (a[::][begin:end:step],
            a[::1][begin:end:step],
            a[87::-1][begin:end:step],
            a[1::1][begin:end:step],
            a[-3::-1][begin:end:step],
            a[-89::1][begin:end:step],
            a[88:1:-1][begin:end:step],
            a[1:88:1][begin:end:step],
            a[-2:1:-1][begin:end:step],
            a[-89:88:1][begin:end:step],
            a[88:-88:-1][begin:end:step],
            a[2:-1:1][begin:end:step],
            a[-1:-88:-1][begin:end:step],
            a[-88:-1:1][begin:end:step],
            a[:1:-1][begin:end:step],
            a[:87:1][begin:end:step],
            a[:-87:-1][begin:end:step],
            a[:-3:1][begin:end:step])
        """.format(begin=None, end=-3, step=2)
        self.run_test(code, numpy.arange(90),
        step1slice_combination5=[NDArray[int, :]])

    def test_step1slice_combination6(self):
        """ Check for pos step/pos begin/no end combination. """
        code = """
def step1slice_combination6(a):
    begin = {begin}
    end = {end}
    step = {step}
    return (a[::][begin:end:step],
            a[::1][begin:end:step],
            a[87::-1][begin:end:step],
            a[1::1][begin:end:step],
            a[-3::-1][begin:end:step],
            a[-89::1][begin:end:step],
            a[88:1:-1][begin:end:step],
            a[1:88:1][begin:end:step],
            a[-2:1:-1][begin:end:step],
            a[-89:88:1][begin:end:step],
            a[88:-88:-1][begin:end:step],
            a[2:-1:1][begin:end:step],
            a[-1:-88:-1][begin:end:step],
            a[-88:-1:1][begin:end:step],
            a[:1:-1][begin:end:step],
            a[:87:1][begin:end:step],
            a[:-87:-1][begin:end:step],
            a[:-3:1][begin:end:step])
        """.format(begin=2, end=None, step=2)
        self.run_test(code, numpy.arange(90),
        step1slice_combination6=[NDArray[int, :]])

    def test_step1slice_combination7(self):
        """ Check for pos step/pos begin/pos end combination. """
        code = """
def step1slice_combination7(a):
    begin = {begin}
    end = {end}
    step = {step}
    return (a[::][begin:end:step],
            a[::1][begin:end:step],
            a[87::-1][begin:end:step],
            a[1::1][begin:end:step],
            a[-3::-1][begin:end:step],
            a[-89::1][begin:end:step],
            a[88:1:-1][begin:end:step],
            a[1:88:1][begin:end:step],
            a[-2:1:-1][begin:end:step],
            a[-89:88:1][begin:end:step],
            a[88:-88:-1][begin:end:step],
            a[2:-1:1][begin:end:step],
            a[-1:-88:-1][begin:end:step],
            a[-88:-1:1][begin:end:step],
            a[:1:-1][begin:end:step],
            a[:87:1][begin:end:step],
            a[:-87:-1][begin:end:step],
            a[:-3:1][begin:end:step])
        """.format(begin=2, end=9, step=2)
        self.run_test(code, numpy.arange(90),
        step1slice_combination7=[NDArray[int, :]])

    def test_step1slice_combination8(self):
        """ Check for pos step/neg begin/no end combination. """
        code = """
def step1slice_combination8(a):
    begin = {begin}
    end = {end}
    step = {step}
    return (a[::][begin:end:step],
            a[::1][begin:end:step],
            a[87::-1][begin:end:step],
            a[1::1][begin:end:step],
            a[-3::-1][begin:end:step],
            a[-89::1][begin:end:step],
            a[88:1:-1][begin:end:step],
            a[1:88:1][begin:end:step],
            a[-2:1:-1][begin:end:step],
            a[-89:88:1][begin:end:step],
            a[88:-88:-1][begin:end:step],
            a[2:-1:1][begin:end:step],
            a[-1:-88:-1][begin:end:step],
            a[-88:-1:1][begin:end:step],
            a[:1:-1][begin:end:step],
            a[:87:1][begin:end:step],
            a[:-87:-1][begin:end:step],
            a[:-3:1][begin:end:step])
        """.format(begin=-10, end=None, step=2)
        self.run_test(code, numpy.arange(90),
        step1slice_combination8=[NDArray[int, :]])

    def test_step1slice_combination9(self):
        """ Check for neg step/no begin/pos end combination. """
        code = """
def step1slice_combination9(a):
    begin = {begin}
    end = {end}
    step = {step}
    return (a[::][begin:end:step],
            a[::1][begin:end:step],
            a[87::-1][begin:end:step],
            a[1::1][begin:end:step],
            a[-3::-1][begin:end:step],
            a[-89::1][begin:end:step],
            a[88:1:-1][begin:end:step],
            a[1:88:1][begin:end:step],
            a[-2:1:-1][begin:end:step],
            a[-89:88:1][begin:end:step],
            a[88:-88:-1][begin:end:step],
            a[2:-1:1][begin:end:step],
            a[-1:-88:-1][begin:end:step],
            a[-88:-1:1][begin:end:step],
            a[:1:-1][begin:end:step],
            a[:87:1][begin:end:step],
            a[:-87:-1][begin:end:step],
            a[:-3:1][begin:end:step])
        """.format(begin=None, end=2, step=-2)
        self.run_test(code, numpy.arange(90),
        step1slice_combination9=[NDArray[int, :]])

    def test_step1slice_combination10(self):
        """ Check for neg step/no begin/neg end combination. """
        code = """
def step1slice_combination10(a):
    begin = {begin}
    end = {end}
    step = {step}
    return (a[::][begin:end:step],
            a[::1][begin:end:step],
            a[87::-1][begin:end:step],
            a[1::1][begin:end:step],
            a[-3::-1][begin:end:step],
            a[-89::1][begin:end:step],
            a[88:1:-1][begin:end:step],
            a[1:88:1][begin:end:step],
            a[-2:1:-1][begin:end:step],
            a[-89:88:1][begin:end:step],
            a[88:-88:-1][begin:end:step],
            a[2:-1:1][begin:end:step],
            a[-1:-88:-1][begin:end:step],
            a[-88:-1:1][begin:end:step],
            a[:1:-1][begin:end:step],
            a[:87:1][begin:end:step],
            a[:-87:-1][begin:end:step],
            a[:-3:1][begin:end:step])
        """.format(begin=None, end=-10, step=-2)
        self.run_test(code, numpy.arange(90),
        step1slice_combination10=[NDArray[int, :]])

    def test_step1slice_combination11(self):
        """ Check for neg step/pos begin/neg end combination. """
        code = """
def step1slice_combination11(a):
    begin = {begin}
    end = {end}
    step = {step}
    return (a[::][begin:end:step],
            a[::1][begin:end:step],
            a[87::-1][begin:end:step],
            a[1::1][begin:end:step],
            a[-3::-1][begin:end:step],
            a[-89::1][begin:end:step],
            a[88:1:-1][begin:end:step],
            a[1:88:1][begin:end:step],
            a[-2:1:-1][begin:end:step],
            a[-89:88:1][begin:end:step],
            a[88:-88:-1][begin:end:step],
            a[2:-1:1][begin:end:step],
            a[-1:-88:-1][begin:end:step],
            a[-88:-1:1][begin:end:step],
            a[:1:-1][begin:end:step],
            a[:87:1][begin:end:step],
            a[:-87:-1][begin:end:step],
            a[:-3:1][begin:end:step])
        """.format(begin=85, end=-10, step=-2)
        self.run_test(code, numpy.arange(90),
        step1slice_combination11=[NDArray[int, :]])

    def test_step1slice_combination12(self):
        """ Check for neg step/pos begin/no end combination. """
        code = """
def step1slice_combination12(a):
    begin = {begin}
    end = {end}
    step = {step}
    return (a[::][begin:end:step],
            a[::1][begin:end:step],
            a[87::-1][begin:end:step],
            a[1::1][begin:end:step],
            a[-3::-1][begin:end:step],
            a[-89::1][begin:end:step],
            a[88:1:-1][begin:end:step],
            a[1:88:1][begin:end:step],
            a[-2:1:-1][begin:end:step],
            a[-89:88:1][begin:end:step],
            a[88:-88:-1][begin:end:step],
            a[2:-1:1][begin:end:step],
            a[-1:-88:-1][begin:end:step],
            a[-88:-1:1][begin:end:step],
            a[:1:-1][begin:end:step],
            a[:87:1][begin:end:step],
            a[:-87:-1][begin:end:step],
            a[:-3:1][begin:end:step])
        """.format(begin=85, end=None, step=-2)
        self.run_test(code, numpy.arange(90),
        step1slice_combination12=[NDArray[int, :]])

    def test_step1slice_combination13(self):
        """ Check for neg step/pos begin/pos end combination. """
        code = """
def step1slice_combination13(a):
    begin = {begin}
    end = {end}
    step = {step}
    return (a[::][begin:end:step],
            a[::1][begin:end:step],
            a[87::-1][begin:end:step],
            a[1::1][begin:end:step],
            a[-3::-1][begin:end:step],
            a[-89::1][begin:end:step],
            a[88:1:-1][begin:end:step],
            a[1:88:1][begin:end:step],
            a[-2:1:-1][begin:end:step],
            a[-89:88:1][begin:end:step],
            a[88:-88:-1][begin:end:step],
            a[2:-1:1][begin:end:step],
            a[-1:-88:-1][begin:end:step],
            a[-88:-1:1][begin:end:step],
            a[:1:-1][begin:end:step],
            a[:87:1][begin:end:step],
            a[:-87:-1][begin:end:step],
            a[:-3:1][begin:end:step])
        """.format(begin=85, end=3, step=-2)
        self.run_test(code, numpy.arange(90),
        step1slice_combination13=[NDArray[int, :]])

    def test_step1slice_combination14(self):
        """ Check for pos step/neg begin/no end combination. """
        code = """
def step1slice_combination14(a):
    begin = {begin}
    end = {end}
    step = {step}
    return (a[::][begin:end:step],
            a[::1][begin:end:step],
            a[87::-1][begin:end:step],
            a[1::1][begin:end:step],
            a[-3::-1][begin:end:step],
            a[-89::1][begin:end:step],
            a[88:1:-1][begin:end:step],
            a[1:88:1][begin:end:step],
            a[-2:1:-1][begin:end:step],
            a[-89:88:1][begin:end:step],
            a[88:-88:-1][begin:end:step],
            a[2:-1:1][begin:end:step],
            a[-1:-88:-1][begin:end:step],
            a[-88:-1:1][begin:end:step],
            a[:1:-1][begin:end:step],
            a[:87:1][begin:end:step],
            a[:-87:-1][begin:end:step],
            a[:-3:1][begin:end:step])
        """.format(begin=-3, end=None, step=-2)
        self.run_test(code, numpy.arange(90),
        step1slice_combination14=[NDArray[int, :]])

    def test_step1slice_combination15(self):
        """ Check for neg step/neg begin/pos end combination. """
        code = """
def step1slice_combination15(a):
    begin = {begin}
    end = {end}
    step = {step}
    return (a[::][begin:end:step],
            a[::1][begin:end:step],
            a[87::-1][begin:end:step],
            a[1::1][begin:end:step],
            a[-3::-1][begin:end:step],
            a[-89::1][begin:end:step],
            a[88:1:-1][begin:end:step],
            a[1:88:1][begin:end:step],
            a[-2:1:-1][begin:end:step],
            a[-89:88:1][begin:end:step],
            a[88:-88:-1][begin:end:step],
            a[2:-1:1][begin:end:step],
            a[-1:-88:-1][begin:end:step],
            a[-88:-1:1][begin:end:step],
            a[:1:-1][begin:end:step],
            a[:87:1][begin:end:step],
            a[:-87:-1][begin:end:step],
            a[:-3:1][begin:end:step])
        """.format(begin=-3, end=4, step=-2)
        self.run_test(code, numpy.arange(90),
        step1slice_combination15=[NDArray[int, :]])

    def test_step1slice_combination16(self):
        """ Check for neg step/neg begin/neg end combination. """
        code = """
def step1slice_combination16(a):
    begin = {begin}
    end = {end}
    step = {step}
    return (a[::][begin:end:step],
            a[::1][begin:end:step],
            a[87::-1][begin:end:step],
            a[1::1][begin:end:step],
            a[-3::-1][begin:end:step],
            a[-89::1][begin:end:step],
            a[88:1:-1][begin:end:step],
            a[1:88:1][begin:end:step],
            a[-2:1:-1][begin:end:step],
            a[-89:88:1][begin:end:step],
            a[88:-88:-1][begin:end:step],
            a[2:-1:1][begin:end:step],
            a[-1:-88:-1][begin:end:step],
            a[-88:-1:1][begin:end:step],
            a[:1:-1][begin:end:step],
            a[:87:1][begin:end:step],
            a[:-87:-1][begin:end:step],
            a[:-3:1][begin:end:step])
        """.format(begin=-3, end=-10, step=-2)
        self.run_test(code, numpy.arange(90),
        step1slice_combination16=[NDArray[int, :]])

    def test_step1slice_combination17(self):
        """ Check for pos step/pos begin/neg end combination. """
        code = """
def step1slice_combination17(a):
    begin = {begin}
    end = {end}
    step = {step}
    return (a[::][begin:end:step],
            a[::1][begin:end:step],
            a[87::-1][begin:end:step],
            a[1::1][begin:end:step],
            a[-3::-1][begin:end:step],
            a[-89::1][begin:end:step],
            a[88:1:-1][begin:end:step],
            a[1:88:1][begin:end:step],
            a[-2:1:-1][begin:end:step],
            a[-89:88:1][begin:end:step],
            a[88:-88:-1][begin:end:step],
            a[2:-1:1][begin:end:step],
            a[-1:-88:-1][begin:end:step],
            a[-88:-1:1][begin:end:step],
            a[:1:-1][begin:end:step],
            a[:87:1][begin:end:step],
            a[:-87:-1][begin:end:step],
            a[:-3:1][begin:end:step])
        """.format(begin=3, end=-10, step=2)
        self.run_test(code, numpy.arange(90),
        step1slice_combination17=[NDArray[int, :]])

    def test_step1slice_combination18(self):
        """ Check for pos step/pos begin/neg end combination. """
        code = """
def step1slice_combination18(a):
    begin = {begin}
    end = {end}
    step = {step}
    return (a[::][begin:end:step],
            a[::1][begin:end:step],
            a[87::-1][begin:end:step],
            a[1::1][begin:end:step],
            a[-3::-1][begin:end:step],
            a[-89::1][begin:end:step],
            a[88:1:-1][begin:end:step],
            a[1:88:1][begin:end:step],
            a[-2:1:-1][begin:end:step],
            a[-89:88:1][begin:end:step],
            a[88:-88:-1][begin:end:step],
            a[2:-1:1][begin:end:step],
            a[-1:-88:-1][begin:end:step],
            a[-88:-1:1][begin:end:step],
            a[:1:-1][begin:end:step],
            a[:87:1][begin:end:step],
            a[:-87:-1][begin:end:step],
            a[:-3:1][begin:end:step])
        """.format(begin=-80, end=80, step=2)
        self.run_test(code, numpy.arange(90),
        step1slice_combination18=[NDArray[int, :]])

    def test_step1slice_combination19(self):
        """ Check for pos step/neg begin/neg end combination. """
        code = """
def step1slice_combination19(a):
    begin = {begin}
    end = {end}
    step = {step}
    return (a[::][begin:end:step],
            a[::1][begin:end:step],
            a[87::-1][begin:end:step],
            a[1::1][begin:end:step],
            a[-3::-1][begin:end:step],
            a[-89::1][begin:end:step],
            a[88:1:-1][begin:end:step],
            a[1:88:1][begin:end:step],
            a[-2:1:-1][begin:end:step],
            a[-89:88:1][begin:end:step],
            a[88:-88:-1][begin:end:step],
            a[2:-1:1][begin:end:step],
            a[-1:-88:-1][begin:end:step],
            a[-88:-1:1][begin:end:step],
            a[:1:-1][begin:end:step],
            a[:87:1][begin:end:step],
            a[:-87:-1][begin:end:step],
            a[:-3:1][begin:end:step])
        """.format(begin=-80, end=-2, step=2)
        self.run_test(code, numpy.arange(90),
        step1slice_combination19=[NDArray[int, :]])


"""Forest covertype dataset.

A classic dataset for classification benchmarks, featuring categorical and
real-valued features.

The dataset page is available from UCI Machine Learning Repository

    https://archive.ics.uci.edu/ml/datasets/Covertype

Courtesy of Jock A. Blackard and Colorado State University.
"""

# Author: Lars Buitinck
#         Peter Prettenhofer <peter.prettenhofer@gmail.com>
# License: BSD 3 clause

from gzip import GzipFile
import logging
from os.path import dirname, exists, join
from os import remove, makedirs

import numpy as np
import joblib

from . import get_data_home
from ._base import _convert_data_dataframe
from ._base import _fetch_remote
from ._base import RemoteFileMetadata
from ..utils import Bunch
from ._base import _pkl_filepath
from ..utils import check_random_state

# The original data can be found in:
# https://archive.ics.uci.edu/ml/machine-learning-databases/covtype/covtype.data.gz
ARCHIVE = RemoteFileMetadata(
    filename="covtype.data.gz",
    url="https://ndownloader.figshare.com/files/5976039",
    checksum="614360d0257557dd1792834a85a1cdebfadc3c4f30b011d56afee7ffb5b15771",
)

logger = logging.getLogger(__name__)

# Column names reference:
# https://archive.ics.uci.edu/ml/machine-learning-databases/covtype/covtype.info
FEATURE_NAMES = [
    "Elevation",
    "Aspect",
    "Slope",
    "Horizontal_Distance_To_Hydrology",
    "Vertical_Distance_To_Hydrology",
    "Horizontal_Distance_To_Roadways",
    "Hillshade_9am",
    "Hillshade_Noon",
    "Hillshade_3pm",
    "Horizontal_Distance_To_Fire_Points",
]
FEATURE_NAMES += [f"Wilderness_Area_{i}" for i in range(4)]
FEATURE_NAMES += [f"Soil_Type_{i}" for i in range(40)]
TARGET_NAMES = ["Cover_Type"]

def fetch_covtype(
    *,
    data_home=None,
    download_if_missing=True,
    random_state=None,
    shuffle=False,
    return_X_y=False,
    as_frame=False,
):
    """Load the covertype dataset (classification).

    Download it if necessary.

    =================   ============
    Classes                        7
    Samples total             581012
    Dimensionality                54
    Features                     int
    =================   ============

    Read more in the :ref:`User Guide <covtype_dataset>`.

    Parameters
    ----------
    data_home : str, default=None
        Specify another download and cache folder for the datasets. By default
        all scikit-learn data is stored in '~/scikit_learn_data' subfolders.

    download_if_missing : bool, default=True
        If False, raise a IOError if the data is not locally available
        instead of trying to download the data from the source site.

    random_state : int, RandomState instance or None, default=None
        Determines random number generation for dataset shuffling. Pass an int
        for reproducible output across multiple function calls.
        See :term:`Glossary <random_state>`.

    shuffle : bool, default=False
        Whether to shuffle dataset.

    return_X_y : bool, default=False
        If True, returns ``(data.data, data.target)`` instead of a Bunch
        object.

        .. versionadded:: 0.20

    as_frame : bool, default=False
        If True, the data is a pandas DataFrame including columns with
        appropriate dtypes (numeric). The target is a pandas DataFrame or
        Series depending on the number of target columns. If `return_X_y` is
        True, then (`data`, `target`) will be pandas DataFrames or Series as
        described below.

        .. versionadded:: 0.24

    Returns
    -------
    dataset : :class:`~sklearn.utils.Bunch`
        Dictionary-like object, with the following attributes.

        data : ndarray of shape (581012, 54)
            Each row corresponds to the 54 features in the dataset.
        target : ndarray of shape (581012,)
            Each value corresponds to one of
            the 7 forest covertypes with values
            ranging between 1 to 7.
        frame : dataframe of shape (581012, 55)
            Only present when `as_frame=True`. Contains `data` and `target`.
        DESCR : str
            Description of the forest covertype dataset.
        feature_names : list
            The names of the dataset columns.
        target_names: list
            The names of the target columns.

    (data, target) : tuple if ``return_X_y`` is True

        .. versionadded:: 0.20

    """

    data_home = get_data_home(data_home=data_home)
    covtype_dir = join(data_home, "covertype")
    samples_path = _pkl_filepath(covtype_dir, "samples")
    targets_path = _pkl_filepath(covtype_dir, "targets")
    available = exists(samples_path)

    if download_if_missing and not available:
        if not exists(covtype_dir):
            makedirs(covtype_dir)
        logger.info("Downloading %s" % ARCHIVE.url)

        archive_path = _fetch_remote(ARCHIVE, dirname=covtype_dir)
        Xy = np.genfromtxt(GzipFile(filename=archive_path), delimiter=",")
        # delete archive
        remove(archive_path)

        X = Xy[:, :-1]
        y = Xy[:, -1].astype(np.int32, copy=False)

        joblib.dump(X, samples_path, compress=9)
        joblib.dump(y, targets_path, compress=9)

    elif not available and not download_if_missing:
        raise IOError("Data not found and `download_if_missing` is False")
    try:
        X, y
    except NameError:
        X = joblib.load(samples_path)
        y = joblib.load(targets_path)

    if shuffle:
        ind = np.arange(X.shape[0])
        rng = check_random_state(random_state)
        rng.shuffle(ind)
        X = X[ind]
        y = y[ind]

    module_path = dirname(__file__)
    with open(join(module_path, "descr", "covtype.rst")) as rst_file:
        fdescr = rst_file.read()

    frame = None
    if as_frame:
        frame, X, y = _convert_data_dataframe(
            caller_name="fetch_covtype",
            data=X,
            target=y,
            feature_names=FEATURE_NAMES,
            target_names=TARGET_NAMES,
        )
    if return_X_y:
        return X, y

    return Bunch(
        data=X,
        target=y,
        frame=frame,
        target_names=TARGET_NAMES,
        feature_names=FEATURE_NAMES,
        DESCR=fdescr,
    )


import numpy as np
import cv2
import matplotlib.pyplot as plt

"""
在过滤(filtering)图片时, Border 类型对于保持图片大小起决定作用. 因为 filters 会扩展图片的
边界(edge).
"""

img = cv2.imread('images/leaves.png')
red = [0, 0, 255]  # boarder color

# Border 类型
# cv2.BORDER_REPLICATE - Last element is replicated throughout for the total
# width specified, for example:  11111|1234567|777777 直接用边界的颜色填充
#
# cv2.BORDER_REFLECT - Border will be mirror reflection of the elements near
# the edges, for example : 54321|1234567|76543 倒映
#
# cv2.BORDER_REFLECT_101 or cv2.BORDER_DEFAULT - Similar to cv2.BORDER_REFLECT
# but, the value at the edge is not refelcted, for example: 65432|1234567|65432
# 倒映，和上面类似，但在倒映时，会把边界空开
#
# cv2.BORDER_WRAP - Pulls the border from the opposite edge. It will look like
# this : 34567|1234567|12345 上下, 左右重复.
#
# cv2.BORDER_CONSTANT - Adds a constant colored border. The value in RGB or BGR
# should be given as next argument. In this case Red [255, 0,0] 常量，增加的变量通
# 通为value色

border_w = [75, 75, 75, 75]
replicate = cv2.copyMakeBorder(img, *border_w, cv2.BORDER_REPLICATE)
reflect = cv2.copyMakeBorder(img, *border_w, cv2.BORDER_REFLECT)
reflect_101 = cv2.copyMakeBorder(img, *border_w, cv2.BORDER_REFLECT_101)
wrap = cv2.copyMakeBorder(img, *border_w, cv2.BORDER_WRAP)
constant = cv2.copyMakeBorder(img, *border_w, cv2.BORDER_CONSTANT, value=red)

img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
replicate_rgb = cv2.cvtColor(replicate, cv2.COLOR_BGR2RGB)
reflect_rgb = cv2.cvtColor(reflect, cv2.COLOR_BGR2RGB)
reflect_101_rgb = cv2.cvtColor(reflect_101, cv2.COLOR_BGR2RGB)
wrap_rgb = cv2.cvtColor(wrap, cv2.COLOR_BGR2RGB)
constant_rgb = cv2.cvtColor(constant, cv2.COLOR_BGR2RGB)

plt.subplot(231), plt.imshow(img_rgb), plt.title('Original')
plt.xticks([]), plt.yticks([])

plt.subplot(232), plt.imshow(replicate_rgb), plt.title('REPLICATE')
plt.xticks([]), plt.yticks([])

plt.subplot(233), plt.imshow(reflect_rgb), plt.title('REFLECT')
plt.xticks([]), plt.yticks([])

plt.subplot(234), plt.imshow(reflect_101_rgb), plt.title('REFLECT_101')
plt.xticks([]), plt.yticks([])

plt.subplot(235), plt.imshow(wrap_rgb), plt.title('WRAP')
plt.xticks([]), plt.yticks([])

plt.subplot(236), plt.imshow(constant_rgb), plt.title('CONSTANT')
plt.xticks([]), plt.yticks([])

plt.show()

# 结论: 通常采用 reflection 作为 boarder
# TODO: 通过数据说明为何 reflection 最好


"""
Copyright MIT and Harvey Mudd College
MIT License
Summer 2020

Lab 2A - Color Image Line Following
"""

########################################################################################
# Imports
########################################################################################

import sys
import cv2 as cv
import numpy as np

sys.path.insert(1, "../../library")
import racecar_core
import racecar_utils as rc_utils

########################################################################################
# Global variables
########################################################################################

rc = racecar_core.create_racecar()

# >> Constants
# The smallest contour we will recognize as a valid contour
MIN_CONTOUR_AREA = 30

# A crop window for the floor directly in front of the car
CROP_FLOOR = ((360, 0), (rc.camera.get_height(), rc.camera.get_width()))

# Colors, stored as a pair (hsv_min, hsv_max)
BLUE = ((90, 50, 50), (100, 255, 255))  # The HSV range for the color blue
GREEN = ((35,50,50),(70,255,255))
RED = ((0,50,50),(10,255,255))
# TODO (challenge 1): add HSV ranges for other colors DONE

# >> Variables
speed = 0.0  # The current speed of the car
angle = 0.0  # The current angle of the car's wheels
contour_center = None  # The (pixel row, pixel column) of contour
contour_area = 0  # The area of contour
color_priority = (BLUE,RED,GREEN)

########################################################################################
# Functions
########################################################################################

def update_contour():
    """
    Finds contours in the current color image and uses them to update contour_center
    and contour_area
    """
    global contour_center
    global contour_area

    image = rc.camera.get_color_image()

    if image is None:
        contour_center = None
        contour_area = 0
    else:
        # TODO (challenge 1): Search for multiple tape colors with a priority order DONE
        # (currently we only search for blue)

        # Crop the image to the floor directly in front of the car
        image = rc_utils.crop(image, CROP_FLOOR[0], CROP_FLOOR[1])

        # Find all of the colored contours
        for color in color_priority:
            contours = rc_utils.find_contours(image, color[0], color[1])
            if len(contours) > 0:
                break

        # Select the largest contour
        contour = rc_utils.get_largest_contour(contours, MIN_CONTOUR_AREA)

        if contour is not None:
            # Calculate contour information
            contour_center = rc_utils.get_contour_center(contour)
            contour_area = rc_utils.get_contour_area(contour)

            # Draw contour onto the image
            rc_utils.draw_contour(image, contour)
            rc_utils.draw_circle(image, contour_center)

        else:
            contour_center = None
            contour_area = 0

        # Display the image to the screen
        rc.display.show_color_image(image)

def start():
    """
    This function is run once every time the start button is pressed
    """
    global speed
    global angle

    # Initialize variables
    speed = 0
    angle = 0

    # Set initial driving speed and angle
    rc.drive.set_speed_angle(speed, angle)

    # Set update_slow to refresh every half second
    rc.set_update_slow_time(0.5)

    # Print start message
    print(
        ">> Lab 2A - Color Image Line Following\n"
        "\n"
        "Controls:\n"
        "   Right trigger = accelerate forward\n"
        "   Left trigger = accelerate backward\n"
        "   A button = print current speed and angle\n"
        "   B button = print contour center and area"
    )

def update():
    """
    After start() is run, this function is run every frame until the back button
    is pressed
    """
    global speed
    global angle

    # Search for contours in the current color image
    update_contour()

    # Choose an angle based on contour_center
    # If we could not find a contour, keep the previous angle
    if contour_center is not None:
        # Current implementation: bang-bang control (very choppy)
        # TODO (warmup): Implement a smoother way to follow the line
        errorTerm = contour_center[1]-320
        angle = errorTerm/320
        #dimensionsa re 480x640
    # Use the triggers to control the car's speed
    forwardSpeed = rc.controller.get_trigger(rc.controller.Trigger.RIGHT)
    backSpeed = rc.controller.get_trigger(rc.controller.Trigger.LEFT)
    speed = forwardSpeed - backSpeed

    rc.drive.set_speed_angle(speed, angle)

    # Print the current speed and angle when the A button is held down
    if rc.controller.is_down(rc.controller.Button.A):
        print("Speed:", speed, "Angle:", angle)

    # Print the center and area of the largest contour when B is held down
    if rc.controller.is_down(rc.controller.Button.B):
        if contour_center is None:
            print("No contour found")
        else:
            print("Center:", contour_center, "Area:", contour_area)

def update_slow():
    """
    After start() is run, this function is run at a constant rate that is slower
    than update().  By default, update_slow() is run once per second
    """
    # Print a line of ascii text denoting the contour area and x-position
    if rc.camera.get_color_image() is None:
        # If no image is found, print all X's and don't display an image
        print("X" * 10 + " (No image) " + "X" * 10)
    else:
        # If an image is found but no contour is found, print all dashes
        if contour_center is None:
            print("-" * 32 + " : area = " + str(contour_area))

        # Otherwise, print a line of dashes with a | indicating the contour x-position
        else:
            s = ["-"] * 32
            s[int(contour_center[1] / 20)] = "|"
            print("".join(s) + " : area = " + str(contour_area))

########################################################################################
# DO NOT MODIFY: Register start and update and begin execution
########################################################################################

if __name__ == "__main__":
    rc.set_start_update(start, update, update_slow)
    rc.go()


import pandas as pd
import numpy as np
import unittest

class Mytest(unittest.TestCase):
    '''
    If a dataframe is empty ,it checks and returns empty
    note: Nan is not considered as empty
    '''
    def setUp(self):
        self.df_empty = pd.DataFrame({'A': []})
        self.df=pd.DataFrame({'H' : [np.nan]})

    def test_Empty(self):
        self.assertEqual((self.df_empty).empty,(True))
        self.assertEqual((self.df).empty, (False))
        self.assertEqual(pd.Series([]).empty,(True))

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


"""
This module tests the functions implemented in sunpy.util.util.
"""

from __future__ import absolute_import, division, print_function
import numpy as np

import pytest
from pytest_mock import mocker

from sunpy.util import util

def test_to_signed():
    """
    This should return a signed type that can hold uint32 and ensure that
    an exception is raised when attempting to convert an unsigned 64 bit integer
    to an integer
    """
    assert util.to_signed(np.dtype('uint32')) == np.dtype('int64')

    with pytest.raises(ValueError):
        util.to_signed(np.dtype('uint64')) == np.dtype('int64')

def test_unique():
    """
    This should add the unique values of itr to unique_list.
    """
    itr = [6, 1, 2, 1, 7, 41.2, '41.2', 1, '41.2']
    unique_list = []
    for elem in util.unique(itr):
        unique_list.append(elem)
    assert unique_list == [6, 1, 2, 7, 41.2, '41.2']

def test_unique_key():
    """
    This should add each element of itr to unique_list if no preceding
    element is congruent to it in mod 10.
    """
    itr = [7, 3, 17, 104, 6, 1006, 117, 14, 10]
    unique_list = []
    for elem in util.unique(itr, lambda x: x % 10):
        unique_list.append(elem)
    assert unique_list == [7, 3, 104, 6, 10]

def test_print_table():
    """
    This should return a string representation of lst with table elements
    left-justified and with columns separated by dashes.
    """
    lst = [['n', 'sqrt(n)', 'n^2'],
           ['1', '1', '1'],
           ['4', '2', '16'],
           ['3', '1.732', '9']]
    expected = ('n|sqrt(n)|n^2\n'
                '1|1      |1  \n'
                '4|2      |16 \n'
                '3|1.732  |9  ')
    assert util.print_table(lst, colsep='|') == expected

def test_minimal_pairs():
    """
    This should return the pairs of elements from list1 and list2 with
    minimal difference between their values.
    """
    list1 = [0, 5, 10, 15, 20, 25]
    list2 = [3, 12, 19, 21, 26, 29]
    assert list(util.minimal_pairs(list1, list2)) == [(1, 0, 2), (2, 1, 2),
                                                      (4, 2, 1), (5, 4, 1)]

def test_find_next():
    """
    This should return a generator yielding the nearest larger element in
    list2 for each element in list1 (or None if none exists after the
    previous element yielded from list2).
    """
    list1 = [1, 2, 3, 4, 5, 6, 7, 8, 9]
    list2 = [0, 2, 3, 5, 0, 0, 5, 9, 10, 15]
    assert list(util.find_next(list1, list2, None)) == [(1, 2), (2, 3), (3, 5), (4, 5), (5, 9),
                                                        (6, 10), (7, 15), (8, None), (9, None)]

def test_common_base():
    """
    This should return the base class common to each object in objs.
    """
    class TestA(object):
        """Base test class."""
        pass

    class TestB(TestA):
        """First inherited class."""
        pass

    class TestC(TestA):
        """Second inherited class."""
        pass
    inst_b = TestB()
    inst_c = TestC()
    objs = [inst_b, inst_c]
    assert util.common_base(objs) == TestA

def test_merge():
    """
    This should return a sorted (from greatest to least) merged list
    from list1 and list2.
    """
    list1 = [13, 11, 9, 7, 5, 3, 1]
    list2 = [14, 12, 10, 8, 6, 4, 2]
    result = list(util.merge([list1, list2]))
    assert result[::-1] == sorted(result)

    assert list(util.merge([[], [1], []])) == [1]

def test_replacement_filename():
    """
    This should return a replacement path for the current file.
    """
    assert util.replacement_filename(__file__).endswith('test_util.0.py')

def test_replacement_filename_path_not_exists(mocker):
    """
    If a candidate path does not exist, then just return it as it is OK to use
    """
    path_not_exists = '/tmp'
    mocker.patch('os.path.exists', return_value=False)

    assert util.replacement_filename(path_not_exists) == path_not_exists

def test_expand_list():
    """
    This should return an expanded version of list lst.
    """
    lst = [1, 2, 3, [4, 5, 6], 7, (8, 9), ((10, 11), ((12, 13),))]
    assert util.expand_list(lst) == [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]

def test_expand_list_generator():

    lst = ['a', 'b', [], (['c', 'd']), tuple(), ['e']]
    assert list(util.expand_list_generator(lst)) == ['a', 'b', 'c', 'd', 'e']


# Copyright 2016 The TensorFlow Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
"""A dataset loader for imports85.data."""

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import collections

import numpy as np
import tensorflow as tf

try:
  import pandas as pd  # pylint: disable=g-import-not-at-top
except ImportError:
  pass

URL = "https://archive.ics.uci.edu/ml/machine-learning-databases/autos/imports-85.data"

# Order is important for the csv-readers, so we use an OrderedDict here.
defaults = collections.OrderedDict([
    ("symboling", [0]),
    ("normalized-losses", [0.0]),
    ("make", [""]),
    ("fuel-type", [""]),
    ("aspiration", [""]),
    ("num-of-doors", [""]),
    ("body-style", [""]),
    ("drive-wheels", [""]),
    ("engine-location", [""]),
    ("wheel-base", [0.0]),
    ("length", [0.0]),
    ("width", [0.0]),
    ("height", [0.0]),
    ("curb-weight", [0.0]),
    ("engine-type", [""]),
    ("num-of-cylinders", [""]),
    ("engine-size", [0.0]),
    ("fuel-system", [""]),
    ("bore", [0.0]),
    ("stroke", [0.0]),
    ("compression-ratio", [0.0]),
    ("horsepower", [0.0]),
    ("peak-rpm", [0.0]),
    ("city-mpg", [0.0]),
    ("highway-mpg", [0.0]),
    ("price", [0.0])
])  # pyformat: disable

types = collections.OrderedDict((key, type(value[0]))
                                for key, value in defaults.items())

def _get_imports85():
  path = tf.contrib.keras.utils.get_file(URL.split("/")[-1], URL)
  return path

def dataset(y_name="price", train_fraction=0.7):
  """Load the imports85 data as a (train,test) pair of `Dataset`.

  Each dataset generates (features_dict, label) pairs.

  Args:
    y_name: The name of the column to use as the label.
    train_fraction: A float, the fraction of data to use for training. The
        remainder will be used for evaluation.
  Returns:
    A (train,test) pair of `Datasets`
  """
  # Download and cache the data
  path = _get_imports85()

  # Define how the lines of the file should be parsed
  def decode_line(line):
    """Convert a csv line into a (features_dict,label) pair."""
    # Decode the line to a tuple of items based on the types of
    # csv_header.values().
    items = tf.decode_csv(line, list(defaults.values()))

    # Convert the keys and items to a dict.
    pairs = zip(defaults.keys(), items)
    features_dict = dict(pairs)

    # Remove the label from the features_dict
    label = features_dict.pop(y_name)

    return features_dict, label

  def has_no_question_marks(line):
    """Returns True if the line of text has no question marks."""
    # split the line into an array of characters
    chars = tf.string_split(line[tf.newaxis], "").values
    # for each character check if it is a question mark
    is_question = tf.equal(chars, "?")
    any_question = tf.reduce_any(is_question)
    no_question = ~any_question

    return no_question

  def in_training_set(line):
    """Returns a boolean tensor, true if the line is in the training set."""
    # If you randomly split the dataset you won't get the same split in both
    # sessions if you stop and restart training later. Also a simple
    # random split won't work with a dataset that's too big to `.cache()` as
    # we are doing here.
    num_buckets = 1000000
    bucket_id = tf.string_to_hash_bucket_fast(line, num_buckets)
    # Use the hash bucket id as a random number that's deterministic per example
    return bucket_id < int(train_fraction * num_buckets)

  def in_test_set(line):
    """Returns a boolean tensor, true if the line is in the training set."""
    # Items not in the training set are in the test set.
    # This line must use `~` instead of `not` because `not` only works on python
    # booleans but we are dealing with symbolic tensors.
    return ~in_training_set(line)

  base_dataset = (
      tf.data
      # Get the lines from the file.
      .TextLineDataset(path)
      # drop lines with question marks.
      .filter(has_no_question_marks))

  train = (base_dataset
           # Take only the training-set lines.
           .filter(in_training_set)
           # Decode each line into a (features_dict, label) pair.
           .map(decode_line)
           # Cache data so you only decode the file once.
           .cache())

  # Do the same for the test-set.
  test = (base_dataset.filter(in_test_set).cache().map(decode_line))

  return train, test

def raw_dataframe():
  """Load the imports85 data as a pd.DataFrame."""
  # Download and cache the data
  path = _get_imports85()

  # Load it into a pandas dataframe
  df = pd.read_csv(path, names=types.keys(), dtype=types, na_values="?")

  return df

def load_data(y_name="price", train_fraction=0.7, seed=None):
  """Get the imports85 data set.

  A description of the data is available at:
    https://archive.ics.uci.edu/ml/datasets/automobile

  The data itself can be found at:
    https://archive.ics.uci.edu/ml/machine-learning-databases/autos/imports-85.data

  Args:
    y_name: the column to return as the label.
    train_fraction: the fraction of the dataset to use for training.
    seed: The random seed to use when shuffling the data. `None` generates a
      unique shuffle every run.
  Returns:
    a pair of pairs where the first pair is the training data, and the second
    is the test data:
    `(x_train, y_train), (x_test, y_test) = get_imports85_dataset(...)`
    `x` contains a pandas DataFrame of features, while `y` contains the label
    array.
  """
  # Load the raw data columns.
  data = raw_dataframe()

  # Delete rows with unknowns
  data = data.dropna()

  # Shuffle the data
  np.random.seed(seed)

  # Split the data into train/test subsets.
  x_train = data.sample(frac=train_fraction, random_state=seed)
  x_test = data.drop(x_train.index)

  # Extract the label from the features dataframe.
  y_train = x_train.pop(y_name)
  y_test = x_test.pop(y_name)

  return (x_train, y_train), (x_test, y_test)


# ---
# jupyter:
#   jupytext:
#     formats: ipynb,py
#     text_representation:
#       extension: .py
#       format_name: light
#       format_version: '1.5'
#       jupytext_version: 1.9.1+dev
#   kernelspec:
#     display_name: Python [conda env:generic_expression] *
#     language: python
#     name: conda-env-generic_expression-py
# ---

# # Examine simulation approach
#
# **Question:** Can we separate between generic and specific genes by adding gaussian noise to simulate experiments? Does VAE approach recapitulate generic genes better than gaussian noise approach?
#
# To answer this question we will compare how well SOPHIE (VAE approach) can recapitulate manually curated generic genes (Crow et al.) compared to generic genes generated using noise approach
#
# In this notebook we will:
# 1. Generate the noise simulated experiments
# 2. Compare generic genes against Crow et al. generic genes
# 3. Compare SOPHIE vs Crow et al. results against noise vs Crow et al. results. The results for SOPHIE vs Crow et al. can be found [here](http://localhost:8888/notebooks/human_general_analysis/2_identify_generic_genes_pathways.ipynb).

# +
# %load_ext autoreload
# %load_ext rpy2.ipython
# %autoreload 2

import os
import sys
import pandas as pd
import numpy as np
import pickle
import scipy.stats as ss
import seaborn as sns
import matplotlib.pyplot as plt
from rpy2.robjects import pandas2ri
from ponyo import utils
from generic_expression_patterns_modules import process, stats, ranking

pandas2ri.activate()

np.random.seed(123)

# +
# Read in config variables
base_dir = os.path.abspath(os.path.join(os.getcwd(), "../"))

config_filename = os.path.abspath(
    os.path.join(base_dir, "configs", "config_human_general.tsv")
)

params = utils.read_config(config_filename)

# +
# Load params
local_dir = params["local_dir"]
project_id = params["project_id"]
dataset_name = params["dataset_name"]
mapped_template_filename = params["mapped_template_filename"]
processed_template_filename = params["processed_template_filename"]
num_runs = params["num_simulated"]
col_to_rank_genes = params["rank_genes_by"]
count_threshold = params["count_threshold"]
logFC_name = params["DE_logFC_name"]
pvalue_name = params["DE_pvalue_name"]

# Set mean and standard deviation for noise distribution
# Here I played around with different sigma values
mu = 0
sigma = 1000

# Load metadata file with grouping assignments for samples
sample_id_metadata_filename = os.path.join(
    base_dir, dataset_name, "data", "metadata", f"{project_id}_process_samples.tsv"
)

# Load metadata file with grouping assignments for samples
metadata_filename = os.path.join(
    base_dir, dataset_name, "data", "metadata", f"{project_id}_groups.tsv"
)

# Percentile threshold to identify generic genes
percentile_threshold = 80.0
# -

# Output files
gene_summary_filename = os.path.join(
    base_dir, dataset_name, f"generic_gene_summary_{project_id}_noise_model.tsv"
)

# ## Simulate data using noise approach
#
# 1. Start with template experiment
# 2. Add gaussian noise vector to each sample
# 3. Process simulated data to remove any unnecessary samples

# Create subdirectory: "<local_dir>/pseudo_experiment_noise/"
os.makedirs(os.path.join(local_dir, "pseudo_experiment_noise"), exist_ok=True)

mapped_template = pd.read_csv(mapped_template_filename, sep="\t", index_col=0, header=0)

# Simulate data by adding noise
for i in range(num_runs):
    simulated_data_filename = os.path.join(
        local_dir,
        "pseudo_experiment_noise",
        f"selected_simulated_data_{project_id}_{i}.txt",
    )

    noise = np.random.normal(mu, sigma, mapped_template.shape)

    simulated_data = mapped_template + noise

    # Set any negative counts to 0
    simulated_data[simulated_data < 0] = 0

    simulated_data.to_csv(simulated_data_filename, sep="\t")

# ### Examine distribution of template data
#
# We want to play around with the amount of noise that we add and so it would be a good idea to know what the distribution looks like for the original data

print(mapped_template.mean().mean())
sns.displot(mapped_template.mean())
plt.title("Mean gene expression for template experiment")

print(mapped_template.std().mean())
sns.displot(mapped_template.std())
plt.title("Std gene expression for template experiment")

# ## Quick check
#
# Check that we are producing distinct simulated experiments (i.e. that we are not getting the same values for each simulated experiment)
#
# Here I randomly selected two different simulated experiments. File names for the simulated experiments have the following format `selected_simulated_data_{project_id}_<unique identifier>_processed.txt`. I selected two simulated experiments by their integer identifier.

mapped_template.head()

# +
simulated_data_filename_0 = os.path.join(
    local_dir,
    "pseudo_experiment_noise",
    f"selected_simulated_data_{project_id}_0_processed.txt",
)

simulated_0 = pd.read_csv(simulated_data_filename_0, sep="\t", index_col=0, header=0)

simulated_0.head()

# +
simulated_data_filename_20 = os.path.join(
    local_dir,
    "pseudo_experiment_noise",
    f"selected_simulated_data_{project_id}_20_processed.txt",
)

simulated_20 = pd.read_csv(simulated_data_filename_20, sep="\t", index_col=0, header=0)

simulated_20.head()
# -

# ## Process template and simulated experiments
#
# * Remove samples not required for comparison
# * Make sure ordering of samples matches metadata for proper comparison
# * Make sure values are cast as integers for using DESeq
# * Filter lowly expressed genes for using DESeq

# +
if not os.path.exists(sample_id_metadata_filename):
    sample_id_metadata_filename = None

stats.process_samples_for_DESeq(
    mapped_template_filename,
    metadata_filename,
    processed_template_filename,
    count_threshold,
    sample_id_metadata_filename,
)

for i in range(num_runs):
    simulated_filename = os.path.join(
        local_dir,
        "pseudo_experiment_noise",
        f"selected_simulated_data_{project_id}_{i}.txt",
    )
    out_simulated_filename = os.path.join(
        local_dir,
        "pseudo_experiment_noise",
        f"selected_simulated_data_{project_id}_{i}_processed.txt",
    )
    stats.process_samples_for_DESeq(
        simulated_filename,
        metadata_filename,
        out_simulated_filename,
        count_threshold,
        sample_id_metadata_filename,
    )
# -

# ## Differential expression analysis
#
# The gene expression dataset is using RNA-seq so we will use DESeq2 in this case

# Create subdirectory: "<local_dir>/DE_stats/"
os.makedirs(os.path.join(local_dir, "DE_stats"), exist_ok=True)

# + magic_args="-i metadata_filename -i project_id -i processed_template_filename -i local_dir -i base_dir" language="R"
#
# source(paste0(base_dir, '/generic_expression_patterns_modules/DE_analysis.R'))
#
# # File created: "<local_dir>/DE_stats/DE_stats_template_data_<project_id>_real.txt"
# get_DE_stats_DESeq(metadata_filename,
#                    project_id,
#                    processed_template_filename,
#                    "template",
#                    local_dir,
#                    "real")

# +
# Check number of DEGs
template_DE_stats_filename = os.path.join(
    local_dir, "DE_stats", f"DE_stats_template_data_{project_id}_real.txt"
)

template_DE_stats = pd.read_csv(
    template_DE_stats_filename, sep="\t", header=0, index_col=0
)

selected = template_DE_stats[
    (template_DE_stats["padj"] < 0.01) & (abs(template_DE_stats["log2FoldChange"]) > 1)
]
print(selected.shape)

# + magic_args="-i metadata_filename -i project_id -i base_dir -i local_dir -i num_runs" language="R"
#
# source(paste0(base_dir, '/generic_expression_patterns_modules/DE_analysis.R'))
#
# # Files created: "<local_dir>/DE_stats/DE_stats_simulated_data_SRP012656_<n>.txt"
# for (i in 0:(num_runs-1)){
#     simulated_data_filename <- paste(local_dir,
#                                      "pseudo_experiment_noise/selected_simulated_data_",
#                                      project_id,
#                                      "_",
#                                      i,
#                                      "_processed.txt",
#                                      sep = "")
#
#     get_DE_stats_DESeq(metadata_filename,
#                        project_id,
#                        simulated_data_filename,
#                        "simulated",
#                        local_dir,
#                        i)
# }
# -

# ## Rank genes

analysis_type = "DE"
template_DE_stats, simulated_DE_summary_stats = ranking.process_and_rank_genes_pathways(
    template_DE_stats_filename,
    local_dir,
    num_runs,
    project_id,
    analysis_type,
    col_to_rank_genes,
    logFC_name,
    pvalue_name,
)

# ## Gene summary table
#
# Note: Using DESeq, genes with NaN in `Adj P-value (Real)` column are those genes flagged because of the `cooksCutoff` parameter. The cook's distance as a diagnostic to tell if a single sample has a count which has a disproportionate impact on the log fold change and p-values. These genes are flagged with an NA in the pvalue and padj columns of the result table. For more information you can read [DESeq FAQs](https://bioconductor.org/packages/release/bioc/vignettes/DESeq2/inst/doc/DESeq2.html#pvaluesNA)

# +
summary_gene_ranks = ranking.generate_summary_table(
    template_DE_stats_filename,
    template_DE_stats,
    simulated_DE_summary_stats,
    col_to_rank_genes,
    local_dir,
    "gene",
    params,
)

summary_gene_ranks.head()
# -

summary_gene_ranks.isna().any()

# Create `gene_summary_filename`
summary_gene_ranks.to_csv(gene_summary_filename, sep="\t")

# ## Compare gene ranking
# Studies have found that some genes are more likely to be differentially expressed even across a wide range of experimental designs. These *generic genes* are not necessarily specific to the biological process being studied but instead represent a more systematic change.
#
# We want to compare the ability to detect these generic genes using our method vs those found by [Crow et. al. publication](https://www.pnas.org/content/pnas/116/13/6491.full.pdf). Their genes are ranked 0 = not commonly DE; 1 = commonly DE. Genes by the number differentially expressed gene sets they appear in and then ranking genes by this score.

# +
# Get generic genes identified by Crow et. al.
DE_prior_filename = params["reference_gene_filename"]
ref_gene_col = params["reference_gene_name_col"]
ref_rank_col = params["reference_rank_col"]

figure_filename = f"gene_ranking_{col_to_rank_genes}.svg"

corr, shared_ranking = ranking.compare_gene_ranking(
    summary_gene_ranks, DE_prior_filename, ref_gene_col, ref_rank_col, figure_filename
)

# +
# Hypergeometric test:
# Given N number of genes with K common genes in Crow et al.
# SOPHIE identifies n genes as being common
# What is the probability that k of the genes identified by SOPHIE
# are also common in Crow et al.? What is the probability of drawing
# k or more concordant genes?

num_Crow_genes = shared_ranking.shape[0]
num_generic_Crow_genes = shared_ranking.query(f"{ref_rank_col}>=80.0").shape[0]
num_generic_noise_genes = shared_ranking[
    shared_ranking["Percentile (simulated)"] >= percentile_threshold
].shape[0]
num_concordant_generic_genes = shared_ranking[
    (shared_ranking[ref_rank_col] >= percentile_threshold)
    & (shared_ranking["Percentile (simulated)"] >= percentile_threshold)
].shape[0]
# -

print(num_Crow_genes)
print(num_generic_Crow_genes)
print(num_generic_noise_genes)
print(num_concordant_generic_genes)

p = ss.hypergeom.sf(
    num_concordant_generic_genes,
    num_Crow_genes,
    num_generic_Crow_genes,
    num_generic_noise_genes,
)
print(p)

# **Takeaway**
# * Looks like noise and VAE can both recapitulate generic genes, which is expected.
# * Looks like template experiment already expresses generic genes (refer to other [notebook](comparisons_against_template.ipynb), so adding a small amount of noise (Normal(0,2)) will still find these generic results. This is expected, given that generic genes are "generic" because they are found across many experiments.
# * The reason that we think that generic genes are found by both the VAE approach and this noise approach is because they are "generic". So these generic signals are already found to exist across many experiments and by adding noise to the experiments we are disrupting that signal a bit but its still there.
#
# The benefit to using a VAE, presumably, is that the VAE will allow us to identify those specific genes by generating different types of experiments, where as the noise approach is limited to generating the same experiment but with different amounts of noise added.
#
# So, what we really want to determine is if SOPHIE can better **separate** between generic and specific genes. To do this, we would need a gold standard for what are specific genes for some experiment, which we do not have. So for now we will leave the experiment as is.


"""

    Copyright (c) 2014-2015-2015, The University of Texas at Austin.
    All rights reserved.

    This file is part of BLASpy and is available under the 3-Clause
    BSD License, which can be found in the LICENSE file at the top-level
    directory or at http://opensource.org/licenses/BSD-3-Clause

"""

from ..helpers import random_vector
from blaspy import swap
from numpy import allclose, copy
from itertools import product
from random import randint, uniform

N_MIN, N_MAX = 2, 1e3           # matrix/vector sizes
STRIDE_MAX = 1e2                # max vector stride

def acceptance_test_swap():
    """
    Test vector swap.

    Returns:
        A list of strings representing the failed tests.
    """

    tests_failed = []

    # values to test
    dtypes = ('float64', 'float32')
    bools = (True, False)
    strides = (1, None)  # None indicates random stride

    # test all combinations of all possible values
    for (dtype, as_matrix, x_is_row, y_is_row, stride) in product(dtypes, bools, bools, bools,
                                                                  strides):

        # if a test fails, create a string representation of its name and append it to the list
        # of failed tests
        if not passed_test(dtype, as_matrix, x_is_row, y_is_row, stride):
            variables = (dtype,
                         "_matrix" if as_matrix else "_ndarray",
                         "_row" if x_is_row else "_col",
                         "_row" if y_is_row else "_col",
                         "_rand_stride" if stride is None else "")
            test_name = "".join(variables)
            tests_failed.append(test_name)

    return tests_failed

def passed_test(dtype, as_matrix, x_is_row, y_is_row, stride):
    """
    Run one vector swap test.

    Arguments:
        dtype:        either 'float64' or 'float32', the NumPy dtype to test
        as_matrix:    True to test a NumPy matrix, False to test a NumPy ndarray
        x_is_row:     True to test a row vector as parameter x, False to test a column vector
        y_is_row:     True to test a row vector as parameter y, False to test a column vector
        stride:       stride of x and y to test; if None, a random stride is assigned

    Returns:
        True if the expected result is within the margin of error of the actual result,
        False otherwise.
    """

    # generate random sizes for vector dimensions and vector stride (if necessary)
    length = randint(N_MIN, N_MAX)
    stride = randint(N_MIN, STRIDE_MAX) if stride is None else stride

    # create random vectors to test
    x = random_vector(length, x_is_row, dtype, as_matrix)
    y = random_vector(length, y_is_row, dtype, as_matrix)

    # compute the expected result
    if stride == 1:
        x_2 = copy(y.T) if y_is_row else copy(y)
        y_2 = copy(x.T) if x_is_row else copy(x)
    else:
        x_2 = copy(x.T) if x_is_row else copy(x)
        y_2 = copy(y.T) if y_is_row else copy(y)
        for i in range(0, length, stride):
            temp = x_2[i, 0]
            x_2[i, 0] = y_2[i, 0]
            y_2[i, 0] = temp

    # get the actual result
    swap(x, y, stride, stride)

    # compare the actual result to the expected result and return result of the test
    passed_x = allclose(x.T, x_2) if x_is_row else allclose(x, x_2)
    passed_y = allclose(y.T, y_2) if y_is_row else allclose(y, y_2)
    return passed_x and passed_y


# -*- coding: utf-8 -*-
"""
Assignment Chaper 01 (Think Stats 2, Allen B. Downey)
Ex 1-2
Self-study on statistics using pyhton
@author: Github: @rafaelmm82
"""

from __future__ import print_function, division

import sys
import numpy as np
import thinkstats2

from collections import defaultdict

def ReadFemResp(dct_file='2002FemResp.dct',
                dat_file='2002FemResp.dat.gz',
                nrows=None):
    """Reads the NSFG respondent data.

    dct_file: string file name
    dat_file: string file name

    returns: DataFrame
    """
    dct = thinkstats2.ReadStataDct(dct_file)
    df = dct.ReadFixedWidth(dat_file, compression='gzip', nrows=nrows)
    CleanFemResp(df)
    return df

def CleanFemResp(df):
    """Recodes variables from the respondent frame.

    df: DataFrame
    """
    pass

def ReadFemPreg(dct_file='2002FemPreg.dct',
                dat_file='2002FemPreg.dat.gz'):
    """Reads the NSFG pregnancy data.

    dct_file: string file name
    dat_file: string file name

    returns: DataFrame
    """
    dct = thinkstats2.ReadStataDct(dct_file)
    df = dct.ReadFixedWidth(dat_file, compression='gzip')
    CleanFemPreg(df)
    return df

def CleanFemPreg(df):
    """Recodes variables from the pregnancy frame.

    df: DataFrame
    """
    # mother's age is encoded in centiyears; convert to years
    df.agepreg /= 100.0

    # birthwgt_lb contains at least one bogus value (51 lbs)
    # replace with NaN
    df.loc[df.birthwgt_lb > 20, 'birthwgt_lb'] = np.nan

    # replace 'not ascertained', 'refused', 'don't know' with NaN
    na_vals = [97, 98, 99]
    df.birthwgt_lb.replace(na_vals, np.nan, inplace=True)
    df.birthwgt_oz.replace(na_vals, np.nan, inplace=True)
    df.hpagelb.replace(na_vals, np.nan, inplace=True)

    df.babysex.replace([7, 9], np.nan, inplace=True)
    df.nbrnaliv.replace([9], np.nan, inplace=True)

    # birthweight is stored in two columns, lbs and oz.
    # convert to a single column in lb
    # NOTE: creating a new column requires dictionary syntax,
    # not attribute assignment (like df.totalwgt_lb)
    df['totalwgt_lb'] = df.birthwgt_lb + df.birthwgt_oz / 16.0

    # due to a bug in ReadStataDct, the last variable gets clipped;
    # so for now set it to NaN
    df.cmintvw = np.nan

def ValidatePregnum(resp, preg):
    """Validate pregnum in the respondent file.

    resp: respondent DataFrame
    preg: pregnancy DataFrame
    """
    # make the map from caseid to list of pregnancy indices
    preg_map = MakePregMap(preg)

    # iterate through the respondent pregnum series
    for index, pregnum in resp.pregnum.iteritems():
        caseid = resp.caseid[index]
        indices = preg_map[caseid]

        # check that pregnum from the respondent file equals
        # the number of records in the pregnancy file
        if len(indices) != pregnum:
            print(caseid, len(indices), pregnum)
            return False

    return True

def MakePregMap(df):
    """Make a map from caseid to list of preg indices.

    df: DataFrame

    returns: dict that maps from caseid to list of indices into `preg`
    """
    d = defaultdict(list)
    for index, caseid in df.caseid.iteritems():
        d[caseid].append(index)
    return d

def main():
    """Tests the functions in this module.

    script: string script name
    """
    # read and validate the respondent file
    resp = ReadFemResp()

    assert(len(resp) == 7643)
    assert(resp.pregnum.value_counts()[1] == 1267)

    # read and validate the pregnancy file
    preg = ReadFemPreg()
    print(preg.shape)

    # validate that the pregnum column in `resp` matches the number
    # of entries in `preg`
    assert(ValidatePregnum(resp, preg))

    print('Everything is ok!')

if __name__ == '__main__':
    main()


#Joy
import numpy as np    #the numpy library
import matplotlib.pyplot as plt

import sys  #gives any command line arguments, incl program name
import os  #gives access to operating

print(sys.argv)     #print any comand arguments, incl program name
print(os.getcwd)   #print the current working directory