<commit_before>"""
This file contains a class that builds a Smolyak Grid.  The hope is that
it will eventually contain the interpolation routines necessary so that
the given some data, this class can build a grid and use the Chebyshev
polynomials to interpolate and approximate the data.

Method based on Judd, Maliar, Maliar, Valero 2013 (W.P)

Authors: <NAME> and <NAME>

"""
import sys
from operator import mul
from itertools import product, combinations_with_replacement
from itertools import chain
import numpy as np
from scipy.linalg import lu
import matplotlib.pyplot as plt
import pandas as pd
from mpl_toolkits.mplot3d import Axes3D
from util import *


def a_chain(n):
    """
    This method finds all of the unidimensional disjoint sets
    that we will use to construct the grid.  It improves on
    past algorithms by noting that A_{n} = S_{n}[evens] except for
    A_1 = {0} and A_2 = {-1, 1}. Additionally, A_{n} = A_{n+1}[odds]
    This prevents the calculation of these nodes repeatedly.  Thus
    we only need to calculate biggest of the S_n's to build the
    sequence of A_n's

    Parameters
    ----------
    n : scalar : integer
      This is the number of disjoint sets from Sn that this should make

    Returns
    -------
    A_chain : dictionary : lists
      This is a dictionary of the disjoint sets that are made.  They are
      indexed by the integer corresponding
    """

    # # Start w finding the biggest Sn(We will subsequently reduce it)
    Sn = _s_n(n)

    A_chain = {}
    A_chain[1] = [0.]
    A_chain[2] = [-1., 1.]

    # Need a for loop to extract remaining elements
    for seq in xrange(n, 2, -1):
        num = Sn.size
        # Need odd indices in python because indexing starts at 0
        A_chain[seq] = tuple(Sn[range(1, num, 2)])
        # A_chain.append(list(Sn[range(1, num, 2)]))
        Sn = Sn[range(0, num, 2)]

    return A_chain

def _s_n(n):
    """
    This method finds the element S_n for the Chebyshev Extrema
    """

    if n == 1:
        return np.array([0.])

    # Apply the necessary transformation to get the nested sequence
    m_i = 2**(n-1) + 1

    # Create an array of values that will be passed in to calculate
    # the set of values
    comp_vals = np.arange(1., m_i + 1.)

    # Values are - cos(pi(j-1)/(n-1)) for j in [1, 2, ..., n]
    vals = -1. * np.cos(np.pi*(comp_vals - 1.)/(m_i-1.))
    vals[np.where(np.abs(vals) < 1e-14)] = 0.0

    return vals

def smol_inds(d, mu):
    """
    This method finds all of the indices that satisfy the requirement
    that d \leq \sum_{i=1}^d \leq d + \mu.  Once we have these, then
    they can be used to build both the grid and the polynomial
    basis.

    Notes
    =====
    This method sets the attribute smol_inds
    """
    if type(mu)==int:
        max_mu = mu
    else:
        max_mu = int(np.max(mu))

    # Need to capture up to value mu + 1 so in python need mu+2
    possible_values = range(1, max_mu + 2)

    # find all (i1, i2, ... id) such that their sum is in range
    # we want; this will cut down on later iterations
    poss_inds = [el for el in combinations_with_replacement(possible_values, d)
                  if d < sum(el) <= d+max_mu]

    if type(mu)==int:
        true_inds = [[el for el in permute(list(val))] for val in poss_inds]
    else:
        true_inds = [[el for el in permute(list(val)) if all(el <= mu+1)] for val in poss_inds]

    # Add the d dimension 1 array so that we don't repeat it a bunch
    # of times
    true_inds.extend([[[1]*d]])

    tinds = list(chain.from_iterable(true_inds))

    return tinds

def build_grid(d, mu):
    """
    This method builds a grid for the object

    Notes
    =====
    This method sets the attribute grid
    """
    # Get An chain
    An = a_chain(mu + 1)

    points = []

    # Need to get the correct indices

    tinds = smol_inds(d, mu)

    for el in tinds:
        temp = [An[i] for i in el]
        # Save these indices that we iterate through because
        # we need them for the chebyshev polynomial combination
        # inds.append(el)
        points.extend(list(product(*temp)))

    grid = pd.lib.to_object_array_tuples(points).astype(float)

    return grid, tinds

def phi_chain(n):
    """
    Finds the disjoint sets of aphi's that will be used to compute
    which functions we need to calculate
    """

    # First create a dictionary
    aphi_chain = {}

    aphi_chain[1] = [1]
    aphi_chain[2] = [2, 3]

    curr_val = 4
    for i in xrange(3, n+1):
        end_val = 2**(i-1) + 1
        temp = range(curr_val, end_val+1)
        aphi_chain[i] = temp
        curr_val = end_val+1

    return aphi_chain

