_special_matrices.py 39 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379
  1. import math
  2. import numpy as np
  3. from numpy.lib.stride_tricks import as_strided
  4. __all__ = ['tri', 'tril', 'triu', 'toeplitz', 'circulant', 'hankel',
  5. 'hadamard', 'leslie', 'kron', 'block_diag', 'companion',
  6. 'helmert', 'hilbert', 'invhilbert', 'pascal', 'invpascal', 'dft',
  7. 'fiedler', 'fiedler_companion', 'convolution_matrix']
  8. # -----------------------------------------------------------------------------
  9. # matrix construction functions
  10. # -----------------------------------------------------------------------------
  11. #
  12. # *Note*: tri{,u,l} is implemented in NumPy, but an important bug was fixed in
  13. # 2.0.0.dev-1af2f3, the following tri{,u,l} definitions are here for backwards
  14. # compatibility.
  15. def tri(N, M=None, k=0, dtype=None):
  16. """
  17. Construct (N, M) matrix filled with ones at and below the kth diagonal.
  18. The matrix has A[i,j] == 1 for j <= i + k
  19. Parameters
  20. ----------
  21. N : int
  22. The size of the first dimension of the matrix.
  23. M : int or None, optional
  24. The size of the second dimension of the matrix. If `M` is None,
  25. `M = N` is assumed.
  26. k : int, optional
  27. Number of subdiagonal below which matrix is filled with ones.
  28. `k` = 0 is the main diagonal, `k` < 0 subdiagonal and `k` > 0
  29. superdiagonal.
  30. dtype : dtype, optional
  31. Data type of the matrix.
  32. Returns
  33. -------
  34. tri : (N, M) ndarray
  35. Tri matrix.
  36. Examples
  37. --------
  38. >>> from scipy.linalg import tri
  39. >>> tri(3, 5, 2, dtype=int)
  40. array([[1, 1, 1, 0, 0],
  41. [1, 1, 1, 1, 0],
  42. [1, 1, 1, 1, 1]])
  43. >>> tri(3, 5, -1, dtype=int)
  44. array([[0, 0, 0, 0, 0],
  45. [1, 0, 0, 0, 0],
  46. [1, 1, 0, 0, 0]])
  47. """
  48. if M is None:
  49. M = N
  50. if isinstance(M, str):
  51. # pearu: any objections to remove this feature?
  52. # As tri(N,'d') is equivalent to tri(N,dtype='d')
  53. dtype = M
  54. M = N
  55. m = np.greater_equal.outer(np.arange(k, N+k), np.arange(M))
  56. if dtype is None:
  57. return m
  58. else:
  59. return m.astype(dtype)
  60. def tril(m, k=0):
  61. """
  62. Make a copy of a matrix with elements above the kth diagonal zeroed.
  63. Parameters
  64. ----------
  65. m : array_like
  66. Matrix whose elements to return
  67. k : int, optional
  68. Diagonal above which to zero elements.
  69. `k` == 0 is the main diagonal, `k` < 0 subdiagonal and
  70. `k` > 0 superdiagonal.
  71. Returns
  72. -------
  73. tril : ndarray
  74. Return is the same shape and type as `m`.
  75. Examples
  76. --------
  77. >>> from scipy.linalg import tril
  78. >>> tril([[1,2,3],[4,5,6],[7,8,9],[10,11,12]], -1)
  79. array([[ 0, 0, 0],
  80. [ 4, 0, 0],
  81. [ 7, 8, 0],
  82. [10, 11, 12]])
  83. """
  84. m = np.asarray(m)
  85. out = tri(m.shape[0], m.shape[1], k=k, dtype=m.dtype.char) * m
  86. return out
  87. def triu(m, k=0):
  88. """
  89. Make a copy of a matrix with elements below the kth diagonal zeroed.
  90. Parameters
  91. ----------
  92. m : array_like
  93. Matrix whose elements to return
  94. k : int, optional
  95. Diagonal below which to zero elements.
  96. `k` == 0 is the main diagonal, `k` < 0 subdiagonal and
  97. `k` > 0 superdiagonal.
  98. Returns
  99. -------
  100. triu : ndarray
  101. Return matrix with zeroed elements below the kth diagonal and has
  102. same shape and type as `m`.
  103. Examples
  104. --------
  105. >>> from scipy.linalg import triu
  106. >>> triu([[1,2,3],[4,5,6],[7,8,9],[10,11,12]], -1)
  107. array([[ 1, 2, 3],
  108. [ 4, 5, 6],
  109. [ 0, 8, 9],
  110. [ 0, 0, 12]])
  111. """
  112. m = np.asarray(m)
  113. out = (1 - tri(m.shape[0], m.shape[1], k - 1, m.dtype.char)) * m
  114. return out
  115. def toeplitz(c, r=None):
  116. """
  117. Construct a Toeplitz matrix.
  118. The Toeplitz matrix has constant diagonals, with c as its first column
  119. and r as its first row. If r is not given, ``r == conjugate(c)`` is
  120. assumed.
  121. Parameters
  122. ----------
  123. c : array_like
  124. First column of the matrix. Whatever the actual shape of `c`, it
  125. will be converted to a 1-D array.
  126. r : array_like, optional
  127. First row of the matrix. If None, ``r = conjugate(c)`` is assumed;
  128. in this case, if c[0] is real, the result is a Hermitian matrix.
  129. r[0] is ignored; the first row of the returned matrix is
  130. ``[c[0], r[1:]]``. Whatever the actual shape of `r`, it will be
  131. converted to a 1-D array.
  132. Returns
  133. -------
  134. A : (len(c), len(r)) ndarray
  135. The Toeplitz matrix. Dtype is the same as ``(c[0] + r[0]).dtype``.
  136. See Also
  137. --------
  138. circulant : circulant matrix
  139. hankel : Hankel matrix
  140. solve_toeplitz : Solve a Toeplitz system.
  141. Notes
  142. -----
  143. The behavior when `c` or `r` is a scalar, or when `c` is complex and
  144. `r` is None, was changed in version 0.8.0. The behavior in previous
  145. versions was undocumented and is no longer supported.
  146. Examples
  147. --------
  148. >>> from scipy.linalg import toeplitz
  149. >>> toeplitz([1,2,3], [1,4,5,6])
  150. array([[1, 4, 5, 6],
  151. [2, 1, 4, 5],
  152. [3, 2, 1, 4]])
  153. >>> toeplitz([1.0, 2+3j, 4-1j])
  154. array([[ 1.+0.j, 2.-3.j, 4.+1.j],
  155. [ 2.+3.j, 1.+0.j, 2.-3.j],
  156. [ 4.-1.j, 2.+3.j, 1.+0.j]])
  157. """
  158. c = np.asarray(c).ravel()
  159. if r is None:
  160. r = c.conjugate()
  161. else:
  162. r = np.asarray(r).ravel()
  163. # Form a 1-D array containing a reversed c followed by r[1:] that could be
  164. # strided to give us toeplitz matrix.
  165. vals = np.concatenate((c[::-1], r[1:]))
  166. out_shp = len(c), len(r)
  167. n = vals.strides[0]
  168. return as_strided(vals[len(c)-1:], shape=out_shp, strides=(-n, n)).copy()
  169. def circulant(c):
  170. """
  171. Construct a circulant matrix.
  172. Parameters
  173. ----------
  174. c : (N,) array_like
  175. 1-D array, the first column of the matrix.
  176. Returns
  177. -------
  178. A : (N, N) ndarray
  179. A circulant matrix whose first column is `c`.
  180. See Also
  181. --------
  182. toeplitz : Toeplitz matrix
  183. hankel : Hankel matrix
  184. solve_circulant : Solve a circulant system.
  185. Notes
  186. -----
  187. .. versionadded:: 0.8.0
  188. Examples
  189. --------
  190. >>> from scipy.linalg import circulant
  191. >>> circulant([1, 2, 3])
  192. array([[1, 3, 2],
  193. [2, 1, 3],
  194. [3, 2, 1]])
  195. """
  196. c = np.asarray(c).ravel()
  197. # Form an extended array that could be strided to give circulant version
  198. c_ext = np.concatenate((c[::-1], c[:0:-1]))
  199. L = len(c)
  200. n = c_ext.strides[0]
  201. return as_strided(c_ext[L-1:], shape=(L, L), strides=(-n, n)).copy()
  202. def hankel(c, r=None):
  203. """
  204. Construct a Hankel matrix.
  205. The Hankel matrix has constant anti-diagonals, with `c` as its
  206. first column and `r` as its last row. If `r` is not given, then
  207. `r = zeros_like(c)` is assumed.
  208. Parameters
  209. ----------
  210. c : array_like
  211. First column of the matrix. Whatever the actual shape of `c`, it
  212. will be converted to a 1-D array.
  213. r : array_like, optional
  214. Last row of the matrix. If None, ``r = zeros_like(c)`` is assumed.
  215. r[0] is ignored; the last row of the returned matrix is
  216. ``[c[-1], r[1:]]``. Whatever the actual shape of `r`, it will be
  217. converted to a 1-D array.
  218. Returns
  219. -------
  220. A : (len(c), len(r)) ndarray
  221. The Hankel matrix. Dtype is the same as ``(c[0] + r[0]).dtype``.
  222. See Also
  223. --------
  224. toeplitz : Toeplitz matrix
  225. circulant : circulant matrix
  226. Examples
  227. --------
  228. >>> from scipy.linalg import hankel
  229. >>> hankel([1, 17, 99])
  230. array([[ 1, 17, 99],
  231. [17, 99, 0],
  232. [99, 0, 0]])
  233. >>> hankel([1,2,3,4], [4,7,7,8,9])
  234. array([[1, 2, 3, 4, 7],
  235. [2, 3, 4, 7, 7],
  236. [3, 4, 7, 7, 8],
  237. [4, 7, 7, 8, 9]])
  238. """
  239. c = np.asarray(c).ravel()
  240. if r is None:
  241. r = np.zeros_like(c)
  242. else:
  243. r = np.asarray(r).ravel()
  244. # Form a 1-D array of values to be used in the matrix, containing `c`
  245. # followed by r[1:].
  246. vals = np.concatenate((c, r[1:]))
  247. # Stride on concatenated array to get hankel matrix
  248. out_shp = len(c), len(r)
  249. n = vals.strides[0]
  250. return as_strided(vals, shape=out_shp, strides=(n, n)).copy()
  251. def hadamard(n, dtype=int):
  252. """
  253. Construct an Hadamard matrix.
  254. Constructs an n-by-n Hadamard matrix, using Sylvester's
  255. construction. `n` must be a power of 2.
  256. Parameters
  257. ----------
  258. n : int
  259. The order of the matrix. `n` must be a power of 2.
  260. dtype : dtype, optional
  261. The data type of the array to be constructed.
  262. Returns
  263. -------
  264. H : (n, n) ndarray
  265. The Hadamard matrix.
  266. Notes
  267. -----
  268. .. versionadded:: 0.8.0
  269. Examples
  270. --------
  271. >>> from scipy.linalg import hadamard
  272. >>> hadamard(2, dtype=complex)
  273. array([[ 1.+0.j, 1.+0.j],
  274. [ 1.+0.j, -1.-0.j]])
  275. >>> hadamard(4)
  276. array([[ 1, 1, 1, 1],
  277. [ 1, -1, 1, -1],
  278. [ 1, 1, -1, -1],
  279. [ 1, -1, -1, 1]])
  280. """
  281. # This function is a slightly modified version of the
  282. # function contributed by Ivo in ticket #675.
  283. if n < 1:
  284. lg2 = 0
  285. else:
  286. lg2 = int(math.log(n, 2))
  287. if 2 ** lg2 != n:
  288. raise ValueError("n must be an positive integer, and n must be "
  289. "a power of 2")
  290. H = np.array([[1]], dtype=dtype)
  291. # Sylvester's construction
  292. for i in range(0, lg2):
  293. H = np.vstack((np.hstack((H, H)), np.hstack((H, -H))))
  294. return H
  295. def leslie(f, s):
  296. """
  297. Create a Leslie matrix.
  298. Given the length n array of fecundity coefficients `f` and the length
  299. n-1 array of survival coefficients `s`, return the associated Leslie
  300. matrix.
  301. Parameters
  302. ----------
  303. f : (N,) array_like
  304. The "fecundity" coefficients.
  305. s : (N-1,) array_like
  306. The "survival" coefficients, has to be 1-D. The length of `s`
  307. must be one less than the length of `f`, and it must be at least 1.
  308. Returns
  309. -------
  310. L : (N, N) ndarray
  311. The array is zero except for the first row,
  312. which is `f`, and the first sub-diagonal, which is `s`.
  313. The data-type of the array will be the data-type of ``f[0]+s[0]``.
  314. Notes
  315. -----
  316. .. versionadded:: 0.8.0
  317. The Leslie matrix is used to model discrete-time, age-structured
  318. population growth [1]_ [2]_. In a population with `n` age classes, two sets
  319. of parameters define a Leslie matrix: the `n` "fecundity coefficients",
  320. which give the number of offspring per-capita produced by each age
  321. class, and the `n` - 1 "survival coefficients", which give the
  322. per-capita survival rate of each age class.
  323. References
  324. ----------
  325. .. [1] P. H. Leslie, On the use of matrices in certain population
  326. mathematics, Biometrika, Vol. 33, No. 3, 183--212 (Nov. 1945)
  327. .. [2] P. H. Leslie, Some further notes on the use of matrices in
  328. population mathematics, Biometrika, Vol. 35, No. 3/4, 213--245
  329. (Dec. 1948)
  330. Examples
  331. --------
  332. >>> from scipy.linalg import leslie
  333. >>> leslie([0.1, 2.0, 1.0, 0.1], [0.2, 0.8, 0.7])
  334. array([[ 0.1, 2. , 1. , 0.1],
  335. [ 0.2, 0. , 0. , 0. ],
  336. [ 0. , 0.8, 0. , 0. ],
  337. [ 0. , 0. , 0.7, 0. ]])
  338. """
  339. f = np.atleast_1d(f)
  340. s = np.atleast_1d(s)
  341. if f.ndim != 1:
  342. raise ValueError("Incorrect shape for f. f must be 1D")
  343. if s.ndim != 1:
  344. raise ValueError("Incorrect shape for s. s must be 1D")
  345. if f.size != s.size + 1:
  346. raise ValueError("Incorrect lengths for f and s. The length"
  347. " of s must be one less than the length of f.")
  348. if s.size == 0:
  349. raise ValueError("The length of s must be at least 1.")
  350. tmp = f[0] + s[0]
  351. n = f.size
  352. a = np.zeros((n, n), dtype=tmp.dtype)
  353. a[0] = f
  354. a[list(range(1, n)), list(range(0, n - 1))] = s
  355. return a
  356. def kron(a, b):
  357. """
  358. Kronecker product.
  359. The result is the block matrix::
  360. a[0,0]*b a[0,1]*b ... a[0,-1]*b
  361. a[1,0]*b a[1,1]*b ... a[1,-1]*b
  362. ...
  363. a[-1,0]*b a[-1,1]*b ... a[-1,-1]*b
  364. Parameters
  365. ----------
  366. a : (M, N) ndarray
  367. Input array
  368. b : (P, Q) ndarray
  369. Input array
  370. Returns
  371. -------
  372. A : (M*P, N*Q) ndarray
  373. Kronecker product of `a` and `b`.
  374. Examples
  375. --------
  376. >>> from numpy import array
  377. >>> from scipy.linalg import kron
  378. >>> kron(array([[1,2],[3,4]]), array([[1,1,1]]))
  379. array([[1, 1, 1, 2, 2, 2],
  380. [3, 3, 3, 4, 4, 4]])
  381. """
  382. if not a.flags['CONTIGUOUS']:
  383. a = np.reshape(a, a.shape)
  384. if not b.flags['CONTIGUOUS']:
  385. b = np.reshape(b, b.shape)
  386. o = np.outer(a, b)
  387. o = o.reshape(a.shape + b.shape)
  388. return np.concatenate(np.concatenate(o, axis=1), axis=1)
  389. def block_diag(*arrs):
  390. """
  391. Create a block diagonal matrix from provided arrays.
  392. Given the inputs `A`, `B` and `C`, the output will have these
  393. arrays arranged on the diagonal::
  394. [[A, 0, 0],
  395. [0, B, 0],
  396. [0, 0, C]]
  397. Parameters
  398. ----------
  399. A, B, C, ... : array_like, up to 2-D
  400. Input arrays. A 1-D array or array_like sequence of length `n` is
  401. treated as a 2-D array with shape ``(1,n)``.
  402. Returns
  403. -------
  404. D : ndarray
  405. Array with `A`, `B`, `C`, ... on the diagonal. `D` has the
  406. same dtype as `A`.
  407. Notes
  408. -----
  409. If all the input arrays are square, the output is known as a
  410. block diagonal matrix.
  411. Empty sequences (i.e., array-likes of zero size) will not be ignored.
  412. Noteworthy, both [] and [[]] are treated as matrices with shape ``(1,0)``.
  413. Examples
  414. --------
  415. >>> import numpy as np
  416. >>> from scipy.linalg import block_diag
  417. >>> A = [[1, 0],
  418. ... [0, 1]]
  419. >>> B = [[3, 4, 5],
  420. ... [6, 7, 8]]
  421. >>> C = [[7]]
  422. >>> P = np.zeros((2, 0), dtype='int32')
  423. >>> block_diag(A, B, C)
  424. array([[1, 0, 0, 0, 0, 0],
  425. [0, 1, 0, 0, 0, 0],
  426. [0, 0, 3, 4, 5, 0],
  427. [0, 0, 6, 7, 8, 0],
  428. [0, 0, 0, 0, 0, 7]])
  429. >>> block_diag(A, P, B, C)
  430. array([[1, 0, 0, 0, 0, 0],
  431. [0, 1, 0, 0, 0, 0],
  432. [0, 0, 0, 0, 0, 0],
  433. [0, 0, 0, 0, 0, 0],
  434. [0, 0, 3, 4, 5, 0],
  435. [0, 0, 6, 7, 8, 0],
  436. [0, 0, 0, 0, 0, 7]])
  437. >>> block_diag(1.0, [2, 3], [[4, 5], [6, 7]])
  438. array([[ 1., 0., 0., 0., 0.],
  439. [ 0., 2., 3., 0., 0.],
  440. [ 0., 0., 0., 4., 5.],
  441. [ 0., 0., 0., 6., 7.]])
  442. """
  443. if arrs == ():
  444. arrs = ([],)
  445. arrs = [np.atleast_2d(a) for a in arrs]
  446. bad_args = [k for k in range(len(arrs)) if arrs[k].ndim > 2]
  447. if bad_args:
  448. raise ValueError("arguments in the following positions have dimension "
  449. "greater than 2: %s" % bad_args)
  450. shapes = np.array([a.shape for a in arrs])
  451. out_dtype = np.result_type(*[arr.dtype for arr in arrs])
  452. out = np.zeros(np.sum(shapes, axis=0), dtype=out_dtype)
  453. r, c = 0, 0
  454. for i, (rr, cc) in enumerate(shapes):
  455. out[r:r + rr, c:c + cc] = arrs[i]
  456. r += rr
  457. c += cc
  458. return out
  459. def companion(a):
  460. """
  461. Create a companion matrix.
  462. Create the companion matrix [1]_ associated with the polynomial whose
  463. coefficients are given in `a`.
  464. Parameters
  465. ----------
  466. a : (N,) array_like
  467. 1-D array of polynomial coefficients. The length of `a` must be
  468. at least two, and ``a[0]`` must not be zero.
  469. Returns
  470. -------
  471. c : (N-1, N-1) ndarray
  472. The first row of `c` is ``-a[1:]/a[0]``, and the first
  473. sub-diagonal is all ones. The data-type of the array is the same
  474. as the data-type of ``1.0*a[0]``.
  475. Raises
  476. ------
  477. ValueError
  478. If any of the following are true: a) ``a.ndim != 1``;
  479. b) ``a.size < 2``; c) ``a[0] == 0``.
  480. Notes
  481. -----
  482. .. versionadded:: 0.8.0
  483. References
  484. ----------
  485. .. [1] R. A. Horn & C. R. Johnson, *Matrix Analysis*. Cambridge, UK:
  486. Cambridge University Press, 1999, pp. 146-7.
  487. Examples
  488. --------
  489. >>> from scipy.linalg import companion
  490. >>> companion([1, -10, 31, -30])
  491. array([[ 10., -31., 30.],
  492. [ 1., 0., 0.],
  493. [ 0., 1., 0.]])
  494. """
  495. a = np.atleast_1d(a)
  496. if a.ndim != 1:
  497. raise ValueError("Incorrect shape for `a`. `a` must be "
  498. "one-dimensional.")
  499. if a.size < 2:
  500. raise ValueError("The length of `a` must be at least 2.")
  501. if a[0] == 0:
  502. raise ValueError("The first coefficient in `a` must not be zero.")
  503. first_row = -a[1:] / (1.0 * a[0])
  504. n = a.size
  505. c = np.zeros((n - 1, n - 1), dtype=first_row.dtype)
  506. c[0] = first_row
  507. c[list(range(1, n - 1)), list(range(0, n - 2))] = 1
  508. return c
  509. def helmert(n, full=False):
  510. """
  511. Create an Helmert matrix of order `n`.
  512. This has applications in statistics, compositional or simplicial analysis,
  513. and in Aitchison geometry.
  514. Parameters
  515. ----------
  516. n : int
  517. The size of the array to create.
  518. full : bool, optional
  519. If True the (n, n) ndarray will be returned.
  520. Otherwise the submatrix that does not include the first
  521. row will be returned.
  522. Default: False.
  523. Returns
  524. -------
  525. M : ndarray
  526. The Helmert matrix.
  527. The shape is (n, n) or (n-1, n) depending on the `full` argument.
  528. Examples
  529. --------
  530. >>> from scipy.linalg import helmert
  531. >>> helmert(5, full=True)
  532. array([[ 0.4472136 , 0.4472136 , 0.4472136 , 0.4472136 , 0.4472136 ],
  533. [ 0.70710678, -0.70710678, 0. , 0. , 0. ],
  534. [ 0.40824829, 0.40824829, -0.81649658, 0. , 0. ],
  535. [ 0.28867513, 0.28867513, 0.28867513, -0.8660254 , 0. ],
  536. [ 0.2236068 , 0.2236068 , 0.2236068 , 0.2236068 , -0.89442719]])
  537. """
  538. H = np.tril(np.ones((n, n)), -1) - np.diag(np.arange(n))
  539. d = np.arange(n) * np.arange(1, n+1)
  540. H[0] = 1
  541. d[0] = n
  542. H_full = H / np.sqrt(d)[:, np.newaxis]
  543. if full:
  544. return H_full
  545. else:
  546. return H_full[1:]
  547. def hilbert(n):
  548. """
  549. Create a Hilbert matrix of order `n`.
  550. Returns the `n` by `n` array with entries `h[i,j] = 1 / (i + j + 1)`.
  551. Parameters
  552. ----------
  553. n : int
  554. The size of the array to create.
  555. Returns
  556. -------
  557. h : (n, n) ndarray
  558. The Hilbert matrix.
  559. See Also
  560. --------
  561. invhilbert : Compute the inverse of a Hilbert matrix.
  562. Notes
  563. -----
  564. .. versionadded:: 0.10.0
  565. Examples
  566. --------
  567. >>> from scipy.linalg import hilbert
  568. >>> hilbert(3)
  569. array([[ 1. , 0.5 , 0.33333333],
  570. [ 0.5 , 0.33333333, 0.25 ],
  571. [ 0.33333333, 0.25 , 0.2 ]])
  572. """
  573. values = 1.0 / (1.0 + np.arange(2 * n - 1))
  574. h = hankel(values[:n], r=values[n - 1:])
  575. return h
  576. def invhilbert(n, exact=False):
  577. """
  578. Compute the inverse of the Hilbert matrix of order `n`.
  579. The entries in the inverse of a Hilbert matrix are integers. When `n`
  580. is greater than 14, some entries in the inverse exceed the upper limit
  581. of 64 bit integers. The `exact` argument provides two options for
  582. dealing with these large integers.
  583. Parameters
  584. ----------
  585. n : int
  586. The order of the Hilbert matrix.
  587. exact : bool, optional
  588. If False, the data type of the array that is returned is np.float64,
  589. and the array is an approximation of the inverse.
  590. If True, the array is the exact integer inverse array. To represent
  591. the exact inverse when n > 14, the returned array is an object array
  592. of long integers. For n <= 14, the exact inverse is returned as an
  593. array with data type np.int64.
  594. Returns
  595. -------
  596. invh : (n, n) ndarray
  597. The data type of the array is np.float64 if `exact` is False.
  598. If `exact` is True, the data type is either np.int64 (for n <= 14)
  599. or object (for n > 14). In the latter case, the objects in the
  600. array will be long integers.
  601. See Also
  602. --------
  603. hilbert : Create a Hilbert matrix.
  604. Notes
  605. -----
  606. .. versionadded:: 0.10.0
  607. Examples
  608. --------
  609. >>> from scipy.linalg import invhilbert
  610. >>> invhilbert(4)
  611. array([[ 16., -120., 240., -140.],
  612. [ -120., 1200., -2700., 1680.],
  613. [ 240., -2700., 6480., -4200.],
  614. [ -140., 1680., -4200., 2800.]])
  615. >>> invhilbert(4, exact=True)
  616. array([[ 16, -120, 240, -140],
  617. [ -120, 1200, -2700, 1680],
  618. [ 240, -2700, 6480, -4200],
  619. [ -140, 1680, -4200, 2800]], dtype=int64)
  620. >>> invhilbert(16)[7,7]
  621. 4.2475099528537506e+19
  622. >>> invhilbert(16, exact=True)[7,7]
  623. 42475099528537378560
  624. """
  625. from scipy.special import comb
  626. if exact:
  627. if n > 14:
  628. dtype = object
  629. else:
  630. dtype = np.int64
  631. else:
  632. dtype = np.float64
  633. invh = np.empty((n, n), dtype=dtype)
  634. for i in range(n):
  635. for j in range(0, i + 1):
  636. s = i + j
  637. invh[i, j] = ((-1) ** s * (s + 1) *
  638. comb(n + i, n - j - 1, exact) *
  639. comb(n + j, n - i - 1, exact) *
  640. comb(s, i, exact) ** 2)
  641. if i != j:
  642. invh[j, i] = invh[i, j]
  643. return invh
  644. def pascal(n, kind='symmetric', exact=True):
  645. """
  646. Returns the n x n Pascal matrix.
  647. The Pascal matrix is a matrix containing the binomial coefficients as
  648. its elements.
  649. Parameters
  650. ----------
  651. n : int
  652. The size of the matrix to create; that is, the result is an n x n
  653. matrix.
  654. kind : str, optional
  655. Must be one of 'symmetric', 'lower', or 'upper'.
  656. Default is 'symmetric'.
  657. exact : bool, optional
  658. If `exact` is True, the result is either an array of type
  659. numpy.uint64 (if n < 35) or an object array of Python long integers.
  660. If `exact` is False, the coefficients in the matrix are computed using
  661. `scipy.special.comb` with `exact=False`. The result will be a floating
  662. point array, and the values in the array will not be the exact
  663. coefficients, but this version is much faster than `exact=True`.
  664. Returns
  665. -------
  666. p : (n, n) ndarray
  667. The Pascal matrix.
  668. See Also
  669. --------
  670. invpascal
  671. Notes
  672. -----
  673. See https://en.wikipedia.org/wiki/Pascal_matrix for more information
  674. about Pascal matrices.
  675. .. versionadded:: 0.11.0
  676. Examples
  677. --------
  678. >>> from scipy.linalg import pascal
  679. >>> pascal(4)
  680. array([[ 1, 1, 1, 1],
  681. [ 1, 2, 3, 4],
  682. [ 1, 3, 6, 10],
  683. [ 1, 4, 10, 20]], dtype=uint64)
  684. >>> pascal(4, kind='lower')
  685. array([[1, 0, 0, 0],
  686. [1, 1, 0, 0],
  687. [1, 2, 1, 0],
  688. [1, 3, 3, 1]], dtype=uint64)
  689. >>> pascal(50)[-1, -1]
  690. 25477612258980856902730428600
  691. >>> from scipy.special import comb
  692. >>> comb(98, 49, exact=True)
  693. 25477612258980856902730428600
  694. """
  695. from scipy.special import comb
  696. if kind not in ['symmetric', 'lower', 'upper']:
  697. raise ValueError("kind must be 'symmetric', 'lower', or 'upper'")
  698. if exact:
  699. if n >= 35:
  700. L_n = np.empty((n, n), dtype=object)
  701. L_n.fill(0)
  702. else:
  703. L_n = np.zeros((n, n), dtype=np.uint64)
  704. for i in range(n):
  705. for j in range(i + 1):
  706. L_n[i, j] = comb(i, j, exact=True)
  707. else:
  708. L_n = comb(*np.ogrid[:n, :n])
  709. if kind == 'lower':
  710. p = L_n
  711. elif kind == 'upper':
  712. p = L_n.T
  713. else:
  714. p = np.dot(L_n, L_n.T)
  715. return p
  716. def invpascal(n, kind='symmetric', exact=True):
  717. """
  718. Returns the inverse of the n x n Pascal matrix.
  719. The Pascal matrix is a matrix containing the binomial coefficients as
  720. its elements.
  721. Parameters
  722. ----------
  723. n : int
  724. The size of the matrix to create; that is, the result is an n x n
  725. matrix.
  726. kind : str, optional
  727. Must be one of 'symmetric', 'lower', or 'upper'.
  728. Default is 'symmetric'.
  729. exact : bool, optional
  730. If `exact` is True, the result is either an array of type
  731. ``numpy.int64`` (if `n` <= 35) or an object array of Python integers.
  732. If `exact` is False, the coefficients in the matrix are computed using
  733. `scipy.special.comb` with `exact=False`. The result will be a floating
  734. point array, and for large `n`, the values in the array will not be the
  735. exact coefficients.
  736. Returns
  737. -------
  738. invp : (n, n) ndarray
  739. The inverse of the Pascal matrix.
  740. See Also
  741. --------
  742. pascal
  743. Notes
  744. -----
  745. .. versionadded:: 0.16.0
  746. References
  747. ----------
  748. .. [1] "Pascal matrix", https://en.wikipedia.org/wiki/Pascal_matrix
  749. .. [2] Cohen, A. M., "The inverse of a Pascal matrix", Mathematical
  750. Gazette, 59(408), pp. 111-112, 1975.
  751. Examples
  752. --------
  753. >>> from scipy.linalg import invpascal, pascal
  754. >>> invp = invpascal(5)
  755. >>> invp
  756. array([[ 5, -10, 10, -5, 1],
  757. [-10, 30, -35, 19, -4],
  758. [ 10, -35, 46, -27, 6],
  759. [ -5, 19, -27, 17, -4],
  760. [ 1, -4, 6, -4, 1]])
  761. >>> p = pascal(5)
  762. >>> p.dot(invp)
  763. array([[ 1., 0., 0., 0., 0.],
  764. [ 0., 1., 0., 0., 0.],
  765. [ 0., 0., 1., 0., 0.],
  766. [ 0., 0., 0., 1., 0.],
  767. [ 0., 0., 0., 0., 1.]])
  768. An example of the use of `kind` and `exact`:
  769. >>> invpascal(5, kind='lower', exact=False)
  770. array([[ 1., -0., 0., -0., 0.],
  771. [-1., 1., -0., 0., -0.],
  772. [ 1., -2., 1., -0., 0.],
  773. [-1., 3., -3., 1., -0.],
  774. [ 1., -4., 6., -4., 1.]])
  775. """
  776. from scipy.special import comb
  777. if kind not in ['symmetric', 'lower', 'upper']:
  778. raise ValueError("'kind' must be 'symmetric', 'lower' or 'upper'.")
  779. if kind == 'symmetric':
  780. if exact:
  781. if n > 34:
  782. dt = object
  783. else:
  784. dt = np.int64
  785. else:
  786. dt = np.float64
  787. invp = np.empty((n, n), dtype=dt)
  788. for i in range(n):
  789. for j in range(0, i + 1):
  790. v = 0
  791. for k in range(n - i):
  792. v += comb(i + k, k, exact=exact) * comb(i + k, i + k - j,
  793. exact=exact)
  794. invp[i, j] = (-1)**(i - j) * v
  795. if i != j:
  796. invp[j, i] = invp[i, j]
  797. else:
  798. # For the 'lower' and 'upper' cases, we computer the inverse by
  799. # changing the sign of every other diagonal of the pascal matrix.
  800. invp = pascal(n, kind=kind, exact=exact)
  801. if invp.dtype == np.uint64:
  802. # This cast from np.uint64 to int64 OK, because if `kind` is not
  803. # "symmetric", the values in invp are all much less than 2**63.
  804. invp = invp.view(np.int64)
  805. # The toeplitz matrix has alternating bands of 1 and -1.
  806. invp *= toeplitz((-1)**np.arange(n)).astype(invp.dtype)
  807. return invp
  808. def dft(n, scale=None):
  809. """
  810. Discrete Fourier transform matrix.
  811. Create the matrix that computes the discrete Fourier transform of a
  812. sequence [1]_. The nth primitive root of unity used to generate the
  813. matrix is exp(-2*pi*i/n), where i = sqrt(-1).
  814. Parameters
  815. ----------
  816. n : int
  817. Size the matrix to create.
  818. scale : str, optional
  819. Must be None, 'sqrtn', or 'n'.
  820. If `scale` is 'sqrtn', the matrix is divided by `sqrt(n)`.
  821. If `scale` is 'n', the matrix is divided by `n`.
  822. If `scale` is None (the default), the matrix is not normalized, and the
  823. return value is simply the Vandermonde matrix of the roots of unity.
  824. Returns
  825. -------
  826. m : (n, n) ndarray
  827. The DFT matrix.
  828. Notes
  829. -----
  830. When `scale` is None, multiplying a vector by the matrix returned by
  831. `dft` is mathematically equivalent to (but much less efficient than)
  832. the calculation performed by `scipy.fft.fft`.
  833. .. versionadded:: 0.14.0
  834. References
  835. ----------
  836. .. [1] "DFT matrix", https://en.wikipedia.org/wiki/DFT_matrix
  837. Examples
  838. --------
  839. >>> import numpy as np
  840. >>> from scipy.linalg import dft
  841. >>> np.set_printoptions(precision=2, suppress=True) # for compact output
  842. >>> m = dft(5)
  843. >>> m
  844. array([[ 1. +0.j , 1. +0.j , 1. +0.j , 1. +0.j , 1. +0.j ],
  845. [ 1. +0.j , 0.31-0.95j, -0.81-0.59j, -0.81+0.59j, 0.31+0.95j],
  846. [ 1. +0.j , -0.81-0.59j, 0.31+0.95j, 0.31-0.95j, -0.81+0.59j],
  847. [ 1. +0.j , -0.81+0.59j, 0.31-0.95j, 0.31+0.95j, -0.81-0.59j],
  848. [ 1. +0.j , 0.31+0.95j, -0.81+0.59j, -0.81-0.59j, 0.31-0.95j]])
  849. >>> x = np.array([1, 2, 3, 0, 3])
  850. >>> m @ x # Compute the DFT of x
  851. array([ 9. +0.j , 0.12-0.81j, -2.12+3.44j, -2.12-3.44j, 0.12+0.81j])
  852. Verify that ``m @ x`` is the same as ``fft(x)``.
  853. >>> from scipy.fft import fft
  854. >>> fft(x) # Same result as m @ x
  855. array([ 9. +0.j , 0.12-0.81j, -2.12+3.44j, -2.12-3.44j, 0.12+0.81j])
  856. """
  857. if scale not in [None, 'sqrtn', 'n']:
  858. raise ValueError("scale must be None, 'sqrtn', or 'n'; "
  859. "%r is not valid." % (scale,))
  860. omegas = np.exp(-2j * np.pi * np.arange(n) / n).reshape(-1, 1)
  861. m = omegas ** np.arange(n)
  862. if scale == 'sqrtn':
  863. m /= math.sqrt(n)
  864. elif scale == 'n':
  865. m /= n
  866. return m
  867. def fiedler(a):
  868. """Returns a symmetric Fiedler matrix
  869. Given an sequence of numbers `a`, Fiedler matrices have the structure
  870. ``F[i, j] = np.abs(a[i] - a[j])``, and hence zero diagonals and nonnegative
  871. entries. A Fiedler matrix has a dominant positive eigenvalue and other
  872. eigenvalues are negative. Although not valid generally, for certain inputs,
  873. the inverse and the determinant can be derived explicitly as given in [1]_.
  874. Parameters
  875. ----------
  876. a : (n,) array_like
  877. coefficient array
  878. Returns
  879. -------
  880. F : (n, n) ndarray
  881. See Also
  882. --------
  883. circulant, toeplitz
  884. Notes
  885. -----
  886. .. versionadded:: 1.3.0
  887. References
  888. ----------
  889. .. [1] J. Todd, "Basic Numerical Mathematics: Vol.2 : Numerical Algebra",
  890. 1977, Birkhauser, :doi:`10.1007/978-3-0348-7286-7`
  891. Examples
  892. --------
  893. >>> import numpy as np
  894. >>> from scipy.linalg import det, inv, fiedler
  895. >>> a = [1, 4, 12, 45, 77]
  896. >>> n = len(a)
  897. >>> A = fiedler(a)
  898. >>> A
  899. array([[ 0, 3, 11, 44, 76],
  900. [ 3, 0, 8, 41, 73],
  901. [11, 8, 0, 33, 65],
  902. [44, 41, 33, 0, 32],
  903. [76, 73, 65, 32, 0]])
  904. The explicit formulas for determinant and inverse seem to hold only for
  905. monotonically increasing/decreasing arrays. Note the tridiagonal structure
  906. and the corners.
  907. >>> Ai = inv(A)
  908. >>> Ai[np.abs(Ai) < 1e-12] = 0. # cleanup the numerical noise for display
  909. >>> Ai
  910. array([[-0.16008772, 0.16666667, 0. , 0. , 0.00657895],
  911. [ 0.16666667, -0.22916667, 0.0625 , 0. , 0. ],
  912. [ 0. , 0.0625 , -0.07765152, 0.01515152, 0. ],
  913. [ 0. , 0. , 0.01515152, -0.03077652, 0.015625 ],
  914. [ 0.00657895, 0. , 0. , 0.015625 , -0.00904605]])
  915. >>> det(A)
  916. 15409151.999999998
  917. >>> (-1)**(n-1) * 2**(n-2) * np.diff(a).prod() * (a[-1] - a[0])
  918. 15409152
  919. """
  920. a = np.atleast_1d(a)
  921. if a.ndim != 1:
  922. raise ValueError("Input 'a' must be a 1D array.")
  923. if a.size == 0:
  924. return np.array([], dtype=float)
  925. elif a.size == 1:
  926. return np.array([[0.]])
  927. else:
  928. return np.abs(a[:, None] - a)
  929. def fiedler_companion(a):
  930. """ Returns a Fiedler companion matrix
  931. Given a polynomial coefficient array ``a``, this function forms a
  932. pentadiagonal matrix with a special structure whose eigenvalues coincides
  933. with the roots of ``a``.
  934. Parameters
  935. ----------
  936. a : (N,) array_like
  937. 1-D array of polynomial coefficients in descending order with a nonzero
  938. leading coefficient. For ``N < 2``, an empty array is returned.
  939. Returns
  940. -------
  941. c : (N-1, N-1) ndarray
  942. Resulting companion matrix
  943. See Also
  944. --------
  945. companion
  946. Notes
  947. -----
  948. Similar to `companion` the leading coefficient should be nonzero. In the case
  949. the leading coefficient is not 1, other coefficients are rescaled before
  950. the array generation. To avoid numerical issues, it is best to provide a
  951. monic polynomial.
  952. .. versionadded:: 1.3.0
  953. References
  954. ----------
  955. .. [1] M. Fiedler, " A note on companion matrices", Linear Algebra and its
  956. Applications, 2003, :doi:`10.1016/S0024-3795(03)00548-2`
  957. Examples
  958. --------
  959. >>> import numpy as np
  960. >>> from scipy.linalg import fiedler_companion, eigvals
  961. >>> p = np.poly(np.arange(1, 9, 2)) # [1., -16., 86., -176., 105.]
  962. >>> fc = fiedler_companion(p)
  963. >>> fc
  964. array([[ 16., -86., 1., 0.],
  965. [ 1., 0., 0., 0.],
  966. [ 0., 176., 0., -105.],
  967. [ 0., 1., 0., 0.]])
  968. >>> eigvals(fc)
  969. array([7.+0.j, 5.+0.j, 3.+0.j, 1.+0.j])
  970. """
  971. a = np.atleast_1d(a)
  972. if a.ndim != 1:
  973. raise ValueError("Input 'a' must be a 1-D array.")
  974. if a.size <= 2:
  975. if a.size == 2:
  976. return np.array([[-(a/a[0])[-1]]])
  977. return np.array([], dtype=a.dtype)
  978. if a[0] == 0.:
  979. raise ValueError('Leading coefficient is zero.')
  980. a = a/a[0]
  981. n = a.size - 1
  982. c = np.zeros((n, n), dtype=a.dtype)
  983. # subdiagonals
  984. c[range(3, n, 2), range(1, n-2, 2)] = 1.
  985. c[range(2, n, 2), range(1, n-1, 2)] = -a[3::2]
  986. # superdiagonals
  987. c[range(0, n-2, 2), range(2, n, 2)] = 1.
  988. c[range(0, n-1, 2), range(1, n, 2)] = -a[2::2]
  989. c[[0, 1], 0] = [-a[1], 1]
  990. return c
  991. def convolution_matrix(a, n, mode='full'):
  992. """
  993. Construct a convolution matrix.
  994. Constructs the Toeplitz matrix representing one-dimensional
  995. convolution [1]_. See the notes below for details.
  996. Parameters
  997. ----------
  998. a : (m,) array_like
  999. The 1-D array to convolve.
  1000. n : int
  1001. The number of columns in the resulting matrix. It gives the length
  1002. of the input to be convolved with `a`. This is analogous to the
  1003. length of `v` in ``numpy.convolve(a, v)``.
  1004. mode : str
  1005. This is analogous to `mode` in ``numpy.convolve(v, a, mode)``.
  1006. It must be one of ('full', 'valid', 'same').
  1007. See below for how `mode` determines the shape of the result.
  1008. Returns
  1009. -------
  1010. A : (k, n) ndarray
  1011. The convolution matrix whose row count `k` depends on `mode`::
  1012. ======= =========================
  1013. mode k
  1014. ======= =========================
  1015. 'full' m + n -1
  1016. 'same' max(m, n)
  1017. 'valid' max(m, n) - min(m, n) + 1
  1018. ======= =========================
  1019. See Also
  1020. --------
  1021. toeplitz : Toeplitz matrix
  1022. Notes
  1023. -----
  1024. The code::
  1025. A = convolution_matrix(a, n, mode)
  1026. creates a Toeplitz matrix `A` such that ``A @ v`` is equivalent to
  1027. using ``convolve(a, v, mode)``. The returned array always has `n`
  1028. columns. The number of rows depends on the specified `mode`, as
  1029. explained above.
  1030. In the default 'full' mode, the entries of `A` are given by::
  1031. A[i, j] == (a[i-j] if (0 <= (i-j) < m) else 0)
  1032. where ``m = len(a)``. Suppose, for example, the input array is
  1033. ``[x, y, z]``. The convolution matrix has the form::
  1034. [x, 0, 0, ..., 0, 0]
  1035. [y, x, 0, ..., 0, 0]
  1036. [z, y, x, ..., 0, 0]
  1037. ...
  1038. [0, 0, 0, ..., x, 0]
  1039. [0, 0, 0, ..., y, x]
  1040. [0, 0, 0, ..., z, y]
  1041. [0, 0, 0, ..., 0, z]
  1042. In 'valid' mode, the entries of `A` are given by::
  1043. A[i, j] == (a[i-j+m-1] if (0 <= (i-j+m-1) < m) else 0)
  1044. This corresponds to a matrix whose rows are the subset of those from
  1045. the 'full' case where all the coefficients in `a` are contained in the
  1046. row. For input ``[x, y, z]``, this array looks like::
  1047. [z, y, x, 0, 0, ..., 0, 0, 0]
  1048. [0, z, y, x, 0, ..., 0, 0, 0]
  1049. [0, 0, z, y, x, ..., 0, 0, 0]
  1050. ...
  1051. [0, 0, 0, 0, 0, ..., x, 0, 0]
  1052. [0, 0, 0, 0, 0, ..., y, x, 0]
  1053. [0, 0, 0, 0, 0, ..., z, y, x]
  1054. In the 'same' mode, the entries of `A` are given by::
  1055. d = (m - 1) // 2
  1056. A[i, j] == (a[i-j+d] if (0 <= (i-j+d) < m) else 0)
  1057. The typical application of the 'same' mode is when one has a signal of
  1058. length `n` (with `n` greater than ``len(a)``), and the desired output
  1059. is a filtered signal that is still of length `n`.
  1060. For input ``[x, y, z]``, this array looks like::
  1061. [y, x, 0, 0, ..., 0, 0, 0]
  1062. [z, y, x, 0, ..., 0, 0, 0]
  1063. [0, z, y, x, ..., 0, 0, 0]
  1064. [0, 0, z, y, ..., 0, 0, 0]
  1065. ...
  1066. [0, 0, 0, 0, ..., y, x, 0]
  1067. [0, 0, 0, 0, ..., z, y, x]
  1068. [0, 0, 0, 0, ..., 0, z, y]
  1069. .. versionadded:: 1.5.0
  1070. References
  1071. ----------
  1072. .. [1] "Convolution", https://en.wikipedia.org/wiki/Convolution
  1073. Examples
  1074. --------
  1075. >>> import numpy as np
  1076. >>> from scipy.linalg import convolution_matrix
  1077. >>> A = convolution_matrix([-1, 4, -2], 5, mode='same')
  1078. >>> A
  1079. array([[ 4, -1, 0, 0, 0],
  1080. [-2, 4, -1, 0, 0],
  1081. [ 0, -2, 4, -1, 0],
  1082. [ 0, 0, -2, 4, -1],
  1083. [ 0, 0, 0, -2, 4]])
  1084. Compare multiplication by `A` with the use of `numpy.convolve`.
  1085. >>> x = np.array([1, 2, 0, -3, 0.5])
  1086. >>> A @ x
  1087. array([ 2. , 6. , -1. , -12.5, 8. ])
  1088. Verify that ``A @ x`` produced the same result as applying the
  1089. convolution function.
  1090. >>> np.convolve([-1, 4, -2], x, mode='same')
  1091. array([ 2. , 6. , -1. , -12.5, 8. ])
  1092. For comparison to the case ``mode='same'`` shown above, here are the
  1093. matrices produced by ``mode='full'`` and ``mode='valid'`` for the
  1094. same coefficients and size.
  1095. >>> convolution_matrix([-1, 4, -2], 5, mode='full')
  1096. array([[-1, 0, 0, 0, 0],
  1097. [ 4, -1, 0, 0, 0],
  1098. [-2, 4, -1, 0, 0],
  1099. [ 0, -2, 4, -1, 0],
  1100. [ 0, 0, -2, 4, -1],
  1101. [ 0, 0, 0, -2, 4],
  1102. [ 0, 0, 0, 0, -2]])
  1103. >>> convolution_matrix([-1, 4, -2], 5, mode='valid')
  1104. array([[-2, 4, -1, 0, 0],
  1105. [ 0, -2, 4, -1, 0],
  1106. [ 0, 0, -2, 4, -1]])
  1107. """
  1108. if n <= 0:
  1109. raise ValueError('n must be a positive integer.')
  1110. a = np.asarray(a)
  1111. if a.ndim != 1:
  1112. raise ValueError('convolution_matrix expects a one-dimensional '
  1113. 'array as input')
  1114. if a.size == 0:
  1115. raise ValueError('len(a) must be at least 1.')
  1116. if mode not in ('full', 'valid', 'same'):
  1117. raise ValueError(
  1118. "'mode' argument must be one of ('full', 'valid', 'same')")
  1119. # create zero padded versions of the array
  1120. az = np.pad(a, (0, n-1), 'constant')
  1121. raz = np.pad(a[::-1], (0, n-1), 'constant')
  1122. if mode == 'same':
  1123. trim = min(n, len(a)) - 1
  1124. tb = trim//2
  1125. te = trim - tb
  1126. col0 = az[tb:len(az)-te]
  1127. row0 = raz[-n-tb:len(raz)-tb]
  1128. elif mode == 'valid':
  1129. tb = min(n, len(a)) - 1
  1130. te = tb
  1131. col0 = az[tb:len(az)-te]
  1132. row0 = raz[-n-tb:len(raz)-tb]
  1133. else: # 'full'
  1134. col0 = az
  1135. row0 = raz[-n:]
  1136. return toeplitz(col0, row0)