qoro-divi 0.2.0b1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. divi/__init__.py +8 -0
  2. divi/_pbar.py +73 -0
  3. divi/circuits.py +139 -0
  4. divi/exp/cirq/__init__.py +7 -0
  5. divi/exp/cirq/_lexer.py +126 -0
  6. divi/exp/cirq/_parser.py +889 -0
  7. divi/exp/cirq/_qasm_export.py +37 -0
  8. divi/exp/cirq/_qasm_import.py +35 -0
  9. divi/exp/cirq/exception.py +21 -0
  10. divi/exp/scipy/_cobyla.py +342 -0
  11. divi/exp/scipy/pyprima/LICENCE.txt +28 -0
  12. divi/exp/scipy/pyprima/__init__.py +263 -0
  13. divi/exp/scipy/pyprima/cobyla/__init__.py +0 -0
  14. divi/exp/scipy/pyprima/cobyla/cobyla.py +599 -0
  15. divi/exp/scipy/pyprima/cobyla/cobylb.py +849 -0
  16. divi/exp/scipy/pyprima/cobyla/geometry.py +240 -0
  17. divi/exp/scipy/pyprima/cobyla/initialize.py +269 -0
  18. divi/exp/scipy/pyprima/cobyla/trustregion.py +540 -0
  19. divi/exp/scipy/pyprima/cobyla/update.py +331 -0
  20. divi/exp/scipy/pyprima/common/__init__.py +0 -0
  21. divi/exp/scipy/pyprima/common/_bounds.py +41 -0
  22. divi/exp/scipy/pyprima/common/_linear_constraints.py +46 -0
  23. divi/exp/scipy/pyprima/common/_nonlinear_constraints.py +64 -0
  24. divi/exp/scipy/pyprima/common/_project.py +224 -0
  25. divi/exp/scipy/pyprima/common/checkbreak.py +107 -0
  26. divi/exp/scipy/pyprima/common/consts.py +48 -0
  27. divi/exp/scipy/pyprima/common/evaluate.py +101 -0
  28. divi/exp/scipy/pyprima/common/history.py +39 -0
  29. divi/exp/scipy/pyprima/common/infos.py +30 -0
  30. divi/exp/scipy/pyprima/common/linalg.py +452 -0
  31. divi/exp/scipy/pyprima/common/message.py +336 -0
  32. divi/exp/scipy/pyprima/common/powalg.py +131 -0
  33. divi/exp/scipy/pyprima/common/preproc.py +393 -0
  34. divi/exp/scipy/pyprima/common/present.py +5 -0
  35. divi/exp/scipy/pyprima/common/ratio.py +56 -0
  36. divi/exp/scipy/pyprima/common/redrho.py +49 -0
  37. divi/exp/scipy/pyprima/common/selectx.py +346 -0
  38. divi/interfaces.py +25 -0
  39. divi/parallel_simulator.py +258 -0
  40. divi/qasm.py +220 -0
  41. divi/qem.py +191 -0
  42. divi/qlogger.py +119 -0
  43. divi/qoro_service.py +343 -0
  44. divi/qprog/__init__.py +13 -0
  45. divi/qprog/_graph_partitioning.py +619 -0
  46. divi/qprog/_mlae.py +182 -0
  47. divi/qprog/_qaoa.py +440 -0
  48. divi/qprog/_vqe.py +275 -0
  49. divi/qprog/_vqe_sweep.py +144 -0
  50. divi/qprog/batch.py +235 -0
  51. divi/qprog/optimizers.py +75 -0
  52. divi/qprog/quantum_program.py +493 -0
  53. divi/utils.py +116 -0
  54. qoro_divi-0.2.0b1.dist-info/LICENSE +190 -0
  55. qoro_divi-0.2.0b1.dist-info/LICENSES/Apache-2.0.txt +73 -0
  56. qoro_divi-0.2.0b1.dist-info/METADATA +57 -0
  57. qoro_divi-0.2.0b1.dist-info/RECORD +58 -0
  58. qoro_divi-0.2.0b1.dist-info/WHEEL +4 -0