def poly_inds(d, mu):
    """
    This function builds the indices of the basis polynomials that
    will be used to interpolate.
    """
    inds = smol_inds(d, mu)
    aphi = phi_chain(mu + 1)

    # Bring in polynomials
    # cheb_dict = self.calc_chebvals()

    base_polys = []

    for el in inds:
        temp = [aphi[i] for i in el]
        # Save these indices that we iterate through because
        # we need them for the chebyshev polynomial combination
        # inds.append(el)
        base_polys.extend(list(product(*temp)))

    return base_polys

def build_B(d, mu, grid):
    """
    This function builds the matrix B that will be used to calc
    the interpolation coefficients for a given set of data.

    Notes
    =====
    This method sets the attributes B, B_L, B_U
    """
    Ts = cheby2n(grid.T, m_i(mu + 1))
    base_polys = poly_inds(d, mu)
    n = len(grid)
    B = np.empty((n, n), order='F')
    for ind, comb in enumerate(base_polys):
        B[:, ind] = reduce(mul, [Ts[comb[i] - 1, i, :]
                           for i in range(d)])

    return B

def cheby_eval(x, n):<commit_msg>DOC: updated docstrings in python<commit_after>"""
This file contains a class that builds a Smolyak Grid.  The hope is that
it will eventually contain the interpolation routines necessary so that
the given some data, this class can build a grid and use the Chebyshev
polynomials to interpolate and approximate the data.

Method based on Judd, Maliar, Maliar, Valero 2013 (W.P)

Authors: <NAME> and <NAME>

"""
import sys
from operator import mul
from itertools import product, combinations_with_replacement
from itertools import chain
import numpy as np
from scipy.linalg import lu
import matplotlib.pyplot as plt
import pandas as pd
from mpl_toolkits.mplot3d import Axes3D
from util import *


def a_chain(n):
    """
    This method finds all of the unidimensional disjoint sets
    that we will use to construct the grid.  It improves on
    past algorithms by noting that :math:`A_{n} = S_{n}` [evens] except for
    :math:`A_1 = \{0\}` and :math:`A_2 = \{-1, 1\}` . Additionally,
    :math:`A_{n} = A_{n+1}` [odds] This prevents the calculation of these
    nodes repeatedly.  Thus we only need to calculate biggest of the S_n's to
    build the sequence of :math:`A_n` 's

    Parameters
    ----------
    n : scalar : int
      This is the number of disjoint sets from Sn that this should make

    Returns
    -------
    A_chain : dict (int -> list)
      This is a dictionary of the disjoint sets that are made.  They are
      indexed by the integer corresponding
    """

    # # Start w finding the biggest Sn(We will subsequently reduce it)
    Sn = _s_n(n)

    A_chain = {}
    A_chain[1] = [0.]
    A_chain[2] = [-1., 1.]

    # Need a for loop to extract remaining elements
    for seq in xrange(n, 2, -1):
        num = Sn.size
        # Need odd indices in python because indexing starts at 0
        A_chain[seq] = tuple(Sn[range(1, num, 2)])
        # A_chain.append(list(Sn[range(1, num, 2)]))
        Sn = Sn[range(0, num, 2)]

    return A_chain

def _s_n(n):
    """
    This method finds the element S_n for the Chebyshev Extrema
    """

    if n == 1:
        return np.array([0.])

    # Apply the necessary transformation to get the nested sequence
    m_i = 2**(n-1) + 1

    # Create an array of values that will be passed in to calculate
    # the set of values
    comp_vals = np.arange(1., m_i + 1.)

    # Values are - cos(pi(j-1)/(n-1)) for j in [1, 2, ..., n]
    vals = -1. * np.cos(np.pi*(comp_vals - 1.)/(m_i-1.))
    vals[np.where(np.abs(vals) < 1e-14)] = 0.0

    return vals

