Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.9/dist-packages/scipy/linalg/_basic.py: 7%

431 statements  

« prev     ^ index     » next       coverage.py v7.3.1, created at 2023-09-23 06:43 +0000

1# 

2# Author: Pearu Peterson, March 2002 

3# 

4# w/ additions by Travis Oliphant, March 2002 

5# and Jake Vanderplas, August 2012 

6 

7from warnings import warn 

8from itertools import product 

9import numpy as np 

10from numpy import atleast_1d, atleast_2d 

11from .lapack import get_lapack_funcs, _compute_lwork 

12from ._misc import LinAlgError, _datacopied, LinAlgWarning 

13from ._decomp import _asarray_validated 

14from . import _decomp, _decomp_svd 

15from ._solve_toeplitz import levinson 

16from ._cythonized_array_utils import find_det_from_lu 

17from scipy._lib.deprecation import _NoValue, _deprecate_positional_args 

18 

19# deprecated imports to be removed in SciPy 1.13.0 

20from scipy.linalg._flinalg_py import get_flinalg_funcs # noqa 

21 

22__all__ = ['solve', 'solve_triangular', 'solveh_banded', 'solve_banded', 

23 'solve_toeplitz', 'solve_circulant', 'inv', 'det', 'lstsq', 

24 'pinv', 'pinvh', 'matrix_balance', 'matmul_toeplitz'] 

25 

26 

27# The numpy facilities for type-casting checks are too slow for small sized 

28# arrays and eat away the time budget for the checkups. Here we set a 

29# precomputed dict container of the numpy.can_cast() table. 

30 

31# It can be used to determine quickly what a dtype can be cast to LAPACK 

32# compatible types, i.e., 'float32, float64, complex64, complex128'. 

33# Then it can be checked via "casting_dict[arr.dtype.char]" 

34lapack_cast_dict = {x: ''.join([y for y in 'fdFD' if np.can_cast(x, y)]) 

35 for x in np.typecodes['All']} 

36 

37 

38# Linear equations 

39def _solve_check(n, info, lamch=None, rcond=None): 

40 """ Check arguments during the different steps of the solution phase """ 

41 if info < 0: 

42 raise ValueError('LAPACK reported an illegal value in {}-th argument' 

43 '.'.format(-info)) 

44 elif 0 < info: 

45 raise LinAlgError('Matrix is singular.') 

46 

47 if lamch is None: 

48 return 

49 E = lamch('E') 

50 if rcond < E: 

51 warn('Ill-conditioned matrix (rcond={:.6g}): ' 

52 'result may not be accurate.'.format(rcond), 

53 LinAlgWarning, stacklevel=3) 

54 

55 

56def solve(a, b, lower=False, overwrite_a=False, 

57 overwrite_b=False, check_finite=True, assume_a='gen', 

58 transposed=False): 

59 """ 

60 Solves the linear equation set ``a @ x == b`` for the unknown ``x`` 

61 for square `a` matrix. 

62 

63 If the data matrix is known to be a particular type then supplying the 

64 corresponding string to ``assume_a`` key chooses the dedicated solver. 

65 The available options are 

66 

67 =================== ======== 

68 generic matrix 'gen' 

69 symmetric 'sym' 

70 hermitian 'her' 

71 positive definite 'pos' 

72 =================== ======== 

73 

74 If omitted, ``'gen'`` is the default structure. 

75 

76 The datatype of the arrays define which solver is called regardless 

77 of the values. In other words, even when the complex array entries have 

78 precisely zero imaginary parts, the complex solver will be called based 

79 on the data type of the array. 

80 

81 Parameters 

82 ---------- 

83 a : (N, N) array_like 

84 Square input data 

85 b : (N, NRHS) array_like 

86 Input data for the right hand side. 

87 lower : bool, default: False 

88 Ignored if ``assume_a == 'gen'`` (the default). If True, the 

89 calculation uses only the data in the lower triangle of `a`; 

90 entries above the diagonal are ignored. If False (default), the 

91 calculation uses only the data in the upper triangle of `a`; entries 

92 below the diagonal are ignored. 

93 overwrite_a : bool, default: False 

94 Allow overwriting data in `a` (may enhance performance). 

95 overwrite_b : bool, default: False 

96 Allow overwriting data in `b` (may enhance performance). 

97 check_finite : bool, default: True 

98 Whether to check that the input matrices contain only finite numbers. 

99 Disabling may give a performance gain, but may result in problems 

100 (crashes, non-termination) if the inputs do contain infinities or NaNs. 

101 assume_a : str, {'gen', 'sym', 'her', 'pos'} 

102 Valid entries are explained above. 

103 transposed : bool, default: False 

104 If True, solve ``a.T @ x == b``. Raises `NotImplementedError` 

105 for complex `a`. 

106 

107 Returns 

108 ------- 

109 x : (N, NRHS) ndarray 

110 The solution array. 

111 

112 Raises 

113 ------ 

114 ValueError 

115 If size mismatches detected or input a is not square. 

116 LinAlgError 

117 If the matrix is singular. 

118 LinAlgWarning 

119 If an ill-conditioned input a is detected. 

120 NotImplementedError 

121 If transposed is True and input a is a complex matrix. 

122 

123 Notes 

124 ----- 

125 If the input b matrix is a 1-D array with N elements, when supplied 

126 together with an NxN input a, it is assumed as a valid column vector 

127 despite the apparent size mismatch. This is compatible with the 

128 numpy.dot() behavior and the returned result is still 1-D array. 

129 

130 The generic, symmetric, Hermitian and positive definite solutions are 

131 obtained via calling ?GESV, ?SYSV, ?HESV, and ?POSV routines of 

132 LAPACK respectively. 

133 

134 Examples 

135 -------- 

136 Given `a` and `b`, solve for `x`: 

137 

138 >>> import numpy as np 

139 >>> a = np.array([[3, 2, 0], [1, -1, 0], [0, 5, 1]]) 

140 >>> b = np.array([2, 4, -1]) 

141 >>> from scipy import linalg 

142 >>> x = linalg.solve(a, b) 

143 >>> x 

144 array([ 2., -2., 9.]) 

145 >>> np.dot(a, x) == b 

146 array([ True, True, True], dtype=bool) 

147 

148 """ 

149 # Flags for 1-D or N-D right-hand side 

150 b_is_1D = False 

151 

152 a1 = atleast_2d(_asarray_validated(a, check_finite=check_finite)) 

153 b1 = atleast_1d(_asarray_validated(b, check_finite=check_finite)) 

154 n = a1.shape[0] 

155 

156 overwrite_a = overwrite_a or _datacopied(a1, a) 

157 overwrite_b = overwrite_b or _datacopied(b1, b) 

158 

159 if a1.shape[0] != a1.shape[1]: 

160 raise ValueError('Input a needs to be a square matrix.') 

161 

162 if n != b1.shape[0]: 

163 # Last chance to catch 1x1 scalar a and 1-D b arrays 

164 if not (n == 1 and b1.size != 0): 

165 raise ValueError('Input b has to have same number of rows as ' 

166 'input a') 

167 

168 # accommodate empty arrays 

169 if b1.size == 0: 

170 return np.asfortranarray(b1.copy()) 

171 

172 # regularize 1-D b arrays to 2D 

173 if b1.ndim == 1: 

174 if n == 1: 

175 b1 = b1[None, :] 

176 else: 

177 b1 = b1[:, None] 

178 b_is_1D = True 

179 

180 if assume_a not in ('gen', 'sym', 'her', 'pos'): 

181 raise ValueError('{} is not a recognized matrix structure' 

182 ''.format(assume_a)) 

183 

184 # for a real matrix, describe it as "symmetric", not "hermitian" 

185 # (lapack doesn't know what to do with real hermitian matrices) 

186 if assume_a == 'her' and not np.iscomplexobj(a1): 

187 assume_a = 'sym' 

188 

189 # Get the correct lamch function. 

190 # The LAMCH functions only exists for S and D 

191 # So for complex values we have to convert to real/double. 

192 if a1.dtype.char in 'fF': # single precision 

193 lamch = get_lapack_funcs('lamch', dtype='f') 

194 else: 

195 lamch = get_lapack_funcs('lamch', dtype='d') 

196 

197 # Currently we do not have the other forms of the norm calculators 

198 # lansy, lanpo, lanhe. 

199 # However, in any case they only reduce computations slightly... 

200 lange = get_lapack_funcs('lange', (a1,)) 

201 

202 # Since the I-norm and 1-norm are the same for symmetric matrices 

203 # we can collect them all in this one call 

204 # Note however, that when issuing 'gen' and form!='none', then 

205 # the I-norm should be used 

206 if transposed: 

207 trans = 1 

208 norm = 'I' 

209 if np.iscomplexobj(a1): 

210 raise NotImplementedError('scipy.linalg.solve can currently ' 

211 'not solve a^T x = b or a^H x = b ' 

212 'for complex matrices.') 

213 else: 

214 trans = 0 

215 norm = '1' 

216 

217 anorm = lange(norm, a1) 

218 

219 # Generalized case 'gesv' 

220 if assume_a == 'gen': 

221 gecon, getrf, getrs = get_lapack_funcs(('gecon', 'getrf', 'getrs'), 

222 (a1, b1)) 

223 lu, ipvt, info = getrf(a1, overwrite_a=overwrite_a) 

224 _solve_check(n, info) 

225 x, info = getrs(lu, ipvt, b1, 

226 trans=trans, overwrite_b=overwrite_b) 

227 _solve_check(n, info) 

228 rcond, info = gecon(lu, anorm, norm=norm) 

229 # Hermitian case 'hesv' 

230 elif assume_a == 'her': 

231 hecon, hesv, hesv_lw = get_lapack_funcs(('hecon', 'hesv', 

232 'hesv_lwork'), (a1, b1)) 

233 lwork = _compute_lwork(hesv_lw, n, lower) 

234 lu, ipvt, x, info = hesv(a1, b1, lwork=lwork, 

235 lower=lower, 

236 overwrite_a=overwrite_a, 

237 overwrite_b=overwrite_b) 

238 _solve_check(n, info) 

239 rcond, info = hecon(lu, ipvt, anorm) 

240 # Symmetric case 'sysv' 

241 elif assume_a == 'sym': 

242 sycon, sysv, sysv_lw = get_lapack_funcs(('sycon', 'sysv', 

243 'sysv_lwork'), (a1, b1)) 

244 lwork = _compute_lwork(sysv_lw, n, lower) 

245 lu, ipvt, x, info = sysv(a1, b1, lwork=lwork, 

246 lower=lower, 

247 overwrite_a=overwrite_a, 

248 overwrite_b=overwrite_b) 

