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

129 statements  

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

1"""QR decomposition functions.""" 

2import numpy 

3 

4# Local imports 

5from .lapack import get_lapack_funcs 

6from ._misc import _datacopied 

7 

8__all__ = ['qr', 'qr_multiply', 'rq'] 

9 

10 

11def safecall(f, name, *args, **kwargs): 

12 """Call a LAPACK routine, determining lwork automatically and handling 

13 error return values""" 

14 lwork = kwargs.get("lwork", None) 

15 if lwork in (None, -1): 

16 kwargs['lwork'] = -1 

17 ret = f(*args, **kwargs) 

18 kwargs['lwork'] = ret[-2][0].real.astype(numpy.int_) 

19 ret = f(*args, **kwargs) 

20 if ret[-1] < 0: 

21 raise ValueError("illegal value in %dth argument of internal %s" 

22 % (-ret[-1], name)) 

23 return ret[:-2] 

24 

25 

26def qr(a, overwrite_a=False, lwork=None, mode='full', pivoting=False, 

27 check_finite=True): 

28 """ 

29 Compute QR decomposition of a matrix. 

30 

31 Calculate the decomposition ``A = Q R`` where Q is unitary/orthogonal 

32 and R upper triangular. 

33 

34 Parameters 

35 ---------- 

36 a : (M, N) array_like 

37 Matrix to be decomposed 

38 overwrite_a : bool, optional 

39 Whether data in `a` is overwritten (may improve performance if 

40 `overwrite_a` is set to True by reusing the existing input data 

41 structure rather than creating a new one.) 

42 lwork : int, optional 

43 Work array size, lwork >= a.shape[1]. If None or -1, an optimal size 

44 is computed. 

45 mode : {'full', 'r', 'economic', 'raw'}, optional 

46 Determines what information is to be returned: either both Q and R 

47 ('full', default), only R ('r') or both Q and R but computed in 

48 economy-size ('economic', see Notes). The final option 'raw' 

49 (added in SciPy 0.11) makes the function return two matrices 

50 (Q, TAU) in the internal format used by LAPACK. 

51 pivoting : bool, optional 

52 Whether or not factorization should include pivoting for rank-revealing 

53 qr decomposition. If pivoting, compute the decomposition 

54 ``A P = Q R`` as above, but where P is chosen such that the diagonal 

55 of R is non-increasing. 

56 check_finite : bool, optional 

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

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

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

60 

61 Returns 

62 ------- 

63 Q : float or complex ndarray 

64 Of shape (M, M), or (M, K) for ``mode='economic'``. Not returned 

65 if ``mode='r'``. Replaced by tuple ``(Q, TAU)`` if ``mode='raw'``. 

66 R : float or complex ndarray 

67 Of shape (M, N), or (K, N) for ``mode in ['economic', 'raw']``. 

68 ``K = min(M, N)``. 

69 P : int ndarray 

70 Of shape (N,) for ``pivoting=True``. Not returned if 

71 ``pivoting=False``. 

72 

73 Raises 

74 ------ 

75 LinAlgError 

76 Raised if decomposition fails 

77 

78 Notes 

79 ----- 

80 This is an interface to the LAPACK routines dgeqrf, zgeqrf, 

81 dorgqr, zungqr, dgeqp3, and zgeqp3. 

82 

83 If ``mode=economic``, the shapes of Q and R are (M, K) and (K, N) instead 

84 of (M,M) and (M,N), with ``K=min(M,N)``. 

85 

86 Examples 

87 -------- 

88 >>> import numpy as np 

89 >>> from scipy import linalg 

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

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

92 

93 >>> q, r = linalg.qr(a) 

94 >>> np.allclose(a, np.dot(q, r)) 

95 True 

96 >>> q.shape, r.shape 

97 ((9, 9), (9, 6)) 

98 

99 >>> r2 = linalg.qr(a, mode='r') 

100 >>> np.allclose(r, r2) 

101 True 

102 

103 >>> q3, r3 = linalg.qr(a, mode='economic') 

104 >>> q3.shape, r3.shape 

105 ((9, 6), (6, 6)) 

106 

107 >>> q4, r4, p4 = linalg.qr(a, pivoting=True) 

108 >>> d = np.abs(np.diag(r4)) 

109 >>> np.all(d[1:] <= d[:-1]) 

110 True 

111 >>> np.allclose(a[:, p4], np.dot(q4, r4)) 

112 True 

113 >>> q4.shape, r4.shape, p4.shape 

114 ((9, 9), (9, 6), (6,)) 

115 

116 >>> q5, r5, p5 = linalg.qr(a, mode='economic', pivoting=True) 

117 >>> q5.shape, r5.shape, p5.shape 

118 ((9, 6), (6, 6), (6,)) 

119 

120 """ 