@@ -0,0 +1,336 @@
1
+ """
2
+ This module provides some functions that print messages to terminal/files.
3
+
4
+ Translated from Zaikun Zhang's modern-Fortran reference implementation in PRIMA.
5
+
6
+ Dedicated to late Professor M. J. D. Powell FRS (1936--2015).
7
+
8
+ Python translation by Nickolai Belakovski.
9
+
10
+ N.B.:
11
+ 1. In case parallelism is desirable (especially during initialization), the functions may
12
+ have to be modified or disabled due to the IO operations.
13
+ 2. IPRINT indicates the level of verbosity, which increases with the absolute value of IPRINT.
14
+ IPRINT = +/-3 can be expensive due to high IO operations.
15
+ """
16
+
17
+ import numpy as np
18
+
19
+ from .consts import DEBUGGING
20
+ from .infos import (
21
+ CALLBACK_TERMINATE,
22
+ DAMAGING_ROUNDING,
23
+ FTARGET_ACHIEVED,
24
+ MAXFUN_REACHED,
25
+ MAXTR_REACHED,
26
+ NAN_INF_F,
27
+ NAN_INF_MODEL,
28
+ NAN_INF_X,
29
+ NO_SPACE_BETWEEN_BOUNDS,
30
+ SMALL_TR_RADIUS,
31
+ TRSUBP_FAILED,
32
+ ZERO_LINEAR_CONSTRAINT,
33
+ )
34
+ from .present import present
35
+
36
+ spaces = " "
37
+
38
+
39
+ def get_info_string(solver, info):
40
+ if info == FTARGET_ACHIEVED:
41
+ reason = "the target function value is achieved."
42
+ elif info == MAXFUN_REACHED:
43
+ reason = "the objective function has been evaluated MAXFUN times."
44
+ elif info == MAXTR_REACHED:
45
+ reason = "the maximal number of trust region iterations has been reached."
46
+ elif info == SMALL_TR_RADIUS:
47
+ reason = "the trust region radius reaches its lower bound."
48
+ elif info == TRSUBP_FAILED:
49
+ reason = "a trust region step has failed to reduce the quadratic model."
50
+ elif info == NAN_INF_X:
51
+ reason = "NaN or Inf occurs in x."
52
+ elif info == NAN_INF_F:
53
+ reason = "the objective function returns NaN/+Inf."
54
+ elif info == NAN_INF_MODEL:
55
+ reason = "NaN or Inf occurs in the models."
56
+ elif info == DAMAGING_ROUNDING:
57
+ reason = "rounding errors are becoming damaging."
58
+ elif info == NO_SPACE_BETWEEN_BOUNDS:
59
+ reason = "there is no space between the lower and upper bounds of variable."
60
+ elif info == ZERO_LINEAR_CONSTRAINT:
61
+ reason = "one of the linear constraints has a zero gradient"
62
+ elif info == CALLBACK_TERMINATE:
63
+ reason = "the callback function requested termination"
64
+ else:
65
+ reason = "UNKNOWN EXIT FLAG"
66
+ ret_message = f"Return from {solver} because {reason.strip()}"
67
+ return ret_message
68
+
69
+
70
+ def retmsg(solver, info, iprint, nf, f, x, cstrv=None, constr=None):
71
+ """
72
+ This function prints messages at return.
73
+ """
74
+ # Local variables
75
+ valid_exit_codes = [
76
+ FTARGET_ACHIEVED,
77
+ MAXFUN_REACHED,
78
+ MAXTR_REACHED,
79
+ SMALL_TR_RADIUS,
80
+ TRSUBP_FAILED,
81
+ NAN_INF_F,
82
+ NAN_INF_X,
83
+ NAN_INF_MODEL,
84
+ DAMAGING_ROUNDING,
85
+ NO_SPACE_BETWEEN_BOUNDS,
86
+ ZERO_LINEAR_CONSTRAINT,
87
+ CALLBACK_TERMINATE,
88
+ ]
89
+
90
+ # Preconditions
91
+ if DEBUGGING:
92
+ assert info in valid_exit_codes
93
+
94
+ # ====================#
95
+ # Calculation starts #
96
+ # ====================#
97
+
98
+ if abs(iprint) < 1: # No printing (iprint == 0)
99
+ return
100
+ elif iprint > 0: # Print the message to the standard out.
101
+ fname = ""
102
+ else: # Print the message to a file named FNAME.
103
+ fname = f"{solver}_output.txt"
104
+
105
+ # Decide whether the problem is truly constrained.
106
+ if present(constr):
107
+ is_constrained = np.size(constr) > 0
108
+ else:
109
+ is_constrained = present(cstrv)
110
+
111
+ # Decide the constraint violation.
112
+ if present(cstrv):
113
+ cstrv_loc = cstrv
114
+ elif present(constr):
115
+ cstrv_loc = np.max(
116
+ np.append(0, -constr)
117
+ ) # N.B.: We assume that the constraint is CONSTR >= 0.
118
+ else:
119
+ cstrv_loc = 0
120
+
121
+ # Decide the return message.
122
+ ret_message = get_info_string(solver, info)
123
+
124
+ if np.size(x) <= 2:
125
+ x_message = f"\nThe corresponding X is: {x}" # Printed in one line
126
+ else:
127
+ x_message = f"\nThe corresponding X is:\n{x}"
128
+
129
+ if is_constrained:
130
+ nf_message = (
131
+ f"\nNumber of function values = {nf}{spaces}"
132
+ f"Least value of F = {f}{spaces}Constraint violation = {cstrv_loc}"
133
+ )
134
+ else:
135
+ nf_message = f"\nNumber of function values = {nf}{spaces}Least value of F = {f}"
136
+
137
+ if is_constrained and present(constr):
138
+ if np.size(constr) <= 2:
139
+ constr_message = (
140
+ f"\nThe constraint value is: {constr}" # Printed in one line
141
+ )
142
+ else:
143
+ constr_message = f"\nThe constraint value is:\n{constr}"
144
+ else:
145
+ constr_message = ""
146
+
147
+ # Print the message.
148
+ if abs(iprint) >= 2:
149
+ message = f"\n{ret_message}{nf_message}{x_message}{constr_message}\n"
150
+ else:
151
+ message = f"{ret_message}{nf_message}{x_message}{constr_message}\n"
152
+ if len(fname) > 0:
153
+ with open(fname, "a") as f:
154
+ f.write(message)
155
+ else:
156
+ print(message)
157
+
158
+
159
+ def rhomsg(solver, iprint, nf, delta, f, rho, x, cstrv=None, constr=None, cpen=None):
160
+ """
161
+ This function prints messages when RHO is updated.
162
+ """
163
+
164
+ # ====================#
165
+ # Calculation starts #
166
+ # ====================#
167
+
168
+ if abs(iprint) < 2: # No printing
169
+ return
170
+ elif iprint > 0: # Print the message to the standard out.
171
+ fname = ""
172
+ else: # Print the message to a file named FNAME.
173
+ fname = f"{solver.strip()}_output.txt"
174
+
175
+ # Decide whether the problem is truly constrained.
176
+ if present(constr):
177
+ is_constrained = np.size(constr) > 0
178
+ else:
179
+ is_constrained = present(cstrv)
180
+
181
+ # Decide the constraint violation.
182
+ if present(cstrv):
183
+ cstrv_loc = cstrv
184
+ elif present(constr):
185
+ cstrv_loc = np.max(
186
+ np.append(0, -constr)
187
+ ) # N.B.: We assume that the constraint is CONSTR >= 0.
188
+ else:
189
+ cstrv_loc = 0
190
+
191
+ if present(cpen):
192
+ rho_message = (
193
+ f"\nNew RHO = {rho}{spaces}Delta = {delta}{spaces}" f"CPEN = {cpen}"
194
+ )
195
+ else:
196
+ rho_message = f"\nNew RHO = {rho}{spaces}Delta = {delta}"
197
+
198
+ if np.size(x) <= 2:
199
+ x_message = f"\nThe corresponding X is: {x}" # Printed in one line
200
+ else:
201
+ x_message = f"\nThe corresponding X is:\n{x}"
202
+
203
+ if is_constrained:
204
+ nf_message = (
205
+ f"\nNumber of function values = {nf}{spaces}"
206
+ f"Least value of F = {f}{spaces}Constraint violation = {cstrv_loc}"
207
+ )
208
+ else:
209
+ nf_message = f"\nNumber of function values = {nf}{spaces}Least value of F = {f}"
210
+
211
+ if is_constrained and present(constr):
212
+ if np.size(constr) <= 2:
213
+ constr_message = (
214
+ f"\nThe constraint value is: {constr}" # Printed in one line
215
+ )
216
+ else:
217
+ constr_message = f"\nThe constraint value is:\n{constr}"
218
+ else:
219
+ constr_message = ""
220
+
221
+ # Print the message.
222
+ if abs(iprint) >= 3:
223
+ message = f"\n{rho_message}{nf_message}{x_message}{constr_message}"
224
+ else:
225
+ message = f"{rho_message}{nf_message}{x_message}{constr_message}"
226
+ if len(fname) > 0:
227
+ with open(fname, "a") as f:
228
+ f.write(message)
229
+ else:
230
+ print(message)
231
+
232
+ # ====================#
233
+ # Calculation ends #
234
+ # ====================#
235
+
236
+
237
+ def cpenmsg(solver, iprint, cpen):
238
+ """
239
+ This function prints a message when CPEN is updated.
240
+ """
241
+
242
+ # ====================#
243
+ # Calculation starts #
244
+ # ====================#
245
+
246
+ if abs(iprint) < 2: # No printing
247
+ return
248
+ elif iprint > 0: # Print the message to the standard out.
249
+ fname = ""
250
+ else: # Print the message to a file named FNAME.
251
+ fname = f"{solver.strip()}_output.txt"
252
+
253
+ # Print the message.
254
+ if abs(iprint) >= 3:
255
+ message = f"\nSet CPEN to {cpen}"
256
+ else:
257
+ message = f"\n\nSet CPEN to {cpen}"
258
+ if len(fname) > 0:
259
+ with open(fname, "a") as f:
260
+ f.write(message)
261
+ else:
262
+ print(message)
263
+
264
+ # ====================#
265
+ # Calculation ends #
266
+ # ====================#
267
+
268
+
269
+ def fmsg(solver, state, iprint, nf, delta, f, x, cstrv=None, constr=None):
270
+ """
271
+ This subroutine prints messages for each evaluation of the objective function.
272
+ """
273
+
274
+ # ====================#
275
+ # Calculation starts #
276
+ # ====================#
277
+
278
+ if abs(iprint) < 2: # No printing
279
+ return
280
+ elif iprint > 0: # Print the message to the standard out.
281
+ fname = ""
282
+ else: # Print the message to a file named FNAME.
283
+ fname = f"{solver.strip()}_output.txt"
284
+
285
+ # Decide whether the problem is truly constrained.
286
+ if present(constr):
287
+ is_constrained = np.size(constr) > 0
288
+ else:
289
+ is_constrained = present(cstrv)
290
+
291
+ # Decide the constraint violation.
292
+ if present(cstrv):
293
+ cstrv_loc = cstrv
294
+ elif present(constr):
295
+ cstrv_loc = np.max(
296
+ np.append(0, -constr)
297
+ ) # N.B.: We assume that the constraint is CONSTR >= 0.
298
+ else:
299
+ cstrv_loc = 0
300
+
301
+ delta_message = f"\n{state} step with radius = {delta}"
302
+
303
+ if is_constrained:
304
+ nf_message = (
305
+ f"\nNumber of function values = {nf}{spaces}"
306
+ f"Least value of F = {f}{spaces}Constraint violation = {cstrv_loc}"
307
+ )
308
+ else:
309
+ nf_message = f"\nNumber of function values = {nf}{spaces}Least value of F = {f}"
310
+
311
+ if np.size(x) <= 2:
312
+ x_message = f"\nThe corresponding X is: {x}" # Printed in one line
313
+ else:
314
+ x_message = f"\nThe corresponding X is:\n{x}"
315
+
316
+ if is_constrained and present(constr):
317
+ if np.size(constr) <= 2:
318
+ constr_message = (
319
+ f"\nThe constraint value is: {constr}" # Printed in one line
320
+ )
321
+ else:
322
+ constr_message = f"\nThe constraint value is:\n{constr}"
323
+ else:
324
+ constr_message = ""
325
+
326
+ # Print the message.
327
+ message = f"{delta_message}{nf_message}{x_message}{constr_message}"
328
+ if len(fname) > 0:
329
+ with open(fname, "a") as f:
330
+ f.write(message)
331
+ else:
332
+ print(message)
333
+
334
+ # ====================#
335
+ # Calculation ends #
336
+ # ====================#
@@ -0,0 +1,131 @@
1
+ """
2
+ This module provides some Powell-style linear algebra procedures.
3
+
4
+ Translated from Zaikun Zhang's modern-Fortran reference implementation in PRIMA.
5
+
6
+ Dedicated to late Professor M. J. D. Powell FRS (1936--2015).
7
+
8
+ Python translation by Nickolai Belakovski.
9
+ """
10
+
11
+ import numpy as np
12
+
13
+ from .consts import DEBUGGING, EPS
14
+ from .linalg import hypot, inprod, isminor, matprod, planerot
15
+
16
+
17
+ def qradd_Rdiag(c, Q, Rdiag, n):
18
+ """
19
+ This function updates the QR factorization of an MxN matrix A of full column rank, attempting to
20
+ add a new column C to this matrix as the LAST column while maintaining the full-rankness.
21
+ Case 1. If C is not in range(A) (theoretically, it implies N < M), then the new matrix is np.hstack([A, C])
22
+ Case 2. If C is in range(A), then the new matrix is np.hstack([A[:, :n-1], C])
23
+ N.B.:
24
+ 0. Instead of R, this subroutine updates Rdiag, which is np.diag(R), with a size at most M and at
25
+ least min(m, n+1). The number is min(m, n+1) rather than min(m, n) as n may be augmented by 1 in
26
+ the function.
27
+ 1. With the two cases specified as above, this function does not need A as an input.
28
+ 2. The function changes only Q[:, nsave:m] (nsave is the original value of n) and
29
+ R[:, n-1] (n takes the updated value)
30
+ 3. Indeed, when C is in range(A), Powell wrote in comments that "set iOUT to the index of the
31
+ constraint (here, column of A --- Zaikun) to be deleted, but branch if no suitable index can be
32
+ found". The idea is to replace a column of A by C so that the new matrix still has full rank
33
+ (such a column must exist unless C = 0). But his code essentially sets iout=n always. Maybe he
34
+ found this worked well enough in practice. Meanwhile, Powell's code includes a snippet that can
35
+ never be reached, which was probably intended to deal with the case that IOUT != n
36
+ """
37
+ m = Q.shape[1]
38
+ nsave = n # Needed for debugging (only)
39
+
40
+ # As in Powell's COBYLA, CQ is set to 0 at the positions with CQ being negligible as per ISMINOR.
41
+ # This may not be the best choice if the subroutine is used in other contexts, e.g. LINCOA.
42
+ cq = matprod(c, Q)
43
+ cqa = matprod(abs(c), abs(Q))
44
+ # The line below basically makes an element of cq 0 if adding it to the corresponding element of
45
+ # cqa does not change the latter.
46
+ cq = np.array([0 if isminor(cqi, cqai) else cqi for cqi, cqai in zip(cq, cqa)])
47
+
48
+ # Update Q so that the columns of Q[:, n+1:m] are orthogonal to C. This is done by applying a 2D
49
+ # Givens rotation to Q[:, [k, k+1]] from the right to zero C' @ Q[:, k+1] out for K=n+1, ... m-1.
50
+ # Nothing will be done if n >= m-1
51
+ for k in range(m - 2, n - 1, -1):
52
+ if abs(cq[k + 1]) > 0:
53
+ # Powell wrote cq[k+1] != 0 instead of abs. The two differ if cq[k+1] is NaN.
54
+ # If we apply the rotation below when cq[k+1] = 0, then cq[k] will get updated to |cq[k]|.
55
+ G = planerot(cq[k : k + 2])
56
+ Q[:, [k, k + 1]] = matprod(Q[:, [k, k + 1]], G.T)
57
+ cq[k] = hypot(*cq[k : k + 2])
58
+
59
+ # Augment n by 1 if C is not in range(A)
60
+ if n < m:
61
+ # Powell's condition for the following if: cq[n+1] != 0
62
+ if abs(cq[n]) > EPS**2 and not isminor(cq[n], cqa[n]):
63
+ n += 1
64
+
65
+ # Update Rdiag so that Rdiag[n] = cq[n] = np.dot(c, q[:, n]). Note that N may be been augmented.
66
+ if n - 1 >= 0 and n - 1 < m: # n >= m should not happen unless the input is wrong
67
+ Rdiag[n - 1] = cq[n - 1]
68
+
69
+ if DEBUGGING:
70
+ assert nsave <= n <= min(nsave + 1, m)
71
+ assert n <= len(Rdiag) <= m
72
+ assert Q.shape == (m, m)
73
+
74
+ return Q, Rdiag, n
75
+
76
+
77
+ def qrexc_Rdiag(A, Q, Rdiag, i): # Used in COBYLA
78
+ """
79
+ This function updates the QR factorization for an MxN matrix A=Q@R so that the updated Q and
80
+ R form a QR factorization of [A_0, ..., A_{I-1}, A_{I+1}, ..., A_{N-1}, A_I] which is the matrix
81
+ obtained by rearranging columns [I, I+1, ... N-1] of A to [I+1, ..., N-1, I]. Here A is ASSUMED TO
82
+ BE OF FULL COLUMN RANK, Q is a matrix whose columns are orthogonal, and R, which is not present,
83
+ is an upper triangular matrix whose diagonal entries are nonzero. Q and R need not be square.
84
+ N.B.:
85
+ 0. Instead of R, this function updates Rdiag, which is np.diag(R), the size being n.
86
+ 1. With L = Q.shape[1] = R.shape[0], we have M >= L >= N. Most often L = M or N.
87
+ 2. This function changes only Q[:, i:] and Rdiag[i:]
88
+ 3. (NDB 20230919) In Python, i is either icon or nact - 2, whereas in FORTRAN it is either icon or nact - 1.
89
+ """
90
+
91
+ # Sizes
92
+ m, n = A.shape
93
+
94
+ # Preconditions
95
+ assert n >= 1 and n <= m
96
+ assert i >= 0 and i < n
97
+ assert len(Rdiag) == n
98
+ assert Q.shape[0] == m and Q.shape[1] >= n and Q.shape[1] <= m
99
+ # tol = max(1.0E-8, min(1.0E-1, 1.0E8 * EPS * m + 1))
100
+ # assert isorth(Q, tol) # Costly!
101
+
102
+ if i < 0 or i >= n:
103
+ return Q, Rdiag
104
+
105
+ # Let R be the upper triangular matrix in the QR factorization, namely R = Q.T@A.
106
+ # For each k, find the Givens rotation G with G@(R[k:k+2, :]) = [hypt, 0], and update Q[:, k:k+2]
107
+ # to Q[:, k:k+2]@(G.T). Then R = Q.T@A is an upper triangular matrix as long as A[:, [k, k+1]] is
108
+ # updated to A[:, [k+1, k]]. Indeed, this new upper triangular matrix can be obtained by first
109
+ # updating R[[k, k+1], :] to G@(R[[k, k+1], :]) and then exchanging its columns K and K+1; at the same
110
+ # time, entries k and k+1 of R's diagonal Rdiag become [hypt, -(Rdiag[k+1]/hypt)*RDiag[k]].
111
+ # After this is done for each k = 0, ..., n-2, we obtain the QR factorization of the matrix that
112
+ # rearranges columns [i, i+1, ... n-1] of A as [i+1, ..., n-1, i].
113
+ # Powell's code, however, is slightly different: before everything, he first exchanged columns k and
114
+ # k+1 of Q (as well as rows k and k+1 of R). This makes sure that the entries of the update Rdiag
115
+ # are all positive if it is the case for the original Rdiag.
116
+ for k in range(i, n - 1):
117
+ G = planerot([Rdiag[k + 1], inprod(Q[:, k], A[:, k + 1])])
118
+ Q[:, [k, k + 1]] = matprod(Q[:, [k + 1, k]], (G.T))
119
+ # Powell's code updates Rdiag in the following way:
120
+ # hypt = np.sqrt(Rdiag[k+1]**2 + np.dot(Q[:, k], A[:, k+1])**2)
121
+ # Rdiag[[k, k+1]] = [hypt, (Rdiag[k+1]/hypt)*Rdiag[k]]
122
+ # Note that Rdiag[n-1] inherits all rounding in Rdiag[i:n-1] and Q[:, i:n-1] and hence contains
123
+ # significant errors. Thus we may modify Powell's code to set only Rdiag[k] = hypt here and then
124
+ # calculate Rdiag[n] by an inner product after the loop. Nevertheless, we simple calculate RDiag
125
+ # from scratch below.
126
+
127
+ # Calculate Rdiag(i:n) from scratch
128
+ Rdiag[i : n - 1] = [inprod(Q[:, k], A[:, k + 1]) for k in range(i, n - 1)]
129
+ Rdiag[n - 1] = inprod(Q[:, n - 1], A[:, i])
130
+
131
+ return Q, Rdiag