def smol_inds(d, mu):
    """
    Finds all of the indices that satisfy the requirement that
    :math:`d \leq \sum_{i=1}^d \leq d + \mu`.

    Parameters
    ----------
    d : int
        The number of dimensions in the grid

    mu : int or array : int
        The parameter mu defining the density of the grid. If an array,
        there must be d elements and an anisotropic grid is formed

    Returns
    -------
    true_inds : Array
        A 1-d Any array containing all d element arrays satisfying the
        constraint

    Notes
    -----
    This function is used directly by build_grid and poly_inds

    """
    if type(mu)==int:
        max_mu = mu
    else:
        if mu.size != d:
            raise ValueError("mu must have d elements. It has %i" % mu.size)
        max_mu = int(np.max(mu))

    # Need to capture up to value mu + 1 so in python need mu+2
    possible_values = range(1, max_mu + 2)

    # find all (i1, i2, ... id) such that their sum is in range
    # we want; this will cut down on later iterations
    poss_inds = [el for el in combinations_with_replacement(possible_values, d)
                  if d < sum(el) <= d+max_mu]

    if type(mu)==int:
        true_inds = [[el for el in permute(list(val))] for val in poss_inds]
    else:
        true_inds = [[el for el in permute(list(val)) if all(el <= mu+1)] for val in poss_inds]

    # Add the d dimension 1 array so that we don't repeat it a bunch
    # of times
    true_inds.extend([[[1]*d]])

    tinds = list(chain.from_iterable(true_inds))

    return tinds

def build_grid(d, mu):
    """
    This method builds a grid for the object

    """
    # Get An chain
    An = a_chain(mu + 1)

    points = []

    # Need to get the correct indices

    tinds = smol_inds(d, mu)

    for el in tinds:
        temp = [An[i] for i in el]
        # Save these indices that we iterate through because
        # we need them for the chebyshev polynomial combination
        # inds.append(el)
        points.extend(list(product(*temp)))

    grid = pd.lib.to_object_array_tuples(points).astype(float)

    return grid, tinds

def phi_chain(n):
    """
    For each number in 1 to n, compute the Smolyak indices for the
    corresponding basis functions. This is the :math:`n` in :math:`\\phi_n`

    Parameters
    ----------
    n : int
        The last Smolyak index :math:`n` for which the basis polynomial
        indices should be found

    Returns
    -------
    aphi_chain : dict (int -> list)
        A dictionary whose keys are the Smolyak index :math:`n` and values are
        lists containing all basis polynomial subscripts for that Smolyak
        index

    """

    # First create a dictionary
    aphi_chain = {}

    aphi_chain[1] = [1]
    aphi_chain[2] = [2, 3]

    curr_val = 4
    for i in xrange(3, n+1):
        end_val = 2**(i-1) + 1
        temp = range(curr_val, end_val+1)
        aphi_chain[i] = temp
        curr_val = end_val+1

    return aphi_chain

def poly_inds(d, mu):
    """
    Build indices specifying all the Cartesian products of Chebychev
    polynomials needed to build Smolyak polynomial

    Parameters
    ----------
    d : int
        The number of dimensions in grid / polynomial

    mu : int
        The parameter mu defining the density of the grid

    Returns
    -------
    phi_inds : Array{Int, 2}
        A two dimensional array of integers where each row specifies a
        new set of indices needed to define a smolyak basis polynomial

    Notes
    -----
    This function uses smol_inds and phi_chain. The output of this
    function is used by build_B to construct the B matrix

    """
    inds = smol_inds(d, mu)
    aphi = phi_chain(mu + 1)

    # Bring in polynomials
    # cheb_dict = self.calc_chebvals()

    base_polys = []

    for el in inds:
        temp = [aphi[i] for i in el]
        # Save these indices that we iterate through because
        # we need them for the chebyshev polynomial combination
        # inds.append(el)
        base_polys.extend(list(product(*temp)))

    return base_polys

def build_B(d, mu, grid):
    """
    Compute the matrix B from equation 22 in JMMV 2013
    Translation of dolo.numeric.interpolation.smolyak.SmolyakBasic

    Parameters
    ----------
    d : Int
        The number of dimensions on the grid

    mu : Int
        The mu parameter used to define grid

    grid : array : (float, dims=2)
        The smolyak grid returned by calling `build_grid(d, mu)`

    Returns
    -------
    B : Array{Float64, 2}
        The matrix B that represents the Smolyak polynomial
        corresponding to grid

    """
    Ts = cheby2n(grid.T, m_i(mu + 1))
    base_polys = poly_inds(d, mu)
    n = len(grid)
    B = np.empty((n, n), order='F')
    for ind, comb in enumerate(base_polys):
        B[:, ind] = reduce(mul, [Ts[comb[i] - 1, i, :]
                           for i in range(d)])

    return B

def cheby_eval(x, n):
{'fraction_non_alphanumeric': 0.10022675736961452, 'fraction_numerical': 0.012018140589569161, 'mean_word_length': 2.3598273235144744, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '570246', 'n_tokens_mistral': 4447, 'n_tokens_neox': 4208, 'n_words': 1626}