CONOPT
Loading...
Searching...
No Matches
pinadd2.py
Go to the documentation of this file.
7
8import os
9import sys
10import math
11
12import conopt as co
13
14sys.path.append('../common/')
15import std
16
17
18class PinAdd2ModelData(co.ModelData):
19 """ """
20
21 def __init__(self):
22 self.CONS_SEQ = 0
23 self.CONS_DREV = 1
24
25 self.T = 0
26
27 # index arrays for the variables
28 self.vartd = []
29 self.varcs = []
30 self.vars = []
31 self.vard = []
32 self.varr = []
33 self.varp = []
34 self.varrev = []
35
36 # index arrays for the constraints
37 self.consttdeq = []
38 self.constseq = []
39 self.constcseq = []
40 self.constdeq = []
41 self.constreq = []
42 self.constdrev = []
43
44 self.consmapping = {}
45
46 self.hessianstart = []
47 super().__init__()
48
49 def buildModel(self, T, xkeep, xstat, estat):
50 """
51 adding the variables and constraints to the model
52 @ingroup PYTHON1THREAD_PINADD2
53 """
54
55 self.T = T
56 demand = [1.0 + 2.3 * pow(1.015, t) for t in range(T)]
57
58 # adding the variables to the model
59 for t in range(T):
60 # td: Lower=0, Upper=inf, Curr=18
61 varidx = self.addVariable(0, co.Conopt.Infinity, 18)
62 self.vartd.append(varidx)
63
64 # cs: Lower=0, Upper=inf, Curr=7*t
65 varidx = self.addVariable(0, co.Conopt.Infinity, 7 * (t + 1))
66 self.varcs.append(varidx)
67
68 # s: Lower=0, Upper=inf, Curr=7
69 varidx = self.addVariable(0, co.Conopt.Infinity, 7)
70 self.vars.append(varidx)
71
72 # d: Lower=0, Upper=inf, Curr=td-s
73 varidx = self.addVariable(
74 0,
75 co.Conopt.Infinity,
76 self.getVariable(self.vartd[t]).curr
77 - self.getVariable(self.vars[t]).curr,
78 )
79 self.vard.append(varidx)
80
81 # r: Lower=1, Upper=inf, Curr=r(t-1)-d
82 if t > 0:
83 varidx = self.addVariable(
84 1,
85 co.Conopt.Infinity,
86 self.getVariable(self.varr[t - 1]).curr
87 - self.getVariable(self.vard[t]).curr,
88 )
89 else:
90 varidx = self.addVariable(
91 1,
92 co.Conopt.Infinity,
93 500 - self.getVariable(self.vard[t]).curr,
94 )
95 self.varr.append(varidx)
96
97 # p: Lower=1, Upper=inf, Curr=14
98 varidx = self.addVariable(1, co.Conopt.Infinity, 14)
99 self.varp.append(varidx)
100
101 # rev: Lower=-inf, Upper=inf, Curr=0
102 varidx = self.addVariable(-co.Conopt.Infinity, co.Conopt.Infinity)
103 self.varrev.append(varidx)
104
105 # This is a restart: Use the initial values from last solve for
106 # the variables in the first periods and extrapolate the last
107 # period using a linear extrapolation between the last two
108 # periods.
109 if len(xkeep) > 0:
110 for i in range(len(xkeep)):
111 self.getVariable(i).curr = xkeep[i]
112
113 # linear extrapolation for the last period of variable td
114 self.getVariable(self.vartd[T - 1]).curr = (
115 2 * self.getVariable(self.vartd[T - 2]).curr
116 - self.getVariable(self.vartd[T - 3]).curr
117 )
118 # cs
119 self.getVariable(self.varcs[T - 1]).curr = (
120 2 * self.getVariable(self.varcs[T - 2]).curr
121 - self.getVariable(self.varcs[T - 3]).curr
122 )
123 # s
124 self.getVariable(self.vars[T - 1]).curr = (
125 2 * self.getVariable(self.vars[T - 2]).curr
126 - self.getVariable(self.vars[T - 3]).curr
127 )
128 # d
129 self.getVariable(self.vard[T - 1]).curr = (
130 2 * self.getVariable(self.vard[T - 2]).curr
131 - self.getVariable(self.vard[T - 3]).curr
132 )
133 # r
134 self.getVariable(self.varr[T - 1]).curr = (
135 2 * self.getVariable(self.varr[T - 2]).curr
136 - self.getVariable(self.varr[T - 3]).curr
137 )
138 # p
139 self.getVariable(self.varp[T - 1]).curr = (
140 2 * self.getVariable(self.varp[T - 2]).curr
141 - self.getVariable(self.varp[T - 3]).curr
142 )
143 # rev
144 self.getVariable(self.varrev[T - 1]).curr = (
145 2 * self.getVariable(self.varrev[T - 2]).curr
146 - self.getVariable(self.varrev[T - 3]).curr
147 )
148
149 # The variables from the last solve are given the old status and
150 # the variables in the new period are given those in the last
151 # period. Similarly with the Equation status:
152 for i in range(len(xstat)):
153 self.getVariable(i).varstatus = xstat[i]
154
155 # td
156 self.getVariable(self.vartd[T - 1]).varstatus = self.getVariable(
157 self.vartd[T - 2]
158 ).varstatus
159 # cs
160 self.getVariable(self.varcs[T - 1]).varstatus = self.getVariable(
161 self.varcs[T - 2]
162 ).varstatus
163 # s
164 self.getVariable(self.vars[T - 1]).varstatus = self.getVariable(
165 self.vars[T - 2]
166 ).varstatus
167 # d
168 self.getVariable(self.vard[T - 1]).varstatus = self.getVariable(
169 self.vard[T - 2]
170 ).varstatus
171 # r
172 self.getVariable(self.varr[T - 1]).varstatus = self.getVariable(
173 self.varr[T - 2]
174 ).varstatus
175 # p
176 self.getVariable(self.varp[T - 1]).varstatus = self.getVariable(
177 self.varp[T - 2]
178 ).varstatus
179 # rev
180 self.getVariable(self.varrev[T - 1]).varstatus = self.getVariable(
181 self.varrev[T - 2]
182 ).varstatus
183
184 # adding the objective
185 objcoeff = [pow(1.05, 1 - (t + 1)) for t in range(T)]
186 objnlflag = [0] * T
187 objidx = self.addConstraint(
188 co.ConstraintType_Free, 0.0, self.varrev, objcoeff, objnlflag
189 )
190
191 # adding the constraints to the model
192 for t in range(T):
193 if t == 0:
194 considx = self.addConstraint(
195 co.ConstraintType_Eq,
196 demand[t] + 0.87 * 18.0,
197 [self.vartd[t], self.varp[t]], # the variables
198 [1.0, 0.13], # the coefficients
199 [0, 0], # nlflags
200 )
201 else:
202 considx = self.addConstraint(
203 co.ConstraintType_Eq,
204 demand[t],
205 [self.vartd[t], self.vartd[t - 1], self.varp[t]],
206 [1.0, -0.87, 0.13],
207 [0, 0, 0],
208 )
209 self.consttdeq.append(considx)
210
211 if t == 0:
212 considx = self.addConstraint(
213 co.ConstraintType_Eq,
214 0.75 * 6.5,
215 [self.vars[t], self.varp[t], self.varcs[t]],
216 [1.0, 0.0, 0.0],
217 [0, 1, 1],
218 )
219 else:
220 considx = self.addConstraint(
221 co.ConstraintType_Eq,
222 0.0,
223 [
224 self.vars[t],
225 self.vars[t - 1],
226 self.varp[t],
227 self.varcs[t],
228 ],
229 [1.0, -0.75, 0.0, 0.0],
230 [0, 0, 1, 1],
231 )
232 self.constseq.append(considx)
233 self.consmapping[considx] = (self.CONS_SEQ, t)
234
235 if t == 0:
236 considx = self.addConstraint(
237 co.ConstraintType_Eq,
238 0.0,
239 [self.varcs[t], self.vars[t]],
240 [1.0, -1.0],
241 [0, 0],
242 )
243 else:
244 considx = self.addConstraint(
245 co.ConstraintType_Eq,
246 0.0,
247 [self.varcs[t], self.varcs[t - 1], self.vars[t]],
248 [1.0, -1.0, -1.0],
249 [0, 0, 0],
250 )
251 self.constcseq.append(considx)
252
253 considx = self.addConstraint(
254 co.ConstraintType_Eq,
255 0.0,
256 [self.vard[t], self.vartd[t], self.vars[t]],
257 [1.0, -1.0, 1.0],
258 [0, 0, 0],
259 )
260 self.constdeq.append(considx)
261
262 if t == 0:
263 considx = self.addConstraint(
264 co.ConstraintType_Eq,
265 500.0,
266 [self.varr[t], self.vard[t]],
267 [1.0, 1.0],
268 [0, 0],
269 )
270 else:
271 considx = self.addConstraint(
272 co.ConstraintType_Eq,
273 0.0,
274 [self.varr[t], self.varr[t - 1], self.vard[t]],
275 [1.0, -1.0, 1.0],
276 [0, 0, 0],
277 )
278 self.constreq.append(considx)
279
280 considx = self.addConstraint(
281 co.ConstraintType_Eq,
282 0.0,
283 [self.varrev[t], self.vard[t], self.varp[t], self.varr[t]],
284 [1.0, 0.0, 0.0, 0.0],
285 [0, 1, 1, 1],
286 )
287 self.constdrev.append(considx)
288 self.consmapping[considx] = (self.CONS_DREV, t)
289
290 # Restore values from previous runs
291 if len(estat) > 0:
292 # the equation status
293 for i in range(len(estat)):
294 self.getConstraint(i).slackstatus = estat[i]
295
296 # tdeq
297 self.getConstraint(
298 self.consttdeq[T - 1]
299 ).slackstatus = self.getConstraint(self.consttdeq[T - 2]).slackstatus
300 # seq
301 self.getConstraint(
302 self.constseq[T - 1]
303 ).slackstatus = self.getConstraint(self.constseq[T - 2]).slackstatus
304 # cseq
305 self.getConstraint(
306 self.constcseq[T - 1]
307 ).slackstatus = self.getConstraint(self.constcseq[T - 2]).slackstatus
308 # deq
309 self.getConstraint(
310 self.constdeq[T - 1]
311 ).slackstatus = self.getConstraint(self.constdeq[T - 2]).slackstatus
312 # req
313 self.getConstraint(
314 self.constreq[T - 1]
315 ).slackstatus = self.getConstraint(self.constreq[T - 2]).slackstatus
316 # drev
317 self.getConstraint(
318 self.constdrev[T - 1]
319 ).slackstatus = self.getConstraint(self.constdrev[T - 2]).slackstatus
320
321 # setting the objective constraint
322 self.setObjectiveElement(co.ObjectiveElement_Constraint, objidx)
323
324 # setting the optimisation direction
325 self.setOptimizationSense(co.Sense_Maximize)
326
327 hsrow = []
328 hscol = []
329
330 for t in range(T):
331 # storing the start index for the hessian in each time period.
332 # This will provide a mapping that can be used in the hessian
333 # evaluation
334 self.hessianstart.append(len(hscol))
335
336 hscol.append(self.varcs[t])
337 hsrow.append(self.varcs[t])
338 hscol.append(self.varcs[t])
339 hsrow.append(self.varp[t])
340 hscol.append(self.vard[t])
341 hsrow.append(self.varr[t])
342 hscol.append(self.vard[t])
343 hsrow.append(self.varp[t])
344 hscol.append(self.varr[t])
345 hsrow.append(self.varr[t])
346 self.setSDLagrangianStructure(hsrow, hscol)
347
348 def evaluateNonlinearTerm(self, x, rowno, ignerr, thread):
349 """
350 @copydoc conopt.ModelData.evaluateNonlinearTerm
351 @ingroup PYTHON1THREAD_PINADD2
352 """
353 if rowno not in self.consmapping:
354 return
355
356 # unpack consset and time index
357 consset, t = self.consmapping[rowno]
358 assert consset in (self.CONS_SEQ, self.CONS_DREV)
359
360 g = 0
361 if consset == self.CONS_SEQ:
362 h1 = 1.1 + 0.1 * x[self.varp[t]]
363 h2 = pow(1.02, -x[self.varcs[t]] / 7.0)
364 g = -h1 * h2
365
366 elif consset == self.CONS_DREV:
367 g = -x[self.vard[t]] * (x[self.varp[t]] - 250.0 / x[self.varr[t]])
368
369 return g
370
371 def evaluateNonlinearJacobian(self, x, rowno, jacnum, ignerr, thread):
372 """
373 @copydoc conopt.ModelData.evaluateNonlinearJacobian
374 @ingroup PYTHON1THREAD_PINADD2
375 """
376 if rowno not in self.consmapping:
377 return
378
379 # unpack consset and time index
380 consset, t = self.consmapping[rowno]
381 assert consset in (self.CONS_SEQ, self.CONS_DREV)
382
383 jac = []
384 if consset == self.CONS_SEQ:
385 h1 = 1.1 + 0.1 * x[self.varp[t]]
386 h2 = pow(1.02, -x[self.varcs[t]] / 7.0)
387 jac.append(h1 * h2 * math.log(1.02) / 7.0)
388 jac.append(-h2 * 0.1)
389
390 elif consset == self.CONS_DREV:
391 jac.append(-(x[self.varp[t]] - 250.0 / x[self.varr[t]]))
392 jac.append(-x[self.vard[t]] * 250.0 / pow(x[self.varr[t]], 2))
393 jac.append(-x[self.vard[t]])
394
395 return jac
396
397 def evaluateSDLagrangian(self, x, u, hessianrow, hessiancol):
398 """
399 @copydoc conopt.ModelData.evaluateSDLagrangian
400 @ingroup PYTHON1THREAD_PINADD2
401 """
402 numhessian = len(hessianrow)
403 hessian = [0 for i in range(numhessian)]
404
405 # Normal Evaluation mode
406 for t in range(self.T):
407 hessidx = self.hessianstart[t]
408 cs = x[self.varcs[t]]
409 d = x[self.vard[t]]
410 r = x[self.varr[t]]
411 p = x[self.varp[t]]
412
413 h1 = 1.1 + 0.1 * p
414 h2 = pow(1.02, -cs / 7.0)
415
416 # the second derivative of the SEQ equations
417 hessian[hessidx] = (
418 -h1 * h2 * pow(math.log(1.02) / 7.0, 2) * u[self.constseq[t]]
419 )
420 hessian[hessidx + 1] = (
421 0.1 * h2 * (math.log(1.02) / 7.0) * u[self.constseq[t]]
422 )
423
424 # the second derivative of the DREV equations
425 hessian[hessidx + 2] = -250.0 / pow(r, 2) * u[self.constdrev[t]]
426 hessian[hessidx + 3] = -1.0 * u[self.constdrev[t]]
427 hessian[hessidx + 4] = 500.0 * d / pow(r, 3) * u[self.constdrev[t]]
428
429 return hessian
430
431
432if __name__ == '__main__':
433 name = os.path.basename(__file__)[:-3]
434
435 conopt = co.Conopt(name)
436 msghdlr = std.TutMessageHandler(name)
437 conopt.setMessageHandler(msghdlr)
438
439 # getting the license variables
440 license_int_1 = os.environ.get('CONOPT_LICENSE_INT_1', None)
441 license_int_2 = os.environ.get('CONOPT_LICENSE_INT_2', None)
442 license_int_3 = os.environ.get('CONOPT_LICENSE_INT_3', None)
443 license_text = os.environ.get('CONOPT_LICENSE_TEXT', None)
444 if (
445 license_int_1 is not None
446 and license_int_2 is not None
447 and license_int_3 is not None
448 and license_text is not None
449 ):
450 conopt.setLicense(
451 int(license_int_1),
452 int(license_int_2),
453 int(license_int_3),
454 license_text,
455 )
456
457 expected_sols = [1170.49, 1225.86, 1280.28, 1333.74, 1386.24]
458 for i in range(16, 21):
459 model = PinAdd2ModelData()
460
461 xkeep = conopt.getVariableValues()
462 xstat = conopt.getVariableStatus()
463 estat = conopt.getConstraintStatus()
464
465 # building the model
466 model.buildModel(
467 i, xkeep, xstat, estat
468 ) # Add T, and other vectors as parameters
469
470 conopt.loadModel(model)
471
472 coi_error = conopt.solve()
473
474 retcode = std.checkSolve(
475 conopt, expected_sols[i - 16], coi_error, tol=0.01
476 )
477
478 sys.exit(retcode)
static int checkSolve(String name, int model_status, int solution_status, double objective, double expected_objective, double tol)
Definition std.java:20
evaluateNonlinearTerm(self, x, rowno, ignerr, thread)
callback method for evaluating the nonlinear terms in a given row
Definition pinadd2.py:348
evaluateNonlinearJacobian(self, x, rowno, jacnum, ignerr, thread)
callback method for evaluating the jacobian for the nonlinear terms in a given row
Definition pinadd2.py:371
buildModel(self, T, xkeep, xstat, estat)
adding the variables and constraints to the model
Definition pinadd2.py:49
evaluateSDLagrangian(self, x, u, hessianrow, hessiancol)
Computes and returns the numerical values of the Lagrangian of the Hessian.
Definition pinadd2.py:397