121 # 'qr' was the old default, equivalent to 'full'. Neither 'full' nor 

122 # 'qr' are used below. 

123 # 'raw' is used internally by qr_multiply 

124 if mode not in ['full', 'qr', 'r', 'economic', 'raw']: 

125 raise ValueError("Mode argument should be one of ['full', 'r'," 

126 "'economic', 'raw']") 

127 

128 if check_finite: 

129 a1 = numpy.asarray_chkfinite(a) 

130 else: 

131 a1 = numpy.asarray(a) 

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

133 raise ValueError("expected a 2-D array") 

134 M, N = a1.shape 

135 overwrite_a = overwrite_a or (_datacopied(a1, a)) 

136 

137 if pivoting: 

138 geqp3, = get_lapack_funcs(('geqp3',), (a1,)) 

139 qr, jpvt, tau = safecall(geqp3, "geqp3", a1, overwrite_a=overwrite_a) 

140 jpvt -= 1 # geqp3 returns a 1-based index array, so subtract 1 

141 else: 

142 geqrf, = get_lapack_funcs(('geqrf',), (a1,)) 

143 qr, tau = safecall(geqrf, "geqrf", a1, lwork=lwork, 

144 overwrite_a=overwrite_a) 

145 

146 if mode not in ['economic', 'raw'] or M < N: 

147 R = numpy.triu(qr) 

148 else: 

149 R = numpy.triu(qr[:N, :]) 

150 

151 if pivoting: 

152 Rj = R, jpvt 

153 else: 

154 Rj = R, 

155 

156 if mode == 'r': 

157 return Rj 

158 elif mode == 'raw': 

159 return ((qr, tau),) + Rj 

160 

161 gor_un_gqr, = get_lapack_funcs(('orgqr',), (qr,)) 

162 

163 if M < N: 

164 Q, = safecall(gor_un_gqr, "gorgqr/gungqr", qr[:, :M], tau, 

165 lwork=lwork, overwrite_a=1) 

166 elif mode == 'economic': 

167 Q, = safecall(gor_un_gqr, "gorgqr/gungqr", qr, tau, lwork=lwork, 

168 overwrite_a=1) 

169 else: 

170 t = qr.dtype.char 

171 qqr = numpy.empty((M, M), dtype=t) 

172 qqr[:, :N] = qr 

173 Q, = safecall(gor_un_gqr, "gorgqr/gungqr", qqr, tau, lwork=lwork, 

174 overwrite_a=1) 

175 

176 return (Q,) + Rj 

177 

178 

179def qr_multiply(a, c, mode='right', pivoting=False, conjugate=False, 

180 overwrite_a=False, overwrite_c=False): 

