def prange(N=1, dim=1): """ Constructor to create a range of polynomials where the exponent vary. Args: N (int): Number of polynomials in the array. dim (int): The dimension the polynomial should span. Returns: (numpoly.ndpoly): A polynomial array of length N containing simple polynomials with increasing exponent. Examples: >>> chaospy.prange(4) polynomial([1, q0, q0**2, q0**3]) >>> chaospy.prange(4, dim=3) polynomial([1, q2, q2**2, q2**3]) """ logger = logging.getLogger(__name__) logger.warning( "chaospy.prange is deprecated; use chaospy.monomial instead") return numpoly.monomial(N, names=["q%d" % (dim - 1)])
def basis(start, stop=None, dim=1, sort="G", cross_truncation=1.): """ Create an N-dimensional unit polynomial basis. Args: start (int, numpy.ndarray): the minimum polynomial to include. If int is provided, set as lowest total order. If array of int, set as lower order along each axis. stop (int, numpy.ndarray): the maximum shape included. If omitted: ``stop <- start; start <- 0`` If int is provided, set as largest total order. If array of int, set as largest order along each axis. dim (int): dim of the basis. Ignored if array is provided in either start or stop. sort (str): The polynomial ordering where the letters ``G``, ``I`` and ``R`` can be used to set grade, inverse and reverse to the ordering. For ``basis(start=0, stop=2, dim=2, order=order)`` we get: ====== ================== order output ====== ================== "" [1 y y^2 x xy x^2] "G" [1 y x y^2 xy x^2] "I" [x^2 xy x y^2 y 1] "R" [1 x x^2 y xy y^2] "GIR" [y^2 xy x^2 y x 1] ====== ================== cross_truncation (float): Use hyperbolic cross truncation scheme to reduce the number of terms in expansion. Returns: (chaospy.poly.ndpoly) : Polynomial array. Examples: >>> chaospy.basis(2, dim=2, sort="GR") polynomial([1, q0, q1, q0**2, q0*q1, q1**2]) >>> chaospy.basis(2, dim=4, sort="GR", cross_truncation=0) polynomial([1, q0, q1, q2, q3, q0**2, q1**2, q2**2, q3**2]) >>> chaospy.basis(2, 2, dim=2, sort="GR", cross_truncation=numpy.inf) polynomial([q0**2, q1**2, q0**2*q1, q0*q1**2, q0**2*q1**2]) """ if stop is None: start, stop = 0, start dim = max(numpy.asarray(start).size, numpy.asarray(stop).size, dim) return numpoly.monomial( start=start, stop=numpy.array(stop)+1, ordering=sort, cross_truncation=cross_truncation, names=numpoly.symbols("q:%d" % dim, asarray=True), )
def basis(start, stop=None, dim=1, cross_truncation=1., sort="G"): """ Create an N-dimensional unit polynomial basis. Args: start (int, numpy.ndarray): the minimum polynomial to include. If int is provided, set as lowest total order. If array of int, set as lower order along each axis. stop (int, numpy.ndarray): the maximum shape included. If omitted: ``stop <- start; start <- 0`` If int is provided, set as largest total order. If array of int, set as largest order along each axis. dim (int): dim of the basis. Ignored if array is provided in either start or stop. cross_truncation (float): Use hyperbolic cross truncation scheme to reduce the number of terms in expansion. Returns: (numpoly.ndpoly) : Polynomial array. Examples: >>> chaospy.basis(2, dim=2) polynomial([1, q1, q0, q1**2, q0*q1, q0**2]) >>> chaospy.basis(2, dim=4, cross_truncation=0) polynomial([1, q3, q2, q1, q0, q3**2, q2**2, q1**2, q0**2]) >>> chaospy.basis(2, 2, dim=2, cross_truncation=numpy.inf) polynomial([q1**2, q0**2, q0*q1**2, q0**2*q1, q0**2*q1**2]) """ logger = logging.getLogger(__name__) logger.warning("chaospy.basis is deprecated; use chaospy.monomial instead") if stop is None: start, stop = 0, start dim = max(numpy.asarray(start).size, numpy.asarray(stop).size, dim) out = numpoly.monomial( start=start, stop=numpy.array(stop)+1, reverse="R" not in sort.upper(), graded="G" in sort.upper(), cross_truncation=cross_truncation, names=numpoly.symbols("q:%d" % dim, asarray=True), ) if "I" in sort.upper(): out = out[::-1] return out
def test_diagonal(interface): """Tests for numpoly.diagonal.""" # TODO: return view instead of copy poly = polynomial([[1, 2, X], [4, Y, 6], [7, 8, X + Y]]) assert_equal(interface.diagonal(poly), [1, Y, X + Y]) assert_equal(interface.diagonal(poly, offset=1), [2, 6]) assert_equal(interface.diagonal(poly, offset=-1), [4, 8]) poly = numpoly.monomial(27).reshape(3, 3, 3) assert_equal(interface.diagonal(poly, axis1=0, axis2=1), [[1, X**12, X**24], [X, X**13, X**25], [X**2, X**14, X**26]]) assert_equal( interface.diagonal(poly, axis1=0, axis2=2), [[1, X**10, X**20], [X**3, X**13, X**23], [X**6, X**16, X**26]]) assert_equal( interface.diagonal(poly, axis1=1, axis2=2), [[1, X**4, X**8], [X**9, X**13, X**17], [X**18, X**22, X**26]])
def prange(N=1, dim=1): """ Constructor to create a range of polynomials where the exponent vary. Args: N (int): Number of polynomials in the array. dim (int): The dimension the polynomial should span. Returns: (chaospy.poly.ndpoly): A polynomial array of length N containing simple polynomials with increasing exponent. Examples: >>> chaospy.prange(4) polynomial([1, q0, q0**2, q0**3]) >>> chaospy.prange(4, dim=3) polynomial([1, q2, q2**2, q2**3]) """ return numpoly.monomial(N, names=["q%d" % (dim-1)])
def orth_chol(order, dist, normed=False, graded=True, reverse=True, cross_truncation=1., retall=False, **kws): """ Create orthogonal polynomial expansion from Cholesky decomposition. Args: order (int): Order of polynomial expansion dist (Dist): Distribution space where polynomials are orthogonal normed (bool): If True orthonormal polynomials will be used instead of monic. graded (bool): Graded sorting, meaning the indices are always sorted by the index sum. E.g. ``q0**2*q1**2*q2**2`` has an exponent sum of 6, and will therefore be consider larger than both ``q0**2*q1*q2``, ``q0*q1**2*q2`` and ``q0*q1*q2**2``, which all have exponent sum of 5. reverse (bool): Reverse lexicographical sorting meaning that ``q0*q1**3`` is considered bigger than ``q0**3*q1``, instead of the opposite. cross_truncation (float): Use hyperbolic cross truncation scheme to reduce the number of terms in expansion. retall (bool): If true return numerical stabilized norms as well. Roughly the same as ``cp.E(orth**2, dist)``. Examples: >>> distribution = chaospy.Normal() >>> expansion, norms = chaospy.orth_chol(3, distribution, retall=True) >>> expansion.round(4) polynomial([1.0, q0, q0**2-1.0, q0**3-3.0*q0]) >>> norms array([1., 1., 2., 6.]) """ dim = len(dist) basis = numpoly.monomial( start=1, stop=order + 1, names=numpoly.variable(dim).names, graded=graded, reverse=reverse, cross_truncation=cross_truncation, ) length = len(basis) covariance = chaospy.descriptives.Cov(basis, dist) cholmat = chaospy.chol.gill_king(covariance) cholmat_inv = numpy.linalg.inv(cholmat.T).T if not normed: diag_mesh = numpy.repeat(numpy.diag(cholmat_inv), len(cholmat_inv)) cholmat_inv /= diag_mesh.reshape(cholmat_inv.shape) norms = numpy.hstack([1, numpy.diag(cholmat)**2]) else: norms = numpy.ones(length + 1, dtype=float) coefs = numpy.empty((length + 1, length + 1)) coefs[1:, 1:] = cholmat_inv coefs[0, 0] = 1 coefs[0, 1:] = 0 expected = -numpy.sum( cholmat_inv * chaospy.descriptives.E(basis, dist, **kws), -1) coefs[1:, 0] = expected coefs = coefs.T out = {} out[(0, ) * dim] = coefs[0] for idx, key in enumerate(basis.exponents): out[tuple(key)] = coefs[idx + 1] names = numpoly.symbols("q:%d" % dim) polynomials = numpoly.polynomial(out, names=names) if retall: return polynomials, norms return polynomials
def lagrange_polynomial(abscissas, graded=True, reverse=True, sort=None): """ Create Lagrange polynomials. Args: abscissas (numpy.ndarray): Sample points where the Lagrange polynomials shall be defined. graded (bool): Graded sorting, meaning the indices are always sorted by the index sum. E.g. ``q0**2*q1**2*q2**2`` has an exponent sum of 6, and will therefore be consider larger than both ``q0**2*q1*q2``, ``q0*q1**2*q2`` and ``q0*q1*q2**2``, which all have exponent sum of 5. reverse (bool): Reverse lexicographical sorting meaning that ``q0*q1**3`` is considered bigger than ``q0**3*q1``, instead of the opposite. Example: >>> chaospy.lagrange_polynomial([4]).round(4) polynomial([4.0]) >>> chaospy.lagrange_polynomial([-10, 10]).round(4) polynomial([-0.05*q0+0.5, 0.05*q0+0.5]) >>> chaospy.lagrange_polynomial([-1, 0, 1]).round(4) polynomial([0.5*q0**2-0.5*q0, -q0**2+1.0, 0.5*q0**2+0.5*q0]) >>> poly = chaospy.lagrange_polynomial([[1, 0, 1], [0, 1, 2]]) >>> poly.round(4) polynomial([-0.5*q1+0.5*q0+0.5, -q0+1.0, 0.5*q1+0.5*q0-0.5]) >>> poly([1, 0, 1], [0, 1, 2]).round(14) array([[1., 0., 0.], [0., 1., 0.], [0., 0., 1.]]) >>> nodes = numpy.array([[ 0.17, 0.15, 0.17, 0.19], ... [14.94, 16.69, 16.69, 16.69]]) >>> poly = chaospy.lagrange_polynomial(nodes) # doctest: +IGNORE_EXCEPTION_DETAIL Traceback (most recent call last): ... LinAlgError: Lagrange abscissas resulted in invertible matrix """ abscissas = numpy.asfarray(abscissas) if len(abscissas.shape) == 1: abscissas = abscissas.reshape(1, abscissas.size) dim, size = abscissas.shape order = 1 while comb(order + dim, dim) < size: order += 1 indices = numpoly.glexindex(0, order + 1, dimensions=dim, graded=graded, reverse=reverse)[:size] idx, idy = numpy.mgrid[:size, :size] matrix = numpy.prod(abscissas.T[idx]**indices[idy], -1) det = numpy.linalg.det(matrix) if det == 0: raise numpy.linalg.LinAlgError( "Lagrange abscissas resulted in invertible matrix") vec = numpoly.monomial(0, order + 1, dimensions=dim, graded=graded, reverse=reverse)[:size] coeffs = numpy.zeros((size, size)) if size == 1: out = numpoly.monomial( 0, 1, dimensions=dim, graded=graded, reverse=reverse) * abscissas.item() elif size == 2: coeffs = numpy.linalg.inv(matrix) out = numpoly.sum(vec * (coeffs.T), 1) else: for i in range(size): if i % 2 != 0: k = 1 else: k = 0 for j in range(size): if k % 2 == 0: coeffs[i, j] += numpy.linalg.det(matrix[1:, 1:]) else: if size % 2 == 0: coeffs[i, j] += -numpy.linalg.det(matrix[1:, 1:]) else: coeffs[i, j] += numpy.linalg.det(matrix[1:, 1:]) matrix = numpy.roll(matrix, -1, axis=0) k += 1 matrix = numpy.roll(matrix, -1, axis=1) coeffs /= det out = numpoly.sum(vec * (coeffs.T), 1) return out
def orth_gs(order, dist, normed=False, graded=True, reverse=True, retall=False, cross_truncation=1., **kws): """ Gram-Schmidt process for generating orthogonal polynomials. Args: order (int, numpoly.ndpoly): The upper polynomial order. Alternative a custom polynomial basis can be used. dist (Dist): Weighting distribution(s) defining orthogonality. normed (bool): If True orthonormal polynomials will be used instead of monic. graded (bool): Graded sorting, meaning the indices are always sorted by the index sum. E.g. ``q0**2*q1**2*q2**2`` has an exponent sum of 6, and will therefore be consider larger than both ``q0**2*q1*q2``, ``q0*q1**2*q2`` and ``q0*q1*q2**2``, which all have exponent sum of 5. reverse (bool): Reverse lexicographical sorting meaning that ``q0*q1**3`` is considered bigger than ``q0**3*q1``, instead of the opposite. retall (bool): If true return numerical stabilized norms as well. Roughly the same as ``cp.E(orth**2, dist)``. cross_truncation (float): Use hyperbolic cross truncation scheme to reduce the number of terms in expansion. Returns: (chapspy.poly.ndpoly): The orthogonal polynomial expansion. Examples: >>> distribution = chaospy.J(chaospy.Normal(), chaospy.Normal()) >>> polynomials, norms = chaospy.orth_gs(2, distribution, retall=True) >>> polynomials.round(10) polynomial([1.0, q1, q0, q1**2-1.0, q0*q1, q0**2-1.0]) >>> norms.round(10) array([1., 1., 1., 2., 1., 2.]) >>> polynomials = chaospy.orth_gs(2, distribution, normed=True) >>> polynomials.round(3) polynomial([1.0, q1, q0, 0.707*q1**2-0.707, q0*q1, 0.707*q0**2-0.707]) """ logger = logging.getLogger(__name__) dim = len(dist) if isinstance(order, int): if order == 0: return numpoly.polynomial(1) basis = numpoly.monomial( 0, order + 1, names=numpoly.variable(2).names, graded=graded, reverse=reverse, cross_truncation=cross_truncation, ) else: basis = order basis = list(basis) polynomials = [basis[0]] norms = [1.] for idx in range(1, len(basis)): # orthogonalize polynomial: for idy in range(idx): orth = chaospy.E(basis[idx] * polynomials[idy], dist, **kws) basis[idx] = basis[idx] - polynomials[idy] * orth / norms[idy] norms_ = chaospy.E(basis[idx]**2, dist, **kws) if norms_ <= 0: logger.warning("Warning: Polynomial cutoff at term %d", idx) break norms.append(1. if normed else norms_) basis[idx] = basis[idx] / numpy.sqrt(norms_) if normed else basis[idx] polynomials.append(basis[idx]) polynomials = chaospy.polynomial(polynomials).flatten() if retall: norms = numpy.array(norms) return polynomials, norms return polynomials
def test_display_order(display_config): """Ensure string output changes with various display options.""" expected_output = display_config.pop("expected_output") polynomial = numpy.sum(numpoly.monomial(3, dimensions=("q0", "q1"))) with numpoly.global_options(**display_config): assert str(polynomial) == expected_output
def test_monomial(): assert not numpoly.monomial(0).size assert numpoly.monomial(1) == 1 assert numpy.all(numpoly.monomial(2, dimensions="q0") == [1, X]) assert numpoly.monomial(1, 2, dimensions="q0") == X assert numpoly.monomial(1, 2, dimensions=None) == X
def basis(start, stop=None, dim=1, graded=True, reverse=True, cross_truncation=1., sort=None): """ Create an N-dimensional unit polynomial basis. Args: start (int, numpy.ndarray): the minimum polynomial to include. If int is provided, set as lowest total order. If array of int, set as lower order along each axis. stop (int, numpy.ndarray): the maximum shape included. If omitted: ``stop <- start; start <- 0`` If int is provided, set as largest total order. If array of int, set as largest order along each axis. dim (int): dim of the basis. Ignored if array is provided in either start or stop. graded (bool): Graded sorting, meaning the indices are always sorted by the index sum. E.g. ``q0**2*q1**2*q2**2`` has an exponent sum of 6, and will therefore be consider larger than both ``q0**2*q1*q2``, ``q0*q1**2*q2`` and ``q0*q1*q2**2``, which all have exponent sum of 5. reverse (bool): Reverse lexicographical sorting meaning that ``q0*q1**3`` is considered bigger than ``q0**3*q1``, instead of the opposite. cross_truncation (float): Use hyperbolic cross truncation scheme to reduce the number of terms in expansion. Returns: (chaospy.poly.ndpoly) : Polynomial array. Examples: >>> chaospy.basis(2, dim=2) polynomial([1, q1, q0, q1**2, q0*q1, q0**2]) >>> chaospy.basis(2, dim=4, cross_truncation=0) polynomial([1, q3, q2, q1, q0, q3**2, q2**2, q1**2, q0**2]) >>> chaospy.basis(2, 2, dim=2, cross_truncation=numpy.inf) polynomial([q1**2, q0**2, q0*q1**2, q0**2*q1, q0**2*q1**2]) """ logger = logging.getLogger(__name__) if sort is not None: logger.warning("deprecation warning: 'sort' argument is deprecated; " "use 'graded' and/or 'reverse' instead") graded = "G" in sort.upper() reverse = "R" not in sort.upper() inverse = "I" in sort.upper() out = basis(start, stop, dim, graded, reverse, cross_truncation) if inverse: out = out[::-1] return out if stop is None: start, stop = 0, start dim = max(numpy.asarray(start).size, numpy.asarray(stop).size, dim) return numpoly.monomial( start=start, stop=numpy.array(stop) + 1, reverse=reverse, graded=graded, cross_truncation=cross_truncation, names=numpoly.symbols("q:%d" % dim, asarray=True), )
def test_numpoly_monomial(): assert not numpoly.monomial(0).size assert numpoly.monomial(1) == 1 assert numpy.all(numpoly.monomial(2, names="X") == [1, X])