Compares several statments by timing them and also
    checks that they have the same return value

    Args:
        stmt_list (list) : list of statments to compare
        setup (str) :
        iterations (int) :
        verbose (bool) :
        strict (bool) :

    Returns:
        tuple (bool, list, list) : (passed, time_list, result_list)
            passed (bool): True if all results are the same
            time_list (list): list of times for each statment
            result_list (list): list of results values for each statment

    CommandLine:
        python -m utool.util_dev --exec-timeit_compare

    Example:
        >>> # ENABLE_DOCTEST
        >>> from utool.util_dev import *  # NOQA
        >>> import utool as ut
        >>> setup = ut.codeblock(
                '''
                import numpy as np
                rng = np.random.RandomState(0)
                invVR_mats = rng.rand(1000, 3, 3).astype(np.float64)
                ''')
        >>> stmt1 = 'invVR_mats[:, 0:2, 2].T'
        >>> stmt2 = 'invVR_mats.T[2, 0:2]'
        >>> iterations = 1000
        >>> verbose = True
        >>> stmt_list = [stmt1, stmt2]
        >>> ut.timeit_compare(stmt_list, setup=setup, iterations=iterations, verbose=verbose)

def timeit_compare(stmt_list, setup='', iterations=100000, verbose=True,
                   strict=False, assertsame=True):
    """
    Compares several statments by timing them and also
    checks that they have the same return value

    Args:
        stmt_list (list) : list of statments to compare
        setup (str) :
        iterations (int) :
        verbose (bool) :
        strict (bool) :

    Returns:
        tuple (bool, list, list) : (passed, time_list, result_list)
            passed (bool): True if all results are the same
            time_list (list): list of times for each statment
            result_list (list): list of results values for each statment

    CommandLine:
        python -m utool.util_dev --exec-timeit_compare

    Example:
        >>> # ENABLE_DOCTEST
        >>> from utool.util_dev import *  # NOQA
        >>> import utool as ut
        >>> setup = ut.codeblock(
                '''
                import numpy as np
                rng = np.random.RandomState(0)
                invVR_mats = rng.rand(1000, 3, 3).astype(np.float64)
                ''')
        >>> stmt1 = 'invVR_mats[:, 0:2, 2].T'
        >>> stmt2 = 'invVR_mats.T[2, 0:2]'
        >>> iterations = 1000
        >>> verbose = True
        >>> stmt_list = [stmt1, stmt2]
        >>> ut.timeit_compare(stmt_list, setup=setup, iterations=iterations, verbose=verbose)
    """
    import timeit
    import utool as ut

    stmt_list = [s for s in stmt_list if not s.startswith('#')]

    for stmtx in range(len(stmt_list)):
        # Hacky way of removing assignment and just getting statement
        # We have to make sure it is ok when using it for kwargs
        stmt = stmt_list[stmtx]
        eqpos = stmt.find('=')
        lparen_pos = stmt.find('(')
        if eqpos > 0 and (lparen_pos == -1 or lparen_pos > eqpos):
            stmt = '='.join(stmt.split('=')[1:])
            stmt_list[stmtx] = stmt

    if verbose:
        print('+----------------')
        print('| TIMEIT COMPARE')
        print('+----------------')
        print('| iterations = %d' % (iterations,))
        print('| Input:')
        #print('|     +------------')
        print('|     | num | stmt')
        for count, stmt in enumerate(stmt_list):
            print('|     | %3d | %r' % (count, stmt))
        print('...')
        sys.stdout.flush()
        #print('+     L________________')

    if assertsame:
        result_list = [_testit(stmt, setup) for stmt in stmt_list]
    else:
        result_list = None
    time_list   = [timeit.timeit(stmt, setup=setup, number=iterations)
                   for stmt in stmt_list]

    def numpy_diff_tests(result_list):
        print('Testing numpy arrays')
        shape_list = [a.shape for a in result_list]
        print('shape_list = %r' % (shape_list,))
        sum_list = [a.sum() for a in result_list]
        diff_list = [np.abs(a - b) for a, b in ut.itertwo(result_list)]
        print('diff stats')
        for diffs in diff_list:
            print(ut.repr4(ut.get_stats(diffs, precision=2, use_median=True)))
        print('diff_list = %r' % (diff_list,))
        print('sum_list = %r' % (sum_list,))
        print('passed_list = %r' % (passed_list,))

    if assertsame:
        if ut.list_type(result_list) is np.ndarray:
            passed_list = [np.allclose(*tup) for tup in ut.itertwo(result_list)]
            passed = all(passed_list)
            is_numpy = True
        else:
            passed = ut.allsame(result_list, strict=False)
            is_numpy = False
    else:
        passed = True
    if verbose:
        print('| Output:')
        if not passed and assertsame:
            print('|    * FAILED: results differ between some statements')
            if is_numpy:
                numpy_diff_tests(result_list)
            print('| Results:')
            for result in result_list:
                for count, result in enumerate(result_list):
                    print('<Result %d>' % count)
                    print(result)
                    #print(ut.truncate_str(repr(result)))
                    print('</Result %d>' % count)
            if strict:
                raise AssertionError('Results are not valid')
        else:
            if assertsame:
                print('|    * PASSED: each statement produced the same result')
            else:
                print('|    * PASSED: each statement did not error')
            passed = True
        #print('|    +-----------------------------------')
        print('|    | num | total time | per loop | stmt')
        for count, tup in enumerate(zip(stmt_list, time_list)):
            stmt, time = tup
            print('|    | %3d | %10s | %8s | %s' %
                  (count, ut.seconds_str(time),
                   ut.seconds_str(time / iterations), stmt))
        #print('|    L___________________________________')
        if verbose:
            print('L_________________')
        return (passed, time_list, result_list)