qoro-divi 0.2.0b1__py3-none-any.whl → 0.6.0__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 (92) hide show
  1. divi/__init__.py +1 -2
  2. divi/backends/__init__.py +10 -0
  3. divi/backends/_backend_properties_conversion.py +227 -0
  4. divi/backends/_circuit_runner.py +70 -0
  5. divi/backends/_execution_result.py +70 -0
  6. divi/backends/_parallel_simulator.py +486 -0
  7. divi/backends/_qoro_service.py +663 -0
  8. divi/backends/_qpu_system.py +101 -0
  9. divi/backends/_results_processing.py +133 -0
  10. divi/circuits/__init__.py +13 -0
  11. divi/{exp/cirq → circuits/_cirq}/__init__.py +1 -2
  12. divi/circuits/_cirq/_parser.py +110 -0
  13. divi/circuits/_cirq/_qasm_export.py +78 -0
  14. divi/circuits/_core.py +391 -0
  15. divi/{qasm.py → circuits/_qasm_conversion.py} +73 -14
  16. divi/circuits/_qasm_validation.py +694 -0
  17. divi/qprog/__init__.py +27 -8
  18. divi/qprog/_expectation.py +181 -0
  19. divi/qprog/_hamiltonians.py +281 -0
  20. divi/qprog/algorithms/__init__.py +16 -0
  21. divi/qprog/algorithms/_ansatze.py +368 -0
  22. divi/qprog/algorithms/_custom_vqa.py +263 -0
  23. divi/qprog/algorithms/_pce.py +262 -0
  24. divi/qprog/algorithms/_qaoa.py +579 -0
  25. divi/qprog/algorithms/_vqe.py +262 -0
  26. divi/qprog/batch.py +387 -74
  27. divi/qprog/checkpointing.py +556 -0
  28. divi/qprog/exceptions.py +9 -0
  29. divi/qprog/optimizers.py +1014 -43
  30. divi/qprog/quantum_program.py +243 -412
  31. divi/qprog/typing.py +62 -0
  32. divi/qprog/variational_quantum_algorithm.py +1208 -0
  33. divi/qprog/workflows/__init__.py +10 -0
  34. divi/qprog/{_graph_partitioning.py → workflows/_graph_partitioning.py} +139 -95
  35. divi/qprog/workflows/_qubo_partitioning.py +221 -0
  36. divi/qprog/workflows/_vqe_sweep.py +560 -0
  37. divi/reporting/__init__.py +7 -0
  38. divi/reporting/_pbar.py +127 -0
  39. divi/reporting/_qlogger.py +68 -0
  40. divi/reporting/_reporter.py +155 -0
  41. {qoro_divi-0.2.0b1.dist-info → qoro_divi-0.6.0.dist-info}/METADATA +43 -15
  42. qoro_divi-0.6.0.dist-info/RECORD +47 -0
  43. {qoro_divi-0.2.0b1.dist-info → qoro_divi-0.6.0.dist-info}/WHEEL +1 -1
  44. qoro_divi-0.6.0.dist-info/licenses/LICENSES/.license-header +3 -0
  45. divi/_pbar.py +0 -73
  46. divi/circuits.py +0 -139
  47. divi/exp/cirq/_lexer.py +0 -126
  48. divi/exp/cirq/_parser.py +0 -889
  49. divi/exp/cirq/_qasm_export.py +0 -37
  50. divi/exp/cirq/_qasm_import.py +0 -35
  51. divi/exp/cirq/exception.py +0 -21
  52. divi/exp/scipy/_cobyla.py +0 -342
  53. divi/exp/scipy/pyprima/LICENCE.txt +0 -28
  54. divi/exp/scipy/pyprima/__init__.py +0 -263
  55. divi/exp/scipy/pyprima/cobyla/__init__.py +0 -0
  56. divi/exp/scipy/pyprima/cobyla/cobyla.py +0 -599
  57. divi/exp/scipy/pyprima/cobyla/cobylb.py +0 -849
  58. divi/exp/scipy/pyprima/cobyla/geometry.py +0 -240
  59. divi/exp/scipy/pyprima/cobyla/initialize.py +0 -269
  60. divi/exp/scipy/pyprima/cobyla/trustregion.py +0 -540
  61. divi/exp/scipy/pyprima/cobyla/update.py +0 -331
  62. divi/exp/scipy/pyprima/common/__init__.py +0 -0
  63. divi/exp/scipy/pyprima/common/_bounds.py +0 -41
  64. divi/exp/scipy/pyprima/common/_linear_constraints.py +0 -46
  65. divi/exp/scipy/pyprima/common/_nonlinear_constraints.py +0 -64
  66. divi/exp/scipy/pyprima/common/_project.py +0 -224
  67. divi/exp/scipy/pyprima/common/checkbreak.py +0 -107
  68. divi/exp/scipy/pyprima/common/consts.py +0 -48
  69. divi/exp/scipy/pyprima/common/evaluate.py +0 -101
  70. divi/exp/scipy/pyprima/common/history.py +0 -39
  71. divi/exp/scipy/pyprima/common/infos.py +0 -30
  72. divi/exp/scipy/pyprima/common/linalg.py +0 -452
  73. divi/exp/scipy/pyprima/common/message.py +0 -336
  74. divi/exp/scipy/pyprima/common/powalg.py +0 -131
  75. divi/exp/scipy/pyprima/common/preproc.py +0 -393
  76. divi/exp/scipy/pyprima/common/present.py +0 -5
  77. divi/exp/scipy/pyprima/common/ratio.py +0 -56
  78. divi/exp/scipy/pyprima/common/redrho.py +0 -49
  79. divi/exp/scipy/pyprima/common/selectx.py +0 -346
  80. divi/interfaces.py +0 -25
  81. divi/parallel_simulator.py +0 -258
  82. divi/qlogger.py +0 -119
  83. divi/qoro_service.py +0 -343
  84. divi/qprog/_mlae.py +0 -182
  85. divi/qprog/_qaoa.py +0 -440
  86. divi/qprog/_vqe.py +0 -275
  87. divi/qprog/_vqe_sweep.py +0 -144
  88. divi/utils.py +0 -116
  89. qoro_divi-0.2.0b1.dist-info/RECORD +0 -58
  90. /divi/{qem.py → circuits/qem.py} +0 -0
  91. {qoro_divi-0.2.0b1.dist-info → qoro_divi-0.6.0.dist-info/licenses}/LICENSE +0 -0
  92. {qoro_divi-0.2.0b1.dist-info → qoro_divi-0.6.0.dist-info/licenses}/LICENSES/Apache-2.0.txt +0 -0
