# Path: distributions/tests/util.py
# def require_cython():
#     if not distributions.has_cython:
#         raise SkipTest('no cython support')
# 
# def assert_close(lhs, rhs, tol=TOL, err_msg=None):
#     try:
#         if isinstance(lhs, dict):
#             assert_true(
#                 isinstance(rhs, dict),
#                 'type mismatch: {} vs {}'.format(type(lhs), type(rhs)))
#             assert_equal(set(lhs.keys()), set(rhs.keys()))
#             for key, val in lhs.iteritems():
#                 msg = '{}[{}]'.format(err_msg or '', key)
#                 assert_close(val, rhs[key], tol, msg)
#         elif isinstance(lhs, float) or isinstance(lhs, numpy.float64):
#             assert_true(
#                 isinstance(rhs, float) or isinstance(rhs, numpy.float64),
#                 'type mismatch: {} vs {}'.format(type(lhs), type(rhs)))
#             diff = abs(lhs - rhs)
#             norm = 1 + abs(lhs) + abs(rhs)
#             msg = '{} off by {}% = {}'.format(
#                 err_msg or '',
#                 100 * diff / norm,
#                 diff)
#             assert_less(diff, tol * norm, msg)
#         elif isinstance(lhs, numpy.ndarray) or isinstance(rhs, numpy.ndarray):
#             assert_true(
#                 (isinstance(lhs, numpy.ndarray) or isinstance(lhs, list)) and
#                 (isinstance(rhs, numpy.ndarray) or isinstance(rhs, list)),
#                 'type mismatch: {} vs {}'.format(type(lhs), type(rhs)))
#             decimal = int(round(-math.log10(tol)))
#             assert_array_almost_equal(
#                 lhs,
#                 rhs,
#                 decimal=decimal,
#                 err_msg=(err_msg or ''))
#         elif isinstance(lhs, list) or isinstance(lhs, tuple):
#             assert_true(
#                 isinstance(rhs, list) or isinstance(rhs, tuple),
#                 'type mismatch: {} vs {}'.format(type(lhs), type(rhs)))
#             for pos, (x, y) in enumerate(izip(lhs, rhs)):
#                 msg = '{}[{}]'.format(err_msg or '', pos)
#                 assert_close(x, y, tol, msg)
#         else:
#             assert_equal(lhs, rhs, err_msg)
#     except Exception:
#         print err_msg or ''
#         print 'actual = {}'.format(print_short(lhs))
#         print 'expected = {}'.format(print_short(rhs))
#         raise


import numpy
from nose.tools import assert_equal
from distributions.tests.util import require_cython, assert_close
    from distributions.lp.special import log_stirling1_row
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
# TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.



def test_log_stirling1_row():
    require_cython()
    MAX_N = 128

    rows = [[1]]
    for n in range(1, MAX_N + 1):
        prev = rows[-1]
        middle = [(n - 1) * prev[k] + prev[k - 1] for k in range(1, n)]
        row = [0] + middle + [1]
        rows.append(row)

    for n in range(1, MAX_N + 1):
        print 'Row {}:'.format(n),
        row_py = numpy.log(numpy.array(rows[n][1:], dtype=numpy.double))
        row_cpp = log_stirling1_row(n)[1:]
        assert_equal(len(row_py), len(row_cpp))

        # only the slopes need to be accurate
        #print 0,
        #assert_close(row_py[0], row_cpp[0])
        #print len(row_py)
        #assert_close(row_py[-1], row_cpp[-1])

        diff_py = numpy.diff(row_py)

# Path: distributions/tests/util.py
# def require_cython():
#     if not distributions.has_cython:
#         raise SkipTest('no cython support')
# 
# def assert_close(lhs, rhs, tol=TOL, err_msg=None):
#     try:
#         if isinstance(lhs, dict):
#             assert_true(
#                 isinstance(rhs, dict),
#                 'type mismatch: {} vs {}'.format(type(lhs), type(rhs)))
#             assert_equal(set(lhs.keys()), set(rhs.keys()))
#             for key, val in lhs.iteritems():
#                 msg = '{}[{}]'.format(err_msg or '', key)
#                 assert_close(val, rhs[key], tol, msg)
#         elif isinstance(lhs, float) or isinstance(lhs, numpy.float64):
#             assert_true(
#                 isinstance(rhs, float) or isinstance(rhs, numpy.float64),
#                 'type mismatch: {} vs {}'.format(type(lhs), type(rhs)))
#             diff = abs(lhs - rhs)
#             norm = 1 + abs(lhs) + abs(rhs)
#             msg = '{} off by {}% = {}'.format(
#                 err_msg or '',
#                 100 * diff / norm,
#                 diff)
#             assert_less(diff, tol * norm, msg)
#         elif isinstance(lhs, numpy.ndarray) or isinstance(rhs, numpy.ndarray):
#             assert_true(
#                 (isinstance(lhs, numpy.ndarray) or isinstance(lhs, list)) and
#                 (isinstance(rhs, numpy.ndarray) or isinstance(rhs, list)),
#                 'type mismatch: {} vs {}'.format(type(lhs), type(rhs)))
#             decimal = int(round(-math.log10(tol)))
#             assert_array_almost_equal(
#                 lhs,
#                 rhs,
#                 decimal=decimal,
#                 err_msg=(err_msg or ''))
#         elif isinstance(lhs, list) or isinstance(lhs, tuple):
#             assert_true(
#                 isinstance(rhs, list) or isinstance(rhs, tuple),
#                 'type mismatch: {} vs {}'.format(type(lhs), type(rhs)))
#             for pos, (x, y) in enumerate(izip(lhs, rhs)):
#                 msg = '{}[{}]'.format(err_msg or '', pos)
#                 assert_close(x, y, tol, msg)
#         else:
#             assert_equal(lhs, rhs, err_msg)
#     except Exception:
#         print err_msg or ''
#         print 'actual = {}'.format(print_short(lhs))
#         print 'expected = {}'.format(print_short(rhs))
#         raise


# Path: distributions/tests/test_special.py
import numpy
from nose.tools import assert_equal
from distributions.tests.util import require_cython, assert_close
    from distributions.lp.special import log_stirling1_row

# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
# TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.



def test_log_stirling1_row():
    require_cython()
    MAX_N = 128

    rows = [[1]]
    for n in range(1, MAX_N + 1):
        prev = rows[-1]
        middle = [(n - 1) * prev[k] + prev[k - 1] for k in range(1, n)]
        row = [0] + middle + [1]
        rows.append(row)

    for n in range(1, MAX_N + 1):
        print 'Row {}:'.format(n),
        row_py = numpy.log(numpy.array(rows[n][1:], dtype=numpy.double))
        row_cpp = log_stirling1_row(n)[1:]
        assert_equal(len(row_py), len(row_cpp))

        # only the slopes need to be accurate
        #print 0,
        #assert_close(row_py[0], row_cpp[0])
        #print len(row_py)
        #assert_close(row_py[-1], row_cpp[-1])

        diff_py = numpy.diff(row_py)

        diff_cpp = numpy.diff(row_cpp)