annotate DEPENDENCIES/mingw32/Python27/Lib/site-packages/numpy/polynomial/polyutils.py @ 133:4acb5d8d80b6 tip

Don't fail environmental check if README.md exists (but .txt and no-suffix don't)
author Chris Cannam
date Tue, 30 Jul 2019 12:25:44 +0100
parents 2a2c65a20a8b
children
rev   line source
Chris@87 1 """
Chris@87 2 Utililty classes and functions for the polynomial modules.
Chris@87 3
Chris@87 4 This module provides: error and warning objects; a polynomial base class;
Chris@87 5 and some routines used in both the `polynomial` and `chebyshev` modules.
Chris@87 6
Chris@87 7 Error objects
Chris@87 8 -------------
Chris@87 9
Chris@87 10 .. autosummary::
Chris@87 11 :toctree: generated/
Chris@87 12
Chris@87 13 PolyError base class for this sub-package's errors.
Chris@87 14 PolyDomainError raised when domains are mismatched.
Chris@87 15
Chris@87 16 Warning objects
Chris@87 17 ---------------
Chris@87 18
Chris@87 19 .. autosummary::
Chris@87 20 :toctree: generated/
Chris@87 21
Chris@87 22 RankWarning raised in least-squares fit for rank-deficient matrix.
Chris@87 23
Chris@87 24 Base class
Chris@87 25 ----------
Chris@87 26
Chris@87 27 .. autosummary::
Chris@87 28 :toctree: generated/
Chris@87 29
Chris@87 30 PolyBase Obsolete base class for the polynomial classes. Do not use.
Chris@87 31
Chris@87 32 Functions
Chris@87 33 ---------
Chris@87 34
Chris@87 35 .. autosummary::
Chris@87 36 :toctree: generated/
Chris@87 37
Chris@87 38 as_series convert list of array_likes into 1-D arrays of common type.
Chris@87 39 trimseq remove trailing zeros.
Chris@87 40 trimcoef remove small trailing coefficients.
Chris@87 41 getdomain return the domain appropriate for a given set of abscissae.
Chris@87 42 mapdomain maps points between domains.
Chris@87 43 mapparms parameters of the linear map between domains.
Chris@87 44
Chris@87 45 """
Chris@87 46 from __future__ import division, absolute_import, print_function
Chris@87 47
Chris@87 48 import numpy as np
Chris@87 49
Chris@87 50 __all__ = [
Chris@87 51 'RankWarning', 'PolyError', 'PolyDomainError', 'as_series', 'trimseq',
Chris@87 52 'trimcoef', 'getdomain', 'mapdomain', 'mapparms', 'PolyBase']
Chris@87 53
Chris@87 54 #
Chris@87 55 # Warnings and Exceptions
Chris@87 56 #
Chris@87 57
Chris@87 58 class RankWarning(UserWarning):
Chris@87 59 """Issued by chebfit when the design matrix is rank deficient."""
Chris@87 60 pass
Chris@87 61
Chris@87 62 class PolyError(Exception):
Chris@87 63 """Base class for errors in this module."""
Chris@87 64 pass
Chris@87 65
Chris@87 66 class PolyDomainError(PolyError):
Chris@87 67 """Issued by the generic Poly class when two domains don't match.
Chris@87 68
Chris@87 69 This is raised when an binary operation is passed Poly objects with
Chris@87 70 different domains.
Chris@87 71
Chris@87 72 """
Chris@87 73 pass
Chris@87 74
Chris@87 75 #
Chris@87 76 # Base class for all polynomial types
Chris@87 77 #
Chris@87 78
Chris@87 79 class PolyBase(object):
Chris@87 80 """
Chris@87 81 Base class for all polynomial types.
Chris@87 82
Chris@87 83 Deprecated in numpy 1.9.0, use the abstract
Chris@87 84 ABCPolyBase class instead. Note that the latter
Chris@87 85 reguires a number of virtual functions to be
Chris@87 86 implemented.
Chris@87 87
Chris@87 88 """
Chris@87 89 pass
Chris@87 90
Chris@87 91 #
Chris@87 92 # Helper functions to convert inputs to 1-D arrays
Chris@87 93 #
Chris@87 94 def trimseq(seq):
Chris@87 95 """Remove small Poly series coefficients.
Chris@87 96
Chris@87 97 Parameters
Chris@87 98 ----------
Chris@87 99 seq : sequence
Chris@87 100 Sequence of Poly series coefficients. This routine fails for
Chris@87 101 empty sequences.
Chris@87 102
Chris@87 103 Returns
Chris@87 104 -------
Chris@87 105 series : sequence
Chris@87 106 Subsequence with trailing zeros removed. If the resulting sequence
Chris@87 107 would be empty, return the first element. The returned sequence may
Chris@87 108 or may not be a view.
Chris@87 109
Chris@87 110 Notes
Chris@87 111 -----
Chris@87 112 Do not lose the type info if the sequence contains unknown objects.
Chris@87 113
Chris@87 114 """
Chris@87 115 if len(seq) == 0:
Chris@87 116 return seq
Chris@87 117 else:
Chris@87 118 for i in range(len(seq) - 1, -1, -1):
Chris@87 119 if seq[i] != 0:
Chris@87 120 break
Chris@87 121 return seq[:i+1]
Chris@87 122
Chris@87 123
Chris@87 124 def as_series(alist, trim=True):
Chris@87 125 """
Chris@87 126 Return argument as a list of 1-d arrays.
Chris@87 127
Chris@87 128 The returned list contains array(s) of dtype double, complex double, or
Chris@87 129 object. A 1-d argument of shape ``(N,)`` is parsed into ``N`` arrays of
Chris@87 130 size one; a 2-d argument of shape ``(M,N)`` is parsed into ``M`` arrays
Chris@87 131 of size ``N`` (i.e., is "parsed by row"); and a higher dimensional array
Chris@87 132 raises a Value Error if it is not first reshaped into either a 1-d or 2-d
Chris@87 133 array.
Chris@87 134
Chris@87 135 Parameters
Chris@87 136 ----------
Chris@87 137 a : array_like
Chris@87 138 A 1- or 2-d array_like
Chris@87 139 trim : boolean, optional
Chris@87 140 When True, trailing zeros are removed from the inputs.
Chris@87 141 When False, the inputs are passed through intact.
Chris@87 142
Chris@87 143 Returns
Chris@87 144 -------
Chris@87 145 [a1, a2,...] : list of 1-D arrays
Chris@87 146 A copy of the input data as a list of 1-d arrays.
Chris@87 147
Chris@87 148 Raises
Chris@87 149 ------
Chris@87 150 ValueError
Chris@87 151 Raised when `as_series` cannot convert its input to 1-d arrays, or at
Chris@87 152 least one of the resulting arrays is empty.
Chris@87 153
Chris@87 154 Examples
Chris@87 155 --------
Chris@87 156 >>> from numpy import polynomial as P
Chris@87 157 >>> a = np.arange(4)
Chris@87 158 >>> P.as_series(a)
Chris@87 159 [array([ 0.]), array([ 1.]), array([ 2.]), array([ 3.])]
Chris@87 160 >>> b = np.arange(6).reshape((2,3))
Chris@87 161 >>> P.as_series(b)
Chris@87 162 [array([ 0., 1., 2.]), array([ 3., 4., 5.])]
Chris@87 163
Chris@87 164 """
Chris@87 165 arrays = [np.array(a, ndmin=1, copy=0) for a in alist]
Chris@87 166 if min([a.size for a in arrays]) == 0:
Chris@87 167 raise ValueError("Coefficient array is empty")
Chris@87 168 if any([a.ndim != 1 for a in arrays]):
Chris@87 169 raise ValueError("Coefficient array is not 1-d")
Chris@87 170 if trim:
Chris@87 171 arrays = [trimseq(a) for a in arrays]
Chris@87 172
Chris@87 173 if any([a.dtype == np.dtype(object) for a in arrays]):
Chris@87 174 ret = []
Chris@87 175 for a in arrays:
Chris@87 176 if a.dtype != np.dtype(object):
Chris@87 177 tmp = np.empty(len(a), dtype=np.dtype(object))
Chris@87 178 tmp[:] = a[:]
Chris@87 179 ret.append(tmp)
Chris@87 180 else:
Chris@87 181 ret.append(a.copy())
Chris@87 182 else:
Chris@87 183 try:
Chris@87 184 dtype = np.common_type(*arrays)
Chris@87 185 except:
Chris@87 186 raise ValueError("Coefficient arrays have no common type")
Chris@87 187 ret = [np.array(a, copy=1, dtype=dtype) for a in arrays]
Chris@87 188 return ret
Chris@87 189
Chris@87 190
Chris@87 191 def trimcoef(c, tol=0):
Chris@87 192 """
Chris@87 193 Remove "small" "trailing" coefficients from a polynomial.
Chris@87 194
Chris@87 195 "Small" means "small in absolute value" and is controlled by the
Chris@87 196 parameter `tol`; "trailing" means highest order coefficient(s), e.g., in
Chris@87 197 ``[0, 1, 1, 0, 0]`` (which represents ``0 + x + x**2 + 0*x**3 + 0*x**4``)
Chris@87 198 both the 3-rd and 4-th order coefficients would be "trimmed."
Chris@87 199
Chris@87 200 Parameters
Chris@87 201 ----------
Chris@87 202 c : array_like
Chris@87 203 1-d array of coefficients, ordered from lowest order to highest.
Chris@87 204 tol : number, optional
Chris@87 205 Trailing (i.e., highest order) elements with absolute value less
Chris@87 206 than or equal to `tol` (default value is zero) are removed.
Chris@87 207
Chris@87 208 Returns
Chris@87 209 -------
Chris@87 210 trimmed : ndarray
Chris@87 211 1-d array with trailing zeros removed. If the resulting series
Chris@87 212 would be empty, a series containing a single zero is returned.
Chris@87 213
Chris@87 214 Raises
Chris@87 215 ------
Chris@87 216 ValueError
Chris@87 217 If `tol` < 0
Chris@87 218
Chris@87 219 See Also
Chris@87 220 --------
Chris@87 221 trimseq
Chris@87 222
Chris@87 223 Examples
Chris@87 224 --------
Chris@87 225 >>> from numpy import polynomial as P
Chris@87 226 >>> P.trimcoef((0,0,3,0,5,0,0))
Chris@87 227 array([ 0., 0., 3., 0., 5.])
Chris@87 228 >>> P.trimcoef((0,0,1e-3,0,1e-5,0,0),1e-3) # item == tol is trimmed
Chris@87 229 array([ 0.])
Chris@87 230 >>> i = complex(0,1) # works for complex
Chris@87 231 >>> P.trimcoef((3e-4,1e-3*(1-i),5e-4,2e-5*(1+i)), 1e-3)
Chris@87 232 array([ 0.0003+0.j , 0.0010-0.001j])
Chris@87 233
Chris@87 234 """
Chris@87 235 if tol < 0:
Chris@87 236 raise ValueError("tol must be non-negative")
Chris@87 237
Chris@87 238 [c] = as_series([c])
Chris@87 239 [ind] = np.where(np.abs(c) > tol)
Chris@87 240 if len(ind) == 0:
Chris@87 241 return c[:1]*0
Chris@87 242 else:
Chris@87 243 return c[:ind[-1] + 1].copy()
Chris@87 244
Chris@87 245 def getdomain(x):
Chris@87 246 """
Chris@87 247 Return a domain suitable for given abscissae.
Chris@87 248
Chris@87 249 Find a domain suitable for a polynomial or Chebyshev series
Chris@87 250 defined at the values supplied.
Chris@87 251
Chris@87 252 Parameters
Chris@87 253 ----------
Chris@87 254 x : array_like
Chris@87 255 1-d array of abscissae whose domain will be determined.
Chris@87 256
Chris@87 257 Returns
Chris@87 258 -------
Chris@87 259 domain : ndarray
Chris@87 260 1-d array containing two values. If the inputs are complex, then
Chris@87 261 the two returned points are the lower left and upper right corners
Chris@87 262 of the smallest rectangle (aligned with the axes) in the complex
Chris@87 263 plane containing the points `x`. If the inputs are real, then the
Chris@87 264 two points are the ends of the smallest interval containing the
Chris@87 265 points `x`.
Chris@87 266
Chris@87 267 See Also
Chris@87 268 --------
Chris@87 269 mapparms, mapdomain
Chris@87 270
Chris@87 271 Examples
Chris@87 272 --------
Chris@87 273 >>> from numpy.polynomial import polyutils as pu
Chris@87 274 >>> points = np.arange(4)**2 - 5; points
Chris@87 275 array([-5, -4, -1, 4])
Chris@87 276 >>> pu.getdomain(points)
Chris@87 277 array([-5., 4.])
Chris@87 278 >>> c = np.exp(complex(0,1)*np.pi*np.arange(12)/6) # unit circle
Chris@87 279 >>> pu.getdomain(c)
Chris@87 280 array([-1.-1.j, 1.+1.j])
Chris@87 281
Chris@87 282 """
Chris@87 283 [x] = as_series([x], trim=False)
Chris@87 284 if x.dtype.char in np.typecodes['Complex']:
Chris@87 285 rmin, rmax = x.real.min(), x.real.max()
Chris@87 286 imin, imax = x.imag.min(), x.imag.max()
Chris@87 287 return np.array((complex(rmin, imin), complex(rmax, imax)))
Chris@87 288 else:
Chris@87 289 return np.array((x.min(), x.max()))
Chris@87 290
Chris@87 291 def mapparms(old, new):
Chris@87 292 """
Chris@87 293 Linear map parameters between domains.
Chris@87 294
Chris@87 295 Return the parameters of the linear map ``offset + scale*x`` that maps
Chris@87 296 `old` to `new` such that ``old[i] -> new[i]``, ``i = 0, 1``.
Chris@87 297
Chris@87 298 Parameters
Chris@87 299 ----------
Chris@87 300 old, new : array_like
Chris@87 301 Domains. Each domain must (successfully) convert to a 1-d array
Chris@87 302 containing precisely two values.
Chris@87 303
Chris@87 304 Returns
Chris@87 305 -------
Chris@87 306 offset, scale : scalars
Chris@87 307 The map ``L(x) = offset + scale*x`` maps the first domain to the
Chris@87 308 second.
Chris@87 309
Chris@87 310 See Also
Chris@87 311 --------
Chris@87 312 getdomain, mapdomain
Chris@87 313
Chris@87 314 Notes
Chris@87 315 -----
Chris@87 316 Also works for complex numbers, and thus can be used to calculate the
Chris@87 317 parameters required to map any line in the complex plane to any other
Chris@87 318 line therein.
Chris@87 319
Chris@87 320 Examples
Chris@87 321 --------
Chris@87 322 >>> from numpy import polynomial as P
Chris@87 323 >>> P.mapparms((-1,1),(-1,1))
Chris@87 324 (0.0, 1.0)
Chris@87 325 >>> P.mapparms((1,-1),(-1,1))
Chris@87 326 (0.0, -1.0)
Chris@87 327 >>> i = complex(0,1)
Chris@87 328 >>> P.mapparms((-i,-1),(1,i))
Chris@87 329 ((1+1j), (1+0j))
Chris@87 330
Chris@87 331 """
Chris@87 332 oldlen = old[1] - old[0]
Chris@87 333 newlen = new[1] - new[0]
Chris@87 334 off = (old[1]*new[0] - old[0]*new[1])/oldlen
Chris@87 335 scl = newlen/oldlen
Chris@87 336 return off, scl
Chris@87 337
Chris@87 338 def mapdomain(x, old, new):
Chris@87 339 """
Chris@87 340 Apply linear map to input points.
Chris@87 341
Chris@87 342 The linear map ``offset + scale*x`` that maps the domain `old` to
Chris@87 343 the domain `new` is applied to the points `x`.
Chris@87 344
Chris@87 345 Parameters
Chris@87 346 ----------
Chris@87 347 x : array_like
Chris@87 348 Points to be mapped. If `x` is a subtype of ndarray the subtype
Chris@87 349 will be preserved.
Chris@87 350 old, new : array_like
Chris@87 351 The two domains that determine the map. Each must (successfully)
Chris@87 352 convert to 1-d arrays containing precisely two values.
Chris@87 353
Chris@87 354 Returns
Chris@87 355 -------
Chris@87 356 x_out : ndarray
Chris@87 357 Array of points of the same shape as `x`, after application of the
Chris@87 358 linear map between the two domains.
Chris@87 359
Chris@87 360 See Also
Chris@87 361 --------
Chris@87 362 getdomain, mapparms
Chris@87 363
Chris@87 364 Notes
Chris@87 365 -----
Chris@87 366 Effectively, this implements:
Chris@87 367
Chris@87 368 .. math ::
Chris@87 369 x\\_out = new[0] + m(x - old[0])
Chris@87 370
Chris@87 371 where
Chris@87 372
Chris@87 373 .. math ::
Chris@87 374 m = \\frac{new[1]-new[0]}{old[1]-old[0]}
Chris@87 375
Chris@87 376 Examples
Chris@87 377 --------
Chris@87 378 >>> from numpy import polynomial as P
Chris@87 379 >>> old_domain = (-1,1)
Chris@87 380 >>> new_domain = (0,2*np.pi)
Chris@87 381 >>> x = np.linspace(-1,1,6); x
Chris@87 382 array([-1. , -0.6, -0.2, 0.2, 0.6, 1. ])
Chris@87 383 >>> x_out = P.mapdomain(x, old_domain, new_domain); x_out
Chris@87 384 array([ 0. , 1.25663706, 2.51327412, 3.76991118, 5.02654825,
Chris@87 385 6.28318531])
Chris@87 386 >>> x - P.mapdomain(x_out, new_domain, old_domain)
Chris@87 387 array([ 0., 0., 0., 0., 0., 0.])
Chris@87 388
Chris@87 389 Also works for complex numbers (and thus can be used to map any line in
Chris@87 390 the complex plane to any other line therein).
Chris@87 391
Chris@87 392 >>> i = complex(0,1)
Chris@87 393 >>> old = (-1 - i, 1 + i)
Chris@87 394 >>> new = (-1 + i, 1 - i)
Chris@87 395 >>> z = np.linspace(old[0], old[1], 6); z
Chris@87 396 array([-1.0-1.j , -0.6-0.6j, -0.2-0.2j, 0.2+0.2j, 0.6+0.6j, 1.0+1.j ])
Chris@87 397 >>> new_z = P.mapdomain(z, old, new); new_z
Chris@87 398 array([-1.0+1.j , -0.6+0.6j, -0.2+0.2j, 0.2-0.2j, 0.6-0.6j, 1.0-1.j ])
Chris@87 399
Chris@87 400 """
Chris@87 401 x = np.asanyarray(x)
Chris@87 402 off, scl = mapparms(old, new)
Chris@87 403 return off + scl*x