@@ -1,540 +0,0 @@
1
- """
2
- This module provides subroutines concerning the trust-region calculations of COBYLA.
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
- import numpy.typing as npt
13
-
14
- from ..common.consts import DEBUGGING, EPS, REALMAX, REALMIN
15
- from ..common.linalg import inprod, isminor, lsqr, matprod, primasum
16
- from ..common.powalg import qradd_Rdiag, qrexc_Rdiag
17
-
18
-
19
- def trstlp(A, b, delta, g):
20
- """
21
- This function calculated an n-component vector d by the following two stages. In the first
22
- stage, d is set to the shortest vector that minimizes the greatest violation of the constraints
23
- A.T @ D <= B, K = 1, 2, 3, ..., M,
24
- subject to the Euclidean length of d being at most delta. If its length is strictly less than
25
- delta, then the second stage uses the resultant freedom in d to minimize the objective function
26
- G.T @ D
27
- subject to no increase in any greatest constraint violation.
28
-
29
- It is possible but rare that a degeneracy may prevent d from attaining the target length delta.
30
-
31
- cviol is the largest constraint violation of the current d: max(max(A.T@D - b), 0)
32
- icon is the index of a most violated constraint if cviol is positive.
33
-
34
- nact is the number of constraints in the active set and iact[0], ..., iact[nact-1] are their indices,
35
- while the remainder of the iact contains a permutation of the remaining constraint indicies.
36
- N.B.: nact <= min(num_constraints, num_vars). Obviously nact <= num_constraints. In addition, the constraints
37
- in iact[0, ..., nact-1] have linearly independent gradients (see the comments above the instruction
38
- that delete a constraint from the active set to make room for the new active constraint with index iact[icon]);
39
- it can also be seen from the update of nact: starting from 0, nact is incremented only if nact < n.
40
-
41
- Further, Z is an orthogonal matrix whose first nact columns can be regarded as the result of
42
- Gram-Schmidt applied to the active constraint gradients. For j = 0, 1, ..., nact-1, the number
43
- zdota[j] is the scalar product of the jth column of Z with the gradient of the jth active
44
- constraint. d is the current vector of variables and here the residuals of the active constraints
45
- should be zero. Further, the active constraints have nonnegative Lagrange multipliers that are
46
- held at the beginning of vmultc. The remainder of this vector holds the residuals of the inactive
47
- constraints at d, the ordering of the components of vmultc being in agreement with the permutation
48
- of the indices of the constraints that is in iact. All these residuals are nonnegative, which is
49
- achieved by the shift cviol that makes the least residual zero.
50
-
51
- N.B.:
52
- 0. In Powell's implementation, the constraints are A.T @ D >= B. In other words, the A and B in
53
- our implementation are the negative of those in Powell's implementation.
54
- 1. The algorithm was NOT documented in the COBYLA paper. A note should be written to introduce it!
55
- 2. As a major part of the algorithm (see trstlp_sub), the code maintains and updates the QR
56
- factorization of A[iact[:nact]], i.e. the gradients of all the active (linear) constraints. The
57
- matrix Z is indeed Q, and the vector zdota is the diagonal of R. The factorization is updated by
58
- Givens rotations when an index is added in or removed from iact.
59
- 3. There are probably better algorithms available for the trust-region linear programming problem.
60
- """
61
-
62
- # Sizes
63
- num_constraints = A.shape[1]
64
- num_vars = A.shape[0]
65
-
66
- # Preconditions
67
- if DEBUGGING:
68
- assert num_vars >= 1
69
- assert num_constraints >= 0
70
- assert np.size(g) == num_vars
71
- assert np.size(b) == num_constraints
72
- assert delta > 0
73
-
74
- vmultc = np.zeros(num_constraints + 1)
75
- iact = np.zeros(num_constraints + 1, dtype=int)
76
- nact = 0
77
- d = np.zeros(num_vars)
78
- z = np.zeros((num_vars, num_vars))
79
-
80
- # ==================
81
- # Calculation starts
82
- # ==================
83
-
84
- # Form A_aug and B_aug. This allows the gradient of the objective function to be regarded as the
85
- # gradient of a constraint in the second stage.
86
- A_aug = np.hstack([A, g.reshape((num_vars, 1))])
87
- b_aug = np.hstack([b, 0])
88
-
89
- # Scale the problem if A contains large values. Otherwise floating point exceptions may occur.
90
- # Note that the trust-region step is scale invariant.
91
- for i in range(
92
- num_constraints + 1
93
- ): # Note that A_aug.shape[1] == num_constraints+1
94
- if (maxval := max(abs(A_aug[:, i]))) > 1e12:
95
- modscal = max(2 * REALMIN, 1 / maxval)
96
- A_aug[:, i] *= modscal
97
- b_aug[i] *= modscal
98
-
99
- # Stage 1: minimize the 1+infinity constraint violation of the linearized constraints.
100
- iact[:num_constraints], nact, d, vmultc[:num_constraints], z = trstlp_sub(
101
- iact[:num_constraints],
102
- nact,
103
- 1,
104
- A_aug[:, :num_constraints],
105
- b_aug[:num_constraints],
106
- delta,
107
- d,
108
- vmultc[:num_constraints],
109
- z,
110
- )
111
-
112
- # Stage 2: minimize the linearized objective without increasing the 1_infinity constraint violation.
113
- iact, nact, d, vmultc, z = trstlp_sub(
114
- iact, nact, 2, A_aug, b_aug, delta, d, vmultc, z
115
- )
116
-
117
- # ================
118
- # Calculation ends
119
- # ================
120
-
121
- # Postconditions
122
- if DEBUGGING:
123
- assert all(np.isfinite(d))
124
- # Due to rounding, it may happen that ||D|| > DELTA, but ||D|| > 2*DELTA is highly improbable.
125
- assert np.linalg.norm(d) <= 2 * delta
126
-
127
- return d
128
-
129
-
130
- def trstlp_sub(iact: npt.NDArray, nact: int, stage, A, b, delta, d, vmultc, z):
131
- """
132
- This subroutine does the real calculations for trstlp, both stage 1 and stage 2.
133
- Major differences between stage 1 and stage 2:
134
- 1. Initialization. Stage 2 inherits the values of some variables from stage 1, so they are
135
- initialized in stage 1 but not in stage 2.
136
- 2. cviol. cviol is updated after at iteration in stage 1, while it remains a constant in stage2.
137
- 3. sdirn. See the definition of sdirn in the code for details.
138
- 4. optnew. The two stages have different objectives, so optnew is updated differently.
139
- 5. step. step <= cviol in stage 1.
140
- """
141
- zdasav = np.zeros(z.shape[1])
142
- vmultd = np.zeros(np.size(vmultc))
143
- zdota = np.zeros(np.size(z, 1))
144
-
145
- # Sizes
146
- mcon = np.size(A, 1)
147
- num_vars = np.size(A, 0)
148
-
149
- # Preconditions
150
- if DEBUGGING:
151
- assert num_vars >= 1
152
- assert stage == 1 or stage == 2
153
- assert (mcon >= 0 and stage == 1) or (mcon >= 1 and stage == 2)
154
- assert np.size(b) == mcon
155
- assert np.size(iact) == mcon
156
- assert np.size(vmultc) == mcon
157
- assert np.size(d) == num_vars
158
- assert np.size(z, 0) == num_vars and np.size(z, 1) == num_vars
159
- assert delta > 0
160
- if stage == 2:
161
- assert all(np.isfinite(d)) and np.linalg.norm(d) <= 2 * delta
162
- assert nact >= 0 and nact <= np.minimum(mcon, num_vars)
163
- assert all(vmultc[:mcon]) >= 0
164
- # N.B.: Stage 1 defines only VMULTC(1:M); VMULTC(M+1) is undefined!
165
-
166
- # Initialize according to stage
167
- if stage == 1:
168
- iact = np.linspace(0, mcon - 1, mcon, dtype=int)
169
- nact = 0
170
- d = np.zeros(num_vars)
171
- cviol = np.max(np.append(0, -b))
172
- vmultc = cviol + b
173
- z = np.eye(num_vars)
174
- if mcon == 0 or cviol <= 0:
175
- # Check whether a quick return is possible. Make sure the in-outputs have been initialized.
176
- return iact, nact, d, vmultc, z
177
-
178
- if all(np.isnan(b)):
179
- return iact, nact, d, vmultc, z
180
- else:
181
- icon = np.nanargmax(-b)
182
- num_constraints = mcon
183
- sdirn = np.zeros(len(d))
184
- else:
185
- if inprod(d, d) >= delta * delta:
186
- # Check whether a quick return is possible.
187
- return iact, nact, d, vmultc, z
188
-
189
- iact[mcon - 1] = mcon - 1
190
- vmultc[mcon - 1] = 0
191
- num_constraints = mcon - 1
192
- icon = mcon - 1
193
-
194
- # In Powell's code, stage 2 uses the zdota and cviol calculated by stage1. Here we recalculate
195
- # them so that they need not be passed from stage 1 to 2, and hence the coupling is reduced.
196
- cviol = np.max(
197
- np.append(0, matprod(d, A[:, :num_constraints]) - b[:num_constraints])
198
- )
199
- zdota[:nact] = [inprod(z[:, k], A[:, iact[k]]) for k in range(nact)]
200
-
201
- # More initialization
202
- optold = REALMAX
203
- nactold = nact
204
- nfail = 0
205
-
206
- # Zaikun 20211011: vmultd is computed from scratch at each iteration, but vmultc is inherited
207
-
208
- # Powell's code can encounter infinite cycling, which did happen when testing the following CUTEst
209
- # problems: DANWOODLS, GAUSS1LS, GAUSS2LS, GAUSS3LS, KOEBHELB, TAX13322, TAXR13322. Indeed, in all
210
- # these cases, Inf/NaN appear in d due to extremely large values in A (up to 10^219). To resolve
211
- # this, we set the maximal number of iterations to maxiter, and terminate if Inf/NaN occurs in d.
212
- maxiter = np.minimum(10000, 100 * max(num_constraints, num_vars))
213
- for iter in range(maxiter):
214
- if DEBUGGING:
215
- assert all(vmultc >= 0)
216
- if stage == 1:
217
- optnew = cviol
218
- else:
219
- optnew = inprod(d, A[:, mcon - 1])
220
-
221
- # End the current stage of the calculation if 3 consecutive iterations have either failed to
222
- # reduce the best calculated value of the objective function or to increase the number of active
223
- # constraints since the best value was calculated. This strategy prevents cycling, but there is
224
- # a remote possibility that it will cause premature termination.
225
- if optnew < optold or nact > nactold:
226
- nactold = nact
227
- nfail = 0
228
- else:
229
- nfail += 1
230
- optold = np.minimum(optold, optnew)
231
- if nfail == 3:
232
- break
233
-
234
- # If icon exceeds nact, then we add the constraint with index iact[icon] to the active set.
235
- if (
236
- icon >= nact
237
- ): # In Python this needs to be >= since Python is 0-indexed (in Fortran we have 1 > 0, in Python we need 0 >= 0)
238
- zdasav[:nact] = zdota[:nact]
239
- nactsav = nact
240
- z, zdota, nact = qradd_Rdiag(
241
- A[:, iact[icon]], z, zdota, nact
242
- ) # May update nact to nact+1
243
- # Indeed it suffices to pass zdota[:min(num_vars, nact+1)] to qradd as follows:
244
- # qradd(A[:, iact[icon]], z, zdota[:min(num_vars, nact+1)], nact)
245
-
246
- if nact == nactsav + 1:
247
- # N.B.: It is possible to index arrays using [nact, icon] when nact == icon.
248
- # Zaikun 20211012: Why should vmultc[nact] = 0?
249
- if nact != (icon + 1): # Need to add 1 to Python for 0 indexing
250
- vmultc[[icon, nact - 1]] = vmultc[nact - 1], 0
251
- iact[[icon, nact - 1]] = iact[[nact - 1, icon]]
252
- else:
253
- vmultc[nact - 1] = 0
254
- else:
255
- # Zaikun 20211011:
256
- # 1. VMULTD is calculated from scratch for the first time (out of 2) in one iteration.
257
- # 2. Note that IACT has not been updated to replace IACT[NACT] with IACT[ICON]. Thus
258
- # A[:, IACT[:NACT]] is the UNUPDATED version before QRADD (note Z[:, :NACT] remains the
259
- # same before and after QRADD). Therefore if we supply ZDOTA to LSQR (as Rdiag) as
260
- # Powell did, we should use the UNUPDATED version, namely ZDASAV.
261
- # vmultd[:nact] = lsqr(A[:, iact[:nact]], A[:, iact[icon]], z[:, :nact], zdasav[:nact])
262
- vmultd[:nact] = lsqr(
263
- A[:, iact[:nact]], A[:, iact[icon]], z[:, :nact], zdasav[:nact]
264
- )
265
- if not any(
266
- np.logical_and(vmultd[:nact] > 0, iact[:nact] <= num_constraints)
267
- ):
268
- # N.B.: This can be triggered by NACT == 0 (among other possibilities)! This is
269
- # important, because NACT will be used as an index in the sequel.
270
- break
271
- # vmultd[NACT+1:mcon] is not used, but we have to initialize it in Fortran, or compilers
272
- # complain about the where construct below (another solution: restrict where to 1:NACT).
273
- vmultd[nact:mcon] = -1 # len(vmultd) == mcon
274
-
275
- # Revise the Lagrange multipliers. The revision is not applicable to vmultc[nact:num_constraints].
276
- fracmult = [
277
- (
278
- vmultc[i] / vmultd[i]
279
- if vmultd[i] > 0 and iact[i] <= num_constraints
280
- else REALMAX
281
- )
282
- for i in range(nact)
283
- ]
284
- # Only the places with vmultd > 0 and iact <= m is relevant below, if any.
285
- frac = min(fracmult[:nact]) # fracmult[nact:mcon] may contain garbage
286
- vmultc[:nact] = np.maximum(
287
- np.zeros(len(vmultc[:nact])), vmultc[:nact] - frac * vmultd[:nact]
288
- )
289
-
290
- # Reorder the active constraints so that the one to be replaced is at the end of the list.
291
- # Exit if the new value of zdota[nact] is not acceptable. Powell's condition for the
292
- # following If: not abs(zdota[nact]) > 0. Note that it is different from
293
- # 'abs(zdota[nact]) <=0)' as zdota[nact] can be NaN.
294
- # N.B.: We cannot arrive here with nact == 0, which should have triggered a break above
295
- if np.isnan(zdota[nact - 1]) or abs(zdota[nact - 1]) <= EPS**2:
296
- break
297
- vmultc[[icon, nact - 1]] = (
298
- 0,
299
- frac,
300
- ) # vmultc[[icon, nact]] is valid as icon > nact
301
- iact[[icon, nact - 1]] = iact[[nact - 1, icon]]
302
- # end if nact == nactsav + 1
303
-
304
- # In stage 2, ensure that the objective continues to be treated as the last active constraint.
305
- # Zaikun 20211011, 20211111: Is it guaranteed for stage 2 that iact[nact-1] = mcon when
306
- # iact[nact] != mcon??? If not, then how does the following procedure ensure that mcon is
307
- # the last of iact[:nact]?
308
- if stage == 2 and iact[nact - 1] != (mcon - 1):
309
- if nact <= 1:
310
- # We must exit, as nact-2 is used as an index below. Powell's code does not have this.
311
- break
312
- z, zdota[:nact] = qrexc_Rdiag(
313
- A[:, iact[:nact]], z, zdota[:nact], nact - 2
314
- ) # We pass nact-2 in Python instead of nact-1
315
- # Indeed, it suffices to pass Z[:, :nact] to qrexc as follows:
316
- # z[:, :nact], zdota[:nact] = qrexc(A[:, iact[:nact]], z[:, :nact], zdota[:nact], nact - 1)
317
- iact[[nact - 2, nact - 1]] = iact[[nact - 1, nact - 2]]
318
- vmultc[[nact - 2, nact - 1]] = vmultc[[nact - 1, nact - 2]]
319
- # Zaikun 20211117: It turns out that the last few lines do not guarantee iact[nact] == num_vars in
320
- # stage 2; the following test cannot be passed. IS THIS A BUG?!
321
- # assert iact[nact] == mcon or stage == 1, 'iact[nact] must == mcon in stage 2'
322
-
323
- # Powell's code does not have the following. It avoids subsequent floating points exceptions.
324
- if np.isnan(zdota[nact - 1]) or abs(zdota[nact - 1]) <= EPS**2:
325
- break
326
-
327
- # Set sdirn to the direction of the next change to the current vector of variables
328
- # Usually during stage 1 the vector sdirn gives a search direction that reduces all the
329
- # active constraint violations by one simultaneously.
330
- if stage == 1:
331
- sdirn -= (
332
- (inprod(sdirn, A[:, iact[nact - 1]]) + 1) / zdota[nact - 1]
333
- ) * z[:, nact - 1]
334
- else:
335
- sdirn = -1 / zdota[nact - 1] * z[:, nact - 1]
336
- else: # icon < nact
337
- # Delete the constraint with the index iact[icon] from the active set, which is done by
338
- # reordering iact[icon:nact] into [iact[icon+1:nact], iact[icon]] and then reduce nact to
339
- # nact - 1. In theory, icon > 0.
340
- # assert icon > 0, "icon > 0 is required" # For Python I think this is irrelevant
341
- z, zdota[:nact] = qrexc_Rdiag(
342
- A[:, iact[:nact]], z, zdota[:nact], icon
343
- ) # qrexc does nothing if icon == nact
344
- # Indeed, it suffices to pass Z[:, :nact] to qrexc as follows:
345
- # z[:, :nact], zdota[:nact] = qrexc(A[:, iact[:nact]], z[:, :nact], zdota[:nact], icon)
346
- iact[icon:nact] = [*iact[icon + 1 : nact], iact[icon]]
347
- vmultc[icon:nact] = [*vmultc[icon + 1 : nact], vmultc[icon]]
348
- nact -= 1
349
-
350
- # Powell's code does not have the following. It avoids subsequent exceptions.
351
- # Zaikun 20221212: In theory, nact > 0 in stage 2, as the objective function should always
352
- # be considered as an "active constraint" --- more precisely, iact[nact] = mcon. However,
353
- # looking at the code, I cannot see why in stage 2 nact must be positive after the reduction
354
- # above. It did happen in stage 1 that nact became 0 after the reduction --- this is
355
- # extremely rare, and it was never observed until 20221212, after almost one year of
356
- # random tests. Maybe nact is theoretically positive even in stage 1?
357
- if stage == 2 and nact < 0:
358
- break # If this case ever occurs, we have to break, as nact is used as an index below.
359
- if nact > 0:
360
- if np.isnan(zdota[nact - 1]) or abs(zdota[nact - 1]) <= EPS**2:
361
- break
362
-
363
- # Set sdirn to the direction of the next change to the current vector of variables.
364
- if stage == 1:
365
- sdirn -= inprod(sdirn, z[:, nact]) * z[:, nact]
366
- # sdirn is orthogonal to z[:, nact+1]
367
- else:
368
- sdirn = -1 / zdota[nact - 1] * z[:, nact - 1]
369
- # end if icon > nact
370
-
371
- # Calculate the step to the trust region boundary or take the step that reduces cviol to 0.
372
- # ----------------------------------------------------------------------------------------- #
373
- # The following calculation of step is adopted from NEWUOA/BOBYQA/LINCOA. It seems to improve
374
- # the performance of COBYLA. We also found that removing the precaution about underflows is
375
- # beneficial to the overall performance of COBYLA --- the underflows are harmless anyway.
376
- dd = delta * delta - inprod(d, d)
377
- ss = inprod(sdirn, sdirn)
378
- sd = inprod(sdirn, d)
379
- if dd <= 0 or ss <= EPS * delta * delta or np.isnan(sd):
380
- break
381
- # sqrtd: square root of a discriminant. The max avoids sqrtd < abs(sd) due to underflow
382
- sqrtd = max(np.sqrt(ss * dd + sd * sd), abs(sd), np.sqrt(ss * dd))
383
- if sd > 0:
384
- step = dd / (sqrtd + sd)
385
- else:
386
- step = (sqrtd - sd) / ss
387
- # step < 0 should not happen. Step can be 0 or NaN when, e.g., sd or ss becomes inf
388
- if step <= 0 or not np.isfinite(step):
389
- break
390
-
391
- # Powell's approach and comments are as follows.
392
- # -------------------------------------------------- #
393
- # The two statements below that include the factor eps prevent
394
- # some harmless underflows that occurred in a test calculation
395
- # (Zaikun: here, eps is the machine epsilon; Powell's original
396
- # code used 1.0e-6, and Powell's code was written in single
397
- # precision). Further, we skip the step if it could be 0 within
398
- # a reasonable tolerance for computer rounding errors.
399
-
400
- # !dd = delta*delta - sum(d**2, mask=(abs(d) >= EPS * delta))
401
- # !ss = inprod(sdirn, sdirn)
402
- # !if (dd <= 0) then
403
- # ! exit
404
- # !end if
405
- # !sd = inprod(sdirn, d)
406
- # !if (abs(sd) >= EPS * sqrt(ss * dd)) then
407
- # ! step = dd / (sqrt(ss * dd + sd*sd) + sd)
408
- # !else
409
- # ! step = dd / (sqrt(ss * dd) + sd)
410
- # !end if
411
- # -------------------------------------------------- #
412
-
413
- if stage == 1:
414
- if isminor(cviol, step):
415
- break
416
- step = min(step, cviol)
417
-
418
- # Set dnew to the new variables if step is the steplength, and reduce cviol to the corresponding
419
- # maximum residual if stage 1 is being done
420
- dnew = d + step * sdirn
421
- if stage == 1:
422
- cviol = np.max(
423
- np.append(0, matprod(dnew, A[:, iact[:nact]]) - b[iact[:nact]])
424
- )
425
- # N.B.: cviol will be used when calculating vmultd[nact+1:mcon].
426
-
427
- # Zaikun 20211011:
428
- # 1. vmultd is computed from scratch for the second (out of 2) time in one iteration.
429
- # 2. vmultd[:nact] and vmultd[nact:mcon] are calculated separately with no coupling.
430
- # 3. vmultd will be calculated from scratch again in the next iteration.
431
- # Set vmultd to the vmultc vector that would occur if d became dnew. A device is included to
432
- # force vmultd[k] = 0 if deviations from this value can be attributed to computer rounding
433
- # errors. First calculate the new Lagrange multipliers.
434
- vmultd[:nact] = -lsqr(A[:, iact[:nact]], dnew, z[:, :nact], zdota[:nact])
435
- if stage == 2:
436
- vmultd[nact - 1] = max(0, vmultd[nact - 1]) # This seems never activated.
437
- # Complete vmultd by finding the new constraint residuals. (Powell wrote "Complete vmultc ...")
438
- cvshift = cviol - (
439
- matprod(dnew, A[:, iact]) - b[iact]
440
- ) # Only cvshift[nact+1:mcon] is needed
441
- cvsabs = matprod(abs(dnew), abs(A[:, iact])) + abs(b[iact]) + cviol
442
- cvshift[isminor(cvshift, cvsabs)] = 0
443
- vmultd[nact:mcon] = cvshift[nact:mcon]
444
-
445
- # Calculate the fraction of the step from d to dnew that will be taken
446
- fracmult = [
447
- vmultc[i] / (vmultc[i] - vmultd[i]) if vmultd[i] < 0 else REALMAX
448
- for i in range(len(vmultd))
449
- ]
450
- # Only the places with vmultd < 0 are relevant below, if any.
451
- icon = np.argmin(np.append(1, fracmult)) - 1
452
- frac = min(np.append(1, fracmult))
453
-
454
- # Update d, vmultc, and cviol
455
- dold = d
456
- d = (1 - frac) * d + frac * dnew
457
- vmultc = np.maximum(0, (1 - frac) * vmultc + frac * vmultd)
458
- # Break in the case of inf/nan in d or vmultc.
459
- if not (np.isfinite(primasum(abs(d))) and np.isfinite(primasum(abs(vmultc)))):
460
- d = dold # Should we restore also iact, nact, vmultc, and z?
461
- break
462
-
463
- if stage == 1:
464
- # cviol = (1 - frac) * cvold + frac * cviol # Powell's version
465
- # In theory, cviol = np.max(np.append(d@A - b, 0)), yet the
466
- # cviol updated as above can be quite different from this value if A has huge entries (e.g., > 1e20)
467
- cviol = np.max(np.append(0, matprod(d, A) - b))
468
-
469
- if icon < 0 or icon >= mcon:
470
- # In Powell's code, the condition is icon == 0. Indeed, icon < 0 cannot hold unless
471
- # fracmult contains only nan, which should not happen; icon >= mcon should never occur.
472
- break
473
-
474
- # ==================#
475
- # Calculation ends #
476
- # ==================#
477
-
478
- # Postconditions
479
- if DEBUGGING:
480
- assert np.size(iact) == mcon
481
- assert np.size(vmultc) == mcon
482
- assert all(vmultc >= 0)
483
- assert np.size(d) == num_vars
484
- assert all(np.isfinite(d))
485
- assert np.linalg.norm(d) <= 2 * delta
486
- assert np.size(z, 0) == num_vars and np.size(z, 1) == num_vars
487
- assert nact >= 0 and nact <= np.minimum(mcon, num_vars)
488
-
489
- return iact, nact, d, vmultc, z
490
-
491
-
492
- def trrad(delta_in, dnorm, eta1, eta2, gamma1, gamma2, ratio):
493
- """
494
- This function updates the trust region radius according to RATIO and DNORM.
495
- """
496
-
497
- # Preconditions
498
- if DEBUGGING:
499
- assert delta_in >= dnorm > 0
500
- assert 0 <= eta1 <= eta2 < 1
501
- assert 0 < gamma1 < 1 < gamma2
502
- # By the definition of RATIO in ratio.f90, RATIO cannot be NaN unless the
503
- # actual reduction is NaN, which should NOT happen due to the moderated extreme
504
- # barrier.
505
- assert not np.isnan(ratio)
506
-
507
- # ====================#
508
- # Calculation starts #
509
- # ====================#
510
-
511
- if ratio <= eta1:
512
- delta = gamma1 * dnorm # Powell's UOBYQA/NEWUOA
513
- # delta = gamma1 * delta_in # Powell's COBYLA/LINCOA
514
- # delta = min(gamma1 * delta_in, dnorm) # Powell's BOBYQA
515
- elif ratio <= eta2:
516
- delta = max(gamma1 * delta_in, dnorm) # Powell's UOBYQA/NEWUOA/BOBYQA/LINCOA
517
- else:
518
- delta = max(gamma1 * delta_in, gamma2 * dnorm) # Powell's NEWUOA/BOBYQA
519
- # delta = max(delta_in, gamma2 * dnorm) # Modified version. Works well for UOBYQA
520
- # For noise-free CUTEst problems of <= 100 variables, Powell's version works slightly better
521
- # than the modified one.
522
- # delta = max(delta_in, 1.25*dnorm, dnorm + rho) # Powell's UOBYQA
523
- # delta = min(max(gamma1 * delta_in, gamma2 * dnorm), gamma3 * delta_in) # Powell's LINCOA, gamma3 = np.sqrt(2)
524
-
525
- # For noisy problems, the following may work better.
526
- # if ratio <= eta1:
527
- # delta = gamma1 * dnorm
528
- # elseif ratio <= eta2: # Ensure DELTA >= DELTA_IN
529
- # delta = delta_in
530
- # else: # Ensure DELTA > DELTA_IN with a constant factor
531
- # delta = max(delta_in * (1 + gamma2) / 2, gamma2 * dnorm)
532
-
533
- # ==================#
534
- # Calculation ends #
535
- # ==================#
536
-
537
- # Postconditions
538
- if DEBUGGING:
539
- assert delta > 0
540
- return delta