249 _solve_check(n, info) 

250 rcond, info = sycon(lu, ipvt, anorm) 

251 # Positive definite case 'posv' 

252 else: 

253 pocon, posv = get_lapack_funcs(('pocon', 'posv'), 

254 (a1, b1)) 

255 lu, x, info = posv(a1, b1, lower=lower, 

256 overwrite_a=overwrite_a, 

257 overwrite_b=overwrite_b) 

258 _solve_check(n, info) 

259 rcond, info = pocon(lu, anorm) 

260 

261 _solve_check(n, info, lamch, rcond) 

262 

263 if b_is_1D: 

264 x = x.ravel() 

265 

266 return x 

267 

268 

269def solve_triangular(a, b, trans=0, lower=False, unit_diagonal=False, 

270 overwrite_b=False, check_finite=True): 

271 """ 

272 Solve the equation `a x = b` for `x`, assuming a is a triangular matrix. 

273 

274 Parameters 

275 ---------- 

276 a : (M, M) array_like 

277 A triangular matrix 

278 b : (M,) or (M, N) array_like 

279 Right-hand side matrix in `a x = b` 

280 lower : bool, optional 

281 Use only data contained in the lower triangle of `a`. 

282 Default is to use upper triangle. 

283 trans : {0, 1, 2, 'N', 'T', 'C'}, optional 

284 Type of system to solve: 

285 

286 ======== ========= 

287 trans system 

288 ======== ========= 

289 0 or 'N' a x = b 

290 1 or 'T' a^T x = b 

291 2 or 'C' a^H x = b 

292 ======== ========= 

293 unit_diagonal : bool, optional 

294 If True, diagonal elements of `a` are assumed to be 1 and 

295 will not be referenced. 

296 overwrite_b : bool, optional 

297 Allow overwriting data in `b` (may enhance performance) 

298 check_finite : bool, optional 

299 Whether to check that the input matrices contain only finite numbers. 

300 Disabling may give a performance gain, but may result in problems 

301 (crashes, non-termination) if the inputs do contain infinities or NaNs. 

302 

303 Returns 

304 ------- 

305 x : (M,) or (M, N) ndarray 

306 Solution to the system `a x = b`. Shape of return matches `b`. 

307 

308 Raises 

309 ------ 

310 LinAlgError 

311 If `a` is singular 

312 

313 Notes 

314 ----- 

315 .. versionadded:: 0.9.0 

316 

317 Examples 

318 -------- 

319 Solve the lower triangular system a x = b, where:: 

320 

321 [3 0 0 0] [4] 

322 a = [2 1 0 0] b = [2] 

323 [1 0 1 0] [4] 

324 [1 1 1 1] [2] 

325 

326 >>> import numpy as np 

327 >>> from scipy.linalg import solve_triangular 

328 >>> a = np.array([[3, 0, 0, 0], [2, 1, 0, 0], [1, 0, 1, 0], [1, 1, 1, 1]]) 

329 >>> b = np.array([4, 2, 4, 2]) 

330 >>> x = solve_triangular(a, b, lower=True) 

331 >>> x 

332 array([ 1.33333333, -0.66666667, 2.66666667, -1.33333333]) 

333 >>> a.dot(x) # Check the result 

334 array([ 4., 2., 4., 2.]) 

335 

336 """ 

337 

338 a1 = _asarray_validated(a, check_finite=check_finite) 

339 b1 = _asarray_validated(b, check_finite=check_finite) 

340 if len(a1.shape) != 2 or a1.shape[0] != a1.shape[1]: 

341 raise ValueError('expected square matrix') 

342 if a1.shape[0] != b1.shape[0]: 

343 raise ValueError('shapes of a {} and b {} are incompatible' 

344 .format(a1.shape, b1.shape)) 

345 overwrite_b = overwrite_b or _datacopied(b1, b) 

346 

347 trans = {'N': 0, 'T': 1, 'C': 2}.get(trans, trans) 

348 trtrs, = get_lapack_funcs(('trtrs',), (a1, b1)) 

349 if a1.flags.f_contiguous or trans == 2: 

350 x, info = trtrs(a1, b1, overwrite_b=overwrite_b, lower=lower, 

351 trans=trans, unitdiag=unit_diagonal) 

352 else: 

353 # transposed system is solved since trtrs expects Fortran ordering 

354 x, info = trtrs(a1.T, b1, overwrite_b=overwrite_b, lower=not lower, 

355 trans=not trans, unitdiag=unit_diagonal) 

356 

357 if info == 0: 

358 return x 

359 if info > 0: 

360 raise LinAlgError("singular matrix: resolution failed at diagonal %d" % 

361 (info-1)) 

362 raise ValueError('illegal value in %dth argument of internal trtrs' % 

363 (-info)) 

364 

365 

366def solve_banded(l_and_u, ab, b, overwrite_ab=False, overwrite_b=False, 

367 check_finite=True): 

368 """ 

369 Solve the equation a x = b for x, assuming a is banded matrix. 

370 

371 The matrix a is stored in `ab` using the matrix diagonal ordered form:: 

372 

373 ab[u + i - j, j] == a[i,j] 

374 

375 Example of `ab` (shape of a is (6,6), `u` =1, `l` =2):: 

376 

377 * a01 a12 a23 a34 a45 

378 a00 a11 a22 a33 a44 a55 

379 a10 a21 a32 a43 a54 * 

380 a20 a31 a42 a53 * * 

381 

382 Parameters 

383 ---------- 

384 (l, u) : (integer, integer) 

385 Number of non-zero lower and upper diagonals 

386 ab : (`l` + `u` + 1, M) array_like 

387 Banded matrix 

388 b : (M,) or (M, K) array_like 

389 Right-hand side 

390 overwrite_ab : bool, optional 

391 Discard data in `ab` (may enhance performance) 

392 overwrite_b : bool, optional 

393 Discard data in `b` (may enhance performance) 

394 check_finite : bool, optional 

395 Whether to check that the input matrices contain only finite numbers. 

396 Disabling may give a performance gain, but may result in problems 

397 (crashes, non-termination) if the inputs do contain infinities or NaNs. 

398 

399 Returns 

400 ------- 

401 x : (M,) or (M, K) ndarray 

402 The solution to the system a x = b. Returned shape depends on the 

403 shape of `b`. 

404 

405 Examples 

406 -------- 

407 Solve the banded system a x = b, where:: 

408 

409 [5 2 -1 0 0] [0] 

410 [1 4 2 -1 0] [1] 

411 a = [0 1 3 2 -1] b = [2] 

412 [0 0 1 2 2] [2] 

413 [0 0 0 1 1] [3] 

414 

415 There is one nonzero diagonal below the main diagonal (l = 1), and 

416 two above (u = 2). The diagonal banded form of the matrix is:: 

417 

418 [* * -1 -1 -1] 

419 ab = [* 2 2 2 2] 

420 [5 4 3 2 1] 

421 [1 1 1 1 *] 

422 

423 >>> import numpy as np 

424 >>> from scipy.linalg import solve_banded 

425 >>> ab = np.array([[0, 0, -1, -1, -1], 

426 ... [0, 2, 2, 2, 2], 

427 ... [5, 4, 3, 2, 1], 

428 ... [1, 1, 1, 1, 0]]) 

429 >>> b = np.array([0, 1, 2, 2, 3]) 

430 >>> x = solve_banded((1, 2), ab, b) 

431 >>> x 

432 array([-2.37288136, 3.93220339, -4. , 4.3559322 , -1.3559322 ]) 

433 

434 """ 

435 

436 a1 = _asarray_validated(ab, check_finite=check_finite, as_inexact=True) 

437 b1 = _asarray_validated(b, check_finite=check_finite, as_inexact=True) 

438 # Validate shapes. 

439 if a1.shape[-1] != b1.shape[0]: 

440 raise ValueError("shapes of ab and b are not compatible.") 

441 (nlower, nupper) = l_and_u 

442 if nlower + nupper + 1 != a1.shape[0]: 

443 raise ValueError("invalid values for the number of lower and upper " 

444 "diagonals: l+u+1 (%d) does not equal ab.shape[0] " 

445 "(%d)" % (nlower + nupper + 1, ab.shape[0])) 

446 

447 overwrite_b = overwrite_b or _datacopied(b1, b) 

448 if a1.shape[-1] == 1: 

449 b2 = np.array(b1, copy=(not overwrite_b)) 

450 b2 /= a1[1, 0] 

451 return b2 

452 if nlower == nupper == 1: 

453 overwrite_ab = overwrite_ab or _datacopied(a1, ab) 

454 gtsv, = get_lapack_funcs(('gtsv',), (a1, b1)) 

455 du = a1[0, 1:] 

456 d = a1[1, :] 

457 dl = a1[2, :-1] 

458 du2, d, du, x, info = gtsv(dl, d, du, b1, overwrite_ab, overwrite_ab, 

459 overwrite_ab, overwrite_b) 

460 else: 

461 gbsv, = get_lapack_funcs(('gbsv',), (a1, b1)) 

462 a2 = np.zeros((2*nlower + nupper + 1, a1.shape[1]), dtype=gbsv.dtype) 

463 a2[nlower:, :] = a1 

464 lu, piv, x, info = gbsv(nlower, nupper, a2, b1, overwrite_ab=True, 

465 overwrite_b=overwrite_b) 

466 if info == 0: 

467 return x 

468 if info > 0: 

469 raise LinAlgError("singular matrix") 

470 raise ValueError('illegal value in %d-th argument of internal ' 

471 'gbsv/gtsv' % -info) 

472 

473 

474def solveh_banded(ab, b, overwrite_ab=False, overwrite_b=False, lower=False, 

475 check_finite=True): 

