diff --git a/include/permanent/common.h b/include/permanent/common.h index e05becc..7654964 100644 --- a/include/permanent/common.h +++ b/include/permanent/common.h @@ -21,15 +21,13 @@ template struct _result_t; template -struct _result_t && !std::is_integral_v, void>> +struct _result_t, void>> { typedef double type; }; template -struct _result_t, void, - std::enable_if_t && !std::is_integral_v, void>> +struct _result_t, void, std::enable_if_t, void>> { typedef std::complex type; }; diff --git a/include/permanent/glynn.h b/include/permanent/glynn.h index 2f5c200..4969f7e 100644 --- a/include/permanent/glynn.h +++ b/include/permanent/glynn.h @@ -14,6 +14,159 @@ result_t glynn_square(const size_t m, const size_t n, const T *ptr) { (void)n; + /* Fill delta array (all +1 to start), and permutation array with [0...m]. */ + + sgn_t delta[64]; + size_t perm[64 + 1]; + for (size_t i = 0; i < m; ++i) { + perm[i] = i; + delta[i] = 1; + } + + /* Handle first permutation. */ + + // result_t vec[64]; + result_t out = 1; + for (size_t j = 0; j < m; ++j) { + result_t sum = 0; + for (size_t i = 0; i < m; ++i) { + sum += ptr[i * m + j] * delta[i]; + } + out *= sum; + // vec[j] = sum; + } + // for (size_t j = 0; j < m; ++j) { + // out *= vec[j]; + // } + + /* Iterate from the second to the final permutation. */ + + std::size_t bound = m - 1; + std::size_t pos = 0; + sgn_t sign = 1; + while (pos != bound) { + /* Update sign and delta. */ + + sign *= -1; + delta[bound - pos] *= -1; + + /* Compute term. */ + + result_t prod = 1; + for (size_t j = 0; j < m; ++j) { + result_t sum = 0; + for (size_t i = 0; i < m; ++i) { + sum += ptr[i * m + j] * delta[i]; + } + // vec[j] = sum; + prod *= sum; + } + + /* Multiply by the product of the vectors in delta. */ + + // for (size_t i = 0; i < m; ++i) { + // prod *= vec[i]; + // } + out += sign * prod; + + /* Go to next permutation. */ + + perm[0] = 0; + perm[pos] = perm[pos + 1]; + ++pos; + perm[pos] = pos; + pos = perm[0]; + } + + /* Divide by external factor and return permanent. */ + + return out / (1UL << bound); +} + +template +result_t glynn_rectangular(const size_t m, const size_t n, const T *ptr) +{ + /* Fill delta array (all +1 to start), and permutation array with [0...n]. + */ + + sgn_t delta[64]; + size_t perm[64 + 1]; + for (size_t i = 0; i < n; ++i) { + delta[i] = 1; + perm[i] = i; + } + + /* Handle first permutation. */ + + result_t out = 1; + for (size_t j = 0; j < n; ++j) { + result_t sum = 0; + for (size_t i = 0; i < m; ++i) { + sum += ptr[i * n + j] * delta[i]; + } + for (size_t k = m; k < n; ++k) { + sum += delta[k]; + } + // vec[j] = sum; + out *= sum; + } + // for (i = 0; i < n; ++i) { + // out *= vec[i]; + // } + + /* Iterate from the second to the final permutation. */ + + size_t pos = 0; + size_t bound = n - 1; + sgn_t sign = 1; + while (pos != bound) { + /* Update sign and delta. */ + + sign *= -1; + delta[bound - pos] *= -1; + + /* Compute term. */ + + result_t prod = 1; + for (size_t j = 0; j < n; ++j) { + result_t sum = 0; + for (size_t i = 0; i < m; ++i) { + sum += ptr[i * n + j] * delta[i]; + } + + for (size_t k = m; k < n; ++k) { + sum += delta[k]; + } + prod *= sum; + } + + /* Multiply by the product of the vectors in delta. */ + + // T prod = 1.0; + // for (i = 0; i < n; ++i) { + // prod *= vec[i]; + // } + out += sign * prod; + + /* Go to next permutation. */ + + perm[0] = 0; + perm[pos] = perm[pos + 1]; + ++pos; + perm[pos] = pos; + pos = perm[0]; + } + + /* Divide by external factor and return permanent. */ + + return (out / (1UL << bound)) / factorial>(n - m); +} + +template +result_t glynn_square1(const size_t m, const size_t n, const T *ptr) +{ + (void)n; + // Fill delta array ([+1...+1]) and permutation array ([0...m]) size_t perm[64 + 1]; sgn_t delta[64]; @@ -72,7 +225,7 @@ result_t glynn_square(const size_t m, const size_t n, const T *ptr) } template -result_t glynn_rectangular(const size_t m, const size_t n, const T *ptr) +result_t glynn_rectangular1(const size_t m, const size_t n, const T *ptr) { // Fill delta array ([+1...+1]) and permutation array ([0...m]) size_t perm[64 + 1]; diff --git a/include/permanent/tuning.default.h b/include/permanent/tuning.default.h index 2f150a7..a73d11b 100644 --- a/include/permanent/tuning.default.h +++ b/include/permanent/tuning.default.h @@ -8,10 +8,10 @@ namespace permanent { template struct _tuning_params_t { - static constexpr double PARAM_1 = +0.000000000e+00; - static constexpr double PARAM_2 = +0.000000000e+00; - static constexpr double PARAM_3 = +0.000000000e+00; - static constexpr double PARAM_4 = +0.000000000e+00; + static constexpr double PARAM_1 = -5.72098e-01; + static constexpr double PARAM_2 = -2.20142e+01; + static constexpr double PARAM_3 = +1.52979e+01; + static constexpr double PARAM_4 = +3.00000e+00; }; template diff --git a/src/main.cc b/src/main.cc index fde7c61..48d1c1a 100644 --- a/src/main.cc +++ b/src/main.cc @@ -259,11 +259,11 @@ static PyObject *py_opt(PyObject *module, PyObject *object) size_t m = PyArray_DIMS(matrix)[0]; size_t n = PyArray_DIMS(matrix)[1]; - if (m > n) { - return py_opt(module, PyArray_Transpose(matrix, nullptr)); - } else if (m > 64 || n > 64) { + if (m > 64 || n > 64) { PyErr_SetString(PyExc_ValueError, "Argument array must have <=64 rows and columns"); return nullptr; + } else if (m > n) { + return py_opt(module, PyArray_Transpose(matrix, nullptr)); } PERMANENT_DISPATCH_ARRAY_TYPE(permanent::opt, matrix) @@ -282,7 +282,10 @@ static PyObject *py_combinatoric(PyObject *module, PyObject *object) size_t m = PyArray_DIMS(matrix)[0]; size_t n = PyArray_DIMS(matrix)[1]; - if (m > n) { + if (m > 64 || n > 64) { + PyErr_SetString(PyExc_ValueError, "Argument array must have <=64 rows and columns"); + return nullptr; + } else if (m > n) { return py_combinatoric(module, PyArray_Transpose(matrix, nullptr)); } @@ -302,7 +305,10 @@ static PyObject *py_glynn(PyObject *module, PyObject *object) size_t m = PyArray_DIMS(matrix)[0]; size_t n = PyArray_DIMS(matrix)[1]; - if (m > n) { + if (m > 64 || n > 64) { + PyErr_SetString(PyExc_ValueError, "Argument array must have <=64 rows and columns"); + return nullptr; + } else if (m > n) { return py_glynn(module, PyArray_Transpose(matrix, nullptr)); } @@ -320,7 +326,10 @@ static PyObject *py_ryser(PyObject *module, PyObject *object) size_t m = PyArray_DIMS(matrix)[0]; size_t n = PyArray_DIMS(matrix)[1]; - if (m > n) { + if (m > 64 || n > 64) { + PyErr_SetString(PyExc_ValueError, "Argument array must have <=64 rows and columns"); + return nullptr; + } else if (m > n) { return py_ryser(module, PyArray_Transpose(matrix, nullptr)); } diff --git a/src/tuning.cc b/src/tuning.cc index 36f9d4f..b7d6f64 100644 --- a/src/tuning.cc +++ b/src/tuning.cc @@ -54,19 +54,19 @@ int generate_tuning_data(std::ofstream &csv_file, const size_t m, const size_t n if (m == n) { for (size_t i = 0; i != NUM_TRIALS; ++i) { begin = std::clock(); - soln_combn = permanent::combinatoric(m, n, array); + soln_combn = permanent::combinatoric_square(m, n, array); ensure(soln_combn); end = std::clock(); time_combn[i] = static_cast(end - begin); begin = std::clock(); - soln_glynn = permanent::glynn(m, n, array); + soln_glynn = permanent::glynn_square(m, n, array); ensure(soln_glynn); end = std::clock(); time_glynn[i] = static_cast(end - begin); begin = std::clock(); - soln_ryser = permanent::ryser(m, n, array); + soln_ryser = permanent::ryser_square(m, n, array); ensure(soln_ryser); end = std::clock(); time_ryser[i] = static_cast(end - begin); diff --git a/tests/test_permanent.py b/tests/test_permanent.py index dcc5bb4..ee53532 100644 --- a/tests/test_permanent.py +++ b/tests/test_permanent.py @@ -1,239 +1,317 @@ -import numpy as np -import math -import permanent - - -REL_ERROR = 0.0001 - - -# Test square matrices -def test_2by2_comb(): - matrix = np.arange(1, 5, dtype=np.double).reshape(2, 2) - assert abs((permanent.combinatoric(matrix) - 10) / 10) <= REL_ERROR - - -def test_2by2_glynn(): - matrix = np.arange(1, 5, dtype=np.double).reshape(2, 2) - assert abs((permanent.glynn(matrix) - 10) / 10) <= REL_ERROR - - -def test_2by2_ryser(): - matrix = np.arange(1, 5, dtype=np.double).reshape(2, 2) - assert abs((permanent.ryser(matrix) - 10) / 10) <= REL_ERROR - - -def test_3by3_comb(): - matrix = np.arange(1, 10, dtype=np.double).reshape(3, 3) - assert abs((permanent.combinatoric(matrix) - 450) / 450) <= REL_ERROR - - -def test_3by3_glynn(): - matrix = np.arange(1, 10, dtype=np.double).reshape(3, 3) - assert abs((permanent.glynn(matrix) - 450) / 450) <= REL_ERROR - - -def test_3by3_ryser(): - matrix = np.arange(1, 10, dtype=np.double).reshape(3, 3) - assert abs((permanent.ryser(matrix) - 450) / 450) <= REL_ERROR - - -def test_4by4_comb(): - matrix = np.arange(1, 17, dtype=np.double).reshape(4, 4) - assert abs((permanent.combinatoric(matrix) - 55456) / 55456) <= REL_ERROR - - -def test_4by4_glynn(): - matrix = np.arange(1, 17, dtype=np.double).reshape(4, 4) - assert abs((permanent.glynn(matrix) - 55456) / 55456) <= REL_ERROR - - -def test_4by4_ryser(): - matrix = np.arange(1, 17, dtype=np.double).reshape(4, 4) - assert abs((permanent.ryser(matrix) - 55456) / 55456) <= REL_ERROR - - -def test_7by7_comb(): - matrix = np.arange(1, 50, dtype=np.double).reshape(7, 7) - assert ( - abs((permanent.combinatoric(matrix) - 5373548250000) / 5373548250000) - <= REL_ERROR - ) - - -def test_7by7_glynn(): - matrix = np.arange(1, 50, dtype=np.double).reshape(7, 7) - assert abs((permanent.glynn(matrix) - 5373548250000) / 5373548250000) <= REL_ERROR - - -def test_7by7_ryser(): - matrix = np.arange(1, 50, dtype=np.double).reshape(7, 7) - assert abs((permanent.ryser(matrix) - 5373548250000) / 5373548250000) <= REL_ERROR - - -## Test rectangular matrices -def test_2by3_comb(): - matrix = np.arange(1, 7, dtype=np.double).reshape(2, 3) - assert abs((permanent.combinatoric(matrix) - 58) / 58) <= REL_ERROR - - -def test_2by3_glynn(): - matrix = np.arange(1, 7, dtype=np.double).reshape(2, 3) - assert abs((permanent.glynn(matrix) - 58) / 58) <= REL_ERROR - - -def test_2by3_ryser(): - matrix = np.arange(1, 7, dtype=np.double).reshape(2, 3) - assert abs((permanent.ryser(matrix) - 58) / 58) <= REL_ERROR - - -def test_2by4_comb(): - matrix = np.arange(1, 9, dtype=np.double).reshape(2, 4) - assert abs((permanent.combinatoric(matrix) - 190) / 190) <= REL_ERROR - - -def test_2by4_glynn(): - matrix = np.arange(1, 9, dtype=np.double).reshape(2, 4) - assert abs((permanent.glynn(matrix) - 190) / 190) <= REL_ERROR - - -def test_2by4_ryser(): - matrix = np.arange(1, 9, dtype=np.double).reshape(2, 4) - assert abs((permanent.ryser(matrix) - 190) / 190) <= REL_ERROR - - -def test_2by7_comb(): - matrix = np.arange(1, 15, dtype=np.double).reshape(2, 7) - assert abs((permanent.combinatoric(matrix) - 1820) / 1820) <= REL_ERROR +from math import factorial +import numpy as np +import numpy.testing as npt -def test_2by7_glynn(): - matrix = np.arange(1, 15, dtype=np.double).reshape(2, 7) - assert abs((permanent.glynn(matrix) - 1820) / 1820) <= REL_ERROR - - -def test_2by7_ryser(): - matrix = np.arange(1, 15, dtype=np.double).reshape(2, 7) - assert abs((permanent.ryser(matrix) - 1820) / 1820) <= REL_ERROR - - -def test_5by7_comb(): - matrix = np.arange(1, 36, dtype=np.double).reshape(5, 7) - assert abs((permanent.combinatoric(matrix) - 1521238320) / 1521238320) <= REL_ERROR - - -def test_5by7_glynn(): - matrix = np.arange(1, 36, dtype=np.double).reshape(5, 7) - assert abs((permanent.glynn(matrix) - 1521238320) / 1521238320) <= REL_ERROR - - -def test_5by7_ryser(): - matrix = np.arange(1, 36, dtype=np.double).reshape(5, 7) - assert abs((permanent.ryser(matrix) - 1521238320) / 1521238320) <= REL_ERROR - - -def test_6by7_comb(): - matrix = np.arange(1, 43, dtype=np.double).reshape(6, 7) - assert ( - abs((permanent.combinatoric(matrix) - 117681979920) / 117681979920) <= REL_ERROR - ) - - -def test_6by7_glynn(): - matrix = np.arange(1, 43, dtype=np.double).reshape(6, 7) - assert abs((permanent.glynn(matrix) - 117681979920) / 117681979920) <= REL_ERROR - - -def test_6by7_ryser(): - matrix = np.arange(1, 43, dtype=np.double).reshape(6, 7) - assert abs((permanent.ryser(matrix) - 117681979920) / 117681979920) <= REL_ERROR - - -def test_ones_comb(): - matrix = np.ones((10, 10), dtype=np.double) - assert ( - abs((permanent.combinatoric(matrix) - math.factorial(10)) / math.factorial(10)) - <= REL_ERROR - ) - - -def test_ones_ryser(): - matrix = np.ones((10, 10), dtype=np.double) - assert ( - abs((permanent.ryser(matrix) - math.factorial(10)) / math.factorial(10)) - <= REL_ERROR - ) - - -def test_ones_glynn(): - matrix = np.ones((10, 10), dtype=np.double) - assert ( - abs((permanent.glynn(matrix) - math.factorial(10)) / math.factorial(10)) - <= REL_ERROR - ) - - -def test_ones_comb_big(): - matrix = np.ones((12, 12), dtype=np.double) - assert ( - abs((permanent.combinatoric(matrix) - math.factorial(12)) / math.factorial(12)) - <= REL_ERROR - ) - - -def test_ones_ryser_big(): - matrix = np.ones((12, 12), dtype=np.double) - assert ( - abs((permanent.ryser(matrix) - math.factorial(12)) / math.factorial(12)) - <= REL_ERROR - ) - - -def test_ones_glynn_big(): - matrix = np.ones((12, 12), dtype=np.double) - assert ( - abs((permanent.glynn(matrix) - math.factorial(12)) / math.factorial(12)) - <= REL_ERROR - ) - - -def test_identity_comb(): - matrix = np.identity(10, dtype=np.double) - assert abs((permanent.combinatoric(matrix) - 1) / 1) <= REL_ERROR - - -def test_identity_ryser(): - matrix = np.identity(10, dtype=np.double) - assert abs((permanent.ryser(matrix) - 1) / 1) <= REL_ERROR - - -def test_identity_glynn(): - matrix = np.identity(10, dtype=np.double) - assert abs((permanent.glynn(matrix) - 1) / 1) <= REL_ERROR - - -def test_identity_ryser_odd(): - matrix = np.identity(5, dtype=np.double) - assert abs((permanent.ryser(matrix) - 1) / 1) <= REL_ERROR - - -def test_identity_glynn_odd(): - matrix = np.identity(5, dtype=np.double) - assert abs((permanent.glynn(matrix) - 1) / 1) <= REL_ERROR - - -def test_identity_comb_diag(): - matrix = np.ones((3, 7), dtype=np.double) - diag_matrix = np.diag(np.diag(matrix)) - assert abs((permanent.combinatoric(diag_matrix) - 1) / 1) <= REL_ERROR - +import pytest -def test_identity_ryser_diag(): - matrix = np.ones((3, 7), dtype=np.double) - diag_matrix = np.diag(np.diag(matrix)) - assert abs((permanent.ryser(diag_matrix) - 1) / 1) <= REL_ERROR +import permanent -def test_identity_glynn_diag(): - matrix = np.ones((3, 7), dtype=np.double) - diag_matrix = np.diag(np.diag(matrix)) - assert abs((permanent.glynn(diag_matrix) - 1) / 1) <= REL_ERROR +ATOL = 0e0 + + +RTOL = 1e-4 + + +FNS = [ + permanent.opt, + permanent.combinatoric, + permanent.glynn, + permanent.ryser, +] + + +@pytest.mark.parametrize( + "args", + [ + (np.arange(1, 5, dtype=float).reshape(2, 2), 10), + (np.arange(1, 5, dtype=int).reshape(2, 2), 10), + (np.arange(1, 5, dtype=complex).reshape(2, 2), 10), + ], +) +@pytest.mark.parametrize("fn", FNS) +def test_compute_permanent(fn, args): + r"""Ensure that the correct permanent is computed.""" + npt.assert_allclose(fn(args[0]), args[1], atol=ATOL, rtol=RTOL) + + +@pytest.mark.parametrize( + "arg", + [ + np.ones((2, 65)), + np.ones((65, 2)), + np.ones((65, 65)), + ], +) +@pytest.mark.parametrize("fn", FNS) +def test_dim_gt_64_raises(fn, arg): + r"""Ensure that matrices with any dimension > 64 raise a ValueError.""" + with npt.assert_raises(ValueError): + fn(arg) + + +@pytest.mark.parametrize( + "arg", + [ + np.ones((2, 23), dtype=int), + np.ones((23, 2), dtype=int), + np.ones((43, 64), dtype=int), + np.ones((64, 43), dtype=int), + ], +) +@pytest.mark.parametrize("fn", FNS) +def test_int_dim_diff_gt_20_raises(fn, arg): + r"""Ensure that integer matrices with difference in dimensions > 20 raise a ValueError.""" + with npt.assert_raises(ValueError): + fn(arg) + + +@pytest.mark.parametrize( + "arg", + [ + np.ones((4, 4), dtype=bool), + np.array([[object() for _ in range(4)] for _ in range(4)]), + np.array([[{"hi": 1} for _ in range(4)] for _ in range(4)]), + np.array([[chr(x) for x in range(65, 69)] for _ in range(4)]), + ], +) +@pytest.mark.parametrize("fn", FNS) +def test_invalid_type_raises(fn, arg): + r"""Ensure that matrices with an invalid dtype raise a ValueError.""" + with npt.assert_raises(TypeError): + fn(arg) + + +# # Test square matrices +# def test_2by2_comb(): +# matrix = np.arange(1, 5, dtype=np.double).reshape(2, 2) +# assert abs((permanent.combinatoric(matrix) - 10) / 10) <= REL_ERROR +# npt.assert_allclose( +# +# +# def test_2by2_glynn(): +# matrix = np.arange(1, 5, dtype=np.double).reshape(2, 2) +# assert abs((permanent.glynn(matrix) - 10) / 10) <= REL_ERROR +# +# +# def test_2by2_ryser(): +# matrix = np.arange(1, 5, dtype=np.double).reshape(2, 2) +# assert abs((permanent.ryser(matrix) - 10) / 10) <= REL_ERROR +# +# +# def test_3by3_comb(): +# matrix = np.arange(1, 10, dtype=np.double).reshape(3, 3) +# assert abs((permanent.combinatoric(matrix) - 450) / 450) <= REL_ERROR +# +# +# def test_3by3_glynn(): +# matrix = np.arange(1, 10, dtype=np.double).reshape(3, 3) +# assert abs((permanent.glynn(matrix) - 450) / 450) <= REL_ERROR +# +# +# def test_3by3_ryser(): +# matrix = np.arange(1, 10, dtype=np.double).reshape(3, 3) +# assert abs((permanent.ryser(matrix) - 450) / 450) <= REL_ERROR +# +# +# def test_4by4_comb(): +# matrix = np.arange(1, 17, dtype=np.double).reshape(4, 4) +# assert abs((permanent.combinatoric(matrix) - 55456) / 55456) <= REL_ERROR +# +# +# def test_4by4_glynn(): +# matrix = np.arange(1, 17, dtype=np.double).reshape(4, 4) +# assert abs((permanent.glynn(matrix) - 55456) / 55456) <= REL_ERROR +# +# +# def test_4by4_ryser(): +# matrix = np.arange(1, 17, dtype=np.double).reshape(4, 4) +# assert abs((permanent.ryser(matrix) - 55456) / 55456) <= REL_ERROR +# +# +# def test_7by7_comb(): +# matrix = np.arange(1, 50, dtype=np.double).reshape(7, 7) +# assert ( +# abs((permanent.combinatoric(matrix) - 5373548250000) / 5373548250000) +# <= REL_ERROR +# ) +# +# +# def test_7by7_glynn(): +# matrix = np.arange(1, 50, dtype=np.double).reshape(7, 7) +# assert abs((permanent.glynn(matrix) - 5373548250000) / 5373548250000) <= REL_ERROR +# +# +# def test_7by7_ryser(): +# matrix = np.arange(1, 50, dtype=np.double).reshape(7, 7) +# assert abs((permanent.ryser(matrix) - 5373548250000) / 5373548250000) <= REL_ERROR +# +# +# ## Test rectangular matrices +# def test_2by3_comb(): +# matrix = np.arange(1, 7, dtype=np.double).reshape(2, 3) +# assert abs((permanent.combinatoric(matrix) - 58) / 58) <= REL_ERROR +# +# +# def test_2by3_glynn(): +# matrix = np.arange(1, 7, dtype=np.double).reshape(2, 3) +# assert abs((permanent.glynn(matrix) - 58) / 58) <= REL_ERROR +# +# +# def test_2by3_ryser(): +# matrix = np.arange(1, 7, dtype=np.double).reshape(2, 3) +# assert abs((permanent.ryser(matrix) - 58) / 58) <= REL_ERROR +# +# +# def test_2by4_comb(): +# matrix = np.arange(1, 9, dtype=np.double).reshape(2, 4) +# assert abs((permanent.combinatoric(matrix) - 190) / 190) <= REL_ERROR +# +# +# def test_2by4_glynn(): +# matrix = np.arange(1, 9, dtype=np.double).reshape(2, 4) +# assert abs((permanent.glynn(matrix) - 190) / 190) <= REL_ERROR +# +# +# def test_2by4_ryser(): +# matrix = np.arange(1, 9, dtype=np.double).reshape(2, 4) +# assert abs((permanent.ryser(matrix) - 190) / 190) <= REL_ERROR +# +# +# def test_2by7_comb(): +# matrix = np.arange(1, 15, dtype=np.double).reshape(2, 7) +# assert abs((permanent.combinatoric(matrix) - 1820) / 1820) <= REL_ERROR +# +# +# def test_2by7_glynn(): +# matrix = np.arange(1, 15, dtype=np.double).reshape(2, 7) +# assert abs((permanent.glynn(matrix) - 1820) / 1820) <= REL_ERROR +# +# +# def test_2by7_ryser(): +# matrix = np.arange(1, 15, dtype=np.double).reshape(2, 7) +# assert abs((permanent.ryser(matrix) - 1820) / 1820) <= REL_ERROR +# +# +# def test_5by7_comb(): +# matrix = np.arange(1, 36, dtype=np.double).reshape(5, 7) +# assert abs((permanent.combinatoric(matrix) - 1521238320) / 1521238320) <= REL_ERROR +# +# +# def test_5by7_glynn(): +# matrix = np.arange(1, 36, dtype=np.double).reshape(5, 7) +# assert abs((permanent.glynn(matrix) - 1521238320) / 1521238320) <= REL_ERROR +# +# +# def test_5by7_ryser(): +# matrix = np.arange(1, 36, dtype=np.double).reshape(5, 7) +# assert abs((permanent.ryser(matrix) - 1521238320) / 1521238320) <= REL_ERROR +# +# +# def test_6by7_comb(): +# matrix = np.arange(1, 43, dtype=np.double).reshape(6, 7) +# assert ( +# abs((permanent.combinatoric(matrix) - 117681979920) / 117681979920) <= REL_ERROR +# ) +# +# +# def test_6by7_glynn(): +# matrix = np.arange(1, 43, dtype=np.double).reshape(6, 7) +# assert abs((permanent.glynn(matrix) - 117681979920) / 117681979920) <= REL_ERROR +# +# +# def test_6by7_ryser(): +# matrix = np.arange(1, 43, dtype=np.double).reshape(6, 7) +# assert abs((permanent.ryser(matrix) - 117681979920) / 117681979920) <= REL_ERROR +# +# +# def test_ones_comb(): +# matrix = np.ones((10, 10), dtype=np.double) +# assert ( +# abs((permanent.combinatoric(matrix) - factorial(10)) / factorial(10)) +# <= REL_ERROR +# ) +# +# +# def test_ones_ryser(): +# matrix = np.ones((10, 10), dtype=np.double) +# assert ( +# abs((permanent.ryser(matrix) - factorial(10)) / factorial(10)) +# <= REL_ERROR +# ) +# +# +# def test_ones_glynn(): +# matrix = np.ones((10, 10), dtype=np.double) +# assert ( +# abs((permanent.glynn(matrix) - factorial(10)) / factorial(10)) +# <= REL_ERROR +# ) +# +# +# def test_ones_comb_big(): +# matrix = np.ones((12, 12), dtype=np.double) +# assert ( +# abs((permanent.combinatoric(matrix) - factorial(12)) / factorial(12)) +# <= REL_ERROR +# ) +# +# +# def test_ones_ryser_big(): +# matrix = np.ones((12, 12), dtype=np.double) +# assert ( +# abs((permanent.ryser(matrix) - factorial(12)) / factorial(12)) +# <= REL_ERROR +# ) +# +# +# def test_ones_glynn_big(): +# matrix = np.ones((12, 12), dtype=np.double) +# assert ( +# abs((permanent.glynn(matrix) - factorial(12)) / factorial(12)) +# <= REL_ERROR +# ) +# +# +# def test_identity_comb(): +# matrix = np.identity(10, dtype=np.double) +# assert abs((permanent.combinatoric(matrix) - 1) / 1) <= REL_ERROR +# +# +# def test_identity_ryser(): +# matrix = np.identity(10, dtype=np.double) +# assert abs((permanent.ryser(matrix) - 1) / 1) <= REL_ERROR +# +# +# def test_identity_glynn(): +# matrix = np.identity(10, dtype=np.double) +# assert abs((permanent.glynn(matrix) - 1) / 1) <= REL_ERROR +# +# +# def test_identity_ryser_odd(): +# matrix = np.identity(5, dtype=np.double) +# assert abs((permanent.ryser(matrix) - 1) / 1) <= REL_ERROR +# +# +# def test_identity_glynn_odd(): +# matrix = np.identity(5, dtype=np.double) +# assert abs((permanent.glynn(matrix) - 1) / 1) <= REL_ERROR +# +# +# def test_identity_comb_diag(): +# matrix = np.ones((3, 7), dtype=np.double) +# diag_matrix = np.diag(np.diag(matrix)) +# assert abs((permanent.combinatoric(diag_matrix) - 1) / 1) <= REL_ERROR +# +# +# def test_identity_ryser_diag(): +# matrix = np.ones((3, 7), dtype=np.double) +# diag_matrix = np.diag(np.diag(matrix)) +# assert abs((permanent.ryser(diag_matrix) - 1) / 1) <= REL_ERROR +# +# +# def test_identity_glynn_diag(): +# matrix = np.ones((3, 7), dtype=np.double) +# diag_matrix = np.diag(np.diag(matrix)) +# assert abs((permanent.glynn(diag_matrix) - 1) / 1) <= REL_ERROR