From 3d4fbc68eb2fa11fa15d77398247dc616d266d1f Mon Sep 17 00:00:00 2001 From: JQZ1111 <75086618+JQZ1111@users.noreply.github.com> Date: Tue, 9 Nov 2021 14:16:05 -0500 Subject: [PATCH 01/43] Update _permanent.py Added Ryser algorithm to find the permanent of a matrix. Note that perm_ryser(A) can find the permanent of a real matrix as well as the permanent of a complex one. --- thewalrus/_permanent.py | 44 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/thewalrus/_permanent.py b/thewalrus/_permanent.py index 1b341f1c2..fcc6c36f5 100644 --- a/thewalrus/_permanent.py +++ b/thewalrus/_permanent.py @@ -18,6 +18,7 @@ from ._hafnian import hafnian_repeated from .libwalrus import perm_complex, perm_real, perm_BBFG_real, perm_BBFG_complex +from numba import jit def perm(A, quad=True, fsum=False, method="bbfg"): @@ -78,6 +79,49 @@ def perm(A, quad=True, fsum=False, method="bbfg"): ) return perm_real(A, quad=quad, fsum=fsum) if isRyser else perm_BBFG_real(A) +@jit(nopython=True) +def perm_ryser(M): + """ + Returns the permanent of a matrix using the Ryser formula in Gray ordering + + The code is an re-implementation from a Python 2 code found in + `Permanent code golf `_ using numba. + + Args: + M (array) : a square array. + + Returns: + np.float64 or np.complex128: the permanent of matrix M. + """ + # Raise an errors if matrix is not square + (a, b) = M.shape + if a != b: + raise Exception('Not a square matrix') + n = len(M) + # row_comb keeps the sum of previous subsets. + # Every iteration, it removes a term and/or adds a new new term + # to give the term to add for the next subset + row_comb = np.zeros((n), dtype=M.dtype) + total = 0 + old_grey = 0 + sign = +1 + binary_power_dict = [2**i for i in range(n)] + num_loops = 2 ** n + for k in range(0, num_loops): + bin_index = ((k+1) % num_loops) + reduced = np.prod(row_comb) + total += sign * reduced + new_grey = bin_index ^ (bin_index // 2) + grey_diff = old_grey ^ new_grey + grey_diff_index = binary_power_dict.index(grey_diff) + new_vector = M[grey_diff_index] + direction = (old_grey > new_grey) - (old_grey < new_grey) + for i in range(n): + row_comb[i] += new_vector[i] * direction + sign = -sign + old_grey = new_grey + return total + def permanent_repeated(A, rpt): r"""Calculates the permanent of matrix :math:`A`, where the ith row/column From 6f8f1fc359a440d8716fa448545133792345e157 Mon Sep 17 00:00:00 2001 From: Brandon Date: Tue, 9 Nov 2021 18:56:28 -0500 Subject: [PATCH 02/43] Verification and correction of minor mistakes --- thewalrus/_permanent.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/thewalrus/_permanent.py b/thewalrus/_permanent.py index fcc6c36f5..864aef860 100644 --- a/thewalrus/_permanent.py +++ b/thewalrus/_permanent.py @@ -93,13 +93,13 @@ def perm_ryser(M): Returns: np.float64 or np.complex128: the permanent of matrix M. """ - # Raise an errors if matrix is not square + # Raises an error if the matrix is not square (a, b) = M.shape if a != b: raise Exception('Not a square matrix') n = len(M) # row_comb keeps the sum of previous subsets. - # Every iteration, it removes a term and/or adds a new new term + # Every iteration, it removes a term and/or adds a new term # to give the term to add for the next subset row_comb = np.zeros((n), dtype=M.dtype) total = 0 From 7c68219eb1259e3ef5a252e8be4f14c998c49801 Mon Sep 17 00:00:00 2001 From: Brandon Date: Tue, 9 Nov 2021 20:36:57 -0500 Subject: [PATCH 03/43] Added the BBFG algorithm --- thewalrus/_permanent.py | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/thewalrus/_permanent.py b/thewalrus/_permanent.py index 864aef860..ffe3ba542 100644 --- a/thewalrus/_permanent.py +++ b/thewalrus/_permanent.py @@ -122,6 +122,47 @@ def perm_ryser(M): old_grey = new_grey return total +@jit(nopython=True) +def perm_bbfg(M): + """ + Returns the permanent of a matrix using the bbfg formula in Gray ordering + + The code is a re-implementation from a Python 2 code found in + `Permanent code golf + `_ + using numba. + + Args: + M (array) : a square array. + + Returns: + np.float64 or np.complex128: the permanent of a matrix M. + """ + # Raises an error if the matrix is not square + (a, b) = M.shape + if a != b: + raise Exception("Not a square matrix") + + n = len(M) + row_comb = np.sum(M, 0) + total = 0 + old_gray = 0 + sign = +1 + binary_power_dict = [2 ** i for i in range(n)] + num_loops = 2 ** (n - 1) + for bin_index in range(1, num_loops + 1): + reduced = np.prod(row_comb) + total += sign * reduced + new_gray = bin_index ^ (bin_index // 2) + gray_diff = old_gray ^ new_gray + gray_diff_index = binary_power_dict.index(gray_diff) + new_vector = M[gray_diff_index] + direction = 2 * ((old_gray > new_gray) - (old_gray < new_gray)) + for i in range(n): + row_comb[i] += new_vector[i] * direction + sign = -sign + old_gray = new_gray + return total / num_loops def permanent_repeated(A, rpt): r"""Calculates the permanent of matrix :math:`A`, where the ith row/column From e990721e44bbf22555cd35330b1718536917f05b Mon Sep 17 00:00:00 2001 From: JQZ1111 <75086618+JQZ1111@users.noreply.github.com> Date: Tue, 9 Nov 2021 22:28:26 -0500 Subject: [PATCH 04/43] Update _permanent.py Changed to possibly return ryser and bbfg instead of complex and real ryser and bbfg --- thewalrus/_permanent.py | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/thewalrus/_permanent.py b/thewalrus/_permanent.py index ffe3ba542..f1c6f0c41 100644 --- a/thewalrus/_permanent.py +++ b/thewalrus/_permanent.py @@ -68,16 +68,8 @@ def perm(A, quad=True, fsum=False, method="bbfg"): ) isRyser = bool(method != "bbfg") - - if A.dtype == np.complex: - if np.any(np.iscomplex(A)): - return perm_complex(A, quad=quad) if isRyser else perm_BBFG_complex(A) - return ( - perm_real(np.float64(A.real), quad=quad, fsum=fsum) - if isRyser - else perm_BBFG_real(np.float64(A.real)) - ) - return perm_real(A, quad=quad, fsum=fsum) if isRyser else perm_BBFG_real(A) + + return perm_ryser(A) if isRyser else perm_bbfg(A) @jit(nopython=True) def perm_ryser(M): From 4ccc15837db915d04040d1e02eb67c22564cb34e Mon Sep 17 00:00:00 2001 From: benjaminlanthier <91567620+benjaminlanthier@users.noreply.github.com> Date: Tue, 9 Nov 2021 23:20:06 -0500 Subject: [PATCH 05/43] Update _permanent.py Used black and pylint --- thewalrus/_permanent.py | 50 +++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 27 deletions(-) diff --git a/thewalrus/_permanent.py b/thewalrus/_permanent.py index f1c6f0c41..cfdbb7f62 100644 --- a/thewalrus/_permanent.py +++ b/thewalrus/_permanent.py @@ -15,18 +15,17 @@ Permanent Python interface """ import numpy as np - -from ._hafnian import hafnian_repeated -from .libwalrus import perm_complex, perm_real, perm_BBFG_real, perm_BBFG_complex from numba import jit +from ._hafnian import hafnian_repeated +# from .libwalrus import perm_complex, perm_real, perm_BBFG_real, perm_BBFG_complex + +# pylint: disable = C0103, R0914 def perm(A, quad=True, fsum=False, method="bbfg"): """Returns the permanent of a matrix using the `method` formula - For more direct control, you may wish to call :func:`perm_real` or :func:`perm_complex` directly. - Args: A (array): a square array. quad (bool): If ``True``, the input matrix is cast to a ``long double`` @@ -35,10 +34,11 @@ def perm(A, quad=True, fsum=False, method="bbfg"): Note that if ``fsum`` is true, double precision will be used, and the ``quad`` keyword argument will be ignored. method (string): "ryser" calls the associated methods to - `Ryser formula `_, + `Ryser formula + `_, and "bbfg" calls the associated methods to - `BBFG formula `_. - + `BBFG formula + `_. Returns: np.float64 or np.complex128: the permanent of matrix A. """ @@ -68,27 +68,30 @@ def perm(A, quad=True, fsum=False, method="bbfg"): ) isRyser = bool(method != "bbfg") - + return perm_ryser(A) if isRyser else perm_bbfg(A) + @jit(nopython=True) def perm_ryser(M): """ Returns the permanent of a matrix using the Ryser formula in Gray ordering - - The code is an re-implementation from a Python 2 code found in - `Permanent code golf `_ using numba. - + + The code is an re-implementation from a Python 2 code found in + `Permanent code golf + `_ + using numba. + Args: M (array) : a square array. - + Returns: np.float64 or np.complex128: the permanent of matrix M. """ # Raises an error if the matrix is not square (a, b) = M.shape if a != b: - raise Exception('Not a square matrix') + raise Exception("Not a square matrix") n = len(M) # row_comb keeps the sum of previous subsets. # Every iteration, it removes a term and/or adds a new term @@ -97,36 +100,34 @@ def perm_ryser(M): total = 0 old_grey = 0 sign = +1 - binary_power_dict = [2**i for i in range(n)] + binary_power_dict = [2 ** i for i in range(n)] num_loops = 2 ** n for k in range(0, num_loops): - bin_index = ((k+1) % num_loops) + bin_index = (k + 1) % num_loops reduced = np.prod(row_comb) total += sign * reduced new_grey = bin_index ^ (bin_index // 2) grey_diff = old_grey ^ new_grey grey_diff_index = binary_power_dict.index(grey_diff) new_vector = M[grey_diff_index] - direction = (old_grey > new_grey) - (old_grey < new_grey) + direction = (old_grey > new_grey) - (old_grey < new_grey) for i in range(n): row_comb[i] += new_vector[i] * direction sign = -sign old_grey = new_grey return total + @jit(nopython=True) def perm_bbfg(M): """ Returns the permanent of a matrix using the bbfg formula in Gray ordering - The code is a re-implementation from a Python 2 code found in `Permanent code golf `_ using numba. - Args: M (array) : a square array. - Returns: np.float64 or np.complex128: the permanent of a matrix M. """ @@ -156,23 +157,18 @@ def perm_bbfg(M): old_gray = new_gray return total / num_loops + def permanent_repeated(A, rpt): r"""Calculates the permanent of matrix :math:`A`, where the ith row/column of :math:`A` is repeated :math:`rpt_i` times. - This function constructs the matrix - .. math:: B = \begin{bmatrix} 0 & A\\ A^T & 0 \end{bmatrix}, - and then calculates :math:`perm(A)=haf(B)`, by calling - >>> hafnian_repeated(B, rpt*2, loop=False) - Args: A (array): matrix of size [N, N] rpt (Sequence): sequence of N positive integers indicating the corresponding rows/columns of A to be repeated. - Returns: np.int64 or np.float64 or np.complex128: the permanent of matrix A. """ From 4ca787d70d377fd6ff1e7f45d772f5afdf58d903 Mon Sep 17 00:00:00 2001 From: JQZ1111 <75086618+JQZ1111@users.noreply.github.com> Date: Mon, 15 Nov 2021 10:44:36 -0500 Subject: [PATCH 06/43] Update libwalrus.pyx --- thewalrus/libwalrus.pyx | 6 ------ 1 file changed, 6 deletions(-) diff --git a/thewalrus/libwalrus.pyx b/thewalrus/libwalrus.pyx index d8321ea16..d9da3d9b5 100644 --- a/thewalrus/libwalrus.pyx +++ b/thewalrus/libwalrus.pyx @@ -33,12 +33,6 @@ cdef extern from "../include/libwalrus.hpp" namespace "libwalrus": T hafnian_rpt[T](vector[T] &mat, vector[int] &nud) T loop_hafnian_rpt[T](vector[T] &mat, vector[T] &mu, vector[int] &nud) - double permanent_quad(vector[double] &mat) - double complex permanent_quad(vector[double complex] &mat) - double perm_fsum[T](vector[T] &mat) - double permanent_fsum(vector[double] &mat) - double perm_BBFG_qp(vector[double] &mat) - double complex perm_BBFG_cmplx(vector[double complex] &mat) double hafnian_recursive_quad(vector[double] &mat) double complex hafnian_recursive_quad(vector[double complex] &mat) From 576b7cc8539230c874d71096eee454504db26177 Mon Sep 17 00:00:00 2001 From: JQZ1111 <75086618+JQZ1111@users.noreply.github.com> Date: Mon, 15 Nov 2021 10:52:53 -0500 Subject: [PATCH 07/43] Update libwalrus.pyx --- thewalrus/libwalrus.pyx | 95 ----------------------------------------- 1 file changed, 95 deletions(-) diff --git a/thewalrus/libwalrus.pyx b/thewalrus/libwalrus.pyx index d9da3d9b5..4b5b6478f 100644 --- a/thewalrus/libwalrus.pyx +++ b/thewalrus/libwalrus.pyx @@ -235,98 +235,3 @@ def haf_real(double[:, :] A, bint loop=False, bint recursive=True, quad=True, bi -# ============================================================================== -# Permanent - -def perm_complex(double complex[:, :] A, quad=True): - """Returns the hafnian of a complex matrix A via the C++ libwalrus library. - - Args: - A (array): a np.float, square array - quad (bool): If ``True``, the input matrix is cast to a ``long double complex`` - matrix internally for a quadruple precision hafnian computation. - - Returns: - np.complex128: the hafnian of matrix A - """ - cdef int i, j, n = A.shape[0] - cdef vector[double complex] mat - - for i in range(n): - for j in range(n): - mat.push_back(A[i, j]) - - # Exposes a c function to python - if quad: - return permanent_quad(mat) - - return permanent(mat) - -def perm_real(double [:, :] A, quad=True, fsum=False): - """Returns the hafnian of a real matrix A via the C++ libwalrus library. - - Args: - A (array): a np.float64, square array - quad (bool): If ``True``, the input matrix is cast to a ``long double`` - matrix internally for a quadruple precision hafnian computation. - fsum (bool): If ``True``, ``fsum`` method is used for summation. - - - Returns: - np.float64: the hafnian of matrix A - """ - cdef int i, j, n = A.shape[0] - cdef vector[double] mat - - for i in range(n): - for j in range(n): - mat.push_back(A[i, j]) - - if fsum: - return permanent_fsum(mat) - - # Exposes a c function to python - if quad: - return permanent_quad(mat) - - return permanent(mat) - -def perm_BBFG_complex(double complex[:, :] A): - """Returns the hafnian of a complex matrix A via the C++ libwalrus library - using Balasubramanian-Bax-Franklin-Glynn formula. - - Args: - A (array): a np.float, square array - - Returns: - np.complex128: the hafnian of matrix A - """ - cdef int i, j, n = A.shape[0] - cdef vector[double complex] mat - - for i in range(n): - for j in range(n): - mat.push_back(A[i, j]) - - # Exposes a c function to python - return perm_BBFG_cmplx(mat) - -def perm_BBFG_real(double [:, :] A): - """Returns the hafnian of a real matrix A via the C++ libwalrus library - using Balasubramanian-Bax-Franklin-Glynn formula. - - Args: - A (array): a np.float64, square array - - Returns: - np.float64: the hafnian of matrix A - """ - cdef int i, j, n = A.shape[0] - cdef vector[double] mat - - for i in range(n): - for j in range(n): - mat.push_back(A[i, j]) - - # Exposes a c function to python - return perm_BBFG_qp(mat) From d7bf16cabde8df82cc5d8a2bd7e8a40501d85840 Mon Sep 17 00:00:00 2001 From: benjaminlanthier <91567620+benjaminlanthier@users.noreply.github.com> Date: Mon, 15 Nov 2021 10:53:48 -0500 Subject: [PATCH 08/43] Update test_permanent.py Removed imports of "perm_real", "perm_complex", "perm_BBFG_real" and "perm_BBFG_complex". --- thewalrus/tests/test_permanent.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/thewalrus/tests/test_permanent.py b/thewalrus/tests/test_permanent.py index c553868a8..7018c4b6d 100644 --- a/thewalrus/tests/test_permanent.py +++ b/thewalrus/tests/test_permanent.py @@ -20,11 +20,11 @@ from thewalrus import ( perm, - perm_real, - perm_complex, + #perm_real, + #perm_complex, permanent_repeated, - perm_BBFG_real, - perm_BBFG_complex, + #perm_BBFG_real, + #perm_BBFG_complex, ) From f4e53a88da74c6a5abb86829e87ed35ef672df7f Mon Sep 17 00:00:00 2001 From: JQZ1111 <75086618+JQZ1111@users.noreply.github.com> Date: Mon, 15 Nov 2021 10:56:22 -0500 Subject: [PATCH 09/43] Update __init__.py --- thewalrus/__init__.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/thewalrus/__init__.py b/thewalrus/__init__.py index 0a9491ef1..7b37010d2 100644 --- a/thewalrus/__init__.py +++ b/thewalrus/__init__.py @@ -126,12 +126,9 @@ ) from ._permanent import ( perm, - perm_complex, - perm_real, - permanent_repeated, - perm_BBFG_real, - perm_BBFG_complex, + permanent_repeated ) + from ._torontonian import ( tor, threshold_detection_prob_displacement, From 282b8b45abcecee3909a12651c76a7a025ac02cf Mon Sep 17 00:00:00 2001 From: Brandon Date: Mon, 15 Nov 2021 10:56:28 -0500 Subject: [PATCH 10/43] Removed the 'quad' and the 'fsum' options --- thewalrus/_permanent.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/thewalrus/_permanent.py b/thewalrus/_permanent.py index cfdbb7f62..2fe070a2f 100644 --- a/thewalrus/_permanent.py +++ b/thewalrus/_permanent.py @@ -22,17 +22,12 @@ # pylint: disable = C0103, R0914 -def perm(A, quad=True, fsum=False, method="bbfg"): +def perm(A, method="bbfg"): """Returns the permanent of a matrix using the `method` formula For more direct control, you may wish to call :func:`perm_real` or :func:`perm_complex` directly. Args: A (array): a square array. - quad (bool): If ``True``, the input matrix is cast to a ``long double`` - matrix internally for a quadruple precision hafnian computation. - fsum (bool): Whether to use the ``fsum`` method for higher accuracy summation. - Note that if ``fsum`` is true, double precision will be used, and the - ``quad`` keyword argument will be ignored. method (string): "ryser" calls the associated methods to `Ryser formula `_, From dfd9cc543687ae56acd679579beae9e85692b89d Mon Sep 17 00:00:00 2001 From: benjaminlanthier <91567620+benjaminlanthier@users.noreply.github.com> Date: Mon, 15 Nov 2021 10:57:43 -0500 Subject: [PATCH 11/43] Update test_permanent.py Corrected function names to be only perm. --- thewalrus/tests/test_permanent.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/thewalrus/tests/test_permanent.py b/thewalrus/tests/test_permanent.py index 7018c4b6d..bec7b0f3a 100644 --- a/thewalrus/tests/test_permanent.py +++ b/thewalrus/tests/test_permanent.py @@ -27,6 +27,11 @@ #perm_BBFG_complex, ) +perm_real = perm +perm_complex = perm +perm_BBFG_real = perm +perm_BBFG_complex = perm + class TestPermanentWrapper: """Tests for the Permanent function""" From bf71bd0d5f95dce19b056b4e0c367c2c28bc92b7 Mon Sep 17 00:00:00 2001 From: JQZ1111 <75086618+JQZ1111@users.noreply.github.com> Date: Mon, 15 Nov 2021 17:28:31 -0500 Subject: [PATCH 12/43] Update libwalrus.hpp Removed #include --- include/libwalrus.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/include/libwalrus.hpp b/include/libwalrus.hpp index 2d82eabf2..abe586574 100644 --- a/include/libwalrus.hpp +++ b/include/libwalrus.hpp @@ -16,7 +16,6 @@ #include #include #include -#include /** * @namespace libwalrus From 1f075c434f72b933b81acdc375c040c04dc367a2 Mon Sep 17 00:00:00 2001 From: JQZ1111 <75086618+JQZ1111@users.noreply.github.com> Date: Mon, 15 Nov 2021 17:31:58 -0500 Subject: [PATCH 13/43] Remove previous c++ permanent implementations --- thewalrus/_permanent.py | 1 - 1 file changed, 1 deletion(-) diff --git a/thewalrus/_permanent.py b/thewalrus/_permanent.py index 2fe070a2f..3f0d8d9ff 100644 --- a/thewalrus/_permanent.py +++ b/thewalrus/_permanent.py @@ -17,7 +17,6 @@ import numpy as np from numba import jit from ._hafnian import hafnian_repeated -# from .libwalrus import perm_complex, perm_real, perm_BBFG_real, perm_BBFG_complex # pylint: disable = C0103, R0914 From 5f739bdecde26043e22aafbc722af42545e1f575 Mon Sep 17 00:00:00 2001 From: Dominic Date: Mon, 15 Nov 2021 17:35:28 -0500 Subject: [PATCH 14/43] Remove the file permanent.hpp --- include/permanent.hpp | 598 ------------------------------------------ 1 file changed, 598 deletions(-) delete mode 100644 include/permanent.hpp diff --git a/include/permanent.hpp b/include/permanent.hpp deleted file mode 100644 index 32490b9d3..000000000 --- a/include/permanent.hpp +++ /dev/null @@ -1,598 +0,0 @@ -// Copyright 2019 Xanadu Quantum Technologies Inc. - -// 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. -#pragma once -#include -#include -#include -#include "fsum.hpp" - -typedef unsigned long long int ullint; -typedef long long int llint; -//typedef long double qp; - -#if (defined(__GNUC__) || defined(__GNUG__)) && !(defined(__clang__) || defined(__INTEL_COMPILER)) -typedef __float128 qp; -//#include -#else -typedef long double qp; -#endif - -/** - * Gray code generator. - * - * @param n - * @return the corresponding Gray code - */ -static inline llint igray(llint n) -{ - /* Right Shift the number by 1 - taking xor with original number */ - return n ^ (n >> 1); -} - -/** - * Returns left most set bit. - * - * @param n - * @return the left most set bit - */ -static inline int left_most_set_bit(llint n) -{ - if (n == 0) - return 0; - - int msb = 0; - - while (n != 0) { - n = n / 2; - msb++; - } - return msb; -} - - -/** - * Decimal to binary conversion - * - * @param \f$k\f$ - * @param \f$n\f$ - * @return \f$n\f$ bit binary representation of integer \f$k\f$ - */ -static inline std::vector dec2bin(llint &k, int &n) -{ - llint kk = k; - int i = n; - std::vector mat(n, 0); - - while ( kk > 0 && i > 0 ) { - mat[i-1] = kk % 2; - kk = kk/2; - i = i-1; - } - return mat; -} - -/** - * Get the next ordering index - * - * @param \f$l\f$ - * @param \f$k\f$ - * @return the \f$k+1\f$-th ordering index with updating \f$l\f$ from init index \f$k\f$ - */ -static inline size_t next_perm_ordering_index(std::vector &l, size_t k) -{ - l[0] = 0; - l[k] = l[k+1]; - l[k+1] = k+1; - return l[0]; -} - -namespace libwalrus { - -/** - * Returns the permanent of a matrix. - * - * \rst - * - * Returns the permanent of a matrix using Ryser's algorithm - * with Gray code ordering, that has a time-complexity of \f$O(n 2^n)\f$ - * - * \endrst - * - * - * @tparam T type of the matrix data - * @param mat a flattened vector of size \f$n^2\f$, representing an - * \f$n\times n\f$ row-ordered symmetric matrix. - * @return permanent of the input matrix - */ -template -inline T permanent(std::vector &mat) -{ - int n = std::sqrt(static_cast(mat.size())); - llint x = static_cast(pow(2,n) - 1) ; - -#ifdef _OPENMP - int nthreads = omp_get_max_threads(); - omp_set_num_threads(nthreads); -#else - int nthreads = 1; -#endif - - std::vector tot(nthreads, static_cast(0)); - - std::vector threadbound_low(nthreads); - std::vector threadbound_hi(nthreads); - - for (int i=0; i < nthreads; i++) { - threadbound_low[i] = i*x/nthreads; - threadbound_hi[i] = (i+1)*x/nthreads; - } - threadbound_hi[nthreads-1] = x; - - #pragma omp parallel for shared(tot) - for (int ii = 0; ii < nthreads; ii++) { - T permtmp = static_cast(0); - int cntr = 0; - std::vector chitmp(n, 0); - std::vector tmp(n, static_cast(0)); - - for (llint k = threadbound_low[ii]; k < threadbound_hi[ii]; k++) { - T rowsumprod = static_cast(1); - llint kg2 = igray(k+1); - llint sgntmp = kg2 - igray(k); - llint sig = sgntmp/std::abs(sgntmp); - int pos = n - left_most_set_bit(sgntmp); - - if ( k == threadbound_low[ii] ) { - chitmp = dec2bin(kg2, n); - - // loop rows of the k-th submatrix - for ( int j = 0; j < n; j++) { - T localsum = static_cast(0); - for (int id = 0; id < n; id++) { - localsum += static_cast(chitmp[id]) * mat[id*n+j]; - } - tmp[j] += localsum; - - // update product of row sums - rowsumprod *= tmp[j]; - } - - cntr = static_cast(std::accumulate(chitmp.begin(), chitmp.end(), 0)); - } - else { - cntr += sig; - - for(int j = 0; j < n; j++ ) { - if (sig < 0) - tmp[j] -= mat[pos * n + j]; - else - tmp[j] += mat[pos * n + j]; - - rowsumprod *= tmp[j]; - } - } - - if ( (static_cast(n)-cntr) % 2 == 0) - permtmp += rowsumprod; - else - permtmp -= rowsumprod; - - } - tot[ii] = permtmp; - } - - return static_cast(std::accumulate(tot.begin(), tot.end(), static_cast(0))); -} - -/** - * Returns the permanent of a matrix using fsum. - * - * \rst - * - * Returns the permanent of a matrix using Ryser's algorithm - * with Gray code ordering. - * - * \endrst - * - * - * @tparam T type of the matrix data - * @param mat a flattened vector of size \f$n^2\f$, representing an - * \f$n\times n\f$ row-ordered symmetric matrix. - * @return permanent of the input matrix - */ -template -inline double perm_fsum(std::vector &mat) -{ - int n = std::sqrt(static_cast(mat.size())); - llint x = static_cast(pow(2,n) - 1) ; - -#ifdef _OPENMP - int nthreads = omp_get_max_threads(); - omp_set_num_threads(nthreads); -#else - int nthreads = 1; -#endif - - std::vector tot(nthreads, static_cast(0)); - - std::vector threadbound_low(nthreads); - std::vector threadbound_hi(nthreads); - - for (int i=0; i < nthreads; i++) { - threadbound_low[i] = i*x/nthreads; - threadbound_hi[i] = (i+1)*x/nthreads; - } - threadbound_hi[nthreads-1] = x; - - #pragma omp parallel for shared(tot) - for (int ii = 0; ii < nthreads; ii++) { - - fsum::sc_partials permtmp; // = 0; - - int cntr = 0; - std::vector chitmp(n, 0); - std::vector tmp(n, static_cast(0)); - - for (llint k = threadbound_low[ii]; k < threadbound_hi[ii]; k++) { - T rowsumprod = static_cast(1); - llint kg2 = igray(k+1); - llint sgntmp = kg2 - igray(k); - llint sig = sgntmp/std::abs(sgntmp); - int pos = 0; - - pos = n - left_most_set_bit(sgntmp); - - if ( k == threadbound_low[ii] ) { - chitmp = dec2bin(kg2, n); - - for ( int j = 0; j < n; j++) { - fsum::sc_partials localsum; //= static_cast(0); - for (int id = 0; id < n; id++) { - localsum += static_cast(chitmp[id]) * mat[id*n+j]; - } - tmp[j] += localsum; - rowsumprod *= tmp[j]; - } - - cntr = static_cast(std::accumulate(chitmp.begin(), chitmp.end(), 0)); - } - else { - cntr += sig; - - for(int j = 0; j < n; j++ ) { - if (sig < 0) - tmp[j] -= mat[pos * n + j]; - else - tmp[j] += mat[pos * n + j]; - - rowsumprod *= tmp[j]; - } - } - - if ( (static_cast(n)-cntr) % 2 == 0) - permtmp += rowsumprod; - else - permtmp -= rowsumprod; - - } - tot[ii] = permtmp; - } - return static_cast(std::accumulate(tot.begin(), tot.end(), static_cast(0))); -} - -/** - * \rst - * - * Returns the permanent of a matrix using the Ryser's algo - * with Gray code ordering - * - * \endrst - * - * - * This is a wrapper around the templated function `libwalrus::permanent` - * for Python integration. It accepts and returns complex double numeric types, - * and returns sensible values for empty and non-even matrices. - * - * In addition, this wrapper function automatically casts all matrices - * to type `complex`, allowing for greater precision than - * supported by Python and NumPy. - * - * - * @param mat vector representing the flattened matrix - * @return the permanent - */ -std::complex permanent_quad(std::vector> &mat) -{ - std::vector> matq(mat.begin(), mat.end()); - std::complex perm = permanent(matq); - return static_cast>(perm); -} - -/** - * \rst - * - * Returns the permanent of a matrix using Ryser's algo - * with Gray code ordering - * - * \endrst - * - * - * This is a wrapper around the templated function `libwalrus::permanent` - * for Python integration. It accepts and returns double numeric types, - * and returns sensible values for empty and non-even matrices. - * - * In addition, this wrapper function automatically casts all matrices - * to type `long double`, allowing for greater precision than supported - * by Python and NumPy. - * - * - * @param mat vector representing the flattened matrix - * @return the permanent - */ -double permanent_quad(std::vector &mat) -{ - std::vector matq(mat.begin(), mat.end()); - qp perm = permanent(matq); - return static_cast(perm); -} - -/** - * \rst - * - * Returns the permanent of a matrix using Ryser's algo - * with Gray code ordering with fsum - * - * \endrst - * - * - * This is a wrapper around the templated function `libwalrus::perm_fsum` - * for Python integration. It accepts and returns double numeric types, - * and returns sensible values for empty and non-even matrices. - * - * - * @param mat vector representing the flattened matrix - * @return the permanent - */ -double permanent_fsum(std::vector &mat) -{ - std::vector matq(mat.begin(), mat.end()); - double perm = perm_fsum(matq); - return static_cast(perm); -} - - -/** - * Returns the permanent of a matrix (nthreads=1) - * - * \rst - * - * Returns the permanent of a matrix using the BBFG algorithm. - * This algorithm was given by Glynn (2010) with the time-complexity - * of \f$O(n 2^n)\f$ using Gray code ordering. - * - * \endrst - * - * - * @tparam T type of the matrix data - * @param mat a flattened vector of size \f$n^2\f$, representing an - * \f$n\times n\f$ row-ordered symmetric matrix. - * @return permanent of the input matrix - */ -template -inline T perm_BBFG_serial(std::vector &mat) -{ - const size_t n = static_cast(std::sqrt(static_cast(mat.size()))); - const double p = pow(2, n-1); - const ullint x = static_cast(p); - if (p != x) { - std::cerr << "overflow to inf" << std::endl; - exit(EXIT_FAILURE); - } - - constexpr T p1 = static_cast(1.0); - constexpr T p2 = static_cast(2.0); - constexpr T n2 = static_cast(-2.0); - constexpr T zero = static_cast(0); - - size_t i, j; - std::vector colsum(n, zero); - // init colsum - for (i=0; i < n; ++i) { - for (j=0; j < n; ++j) { - colsum[i] += mat[j*n + i]; - } - } - - T mulcolsum, coeff; - T total = zero; - ullint k, og=0, ng, gd; - int sgn=1, gdi; - - // over all 2^{n-1} permutations of delta - for (k=1; k < x+1; ++k) { - mulcolsum = std::accumulate( - colsum.begin(), - colsum.end(), - p1, - std::multiplies()); - total += sgn > 0 ? mulcolsum : -mulcolsum; - - // updating gray order - ng = igray(k); - gd = og ^ ng; - - coeff = og > ng ? p2 : n2; - gdi = left_most_set_bit(gd); - for (j=0; j < n; ++j) { - colsum[j] += coeff * mat[gdi * n + j]; - } - - sgn = -sgn; - og = ng; - } - - return total / static_cast(x); -} - -/** - * Returns the permanent of a matrix (nthreads=1) (2nd version) - * - * \rst - * - * Returns the permanent of a matrix using the BBFG algorithm. - * This algorithm was given by Glynn (2010) with the time-complexity - * of \f$O(n 2^n)\f$ using Gray code ordering. - * - * \endrst - * - * - * @tparam T type of the matrix data - * @param mat a flattened vector of size \f$n^2\f$, representing an - * \f$n\times n\f$ row-ordered symmetric matrix. - * @return permanent of the input matrix - */ -template -inline T perm_BBFG_serial2(std::vector &mat) -{ - const size_t n = static_cast(std::sqrt(static_cast(mat.size()))); - const long double p = pow(2, n-1); - const T x = static_cast(p); - if (p == HUGE_VAL || p != x) { - std::cerr << "overflow to inf" << std::endl; - exit(EXIT_FAILURE); - } - - constexpr T p2 = static_cast(2.0); - constexpr T p1 = static_cast(1.0); - constexpr T zero = static_cast(0); - - std::vector grays(n); - std::iota(grays.begin(), grays.end(), 0); - std::vector coeffs(n, p2); - std::vector colsum(n, zero); - T mulcolsum, total = p1; - size_t i, j, k=0; - int sgn=1; - - // init colsum - for (i=0; i < n; ++i) { - for (j=0; j < n; ++j) { - colsum[i] += mat[j*n + i]; - } - total *= colsum[i]; - } - - while (k < n-1) { - for (j=0; j < n; ++j) { - colsum[j] -= coeffs[k] * mat[k*n+j]; - } - - mulcolsum = std::accumulate( - colsum.begin(), - colsum.end(), - p1, - std::multiplies()); - - coeffs[k] = -coeffs[k]; - sgn = -sgn; - total += sgn > 0 ? mulcolsum : -mulcolsum; - k = next_perm_ordering_index(grays, k); - } - - return total / x; -} - -/** - * Returns the permanent of a matrix - * - * \rst - * - * Returns the permanent of a matrix using the BBFG algorithm. - * This algorithm was given by Glynn (2010) with the time-complexity - * of \f$O(n 2^n)\f$ using Gray code ordering. - * - * \endrst - * - * This is a wrapper function for computing permanent of a matrix - * based on Balasubramanian-Bax-Franklin-Glynn (BBFG) formula. - * - * - * @tparam T type of the matrix data - * @param mat a flattened vector of size \f$n^2\f$, representing an - * \f$n\times n\f$ row-ordered symmetric matrix. - * @return permanent of the input matrix - */ -template -inline T perm_BBFG(std::vector &mat) { - return perm_BBFG_serial2(mat); -} - -/** - * \rst - * - * Returns the permanent of a matrix using the BBFG formula. - * This algorithm was given by Glynn (2010) with the time-complexity - * of \f$O(n 2^n)\f$ using Gray code ordering. - * - * \endrst - * - * This is a wrapper around the templated function `libwalrus::perm_BBFG` - * for Python integration. It accepts and returns double numeric types, - * and returns sensible values for empty and non-even matrices. - * - * In addition, this wrapper function automatically casts all matrices - * to type `long double`, allowing for greater precision than supported - * by Python and NumPy. - * - * - * @param mat vector representing the flattened matrix - * @return the permanent - */ -double perm_BBFG_qp(std::vector &mat) -{ - std::vector matqp(mat.begin(), mat.end()); - qp perm = perm_BBFG(matqp); - return static_cast(perm); -} - -/** - * \rst - * - * Returns the permanent of a matrix using the BBFG formula. - * This algorithm was given by Glynn (2010) with the time-complexity - * of \f$O(n 2^n)\f$ using Gray code ordering. - * - * \endrst - * - * This is a wrapper around the templated function `libwalrus::perm_BBFG` - * for Python integration. It accepts and returns complex double numeric types, - * and returns sensible values for empty and non-even matrices. - * - * In addition, this wrapper function automatically casts all matrices - * to type `complex`, allowing for greater precision than - * supported by Python and NumPy. - * - * - * @param mat vector representing the flattened matrix - * @return the permanent - */ -std::complex perm_BBFG_cmplx(std::vector> &mat) -{ - std::vector> matx(mat.begin(), mat.end()); - std::complex perm = perm_BBFG(matx); - return static_cast>(perm); -} - -} From 1de72eb5a0260e56e2f079b1504191cecd5d1504 Mon Sep 17 00:00:00 2001 From: ben Date: Mon, 15 Nov 2021 20:01:21 -0500 Subject: [PATCH 15/43] Applied black and used pytest --- thewalrus/tests/test_permanent.py | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/thewalrus/tests/test_permanent.py b/thewalrus/tests/test_permanent.py index bec7b0f3a..15345f20a 100644 --- a/thewalrus/tests/test_permanent.py +++ b/thewalrus/tests/test_permanent.py @@ -18,14 +18,7 @@ import numpy as np from scipy.special import factorial as fac -from thewalrus import ( - perm, - #perm_real, - #perm_complex, - permanent_repeated, - #perm_BBFG_real, - #perm_BBFG_complex, -) +from thewalrus import perm, permanent_repeated perm_real = perm perm_complex = perm From 367ed3b9e5ec9c46de6ab349e4d905ba50183bd5 Mon Sep 17 00:00:00 2001 From: ben Date: Mon, 15 Nov 2021 20:05:32 -0500 Subject: [PATCH 16/43] Applied black --- thewalrus/__init__.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/thewalrus/__init__.py b/thewalrus/__init__.py index 7b37010d2..c4aa14722 100644 --- a/thewalrus/__init__.py +++ b/thewalrus/__init__.py @@ -124,10 +124,7 @@ interferometer, grad_hermite_multidimensional, ) -from ._permanent import ( - perm, - permanent_repeated -) +from ._permanent import perm, permanent_repeated from ._torontonian import ( tor, From 4e587470e06bf4d797661fa23aec81eef904a667 Mon Sep 17 00:00:00 2001 From: JQZ1111 <75086618+JQZ1111@users.noreply.github.com> Date: Mon, 15 Nov 2021 20:16:58 -0500 Subject: [PATCH 17/43] Put into comment all permanent --- tests/libwalrus_unittest.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/tests/libwalrus_unittest.cpp b/tests/libwalrus_unittest.cpp index d64859343..e9aacbcf9 100644 --- a/tests/libwalrus_unittest.cpp +++ b/tests/libwalrus_unittest.cpp @@ -20,6 +20,7 @@ const double tol = 1.0e-10f; const double tol2 = 1.0e-7f; +/* namespace permanent { TEST(PermanentRealFsum, CompleteGraph) { @@ -50,7 +51,7 @@ TEST(PermanentFsum, Random) { mat[2] * mat[3] * mat[7] + mat[0] * mat[5] * mat[7] + mat[1] * mat[3] * mat[8] + mat[0] * mat[4] * mat[8]; - EXPECT_NEAR(expected, libwalrus::permanent_fsum(mat), tol); + //EXPECT_NEAR(expected, libwalrus::permanent_fsum(mat), tol); } TEST(PermanentReal, CompleteGraph) { @@ -58,9 +59,9 @@ TEST(PermanentReal, CompleteGraph) { std::vector mat3(9, 1.0); std::vector mat4(16, 1.0); - EXPECT_NEAR(2, libwalrus::permanent_quad(mat2), tol); - EXPECT_NEAR(6, libwalrus::permanent_quad(mat3), tol); - EXPECT_NEAR(24, libwalrus::permanent_quad(mat4), tol); + //EXPECT_NEAR(2, libwalrus::permanent_quad(mat2), tol); + //EXPECT_NEAR(6, libwalrus::permanent_quad(mat3), tol); + //EXPECT_NEAR(24, libwalrus::permanent_quad(mat4), tol); } TEST(PermanentReal, Random) { @@ -169,7 +170,7 @@ TEST(PermanentComplexBBFG, Random) { } } // namespace permanent - +*/ namespace recursive_real { // Unit tests for the real recursive_hafnian function From 20fec8904c7619b5466cbecc40f85bf879def223 Mon Sep 17 00:00:00 2001 From: JQZ1111 <75086618+JQZ1111@users.noreply.github.com> Date: Mon, 15 Nov 2021 20:42:43 -0500 Subject: [PATCH 18/43] Remove permanents C++ tests --- tests/libwalrus_unittest.cpp | 154 +---------------------------------- 1 file changed, 2 insertions(+), 152 deletions(-) diff --git a/tests/libwalrus_unittest.cpp b/tests/libwalrus_unittest.cpp index e9aacbcf9..e90d7dca6 100644 --- a/tests/libwalrus_unittest.cpp +++ b/tests/libwalrus_unittest.cpp @@ -9,7 +9,8 @@ // 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 +// See the License for the specific language governing +issions and // limitations under the License. #include #include @@ -20,157 +21,6 @@ const double tol = 1.0e-10f; const double tol2 = 1.0e-7f; -/* -namespace permanent { - -TEST(PermanentRealFsum, CompleteGraph) { - std::vector mat2(4, 1.0); - std::vector mat3(9, 1.0); - std::vector mat4(16, 1.0); - - EXPECT_NEAR(2, libwalrus::permanent_fsum(mat2), tol); - EXPECT_NEAR(6, libwalrus::permanent_fsum(mat3), tol); - EXPECT_NEAR(24, libwalrus::permanent_fsum(mat4), tol); -} - -TEST(PermanentFsum, Random) { - std::vector mat(9, 1.0); - - std::default_random_engine generator; - generator.seed(20); - std::normal_distribution distribution(0.0, 1.0); - - for (int i = 0; i < 3; i++) { - for (int j = 0; j < 3; j++) { - double randnum = distribution(generator); - mat[i * 3 + j] = randnum; - } - } - - double expected = mat[2] * mat[4] * mat[6] + mat[1] * mat[5] * mat[6] + - mat[2] * mat[3] * mat[7] + mat[0] * mat[5] * mat[7] + - mat[1] * mat[3] * mat[8] + mat[0] * mat[4] * mat[8]; - - //EXPECT_NEAR(expected, libwalrus::permanent_fsum(mat), tol); -} - -TEST(PermanentReal, CompleteGraph) { - std::vector mat2(4, 1.0); - std::vector mat3(9, 1.0); - std::vector mat4(16, 1.0); - - //EXPECT_NEAR(2, libwalrus::permanent_quad(mat2), tol); - //EXPECT_NEAR(6, libwalrus::permanent_quad(mat3), tol); - //EXPECT_NEAR(24, libwalrus::permanent_quad(mat4), tol); -} - -TEST(PermanentReal, Random) { - std::vector mat(9, 1.0); - - std::default_random_engine generator; - generator.seed(20); - std::normal_distribution distribution(0.0, 1.0); - - for (int i = 0; i < 3; i++) { - for (int j = 0; j < 3; j++) { - double randnum = distribution(generator); - mat[i * 3 + j] = randnum; - } - } - - double expected = mat[2] * mat[4] * mat[6] + mat[1] * mat[5] * mat[6] + - mat[2] * mat[3] * mat[7] + mat[0] * mat[5] * mat[7] + - mat[1] * mat[3] * mat[8] + mat[0] * mat[4] * mat[8]; - - EXPECT_NEAR(expected, libwalrus::permanent_quad(mat), tol); -} - -TEST(PermanentComplex, Random) { - std::vector> mat(9, 1.0); - - std::default_random_engine generator; - generator.seed(20); - std::normal_distribution distribution(0.0, 1.0); - - for (int i = 0; i < 3; i++) { - for (int j = 0; j < 3; j++) { - double randnum1 = distribution(generator); - double randnum2 = distribution(generator); - mat[i * 3 + j] = std::complex(randnum1, randnum2); - } - } - - std::complex expected = - mat[2] * mat[4] * mat[6] + mat[1] * mat[5] * mat[6] + - mat[2] * mat[3] * mat[7] + mat[0] * mat[5] * mat[7] + - mat[1] * mat[3] * mat[8] + mat[0] * mat[4] * mat[8]; - - std::complex perm = libwalrus::permanent_quad(mat); - - EXPECT_NEAR(std::real(expected), std::real(perm), tol); - EXPECT_NEAR(std::imag(expected), std::imag(perm), tol); -} - -TEST(PermanentRealBBFG, CompleteGraph) { - std::vector mat2(4, 1.0); - std::vector mat3(9, 1.0); - std::vector mat4(16, 1.0); - - EXPECT_NEAR(2, libwalrus::perm_BBFG_qp(mat2), tol); - EXPECT_NEAR(6, libwalrus::perm_BBFG_qp(mat3), tol); - EXPECT_NEAR(24, libwalrus::perm_BBFG_qp(mat4), tol); -} - -TEST(PermanentRealBBFG, Random) { - std::vector mat(9, 1.0); - - std::default_random_engine generator; - generator.seed(20); - std::normal_distribution distribution(0.0, 1.0); - - for (int i = 0; i < 3; i++) { - for (int j = 0; j < 3; j++) { - double randnum = distribution(generator); - mat[i * 3 + j] = randnum; - } - } - - double expected = mat[2] * mat[4] * mat[6] + mat[1] * mat[5] * mat[6] + - mat[2] * mat[3] * mat[7] + mat[0] * mat[5] * mat[7] + - mat[1] * mat[3] * mat[8] + mat[0] * mat[4] * mat[8]; - - EXPECT_NEAR(expected, libwalrus::perm_BBFG_qp(mat), tol); -} - - -TEST(PermanentComplexBBFG, Random) { - std::vector> mat(9, 1.0); - - std::default_random_engine generator; - generator.seed(20); - std::normal_distribution distribution(0.0, 1.0); - - for (int i = 0; i < 3; i++) { - for (int j = 0; j < 3; j++) { - double randnum1 = distribution(generator); - double randnum2 = distribution(generator); - mat[i * 3 + j] = std::complex(randnum1, randnum2); - } - } - - std::complex expected = - mat[2] * mat[4] * mat[6] + mat[1] * mat[5] * mat[6] + - mat[2] * mat[3] * mat[7] + mat[0] * mat[5] * mat[7] + - mat[1] * mat[3] * mat[8] + mat[0] * mat[4] * mat[8]; - - std::complex perm = libwalrus::perm_BBFG_cmplx(mat); - - EXPECT_NEAR(std::real(expected), std::real(perm), tol); - EXPECT_NEAR(std::imag(expected), std::imag(perm), tol); -} - -} // namespace permanent -*/ namespace recursive_real { // Unit tests for the real recursive_hafnian function From 5bbd4f95799e9eb90fed8ec1a215ddaaa7677310 Mon Sep 17 00:00:00 2001 From: JQZ1111 <75086618+JQZ1111@users.noreply.github.com> Date: Mon, 15 Nov 2021 20:45:30 -0500 Subject: [PATCH 19/43] Remove C++ permanent --- thewalrus/libwalrus.pyx | 2 -- 1 file changed, 2 deletions(-) diff --git a/thewalrus/libwalrus.pyx b/thewalrus/libwalrus.pyx index 4b5b6478f..e0070308d 100644 --- a/thewalrus/libwalrus.pyx +++ b/thewalrus/libwalrus.pyx @@ -27,8 +27,6 @@ cdef extern from "../include/libwalrus.hpp" namespace "libwalrus": T hafnian[T](vector[T] &mat) T hafnian_recursive[T](vector[T] &mat) T loop_hafnian[T](vector[T] &mat) - T permanent[T](vector[T] &mat) - T perm_BBFG[T](vector[T] &mat) T hafnian_rpt[T](vector[T] &mat, vector[int] &nud) T loop_hafnian_rpt[T](vector[T] &mat, vector[T] &mu, vector[int] &nud) From ec172d8113778f0b42fcb39a21af8e04a2acd0a6 Mon Sep 17 00:00:00 2001 From: Nicolas Quesada <991946+nquesada@users.noreply.github.com> Date: Mon, 15 Nov 2021 20:48:55 -0500 Subject: [PATCH 20/43] Apply suggestions from code review --- tests/libwalrus_unittest.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/libwalrus_unittest.cpp b/tests/libwalrus_unittest.cpp index e90d7dca6..cbe8f2309 100644 --- a/tests/libwalrus_unittest.cpp +++ b/tests/libwalrus_unittest.cpp @@ -9,8 +9,7 @@ // 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 -issions and +// See the License for the specific language governing permissions and // limitations under the License. #include #include From 0f54091e87e670972817b7a804b654b8d11032ca Mon Sep 17 00:00:00 2001 From: Nicolas Quesada <991946+nquesada@users.noreply.github.com> Date: Mon, 15 Nov 2021 20:56:04 -0500 Subject: [PATCH 21/43] Apply suggestions from code review --- thewalrus/tests/test_permanent.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/thewalrus/tests/test_permanent.py b/thewalrus/tests/test_permanent.py index 15345f20a..935bf0206 100644 --- a/thewalrus/tests/test_permanent.py +++ b/thewalrus/tests/test_permanent.py @@ -22,8 +22,8 @@ perm_real = perm perm_complex = perm -perm_BBFG_real = perm -perm_BBFG_complex = perm +perm_BBFG_real = lambda x: perm(x, method='bbfg') +perm_BBFG_complex = lambda x: perm(x, method='bbfg') class TestPermanentWrapper: From 93c347d7551c18b4c5d4e4145060159fa3aba357 Mon Sep 17 00:00:00 2001 From: Nicolas Quesada Date: Mon, 15 Nov 2021 20:58:30 -0500 Subject: [PATCH 22/43] passes black --- thewalrus/tests/test_permanent.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/thewalrus/tests/test_permanent.py b/thewalrus/tests/test_permanent.py index 935bf0206..cc2fee075 100644 --- a/thewalrus/tests/test_permanent.py +++ b/thewalrus/tests/test_permanent.py @@ -22,8 +22,8 @@ perm_real = perm perm_complex = perm -perm_BBFG_real = lambda x: perm(x, method='bbfg') -perm_BBFG_complex = lambda x: perm(x, method='bbfg') +perm_BBFG_real = lambda x: perm(x, method="bbfg") +perm_BBFG_complex = lambda x: perm(x, method="bbfg") class TestPermanentWrapper: From b58cec8dc72a9d945afb2de030a6f72d9fb1dd47 Mon Sep 17 00:00:00 2001 From: benjaminlanthier <91567620+benjaminlanthier@users.noreply.github.com> Date: Tue, 16 Nov 2021 12:23:57 -0500 Subject: [PATCH 23/43] Update thewalrus/_permanent.py Co-authored-by: Josh Izaac --- thewalrus/_permanent.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/thewalrus/_permanent.py b/thewalrus/_permanent.py index 3f0d8d9ff..345e70bc5 100644 --- a/thewalrus/_permanent.py +++ b/thewalrus/_permanent.py @@ -22,7 +22,7 @@ def perm(A, method="bbfg"): - """Returns the permanent of a matrix using the `method` formula + """Returns the permanent of a matrix using various methods. For more direct control, you may wish to call :func:`perm_real` or :func:`perm_complex` directly. Args: From 70ed023964489725184600612c2ab29531006e92 Mon Sep 17 00:00:00 2001 From: benjaminlanthier <91567620+benjaminlanthier@users.noreply.github.com> Date: Tue, 16 Nov 2021 12:30:29 -0500 Subject: [PATCH 24/43] Update thewalrus/_permanent.py Co-authored-by: Josh Izaac --- thewalrus/_permanent.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/thewalrus/_permanent.py b/thewalrus/_permanent.py index 345e70bc5..7ca129848 100644 --- a/thewalrus/_permanent.py +++ b/thewalrus/_permanent.py @@ -27,7 +27,7 @@ def perm(A, method="bbfg"): or :func:`perm_complex` directly. Args: A (array): a square array. - method (string): "ryser" calls the associated methods to + method (string): Set this to ``"ryser"`` to use the `Ryser formula `_, and "bbfg" calls the associated methods to From 9d144cf5ae9bc92cffdda037fb3eccd44ee4eadd Mon Sep 17 00:00:00 2001 From: benjaminlanthier <91567620+benjaminlanthier@users.noreply.github.com> Date: Tue, 16 Nov 2021 12:31:17 -0500 Subject: [PATCH 25/43] Update thewalrus/_permanent.py Co-authored-by: Josh Izaac --- thewalrus/_permanent.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/thewalrus/_permanent.py b/thewalrus/_permanent.py index 7ca129848..7de81a16b 100644 --- a/thewalrus/_permanent.py +++ b/thewalrus/_permanent.py @@ -30,7 +30,7 @@ def perm(A, method="bbfg"): method (string): Set this to ``"ryser"`` to use the `Ryser formula `_, - and "bbfg" calls the associated methods to + or ``"bbfg"`` to use the `BBFG formula `_. Returns: From 394216e65f16f5edffc6f8a68766ea1cf9d6ea95 Mon Sep 17 00:00:00 2001 From: benjaminlanthier <91567620+benjaminlanthier@users.noreply.github.com> Date: Tue, 16 Nov 2021 12:36:22 -0500 Subject: [PATCH 26/43] Update thewalrus/_permanent.py Co-authored-by: Josh Izaac --- thewalrus/_permanent.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/thewalrus/_permanent.py b/thewalrus/_permanent.py index 7de81a16b..f2751cf0a 100644 --- a/thewalrus/_permanent.py +++ b/thewalrus/_permanent.py @@ -69,7 +69,7 @@ def perm(A, method="bbfg"): @jit(nopython=True) def perm_ryser(M): """ - Returns the permanent of a matrix using the Ryser formula in Gray ordering + Returns the permanent of a matrix using the Ryser formula in Gray ordering. The code is an re-implementation from a Python 2 code found in `Permanent code golf From 07194dc8024d47de71e2f3ea326270f1805e2d77 Mon Sep 17 00:00:00 2001 From: benjaminlanthier <91567620+benjaminlanthier@users.noreply.github.com> Date: Tue, 16 Nov 2021 12:37:02 -0500 Subject: [PATCH 27/43] Update thewalrus/_permanent.py Co-authored-by: Josh Izaac --- thewalrus/_permanent.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/thewalrus/_permanent.py b/thewalrus/_permanent.py index f2751cf0a..33fb3bd02 100644 --- a/thewalrus/_permanent.py +++ b/thewalrus/_permanent.py @@ -74,7 +74,7 @@ def perm_ryser(M): The code is an re-implementation from a Python 2 code found in `Permanent code golf `_ - using numba. + using Numba. Args: M (array) : a square array. From 06e71a1bf737cdc9422557cda5968df92dc85f69 Mon Sep 17 00:00:00 2001 From: benjaminlanthier <91567620+benjaminlanthier@users.noreply.github.com> Date: Tue, 16 Nov 2021 12:38:03 -0500 Subject: [PATCH 28/43] Update thewalrus/_permanent.py Co-authored-by: Josh Izaac --- thewalrus/_permanent.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/thewalrus/_permanent.py b/thewalrus/_permanent.py index 33fb3bd02..282037429 100644 --- a/thewalrus/_permanent.py +++ b/thewalrus/_permanent.py @@ -119,9 +119,11 @@ def perm_bbfg(M): The code is a re-implementation from a Python 2 code found in `Permanent code golf `_ - using numba. + using Numba. + Args: M (array) : a square array. + Returns: np.float64 or np.complex128: the permanent of a matrix M. """ From aeacfbea174839af187ab0ff2c2be54235b13e1b Mon Sep 17 00:00:00 2001 From: JQZ1111 <75086618+JQZ1111@users.noreply.github.com> Date: Tue, 16 Nov 2021 13:51:23 -0500 Subject: [PATCH 29/43] Tried Josh's suggestions --- thewalrus/_permanent.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/thewalrus/_permanent.py b/thewalrus/_permanent.py index 282037429..66749c049 100644 --- a/thewalrus/_permanent.py +++ b/thewalrus/_permanent.py @@ -18,13 +18,10 @@ from numba import jit from ._hafnian import hafnian_repeated -# pylint: disable = C0103, R0914 - - def perm(A, method="bbfg"): """Returns the permanent of a matrix using various methods. - For more direct control, you may wish to call :func:`perm_real` - or :func:`perm_complex` directly. + + Args: A (array): a square array. method (string): Set this to ``"ryser"`` to use the From 9db1b5ecdc9426217ac076cf243cd68e14a3f970 Mon Sep 17 00:00:00 2001 From: JQZ1111 <75086618+JQZ1111@users.noreply.github.com> Date: Tue, 16 Nov 2021 19:27:42 -0500 Subject: [PATCH 30/43] Update _permanent.py --- thewalrus/_permanent.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/thewalrus/_permanent.py b/thewalrus/_permanent.py index 66749c049..f96637ceb 100644 --- a/thewalrus/_permanent.py +++ b/thewalrus/_permanent.py @@ -154,14 +154,20 @@ def perm_bbfg(M): def permanent_repeated(A, rpt): r"""Calculates the permanent of matrix :math:`A`, where the ith row/column of :math:`A` is repeated :math:`rpt_i` times. + This function constructs the matrix + .. math:: B = \begin{bmatrix} 0 & A\\ A^T & 0 \end{bmatrix}, + and then calculates :math:`perm(A)=haf(B)`, by calling + >>> hafnian_repeated(B, rpt*2, loop=False) + Args: A (array): matrix of size [N, N] rpt (Sequence): sequence of N positive integers indicating the corresponding rows/columns of A to be repeated. + Returns: np.int64 or np.float64 or np.complex128: the permanent of matrix A. """ From 6c79f1143c2352fe4d460015f5adadc5ca21cac9 Mon Sep 17 00:00:00 2001 From: Dominic Date: Tue, 16 Nov 2021 19:32:36 -0500 Subject: [PATCH 31/43] Apply black on the file _permanent.py --- thewalrus/_permanent.py | 1 + 1 file changed, 1 insertion(+) diff --git a/thewalrus/_permanent.py b/thewalrus/_permanent.py index f96637ceb..cf73feba8 100644 --- a/thewalrus/_permanent.py +++ b/thewalrus/_permanent.py @@ -18,6 +18,7 @@ from numba import jit from ._hafnian import hafnian_repeated + def perm(A, method="bbfg"): """Returns the permanent of a matrix using various methods. From c45b1f3a89379835d1383214fc57c86c79dec81b Mon Sep 17 00:00:00 2001 From: JQZ1111 <75086618+JQZ1111@users.noreply.github.com> Date: Tue, 16 Nov 2021 19:35:51 -0500 Subject: [PATCH 32/43] Reformat to fit in docs --- thewalrus/_permanent.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/thewalrus/_permanent.py b/thewalrus/_permanent.py index cf73feba8..8f65ff8c0 100644 --- a/thewalrus/_permanent.py +++ b/thewalrus/_permanent.py @@ -22,7 +22,6 @@ def perm(A, method="bbfg"): """Returns the permanent of a matrix using various methods. - Args: A (array): a square array. method (string): Set this to ``"ryser"`` to use the @@ -114,6 +113,7 @@ def perm_ryser(M): def perm_bbfg(M): """ Returns the permanent of a matrix using the bbfg formula in Gray ordering + The code is a re-implementation from a Python 2 code found in `Permanent code golf `_ From 678961762652d119132cca91c87f078cb9fef9d7 Mon Sep 17 00:00:00 2001 From: JQZ1111 <75086618+JQZ1111@users.noreply.github.com> Date: Tue, 16 Nov 2021 19:38:20 -0500 Subject: [PATCH 33/43] Added Polyquantique team names --- .github/ACKNOWLEDGMENTS.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/.github/ACKNOWLEDGMENTS.md b/.github/ACKNOWLEDGMENTS.md index 083acdd56..a706c5e88 100644 --- a/.github/ACKNOWLEDGMENTS.md +++ b/.github/ACKNOWLEDGMENTS.md @@ -48,4 +48,12 @@ * [Ali Asadi](https://github.com/maliasadi) (Western University) - :thread: Commander of threads -* [Sebastián Duque](https://github.com/sduquemesa) (Xanadu) - 🎧 Quantum sound explorer \ No newline at end of file +* [Sebastián Duque](https://github.com/sduquemesa) (Xanadu) - 🎧 Quantum sound explorer + +* [Jiaqi Zhao](https://github.com/JQZ1111) (Polytechnique Montréal) - Photon squeezer + +* [Dominic Leclerc](https://github.com/dleclerc33) (Polytechnique de Montréal) :fleur_de_lis: King of vaccum + +* [Benjamin Lanthier](https://github.com/benjaminlanthier) (Polytechnique de Montréal) :mage: Warlock of eigenvalues + +* [Brandon Turcotte](https://github.com/brandonpolymtl) (Polytechnique de Montréal) - :star2: The Quantum-plators From d39a51f0bf18837646caddbf56164efe53d3bf6c Mon Sep 17 00:00:00 2001 From: ben Date: Tue, 16 Nov 2021 20:07:41 -0500 Subject: [PATCH 34/43] Modified with Josh's suggestions --- thewalrus/_permanent.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/thewalrus/_permanent.py b/thewalrus/_permanent.py index 8f65ff8c0..ddbae7b5a 100644 --- a/thewalrus/_permanent.py +++ b/thewalrus/_permanent.py @@ -113,7 +113,7 @@ def perm_ryser(M): def perm_bbfg(M): """ Returns the permanent of a matrix using the bbfg formula in Gray ordering - + The code is a re-implementation from a Python 2 code found in `Permanent code golf `_ @@ -155,20 +155,20 @@ def perm_bbfg(M): def permanent_repeated(A, rpt): r"""Calculates the permanent of matrix :math:`A`, where the ith row/column of :math:`A` is repeated :math:`rpt_i` times. - + This function constructs the matrix - + .. math:: B = \begin{bmatrix} 0 & A\\ A^T & 0 \end{bmatrix}, - + and then calculates :math:`perm(A)=haf(B)`, by calling - + >>> hafnian_repeated(B, rpt*2, loop=False) - + Args: A (array): matrix of size [N, N] rpt (Sequence): sequence of N positive integers indicating the corresponding rows/columns of A to be repeated. - + Returns: np.int64 or np.float64 or np.complex128: the permanent of matrix A. """ From 2afd373538f117495d732a82f1aea6eecf88fc3c Mon Sep 17 00:00:00 2001 From: Nicolas Quesada <991946+nquesada@users.noreply.github.com> Date: Thu, 18 Nov 2021 09:51:39 -0500 Subject: [PATCH 35/43] Apply suggestions from code review --- thewalrus/_permanent.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/thewalrus/_permanent.py b/thewalrus/_permanent.py index 282037429..b63a51433 100644 --- a/thewalrus/_permanent.py +++ b/thewalrus/_permanent.py @@ -67,7 +67,7 @@ def perm(A, method="bbfg"): @jit(nopython=True) -def perm_ryser(M): +def perm_ryser(M): # pragma: no cover """ Returns the permanent of a matrix using the Ryser formula in Gray ordering. @@ -113,7 +113,7 @@ def perm_ryser(M): @jit(nopython=True) -def perm_bbfg(M): +def perm_bbfg(M): # pragma: no cover """ Returns the permanent of a matrix using the bbfg formula in Gray ordering The code is a re-implementation from a Python 2 code found in From 488b5ade0b7a6c2e2a885181df3576862e2a0bb2 Mon Sep 17 00:00:00 2001 From: Nicolas Quesada <991946+nquesada@users.noreply.github.com> Date: Tue, 23 Nov 2021 16:03:25 -0500 Subject: [PATCH 36/43] Apply suggestions from code review Co-authored-by: Josh Izaac --- thewalrus/_permanent.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/thewalrus/_permanent.py b/thewalrus/_permanent.py index 2bbe6f173..cdb8b79d7 100644 --- a/thewalrus/_permanent.py +++ b/thewalrus/_permanent.py @@ -22,8 +22,9 @@ def perm(A, method="bbfg"): """Returns the permanent of a matrix using various methods. + Args: - A (array): a square array. + A (array[float or complex]): a square array. method (string): Set this to ``"ryser"`` to use the `Ryser formula `_, From adb7139c761e6574de88efaf5d4bea4eb2b7da58 Mon Sep 17 00:00:00 2001 From: JQZ1111 <75086618+JQZ1111@users.noreply.github.com> Date: Tue, 23 Nov 2021 19:33:56 -0500 Subject: [PATCH 37/43] Update _permanent.py --- thewalrus/_permanent.py | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/thewalrus/_permanent.py b/thewalrus/_permanent.py index cdb8b79d7..6444d0dd3 100644 --- a/thewalrus/_permanent.py +++ b/thewalrus/_permanent.py @@ -11,8 +11,25 @@ # 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. -""" -Permanent Python interface +r""" +Permanent Algorithms +============================= +.. currentmodule:: thewalrus._permanent +This submodule provides access to tools for finding the permanent of a matrix. The algorithms implemented +here was first derived in +* Ryser, Herbert John (1963). + Combinatorial Mathematics, The Carus Mathematical Monographs, Vol. 14, Mathematical Association of America. +* Glynn, David G. + (2010), "The permanent of a square matrix", European Journal of Combinatorics, 31 (7): 1887–1891. + `_ +Summary +------- +.. autosummary:: + perm + perm_ryser + perm_bbfg +Code details +------------ """ import numpy as np from numba import jit From f958e0c69ffb2ec7e113dd55726eebd6cd8cc123 Mon Sep 17 00:00:00 2001 From: JQZ1111 <75086618+JQZ1111@users.noreply.github.com> Date: Tue, 23 Nov 2021 19:34:34 -0500 Subject: [PATCH 38/43] Update _permanent.py --- thewalrus/_permanent.py | 1 + 1 file changed, 1 insertion(+) diff --git a/thewalrus/_permanent.py b/thewalrus/_permanent.py index 6444d0dd3..625da0660 100644 --- a/thewalrus/_permanent.py +++ b/thewalrus/_permanent.py @@ -28,6 +28,7 @@ perm perm_ryser perm_bbfg + permanent_repeated Code details ------------ """ From d78f38e89b5bb3319ffc664219fd1cd348bb2d6f Mon Sep 17 00:00:00 2001 From: Nicolas Quesada <991946+nquesada@users.noreply.github.com> Date: Wed, 24 Nov 2021 10:21:33 -0500 Subject: [PATCH 39/43] Apply suggestions from code review --- thewalrus/_permanent.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/thewalrus/_permanent.py b/thewalrus/_permanent.py index cdb8b79d7..acf710665 100644 --- a/thewalrus/_permanent.py +++ b/thewalrus/_permanent.py @@ -80,10 +80,6 @@ def perm_ryser(M): # pragma: no cover Returns: np.float64 or np.complex128: the permanent of matrix M. """ - # Raises an error if the matrix is not square - (a, b) = M.shape - if a != b: - raise Exception("Not a square matrix") n = len(M) # row_comb keeps the sum of previous subsets. # Every iteration, it removes a term and/or adds a new term @@ -126,10 +122,6 @@ def perm_bbfg(M): # pragma: no cover Returns: np.float64 or np.complex128: the permanent of a matrix M. """ - # Raises an error if the matrix is not square - (a, b) = M.shape - if a != b: - raise Exception("Not a square matrix") n = len(M) row_comb = np.sum(M, 0) From daff059499f8f354d582fff7cb9377f40bfa6e9c Mon Sep 17 00:00:00 2001 From: benjaminlanthier <91567620+benjaminlanthier@users.noreply.github.com> Date: Wed, 24 Nov 2021 10:52:30 -0500 Subject: [PATCH 40/43] Update _permanent.py Tried to respect correct indentation --- thewalrus/_permanent.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/thewalrus/_permanent.py b/thewalrus/_permanent.py index 625da0660..bc09e4b46 100644 --- a/thewalrus/_permanent.py +++ b/thewalrus/_permanent.py @@ -14,7 +14,9 @@ r""" Permanent Algorithms ============================= + .. currentmodule:: thewalrus._permanent + This submodule provides access to tools for finding the permanent of a matrix. The algorithms implemented here was first derived in * Ryser, Herbert John (1963). @@ -22,13 +24,16 @@ * Glynn, David G. (2010), "The permanent of a square matrix", European Journal of Combinatorics, 31 (7): 1887–1891. `_ + Summary ------- .. autosummary:: + perm perm_ryser perm_bbfg permanent_repeated + Code details ------------ """ From 9eff336c3ea30fc3d1d197afde43bf6c7a0965e5 Mon Sep 17 00:00:00 2001 From: Nicolas Quesada <991946+nquesada@users.noreply.github.com> Date: Wed, 24 Nov 2021 11:12:31 -0500 Subject: [PATCH 41/43] Update thewalrus/_permanent.py --- thewalrus/_permanent.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/thewalrus/_permanent.py b/thewalrus/_permanent.py index 58be06a9c..aa42e2031 100644 --- a/thewalrus/_permanent.py +++ b/thewalrus/_permanent.py @@ -21,7 +21,7 @@ here was first derived in * Ryser, Herbert John (1963). Combinatorial Mathematics, The Carus Mathematical Monographs, Vol. 14, Mathematical Association of America. -* Glynn, David G. +* Glynn, David G. (2010), "The permanent of a square matrix", European Journal of Combinatorics, 31 (7): 1887–1891. `_ From 050152c65f375bb56b8db3b4ea59be77b0d303c9 Mon Sep 17 00:00:00 2001 From: Nicolas Quesada Date: Thu, 25 Nov 2021 10:29:44 -0500 Subject: [PATCH 42/43] Updates changelog --- .github/CHANGELOG.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/CHANGELOG.md b/.github/CHANGELOG.md index a4847804e..00bee6a2e 100644 --- a/.github/CHANGELOG.md +++ b/.github/CHANGELOG.md @@ -7,6 +7,9 @@ * Multidimensional Hermite polynomials are now implemented in numba, hence reducing the C++ dependencies of The Walrus. [#295](https://github.com/XanaduAI/thewalrus/pull/295) +* Permanent algorithms are implemented in numba, hence reducing the C++ dependencies of The Walrus. [#300](https://github.com/XanaduAI/thewalrus/pull/300) + + ### Bug fixes ### Breaking changes @@ -15,7 +18,7 @@ This release contains contributions from (in alphabetical order): -Mikhail Andrenkov +Mikhail Andrenkov, Sebastián Duque, Benjamin Lanthier, Dominic Leclerc, Nicolas Quesada, Brandon Turcotte, Jiaqi Zhao --- From ceb43ab82b2f56cb442245d803b49b685f71f4a3 Mon Sep 17 00:00:00 2001 From: Nicolas Quesada Date: Thu, 25 Nov 2021 10:33:28 -0500 Subject: [PATCH 43/43] Fix merge conglict --- .github/CHANGELOG.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/CHANGELOG.md b/.github/CHANGELOG.md index 029793677..1b2396304 100644 --- a/.github/CHANGELOG.md +++ b/.github/CHANGELOG.md @@ -15,9 +15,8 @@ This release contains contributions from (in alphabetical order): -<<<<<<< HEAD -Mikhail Andrenkov, Sebastián Duque, Benjamin Lanthier, Dominic Leclerc, Nicolas Quesada, Brandon Turcotte, Jiaqi Zhao -======= +Benjamin Lanthier, Dominic Leclerc, Nicolas Quesada, Brandon Turcotte, Jiaqi Zhao + --- # Version 0.17.0 @@ -34,7 +33,6 @@ Mikhail Andrenkov, Sebastián Duque, Benjamin Lanthier, Dominic Leclerc, Nicolas This release contains contributions from (in alphabetical order): Mikhail Andrenkov, Sebastián Duque ->>>>>>> 9eff336c3ea30fc3d1d197afde43bf6c7a0965e5 ---