# Path: dppy/exact_sampling.py
# def elementary_symmetric_polynomials(eig_vals, size):
#     """ Evaluate the elementary symmetric polynomials :math:`e_k` in the eigenvalues :math:`(\\lambda_1, \\cdots, \\lambda_N)`.
# 
#     :param eig_vals:
#         Collection of eigenvalues :math:`(\\lambda_1, \\cdots, \\lambda_N)` of the similarity kernel :math:`L`.
#     :type eig_vals:
#         list
# 
#     :param size:
#         Maximum degree of elementary symmetric polynomial.
#     :type size:
#         int
# 
#     :return:
#         :math:`[E_{kn}]_{k=0, n=0}^{\text{size}, N}`
#         :math:`E_{kn} = e_k(\\lambda_1, \\cdots, \\lambda_n)`
#     :rtype:
#         array_like
# 
#     .. seealso::
# 
#         - :cite:`KuTa12` Algorithm 7
#         - `Wikipedia <https://en.wikipedia.org/wiki/Elementary_symmetric_polynomial>`_
#     """
# 
#     # Initialize output array
#     N = eig_vals.size
#     E = np.zeros((size + 1, N + 1))
#     E[0, :] = 1.0
# 
#     # Recursive evaluation
#     for k in range(1, size + 1):
#         for n in range(1, N + 1):
#             E[k, n] = E[k, n - 1] + eig_vals[n - 1] * E[k - 1, n - 1]
# 
#     return E


import unittest
import numpy as np
import sys
from itertools import combinations
from dppy.exact_sampling import elementary_symmetric_polynomials as e_k


sys.path.append('..')



class TestElementarySymmetricPolynomials(unittest.TestCase):
    """ Test the recursive evaluations of the elementary symmetric polynomials used for sampling k-DPPs :ref:`finite_dpps_exact_sampling_k_dpps`
    """
    def test_elementary_symmetric_polynomials(self):
        """
        .. math::

            e_k(\\lambda{1:r}=1, \\lambda{r+1:N}=0)
            = \\sum_{\\substack{S \\subset [N]\\\\|S|=k}}
                \\prod_{s\\in S} \\lambda{s}
        """
        N = 10
        E = np.zeros((N + 1, N + 1))
        E[0, :] = 1.0

        lmbda = np.random.randn(N)

        for k in range(1, N + 1):

            for n in range(1, N + 1):

                E[k, n] = np.sum([np.prod(lmbda_s)
                                  for lmbda_s in combinations(lmbda[:n], k)])


# Path: dppy/exact_sampling.py
# def elementary_symmetric_polynomials(eig_vals, size):
#     """ Evaluate the elementary symmetric polynomials :math:`e_k` in the eigenvalues :math:`(\\lambda_1, \\cdots, \\lambda_N)`.
# 
#     :param eig_vals:
#         Collection of eigenvalues :math:`(\\lambda_1, \\cdots, \\lambda_N)` of the similarity kernel :math:`L`.
#     :type eig_vals:
#         list
# 
#     :param size:
#         Maximum degree of elementary symmetric polynomial.
#     :type size:
#         int
# 
#     :return:
#         :math:`[E_{kn}]_{k=0, n=0}^{\text{size}, N}`
#         :math:`E_{kn} = e_k(\\lambda_1, \\cdots, \\lambda_n)`
#     :rtype:
#         array_like
# 
#     .. seealso::
# 
#         - :cite:`KuTa12` Algorithm 7
#         - `Wikipedia <https://en.wikipedia.org/wiki/Elementary_symmetric_polynomial>`_
#     """
# 
#     # Initialize output array
#     N = eig_vals.size
#     E = np.zeros((size + 1, N + 1))
#     E[0, :] = 1.0
# 
#     # Recursive evaluation
#     for k in range(1, size + 1):
#         for n in range(1, N + 1):
#             E[k, n] = E[k, n - 1] + eig_vals[n - 1] * E[k - 1, n - 1]
# 
#     return E


# Path: tests/test_elementary_symmetric_polynomials.py
import unittest
import numpy as np
import sys
from itertools import combinations
from dppy.exact_sampling import elementary_symmetric_polynomials as e_k



sys.path.append('..')



class TestElementarySymmetricPolynomials(unittest.TestCase):
    """ Test the recursive evaluations of the elementary symmetric polynomials used for sampling k-DPPs :ref:`finite_dpps_exact_sampling_k_dpps`
    """
    def test_elementary_symmetric_polynomials(self):
        """
        .. math::

            e_k(\\lambda{1:r}=1, \\lambda{r+1:N}=0)
            = \\sum_{\\substack{S \\subset [N]\\\\|S|=k}}
                \\prod_{s\\in S} \\lambda{s}
        """
        N = 10
        E = np.zeros((N + 1, N + 1))
        E[0, :] = 1.0

        lmbda = np.random.randn(N)

        for k in range(1, N + 1):

            for n in range(1, N + 1):

                E[k, n] = np.sum([np.prod(lmbda_s)
                                  for lmbda_s in combinations(lmbda[:n], k)])


        self.assertTrue(np.allclose(E, e_k(lmbda, N)))