181 """ 

182 Calculate the QR decomposition and multiply Q with a matrix. 

183 

184 Calculate the decomposition ``A = Q R`` where Q is unitary/orthogonal 

185 and R upper triangular. Multiply Q with a vector or a matrix c. 

186 

187 Parameters 

188 ---------- 

189 a : (M, N), array_like 

190 Input array 

191 c : array_like 

192 Input array to be multiplied by ``q``. 

193 mode : {'left', 'right'}, optional 

194 ``Q @ c`` is returned if mode is 'left', ``c @ Q`` is returned if 

195 mode is 'right'. 

196 The shape of c must be appropriate for the matrix multiplications, 

197 if mode is 'left', ``min(a.shape) == c.shape[0]``, 

198 if mode is 'right', ``a.shape[0] == c.shape[1]``. 

199 pivoting : bool, optional 

200 Whether or not factorization should include pivoting for rank-revealing 

201 qr decomposition, see the documentation of qr. 

202 conjugate : bool, optional 

203 Whether Q should be complex-conjugated. This might be faster 

204 than explicit conjugation. 

205 overwrite_a : bool, optional 

206 Whether data in a is overwritten (may improve performance) 

207 overwrite_c : bool, optional 

208 Whether data in c is overwritten (may improve performance). 

209 If this is used, c must be big enough to keep the result, 

210 i.e. ``c.shape[0]`` = ``a.shape[0]`` if mode is 'left'. 

211 

212 Returns 

213 ------- 

214 CQ : ndarray 

215 The product of ``Q`` and ``c``. 

216 R : (K, N), ndarray 

217 R array of the resulting QR factorization where ``K = min(M, N)``. 

218 P : (N,) ndarray 

219 Integer pivot array. Only returned when ``pivoting=True``. 

220 

221 Raises 

222 ------ 

223 LinAlgError 

224 Raised if QR decomposition fails. 

225 

226 Notes 

227 ----- 

228 This is an interface to the LAPACK routines ``?GEQRF``, ``?ORMQR``, 

229 ``?UNMQR``, and ``?GEQP3``. 

230 

231 .. versionadded:: 0.11.0 

232 

233 Examples 

234 -------- 

235 >>> import numpy as np 

236 >>> from scipy.linalg import qr_multiply, qr 

237 >>> A = np.array([[1, 3, 3], [2, 3, 2], [2, 3, 3], [1, 3, 2]]) 

238 >>> qc, r1, piv1 = qr_multiply(A, 2*np.eye(4), pivoting=1) 

239 >>> qc 

240 array([[-1., 1., -1.], 

241 [-1., -1., 1.], 

242 [-1., -1., -1.], 

243 [-1., 1., 1.]]) 

244 >>> r1 

245 array([[-6., -3., -5. ], 

246 [ 0., -1., -1.11022302e-16], 

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

248 >>> piv1 

249 array([1, 0, 2], dtype=int32) 

250 >>> q2, r2, piv2 = qr(A, mode='economic', pivoting=1) 

251 >>> np.allclose(2*q2 - qc, np.zeros((4, 3))) 

252 True 

253 

254 """ 

255 if mode not in ['left', 'right']: 

256 raise ValueError("Mode argument can only be 'left' or 'right' but " 

257 "not '{}'".format(mode)) 

258 c = numpy.asarray_chkfinite(c) 

259 if c.ndim < 2: 

260 onedim = True 

261 c = numpy.atleast_2d(c) 

262 if mode == "left": 

263 c = c.T 

264 else: 

265 onedim = False 

266 

267 a = numpy.atleast_2d(numpy.asarray(a)) # chkfinite done in qr 

268 M, N = a.shape 

269 

270 if mode == 'left': 

271 if c.shape[0] != min(M, N + overwrite_c*(M-N)): 

272 raise ValueError('Array shapes are not compatible for Q @ c' 

273 ' operation: {} vs {}'.format(a.shape, c.shape)) 

274 else: 

275 if M != c.shape[1]: 

276 raise ValueError('Array shapes are not compatible for c @ Q' 

277 ' operation: {} vs {}'.format(c.shape, a.shape)) 

278 

279 raw = qr(a, overwrite_a, None, "raw", pivoting) 

280 Q, tau = raw[0] 

281 

282 gor_un_mqr, = get_lapack_funcs(('ormqr',), (Q,)) 

283 if gor_un_mqr.typecode in ('s', 'd'): 

284 trans = "T" 

285 else: 

286 trans = "C" 

287 

288 Q = Q[:, :min(M, N)] 

289 if M > N and mode == "left" and not overwrite_c: 

290 if conjugate: 

291 cc = numpy.zeros((c.shape[1], M), dtype=c.dtype, order="F") 

292 cc[:, :N] = c.T 

293 else: 

294 cc = numpy.zeros((M, c.shape[1]), dtype=c.dtype, order="F") 

295 cc[:N, :] = c 

296 trans = "N" 

297 if conjugate: 

298 lr = "R" 

299 else: 

300 lr = "L" 

301 overwrite_c = True 

302 elif c.flags["C_CONTIGUOUS"] and trans == "T" or conjugate: 

303 cc = c.T 

304 if mode == "left": 

305 lr = "R" 

306 else: 

307 lr = "L" 

308 else: 

309 trans = "N" 

310 cc = c 

311 if mode == "left": 

312 lr = "L" 

313 else: 

314 lr = "R" 

315 cQ, = safecall(gor_un_mqr, "gormqr/gunmqr", lr, trans, Q, tau, cc, 

316 overwrite_c=overwrite_c) 