476 """ 

477 Solve equation a x = b. a is Hermitian positive-definite banded matrix. 

478 

479 Uses Thomas' Algorithm, which is more efficient than standard LU 

480 factorization, but should only be used for Hermitian positive-definite 

481 matrices. 

482 

483 The matrix ``a`` is stored in `ab` either in lower diagonal or upper 

484 diagonal ordered form: 

485 

486 ab[u + i - j, j] == a[i,j] (if upper form; i <= j) 

487 ab[ i - j, j] == a[i,j] (if lower form; i >= j) 

488 

489 Example of `ab` (shape of ``a`` is (6, 6), number of upper diagonals, 

490 ``u`` =2):: 

491 

492 upper form: 

493 * * a02 a13 a24 a35 

494 * a01 a12 a23 a34 a45 

495 a00 a11 a22 a33 a44 a55 

496 

497 lower form: 

498 a00 a11 a22 a33 a44 a55 

499 a10 a21 a32 a43 a54 * 

500 a20 a31 a42 a53 * * 

501 

502 Cells marked with * are not used. 

503 

504 Parameters 

505 ---------- 

506 ab : (``u`` + 1, M) array_like 

507 Banded matrix 

508 b : (M,) or (M, K) array_like 

509 Right-hand side 

510 overwrite_ab : bool, optional 

511 Discard data in `ab` (may enhance performance) 

512 overwrite_b : bool, optional 

513 Discard data in `b` (may enhance performance) 

514 lower : bool, optional 

515 Is the matrix in the lower form. (Default is upper form) 

516 check_finite : bool, optional 

517 Whether to check that the input matrices contain only finite numbers. 

518 Disabling may give a performance gain, but may result in problems 

519 (crashes, non-termination) if the inputs do contain infinities or NaNs. 

520 

521 Returns 

522 ------- 

523 x : (M,) or (M, K) ndarray 

524 The solution to the system ``a x = b``. Shape of return matches shape 

525 of `b`. 

526 

527 Notes 

528 ----- 

529 In the case of a non-positive definite matrix ``a``, the solver 

530 `solve_banded` may be used. 

531 

532 Examples 

533 -------- 

534 Solve the banded system ``A x = b``, where:: 

535 

536 [ 4 2 -1 0 0 0] [1] 

537 [ 2 5 2 -1 0 0] [2] 

538 A = [-1 2 6 2 -1 0] b = [2] 

539 [ 0 -1 2 7 2 -1] [3] 

540 [ 0 0 -1 2 8 2] [3] 

541 [ 0 0 0 -1 2 9] [3] 

542 

543 >>> import numpy as np 

544 >>> from scipy.linalg import solveh_banded 

545 

546 ``ab`` contains the main diagonal and the nonzero diagonals below the 

547 main diagonal. That is, we use the lower form: 

548 

549 >>> ab = np.array([[ 4, 5, 6, 7, 8, 9], 

550 ... [ 2, 2, 2, 2, 2, 0], 

551 ... [-1, -1, -1, -1, 0, 0]]) 

552 >>> b = np.array([1, 2, 2, 3, 3, 3]) 

553 >>> x = solveh_banded(ab, b, lower=True) 

554 >>> x 

555 array([ 0.03431373, 0.45938375, 0.05602241, 0.47759104, 0.17577031, 

556 0.34733894]) 

557 

558 

559 Solve the Hermitian banded system ``H x = b``, where:: 

560 

561 [ 8 2-1j 0 0 ] [ 1 ] 

562 H = [2+1j 5 1j 0 ] b = [1+1j] 

563 [ 0 -1j 9 -2-1j] [1-2j] 

564 [ 0 0 -2+1j 6 ] [ 0 ] 

565 

566 In this example, we put the upper diagonals in the array ``hb``: 

567 

568 >>> hb = np.array([[0, 2-1j, 1j, -2-1j], 

569 ... [8, 5, 9, 6 ]]) 

570 >>> b = np.array([1, 1+1j, 1-2j, 0]) 

571 >>> x = solveh_banded(hb, b) 

572 >>> x 

573 array([ 0.07318536-0.02939412j, 0.11877624+0.17696461j, 

574 0.10077984-0.23035393j, -0.00479904-0.09358128j]) 

575 

576 """ 

577 a1 = _asarray_validated(ab, check_finite=check_finite) 

578 b1 = _asarray_validated(b, check_finite=check_finite) 

579 # Validate shapes. 

580 if a1.shape[-1] != b1.shape[0]: 

581 raise ValueError("shapes of ab and b are not compatible.") 

582 

583 overwrite_b = overwrite_b or _datacopied(b1, b) 

584 overwrite_ab = overwrite_ab or _datacopied(a1, ab) 

585 

586 if a1.shape[0] == 2: 

587 ptsv, = get_lapack_funcs(('ptsv',), (a1, b1)) 

588 if lower: 

589 d = a1[0, :].real 

590 e = a1[1, :-1] 

591 else: 

592 d = a1[1, :].real 

593 e = a1[0, 1:].conj() 

594 d, du, x, info = ptsv(d, e, b1, overwrite_ab, overwrite_ab, 

595 overwrite_b) 

596 else: 

597 pbsv, = get_lapack_funcs(('pbsv',), (a1, b1)) 

598 c, x, info = pbsv(a1, b1, lower=lower, overwrite_ab=overwrite_ab, 

599 overwrite_b=overwrite_b) 

600 if info > 0: 

601 raise LinAlgError("%dth leading minor not positive definite" % info) 

602 if info < 0: 

603 raise ValueError('illegal value in %dth argument of internal ' 

604 'pbsv' % -info) 

605 return x 

606 

607 

608def solve_toeplitz(c_or_cr, b, check_finite=True): 

609 """Solve a Toeplitz system using Levinson Recursion 

610 

611 The Toeplitz matrix has constant diagonals, with c as its first column 

612 and r as its first row. If r is not given, ``r == conjugate(c)`` is 

613 assumed. 

614 

615 Parameters 

616 ---------- 

617 c_or_cr : array_like or tuple of (array_like, array_like) 

618 The vector ``c``, or a tuple of arrays (``c``, ``r``). Whatever the 

619 actual shape of ``c``, it will be converted to a 1-D array. If not 

620 supplied, ``r = conjugate(c)`` is assumed; in this case, if c[0] is 

621 real, the Toeplitz matrix is Hermitian. r[0] is ignored; the first row 

622 of the Toeplitz matrix is ``[c[0], r[1:]]``. Whatever the actual shape 

623 of ``r``, it will be converted to a 1-D array. 

624 b : (M,) or (M, K) array_like 

625 Right-hand side in ``T x = b``. 

626 check_finite : bool, optional 

627 Whether to check that the input matrices contain only finite numbers. 

628 Disabling may give a performance gain, but may result in problems 

629 (result entirely NaNs) if the inputs do contain infinities or NaNs. 

630 

631 Returns 

632 ------- 

633 x : (M,) or (M, K) ndarray 

634 The solution to the system ``T x = b``. Shape of return matches shape 

635 of `b`. 

636 

637 See Also 

638 -------- 

639 toeplitz : Toeplitz matrix 

640 

641 Notes 

642 ----- 

643 The solution is computed using Levinson-Durbin recursion, which is faster 

644 than generic least-squares methods, but can be less numerically stable. 

645 

646 Examples 

647 -------- 

648 Solve the Toeplitz system T x = b, where:: 

649 

650 [ 1 -1 -2 -3] [1] 

651 T = [ 3 1 -1 -2] b = [2] 

652 [ 6 3 1 -1] [2] 

653 [10 6 3 1] [5] 

654 

655 To specify the Toeplitz matrix, only the first column and the first 

656 row are needed. 

657 

658 >>> import numpy as np 

659 >>> c = np.array([1, 3, 6, 10]) # First column of T 

660 >>> r = np.array([1, -1, -2, -3]) # First row of T 

661 >>> b = np.array([1, 2, 2, 5]) 

662 

663 >>> from scipy.linalg import solve_toeplitz, toeplitz 

664 >>> x = solve_toeplitz((c, r), b) 

665 >>> x 

666 array([ 1.66666667, -1. , -2.66666667, 2.33333333]) 

667 

668 Check the result by creating the full Toeplitz matrix and 

669 multiplying it by `x`. We should get `b`. 

670 

671 >>> T = toeplitz(c, r) 

672 >>> T.dot(x) 

673 array([ 1., 2., 2., 5.]) 

674 

675 """ 

676 # If numerical stability of this algorithm is a problem, a future 

677 # developer might consider implementing other O(N^2) Toeplitz solvers, 

678 # such as GKO (https://www.jstor.org/stable/2153371) or Bareiss. 

679 

680 r, c, b, dtype, b_shape = _validate_args_for_toeplitz_ops( 

681 c_or_cr, b, check_finite, keep_b_shape=True) 

682 

683 # Form a 1-D array of values to be used in the matrix, containing a 

684 # reversed copy of r[1:], followed by c. 

685 vals = np.concatenate((r[-1:0:-1], c)) 

686 if b is None: 

687 raise ValueError('illegal value, `b` is a required argument') 

688 

689 if b.ndim == 1: 

690 x, _ = levinson(vals, np.ascontiguousarray(b)) 

691 else: 

692 x = np.column_stack([levinson(vals, np.ascontiguousarray(b[:, i]))[0] 

693 for i in range(b.shape[1])]) 

694 x = x.reshape(*b_shape) 

695 

696 return x 

697 

698 

699def _get_axis_len(aname, a, axis): 

700 ax = axis 

701 if ax < 0: 

702 ax += a.ndim 

703 if 0 <= ax < a.ndim: 

704 return a.shape[ax] 

705 raise ValueError(f"'{aname}axis' entry is out of bounds") 

706 

707 

708def solve_circulant(c, b, singular='raise', tol=None, 

709 caxis=-1, baxis=0, outaxis=0): 

