ltbams 0.9.9__py3-none-any.whl → 1.0.2a1__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 (191) hide show
  1. ams/__init__.py +4 -11
  2. ams/_version.py +3 -3
  3. ams/cases/5bus/pjm5bus_demo.xlsx +0 -0
  4. ams/cases/5bus/pjm5bus_jumper.xlsx +0 -0
  5. ams/cases/5bus/pjm5bus_uced.json +1062 -0
  6. ams/cases/5bus/pjm5bus_uced.xlsx +0 -0
  7. ams/cases/5bus/pjm5bus_uced_esd1.xlsx +0 -0
  8. ams/cases/5bus/pjm5bus_uced_ev.xlsx +0 -0
  9. ams/cases/ieee123/ieee123.xlsx +0 -0
  10. ams/cases/ieee123/ieee123_regcv1.xlsx +0 -0
  11. ams/cases/ieee14/ieee14.json +1166 -0
  12. ams/cases/ieee14/ieee14.raw +92 -0
  13. ams/cases/ieee14/ieee14_conn.xlsx +0 -0
  14. ams/cases/ieee14/ieee14_uced.xlsx +0 -0
  15. ams/cases/ieee39/ieee39.xlsx +0 -0
  16. ams/cases/ieee39/ieee39_uced.xlsx +0 -0
  17. ams/cases/ieee39/ieee39_uced_esd1.xlsx +0 -0
  18. ams/cases/ieee39/ieee39_uced_pvd1.xlsx +0 -0
  19. ams/cases/ieee39/ieee39_uced_vis.xlsx +0 -0
  20. ams/cases/matpower/benchmark.json +1594 -0
  21. ams/cases/matpower/case118.m +787 -0
  22. ams/cases/matpower/case14.m +129 -0
  23. ams/cases/matpower/case300.m +1315 -0
  24. ams/cases/matpower/case39.m +205 -0
  25. ams/cases/matpower/case5.m +62 -0
  26. ams/cases/matpower/case_ACTIVSg2000.m +9460 -0
  27. ams/cases/npcc/npcc.m +644 -0
  28. ams/cases/npcc/npcc_uced.xlsx +0 -0
  29. ams/cases/pglib/pglib_opf_case39_epri__api.m +243 -0
  30. ams/cases/wecc/wecc.m +714 -0
  31. ams/cases/wecc/wecc_uced.xlsx +0 -0
  32. ams/cli.py +6 -0
  33. ams/core/__init__.py +2 -0
  34. ams/core/documenter.py +652 -0
  35. ams/core/matprocessor.py +782 -0
  36. ams/core/model.py +330 -0
  37. ams/core/param.py +322 -0
  38. ams/core/service.py +918 -0
  39. ams/core/symprocessor.py +224 -0
  40. ams/core/var.py +59 -0
  41. ams/extension/__init__.py +5 -0
  42. ams/extension/eva.py +401 -0
  43. ams/interface.py +1085 -0
  44. ams/io/__init__.py +133 -0
  45. ams/io/json.py +82 -0
  46. ams/io/matpower.py +406 -0
  47. ams/io/psse.py +6 -0
  48. ams/io/pypower.py +103 -0
  49. ams/io/xlsx.py +80 -0
  50. ams/main.py +81 -4
  51. ams/models/__init__.py +24 -0
  52. ams/models/area.py +40 -0
  53. ams/models/bus.py +52 -0
  54. ams/models/cost.py +169 -0
  55. ams/models/distributed/__init__.py +3 -0
  56. ams/models/distributed/esd1.py +71 -0
  57. ams/models/distributed/ev.py +60 -0
  58. ams/models/distributed/pvd1.py +67 -0
  59. ams/models/group.py +231 -0
  60. ams/models/info.py +26 -0
  61. ams/models/line.py +238 -0
  62. ams/models/renewable/__init__.py +5 -0
  63. ams/models/renewable/regc.py +119 -0
  64. ams/models/reserve.py +94 -0
  65. ams/models/shunt.py +14 -0
  66. ams/models/static/__init__.py +2 -0
  67. ams/models/static/gen.py +165 -0
  68. ams/models/static/pq.py +61 -0
  69. ams/models/timeslot.py +69 -0
  70. ams/models/zone.py +49 -0
  71. ams/opt/__init__.py +12 -0
  72. ams/opt/constraint.py +175 -0
  73. ams/opt/exprcalc.py +127 -0
  74. ams/opt/expression.py +188 -0
  75. ams/opt/objective.py +174 -0
  76. ams/opt/omodel.py +432 -0
  77. ams/opt/optzbase.py +192 -0
  78. ams/opt/param.py +156 -0
  79. ams/opt/var.py +233 -0
  80. ams/pypower/__init__.py +8 -0
  81. ams/pypower/_compat.py +9 -0
  82. ams/pypower/core/__init__.py +8 -0
  83. ams/pypower/core/pips.py +894 -0
  84. ams/pypower/core/ppoption.py +244 -0
  85. ams/pypower/core/ppver.py +18 -0
  86. ams/pypower/core/solver.py +2451 -0
  87. ams/pypower/eps.py +6 -0
  88. ams/pypower/idx.py +174 -0
  89. ams/pypower/io.py +604 -0
  90. ams/pypower/make/__init__.py +11 -0
  91. ams/pypower/make/matrices.py +665 -0
  92. ams/pypower/make/pdv.py +506 -0
  93. ams/pypower/routines/__init__.py +7 -0
  94. ams/pypower/routines/cpf.py +513 -0
  95. ams/pypower/routines/cpf_callbacks.py +114 -0
  96. ams/pypower/routines/opf.py +1803 -0
  97. ams/pypower/routines/opffcns.py +1946 -0
  98. ams/pypower/routines/pflow.py +852 -0
  99. ams/pypower/toggle.py +1098 -0
  100. ams/pypower/utils.py +293 -0
  101. ams/report.py +212 -50
  102. ams/routines/__init__.py +23 -0
  103. ams/routines/acopf.py +117 -0
  104. ams/routines/cpf.py +65 -0
  105. ams/routines/dcopf.py +241 -0
  106. ams/routines/dcpf.py +209 -0
  107. ams/routines/dcpf0.py +196 -0
  108. ams/routines/dopf.py +150 -0
  109. ams/routines/ed.py +312 -0
  110. ams/routines/pflow.py +255 -0
  111. ams/routines/pflow0.py +113 -0
  112. ams/routines/routine.py +1033 -0
  113. ams/routines/rted.py +519 -0
  114. ams/routines/type.py +160 -0
  115. ams/routines/uc.py +376 -0
  116. ams/shared.py +63 -9
  117. ams/system.py +61 -22
  118. ams/utils/__init__.py +3 -0
  119. ams/utils/misc.py +77 -0
  120. ams/utils/paths.py +257 -0
  121. docs/Makefile +21 -0
  122. docs/make.bat +35 -0
  123. docs/source/_templates/autosummary/base.rst +5 -0
  124. docs/source/_templates/autosummary/class.rst +35 -0
  125. docs/source/_templates/autosummary/module.rst +65 -0
  126. docs/source/_templates/autosummary/module_toctree.rst +66 -0
  127. docs/source/api.rst +102 -0
  128. docs/source/conf.py +203 -0
  129. docs/source/examples/index.rst +34 -0
  130. docs/source/genmodelref.py +61 -0
  131. docs/source/genroutineref.py +47 -0
  132. docs/source/getting_started/copyright.rst +20 -0
  133. docs/source/getting_started/formats/index.rst +20 -0
  134. docs/source/getting_started/formats/matpower.rst +183 -0
  135. docs/source/getting_started/formats/psse.rst +46 -0
  136. docs/source/getting_started/formats/pypower.rst +223 -0
  137. docs/source/getting_started/formats/xlsx.png +0 -0
  138. docs/source/getting_started/formats/xlsx.rst +23 -0
  139. docs/source/getting_started/index.rst +76 -0
  140. docs/source/getting_started/install.rst +234 -0
  141. docs/source/getting_started/overview.rst +26 -0
  142. docs/source/getting_started/testcase.rst +45 -0
  143. docs/source/getting_started/verification.rst +13 -0
  144. docs/source/images/curent.ico +0 -0
  145. docs/source/images/dcopf_time.png +0 -0
  146. docs/source/images/sponsors/CURENT_Logo_NameOnTrans.png +0 -0
  147. docs/source/images/sponsors/CURENT_Logo_Transparent.png +0 -0
  148. docs/source/images/sponsors/CURENT_Logo_Transparent_Name.png +0 -0
  149. docs/source/images/sponsors/doe.png +0 -0
  150. docs/source/index.rst +108 -0
  151. docs/source/modeling/example.rst +159 -0
  152. docs/source/modeling/index.rst +17 -0
  153. docs/source/modeling/model.rst +210 -0
  154. docs/source/modeling/routine.rst +122 -0
  155. docs/source/modeling/system.rst +51 -0
  156. docs/source/release-notes.rst +398 -0
  157. ltbams-1.0.2a1.dist-info/METADATA +210 -0
  158. ltbams-1.0.2a1.dist-info/RECORD +188 -0
  159. {ltbams-0.9.9.dist-info → ltbams-1.0.2a1.dist-info}/WHEEL +1 -1
  160. ltbams-1.0.2a1.dist-info/top_level.txt +3 -0
  161. tests/__init__.py +0 -0
  162. tests/test_1st_system.py +33 -0
  163. tests/test_addressing.py +40 -0
  164. tests/test_andes_mats.py +61 -0
  165. tests/test_case.py +266 -0
  166. tests/test_cli.py +34 -0
  167. tests/test_export_csv.py +89 -0
  168. tests/test_group.py +83 -0
  169. tests/test_interface.py +216 -0
  170. tests/test_io.py +32 -0
  171. tests/test_jumper.py +27 -0
  172. tests/test_known_good.py +267 -0
  173. tests/test_matp.py +437 -0
  174. tests/test_model.py +54 -0
  175. tests/test_omodel.py +119 -0
  176. tests/test_paths.py +22 -0
  177. tests/test_report.py +251 -0
  178. tests/test_repr.py +21 -0
  179. tests/test_routine.py +178 -0
  180. tests/test_rtn_dcopf.py +101 -0
  181. tests/test_rtn_dcpf.py +77 -0
  182. tests/test_rtn_ed.py +279 -0
  183. tests/test_rtn_pflow.py +219 -0
  184. tests/test_rtn_rted.py +273 -0
  185. tests/test_rtn_uc.py +248 -0
  186. tests/test_service.py +73 -0
  187. ltbams-0.9.9.dist-info/LICENSE +0 -692
  188. ltbams-0.9.9.dist-info/METADATA +0 -859
  189. ltbams-0.9.9.dist-info/RECORD +0 -14
  190. ltbams-0.9.9.dist-info/top_level.txt +0 -1
  191. {ltbams-0.9.9.dist-info → ltbams-1.0.2a1.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,2451 @@
1
+ """
2
+ PYPOWER solver interface.
3
+ """
4
+ import logging
5
+ from functools import wraps
6
+ import re
7
+
8
+ import numpy as np
9
+ from numpy import flatnonzero as find
10
+
11
+ import scipy.sparse as sp
12
+ from scipy.sparse import csr_matrix as c_sparse
13
+
14
+ from andes.shared import rad2deg, deg2rad
15
+
16
+ from ams.shared import inf, nan
17
+
18
+ from ams.pypower.core.pips import pips
19
+ from ams.pypower.make import makeYbus
20
+ import ams.pypower.utils as putils
21
+ from ams.pypower.utils import IDX
22
+ from ams.pypower.routines.opffcns import opf_costfcn, opf_consfcn, opf_hessfcn
23
+
24
+
25
+ logger = logging.getLogger(__name__)
26
+
27
+
28
+ def require_mosek(f):
29
+ """
30
+ Decorator for functions that require mosek.
31
+ """
32
+
33
+ @wraps(f)
34
+ def wrapper(*args, **kwds):
35
+ try:
36
+ from pymosek import mosekopt # NOQA
37
+ except ImportError:
38
+ raise ModuleNotFoundError("Package `pymosek` needs to be manually installed.")
39
+
40
+ return f(*args, **kwds)
41
+
42
+ return wrapper
43
+
44
+
45
+ def require_cplex(f):
46
+ """
47
+ Decorator for functions that require cplex.
48
+ """
49
+
50
+ @wraps(f)
51
+ def wrapper(*args, **kwds):
52
+ try:
53
+ from cplex import Cplex, cplexlp, cplexqp, cplexoptimset # NOQA
54
+ except ImportError:
55
+ raise ModuleNotFoundError("Package `cplex` needs to be manually installed.")
56
+
57
+ return f(*args, **kwds)
58
+
59
+ return wrapper
60
+
61
+
62
+ def require_gurobi(f):
63
+ """
64
+ Decorator for functions that require gurobi.
65
+ """
66
+
67
+ @wraps(f)
68
+ def wrapper(*args, **kwds):
69
+ try:
70
+ from gurobipy import Model, GRB # NOQA
71
+ except ImportError:
72
+ raise ModuleNotFoundError("Package `gurobipy` needs to be manually installed.")
73
+
74
+ return f(*args, **kwds)
75
+
76
+ return wrapper
77
+
78
+
79
+ def require_ipopt(f):
80
+ """
81
+ Decorator for functions that require ipopt.
82
+ """
83
+
84
+ @wraps(f)
85
+ def wrapper(*args, **kwds):
86
+ try:
87
+ import pyipopt # NOQA
88
+ except ImportError:
89
+ raise ModuleNotFoundError("Package `pyipopt` needs to be manually installed.")
90
+
91
+ return f(*args, **kwds)
92
+
93
+ return wrapper
94
+
95
+
96
+ @require_ipopt
97
+ def ipoptopf_solver(om, ppopt):
98
+ """
99
+ Solves AC optimal power flow using IPOPT.
100
+
101
+ Inputs are an OPF model object and a PYPOWER options vector.
102
+
103
+ Outputs are a C{results} dict, C{success} flag and C{raw} output dict.
104
+
105
+ C{results} is a PYPOWER case dict (ppc) with the usual C{baseMVA}, C{bus}
106
+ C{branch}, C{gen}, C{gencost} fields, along with the following additional
107
+ fields:
108
+ - C{order} see 'help ext2int' for details of this field
109
+ - C{x} final value of optimization variables (internal order)
110
+ - C{f} final objective function value
111
+ - C{mu} shadow prices on ...
112
+ - C{var}
113
+ - C{l} lower bounds on variables
114
+ - C{u} upper bounds on variables
115
+ - C{nln}
116
+ - C{l} lower bounds on nonlinear constraints
117
+ - C{u} upper bounds on nonlinear constraints
118
+ - C{lin}
119
+ - C{l} lower bounds on linear constraints
120
+ - C{u} upper bounds on linear constraints
121
+
122
+ C{success} is C{True} if solver converged successfully, C{False} otherwise
123
+
124
+ C{raw} is a raw output dict in form returned by MINOS
125
+ - C{xr} final value of optimization variables
126
+ - C{pimul} constraint multipliers
127
+ - C{info} solver specific termination code
128
+ - C{output} solver specific output information
129
+
130
+ @see: L{opf}, L{pips}
131
+
132
+ @author: Ray Zimmerman (PSERC Cornell)
133
+ @author: Carlos E. Murillo-Sanchez (PSERC Cornell & Universidad
134
+ Autonoma de Manizales)
135
+ """
136
+ # unpack data
137
+ ppc = om.get_ppc()
138
+ baseMVA, bus, gen, branch, gencost = \
139
+ ppc['baseMVA'], ppc['bus'], ppc['gen'], ppc['branch'], ppc['gencost']
140
+ vv, _, nn, _ = om.get_idx()
141
+
142
+ # problem dimensions
143
+ nb = np.shape(bus)[0] # number of buses
144
+ ng = np.shape(gen)[0] # number of gens
145
+ nl = np.shape(branch)[0] # number of branches
146
+ ny = om.getN('var', 'y') # number of piece-wise linear costs
147
+
148
+ # linear constraints
149
+ A, l, u = om.linear_constraints()
150
+
151
+ # bounds on optimization vars
152
+ _, xmin, xmax = om.getv()
153
+
154
+ # build admittance matrices
155
+ Ybus, Yf, Yt = makeYbus(baseMVA, bus, branch)
156
+
157
+ # try to select an interior initial point
158
+ ll = xmin.copy()
159
+ uu = xmax.copy()
160
+ ll[xmin == -inf] = -2e19 # replace Inf with numerical proxies
161
+ uu[xmax == inf] = 2e19
162
+ x0 = (ll + uu) / 2
163
+ Varefs = bus[bus[:, IDX.bus.BUS_TYPE] == IDX.bus.REF, IDX.bus.VA] * deg2rad
164
+ x0[vv['i1']['Va']:vv['iN']['Va']] = Varefs[0] # angles set to first reference angle
165
+ if ny > 0:
166
+ ipwl = find(gencost[:, IDX.cost.MODEL] == IDX.cost.PW_LINEAR)
167
+ # PQ = np.r_[gen[:, PMAX], gen[:, QMAX]]
168
+ # c = totcost(gencost[ipwl, :], PQ[ipwl])
169
+ # largest y-value in CCV data
170
+ c = gencost.flatten('F')[putils.sub2ind(np.shape(gencost), ipwl,
171
+ IDX.cost.NCOST + 2 * gencost[ipwl, IDX.cost.NCOST])]
172
+ x0[vv['i1']['y']:vv['iN']['y']] = max(c) + 0.1 * np.abs(max(c))
173
+ # x0[vv['i1']['y']:vv['iN']['y']) = c + 0.1 * np.abs(c)
174
+
175
+ # find branches with flow limits
176
+ il = find((branch[:, IDX.branch.RATE_A] != 0) & (branch[:, IDX.branch.RATE_A] < 1e10))
177
+ nl2 = len(il) # number of constrained lines
178
+
179
+ # ----- run opf -----
180
+ # build Jacobian and Hessian structure
181
+ if A is not None and sp.issparse(A):
182
+ nA = A.shape[0] # number of original linear constraints
183
+ else:
184
+ nA = 0
185
+ nx = len(x0)
186
+ f = branch[:, IDX.branch.F_BUS] # list of "from" buses
187
+ t = branch[:, IDX.branch.T_BUS] # list of "to" buses
188
+ Cf = c_sparse((np.ones(nl), (np.arange(nl), f)), (nl, nb)) # connection matrix for line & from buses
189
+ Ct = c_sparse((np.ones(nl), (np.arange(nl), t)), (nl, nb)) # connection matrix for line & to buses
190
+ Cl = Cf + Ct
191
+ Cb = Cl.T * Cl + sp.eye(nb, nb)
192
+ Cl2 = Cl[il, :]
193
+ Cg = c_sparse((np.ones(ng), (gen[:, IDX.gen.GEN_BUS], np.arange(ng))), (nb, ng))
194
+ nz = nx - 2 * (nb + ng)
195
+ nxtra = nx - 2 * nb
196
+ if nz > 0:
197
+ Js = sp.vstack([
198
+ sp.hstack([Cb, Cb, Cg, c_sparse((nb, ng)), c_sparse((nb, nz))]),
199
+ sp.hstack([Cb, Cb, c_sparse((nb, ng)), Cg, c_sparse((nb, nz))]),
200
+ sp.hstack([Cl2, Cl2, c_sparse((nl2, 2 * ng)), c_sparse((nl2, nz))]),
201
+ sp.hstack([Cl2, Cl2, c_sparse((nl2, 2 * ng)), c_sparse((nl2, nz))])
202
+ ], 'coo')
203
+ else:
204
+ Js = sp.vstack([
205
+ sp.hstack([Cb, Cb, Cg, c_sparse((nb, ng))]),
206
+ sp.hstack([Cb, Cb, c_sparse((nb, ng)), Cg,]),
207
+ sp.hstack([Cl2, Cl2, c_sparse((nl2, 2 * ng)),]),
208
+ sp.hstack([Cl2, Cl2, c_sparse((nl2, 2 * ng)),])
209
+ ], 'coo')
210
+
211
+ if A is not None and sp.issparse(A):
212
+ Js = sp.vstack([Js, A], 'coo')
213
+
214
+ f, _, d2f = opf_costfcn(x0, om, True)
215
+ Hs = sp.tril(d2f + sp.vstack([
216
+ sp.hstack([Cb, Cb, c_sparse((nb, nxtra))]),
217
+ sp.hstack([Cb, Cb, c_sparse((nb, nxtra))]),
218
+ c_sparse((nxtra, nx))
219
+ ]), format='coo')
220
+
221
+ # set options struct for IPOPT
222
+ # options = {}
223
+ # options['ipopt'] = ipopt_options([], ppopt)
224
+
225
+ # extra data to pass to functions
226
+ userdata = dict(om=om, Ybus=Ybus, Yf=Yf, Yt=Yt, ppopt=ppopt,
227
+ il=il, A=A, nA=nA,
228
+ neqnln=2 * nb, niqnln=2 * nl2, Js=Js, Hs=Hs)
229
+
230
+ # check Jacobian and Hessian structure
231
+ # xr = rand(x0.shape)
232
+ # lmbda = rand( 2 * nb + 2 * nl2)
233
+ # Js1 = eval_jac_g(x, flag, userdata) #(xr, options.auxdata)
234
+ # Hs1 = eval_h(xr, 1, lmbda, userdata)
235
+ # i1, j1, s = find(Js)
236
+ # i2, j2, s = find(Js1)
237
+ # if (len(i1) != len(i2)) | (norm(i1 - i2) != 0) | (norm(j1 - j2) != 0):
238
+ # raise ValueError, 'something''s wrong with the Jacobian structure'
239
+ #
240
+ # i1, j1, s = find(Hs)
241
+ # i2, j2, s = find(Hs1)
242
+ # if (len(i1) != len(i2)) | (norm(i1 - i2) != 0) | (norm(j1 - j2) != 0):
243
+ # raise ValueError, 'something''s wrong with the Hessian structure'
244
+
245
+ # define variable and constraint bounds
246
+ # n is the number of variables
247
+ n = x0.shape[0]
248
+ # xl is the lower bound of x as bounded constraints
249
+ xl = xmin
250
+ # xu is the upper bound of x as bounded constraints
251
+ xu = xmax
252
+
253
+ neqnln = 2 * nb
254
+ niqnln = 2 * nl2
255
+
256
+ # number of constraints
257
+ m = neqnln + niqnln + nA
258
+ # lower bound of constraint
259
+ gl = np.r_[np.zeros(neqnln), -inf * np.ones(niqnln), l]
260
+ # upper bound of constraints
261
+ gu = np.r_[np.zeros(neqnln), np.zeros(niqnln), u]
262
+
263
+ # number of nonzeros in Jacobi matrix
264
+ nnzj = Js.nnz
265
+ # number of non-zeros in Hessian matrix, you can set it to 0
266
+ nnzh = Hs.nnz
267
+
268
+ eval_hessian = True
269
+ if eval_hessian:
270
+ def hessian(x, lagrange, obj_factor, flag, user_data=None): return \
271
+ eval_h(x, lagrange, obj_factor, flag, userdata)
272
+
273
+ nlp = pyipopt.create(n, xl, xu, m, gl, gu, nnzj, nnzh,
274
+ eval_f, eval_grad_f, eval_g, eval_jac_g, hessian)
275
+ else:
276
+ nnzh = 0
277
+ nlp = pyipopt.create(n, xl, xu, m, gl, gu, nnzj, nnzh,
278
+ eval_f, eval_grad_f, eval_g, eval_jac_g)
279
+
280
+ nlp.int_option('print_level', 5)
281
+ nlp.num_option('tol', 1.0000e-12)
282
+ nlp.int_option('max_iter', 250)
283
+ nlp.num_option('dual_inf_tol', 0.10000)
284
+ nlp.num_option('constr_viol_tol', 1.0000e-06)
285
+ nlp.num_option('compl_inf_tol', 1.0000e-05)
286
+ nlp.num_option('acceptable_tol', 1.0000e-08)
287
+ nlp.num_option('acceptable_constr_viol_tol', 1.0000e-04)
288
+ nlp.num_option('acceptable_compl_inf_tol', 0.0010000)
289
+ nlp.str_option('mu_strategy', 'adaptive')
290
+
291
+ iter = 0
292
+
293
+ def intermediate_callback(algmod, iter_count, obj_value, inf_pr, inf_du,
294
+ mu, d_norm, regularization_size, alpha_du, alpha_pr, ls_trials,
295
+ user_data=None):
296
+ iter = iter_count
297
+ return True
298
+
299
+ nlp.set_intermediate_callback(intermediate_callback)
300
+
301
+ # run the optimization
302
+ # returns final solution x, upper and lower bound for multiplier, final
303
+ # objective function obj and the return status of ipopt
304
+ x, zl, zu, obj, status, zg = nlp.solve(x0, m, userdata)
305
+
306
+ info = dict(x=x, zl=zl, zu=zu, obj=obj, status=status, lmbda=zg)
307
+
308
+ nlp.close()
309
+
310
+ success = (status == 0) | (status == 1)
311
+
312
+ output = {'iterations': iter}
313
+
314
+ f, _ = opf_costfcn(x, om)
315
+
316
+ # update solution data
317
+ Va = x[vv['i1']['Va']:vv['iN']['Va']]
318
+ Vm = x[vv['i1']['Vm']:vv['iN']['Vm']]
319
+ Pg = x[vv['i1']['Pg']:vv['iN']['Pg']]
320
+ Qg = x[vv['i1']['Qg']:vv['iN']['Qg']]
321
+ V = Vm * np.exp(1j * Va)
322
+
323
+ # ----- calculate return values -----
324
+ # update voltages & generator outputs
325
+ bus[:, IDX.bus.VA] = Va * rad2deg
326
+ bus[:, IDX.bus.VM] = Vm
327
+ gen[:, IDX.gen.PG] = Pg * baseMVA
328
+ gen[:, IDX.gen.QG] = Qg * baseMVA
329
+ gen[:, IDX.gen.VG] = Vm[gen[:, IDX.gen.GEN_BUS].astype(int)]
330
+
331
+ # compute branch flows
332
+ f_br = branch[:, IDX.branch.F_BUS].astype(int)
333
+ t_br = branch[:, IDX.branch.T_BUS].astype(int)
334
+ Sf = V[f_br] * np.conj(Yf * V) # cplx pwr at "from" bus, p.u.
335
+ St = V[t_br] * np.conj(Yt * V) # cplx pwr at "to" bus, p.u.
336
+ branch[:, IDX.branch.PF] = Sf.real * baseMVA
337
+ branch[:, IDX.branch.QF] = Sf.imag * baseMVA
338
+ branch[:, IDX.branch.PT] = St.real * baseMVA
339
+ branch[:, IDX.branch.QT] = St.imag * baseMVA
340
+
341
+ # line constraint is actually on square of limit
342
+ # so we must fix multipliers
343
+ muSf = np.zeros(nl)
344
+ muSt = np.zeros(nl)
345
+ if len(il) > 0:
346
+ muSf[il] = 2 * info['lmbda'][2 * nb + np.arange(nl2)] * branch[il, IDX.branch.RATE_A] / baseMVA
347
+ muSt[il] = 2 * info['lmbda'][2 * nb + nl2 + np.arange(nl2)] * branch[il, IDX.branch.RATE_A] / baseMVA
348
+
349
+ # update Lagrange multipliers
350
+ bus[:, IDX.bus.MU_VMAX] = info['zu'][vv['i1']['Vm']:vv['iN']['Vm']]
351
+ bus[:, IDX.bus.MU_VMIN] = info['zl'][vv['i1']['Vm']:vv['iN']['Vm']]
352
+ gen[:, IDX.gen.MU_PMAX] = info['zu'][vv['i1']['Pg']:vv['iN']['Pg']] / baseMVA
353
+ gen[:, IDX.gen.MU_PMIN] = info['zl'][vv['i1']['Pg']:vv['iN']['Pg']] / baseMVA
354
+ gen[:, IDX.gen.MU_QMAX] = info['zu'][vv['i1']['Qg']:vv['iN']['Qg']] / baseMVA
355
+ gen[:, IDX.gen.MU_QMIN] = info['zl'][vv['i1']['Qg']:vv['iN']['Qg']] / baseMVA
356
+ bus[:, IDX.bus.LAM_P] = info['lmbda'][nn['i1']['Pmis']:nn['iN']['Pmis']] / baseMVA
357
+ bus[:, IDX.bus.LAM_Q] = info['lmbda'][nn['i1']['Qmis']:nn['iN']['Qmis']] / baseMVA
358
+ branch[:, IDX.branch.MU_SF] = muSf / baseMVA
359
+ branch[:, IDX.branch.MU_ST] = muSt / baseMVA
360
+
361
+ # package up results
362
+ nlnN = om.getN('nln')
363
+
364
+ # extract multipliers for nonlinear constraints
365
+ kl = find(info['lmbda'][:2 * nb] < 0)
366
+ ku = find(info['lmbda'][:2 * nb] > 0)
367
+ nl_mu_l = np.zeros(nlnN)
368
+ nl_mu_u = np.r_[np.zeros(2 * nb), muSf, muSt]
369
+ nl_mu_l[kl] = -info['lmbda'][kl]
370
+ nl_mu_u[ku] = info['lmbda'][ku]
371
+
372
+ # extract multipliers for linear constraints
373
+ lam_lin = info['lmbda'][2 * nb + 2 * nl2 + np.arange(nA)] # lmbda for linear constraints
374
+ kl = find(lam_lin < 0) # lower bound binding
375
+ ku = find(lam_lin > 0) # upper bound binding
376
+ mu_l = np.zeros(nA)
377
+ mu_l[kl] = -lam_lin[kl]
378
+ mu_u = np.zeros(nA)
379
+ mu_u[ku] = lam_lin[ku]
380
+
381
+ mu = {
382
+ 'var': {'l': info['zl'], 'u': info['zu']},
383
+ 'nln': {'l': nl_mu_l, 'u': nl_mu_u},
384
+ 'lin': {'l': mu_l, 'u': mu_u}
385
+ }
386
+
387
+ results = ppc
388
+ results['bus'], results['branch'], results['gen'], \
389
+ results['om'], results['x'], results['mu'], results['f'] = \
390
+ bus, branch, gen, om, x, mu, f
391
+
392
+ pimul = np.r_[
393
+ results['mu']['nln']['l'] - results['mu']['nln']['u'],
394
+ results['mu']['lin']['l'] - results['mu']['lin']['u'],
395
+ -np.ones(ny > 0),
396
+ results['mu']['var']['l'] - results['mu']['var']['u']
397
+ ]
398
+ raw = {'xr': x, 'pimul': pimul, 'info': info['status'], 'output': output}
399
+
400
+ return results, success, raw
401
+
402
+
403
+ def eval_f(x, user_data=None):
404
+ """
405
+ Calculates the objective value.
406
+
407
+ @param x: input vector
408
+ """
409
+ om = user_data['om']
410
+ f, _ = opf_costfcn(x, om)
411
+ return f
412
+
413
+
414
+ def eval_grad_f(x, user_data=None):
415
+ """
416
+ Calculates gradient for objective function.
417
+ """
418
+ om = user_data['om']
419
+ _, df = opf_costfcn(x, om)
420
+ return df
421
+
422
+
423
+ def eval_g(x, user_data=None):
424
+ """
425
+ Calculates the constraint values and returns an array.
426
+ """
427
+ om = user_data['om']
428
+ Ybus = user_data['Ybus']
429
+ Yf = user_data['Yf']
430
+ Yt = user_data['Yt']
431
+ ppopt = user_data['ppopt']
432
+ il = user_data['il']
433
+ A = user_data['A']
434
+
435
+ hn, gn, _, _ = opf_consfcn(x, om, Ybus, Yf, Yt, ppopt, il)
436
+
437
+ if A is not None and sp.issparse(A):
438
+ c = np.r_[gn, hn, A * x]
439
+ else:
440
+ c = np.r_[gn, hn]
441
+ return c
442
+
443
+
444
+ def eval_jac_g(x, flag, user_data=None):
445
+ """
446
+ Calculates the Jacobi matrix.
447
+
448
+ If the flag is true, returns a tuple (row, col) to indicate the
449
+ sparse Jacobi matrix's structure.
450
+ If the flag is false, returns the values of the Jacobi matrix
451
+ with length nnzj.
452
+ """
453
+ Js = user_data['Js']
454
+ if flag:
455
+ return (Js.row, Js.col)
456
+ else:
457
+ om = user_data['om']
458
+ Ybus = user_data['Ybus']
459
+ Yf = user_data['Yf']
460
+ Yt = user_data['Yt']
461
+ ppopt = user_data['ppopt']
462
+ il = user_data['il']
463
+ A = user_data['A']
464
+
465
+ _, _, dhn, dgn = opf_consfcn(x, om, Ybus, Yf, Yt, ppopt, il)
466
+
467
+ if A is not None and sp.issparse(A):
468
+ J = sp.vstack([dgn.T, dhn.T, A], 'coo')
469
+ else:
470
+ J = sp.vstack([dgn.T, dhn.T], 'coo')
471
+
472
+ # FIXME: Extend PyIPOPT to handle changes in sparsity structure
473
+ nnzj = Js.nnz
474
+ Jd = np.zeros(nnzj)
475
+ Jc = J.tocsc()
476
+ for i in range(nnzj):
477
+ Jd[i] = Jc[Js.row[i], Js.col[i]]
478
+
479
+ return Jd
480
+
481
+
482
+ def eval_h(x, lagrange, obj_factor, flag, user_data=None):
483
+ """
484
+ Calculates the Hessian matrix (optional).
485
+
486
+ If omitted, set nnzh to 0 and Ipopt will use approximated Hessian
487
+ which will make the convergence slower.
488
+ """
489
+ Hs = user_data['Hs']
490
+ if flag:
491
+ return (Hs.row, Hs.col)
492
+ else:
493
+ neqnln = user_data['neqnln']
494
+ niqnln = user_data['niqnln']
495
+ om = user_data['om']
496
+ Ybus = user_data['Ybus']
497
+ Yf = user_data['Yf']
498
+ Yt = user_data['Yt']
499
+ ppopt = user_data['ppopt']
500
+ il = user_data['il']
501
+
502
+ lam = {}
503
+ lam['eqnonlin'] = lagrange[:neqnln]
504
+ lam['ineqnonlin'] = lagrange[np.arange(niqnln) + neqnln]
505
+
506
+ H = opf_hessfcn(x, lam, om, Ybus, Yf, Yt, ppopt, il, obj_factor)
507
+
508
+ Hl = sp.tril(H, format='csc')
509
+
510
+ # FIXME: Extend PyIPOPT to handle changes in sparsity structure
511
+ nnzh = Hs.nnz
512
+ Hd = np.zeros(nnzh)
513
+ for i in range(nnzh):
514
+ Hd[i] = Hl[Hs.row[i], Hs.col[i]]
515
+
516
+ return Hd
517
+
518
+
519
+ def qps_cplex(H, c, A, l, u, xmin, xmax, x0, opt):
520
+ """Quadratic Program Solver based on CPLEX.
521
+
522
+ A wrapper function providing a PYPOWER standardized interface for using
523
+ C{cplexqp} or C{cplexlp} to solve the following QP (quadratic programming)
524
+ problem::
525
+
526
+ min 1/2 X'*H*x + c'*x
527
+ x
528
+
529
+ subject to::
530
+
531
+ l <= A*x <= u (linear constraints)
532
+ xmin <= x <= xmax (variable bounds)
533
+
534
+ Inputs (all optional except C{H}, C{c}, C{A} and C{l}):
535
+ - C{H} : matrix (possibly sparse) of quadratic cost coefficients
536
+ - C{c} : vector of linear cost coefficients
537
+ - C{A, l, u} : define the optional linear constraints. Default
538
+ values for the elements of L and U are -Inf and Inf, respectively.
539
+ - C{xmin, xmax} : optional lower and upper bounds on the
540
+ C{x} variables, defaults are -Inf and Inf, respectively.
541
+ - C{x0} : optional starting value of optimization vector C{x}
542
+ - C{opt} : optional options structure with the following fields,
543
+ all of which are also optional (default values shown in parentheses)
544
+ - C{verbose} (0) - controls level of progress output displayed
545
+ - 0 = no progress output
546
+ - 1 = some progress output
547
+ - 2 = verbose progress output
548
+ - C{cplex_opt} - options dict for CPLEX, value in
549
+ verbose overrides these options
550
+ - C{problem} : The inputs can alternatively be supplied in a single
551
+ C{problem} dict with fields corresponding to the input arguments
552
+ described above: C{H, c, A, l, u, xmin, xmax, x0, opt}
553
+
554
+ Outputs:
555
+ - C{x} : solution vector
556
+ - C{f} : final objective function value
557
+ - C{exitflag} : CPLEXQP/CPLEXLP exit flag
558
+ (see C{cplexqp} and C{cplexlp} documentation for details)
559
+ - C{output} : CPLEXQP/CPLEXLP output dict
560
+ (see C{cplexqp} and C{cplexlp} documentation for details)
561
+ - C{lmbda} : dict containing the Langrange and Kuhn-Tucker
562
+ multipliers on the constraints, with fields:
563
+ - mu_l - lower (left-hand) limit on linear constraints
564
+ - mu_u - upper (right-hand) limit on linear constraints
565
+ - lower - lower bound on optimization variables
566
+ - upper - upper bound on optimization variables
567
+
568
+ @author: Ray Zimmerman (PSERC Cornell)
569
+ """
570
+ # ----- input argument handling -----
571
+ # gather inputs
572
+ if isinstance(H, dict): # problem struct
573
+ p = H
574
+ if 'opt' in p:
575
+ opt = p['opt']
576
+ if 'x0' in p:
577
+ x0 = p['x0']
578
+ if 'xmax' in p:
579
+ xmax = p['xmax']
580
+ if 'xmin' in p:
581
+ xmin = p['xmin']
582
+ if 'u' in p:
583
+ u = p['u']
584
+ if 'l' in p:
585
+ l = p['l']
586
+ if 'A' in p:
587
+ A = p['A']
588
+ if 'c' in p:
589
+ c = p['c']
590
+ if 'H' in p:
591
+ H = p['H']
592
+ else: # individual args
593
+ assert H is not None
594
+ assert c is not None
595
+ assert A is not None
596
+ assert l is not None
597
+
598
+ if opt is None:
599
+ opt = {}
600
+ # if x0 is None:
601
+ # x0 = np.array([])
602
+ # if xmax is None:
603
+ # xmax = np.array([])
604
+ # if xmin is None:
605
+ # xmin = np.array([])
606
+
607
+ # define nx, set default values for missing optional inputs
608
+ if len(H) == 0 or not np.any(np.any(H)):
609
+ if len(A) == 0 and len(xmin) == 0 and len(xmax) == 0:
610
+ logger.debug('qps_cplex: LP problem must include constraints or variable bounds\n')
611
+ else:
612
+ if len(A) > 0:
613
+ nx = np.shape(A)[1]
614
+ elif len(xmin) > 0:
615
+ nx = len(xmin)
616
+ else: # if len(xmax) > 0
617
+ nx = len(xmax)
618
+ else:
619
+ nx = np.shape(H)[0]
620
+
621
+ if len(c) == 0:
622
+ c = np.zeros(nx)
623
+
624
+ if len(A) > 0 and (len(l) == 0 or all(l == -inf)) and \
625
+ (len(u) == 0 or all(u == inf)):
626
+ A = None # no limits => no linear constraints
627
+
628
+ nA = np.shape(A)[0] # number of original linear constraints
629
+ if len(u) == 0: # By default, linear inequalities are ...
630
+ u = inf * np.ones(nA) # ... unbounded above and ...
631
+
632
+ if len(l) == 0:
633
+ l = -inf * np.ones(nA) # ... unbounded below.
634
+
635
+ if len(xmin) == 0: # By default, optimization variables are ...
636
+ xmin = -inf * np.ones(nx) # ... unbounded below and ...
637
+
638
+ if len(xmax) == 0:
639
+ xmax = inf * np.ones(nx) # ... unbounded above.
640
+
641
+ if len(x0) == 0:
642
+ x0 = np.zeros(nx)
643
+
644
+ # default options
645
+ if 'verbose' in opt:
646
+ verbose = opt['verbose']
647
+ else:
648
+ verbose = 0
649
+
650
+ # if 'max_it' in opt:
651
+ # max_it = opt['max_it']
652
+ # else:
653
+ # max_it = 0
654
+
655
+ # split up linear constraints
656
+ ieq = find(np.abs(u-l) <= putils.EPS) # equality
657
+ igt = find(u >= 1e10 & l > -1e10) # greater than, unbounded above
658
+ ilt = find(l <= -1e10 & u < 1e10) # less than, unbounded below
659
+ ibx = find((np.abs(u-l) > putils.EPS) & (u < 1e10) & (l > -1e10))
660
+ Ae = A[ieq, :]
661
+ be = u[ieq]
662
+ Ai = np.r_[A[ilt, :], -A[igt, :], A[ibx, :] - A[ibx, :]]
663
+ bi = np.r_[u[ilt], -l[igt], u[ibx], -l[ibx]]
664
+
665
+ # grab some dimensions
666
+ nlt = len(ilt) # number of upper bounded linear inequalities
667
+ ngt = len(igt) # number of lower bounded linear inequalities
668
+ nbx = len(ibx) # number of doubly bounded linear inequalities
669
+
670
+ # set up options struct for CPLEX
671
+ if 'cplex_opt' in opt:
672
+ cplex_opt = cplex_options(opt['cplex_opt'])
673
+ else:
674
+ cplex_opt = cplex_options
675
+
676
+ cplex = Cplex('null')
677
+ vstr = cplex.getVersion
678
+ s, e, tE, m, t = re.compile(vstr, '(\d+\.\d+)\.')
679
+ vnum = int(t[0][0])
680
+ vrb = max([0, verbose - 1])
681
+ cplex_opt['barrier']['display'] = vrb
682
+ cplex_opt['conflict']['display'] = vrb
683
+ cplex_opt['mip']['display'] = vrb
684
+ cplex_opt['sifting']['display'] = vrb
685
+ cplex_opt['simplex']['display'] = vrb
686
+ cplex_opt['tune']['display'] = vrb
687
+ if vrb and (vnum > 12.2):
688
+ cplex_opt['diagnostics'] = 'on'
689
+ # if max_it:
690
+ # cplex_opt. ## not sure what to set here
691
+
692
+ if len(Ai) == 0 and len(Ae) == 0:
693
+ unconstrained = 1
694
+ Ae = c_sparse((1, nx))
695
+ be = 0
696
+ else:
697
+ unconstrained = 0
698
+
699
+ # call the solver
700
+ if verbose:
701
+ methods = [
702
+ 'default',
703
+ 'primal simplex',
704
+ 'dual simplex',
705
+ 'network simplex',
706
+ 'barrier',
707
+ 'sifting',
708
+ 'concurrent'
709
+ ]
710
+
711
+ if len(H) == 0 or not np.any(np.any(H)):
712
+ logger.info('CPLEX Version %s -- %s LP solver\n' %
713
+ (vstr, methods[cplex_opt['lpmethod'] + 1]))
714
+
715
+ x, f, eflag, output, lam = \
716
+ cplexlp(c, Ai, bi, Ae, be, xmin, xmax, x0, cplex_opt)
717
+ else:
718
+ logger.info('CPLEX Version %s -- %s QP solver\n' %
719
+ (vstr, methods[cplex_opt['qpmethod'] + 1]))
720
+ # ensure H is numerically symmetric
721
+ if H != H.T:
722
+ H = (H + H.T) / 2
723
+
724
+ x, f, eflag, output, lam = \
725
+ cplexqp(H, c, Ai, bi, Ae, be, xmin, xmax, x0, cplex_opt)
726
+
727
+ # check for empty results (in case optimization failed)
728
+ if len(x) == 0:
729
+ x = nan * np.zeros(nx)
730
+
731
+ if len(f) == 0:
732
+ f = nan
733
+
734
+ if len(lam) == 0:
735
+ lam['ineqlin'] = nan * np.zeros(len(bi))
736
+ lam['eqlin'] = nan * np.zeros(len(be))
737
+ lam['lower'] = nan * np.zeros(nx)
738
+ lam['upper'] = nan * np.zeros(nx)
739
+ mu_l = nan * np.zeros(nA)
740
+ mu_u = nan * np.zeros(nA)
741
+ else:
742
+ mu_l = np.zeros(nA)
743
+ mu_u = np.zeros(nA)
744
+
745
+ if unconstrained:
746
+ lam['eqlin'] = np.array([])
747
+
748
+ # negate prices depending on version
749
+ if vnum < 12.3:
750
+ lam['eqlin'] = -lam['eqlin']
751
+ lam['ineqlin'] = -lam['ineqlin']
752
+
753
+ # repackage lambdas
754
+ kl = find(lam.eqlin < 0) # lower bound binding
755
+ ku = find(lam.eqlin > 0) # upper bound binding
756
+
757
+ mu_l[ieq[kl]] = -lam['eqlin'][kl]
758
+ mu_l[igt] = lam['ineqlin'][nlt + np.ones(ngt)]
759
+ mu_l[ibx] = lam['ineqlin'][nlt + ngt + nbx + np.ones(nbx)]
760
+
761
+ mu_u[ieq[ku]] = lam['eqlin'][ku]
762
+ mu_u[ilt] = lam['ineqlin'][:nlt]
763
+ mu_u[ibx] = lam['ineqlin'][nlt + ngt + np.ones(nbx)]
764
+
765
+ lmbda = dict(mu_l=mu_l, mu_u=mu_u, lower=lam.lower, upper=lam.upper)
766
+
767
+ return x, f, eflag, output, lmbda
768
+
769
+
770
+ @require_gurobi
771
+ def qps_gurobi(H, c, A, l, u, xmin, xmax, x0, opt):
772
+ """
773
+ Quadratic Program Solver based on GUROBI.
774
+
775
+ A wrapper function providing a PYPOWER standardized interface for using
776
+ gurobipy to solve the following QP (quadratic programming)
777
+ problem:
778
+
779
+ min 1/2 x'*H*x + c'*x
780
+ x
781
+
782
+ subject to
783
+
784
+ l <= A*x <= u (linear constraints)
785
+ xmin <= x <= xmax (variable bounds)
786
+
787
+ Inputs (all optional except H, c, A and l):
788
+ H : matrix (possibly sparse) of quadratic cost coefficients
789
+ c : vector of linear cost coefficients
790
+ A, l, u : define the optional linear constraints. Default
791
+ values for the elements of l and u are -Inf and Inf,
792
+ respectively.
793
+ xmin, xmax : optional lower and upper bounds on the
794
+ C{x} variables, defaults are -Inf and Inf, respectively.
795
+ x0 : optional starting value of optimization vector C{x}
796
+ opt : optional options structure with the following fields,
797
+ all of which are also optional (default values shown in
798
+ parentheses)
799
+ verbose (0) - controls level of progress output displayed
800
+ 0 = no progress output
801
+ 1 = some progress output
802
+ 2 = verbose progress output
803
+ grb_opt - options dict for Gurobi, value in
804
+ verbose overrides these options
805
+ problem : The inputs can alternatively be supplied in a single
806
+ PROBLEM dict with fields corresponding to the input arguments
807
+ described above: H, c, A, l, u, xmin, xmax, x0, opt
808
+
809
+ Outputs:
810
+ x : solution vector
811
+ f : final objective function value
812
+ exitflag : gurobipy exit flag
813
+ 1 = converged
814
+ 0 or negative values = negative of GUROBI_MEX exit flag
815
+ (see gurobipy documentation for details)
816
+ output : gurobipy output dict
817
+ (see gurobipy documentation for details)
818
+ lmbda : dict containing the Langrange and Kuhn-Tucker
819
+ multipliers on the constraints, with fields:
820
+ mu_l - lower (left-hand) limit on linear constraints
821
+ mu_u - upper (right-hand) limit on linear constraints
822
+ lower - lower bound on optimization variables
823
+ upper - upper bound on optimization variables
824
+
825
+ Note the calling syntax is almost identical to that of QUADPROG
826
+ from MathWorks' Optimization Toolbox. The main difference is that
827
+ the linear constraints are specified with A, l, u instead of
828
+ A, b, Aeq, beq.
829
+
830
+ Calling syntax options:
831
+ x, f, exitflag, output, lmbda = ...
832
+ qps_gurobi(H, c, A, l, u, xmin, xmax, x0, opt)
833
+
834
+ r = qps_gurobi(H, c, A, l, u)
835
+ r = qps_gurobi(H, c, A, l, u, xmin, xmax)
836
+ r = qps_gurobi(H, c, A, l, u, xmin, xmax, x0)
837
+ r = qps_gurobi(H, c, A, l, u, xmin, xmax, x0, opt)
838
+ r = qps_gurobi(problem), where problem is a dict with fields:
839
+ H, c, A, l, u, xmin, xmax, x0, opt
840
+ all fields except 'c', 'A' and 'l' or 'u' are optional
841
+
842
+ Example: (problem from from http://www.jmu.edu/docs/sasdoc/sashtml/iml/chap8/sect12.htm)
843
+ H = [ 1003.1 4.3 6.3 5.9;
844
+ 4.3 2.2 2.1 3.9;
845
+ 6.3 2.1 3.5 4.8;
846
+ 5.9 3.9 4.8 10 ]
847
+ c = np.zeros((4, 1))
848
+ A = [ [1 1 1 1]
849
+ [0.17 0.11 0.10 0.18] ]
850
+ l = [1; 0.10]
851
+ u = [1; Inf]
852
+ xmin = np.zeros((4, 1))
853
+ x0 = [1; 0; 0; 1]
854
+ opt = {'verbose': 2}
855
+ x, f, s, out, lmbda = qps_gurobi(H, c, A, l, u, xmin, [], x0, opt)
856
+
857
+ @see: L{gurobipy}.
858
+ """
859
+ # ----- input argument handling -----
860
+ # gather inputs
861
+ if isinstance(H, dict): # problem struct
862
+ p = H
863
+ if 'opt' in p:
864
+ opt = p['opt']
865
+ if 'x0' in p:
866
+ x0 = p['x0']
867
+ if 'xmax' in p:
868
+ xmax = p['xmax']
869
+ if 'xmin' in p:
870
+ xmin = p['xmin']
871
+ if 'u' in p:
872
+ u = p['u']
873
+ if 'l' in p:
874
+ l = p['l']
875
+ if 'A' in p:
876
+ A = p['A']
877
+ if 'c' in p:
878
+ c = p['c']
879
+ if 'H' in p:
880
+ H = p['H']
881
+ else: # individual args
882
+ assert H is not None
883
+ assert c is not None
884
+ assert A is not None
885
+ assert l is not None
886
+
887
+ if opt is None:
888
+ opt = {}
889
+ # if x0 is None:
890
+ # x0 = np.array([])
891
+ # if xmax is None:
892
+ # xmax = np.array([])
893
+ # if xmin is None:
894
+ # xmin = np.array([])
895
+
896
+ # define nx, set default values for missing optional inputs
897
+ if len(H) == 0 or not np.any(np.any(H)):
898
+ if len(A) == 0 and len(xmin) == 0 and len(xmax) == 0:
899
+ logger.debug('qps_gurobi: LP problem must include constraints or variable bounds\n')
900
+ else:
901
+ if len(A) > 0:
902
+ nx = np.shape(A)[1]
903
+ elif len(xmin) > 0:
904
+ nx = len(xmin)
905
+ else: # if len(xmax) > 0
906
+ nx = len(xmax)
907
+ H = c_sparse((nx, nx))
908
+ else:
909
+ nx = np.shape(H)[0]
910
+
911
+ if len(c) == 0:
912
+ c = np.zeros(nx)
913
+
914
+ if len(A) > 0 and (len(l) == 0 or all(l == -inf)) and \
915
+ (len(u) == 0 or all(u == inf)):
916
+ A = None # no limits => no linear constraints
917
+
918
+ nA = np.shape(A)[0] # number of original linear constraints
919
+ if nA:
920
+ if len(u) == 0: # By default, linear inequalities are ...
921
+ u = inf * np.ones(nA) # ... unbounded above and ...
922
+
923
+ if len(l) == 0:
924
+ l = -inf * np.ones(nA) # ... unbounded below.
925
+
926
+ if len(x0) == 0:
927
+ x0 = np.zeros(nx)
928
+
929
+ # default options
930
+ if 'verbose' in opt:
931
+ verbose = opt['verbose']
932
+ else:
933
+ verbose = 0
934
+
935
+ # if 'max_it' in opt:
936
+ # max_it = opt['max_it']
937
+ # else:
938
+ # max_it = 0
939
+
940
+ # set up options struct for Gurobi
941
+ if 'grb_opt' in opt:
942
+ g_opt = gurobi_options(opt['grb_opt'])
943
+ else:
944
+ g_opt = gurobi_options()
945
+
946
+ g_opt['Display'] = min(verbose, 3)
947
+ if verbose:
948
+ g_opt['DisplayInterval'] = 1
949
+ else:
950
+ g_opt['DisplayInterval'] = inf
951
+
952
+ if not sp.issparse(A):
953
+ A = c_sparse(A)
954
+
955
+ # split up linear constraints
956
+ ieq = find(np.abs(u-l) <= putils.EPS) # equality
957
+ igt = find(u >= 1e10 & l > -1e10) # greater than, unbounded above
958
+ ilt = find(l <= -1e10 & u < 1e10) # less than, unbounded below
959
+ ibx = find((np.abs(u-l) > putils.EPS) & (u < 1e10) & (l > -1e10))
960
+
961
+ # grab some dimensions
962
+ nlt = len(ilt) # number of upper bounded linear inequalities
963
+ ngt = len(igt) # number of lower bounded linear inequalities
964
+ nbx = len(ibx) # number of doubly bounded linear inequalities
965
+ neq = len(ieq) # number of equalities
966
+ niq = nlt + ngt + 2 * nbx # number of inequalities
967
+
968
+ AA = [A[ieq, :], A[ilt, :], -A[igt, :], A[ibx, :], -A[ibx, :]]
969
+ bb = [u[ieq], u[ilt], -l[igt], u[ibx], -l[ibx]]
970
+ contypes = '=' * neq + '<' * niq
971
+
972
+ # call the solver
973
+ if len(H) == 0 or not np.any(np.any(H)):
974
+ lpqp = 'LP'
975
+ else:
976
+ lpqp = 'QP'
977
+ rr, cc, vv = find(H)
978
+ g_opt['QP']['qrow'] = int(rr.T - 1)
979
+ g_opt['QP']['qcol'] = int(cc.T - 1)
980
+ g_opt['QP']['qval'] = 0.5 * vv.T
981
+
982
+ if verbose:
983
+ methods = [
984
+ 'primal simplex',
985
+ 'dual simplex',
986
+ 'interior point',
987
+ 'concurrent',
988
+ 'deterministic concurrent'
989
+ ]
990
+ logger.info('Gurobi Version %s -- %s %s solver\n'
991
+ '<unknown>' % (methods[g_opt['Method'] + 1], lpqp))
992
+
993
+ x, f, eflag, output, lmbda = \
994
+ gurobipy(c.T, 1, AA, bb, contypes, xmin, xmax, 'C', g_opt)
995
+ pi = lmbda['Pi']
996
+ rc = lmbda['RC']
997
+ output['flag'] = eflag
998
+ if eflag == 2:
999
+ eflag = 1 # optimal solution found
1000
+ else:
1001
+ eflag = -eflag # failed somehow
1002
+
1003
+ # check for empty results (in case optimization failed)
1004
+ lam = {}
1005
+ if len(x) == 0:
1006
+ x = nan(nx, 1)
1007
+ lam['lower'] = nan(nx)
1008
+ lam['upper'] = nan(nx)
1009
+ else:
1010
+ lam['lower'] = np.zeros(nx)
1011
+ lam['upper'] = np.zeros(nx)
1012
+
1013
+ if len(f) == 0:
1014
+ f = nan
1015
+
1016
+ if len(pi) == 0:
1017
+ pi = nan(len(bb))
1018
+
1019
+ kl = find(rc > 0) # lower bound binding
1020
+ ku = find(rc < 0) # upper bound binding
1021
+ lam['lower'][kl] = rc[kl]
1022
+ lam['upper'][ku] = -rc[ku]
1023
+ lam['eqlin'] = pi[:neq + 1]
1024
+ lam['ineqlin'] = pi[neq + range(niq + 1)]
1025
+ mu_l = np.zeros(nA)
1026
+ mu_u = np.zeros(nA)
1027
+
1028
+ # repackage lmbdas
1029
+ kl = find(lam['eqlin'] > 0) # lower bound binding
1030
+ ku = find(lam['eqlin'] < 0) # upper bound binding
1031
+
1032
+ mu_l[ieq[kl]] = lam['eqlin'][kl]
1033
+ mu_l[igt] = -lam['ineqlin'][nlt + range(ngt + 1)]
1034
+ mu_l[ibx] = -lam['ineqlin'][nlt + ngt + nbx + range(nbx)]
1035
+
1036
+ mu_u[ieq[ku]] = -lam['eqlin'][ku]
1037
+ mu_u[ilt] = -lam['ineqlin'][:nlt + 1]
1038
+ mu_u[ibx] = -lam['ineqlin'][nlt + ngt + range(nbx + 1)]
1039
+
1040
+ lmbda = dict(mu_l=mu_l, mu_u=mu_u, lower=lam['lower'], upper=lam['upper'])
1041
+
1042
+ return x, f, eflag, output, lmbda
1043
+
1044
+
1045
+ def qps_ipopt(H, c, A, l, u, xmin, xmax, x0, opt):
1046
+ """
1047
+ Quadratic Program Solver based on IPOPT.
1048
+
1049
+ Uses IPOPT to solve the following QP (quadratic programming) problem::
1050
+
1051
+ min 1/2 x'*H*x + c'*x
1052
+ x
1053
+
1054
+ subject to::
1055
+
1056
+ l <= A*x <= u (linear constraints)
1057
+ xmin <= x <= xmax (variable bounds)
1058
+
1059
+ Inputs (all optional except C{H}, C{C}, C{A} and C{L}):
1060
+ - C{H} : matrix (possibly sparse) of quadratic cost coefficients
1061
+ - C{C} : vector of linear cost coefficients
1062
+ - C{A, l, u} : define the optional linear constraints. Default
1063
+ values for the elements of C{l} and C{u} are -Inf and Inf,
1064
+ respectively.
1065
+ - C{xmin, xmax} : optional lower and upper bounds on the
1066
+ C{x} variables, defaults are -Inf and Inf, respectively.
1067
+ - C{x0} : optional starting value of optimization vector C{x}
1068
+ - C{opt} : optional options structure with the following fields,
1069
+ all of which are also optional (default values shown in parentheses)
1070
+ - C{verbose} (0) - controls level of progress output displayed
1071
+ - 0 = no progress output
1072
+ - 1 = some progress output
1073
+ - 2 = verbose progress output
1074
+ - C{max_it} (0) - maximum number of iterations allowed
1075
+ - 0 = use algorithm default
1076
+ - C{ipopt_opt} - options struct for IPOPT, values in
1077
+ C{verbose} and C{max_it} override these options
1078
+ - C{problem} : The inputs can alternatively be supplied in a single
1079
+ C{problem} dict with fields corresponding to the input arguments
1080
+ described above: C{H, c, A, l, u, xmin, xmax, x0, opt}
1081
+
1082
+ Outputs:
1083
+ - C{x} : solution vector
1084
+ - C{f} : final objective function value
1085
+ - C{exitflag} : exit flag
1086
+ - 1 = first order optimality conditions satisfied
1087
+ - 0 = maximum number of iterations reached
1088
+ - -1 = numerically failed
1089
+ - C{output} : output struct with the following fields:
1090
+ - C{iterations} - number of iterations performed
1091
+ - C{hist} - dict list with trajectories of the following:
1092
+ C{feascond}, C{gradcond}, C{compcond}, C{costcond}, C{gamma},
1093
+ C{stepsize}, C{obj}, C{alphap}, C{alphad}
1094
+ - message - exit message
1095
+ - C{lmbda} : dict containing the Langrange and Kuhn-Tucker
1096
+ multipliers on the constraints, with fields:
1097
+ - C{mu_l} - lower (left-hand) limit on linear constraints
1098
+ - C{mu_u} - upper (right-hand) limit on linear constraints
1099
+ - C{lower} - lower bound on optimization variables
1100
+ - C{upper} - upper bound on optimization variables
1101
+
1102
+ Calling syntax options::
1103
+ x, f, exitflag, output, lmbda = \
1104
+ qps_ipopt(H, c, A, l, u, xmin, xmax, x0, opt)
1105
+
1106
+ x = qps_ipopt(H, c, A, l, u)
1107
+ x = qps_ipopt(H, c, A, l, u, xmin, xmax)
1108
+ x = qps_ipopt(H, c, A, l, u, xmin, xmax, x0)
1109
+ x = qps_ipopt(H, c, A, l, u, xmin, xmax, x0, opt)
1110
+ x = qps_ipopt(problem), where problem is a struct with fields:
1111
+ H, c, A, l, u, xmin, xmax, x0, opt
1112
+ all fields except 'c', 'A' and 'l' or 'u' are optional
1113
+ x = qps_ipopt(...)
1114
+ x, f = qps_ipopt(...)
1115
+ x, f, exitflag = qps_ipopt(...)
1116
+ x, f, exitflag, output = qps_ipopt(...)
1117
+ x, f, exitflag, output, lmbda = qps_ipopt(...)
1118
+
1119
+ Example::
1120
+ H = [ 1003.1 4.3 6.3 5.9;
1121
+ 4.3 2.2 2.1 3.9;
1122
+ 6.3 2.1 3.5 4.8;
1123
+ 5.9 3.9 4.8 10 ]
1124
+ c = np.zeros((4, 1))
1125
+ A = [ 1 1 1 1
1126
+ 0.17 0.11 0.10 0.18 ]
1127
+ l = [1, 0.10]
1128
+ u = [1, Inf]
1129
+ xmin = np.zeros((4, 1))
1130
+ x0 = [1, 0, 0, 1]
1131
+ opt = {'verbose': 2)
1132
+ x, f, s, out, lambda = qps_ipopt(H, c, A, l, u, xmin, [], x0, opt)
1133
+
1134
+ Problem from U{http://www.jmu.edu/docs/sasdoc/sashtml/iml/chap8/sect12.htm}
1135
+
1136
+ @see: C{pyipopt}, L{ipopt_options}
1137
+
1138
+ @author: Ray Zimmerman (PSERC Cornell)
1139
+ """
1140
+ # ----- input argument handling -----
1141
+ # gather inputs
1142
+ if isinstance(H, dict): # problem struct
1143
+ p = H
1144
+ if 'opt' in p:
1145
+ opt = p['opt']
1146
+ if 'x0' in p:
1147
+ x0 = p['x0']
1148
+ if 'xmax' in p:
1149
+ xmax = p['xmax']
1150
+ if 'xmin' in p:
1151
+ xmin = p['xmin']
1152
+ if 'u' in p:
1153
+ u = p['u']
1154
+ if 'l' in p:
1155
+ l = p['l']
1156
+ if 'A' in p:
1157
+ A = p['A']
1158
+ if 'c' in p:
1159
+ c = p['c']
1160
+ if 'H' in p:
1161
+ H = p['H']
1162
+ else: # individual args
1163
+ assert H is not None
1164
+ assert c is not None
1165
+ assert A is not None
1166
+ assert l is not None
1167
+
1168
+ if opt is None:
1169
+ opt = {}
1170
+ # if x0 is None:
1171
+ # x0 = np.array([])
1172
+ # if xmax is None:
1173
+ # xmax = np.array([])
1174
+ # if xmin is None:
1175
+ # xmin = np.array([])
1176
+
1177
+ # define nx, set default values for missing optional inputs
1178
+ if len(H) == 0 or not np.any(np.any(H)):
1179
+ if len(A) == 0 and len(xmin) == 0 and len(xmax) == 0:
1180
+ logger.info('qps_ipopt: LP problem must include constraints or variable bounds')
1181
+ else:
1182
+ if len(A) > 0:
1183
+ nx = np.shape(A)[1]
1184
+ elif len(xmin) > 0:
1185
+ nx = len(xmin)
1186
+ else: # if len(xmax) > 0
1187
+ nx = len(xmax)
1188
+ H = c_sparse((nx, nx))
1189
+ else:
1190
+ nx = np.shape(H)[0]
1191
+
1192
+ if len(c) == 0:
1193
+ c = np.zeros(nx)
1194
+
1195
+ if len(A) > 0 and (len(l) == 0 or all(l == -inf)) and \
1196
+ (len(u) == 0 or all(u == inf)):
1197
+ A = None # no limits => no linear constraints
1198
+
1199
+ nA = np.shape(A)[0] # number of original linear constraints
1200
+ if nA:
1201
+ if len(u) == 0: # By default, linear inequalities are ...
1202
+ u = inf * np.ones(nA) # ... unbounded above and ...
1203
+
1204
+ if len(l) == 0:
1205
+ l = -inf * np.ones(nA) # ... unbounded below.
1206
+
1207
+ if len(x0) == 0:
1208
+ x0 = np.zeros(nx)
1209
+
1210
+ # default options
1211
+ if 'verbose' in opt:
1212
+ verbose = opt['verbose']
1213
+ else:
1214
+ verbose = 0
1215
+
1216
+ if 'max_it' in opt:
1217
+ max_it = opt['max_it']
1218
+ else:
1219
+ max_it = 0
1220
+
1221
+ # make sure args are sparse/full as expected by IPOPT
1222
+ if len(H) > 0:
1223
+ if not sp.issparse(H):
1224
+ H = c_sparse(H)
1225
+
1226
+ if not sp.issparse(A):
1227
+ A = c_sparse(A)
1228
+
1229
+ # ----- run optimization -----
1230
+ # set options dict for IPOPT
1231
+ options = {}
1232
+ if 'ipopt_opt' in opt:
1233
+ options['ipopt'] = ipopt_options(opt['ipopt_opt'])
1234
+ else:
1235
+ options['ipopt'] = ipopt_options()
1236
+
1237
+ options['ipopt']['jac_c_constant'] = 'yes'
1238
+ options['ipopt']['jac_d_constant'] = 'yes'
1239
+ options['ipopt']['hessian_constant'] = 'yes'
1240
+ options['ipopt']['least_square_init_primal'] = 'yes'
1241
+ options['ipopt']['least_square_init_duals'] = 'yes'
1242
+ # options['ipopt']['mehrotra_algorithm'] = 'yes' ## default 'no'
1243
+ if verbose:
1244
+ options['ipopt']['print_level'] = min(12, verbose * 2 + 1)
1245
+ else:
1246
+ options['ipopt']['print_level = 0']
1247
+
1248
+ if max_it:
1249
+ options['ipopt']['max_iter'] = max_it
1250
+
1251
+ # define variable and constraint bounds, if given
1252
+ if nA:
1253
+ options['cu'] = u
1254
+ options['cl'] = l
1255
+
1256
+ if len(xmin) > 0:
1257
+ options['lb'] = xmin
1258
+
1259
+ if len(xmax) > 0:
1260
+ options['ub'] = xmax
1261
+
1262
+ # assign function handles
1263
+ funcs = {}
1264
+ funcs['objective'] = lambda x: 0.5 * x.T * H * x + c.T * x
1265
+ funcs['gradient'] = lambda x: H * x + c
1266
+ funcs['constraints'] = lambda x: A * x
1267
+ funcs['jacobian'] = lambda x: A
1268
+ funcs['jacobianstructure'] = lambda: A
1269
+ funcs['hessian'] = lambda x, sigma, lmbda: np.tril(H)
1270
+ funcs['hessianstructure'] = lambda: np.tril(H)
1271
+
1272
+ # run the optimization
1273
+ x, info = pyipopt(x0, funcs, options)
1274
+
1275
+ if info['status'] == 0 | info['status'] == 1:
1276
+ eflag = 1
1277
+ else:
1278
+ eflag = 0
1279
+
1280
+ output = {}
1281
+ if 'iter' in info:
1282
+ output['iterations'] = info['iter']
1283
+
1284
+ output['info'] = info['status']
1285
+ f = funcs['objective'](x)
1286
+
1287
+ # repackage lmbdas
1288
+ kl = find(info['lmbda'] < 0) # lower bound binding
1289
+ ku = find(info['lmbda'] > 0) # upper bound binding
1290
+ mu_l = np.zeros(nA)
1291
+ mu_l[kl] = -info['lmbda'][kl]
1292
+ mu_u = np.zeros(nA)
1293
+ mu_u[ku] = info['lmbda'][ku]
1294
+
1295
+ lmbda = dict(mu_l=mu_l, mu_u=mu_u, lower=info['zl'], upper=info['zu'])
1296
+
1297
+ return x, f, eflag, output, lmbda
1298
+
1299
+
1300
+ @require_mosek
1301
+ def qps_mosek(H, c=None, A=None, l=None, u=None, xmin=None, xmax=None,
1302
+ x0=None, opt=None):
1303
+ """
1304
+ Quadratic Program Solver based on MOSEK.
1305
+
1306
+ A wrapper function providing a PYPOWER standardized interface for using
1307
+ MOSEKOPT to solve the following QP (quadratic programming) problem::
1308
+
1309
+ min 1/2 x'*H*x + c'*x
1310
+ x
1311
+
1312
+ subject to::
1313
+
1314
+ l <= A*x <= u (linear constraints)
1315
+ xmin <= x <= xmax (variable bounds)
1316
+
1317
+ Inputs (all optional except C{H}, C{C}, C{A} and C{L}):
1318
+ - C{H} : matrix (possibly sparse) of quadratic cost coefficients
1319
+ - C{C} : vector of linear cost coefficients
1320
+ - C{A, l, u} : define the optional linear constraints. Default
1321
+ values for the elements of L and U are -Inf and Inf, respectively.
1322
+ - xmin, xmax : optional lower and upper bounds on the
1323
+ C{x} variables, defaults are -Inf and Inf, respectively.
1324
+ - C{x0} : optional starting value of optimization vector C{x}
1325
+ - C{opt} : optional options structure with the following fields,
1326
+ all of which are also optional (default values shown in parentheses)
1327
+ - C{verbose} (0) - controls level of progress output displayed
1328
+ - 0 = no progress output
1329
+ - 1 = some progress output
1330
+ - 2 = verbose progress output
1331
+ - C{max_it} (0) - maximum number of iterations allowed
1332
+ - 0 = use algorithm default
1333
+ - C{mosek_opt} - options struct for MOSEK, values in
1334
+ C{verbose} and C{max_it} override these options
1335
+ - C{problem} : The inputs can alternatively be supplied in a single
1336
+ C{problem} struct with fields corresponding to the input arguments
1337
+ described above: C{H, c, A, l, u, xmin, xmax, x0, opt}
1338
+
1339
+ Outputs:
1340
+ - C{x} : solution vector
1341
+ - C{f} : final objective function value
1342
+ - C{exitflag} : exit flag
1343
+ - 1 = success
1344
+ - 0 = terminated at maximum number of iterations
1345
+ - -1 = primal or dual infeasible
1346
+ < 0 = the negative of the MOSEK return code
1347
+ - C{output} : output dict with the following fields:
1348
+ - C{r} - MOSEK return code
1349
+ - C{res} - MOSEK result dict
1350
+ - C{lmbda} : dict containing the Langrange and Kuhn-Tucker
1351
+ multipliers on the constraints, with fields:
1352
+ - C{mu_l} - lower (left-hand) limit on linear constraints
1353
+ - C{mu_u} - upper (right-hand) limit on linear constraints
1354
+ - C{lower} - lower bound on optimization variables
1355
+ - C{upper} - upper bound on optimization variables
1356
+
1357
+ @author: Ray Zimmerman (PSERC Cornell)
1358
+ """
1359
+ # ----- input argument handling -----
1360
+ # gather inputs
1361
+ if isinstance(H, dict): # problem struct
1362
+ p = H
1363
+ else: # individual args
1364
+ p = {'H': H, 'c': c, 'A': A, 'l': l, 'u': u}
1365
+ if xmin is not None:
1366
+ p['xmin'] = xmin
1367
+ if xmax is not None:
1368
+ p['xmax'] = xmax
1369
+ if x0 is not None:
1370
+ p['x0'] = x0
1371
+ if opt is not None:
1372
+ p['opt'] = opt
1373
+
1374
+ # define nx, set default values for H and c
1375
+ if 'H' not in p or len(p['H']) or not np.any(np.any(p['H'])):
1376
+ if ('A' not in p) | len(p['A']) == 0 & \
1377
+ ('xmin' not in p) | len(p['xmin']) == 0 & \
1378
+ ('xmax' not in p) | len(p['xmax']) == 0:
1379
+ logger.debug('qps_mosek: LP problem must include constraints or variable bounds\n')
1380
+ else:
1381
+ if 'A' in p & len(p['A']) > 0:
1382
+ nx = np.shape(p['A'])[1]
1383
+ elif 'xmin' in p & len(p['xmin']) > 0:
1384
+ nx = len(p['xmin'])
1385
+ else: # if isfield(p, 'xmax') && ~isempty(p.xmax)
1386
+ nx = len(p['xmax'])
1387
+ p['H'] = c_sparse((nx, nx))
1388
+ qp = 0
1389
+ else:
1390
+ nx = np.shape(p['H'])[0]
1391
+ qp = 1
1392
+
1393
+ if 'c' not in p | len(p['c']) == 0:
1394
+ p['c'] = np.zeros(nx)
1395
+
1396
+ if 'x0' not in p | len(p['x0']) == 0:
1397
+ p['x0'] = np.zeros(nx)
1398
+
1399
+ # default options
1400
+ if 'opt' not in p:
1401
+ p['opt'] = []
1402
+
1403
+ if 'verbose' in p['opt']:
1404
+ verbose = p['opt']['verbose']
1405
+ else:
1406
+ verbose = 0
1407
+
1408
+ if 'max_it' in p['opt']:
1409
+ max_it = p['opt']['max_it']
1410
+ else:
1411
+ max_it = 0
1412
+
1413
+ if 'mosek_opt' in p['opt']:
1414
+ mosek_opt = mosek_options(p['opt']['mosek_opt'])
1415
+ else:
1416
+ mosek_opt = mosek_options()
1417
+
1418
+ if max_it:
1419
+ mosek_opt['MSK_IPAR_INTPNT_MAX_ITERATIONS'] = max_it
1420
+
1421
+ if qp:
1422
+ mosek_opt['MSK_IPAR_OPTIMIZER'] = 0 # default solver only for QP
1423
+
1424
+ # set up problem struct for MOSEK
1425
+ prob = {}
1426
+ prob['c'] = p['c']
1427
+ if qp:
1428
+ prob['qosubi'], prob['qosubj'], prob['qoval'] = find(sp.tril(c_sparse(p['H'])))
1429
+
1430
+ if 'A' in p & len(p['A']) > 0:
1431
+ prob['a'] = c_sparse(p['A'])
1432
+
1433
+ if 'l' in p & len(p['A']) > 0:
1434
+ prob['blc'] = p['l']
1435
+
1436
+ if 'u' in p & len(p['A']) > 0:
1437
+ prob['buc'] = p['u']
1438
+
1439
+ if 'xmin' in p & len(p['xmin']) > 0:
1440
+ prob['blx'] = p['xmin']
1441
+
1442
+ if 'xmax' in p & len(p['xmax']) > 0:
1443
+ prob['bux'] = p['xmax']
1444
+
1445
+ # A is not allowed to be empty
1446
+ if 'a' not in prob | len(prob['a']) == 0:
1447
+ unconstrained = True
1448
+ prob['a'] = c_sparse((1, (1, 1)), (1, nx))
1449
+ prob.blc = -inf
1450
+ prob.buc = inf
1451
+ else:
1452
+ unconstrained = False
1453
+
1454
+ # ----- run optimization -----
1455
+ if verbose:
1456
+ methods = [
1457
+ 'default',
1458
+ 'interior point',
1459
+ '<default>',
1460
+ '<default>',
1461
+ 'primal simplex',
1462
+ 'dual simplex',
1463
+ 'primal dual simplex',
1464
+ 'automatic simplex',
1465
+ '<default>',
1466
+ '<default>',
1467
+ 'concurrent'
1468
+ ]
1469
+ if len(H) == 0 or not np.any(np.any(H)):
1470
+ lpqp = 'LP'
1471
+ else:
1472
+ lpqp = 'QP'
1473
+
1474
+ # (this code is also in mpver.m)
1475
+ # MOSEK Version 6.0.0.93 (Build date: 2010-10-26 13:03:27)
1476
+ # MOSEK Version 6.0.0.106 (Build date: 2011-3-17 10:46:54)
1477
+ # pat = 'Version (\.*\d)+.*Build date: (\d\d\d\d-\d\d-\d\d)';
1478
+ pat = 'Version (\.*\d)+.*Build date: (\d+-\d+-\d+)'
1479
+ s, e, tE, m, t = re.compile(eval('mosekopt'), pat)
1480
+ if len(t) == 0:
1481
+ vn = '<unknown>'
1482
+ else:
1483
+ vn = t[0][0]
1484
+
1485
+ logger.info('MOSEK Version %s -- %s %s solver\n' %
1486
+ (vn, methods[mosek_opt['MSK_IPAR_OPTIMIZER'] + 1], lpqp))
1487
+
1488
+ cmd = 'minimize echo(%d)' % verbose
1489
+ r, res = mosekopt(cmd, prob, mosek_opt)
1490
+
1491
+ # ----- repackage results -----
1492
+ if 'sol' in res:
1493
+ if 'bas' in res['sol']:
1494
+ sol = res['sol.bas']
1495
+ else:
1496
+ sol = res['sol.itr']
1497
+ x = sol['xx']
1498
+ else:
1499
+ sol = np.array([])
1500
+ x = np.array([])
1501
+
1502
+ # ----- process return codes -----
1503
+ if 'symbcon' in res:
1504
+ sc = res['symbcon']
1505
+ else:
1506
+ r2, res2 = mosekopt('symbcon echo(0)')
1507
+ sc = res2['symbcon']
1508
+
1509
+ eflag = -r
1510
+ msg = ''
1511
+ if r == sc.MSK_RES_OK:
1512
+ if len(sol) > 0:
1513
+ # if sol['solsta'] == sc.MSK_SOL_STA_OPTIMAL:
1514
+ if sol['solsta'] == 'OPTIMAL':
1515
+ msg = 'The solution is optimal.'
1516
+ eflag = 1
1517
+ else:
1518
+ eflag = -1
1519
+ # if sol['prosta'] == sc['MSK_PRO_STA_PRIM_INFEAS']:
1520
+ if sol['prosta'] == 'PRIMAL_INFEASIBLE':
1521
+ msg = 'The problem is primal infeasible.'
1522
+ # elif sol['prosta'] == sc['MSK_PRO_STA_DUAL_INFEAS']:
1523
+ elif sol['prosta'] == 'DUAL_INFEASIBLE':
1524
+ msg = 'The problem is dual infeasible.'
1525
+ else:
1526
+ msg = sol['solsta']
1527
+
1528
+ elif r == sc['MSK_RES_TRM_MAX_ITERATIONS']:
1529
+ eflag = 0
1530
+ msg = 'The optimizer terminated at the maximum number of iterations.'
1531
+ else:
1532
+ if 'rmsg' in res and 'rcodestr' in res:
1533
+ msg = '%s : %s' % (res['rcodestr'], res['rmsg'])
1534
+ else:
1535
+ msg = 'MOSEK return code = %d' % r
1536
+
1537
+ # always alert user if license is expired
1538
+ if (verbose or r == 1001) and len(msg) < 0:
1539
+ logger.info('%s\n' % msg)
1540
+
1541
+ # ----- repackage results -----
1542
+ if r == 0:
1543
+ f = p['c'].T * x
1544
+ if len(p['H']) > 0:
1545
+ f = 0.5 * x.T * p['H'] * x + f
1546
+ else:
1547
+ f = np.array([])
1548
+
1549
+ output = {}
1550
+ output['r'] = r
1551
+ output['res'] = res
1552
+
1553
+ if 'sol' in res:
1554
+ lmbda = {}
1555
+ lmbda['lower'] = sol['slx']
1556
+ lmbda['upper'] = sol['sux']
1557
+ lmbda['mu_l'] = sol['slc']
1558
+ lmbda['mu_u'] = sol['suc']
1559
+ if unconstrained:
1560
+ lmbda['mu_l'] = np.array([])
1561
+ lmbda['mu_u'] = np.array([])
1562
+ else:
1563
+ lmbda = np.array([])
1564
+
1565
+ return x, f, eflag, output, lmbda
1566
+
1567
+
1568
+ def qps_pips(H, c, A, l, u, xmin=None, xmax=None, x0=None, opt=None):
1569
+ """
1570
+ Uses the Python Interior Point Solver (PIPS) to solve the following
1571
+ QP (quadratic programming) problem::
1572
+
1573
+ min 1/2 x'*H*x + C'*x
1574
+ x
1575
+
1576
+ subject to::
1577
+
1578
+ l <= A*x <= u (linear constraints)
1579
+ xmin <= x <= xmax (variable bounds)
1580
+
1581
+ Note the calling syntax is almost identical to that of QUADPROG from
1582
+ MathWorks' Optimization Toolbox. The main difference is that the linear
1583
+ constraints are specified with C{A}, C{L}, C{U} instead of C{A}, C{B},
1584
+ C{Aeq}, C{Beq}.
1585
+
1586
+ Example from U{http://www.uc.edu/sashtml/iml/chap8/sect12.htm}:
1587
+
1588
+ >>> from numpy import array, zeros, Inf
1589
+ >>> from scipy.sparse import csr_matrix
1590
+ >>> H = csr_matrix(np.array([[1003.1, 4.3, 6.3, 5.9],
1591
+ ... [4.3, 2.2, 2.1, 3.9],
1592
+ ... [6.3, 2.1, 3.5, 4.8],
1593
+ ... [5.9, 3.9, 4.8, 10 ]]))
1594
+ >>> c = np.zeros(4)
1595
+ >>> A = csr_matrix(np.array([[1, 1, 1, 1 ],
1596
+ ... [0.17, 0.11, 0.10, 0.18]]))
1597
+ >>> l = np.array([1, 0.10])
1598
+ >>> u = np.array([1, Inf])
1599
+ >>> xmin = np.zeros(4)
1600
+ >>> xmax = None
1601
+ >>> x0 = np.array([1, 0, 0, 1])
1602
+ >>> solution = qps_pips(H, c, A, l, u, xmin, xmax, x0)
1603
+ >>> round(solution["f"], 11) == 1.09666678128
1604
+ True
1605
+ >>> solution["converged"]
1606
+ True
1607
+ >>> solution["output"]["iterations"]
1608
+ 10
1609
+
1610
+ All parameters are optional except C{H}, C{c}, C{A} and C{l} or C{u}.
1611
+ @param H: Quadratic cost coefficients.
1612
+ @type H: csr_matrix
1613
+ @param c: vector of linear cost coefficients
1614
+ @type c: array
1615
+ @param A: Optional linear constraints.
1616
+ @type A: csr_matrix
1617
+ @param l: Optional linear constraints. Default values are M{-Inf}.
1618
+ @type l: array
1619
+ @param u: Optional linear constraints. Default values are M{Inf}.
1620
+ @type u: array
1621
+ @param xmin: Optional lower bounds on the M{x} variables, defaults are
1622
+ M{-Inf}.
1623
+ @type xmin: array
1624
+ @param xmax: Optional upper bounds on the M{x} variables, defaults are
1625
+ M{Inf}.
1626
+ @type xmax: array
1627
+ @param x0: Starting value of optimization vector M{x}.
1628
+ @type x0: array
1629
+ @param opt: optional options dictionary with the following keys, all of
1630
+ which are also optional (default values shown in parentheses)
1631
+ - C{verbose} (False) - Controls level of progress output
1632
+ displayed
1633
+ - C{feastol} (1e-6) - termination tolerance for feasibility
1634
+ condition
1635
+ - C{gradtol} (1e-6) - termination tolerance for gradient
1636
+ condition
1637
+ - C{comptol} (1e-6) - termination tolerance for
1638
+ complementarity condition
1639
+ - C{costtol} (1e-6) - termination tolerance for cost
1640
+ condition
1641
+ - C{max_it} (150) - maximum number of iterations
1642
+ - C{step_control} (False) - set to True to enable step-size
1643
+ control
1644
+ - C{max_red} (20) - maximum number of step-size reductions if
1645
+ step-control is on
1646
+ - C{cost_mult} (1.0) - cost multiplier used to scale the
1647
+ objective function for improved conditioning. Note: The
1648
+ same value must also be passed to the Hessian evaluation
1649
+ function so that it can appropriately scale the objective
1650
+ function term in the Hessian of the Lagrangian.
1651
+ @type opt: dict
1652
+
1653
+ @rtype: dict
1654
+ @return: The solution dictionary has the following keys:
1655
+ - C{x} - solution vector
1656
+ - C{f} - final objective function value
1657
+ - C{converged} - exit status
1658
+ - True = first order optimality conditions satisfied
1659
+ - False = maximum number of iterations reached
1660
+ - None = numerically failed
1661
+ - C{output} - output dictionary with keys:
1662
+ - C{iterations} - number of iterations performed
1663
+ - C{hist} - dictionary of arrays with trajectories of the
1664
+ following: feascond, gradcond, coppcond, costcond, gamma,
1665
+ stepsize, obj, alphap, alphad
1666
+ - C{message} - exit message
1667
+ - C{lmbda} - dictionary containing the Langrange and Kuhn-Tucker
1668
+ multipliers on the constraints, with keys:
1669
+ - C{eqnonlin} - nonlinear equality constraints
1670
+ - C{ineqnonlin} - nonlinear inequality constraints
1671
+ - C{mu_l} - lower (left-hand) limit on linear constraints
1672
+ - C{mu_u} - upper (right-hand) limit on linear constraints
1673
+ - C{lower} - lower bound on optimization variables
1674
+ - C{upper} - upper bound on optimization variables
1675
+
1676
+ @see: L{pips}
1677
+
1678
+ @author: Ray Zimmerman (PSERC Cornell)
1679
+ """
1680
+ if isinstance(H, dict):
1681
+ p = H
1682
+ else:
1683
+ p = {'H': H, 'c': c, 'A': A, 'l': l, 'u': u}
1684
+ if xmin is not None:
1685
+ p['xmin'] = xmin
1686
+ if xmax is not None:
1687
+ p['xmax'] = xmax
1688
+ if x0 is not None:
1689
+ p['x0'] = x0
1690
+ if opt is not None:
1691
+ p['opt'] = opt
1692
+
1693
+ if 'H' not in p or p['H'] == None: # p['H'].nnz == 0:
1694
+ if p['A'] is None or p['A'].nnz == 0 and \
1695
+ 'xmin' not in p and \
1696
+ 'xmax' not in p:
1697
+ # 'xmin' not in p or len(p['xmin']) == 0 and \
1698
+ # 'xmax' not in p or len(p['xmax']) == 0:
1699
+ print('qps_pips: LP problem must include constraints or variable bounds')
1700
+ return
1701
+ else:
1702
+ if p['A'] is not None and p['A'].nnz >= 0:
1703
+ nx = p['A'].shape[1]
1704
+ elif 'xmin' in p and len(p['xmin']) > 0:
1705
+ nx = p['xmin'].shape[0]
1706
+ elif 'xmax' in p and len(p['xmax']) > 0:
1707
+ nx = p['xmax'].shape[0]
1708
+ p['H'] = c_sparse((nx, nx))
1709
+ else:
1710
+ nx = p['H'].shape[0]
1711
+
1712
+ p['xmin'] = -inf * np.ones(nx) if 'xmin' not in p else p['xmin']
1713
+ p['xmax'] = inf * np.ones(nx) if 'xmax' not in p else p['xmax']
1714
+
1715
+ p['c'] = np.zeros(nx) if p['c'] is None else p['c']
1716
+
1717
+ p['x0'] = np.zeros(nx) if 'x0' not in p else p['x0']
1718
+
1719
+ def qp_f(x, return_hessian=False):
1720
+ f = 0.5 * np.dot(x * p['H'], x) + np.dot(p['c'], x)
1721
+ df = p['H'] * x + p['c']
1722
+ if not return_hessian:
1723
+ return f, df
1724
+ d2f = p['H']
1725
+ return f, df, d2f
1726
+
1727
+ p['f_fcn'] = qp_f
1728
+
1729
+ sol = pips(p)
1730
+
1731
+ return sol["x"], sol["f"], sol["eflag"], sol["output"], sol["lmbda"]
1732
+
1733
+
1734
+ def qps_pypower(H, c=None, A=None, l=None, u=None, xmin=None, xmax=None,
1735
+ x0=None, opt=None):
1736
+ """
1737
+ Quadratic Program Solver for PYPOWER.
1738
+
1739
+ A common wrapper function for various QP solvers.
1740
+ Solves the following QP (quadratic programming) problem::
1741
+
1742
+ min 1/2 x'*H*x + c'*x
1743
+ x
1744
+
1745
+ subject to::
1746
+
1747
+ l <= A*x <= u (linear constraints)
1748
+ xmin <= x <= xmax (variable bounds)
1749
+
1750
+ Inputs (all optional except C{H}, C{c}, C{A} and C{l}):
1751
+ - C{H} : matrix (possibly sparse) of quadratic cost coefficients
1752
+ - C{c} : vector of linear cost coefficients
1753
+ - C{A, l, u} : define the optional linear constraints. Default
1754
+ values for the elements of C{l} and C{u} are -Inf and Inf,
1755
+ respectively.
1756
+ - C{xmin}, C{xmax} : optional lower and upper bounds on the
1757
+ C{x} variables, defaults are -Inf and Inf, respectively.
1758
+ - C{x0} : optional starting value of optimization vector C{x}
1759
+ - C{opt} : optional options structure with the following fields,
1760
+ all of which are also optional (default values shown in parentheses)
1761
+ - C{alg} (0) - determines which solver to use
1762
+ - 0 = automatic, first available of BPMPD_MEX, CPLEX,
1763
+ Gurobi, PIPS
1764
+ - 100 = BPMPD_MEX
1765
+ - 200 = PIPS, Python Interior Point Solver
1766
+ pure Python implementation of a primal-dual
1767
+ interior point method
1768
+ - 250 = PIPS-sc, a step controlled variant of PIPS
1769
+ - 300 = Optimization Toolbox, QUADPROG or LINPROG
1770
+ - 400 = IPOPT
1771
+ - 500 = CPLEX
1772
+ - 600 = MOSEK
1773
+ - 700 = Gurobi
1774
+ - C{verbose} (0) - controls level of progress output displayed
1775
+ - 0 = no progress output
1776
+ - 1 = some progress output
1777
+ - 2 = verbose progress output
1778
+ - C{max_it} (0) - maximum number of iterations allowed
1779
+ - 0 = use algorithm default
1780
+ - C{bp_opt} - options vector for BP
1781
+ - C{cplex_opt} - options dict for CPLEX
1782
+ - C{grb_opt} - options dict for gurobipy
1783
+ - C{ipopt_opt} - options dict for IPOPT
1784
+ - C{pips_opt} - options dict for L{qps_pips}
1785
+ - C{mosek_opt} - options dict for MOSEK
1786
+ - C{ot_opt} - options dict for QUADPROG/LINPROG
1787
+ - C{problem} : The inputs can alternatively be supplied in a single
1788
+ C{problem} dict with fields corresponding to the input arguments
1789
+ described above: C{H, c, A, l, u, xmin, xmax, x0, opt}
1790
+
1791
+ Outputs:
1792
+ - C{x} : solution vector
1793
+ - C{f} : final objective function value
1794
+ - C{exitflag} : exit flag
1795
+ - 1 = converged
1796
+ - 0 or negative values = algorithm specific failure codes
1797
+ - C{output} : output struct with the following fields:
1798
+ - C{alg} - algorithm code of solver used
1799
+ - (others) - algorithm specific fields
1800
+ - C{lmbda} : dict containing the Langrange and Kuhn-Tucker
1801
+ multipliers on the constraints, with fields:
1802
+ - C{mu_l} - lower (left-hand) limit on linear constraints
1803
+ - C{mu_u} - upper (right-hand) limit on linear constraints
1804
+ - C{lower} - lower bound on optimization variables
1805
+ - C{upper} - upper bound on optimization variables
1806
+
1807
+
1808
+ Example from U{http://www.uc.edu/sashtml/iml/chap8/sect12.htm}:
1809
+
1810
+ >>> from numpy import array, zeros, Inf
1811
+ >>> from scipy.sparse import csr_matrix
1812
+ >>> H = csr_matrix(np.array([[1003.1, 4.3, 6.3, 5.9],
1813
+ ... [4.3, 2.2, 2.1, 3.9],
1814
+ ... [6.3, 2.1, 3.5, 4.8],
1815
+ ... [5.9, 3.9, 4.8, 10 ]]))
1816
+ >>> c = np.zeros(4)
1817
+ >>> A = csr_matrix(np.array([[1, 1, 1, 1 ],
1818
+ ... [0.17, 0.11, 0.10, 0.18]]))
1819
+ >>> l = np.array([1, 0.10])
1820
+ >>> u = np.array([1, Inf])
1821
+ >>> xmin = np.zeros(4)
1822
+ >>> xmax = None
1823
+ >>> x0 = np.array([1, 0, 0, 1])
1824
+ >>> solution = qps_pips(H, c, A, l, u, xmin, xmax, x0)
1825
+ >>> round(solution["f"], 11) == 1.09666678128
1826
+ True
1827
+ >>> solution["converged"]
1828
+ True
1829
+ >>> solution["output"]["iterations"]
1830
+ 10
1831
+
1832
+ @author: Ray Zimmerman (PSERC Cornell)
1833
+ """
1834
+ # ----- input argument handling -----
1835
+ # gather inputs
1836
+ if isinstance(H, dict): # problem struct
1837
+ p = H
1838
+ if 'opt' in p:
1839
+ opt = p['opt']
1840
+ if 'x0' in p:
1841
+ x0 = p['x0']
1842
+ if 'xmax' in p:
1843
+ xmax = p['xmax']
1844
+ if 'xmin' in p:
1845
+ xmin = p['xmin']
1846
+ if 'u' in p:
1847
+ u = p['u']
1848
+ if 'l' in p:
1849
+ l = p['l']
1850
+ if 'A' in p:
1851
+ A = p['A']
1852
+ if 'c' in p:
1853
+ c = p['c']
1854
+ if 'H' in p:
1855
+ H = p['H']
1856
+ else: # individual args
1857
+ # assert H is not None zero dimensional sparse matrices not supported
1858
+ assert c is not None
1859
+ # assert A is not None zero dimensional sparse matrices not supported
1860
+ # assert l is not None no lower bounds indicated by None
1861
+
1862
+ if opt is None:
1863
+ opt = {}
1864
+ # if x0 is None:
1865
+ # x0 = np.array([])
1866
+ # if xmax is None:
1867
+ # xmax = np.array([])
1868
+ # if xmin is None:
1869
+ # xmin = np.array([])
1870
+
1871
+ # default options
1872
+ if 'alg' in opt:
1873
+ alg = opt['alg']
1874
+ else:
1875
+ alg = 0
1876
+
1877
+ if 'verbose' in opt:
1878
+ verbose = opt['verbose']
1879
+ else:
1880
+ verbose = 0
1881
+
1882
+ if alg == 0:
1883
+ if putils.have_fcn('cplex'): # use CPLEX by default, if available
1884
+ alg = 500
1885
+ elif putils.have_fcn('mosek'): # if not, then MOSEK, if available
1886
+ alg = 600
1887
+ elif putils.have_fcn('gurobipy'): # if not, then Gurobi, if available
1888
+ alg = 700
1889
+ else: # otherwise PIPS
1890
+ alg = 200
1891
+
1892
+ # ----- call the appropriate solver -----
1893
+ if alg == 200 or alg == 250: # use MIPS or sc-MIPS
1894
+ # set up options
1895
+ if 'pips_opt' in opt:
1896
+ pips_opt = opt['pips_opt']
1897
+ else:
1898
+ pips_opt = {}
1899
+
1900
+ if 'max_it' in opt:
1901
+ pips_opt['max_it'] = opt['max_it']
1902
+
1903
+ if alg == 200:
1904
+ pips_opt['step_control'] = False
1905
+ else:
1906
+ pips_opt['step_control'] = True
1907
+
1908
+ pips_opt['verbose'] = verbose
1909
+
1910
+ # call solver
1911
+ x, f, eflag, output, lmbda = \
1912
+ qps_pips(H, c, A, l, u, xmin, xmax, x0, pips_opt)
1913
+ elif alg == 400: # use IPOPT
1914
+ x, f, eflag, output, lmbda = \
1915
+ qps_ipopt(H, c, A, l, u, xmin, xmax, x0, opt)
1916
+ elif alg == 500: # use CPLEX
1917
+ x, f, eflag, output, lmbda = \
1918
+ qps_cplex(H, c, A, l, u, xmin, xmax, x0, opt)
1919
+ elif alg == 600: # use MOSEK
1920
+ x, f, eflag, output, lmbda = \
1921
+ qps_mosek(H, c, A, l, u, xmin, xmax, x0, opt)
1922
+ elif 700: # use Gurobi
1923
+ x, f, eflag, output, lmbda = \
1924
+ qps_gurobi(H, c, A, l, u, xmin, xmax, x0, opt)
1925
+ else:
1926
+ logger.info('qps_pypower: %d is not a valid algorithm code', alg)
1927
+
1928
+ if 'alg' not in output:
1929
+ output['alg'] = alg
1930
+
1931
+ return x, f, eflag, output, lmbda
1932
+
1933
+
1934
+ def cplex_options(overrides=None, ppopt=None):
1935
+ """
1936
+ Sets options for CPLEX.
1937
+
1938
+ Sets the values for the options dict normally passed to
1939
+ C{cplexoptimset}.
1940
+
1941
+ Inputs are all optional, second argument must be either a string
1942
+ (C{fname}) or a dict (C{ppopt}):
1943
+
1944
+ Output is an options dict to pass to C{cplexoptimset}.
1945
+
1946
+ Example:
1947
+
1948
+ If C{ppopt['CPLEX_OPT'] = 3}, then after setting the default CPLEX options,
1949
+ CPLEX_OPTIONS will execute the following user-defined function
1950
+ to allow option overrides::
1951
+
1952
+ opt = cplex_user_options_3(opt, ppopt)
1953
+
1954
+ The contents of cplex_user_options_3.py, could be something like::
1955
+
1956
+ def cplex_user_options_3(opt, ppopt):
1957
+ opt = {}
1958
+ opt['threads'] = 2
1959
+ opt['simplex']['refactor'] = 1
1960
+ opt['timelimit'] = 10000
1961
+ return opt
1962
+
1963
+ For details on the available options, see the I{"Parameters Reference
1964
+ Manual"} section of the CPLEX documentation at:
1965
+ U{http://publib.boulder.ibm.com/infocenter/cosinfoc/v12r2/}
1966
+
1967
+ @param overrides:
1968
+ - dict containing values to override the defaults
1969
+ - fname: name of user-supplied function called after default
1970
+ options are set to modify them. Calling syntax is::
1971
+
1972
+ modified_opt = fname(default_opt)
1973
+
1974
+ @param ppopt: PYPOWER options vector, uses the following entries:
1975
+ - OPF_VIOLATION - used to set opt.simplex.tolerances.feasibility
1976
+ - VERBOSE - used to set opt.barrier.display,
1977
+ opt.conflict.display, opt.mip.display, opt.sifting.display,
1978
+ opt.simplex.display, opt.tune.display
1979
+ - CPLEX_LPMETHOD - used to set opt.lpmethod
1980
+ - CPLEX_QPMETHOD - used to set opt.qpmethod
1981
+ - CPLEX_OPT - user option file, if ppopt['CPLEX_OPT'] is
1982
+ non-zero it is appended to 'cplex_user_options_' to form
1983
+ the name of a user-supplied function used as C{fname}
1984
+ described above, except with calling syntax::
1985
+
1986
+ modified_opt = fname(default_opt, ppopt)
1987
+
1988
+ @see: C{cplexlp}, C{cplexqp}, L{ppoption}.
1989
+
1990
+ @author: Ray Zimmerman (PSERC Cornell)
1991
+ """
1992
+ # ----- initialization and arg handling -----
1993
+ # defaults
1994
+ verbose = 1
1995
+ feastol = 1e-6
1996
+ fname = ''
1997
+
1998
+ # second argument
1999
+ if ppopt != None:
2000
+ if isinstance(ppopt, str): # 2nd arg is FNAME (string)
2001
+ fname = ppopt
2002
+ have_ppopt = False
2003
+ else: # 2nd arg is ppopt (MATPOWER options vector)
2004
+ have_ppopt = True
2005
+ # (make default OPF_VIOLATION correspond to default CPLEX feastol)
2006
+ feastol = ppopt['OPF_VIOLATION'] / 5
2007
+ verbose = ppopt['VERBOSE']
2008
+ lpmethod = ppopt['CPLEX_LPMETHOD']
2009
+ qpmethod = ppopt['CPLEX_QPMETHOD']
2010
+ if ppopt['CPLEX_OPT']:
2011
+ fname = 'cplex_user_options_#d' % ppopt['CPLEX_OPT']
2012
+ else:
2013
+ have_ppopt = False
2014
+
2015
+ # ----- set default options for CPLEX -----
2016
+ opt = cplexoptimset('cplex')
2017
+ opt['simplex']['tolerances']['feasibility'] = feastol
2018
+
2019
+ # printing
2020
+ vrb = max([0, verbose - 1])
2021
+ opt['barrier']['display'] = vrb
2022
+ opt['conflict']['display'] = vrb
2023
+ opt['mip']['display'] = vrb
2024
+ opt['sifting']['display'] = vrb
2025
+ opt['simplex']['display'] = vrb
2026
+ opt['tune']['display'] = vrb
2027
+
2028
+ # solution algorithm
2029
+ if have_ppopt:
2030
+ opt['lpmethod'] = lpmethod
2031
+ opt['qpmethod'] = qpmethod
2032
+ # else:
2033
+ # opt['lpmethod'] = 2
2034
+ # opt['qpmethod'] = 2
2035
+
2036
+ # ----- call user function to modify defaults -----
2037
+ if len(fname) > 0:
2038
+ if have_ppopt:
2039
+ opt = putils.feval(fname, opt, ppopt)
2040
+ else:
2041
+ opt = putils.feval(fname, opt)
2042
+
2043
+ # ----- apply overrides -----
2044
+ if overrides is not None:
2045
+ names = overrides.keys()
2046
+ for k in range(len(names)):
2047
+ if isinstance(overrides[names[k]], dict):
2048
+ names2 = overrides[names[k]].keys()
2049
+ for k2 in range(len(names2)):
2050
+ if isinstance(overrides[names[k]][names2[k2]], dict):
2051
+ names3 = overrides[names[k]][names2[k2]].keys()
2052
+ for k3 in range(len(names3)):
2053
+ opt[names[k]][names2[k2]][names3[k3]] = overrides[names[k]][names2[k2]][names3[k3]]
2054
+ else:
2055
+ opt[names[k]][names2[k2]] = overrides[names[k]][names2[k2]]
2056
+ else:
2057
+ opt[names[k]] = overrides[names[k]]
2058
+
2059
+ return opt
2060
+
2061
+
2062
+ def gurobi_options(overrides=None, ppopt=None):
2063
+ """
2064
+ Sets options for GUROBI.
2065
+
2066
+ Sets the values for the options dict normally passed to GUROBI_MEX.
2067
+
2068
+ Inputs are all optional, second argument must be either a string
2069
+ (fname) or a vector (ppopt):
2070
+
2071
+ overrides - dict containing values to override the defaults
2072
+ fname - name of user-supplied function called after default
2073
+ options are set to modify them. Calling syntax is:
2074
+ modified_opt = fname(default_opt)
2075
+ ppopt - PYPOWER options vector, uses the following entries:
2076
+ OPF_VIOLATION (16) - used to set opt.FeasibilityTol
2077
+ VERBOSE (31) - used to set opt.DisplayInterval, opt.Display
2078
+ GRB_METHOD (121) - used to set opt.Method
2079
+ GRB_TIMELIMIT (122) - used to set opt.TimeLimit (seconds)
2080
+ GRB_THREADS (123) - used to set opt.Threads
2081
+ GRB_OPT (124) - user option file, if PPOPT(124) is non-zero
2082
+ it is appended to 'gurobi_user_options_' to form the name of a
2083
+ user-supplied function used as C{fname} described above, except
2084
+ with calling syntax:
2085
+ modified_opt = fname(default_opt, mpopt)
2086
+
2087
+ Output is an options struct to pass to GUROBI_MEX.
2088
+
2089
+ Example:
2090
+
2091
+ If ppopt['GRB_OPT'] = 3, then after setting the default GUROBI options,
2092
+ GUROBI_OPTIONS will execute the following user-defined function
2093
+ to allow option overrides:
2094
+
2095
+ opt = gurobi_user_options_3(opt, ppopt)
2096
+
2097
+ The contents of gurobi_user_options_3.py, could be something like:
2098
+
2099
+ def gurobi_user_options_3(opt, ppopt):
2100
+ opt = {}
2101
+ opt['OptimalityTol'] = 1e-9
2102
+ opt['IterationLimit'] = 3000
2103
+ opt['BarIterLimit'] = 200
2104
+ opt['Crossover'] = 0
2105
+ opt['Presolve'] = 0
2106
+ return opt
2107
+
2108
+ For details on the available options, see the "Parameters" section
2109
+ of the "Gurobi Optimizer Reference Manual" at:
2110
+
2111
+ http://www.gurobi.com/doc/45/refman/
2112
+
2113
+ @see: L{gurobi_mex}, L{ppoption}.
2114
+ """
2115
+ # ----- initialization and arg handling -----
2116
+ # defaults
2117
+ verbose = True
2118
+ fname = ''
2119
+
2120
+ # second argument
2121
+ if ppopt != None:
2122
+ if isinstance(ppopt, str): # 2nd arg is FNAME (string)
2123
+ fname = ppopt
2124
+ have_ppopt = False
2125
+ else: # 2nd arg is MPOPT (MATPOWER options vector)
2126
+ have_ppopt = True
2127
+ verbose = ppopt['VERBOSE']
2128
+ if ppopt['GRB_OPT']:
2129
+ fname = 'gurobi_user_options_%d', ppopt['GRB_OPT']
2130
+ else:
2131
+ have_ppopt = False
2132
+
2133
+ # ----- set default options for CPLEX -----
2134
+ opt = {}
2135
+ # opt['OptimalityTol'] = 1e-6
2136
+ # -1 - auto, 0 - no, 1 - conserv, 2 - aggressive=
2137
+ # opt['Presolve'] = -1
2138
+ # opt['LogFile'] = 'qps_gurobi.log'
2139
+ if have_ppopt:
2140
+ # (make default OPF_VIOLATION correspond to default FeasibilityTol)
2141
+ opt['FeasibilityTol'] = ppopt['OPF_VIOLATION'] / 5
2142
+ opt['Method'] = ppopt['GRB_METHOD']
2143
+ opt['TimeLimit'] = ppopt['GRB_TIMELIMIT']
2144
+ opt['Threads'] = ppopt['GRB_THREADS']
2145
+ else:
2146
+ opt['Method'] = 1 # dual simplex
2147
+
2148
+ opt['Display'] = min(verbose, 3)
2149
+ if verbose:
2150
+ opt['DisplayInterval'] = 1
2151
+ else:
2152
+ opt['DisplayInterval'] = inf
2153
+
2154
+ # ----- call user function to modify defaults -----
2155
+ if len(fname) > 0:
2156
+ if have_ppopt:
2157
+ opt = putils.feval(fname, opt, ppopt)
2158
+ else:
2159
+ opt = putils.feval(fname, opt)
2160
+
2161
+ # ----- apply overrides -----
2162
+ if overrides is not None:
2163
+ names = overrides.keys()
2164
+ for k in range(len(names)):
2165
+ opt[names[k]] = overrides[names[k]]
2166
+
2167
+ return opt
2168
+
2169
+
2170
+ def ipopt_options(overrides=None, ppopt=None):
2171
+ """
2172
+ Sets options for IPOPT.
2173
+
2174
+ Sets the values for the options.ipopt dict normally passed to
2175
+ IPOPT.
2176
+
2177
+ Inputs are all optional, second argument must be either a string
2178
+ (C{fname}) or a dict (C{ppopt}):
2179
+
2180
+ - C{overrides}
2181
+ - dict containing values to override the defaults
2182
+ - C{fname} name of user-supplied function called after default
2183
+ options are set to modify them. Calling syntax is::
2184
+ modified_opt = fname(default_opt)
2185
+ - C{ppopt} PYPOWER options vector, uses the following entries:
2186
+ - C{OPF_VIOLATION} used to set opt['constr_viol_tol']
2187
+ - C{VERBOSE} used to opt['print_level']
2188
+ - C{IPOPT_OPT} user option file, if ppopt['IPOPT_OPT'] is
2189
+ non-zero it is appended to 'ipopt_user_options_' to form
2190
+ the name of a user-supplied function used as C{fname}
2191
+ described above, except with calling syntax::
2192
+ modified_opt = fname(default_opt ppopt)
2193
+
2194
+ Output is an options.ipopt dict to pass to IPOPT.
2195
+
2196
+ Example: If ppopt['IPOPT_OPT'] = 3, then after setting the default IPOPT
2197
+ options, L{ipopt_options} will execute the following user-defined function
2198
+ to allow option overrides::
2199
+
2200
+ opt = ipopt_user_options_3(opt, ppopt);
2201
+
2202
+ The contents of ipopt_user_options_3.py, could be something like::
2203
+
2204
+ def ipopt_user_options_3(opt, ppopt):
2205
+ opt = {}
2206
+ opt['nlp_scaling_method'] = 'none'
2207
+ opt['max_iter'] = 500
2208
+ opt['derivative_test'] = 'first-order'
2209
+ return opt
2210
+
2211
+ See the options reference section in the IPOPT documentation for
2212
+ details on the available options.
2213
+
2214
+ U{http://www.coin-or.org/Ipopt/documentation/}
2215
+
2216
+ @see: C{pyipopt}, L{ppoption}
2217
+
2218
+ @author: Ray Zimmerman (PSERC Cornell)
2219
+ """
2220
+ # ----- initialization and arg handling -----
2221
+ # defaults
2222
+ verbose = 2
2223
+ fname = ''
2224
+
2225
+ # second argument
2226
+ if ppopt != None:
2227
+ if isinstance(ppopt, str): # 2nd arg is FNAME (string)
2228
+ fname = ppopt
2229
+ have_ppopt = False
2230
+ else: # 2nd arg is ppopt (MATPOWER options vector)
2231
+ have_ppopt = True
2232
+ verbose = ppopt['VERBOSE']
2233
+ if ppopt['IPOPT_OPT']:
2234
+ fname = 'ipopt_user_options_#d' % ppopt['IPOPT_OPT']
2235
+ else:
2236
+ have_ppopt = False
2237
+
2238
+ opt = {}
2239
+ # ----- set default options for IPOPT -----
2240
+ # printing
2241
+ if verbose:
2242
+ opt['print_level'] = min([12, verbose * 2 + 1])
2243
+ else:
2244
+ opt['print_level'] = 0
2245
+
2246
+ # convergence
2247
+ opt['tol'] = 1e-8 # default 1e-8
2248
+ opt['max_iter'] = 250 # default 3000
2249
+ opt['dual_inf_tol'] = 0.1 # default 1
2250
+ if have_ppopt:
2251
+ opt['constr_viol_tol'] = ppopt[16] # default 1e-4
2252
+ opt['acceptable_constr_viol_tol'] = ppopt[16] * 100 # default 1e-2
2253
+ opt['compl_inf_tol'] = 1e-5 # default 1e-4
2254
+ opt['acceptable_tol'] = 1e-8 # default 1e-6
2255
+ # opt['acceptable_iter'] = 15 ## default 15
2256
+ # opt['acceptable_dual_inf_tol'] = 1e+10 ## default 1e+10
2257
+ opt['acceptable_compl_inf_tol'] = 1e-3 # default 1e-2
2258
+ # opt['acceptable_obj_change_tol'] = 1e+20 ## default 1e+20
2259
+ # opt['diverging_iterates_tol'] = 1e+20 ## default 1e+20
2260
+
2261
+ # NLP scaling
2262
+ # opt['nlp_scaling_method'] = 'none' ## default 'gradient-based'
2263
+
2264
+ # NLP
2265
+ # opt['fixed_variable_treatment'] = 'make_constraint' ## default 'make_parameter'
2266
+ # opt['honor_original_bounds'] = 'no' ## default 'yes'
2267
+ # opt['check_derivatives_for_naninf'] = 'yes' ## default 'no'
2268
+
2269
+ # initialization
2270
+ # opt['least_square_init_primal'] = 'yes' ## default 'no'
2271
+ # opt['least_square_init_duals'] = 'yes' ## default 'no'
2272
+
2273
+ # barrier parameter update
2274
+ opt['mu_strategy'] = 'adaptive' # default 'monotone'
2275
+
2276
+ # linear solver
2277
+ # opt['linear_solver'] = 'ma27'
2278
+ # opt['linear_solver'] = 'ma57'
2279
+ # opt['linear_solver'] = 'pardiso'
2280
+ # opt['linear_solver'] = 'wsmp'
2281
+ # opt['linear_solver'] = 'mumps' ## default 'mumps'
2282
+ # opt['linear_solver'] = 'custom'
2283
+ # opt['linear_scaling_on_demand'] = 'no' ## default 'yes'
2284
+
2285
+ # step calculation
2286
+ # opt['mehrotra_algorithm'] = 'yes' ## default 'no'
2287
+ # opt['fast_step_computation'] = 'yes' ## default 'no'
2288
+
2289
+ # restoration phase
2290
+ # opt['expect_infeasible_problem'] = 'yes' ## default 'no'
2291
+
2292
+ # derivative checker
2293
+ # opt['derivative_test'] = 'second-order' ## default 'none'
2294
+
2295
+ # hessian approximation
2296
+ # opt['hessian_approximation'] = 'limited-memory' ## default 'exact'
2297
+
2298
+ # ma57 options
2299
+ # opt['ma57_pre_alloc'] = 3
2300
+ # opt['ma57_pivot_order'] = 4
2301
+
2302
+ # ----- call user function to modify defaults -----
2303
+ if len(fname) > 0:
2304
+ if have_ppopt:
2305
+ opt = putils.feval(fname, opt, ppopt)
2306
+ else:
2307
+ opt = putils.feval(fname, opt)
2308
+
2309
+ # ----- apply overrides -----
2310
+ if overrides is not None:
2311
+ names = overrides.keys()
2312
+ for k in range(len(names)):
2313
+ opt[names[k]] = overrides[names[k]]
2314
+
2315
+ return opt
2316
+
2317
+
2318
+ def mosek_options(overrides=None, ppopt=None):
2319
+ """Sets options for MOSEK.
2320
+
2321
+ Inputs are all optional, second argument must be either a string
2322
+ (C{fname}) or a dict (C{ppopt}):
2323
+
2324
+ - C{overrides}
2325
+ - dict containing values to override the defaults
2326
+ - C{fname} name of user-supplied function called after default
2327
+ options are set to modify them. Calling syntax is::
2328
+ modified_opt = fname(default_opt)
2329
+ - C{ppopt} PYPOWER options vector, uses the following entries:
2330
+ - C{OPF_VIOLATION} used to set opt.MSK_DPAR_INTPNT_TOL_PFEAS
2331
+ - C{VERBOSE} not currently used here
2332
+ - C{MOSEK_LP_ALG} - used to set opt.MSK_IPAR_OPTIMIZER
2333
+ - C{MOSEK_MAX_IT} used to set opt.MSK_IPAR_INTPNT_MAX_ITERATIONS
2334
+ - C{MOSEK_GAP_TOL} used to set opt.MSK_DPAR_INTPNT_TOL_REL_GAP
2335
+ - C{MOSEK_MAX_TIME} used to set opt.MSK_DPAR_OPTIMIZER_MAX_TIME
2336
+ - C{MOSEK_NUM_THREADS} used to set opt.MSK_IPAR_INTPNT_NUM_THREADS
2337
+ - C{MOSEK_OPT} user option file, if ppopt['MOSEK_OPT'] is non-zero
2338
+ it is appended to 'mosek_user_options_' to form
2339
+ the name of a user-supplied function used as C{fname}
2340
+ described above, except with calling syntax::
2341
+ modified_opt = fname(default_opt, ppopt)
2342
+
2343
+ Output is a param dict to pass to MOSEKOPT.
2344
+
2345
+ Example:
2346
+
2347
+ If PPOPT['MOSEK_OPT'] = 3, then after setting the default MOSEK options,
2348
+ L{mosek_options} will execute the following user-defined function
2349
+ to allow option overrides::
2350
+
2351
+ opt = mosek_user_options_3(opt, ppopt)
2352
+
2353
+ The contents of mosek_user_options_3.py, could be something like::
2354
+
2355
+ def mosek_user_options_3(opt, ppopt):
2356
+ opt = {}
2357
+ opt.MSK_DPAR_INTPNT_TOL_DFEAS = 1e-9
2358
+ opt.MSK_IPAR_SIM_MAX_ITERATIONS = 5000000
2359
+ return opt
2360
+
2361
+ See the Parameters reference in Appix E of "The MOSEK
2362
+ optimization toolbox for MATLAB manaul" for
2363
+ details on the available options.
2364
+
2365
+ U{http://www.mosek.com/documentation/}
2366
+
2367
+ @see: C{mosekopt}, L{ppoption}.
2368
+
2369
+ @author: Ray Zimmerman (PSERC Cornell)
2370
+ """
2371
+ # ----- initialization and arg handling -----
2372
+ # defaults
2373
+ verbose = 2
2374
+ gaptol = 0
2375
+ fname = ''
2376
+
2377
+ # get symbolic constant names
2378
+ r, res = mosekopt('symbcon echo(0)')
2379
+ sc = res['symbcon']
2380
+
2381
+ # second argument
2382
+ if ppopt == None:
2383
+ if isinstance(ppopt, str): # 2nd arg is FNAME (string)
2384
+ fname = ppopt
2385
+ have_ppopt = False
2386
+ else: # 2nd arg is ppopt (MATPOWER options vector)
2387
+ have_ppopt = True
2388
+ verbose = ppopt['VERBOSE']
2389
+ if ppopt['MOSEK_OPT']:
2390
+ fname = 'mosek_user_options_#d' # ppopt['MOSEK_OPT']
2391
+ else:
2392
+ have_ppopt = False
2393
+
2394
+ opt = {}
2395
+ # ----- set default options for MOSEK -----
2396
+ # solution algorithm
2397
+ if have_ppopt:
2398
+ alg = ppopt['MOSEK_LP_ALG']
2399
+ if alg == sc['MSK_OPTIMIZER_FREE'] or \
2400
+ alg == sc['MSK_OPTIMIZER_INTPNT'] or \
2401
+ alg == sc['MSK_OPTIMIZER_PRIMAL_SIMPLEX'] or \
2402
+ alg == sc['MSK_OPTIMIZER_DUAL_SIMPLEX'] or \
2403
+ alg == sc['MSK_OPTIMIZER_PRIMAL_DUAL_SIMPLEX'] or \
2404
+ alg == sc['MSK_OPTIMIZER_FREE_SIMPLEX'] or \
2405
+ alg == sc['MSK_OPTIMIZER_CONCURRENT']:
2406
+ opt['MSK_IPAR_OPTIMIZER'] = alg
2407
+ else:
2408
+ opt['MSK_IPAR_OPTIMIZER'] = sc['MSK_OPTIMIZER_FREE']
2409
+
2410
+ # (make default OPF_VIOLATION correspond to default MSK_DPAR_INTPNT_TOL_PFEAS)
2411
+ opt['MSK_DPAR_INTPNT_TOL_PFEAS'] = ppopt['OPF_VIOLATION'] / 500
2412
+ if ppopt['MOSEK_MAX_IT']:
2413
+ opt['MSK_IPAR_INTPNT_MAX_ITERATIONS'] = ppopt['MOSEK_MAX_IT']
2414
+
2415
+ if ppopt['MOSEK_GAP_TOL']:
2416
+ opt['MSK_DPAR_INTPNT_TOL_REL_GAP'] = ppopt['MOSEK_GAP_TOL']
2417
+
2418
+ if ppopt['MOSEK_MAX_TIME']:
2419
+ opt['MSK_DPAR_OPTIMIZER_MAX_TIME'] = ppopt['MOSEK_MAX_TIME']
2420
+
2421
+ if ppopt['MOSEK_NUM_THREADS']:
2422
+ opt['MSK_IPAR_INTPNT_NUM_THREADS'] = ppopt['MOSEK_NUM_THREADS']
2423
+ else:
2424
+ opt['MSK_IPAR_OPTIMIZER'] = sc['MSK_OPTIMIZER_FREE']
2425
+
2426
+ # opt['MSK_DPAR_INTPNT_TOL_PFEAS'] = 1e-8 ## primal feasibility tol
2427
+ # opt['MSK_DPAR_INTPNT_TOL_DFEAS'] = 1e-8 ## dual feasibility tol
2428
+ # opt['MSK_DPAR_INTPNT_TOL_MU_RED'] = 1e-16 ## relative complementarity gap tol
2429
+ # opt['MSK_DPAR_INTPNT_TOL_REL_GAP'] = 1e-8 ## relative gap termination tol
2430
+ # opt['MSK_IPAR_INTPNT_MAX_ITERATIONS'] = 400 ## max iterations for int point
2431
+ # opt['MSK_IPAR_SIM_MAX_ITERATIONS'] = 10000000 ## max iterations for simplex
2432
+ # opt['MSK_DPAR_OPTIMIZER_MAX_TIME'] = -1 ## max time allowed (< 0 --> Inf)
2433
+ # opt['MSK_IPAR_INTPNT_NUM_THREADS'] = 1 ## number of threads
2434
+ # opt['MSK_IPAR_PRESOLVE_USE'] = sc['MSK_PRESOLVE_MODE_OFF']
2435
+
2436
+ # if verbose == 0:
2437
+ # opt['MSK_IPAR_LOG'] = 0
2438
+ #
2439
+
2440
+ # ----- call user function to modify defaults -----
2441
+ if len(fname) > 0:
2442
+ if have_ppopt:
2443
+ opt = putils.feval(fname, opt, ppopt)
2444
+ else:
2445
+ opt = putils.feval(fname, opt)
2446
+
2447
+ # ----- apply overrides -----
2448
+ if overrides is not None:
2449
+ names = overrides.keys()
2450
+ for k in range(len(names)):
2451
+ opt[names[k]] = overrides[names[k]]