317 if trans != "N": 

318 cQ = cQ.T 

319 if mode == "right": 

320 cQ = cQ[:, :min(M, N)] 

321 if onedim: 

322 cQ = cQ.ravel() 

323 

324 return (cQ,) + raw[1:] 

325 

326 

327def rq(a, overwrite_a=False, lwork=None, mode='full', check_finite=True): 

328 """ 

329 Compute RQ decomposition of a matrix. 

330 

331 Calculate the decomposition ``A = R Q`` where Q is unitary/orthogonal 

332 and R upper triangular. 

333 

334 Parameters 

335 ---------- 

336 a : (M, N) array_like 

337 Matrix to be decomposed 

338 overwrite_a : bool, optional 

339 Whether data in a is overwritten (may improve performance) 

340 lwork : int, optional 

341 Work array size, lwork >= a.shape[1]. If None or -1, an optimal size 

342 is computed. 

343 mode : {'full', 'r', 'economic'}, optional 

344 Determines what information is to be returned: either both Q and R 

345 ('full', default), only R ('r') or both Q and R but computed in 

346 economy-size ('economic', see Notes). 

347 check_finite : bool, optional 

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

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

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

351 

352 Returns 

353 ------- 

354 R : float or complex ndarray 

355 Of shape (M, N) or (M, K) for ``mode='economic'``. ``K = min(M, N)``. 

356 Q : float or complex ndarray 

357 Of shape (N, N) or (K, N) for ``mode='economic'``. Not returned 

358 if ``mode='r'``. 

359 

360 Raises 

361 ------ 

362 LinAlgError 

363 If decomposition fails. 

364 

365 Notes 

366 ----- 

367 This is an interface to the LAPACK routines sgerqf, dgerqf, cgerqf, zgerqf, 

368 sorgrq, dorgrq, cungrq and zungrq. 

369 

370 If ``mode=economic``, the shapes of Q and R are (K, N) and (M, K) instead 

371 of (N,N) and (M,N), with ``K=min(M,N)``. 

372 

373 Examples 

374 -------- 

375 >>> import numpy as np 

376 >>> from scipy import linalg 

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

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

379 >>> r, q = linalg.rq(a) 

380 >>> np.allclose(a, r @ q) 

381 True 

382 >>> r.shape, q.shape 

383 ((6, 9), (9, 9)) 

384 >>> r2 = linalg.rq(a, mode='r') 

385 >>> np.allclose(r, r2) 

386 True 

387 >>> r3, q3 = linalg.rq(a, mode='economic') 

388 >>> r3.shape, q3.shape 

389 ((6, 6), (6, 9)) 

390 

391 """ 

392 if mode not in ['full', 'r', 'economic']: 

393 raise ValueError( 

394 "Mode argument should be one of ['full', 'r', 'economic']") 

395 

396 if check_finite: 

397 a1 = numpy.asarray_chkfinite(a) 

398 else: 

399 a1 = numpy.asarray(a) 

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

401 raise ValueError('expected matrix') 

402 M, N = a1.shape 

403 overwrite_a = overwrite_a or (_datacopied(a1, a)) 

404 

405 gerqf, = get_lapack_funcs(('gerqf',), (a1,)) 

406 rq, tau = safecall(gerqf, 'gerqf', a1, lwork=lwork, 

407 overwrite_a=overwrite_a) 

408 if not mode == 'economic' or N < M: 

409 R = numpy.triu(rq, N-M) 

410 else: 

411 R = numpy.triu(rq[-M:, -M:]) 

412 

413 if mode == 'r': 

414 return R 

415 

416 gor_un_grq, = get_lapack_funcs(('orgrq',), (rq,)) 

417 

418 if N < M: 

419 Q, = safecall(gor_un_grq, "gorgrq/gungrq", rq[-N:], tau, lwork=lwork, 

420 overwrite_a=1) 

421 elif mode == 'economic': 

422 Q, = safecall(gor_un_grq, "gorgrq/gungrq", rq, tau, lwork=lwork, 

423 overwrite_a=1) 

424 else: 

425 rq1 = numpy.empty((N, N), dtype=rq.dtype) 

426 rq1[-M:] = rq 

427 Q, = safecall(gor_un_grq, "gorgrq/gungrq", rq1, tau, lwork=lwork, 

428 overwrite_a=1) 

429 

430 return R, Q