710 """Solve C x = b for x, where C is a circulant matrix. 

711 

712 `C` is the circulant matrix associated with the vector `c`. 

713 

714 The system is solved by doing division in Fourier space. The 

715 calculation is:: 

716 

717 x = ifft(fft(b) / fft(c)) 

718 

719 where `fft` and `ifft` are the fast Fourier transform and its inverse, 

720 respectively. For a large vector `c`, this is *much* faster than 

721 solving the system with the full circulant matrix. 

722 

723 Parameters 

724 ---------- 

725 c : array_like 

726 The coefficients of the circulant matrix. 

727 b : array_like 

728 Right-hand side matrix in ``a x = b``. 

729 singular : str, optional 

730 This argument controls how a near singular circulant matrix is 

731 handled. If `singular` is "raise" and the circulant matrix is 

732 near singular, a `LinAlgError` is raised. If `singular` is 

733 "lstsq", the least squares solution is returned. Default is "raise". 

734 tol : float, optional 

735 If any eigenvalue of the circulant matrix has an absolute value 

736 that is less than or equal to `tol`, the matrix is considered to be 

737 near singular. If not given, `tol` is set to:: 

738 

739 tol = abs_eigs.max() * abs_eigs.size * np.finfo(np.float64).eps 

740 

741 where `abs_eigs` is the array of absolute values of the eigenvalues 

742 of the circulant matrix. 

743 caxis : int 

744 When `c` has dimension greater than 1, it is viewed as a collection 

745 of circulant vectors. In this case, `caxis` is the axis of `c` that 

746 holds the vectors of circulant coefficients. 

747 baxis : int 

748 When `b` has dimension greater than 1, it is viewed as a collection 

749 of vectors. In this case, `baxis` is the axis of `b` that holds the 

750 right-hand side vectors. 

751 outaxis : int 

752 When `c` or `b` are multidimensional, the value returned by 

753 `solve_circulant` is multidimensional. In this case, `outaxis` is 

754 the axis of the result that holds the solution vectors. 

755 

756 Returns 

757 ------- 

758 x : ndarray 

759 Solution to the system ``C x = b``. 

760 

761 Raises 

762 ------ 

763 LinAlgError 

764 If the circulant matrix associated with `c` is near singular. 

765 

766 See Also 

767 -------- 

768 circulant : circulant matrix 

769 

770 Notes 

771 ----- 

772 For a 1-D vector `c` with length `m`, and an array `b` 

773 with shape ``(m, ...)``, 

774 

775 solve_circulant(c, b) 

776 

777 returns the same result as 

778 

779 solve(circulant(c), b) 

780 

781 where `solve` and `circulant` are from `scipy.linalg`. 

782 

783 .. versionadded:: 0.16.0 

784 

785 Examples 

786 -------- 

787 >>> import numpy as np 

788 >>> from scipy.linalg import solve_circulant, solve, circulant, lstsq 

789 

790 >>> c = np.array([2, 2, 4]) 

791 >>> b = np.array([1, 2, 3]) 

792 >>> solve_circulant(c, b) 

793 array([ 0.75, -0.25, 0.25]) 

794 

795 Compare that result to solving the system with `scipy.linalg.solve`: 

796 

797 >>> solve(circulant(c), b) 

798 array([ 0.75, -0.25, 0.25]) 

799 

800 A singular example: 

801 

802 >>> c = np.array([1, 1, 0, 0]) 

803 >>> b = np.array([1, 2, 3, 4]) 

804 

805 Calling ``solve_circulant(c, b)`` will raise a `LinAlgError`. For the 

806 least square solution, use the option ``singular='lstsq'``: 

807 

808 >>> solve_circulant(c, b, singular='lstsq') 

809 array([ 0.25, 1.25, 2.25, 1.25]) 

810 

811 Compare to `scipy.linalg.lstsq`: 

812 

813 >>> x, resid, rnk, s = lstsq(circulant(c), b) 

814 >>> x 

815 array([ 0.25, 1.25, 2.25, 1.25]) 

816 

817 A broadcasting example: 

818 

819 Suppose we have the vectors of two circulant matrices stored in an array 

820 with shape (2, 5), and three `b` vectors stored in an array with shape 

821 (3, 5). For example, 

822 

823 >>> c = np.array([[1.5, 2, 3, 0, 0], [1, 1, 4, 3, 2]]) 

824 >>> b = np.arange(15).reshape(-1, 5) 

825 

826 We want to solve all combinations of circulant matrices and `b` vectors, 

827 with the result stored in an array with shape (2, 3, 5). When we 

828 disregard the axes of `c` and `b` that hold the vectors of coefficients, 

829 the shapes of the collections are (2,) and (3,), respectively, which are 

830 not compatible for broadcasting. To have a broadcast result with shape 

831 (2, 3), we add a trivial dimension to `c`: ``c[:, np.newaxis, :]`` has 

832 shape (2, 1, 5). The last dimension holds the coefficients of the 

833 circulant matrices, so when we call `solve_circulant`, we can use the 

834 default ``caxis=-1``. The coefficients of the `b` vectors are in the last 

835 dimension of the array `b`, so we use ``baxis=-1``. If we use the 

836 default `outaxis`, the result will have shape (5, 2, 3), so we'll use 

837 ``outaxis=-1`` to put the solution vectors in the last dimension. 

838 

839 >>> x = solve_circulant(c[:, np.newaxis, :], b, baxis=-1, outaxis=-1) 

840 >>> x.shape 

841 (2, 3, 5) 

842 >>> np.set_printoptions(precision=3) # For compact output of numbers. 

843 >>> x 

844 array([[[-0.118, 0.22 , 1.277, -0.142, 0.302], 

845 [ 0.651, 0.989, 2.046, 0.627, 1.072], 

846 [ 1.42 , 1.758, 2.816, 1.396, 1.841]], 

847 [[ 0.401, 0.304, 0.694, -0.867, 0.377], 

848 [ 0.856, 0.758, 1.149, -0.412, 0.831], 

849 [ 1.31 , 1.213, 1.603, 0.042, 1.286]]]) 

850 

851 Check by solving one pair of `c` and `b` vectors (cf. ``x[1, 1, :]``): 

852 

853 >>> solve_circulant(c[1], b[1, :]) 

854 array([ 0.856, 0.758, 1.149, -0.412, 0.831]) 

855 

856 """ 

857 c = np.atleast_1d(c) 

858 nc = _get_axis_len("c", c, caxis) 

859 b = np.atleast_1d(b) 

860 nb = _get_axis_len("b", b, baxis) 

861 if nc != nb: 

862 raise ValueError('Shapes of c {} and b {} are incompatible' 

863 .format(c.shape, b.shape)) 

864 

865 fc = np.fft.fft(np.moveaxis(c, caxis, -1), axis=-1) 

866 abs_fc = np.abs(fc) 

867 if tol is None: 

868 # This is the same tolerance as used in np.linalg.matrix_rank. 

869 tol = abs_fc.max(axis=-1) * nc * np.finfo(np.float64).eps 

870 if tol.shape != (): 

871 tol.shape = tol.shape + (1,) 

872 else: 

873 tol = np.atleast_1d(tol) 

874 

875 near_zeros = abs_fc <= tol 

876 is_near_singular = np.any(near_zeros) 

877 if is_near_singular: 

878 if singular == 'raise': 

879 raise LinAlgError("near singular circulant matrix.") 

880 else: 

881 # Replace the small values with 1 to avoid errors in the 

882 # division fb/fc below. 

883 fc[near_zeros] = 1 

884 

885 fb = np.fft.fft(np.moveaxis(b, baxis, -1), axis=-1) 

886 

887 q = fb / fc 

888 

889 if is_near_singular: 

890 # `near_zeros` is a boolean array, same shape as `c`, that is 

891 # True where `fc` is (near) zero. `q` is the broadcasted result 

892 # of fb / fc, so to set the values of `q` to 0 where `fc` is near 

893 # zero, we use a mask that is the broadcast result of an array 

894 # of True values shaped like `b` with `near_zeros`. 

895 mask = np.ones_like(b, dtype=bool) & near_zeros 

896 q[mask] = 0 

897 

898 x = np.fft.ifft(q, axis=-1) 

899 if not (np.iscomplexobj(c) or np.iscomplexobj(b)): 

900 x = x.real 

901 if outaxis != -1: 

902 x = np.moveaxis(x, -1, outaxis) 

903 return x 

904 

905 

906# matrix inversion 

907def inv(a, overwrite_a=False, check_finite=True): 

908 """ 

909 Compute the inverse of a matrix. 

910 

911 Parameters 

912 ---------- 

913 a : array_like 

914 Square matrix to be inverted. 

915 overwrite_a : bool, optional 

916 Discard data in `a` (may improve performance). Default is False. 

917 check_finite : bool, optional 

918 Whether to check that the input matrix contains only finite numbers. 

919 Disabling may give a performance gain, but may result in problems 

920 (crashes, non-termination) if the inputs do contain infinities or NaNs. 

921 

922 Returns 

923 ------- 

924 ainv : ndarray 

925 Inverse of the matrix `a`. 

926 

927 Raises 

928 ------ 

929 LinAlgError 

930 If `a` is singular. 

931 ValueError 

932 If `a` is not square, or not 2D. 

933 

934 Examples 

935 -------- 

936 >>> import numpy as np 

937 >>> from scipy import linalg 

938 >>> a = np.array([[1., 2.], [3., 4.]]) 

939 >>> linalg.inv(a) 

940 array([[-2. , 1. ], 

941 [ 1.5, -0.5]]) 

942 >>> np.dot(a, linalg.inv(a)) 

943 array([[ 1., 0.], 

944 [ 0., 1.]]) 

945 

946 """ 

947 a1 = _asarray_validated(a, check_finite=check_finite) 

948 if len(a1.shape) != 2 or a1.shape[0] != a1.shape[1]: 

949 raise ValueError('expected square matrix') 

950 overwrite_a = overwrite_a or _datacopied(a1, a) 

951 # XXX: I found no advantage or disadvantage of using finv. 

952# finv, = get_flinalg_funcs(('inv',),(a1,)) 

953# if finv is not None: 

954# a_inv,info = finv(a1,overwrite_a=overwrite_a) 

955# if info==0: 

956# return a_inv 

957# if info>0: raise LinAlgError, "singular matrix" 

958# if info<0: raise ValueError('illegal value in %d-th argument of ' 

959# 'internal inv.getrf|getri'%(-info)) 

960 getrf, getri, getri_lwork = get_lapack_funcs(('getrf', 'getri', 

961 'getri_lwork'), 

962 (a1,)) 

963 lu, piv, info = getrf(a1, overwrite_a=overwrite_a) 

964 if info == 0: 

965 lwork = _compute_lwork(getri_lwork, a1.shape[0]) 

966 

967 # XXX: the following line fixes curious SEGFAULT when 

968 # benchmarking 500x500 matrix inverse. This seems to 

969 # be a bug in LAPACK ?getri routine because if lwork is 

970 # minimal (when using lwork[0] instead of lwork[1]) then 

971 # all tests pass. Further investigation is required if 

972 # more such SEGFAULTs occur. 

973 lwork = int(1.01 * lwork) 

974 inv_a, info = getri(lu, piv, lwork=lwork, overwrite_lu=1) 

975 if info > 0: 

976 raise LinAlgError("singular matrix") 

977 if info < 0: 

978 raise ValueError('illegal value in %d-th argument of internal ' 

979 'getrf|getri' % -info) 

980 return inv_a 

981 

982 

983# Determinant 

984 

985def det(a, overwrite_a=False, check_finite=True): 

986 """ 

987 Compute the determinant of a matrix 

988 

989 The determinant is a scalar that is a function of the associated square 

990 matrix coefficients. The determinant value is zero for singular matrices. 

991 

992 Parameters 

993 ---------- 

994 a : (..., M, M) array_like 

995 Input array to compute determinants for. 

996 overwrite_a : bool, optional 

997 Allow overwriting data in a (may enhance performance). 

998 check_finite : bool, optional 

999 Whether to check that the input matrix contains only finite numbers. 

1000 Disabling may give a performance gain, but may result in problems 

1001 (crashes, non-termination) if the inputs do contain infinities or NaNs. 

1002 

1003 Returns 

1004 ------- 

1005 det : (...) float or complex 

1006 Determinant of `a`. For stacked arrays, a scalar is returned for each 

1007 (m, m) slice in the last two dimensions of the input. For example, an 

1008 input of shape (p, q, m, m) will produce a result of shape (p, q). If 

1009 all dimensions are 1 a scalar is returned regardless of ndim. 

1010 

1011 Notes 

1012 ----- 

1013 The determinant is computed by performing an LU factorization of the 

1014 input with LAPACK routine 'getrf', and then calculating the product of 

1015 diagonal entries of the U factor. 

1016 

1017 Even the input array is single precision (float32 or complex64), the result 

1018 will be returned in double precision (float64 or complex128) to prevent 

1019 overflows. 

1020 

1021 Examples 

1022 -------- 

1023 >>> import numpy as np 

1024 >>> from scipy import linalg 

1025 >>> a = np.array([[1,2,3], [4,5,6], [7,8,9]]) # A singular matrix 

1026 >>> linalg.det(a) 

1027 0.0 

1028 >>> b = np.array([[0,2,3], [4,5,6], [7,8,9]]) 

1029 >>> linalg.det(b) 

1030 3.0 

1031 >>> # An array with the shape (3, 2, 2, 2) 

1032 >>> c = np.array([[[[1., 2.], [3., 4.]], 

1033 ... [[5., 6.], [7., 8.]]], 

1034 ... [[[9., 10.], [11., 12.]], 

1035 ... [[13., 14.], [15., 16.]]], 

1036 ... [[[17., 18.], [19., 20.]], 

1037 ... [[21., 22.], [23., 24.]]]]) 

1038 >>> linalg.det(c) # The resulting shape is (3, 2) 

1039 array([[-2., -2.], 

1040 [-2., -2.], 

1041 [-2., -2.]]) 

1042 >>> linalg.det(c[0, 0]) # Confirm the (0, 0) slice, [[1, 2], [3, 4]] 

1043 -2.0 

1044 """ 

1045 # The goal is to end up with a writable contiguous array to pass to Cython 

1046 

1047 # First we check and make arrays. 

1048 a1 = np.asarray_chkfinite(a) if check_finite else np.asarray(a) 

1049 if a1.ndim < 2: 

1050 raise ValueError('The input array must be at least two-dimensional.') 

1051 if a1.shape[-1] != a1.shape[-2]: 

1052 raise ValueError('Last 2 dimensions of the array must be square' 

1053 f' but received shape {a1.shape}.') 

1054 

1055 # Also check if dtype is LAPACK compatible 

1056 if a1.dtype.char not in 'fdFD': 

1057 dtype_char = lapack_cast_dict[a1.dtype.char] 

1058 if not dtype_char: # No casting possible 

1059 raise TypeError(f'The dtype "{a1.dtype.name}" cannot be cast ' 

1060 'to float(32, 64) or complex(64, 128).') 

1061 

1062 a1 = a1.astype(dtype_char[0]) # makes a copy, free to scratch 

1063 overwrite_a = True 

1064 

1065 # Empty array has determinant 1 because math. 

1066 if min(*a1.shape) == 0: 

1067 if a1.ndim == 2: 

1068 return np.float64(1.) 

1069 else: 

1070 return np.ones(shape=a1.shape[:-2], dtype=np.float64) 

1071 

1072 # Scalar case 

1073 if a1.shape[-2:] == (1, 1): 

1074 # Either ndarray with spurious singletons or a single element 

1075 if max(*a1.shape) > 1: 

1076 temp = np.squeeze(a1) 

1077 if a1.dtype.char in 'dD': 

1078 return temp 

1079 else: 

1080 return (temp.astype('d') if a1.dtype.char == 'f' else 

1081 temp.astype('D')) 

1082 else: 

1083 return (np.float64(a1.item()) if a1.dtype.char in 'fd' else 

1084 np.complex128(a1.item())) 

1085 

1086 # Then check overwrite permission 

1087 if not _datacopied(a1, a): # "a" still alive through "a1" 

1088 if not overwrite_a: 

1089 # Data belongs to "a" so make a copy 

1090 a1 = a1.copy(order='C') 

1091 # else: Do nothing we'll use "a" if possible 

1092 # else: a1 has its own data thus free to scratch 

1093 

1094 # Then layout checks, might happen that overwrite is allowed but original 

1095 # array was read-only or non-C-contiguous. 

1096 if not (a1.flags['C_CONTIGUOUS'] and a1.flags['WRITEABLE']): 

1097 a1 = a1.copy(order='C') 

1098 

1099 if a1.ndim == 2: 

1100 det = find_det_from_lu(a1) 

1101 # Convert float, complex to to NumPy scalars 

1102 return (np.float64(det) if np.isrealobj(det) else np.complex128(det)) 

1103 

1104 # loop over the stacked array, and avoid overflows for single precision 

1105 # Cf. np.linalg.det(np.diag([1e+38, 1e+38]).astype(np.float32)) 

1106 dtype_char = a1.dtype.char 

1107 if dtype_char in 'fF': 

1108 dtype_char = 'd' if dtype_char.islower() else 'D' 

1109 

1110 det = np.empty(a1.shape[:-2], dtype=dtype_char) 

1111 for ind in product(*[range(x) for x in a1.shape[:-2]]): 

1112 det[ind] = find_det_from_lu(a1[ind]) 

1113 return det 

1114 

1115 

1116# Linear Least Squares 

1117def lstsq(a, b, cond=None, overwrite_a=False, overwrite_b=False, 

1118 check_finite=True, lapack_driver=None): 

1119 """ 

1120 Compute least-squares solution to equation Ax = b. 

1121 

1122 Compute a vector x such that the 2-norm ``|b - A x|`` is minimized. 

1123 

1124 Parameters 

1125 ---------- 

1126 a : (M, N) array_like 

1127 Left-hand side array 

1128 b : (M,) or (M, K) array_like 

1129 Right hand side array 

1130 cond : float, optional 

1131 Cutoff for 'small' singular values; used to determine effective 

1132 rank of a. Singular values smaller than 

1133 ``cond * largest_singular_value`` are considered zero. 

1134 overwrite_a : bool, optional 

1135 Discard data in `a` (may enhance performance). Default is False. 

1136 overwrite_b : bool, optional 

1137 Discard data in `b` (may enhance performance). Default is False. 

1138 check_finite : bool, optional 

1139 Whether to check that the input matrices contain only finite numbers. 

1140 Disabling may give a performance gain, but may result in problems 

1141 (crashes, non-termination) if the inputs do contain infinities or NaNs. 

1142 lapack_driver : str, optional 

1143 Which LAPACK driver is used to solve the least-squares problem. 

1144 Options are ``'gelsd'``, ``'gelsy'``, ``'gelss'``. Default 

1145 (``'gelsd'``) is a good choice. However, ``'gelsy'`` can be slightly 

1146 faster on many problems. ``'gelss'`` was used historically. It is 

1147 generally slow but uses less memory. 

1148 

1149 .. versionadded:: 0.17.0 

1150 

1151 Returns 

1152 ------- 

1153 x : (N,) or (N, K) ndarray 

1154 Least-squares solution. 

1155 residues : (K,) ndarray or float 

1156 Square of the 2-norm for each column in ``b - a x``, if ``M > N`` and 

1157 ``ndim(A) == n`` (returns a scalar if ``b`` is 1-D). Otherwise a 

1158 (0,)-shaped array is returned. 

1159 rank : int 

1160 Effective rank of `a`. 

1161 s : (min(M, N),) ndarray or None 

1162 Singular values of `a`. The condition number of ``a`` is 

1163 ``s[0] / s[-1]``. 

1164 

1165 Raises 

1166 ------ 

1167 LinAlgError 

1168 If computation does not converge. 

1169 

1170 ValueError 

1171 When parameters are not compatible. 

1172 

1173 See Also 

1174 -------- 

1175 scipy.optimize.nnls : linear least squares with non-negativity constraint 

1176 

1177 Notes 

1178 ----- 

1179 When ``'gelsy'`` is used as a driver, `residues` is set to a (0,)-shaped 

1180 array and `s` is always ``None``. 

1181 

1182 Examples 

1183 -------- 

1184 >>> import numpy as np 

1185 >>> from scipy.linalg import lstsq 

1186 >>> import matplotlib.pyplot as plt 

1187 

1188 Suppose we have the following data: 

1189 

1190 >>> x = np.array([1, 2.5, 3.5, 4, 5, 7, 8.5]) 

1191 >>> y = np.array([0.3, 1.1, 1.5, 2.0, 3.2, 6.6, 8.6]) 

1192 

1193 We want to fit a quadratic polynomial of the form ``y = a + b*x**2`` 

1194 to this data. We first form the "design matrix" M, with a constant 

1195 column of 1s and a column containing ``x**2``: 

1196 

1197 >>> M = x[:, np.newaxis]**[0, 2] 

1198 >>> M 

1199 array([[ 1. , 1. ], 

1200 [ 1. , 6.25], 

1201 [ 1. , 12.25], 

1202 [ 1. , 16. ], 

1203 [ 1. , 25. ], 

1204 [ 1. , 49. ], 

1205 [ 1. , 72.25]]) 

1206 

1207 We want to find the least-squares solution to ``M.dot(p) = y``, 

1208 where ``p`` is a vector with length 2 that holds the parameters 

1209 ``a`` and ``b``. 

1210 

1211 >>> p, res, rnk, s = lstsq(M, y) 

1212 >>> p 

1213 array([ 0.20925829, 0.12013861]) 

1214 

1215 Plot the data and the fitted curve. 

1216 

1217 >>> plt.plot(x, y, 'o', label='data') 

1218 >>> xx = np.linspace(0, 9, 101) 

1219 >>> yy = p[0] + p[1]*xx**2 

1220 >>> plt.plot(xx, yy, label='least squares fit, $y = a + bx^2$') 

1221 >>> plt.xlabel('x') 

1222 >>> plt.ylabel('y') 

1223 >>> plt.legend(framealpha=1, shadow=True) 

1224 >>> plt.grid(alpha=0.25) 

1225 >>> plt.show() 

1226 

1227 """ 

1228 a1 = _asarray_validated(a, check_finite=check_finite) 

1229 b1 = _asarray_validated(b, check_finite=check_finite) 

1230 if len(a1.shape) != 2: 

1231 raise ValueError('Input array a should be 2D') 

1232 m, n = a1.shape 

1233 if len(b1.shape) == 2: 

1234 nrhs = b1.shape[1] 

1235 else: 

1236 nrhs = 1 

1237 if m != b1.shape[0]: 

1238 raise ValueError('Shape mismatch: a and b should have the same number' 

1239 ' of rows ({} != {}).'.format(m, b1.shape[0])) 

1240 if m == 0 or n == 0: # Zero-sized problem, confuses LAPACK 

1241 x = np.zeros((n,) + b1.shape[1:], dtype=np.common_type(a1, b1)) 

1242 if n == 0: 

1243 residues = np.linalg.norm(b1, axis=0)**2 

1244 else: 

1245 residues = np.empty((0,)) 

1246 return x, residues, 0, np.empty((0,)) 

1247 

1248 driver = lapack_driver 

1249 if driver is None: 

1250 driver = lstsq.default_lapack_driver 

1251 if driver not in ('gelsd', 'gelsy', 'gelss'): 

1252 raise ValueError('LAPACK driver "%s" is not found' % driver) 

1253 

1254 lapack_func, lapack_lwork = get_lapack_funcs((driver, 

1255 '%s_lwork' % driver), 

1256 (a1, b1)) 

1257 real_data = True if (lapack_func.dtype.kind == 'f') else False 

1258 

1259 if m < n: 

1260 # need to extend b matrix as it will be filled with 

1261 # a larger solution matrix 

1262 if len(b1.shape) == 2: 

1263 b2 = np.zeros((n, nrhs), dtype=lapack_func.dtype) 

1264 b2[:m, :] = b1 

1265 else: 

1266 b2 = np.zeros(n, dtype=lapack_func.dtype) 

1267 b2[:m] = b1 

1268 b1 = b2 

1269 

1270 overwrite_a = overwrite_a or _datacopied(a1, a) 

1271 overwrite_b = overwrite_b or _datacopied(b1, b) 

1272 

1273 if cond is None: 

1274 cond = np.finfo(lapack_func.dtype).eps 

1275 

1276 if driver in ('gelss', 'gelsd'): 

1277 if driver == 'gelss': 

1278 lwork = _compute_lwork(lapack_lwork, m, n, nrhs, cond) 

1279 v, x, s, rank, work, info = lapack_func(a1, b1, cond, lwork, 

1280 overwrite_a=overwrite_a, 

1281 overwrite_b=overwrite_b) 

1282 

1283 elif driver == 'gelsd': 

1284 if real_data: 

1285 lwork, iwork = _compute_lwork(lapack_lwork, m, n, nrhs, cond) 

1286 x, s, rank, info = lapack_func(a1, b1, lwork, 

1287 iwork, cond, False, False) 

1288 else: # complex data 

1289 lwork, rwork, iwork = _compute_lwork(lapack_lwork, m, n, 

1290 nrhs, cond) 

1291 x, s, rank, info = lapack_func(a1, b1, lwork, rwork, iwork, 

1292 cond, False, False) 

1293 if info > 0: 

1294 raise LinAlgError("SVD did not converge in Linear Least Squares") 

1295 if info < 0: 

1296 raise ValueError('illegal value in %d-th argument of internal %s' 

1297 % (-info, lapack_driver)) 

1298 resids = np.asarray([], dtype=x.dtype) 

1299 if m > n: 

1300 x1 = x[:n] 

1301 if rank == n: 

1302 resids = np.sum(np.abs(x[n:])**2, axis=0) 

1303 x = x1 

1304 return x, resids, rank, s 

1305 

1306 elif driver == 'gelsy': 

1307 lwork = _compute_lwork(lapack_lwork, m, n, nrhs, cond) 

1308 jptv = np.zeros((a1.shape[1], 1), dtype=np.int32) 

1309 v, x, j, rank, info = lapack_func(a1, b1, jptv, cond, 

1310 lwork, False, False) 

1311 if info < 0: 

1312 raise ValueError("illegal value in %d-th argument of internal " 

1313 "gelsy" % -info) 

1314 if m > n: 

1315 x1 = x[:n] 

1316 x = x1 

1317 return x, np.array([], x.dtype), rank, None 

1318 

1319 

1320lstsq.default_lapack_driver = 'gelsd' 

1321 

1322 

1323@_deprecate_positional_args(version="1.14") 

1324def pinv(a, *, atol=None, rtol=None, return_rank=False, check_finite=True, 

1325 cond=_NoValue, rcond=_NoValue): 

1326 """ 

1327 Compute the (Moore-Penrose) pseudo-inverse of a matrix. 

1328 

1329 Calculate a generalized inverse of a matrix using its 

1330 singular-value decomposition ``U @ S @ V`` in the economy mode and picking 

1331 up only the columns/rows that are associated with significant singular 

1332 values. 

1333 

1334 If ``s`` is the maximum singular value of ``a``, then the 

1335 significance cut-off value is determined by ``atol + rtol * s``. Any 

1336 singular value below this value is assumed insignificant. 

1337 

1338 Parameters 

1339 ---------- 

1340 a : (M, N) array_like 

1341 Matrix to be pseudo-inverted. 

1342 atol : float, optional 

1343 Absolute threshold term, default value is 0. 

1344 

1345 .. versionadded:: 1.7.0 

1346 

1347 rtol : float, optional 

1348 Relative threshold term, default value is ``max(M, N) * eps`` where 

1349 ``eps`` is the machine precision value of the datatype of ``a``. 

1350 

1351 .. versionadded:: 1.7.0 

1352 

1353 return_rank : bool, optional 

1354 If True, return the effective rank of the matrix. 

1355 check_finite : bool, optional 

1356 Whether to check that the input matrix contains only finite numbers. 

1357 Disabling may give a performance gain, but may result in problems 

1358 (crashes, non-termination) if the inputs do contain infinities or NaNs. 

1359 cond, rcond : float, optional 

1360 In older versions, these values were meant to be used as ``atol`` with 

1361 ``rtol=0``. If both were given ``rcond`` overwrote ``cond`` and hence 

1362 the code was not correct. Thus using these are strongly discouraged and 

1363 the tolerances above are recommended instead. In fact, if provided, 

1364 atol, rtol takes precedence over these keywords. 

1365 

1366 .. deprecated:: 1.7.0 

1367 Deprecated in favor of ``rtol`` and ``atol`` parameters above and 

1368 will be removed in SciPy 1.14.0. 

1369 

1370 .. versionchanged:: 1.3.0 

1371 Previously the default cutoff value was just ``eps*f`` where ``f`` 

1372 was ``1e3`` for single precision and ``1e6`` for double precision. 

1373 

1374 Returns 

1375 ------- 

1376 B : (N, M) ndarray 

1377 The pseudo-inverse of matrix `a`. 

1378 rank : int 

1379 The effective rank of the matrix. Returned if `return_rank` is True. 

1380 

1381 Raises 

1382 ------ 

1383 LinAlgError 

1384 If SVD computation does not converge. 

1385 

1386 See Also 

1387 -------- 

1388 pinvh : Moore-Penrose pseudoinverse of a hermitian matrix. 

1389 

1390 Notes 

1391 ----- 

1392 If ``A`` is invertible then the Moore-Penrose pseudoinverse is exactly 

1393 the inverse of ``A`` [1]_. If ``A`` is not invertible then the 

1394 Moore-Penrose pseudoinverse computes the ``x`` solution to ``Ax = b`` such 

1395 that ``||Ax - b||`` is minimized [1]_. 

1396 

1397 References 

1398 ---------- 

1399 .. [1] Penrose, R. (1956). On best approximate solutions of linear matrix 

1400 equations. Mathematical Proceedings of the Cambridge Philosophical 

1401 Society, 52(1), 17-19. doi:10.1017/S0305004100030929 

1402 

1403 Examples 

1404 -------- 

1405 

1406 Given an ``m x n`` matrix ``A`` and an ``n x m`` matrix ``B`` the four 

1407 Moore-Penrose conditions are: 

1408 

1409 1. ``ABA = A`` (``B`` is a generalized inverse of ``A``), 

1410 2. ``BAB = B`` (``A`` is a generalized inverse of ``B``), 

1411 3. ``(AB)* = AB`` (``AB`` is hermitian), 

1412 4. ``(BA)* = BA`` (``BA`` is hermitian) [1]_. 

1413 

1414 Here, ``A*`` denotes the conjugate transpose. The Moore-Penrose 

1415 pseudoinverse is a unique ``B`` that satisfies all four of these 

1416 conditions and exists for any ``A``. Note that, unlike the standard 

1417 matrix inverse, ``A`` does not have to be a square matrix or have 

1418 linearly independent columns/rows. 

1419 

1420 As an example, we can calculate the Moore-Penrose pseudoinverse of a 

1421 random non-square matrix and verify it satisfies the four conditions. 

1422 

1423 >>> import numpy as np 

1424 >>> from scipy import linalg 

1425 >>> rng = np.random.default_rng() 

1426 >>> A = rng.standard_normal((9, 6)) 

1427 >>> B = linalg.pinv(A) 

1428 >>> np.allclose(A @ B @ A, A) # Condition 1 

1429 True 

1430 >>> np.allclose(B @ A @ B, B) # Condition 2 

1431 True 

1432 >>> np.allclose((A @ B).conj().T, A @ B) # Condition 3 

1433 True 

1434 >>> np.allclose((B @ A).conj().T, B @ A) # Condition 4 

1435 True 

1436 

1437 """ 

1438 a = _asarray_validated(a, check_finite=check_finite) 

1439 u, s, vh = _decomp_svd.svd(a, full_matrices=False, check_finite=False) 

1440 t = u.dtype.char.lower() 

1441 maxS = np.max(s) 

1442 

1443 if rcond is not _NoValue or cond is not _NoValue: 

1444 warn('Use of the "cond" and "rcond" keywords are deprecated and ' 

1445 'will be removed in SciPy 1.14.0. Use "atol" and ' 

1446 '"rtol" keywords instead', DeprecationWarning, stacklevel=2) 

1447 

1448 # backwards compatible only atol and rtol are both missing 

1449 if ((rcond not in (_NoValue, None) or cond not in (_NoValue, None)) 

1450 and (atol is None) and (rtol is None)): 

1451 atol = rcond if rcond not in (_NoValue, None) else cond 

1452 rtol = 0. 

1453 

1454 atol = 0. if atol is None else atol 

1455 rtol = max(a.shape) * np.finfo(t).eps if (rtol is None) else rtol 

1456 

1457 if (atol < 0.) or (rtol < 0.): 

1458 raise ValueError("atol and rtol values must be positive.") 

1459 

1460 val = atol + maxS * rtol 

1461 rank = np.sum(s > val) 

1462 

1463 u = u[:, :rank] 

1464 u /= s[:rank] 

1465 B = (u @ vh[:rank]).conj().T 

1466 

1467 if return_rank: 

1468 return B, rank 

1469 else: 

1470 return B 

1471 

1472 

1473def pinvh(a, atol=None, rtol=None, lower=True, return_rank=False, 

1474 check_finite=True): 

1475 """ 

1476 Compute the (Moore-Penrose) pseudo-inverse of a Hermitian matrix. 

1477 

1478 Calculate a generalized inverse of a complex Hermitian/real symmetric 

1479 matrix using its eigenvalue decomposition and including all eigenvalues 

1480 with 'large' absolute value. 

1481 

1482 Parameters 

1483 ---------- 

1484 a : (N, N) array_like 

1485 Real symmetric or complex hermetian matrix to be pseudo-inverted 

1486 

1487 atol : float, optional 

1488 Absolute threshold term, default value is 0. 

1489 

1490 .. versionadded:: 1.7.0 

1491 

1492 rtol : float, optional 

1493 Relative threshold term, default value is ``N * eps`` where 

1494 ``eps`` is the machine precision value of the datatype of ``a``. 

1495 

1496 .. versionadded:: 1.7.0 

1497 

1498 lower : bool, optional 

1499 Whether the pertinent array data is taken from the lower or upper 

1500 triangle of `a`. (Default: lower) 

1501 return_rank : bool, optional 

1502 If True, return the effective rank of the matrix. 

1503 check_finite : bool, optional 

1504 Whether to check that the input matrix contains only finite numbers. 

1505 Disabling may give a performance gain, but may result in problems 

1506 (crashes, non-termination) if the inputs do contain infinities or NaNs. 

1507 

1508 Returns 

1509 ------- 

1510 B : (N, N) ndarray 

1511 The pseudo-inverse of matrix `a`. 

1512 rank : int 

1513 The effective rank of the matrix. Returned if `return_rank` is True. 

1514 

1515 Raises 

1516 ------ 

1517 LinAlgError 

1518 If eigenvalue algorithm does not converge. 

1519 

1520 See Also 

1521 -------- 

1522 pinv : Moore-Penrose pseudoinverse of a matrix. 

1523 

1524 Examples 

1525 -------- 

1526 

1527 For a more detailed example see `pinv`. 

1528 

1529 >>> import numpy as np 

1530 >>> from scipy.linalg import pinvh 

1531 >>> rng = np.random.default_rng() 

1532 >>> a = rng.standard_normal((9, 6)) 

1533 >>> a = np.dot(a, a.T) 

1534 >>> B = pinvh(a) 

1535 >>> np.allclose(a, a @ B @ a) 

1536 True 

1537 >>> np.allclose(B, B @ a @ B) 

1538 True 

1539 

1540 """ 

1541 a = _asarray_validated(a, check_finite=check_finite) 

1542 s, u = _decomp.eigh(a, lower=lower, check_finite=False) 

1543 t = u.dtype.char.lower() 

1544 maxS = np.max(np.abs(s)) 

1545 

1546 atol = 0. if atol is None else atol 

1547 rtol = max(a.shape) * np.finfo(t).eps if (rtol is None) else rtol 

1548 

1549 if (atol < 0.) or (rtol < 0.): 

1550 raise ValueError("atol and rtol values must be positive.") 

1551 

1552 val = atol + maxS * rtol 

1553 above_cutoff = (abs(s) > val) 

1554 

1555 psigma_diag = 1.0 / s[above_cutoff] 

1556 u = u[:, above_cutoff] 

1557 

1558 B = (u * psigma_diag) @ u.conj().T 

1559 

1560 if return_rank: 

1561 return B, len(psigma_diag) 

1562 else: 

1563 return B 

1564 

1565 

1566def matrix_balance(A, permute=True, scale=True, separate=False, 

1567 overwrite_a=False): 

1568 """ 

1569 Compute a diagonal similarity transformation for row/column balancing. 

1570 

1571 The balancing tries to equalize the row and column 1-norms by applying 

1572 a similarity transformation such that the magnitude variation of the 

1573 matrix entries is reflected to the scaling matrices. 

1574 

1575 Moreover, if enabled, the matrix is first permuted to isolate the upper 

1576 triangular parts of the matrix and, again if scaling is also enabled, 

1577 only the remaining subblocks are subjected to scaling. 

1578 

1579 The balanced matrix satisfies the following equality 

1580 

1581 .. math:: 

1582 

1583 B = T^{-1} A T 

1584 

1585 The scaling coefficients are approximated to the nearest power of 2 

1586 to avoid round-off errors. 

1587 

1588 Parameters 

1589 ---------- 

1590 A : (n, n) array_like 

1591 Square data matrix for the balancing. 

1592 permute : bool, optional 

1593 The selector to define whether permutation of A is also performed 

1594 prior to scaling. 

1595 scale : bool, optional 

1596 The selector to turn on and off the scaling. If False, the matrix 

1597 will not be scaled. 

1598 separate : bool, optional 

1599 This switches from returning a full matrix of the transformation 

1600 to a tuple of two separate 1-D permutation and scaling arrays. 

1601 overwrite_a : bool, optional 

1602 This is passed to xGEBAL directly. Essentially, overwrites the result 

1603 to the data. It might increase the space efficiency. See LAPACK manual 

1604 for details. This is False by default. 

1605 

1606 Returns 

1607 ------- 

1608 B : (n, n) ndarray 

1609 Balanced matrix 

1610 T : (n, n) ndarray 

1611 A possibly permuted diagonal matrix whose nonzero entries are 

1612 integer powers of 2 to avoid numerical truncation errors. 

1613 scale, perm : (n,) ndarray 

1614 If ``separate`` keyword is set to True then instead of the array 

1615 ``T`` above, the scaling and the permutation vectors are given 

1616 separately as a tuple without allocating the full array ``T``. 

1617 

1618 Notes 

1619 ----- 

1620 This algorithm is particularly useful for eigenvalue and matrix 

1621 decompositions and in many cases it is already called by various 

1622 LAPACK routines. 

1623 

1624 The algorithm is based on the well-known technique of [1]_ and has 

1625 been modified to account for special cases. See [2]_ for details 

1626 which have been implemented since LAPACK v3.5.0. Before this version 

1627 there are corner cases where balancing can actually worsen the 

1628 conditioning. See [3]_ for such examples. 

1629 

1630 The code is a wrapper around LAPACK's xGEBAL routine family for matrix 

1631 balancing. 

1632 

1633 .. versionadded:: 0.19.0 

1634 

1635 References 

1636 ---------- 

1637 .. [1] B.N. Parlett and C. Reinsch, "Balancing a Matrix for 

1638 Calculation of Eigenvalues and Eigenvectors", Numerische Mathematik, 

1639 Vol.13(4), 1969, :doi:`10.1007/BF02165404` 

1640 .. [2] R. James, J. Langou, B.R. Lowery, "On matrix balancing and 

1641 eigenvector computation", 2014, :arxiv:`1401.5766` 

1642 .. [3] D.S. Watkins. A case where balancing is harmful. 

1643 Electron. Trans. Numer. Anal, Vol.23, 2006. 

1644 

1645 Examples 

1646 -------- 

1647 >>> import numpy as np 

1648 >>> from scipy import linalg 

1649 >>> x = np.array([[1,2,0], [9,1,0.01], [1,2,10*np.pi]]) 

1650 

1651 >>> y, permscale = linalg.matrix_balance(x) 

1652 >>> np.abs(x).sum(axis=0) / np.abs(x).sum(axis=1) 

1653 array([ 3.66666667, 0.4995005 , 0.91312162]) 

1654 

1655 >>> np.abs(y).sum(axis=0) / np.abs(y).sum(axis=1) 

1656 array([ 1.2 , 1.27041742, 0.92658316]) # may vary 

1657 

1658 >>> permscale # only powers of 2 (0.5 == 2^(-1)) 

1659 array([[ 0.5, 0. , 0. ], # may vary 

1660 [ 0. , 1. , 0. ], 

1661 [ 0. , 0. , 1. ]]) 

1662 

1663 """ 

1664 

1665 A = np.atleast_2d(_asarray_validated(A, check_finite=True)) 

1666 

1667 if not np.equal(*A.shape): 

1668 raise ValueError('The data matrix for balancing should be square.') 

1669 

1670 gebal = get_lapack_funcs(('gebal'), (A,)) 

1671 B, lo, hi, ps, info = gebal(A, scale=scale, permute=permute, 

1672 overwrite_a=overwrite_a) 

1673 

1674 if info < 0: 

1675 raise ValueError('xGEBAL exited with the internal error ' 

1676 '"illegal value in argument number {}.". See ' 

1677 'LAPACK documentation for the xGEBAL error codes.' 

1678 ''.format(-info)) 

1679 

1680 # Separate the permutations from the scalings and then convert to int 

1681 scaling = np.ones_like(ps, dtype=float) 

1682 scaling[lo:hi+1] = ps[lo:hi+1] 

1683 

1684 # gebal uses 1-indexing 

1685 ps = ps.astype(int, copy=False) - 1 

1686 n = A.shape[0] 

1687 perm = np.arange(n) 

1688 

1689 # LAPACK permutes with the ordering n --> hi, then 0--> lo 

1690 if hi < n: 

1691 for ind, x in enumerate(ps[hi+1:][::-1], 1): 

1692 if n-ind == x: 

1693 continue 

1694 perm[[x, n-ind]] = perm[[n-ind, x]] 

1695 

1696 if lo > 0: 

1697 for ind, x in enumerate(ps[:lo]): 

1698 if ind == x: 

1699 continue 

1700 perm[[x, ind]] = perm[[ind, x]] 

1701 

1702 if separate: 

1703 return B, (scaling, perm) 

1704 

1705 # get the inverse permutation 

1706 iperm = np.empty_like(perm) 

1707 iperm[perm] = np.arange(n) 

1708 

1709 return B, np.diag(scaling)[iperm, :] 

1710 

1711 

1712def _validate_args_for_toeplitz_ops(c_or_cr, b, check_finite, keep_b_shape, 

1713 enforce_square=True): 

1714 """Validate arguments and format inputs for toeplitz functions 

1715 

1716 Parameters 

1717 ---------- 

1718 c_or_cr : array_like or tuple of (array_like, array_like) 

1719 The vector ``c``, or a tuple of arrays (``c``, ``r``). Whatever the 

1720 actual shape of ``c``, it will be converted to a 1-D array. If not 

1721 supplied, ``r = conjugate(c)`` is assumed; in this case, if c[0] is 

1722 real, the Toeplitz matrix is Hermitian. r[0] is ignored; the first row 

1723 of the Toeplitz matrix is ``[c[0], r[1:]]``. Whatever the actual shape 

1724 of ``r``, it will be converted to a 1-D array. 

1725 b : (M,) or (M, K) array_like 

1726 Right-hand side in ``T x = b``. 

1727 check_finite : bool 

1728 Whether to check that the input matrices contain only finite numbers. 

1729 Disabling may give a performance gain, but may result in problems 

1730 (result entirely NaNs) if the inputs do contain infinities or NaNs. 

1731 keep_b_shape : bool 

1732 Whether to convert a (M,) dimensional b into a (M, 1) dimensional 

1733 matrix. 

1734 enforce_square : bool, optional 

1735 If True (default), this verifies that the Toeplitz matrix is square. 

1736 

1737 Returns 

1738 ------- 

1739 r : array 

1740 1d array corresponding to the first row of the Toeplitz matrix. 

1741 c: array 

1742 1d array corresponding to the first column of the Toeplitz matrix. 

1743 b: array 

1744 (M,), (M, 1) or (M, K) dimensional array, post validation, 

1745 corresponding to ``b``. 

1746 dtype: numpy datatype 

1747 ``dtype`` stores the datatype of ``r``, ``c`` and ``b``. If any of 

1748 ``r``, ``c`` or ``b`` are complex, ``dtype`` is ``np.complex128``, 

1749 otherwise, it is ``np.float``. 

1750 b_shape: tuple 

1751 Shape of ``b`` after passing it through ``_asarray_validated``. 

1752 

1753 """ 

1754 

1755 if isinstance(c_or_cr, tuple): 

1756 c, r = c_or_cr 

1757 c = _asarray_validated(c, check_finite=check_finite).ravel() 

1758 r = _asarray_validated(r, check_finite=check_finite).ravel() 

1759 else: 

1760 c = _asarray_validated(c_or_cr, check_finite=check_finite).ravel() 

1761 r = c.conjugate() 

1762 

1763 if b is None: 

1764 raise ValueError('`b` must be an array, not None.') 

1765 

1766 b = _asarray_validated(b, check_finite=check_finite) 

1767 b_shape = b.shape 

1768 

1769 is_not_square = r.shape[0] != c.shape[0] 

1770 if (enforce_square and is_not_square) or b.shape[0] != r.shape[0]: 

1771 raise ValueError('Incompatible dimensions.') 

1772 

1773 is_cmplx = np.iscomplexobj(r) or np.iscomplexobj(c) or np.iscomplexobj(b) 

1774 dtype = np.complex128 if is_cmplx else np.float64 

1775 r, c, b = (np.asarray(i, dtype=dtype) for i in (r, c, b)) 

1776 

1777 if b.ndim == 1 and not keep_b_shape: 

1778 b = b.reshape(-1, 1) 

1779 elif b.ndim != 1: 

1780 b = b.reshape(b.shape[0], -1) 

1781 

1782 return r, c, b, dtype, b_shape 

1783 

1784 

1785def matmul_toeplitz(c_or_cr, x, check_finite=False, workers=None): 

1786 """Efficient Toeplitz Matrix-Matrix Multiplication using FFT 

1787 

1788 This function returns the matrix multiplication between a Toeplitz 

1789 matrix and a dense matrix. 

1790 

1791 The Toeplitz matrix has constant diagonals, with c as its first column 

1792 and r as its first row. If r is not given, ``r == conjugate(c)`` is 

1793 assumed. 

1794 

1795 Parameters 

1796 ---------- 

1797 c_or_cr : array_like or tuple of (array_like, array_like) 

1798 The vector ``c``, or a tuple of arrays (``c``, ``r``). Whatever the 

1799 actual shape of ``c``, it will be converted to a 1-D array. If not 

1800 supplied, ``r = conjugate(c)`` is assumed; in this case, if c[0] is 

1801 real, the Toeplitz matrix is Hermitian. r[0] is ignored; the first row 

1802 of the Toeplitz matrix is ``[c[0], r[1:]]``. Whatever the actual shape 

1803 of ``r``, it will be converted to a 1-D array. 

1804 x : (M,) or (M, K) array_like 

1805 Matrix with which to multiply. 

1806 check_finite : bool, optional 

1807 Whether to check that the input matrices contain only finite numbers. 

1808 Disabling may give a performance gain, but may result in problems 

1809 (result entirely NaNs) if the inputs do contain infinities or NaNs. 

1810 workers : int, optional 

1811 To pass to scipy.fft.fft and ifft. Maximum number of workers to use 

1812 for parallel computation. If negative, the value wraps around from 

1813 ``os.cpu_count()``. See scipy.fft.fft for more details. 

1814 

1815 Returns 

1816 ------- 

1817 T @ x : (M,) or (M, K) ndarray 

1818 The result of the matrix multiplication ``T @ x``. Shape of return 

1819 matches shape of `x`. 

1820 

1821 See Also 

1822 -------- 

1823 toeplitz : Toeplitz matrix 

1824 solve_toeplitz : Solve a Toeplitz system using Levinson Recursion 

1825 

1826 Notes 

1827 ----- 

1828 The Toeplitz matrix is embedded in a circulant matrix and the FFT is used 

1829 to efficiently calculate the matrix-matrix product. 

1830 

1831 Because the computation is based on the FFT, integer inputs will 

1832 result in floating point outputs. This is unlike NumPy's `matmul`, 

1833 which preserves the data type of the input. 

1834 

1835 This is partly based on the implementation that can be found in [1]_, 

1836 licensed under the MIT license. More information about the method can be 

1837 found in reference [2]_. References [3]_ and [4]_ have more reference 

1838 implementations in Python. 

1839 

1840 .. versionadded:: 1.6.0 

1841 

1842 References 

1843 ---------- 

1844 .. [1] Jacob R Gardner, Geoff Pleiss, David Bindel, Kilian 

1845 Q Weinberger, Andrew Gordon Wilson, "GPyTorch: Blackbox Matrix-Matrix 

1846 Gaussian Process Inference with GPU Acceleration" with contributions 

1847 from Max Balandat and Ruihan Wu. Available online: 

1848 https://github.com/cornellius-gp/gpytorch 

1849 

1850 .. [2] J. Demmel, P. Koev, and X. Li, "A Brief Survey of Direct Linear 

1851 Solvers". In Z. Bai, J. Demmel, J. Dongarra, A. Ruhe, and H. van der 

1852 Vorst, editors. Templates for the Solution of Algebraic Eigenvalue 

1853 Problems: A Practical Guide. SIAM, Philadelphia, 2000. Available at: 

1854 http://www.netlib.org/utk/people/JackDongarra/etemplates/node384.html 

1855 

1856 .. [3] R. Scheibler, E. Bezzam, I. Dokmanic, Pyroomacoustics: A Python 

1857 package for audio room simulations and array processing algorithms, 

1858 Proc. IEEE ICASSP, Calgary, CA, 2018. 

1859 https://github.com/LCAV/pyroomacoustics/blob/pypi-release/ 

1860 pyroomacoustics/adaptive/util.py 

1861 

1862 .. [4] Marano S, Edwards B, Ferrari G and Fah D (2017), "Fitting 

1863 Earthquake Spectra: Colored Noise and Incomplete Data", Bulletin of 

1864 the Seismological Society of America., January, 2017. Vol. 107(1), 

1865 pp. 276-291. 

1866 

1867 Examples 

1868 -------- 

1869 Multiply the Toeplitz matrix T with matrix x:: 

1870 

1871 [ 1 -1 -2 -3] [1 10] 

1872 T = [ 3 1 -1 -2] x = [2 11] 

1873 [ 6 3 1 -1] [2 11] 

1874 [10 6 3 1] [5 19] 

1875 

1876 To specify the Toeplitz matrix, only the first column and the first 

1877 row are needed. 

1878 

1879 >>> import numpy as np 

1880 >>> c = np.array([1, 3, 6, 10]) # First column of T 

1881 >>> r = np.array([1, -1, -2, -3]) # First row of T 

1882 >>> x = np.array([[1, 10], [2, 11], [2, 11], [5, 19]]) 

1883 

1884 >>> from scipy.linalg import toeplitz, matmul_toeplitz 

1885 >>> matmul_toeplitz((c, r), x) 

1886 array([[-20., -80.], 

1887 [ -7., -8.], 

1888 [ 9., 85.], 

1889 [ 33., 218.]]) 

1890 

1891 Check the result by creating the full Toeplitz matrix and 

1892 multiplying it by ``x``. 

1893 

1894 >>> toeplitz(c, r) @ x 

1895 array([[-20, -80], 

1896 [ -7, -8], 

1897 [ 9, 85], 

1898 [ 33, 218]]) 

1899 

1900 The full matrix is never formed explicitly, so this routine 

1901 is suitable for very large Toeplitz matrices. 

1902 

1903 >>> n = 1000000 

1904 >>> matmul_toeplitz([1] + [0]*(n-1), np.ones(n)) 

1905 array([1., 1., 1., ..., 1., 1., 1.]) 

1906 

1907 """ 

1908 

1909 from ..fft import fft, ifft, rfft, irfft 

1910 

1911 r, c, x, dtype, x_shape = _validate_args_for_toeplitz_ops( 

1912 c_or_cr, x, check_finite, keep_b_shape=False, enforce_square=False) 

1913 n, m = x.shape 

1914 

1915 T_nrows = len(c) 

1916 T_ncols = len(r) 

1917 p = T_nrows + T_ncols - 1 # equivalent to len(embedded_col) 

1918 

1919 embedded_col = np.concatenate((c, r[-1:0:-1])) 

1920 

1921 if np.iscomplexobj(embedded_col) or np.iscomplexobj(x): 

1922 fft_mat = fft(embedded_col, axis=0, workers=workers).reshape(-1, 1) 

1923 fft_x = fft(x, n=p, axis=0, workers=workers) 

1924 

1925 mat_times_x = ifft(fft_mat*fft_x, axis=0, 

1926 workers=workers)[:T_nrows, :] 

1927 else: 

1928 # Real inputs; using rfft is faster 

1929 fft_mat = rfft(embedded_col, axis=0, workers=workers).reshape(-1, 1) 

1930 fft_x = rfft(x, n=p, axis=0, workers=workers) 

1931 

1932 mat_times_x = irfft(fft_mat*fft_x, axis=0, 

1933 workers=workers, n=p)[:T_nrows, :] 

1934 

1935 return_shape = (T_nrows,) if len(x_shape) == 1 else (T_nrows, m) 

1936 return mat_times_x.reshape(*return_shape)