CONOPT
Loading...
Searching...
No Matches
pinadd2ddir.cpp
Go to the documentation of this file.
1
7
8#include <stdlib.h>
9#include <stdio.h>
10#include <math.h>
11#include <string.h>
12#include <iostream>
13#include <map>
14#include <utility>
15#include "conopt.hpp"
16#include <cassert>
17
18#define CONS_SEQ 0
19#define CONS_DREV 1
20
22{
23public:
24 int T = 0;
25
26 /* the demand vector */
27 std::vector<double> demand;
28
29 /* index arrays for the variables */
30 std::vector<int> vartd;
31 std::vector<int> varcs;
32 std::vector<int> vars;
33 std::vector<int> vard;
34 std::vector<int> varr;
35 std::vector<int> varp;
36 std::vector<int> varrev;
37
38 /* index arrays for the constraints */
39 std::vector<int> consttdeq;
40 std::vector<int> constseq;
41 std::vector<int> constcseq;
42 std::vector<int> constdeq;
43 std::vector<int> constreq;
44 std::vector<int> constdrev;
45
46 std::map<int, std::pair<int, int>> consmapping;
47
48 std::vector<int> hessianstart;
49
53 void buildModel(int T, const std::vector<double> &xkeep, const std::vector<int> &xstat,
54 const std::vector<int> &estat)
55 {
56 int varidx;
57 this->T = T;
58
59 /* defining the demand for each time period. */
60 for (int t = 0; t < T; t++)
61 demand.push_back(1.0 + 2.3 * pow(1.015, t));
62
87
88 for (int t = 0; t < T; t++)
89 {
90 /* td: Lower=0, Upper=inf, Curr=18 */
91 varidx = addVariable(0, Conopt::Infinity, 18);
92 vartd.push_back(varidx);
93
94 /* cs: Lower=0, Upper=inf, Curr=7*t */
95 varidx = addVariable(0, Conopt::Infinity, 7 * (t + 1));
96 varcs.push_back(varidx);
97
98 /* s: Lower=0, Upper=inf, Curr=7 */
99 varidx = addVariable(0, Conopt::Infinity, 7);
100 vars.push_back(varidx);
101
102 /* d: Lower=0, Upper=inf, Curr=td-s */
103 varidx =
105 vard.push_back(varidx);
106
107 /* r: Lower=1, Upper=inf, Curr=r(t-1)-d */
108 if (t > 0)
109 varidx = addVariable(
110 1, Conopt::Infinity, getVariable(varr[t - 1]).curr - getVariable(vard[t]).curr);
111 else
112 varidx = addVariable(1, Conopt::Infinity, 500 - getVariable(vard[t]).curr);
113 varr.push_back(varidx);
114
115 /* p: Lower=1, Upper=inf, Curr=14 */
116 varidx = addVariable(1, Conopt::Infinity, 14);
117 varp.push_back(varidx);
118
119 /* rev: Lower=-inf, Upper=inf, Curr=0 */
121 varrev.push_back(varidx);
122 }
123
130 if (xkeep.size() > 0)
131 {
132 for (size_t i = 0; i < xkeep.size(); i++)
133 {
134 getVariable(i).curr = xkeep[i];
135 }
136
137 /* linear extrapolation for the last period of variable td */
138 getVariable(vartd[T - 1]).curr =
139 2 * getVariable(vartd[T - 2]).curr - getVariable(vartd[T - 3]).curr;
140 /* cs */
141 getVariable(varcs[T - 1]).curr =
142 2 * getVariable(varcs[T - 2]).curr - getVariable(varcs[T - 3]).curr;
143 /* s */
144 getVariable(vars[T - 1]).curr =
145 2 * getVariable(vars[T - 2]).curr - getVariable(vars[T - 3]).curr;
146 /* d */
147 getVariable(vard[T - 1]).curr =
148 2 * getVariable(vard[T - 2]).curr - getVariable(vard[T - 3]).curr;
149 /* r */
150 getVariable(varr[T - 1]).curr =
151 2 * getVariable(varr[T - 2]).curr - getVariable(varr[T - 3]).curr;
152 /* p */
153 getVariable(varp[T - 1]).curr =
154 2 * getVariable(varp[T - 2]).curr - getVariable(varp[T - 3]).curr;
155 /* rev */
156 getVariable(varrev[T - 1]).curr =
157 2 * getVariable(varrev[T - 2]).curr - getVariable(varrev[T - 3]).curr;
158
164 for (size_t i = 0; i < xstat.size(); i++)
165 {
166 getVariable(i).varstatus = xstat[i];
167 }
168
169 /* td */
171 /* cs */
173 /* s */
175 /* d */
177 /* r */
179 /* p */
181 /* rev */
183 }
184
185 /* adding the objective */
186 std::vector<double> objcoeff;
187 std::vector<int> objnlflag(T, 0);
188 for (int t = 0; t < T; ++t)
189 {
190 objcoeff.push_back(pow(1.05, 1 - (t + 1)));
191 }
192 int objidx = addConstraint(ConoptConstraintType::Free, 0.0, varrev, objcoeff, objnlflag);
193
194 /* adding the constraint information */
195 int considx;
196 for (int t = 0; t < T; t++)
197 {
198 /* adding the tdeq equations
199 * for the initial time period, the fixed value for td_{t - 1} is applied to the RHS
200 *
201 * tdeq(t): td(t) = 0.87*td(t-1) - 0.13*p(t) + demand(t)
202 *
203 * In GAMS, td("1974") is fixed (td.fx = 18), and the first equation is for 1975.
204 * So here for t=0 (1974), we apply the fixed value 18.0 directly on the RHS.
205 *
206 * That is why below we check if t == 0 and apply the fixed value of 18.0 directly
207 * to the RHS. Otherwise, we use the value of td(t-1) from the previous period.
208 *
209 * The same applies to the remaining equations.
210 */
211 if (t == 0)
212 {
213 considx = addConstraint(ConoptConstraintType::Eq, demand[t] + 0.87 * 18.0,
214 {vartd[t], varp[t]}, // the variables
215 {1.0, 0.13}, // the coefficients
216 {0, 0} // nlflags
217 );
218 }
219 else
220 {
222 {vartd[t], vartd[t - 1], varp[t]}, {1.0, -0.87, 0.13}, {0, 0, 0});
223 }
224 consttdeq.push_back(considx);
225
226 /* adding the seq Equations
227 * for the initial time period, the fixed value of s(1974)=6.5 is applied to the RHS
228 * GAMS: s(t) = 0.75*s(t-1) + (1.1+0.1*p(t))*1.02^(-cs(t)/7)
229 */
230 if (t == 0)
231 {
232 considx = addConstraint(ConoptConstraintType::Eq, 0.75 * 6.5,
233 {vars[t], varp[t], varcs[t]}, {1.0, 0.0, 0.0}, {0, 1, 1});
234 }
235 else
236 {
238 {vars[t], vars[t - 1], varp[t], varcs[t]}, {1.0, -0.75, 0.0, 0.0}, {0, 0, 1, 1});
239 }
240 constseq.push_back(considx);
241
242 /* storing the constraint index for the seq constraint, so that we can identify then
243 * constraint in FDEval
244 */
245 consmapping.emplace(considx, std::make_pair(CONS_SEQ, t));
246
247 /* adding the cseq Equations
248 * for the initial time period, cs(1974)=0.0
249 * cs(t) = cs(t-1) + s(t)
250 * So for t=0, we use cs(0) = s(0) and drop cs(t-1)
251 */
252 if (t == 0)
253 {
254 considx = addConstraint(
255 ConoptConstraintType::Eq, 0.0, {varcs[t], vars[t]}, {1.0, -1.0}, {0, 0});
256 }
257 else
258 {
260 {varcs[t], varcs[t - 1], vars[t]}, {1.0, -1.0, -1.0}, {0, 0, 0});
261 }
262 constcseq.push_back(considx);
263
264 /* adding the deq equations */
265 considx = addConstraint(ConoptConstraintType::Eq, 0.0, {vard[t], vartd[t], vars[t]},
266 {1.0, -1.0, 1.0}, {0, 0, 0});
267 constdeq.push_back(considx);
268
269 /* adding the req equations
270 * for the initial time period, the value of r(1974)=500 is applied to the RHS
271 * r(t) = r(t-1) - d(t)
272 * So for t=0, we use r(0) + d(0) = 500
273 */
274 if (t == 0)
275 {
276 considx = addConstraint(
277 ConoptConstraintType::Eq, 500.0, {varr[t], vard[t]}, {1.0, 1.0}, {0, 0});
278 }
279 else
280 {
281 considx = addConstraint(ConoptConstraintType::Eq, 0.0, {varr[t], varr[t - 1], vard[t]},
282 {1.0, -1.0, 1.0}, {0, 0, 0});
283 }
284 constreq.push_back(considx);
285
286 /* adding the drev equations */
288 {varrev[t], vard[t], varp[t], varr[t]}, {1.0, 0.0, 0.0, 0.0}, {0, 1, 1, 1});
289 constdrev.push_back(considx);
290
291 /* storing the constraint index for the drev constraint, so that we can identify then
292 * constraint in FDEval
293 */
294 consmapping.emplace(considx, std::make_pair(CONS_DREV, t));
295 }
296
297 /* Restore values from previous runs */
298 if (estat.size() > 0)
299 {
300 /* the equation status */
301 for (size_t i = 0; i < estat.size(); i++)
302 {
303 getConstraint(i).slackstatus = estat[i];
304 }
305
306 /* tdeq */
308 /* seq */
310 /* cseq */
312 /* deq */
314 /* req */
316 /* drev */
318 }
319
320 /* setting the objective constraint */
322
323 /* setting the optimisation direction */
325
326 /*
327 There are two nonlinear constraints, Sdef and RevDef and they have
328 the following Hessians (for each time period):
329
330 Revdef equation. Nonlinear term = -d*(p-250/r)
331 Hessian (diagonal and lower triangle): A total of 3 nonzero elements per period
332 3 4 5
333 d r p
334 3 : d
335 4 : r -250/r**2 500*d/r**3
336 5 : p -1
337
338 Sdef: Nonlinear term = -(1.1+0.1p)*1.02**(-cs/7)
339 Hessian (diagonal and lower triangle): A total of 2 nonzero elements per period
340 1 5
341 cs p
342 1 : cs -(1.1+0.1p)*1.02**(-cs/7)*(log(1.02)/7)**2
343 5 : p 0.1*1.02**(-cs/7)*(log(1.02)72)
344
345 The two Hessian matrices do not overlap so the total number of nonzeros is
346 5 per period. The structure using numerical indices for rows and columns and
347 running indices for the Hessian element is:
348
349 1 3 4 5
350 1 0
351 3
352 4 2 4
353 5 1 3
354
355 and the same with names of variables and contributing equations
356 cs d r p
357 cs sdef
358 d
359 r revdef revdef
360 p sdef revdef
361 */
362 /* setting the structure of the hessian.
363 * NOTE: the hessian must be in increasing order of columns, and then
364 * rows. Care must be taken to ensure that the variables are referenced
365 * in the correct order.
366 */
367 std::vector<int> hsrow;
368 std::vector<int> hscol;
369
370 for (int t = 0; t < T; ++t)
371 {
372 /* storing the start index for the hessian in each time period.
373 * This will provide a mapping that can be used in the hessian
374 * evaluation
375 */
376 hessianstart.push_back(hscol.size());
377
378 hscol.push_back(varcs[t]);
379 hsrow.push_back(varcs[t]);
380 hscol.push_back(varcs[t]);
381 hsrow.push_back(varp[t]);
382 hscol.push_back(vard[t]);
383 hsrow.push_back(varr[t]);
384 hscol.push_back(vard[t]);
385 hsrow.push_back(varp[t]);
386 hscol.push_back(varr[t]);
387 hsrow.push_back(varr[t]);
388 }
389 setSDLagrangianStructure(hsrow, hscol);
390 }
391
396 int FDEval(const double x[], double *g, double jac[], int rowno, const int jacnum[], int mode,
397 int ignerr, int *errcnt, int numvar, int numjac, int thread) override
398 {
399 /* returning an iterator based on the row number.
400 * NOTE: a map is just an array of pairs. So for the iterator, the
401 * first element is the key and the second is the value. In our case,
402 * then value is also a pair.
403 */
404 auto itr = consmapping.find(rowno);
405 if (itr == consmapping.end())
406 return 0;
407
408 /* storing the value (a pair) as a separate variable to make the
409 * extraction easier
410 */
411 auto conspair = itr->second;
412 /* I think that this will be a .first and .second. It could be ->first
413 * and ->second
414 */
415 int consset = conspair.first;
416 int t = conspair.second;
417 assert(consset == CONS_SEQ || consset == CONS_DREV);
418
419 if (consset == CONS_SEQ)
420 {
421 double h1, h2;
422 /* seq equation. Nonlinear term = -(1.1+0.1*p(t))*1.02**(-cs(t)/7) */
423
424 h1 = (1.1 + 0.1 * x[varp[t]]);
425 h2 = pow(1.02, -x[varcs[t]] / 7.0);
426 if (1 == mode || 3 == mode)
427 *g = -h1 * h2;
428 if (2 == mode || 3 == mode)
429 {
430 jac[varcs[t]] = h1 * h2 * log(1.02) / 7.0;
431 jac[varp[t]] = -h2 * 0.1;
432 }
433 }
434 else if (consset == CONS_DREV)
435 {
436 /* drev equation. Nonlinear term = -d(to)*(p(to)-250/r(to)) */
437
438 if (1 == mode || 3 == mode)
439 *g = -x[vard[t]] * (x[varp[t]] - 250. / x[varr[t]]);
440 if (2 == mode || 3 == mode)
441 {
442 jac[vard[t]] = -(x[varp[t]] - 250. / x[varr[t]]);
443 jac[varr[t]] = -x[vard[t]] * 250. / pow(x[varr[t]], 2);
444 jac[varp[t]] = -x[vard[t]];
445 }
446 }
447
448 return 0;
449 }
450
455 int SDDir(const double x[], const double dx[], double d2g[], int rowno, const int jacnum[],
456 int *nodrv, int numvar, int numjac, int thread) override
457 {
458 /* returning an iterator based on the row number.
459 * NOTE: a map is just an array of pairs. So for the iterator, the
460 * first element is the key and the second is the value. In our case,
461 * then value is also a pair.
462 */
463 auto itr = consmapping.find(rowno);
464 if (itr == consmapping.end())
465 return 0;
466
467 /* storing the value (a pair) as a separate variable to make the
468 * extraction easier
469 */
470 auto conspair = itr->second;
471 /* I think that this will be a .first and .second. It could be ->first
472 * and ->second
473 */
474 int consset = conspair.first;
475 int t = conspair.second;
476
477 if (consset == CONS_SEQ)
478 {
479 /* seq equation. Nonlinear term = -(1.1+0.1*p)*1.02**(-cs/7) */
480 /* Hessian (diagonal and lower triangle): A total of 2 nonzero elements per period
481 1 5
482 cs p
483 1 : cs -(1.1+0.1p)*1.02**(-cs/7)*(log(1.02)/7)**2
484 5 : p 0.1*1.02**(-cs/7)*(log(1.02)72) */
485
486 double cs = x[varcs[t]];
487 double p = x[varp[t]];
488 double h1 = 1.1 + 0.1 * p;
489 double h2 = pow(1.02, -cs / 7.0);
490 double h11 = -h1 * h2 * pow(log(1.02) / 7.0, 2);
491 double h15 = 0.1 * h2 * (log(1.02) / 7.);
492 d2g[varcs[t]] = h11 * dx[varcs[t]] + h15 * dx[varp[t]];
493 d2g[varp[t]] = h15 * dx[varcs[t]];
494 }
495 else if (consset == CONS_DREV)
496 {
497 /* drev equation. Nonlinear term = -d*(p-250/r) */
498 /* Hessian (diagonal and lower triangle): A total of 3 nonzero elements per period
499 3 4 5
500 d r p
501 3 : d
502 4 : r -250/r**2 500*d/r**3
503 5 : p -1 */
504 double d = x[vard[t]];
505 double r = x[varr[t]];
506 double h34 = -250.0 / pow(r, 2);
507 double h35 = -1.0;
508 double h44 = 500.0 * d / pow(r, 3);
509 d2g[vard[t]] = h34 * dx[varr[t]] + h35 * dx[varp[t]];
510 d2g[varr[t]] = h34 * dx[vard[t]] + h44 * dx[varr[t]];
511 d2g[varp[t]] = h35 * dx[vard[t]];
512 }
513 else
514 {
515 /* Error - this equation is not nonlinear */
516 printf("\nError. Pin_2DDir called with rowno = %d.\n\n", rowno);
517 return 1;
518 }
519
520 return 0;
521 }
522
527 int SDLagrVal(const double x[], const double u[], const int hsrw[], const int hscl[],
528 double hsvl[], int *nodrv, int numvar, int numcon, int nhess) override
529 {
530 double cs, d, r, p;
531 double h1, h2;
532
533 /* Normal Evaluation mode */
534 for (int t = 0; t < T; t++)
535 {
536 int hessidx = hessianstart[t];
537 cs = x[varcs[t]];
538 d = x[vard[t]];
539 r = x[varr[t]];
540 p = x[varp[t]];
541
542 h1 = 1.1 + 0.1 * p;
543 h2 = pow(1.02, -cs / 7.0);
544 /* the second derivative of the SEQ equations */
545 hsvl[hessidx] = -h1 * h2 * pow(log(1.02) / 7.0, 2) * u[constseq[t]];
546 hsvl[hessidx + 1] = 0.1 * h2 * (log(1.02) / 7.) * u[constseq[t]];
547
548 /* the second derivative of the DREV equations */
549 hsvl[hessidx + 2] = -250.0 / pow(r, 2) * u[constdrev[t]];
550 hsvl[hessidx + 3] = -1.0 * u[constdrev[t]];
551 hsvl[hessidx + 4] = 500.0 * d / pow(r, 3) * u[constdrev[t]];
552 }
553
554 return 0;
555 }
556};
557
558#include "std.cpp"
559
563int main(int argc, char **argv)
564{
565 int COI_Error = 0;
566
567 // getting the program name from the executable path
568 std::string pname = getProgramName(argv[0]);
569
570 // initialising the Conopt Object
572 Tut_MessageHandler msghandler(pname);
573
574 // adding the message handler to the conopt interface
575 conopt.setMessageHandler(msghandler);
576
577 for (int i = 16; i <= 20; i++)
578 {
579
580 PADD2DIR_ModelData modeldata;
581
582 auto xkeep = conopt.getVariableValues();
583 auto xstat = conopt.getVariableStatus();
584 auto estat = conopt.getConstraintStatus();
585
586 // building the model
587 modeldata.buildModel(i, xkeep, xstat, estat); // Add T, and other vectors as parameters
588
589 // loading the model in the conopt object
590 conopt.loadModel(modeldata);
591
592#if defined(CONOPT_LICENSE_INT_1) && defined(CONOPT_LICENSE_INT_2) && defined(CONOPT_LICENSE_INT_3) && defined(CONOPT_LICENSE_TEXT)
593 std::string license = CONOPT_LICENSE_TEXT;
594 COI_Error += conopt.setLicense(CONOPT_LICENSE_INT_1, CONOPT_LICENSE_INT_2, CONOPT_LICENSE_INT_3, license);
595#endif
596
597 if (COI_Error)
598 {
599 conopt.sendMessage(
600 "Skipping COI_Solve due to setup errors. COI_Error = " + std::to_string(COI_Error));
601 cpp_log(conopt, "Skipping Solve due to setup errors", COI_Error);
602 }
603
604 COI_Error = conopt.solve(); /* Optimize */
605
606 conopt.sendMessage("After solving. COI_Error = " + std::to_string(COI_Error));
607 if (conopt.modelStatus() != 2 || conopt.solutionStatus() != 1)
608 cpp_log(conopt, "Incorrect Model or Solver Status", -1);
609
610 conopt.printStatus();
611 }
612 cpp_log(conopt, "Successful Solve", COI_Error);
613}
The Conopt class.
Definition conopt.hpp:27
static constexpr double Infinity
Definition conopt.hpp:30
std::vector< int > consttdeq
std::vector< int > constreq
std::vector< int > constcseq
std::vector< double > demand
std::vector< int > constdeq
std::vector< int > vard
std::vector< int > varcs
std::vector< int > vartd
std::vector< int > varr
std::vector< int > varrev
std::vector< int > constseq
std::vector< int > hessianstart
std::vector< int > varp
std::vector< int > vars
std::map< int, std::pair< int, int > > consmapping
std::vector< int > constdrev
char pname[MAXLINE]
Definition comdecl.h:10
int COI_Error
Definition comdecl.h:15
CONOPT C++ interface header file. This is the main object for the CONOPT C++ interface.
int SDLagrVal(const double x[], const double u[], const int hsrw[], const int hscl[], double hsvl[], int *nodrv, int numvar, int numcon, int nhess) override
Computes and returns the numerical values of the Hessian.
int main(int argc, char **argv)
Main program. A simple setup and call of CONOPT.
int FDEval(const double x[], double *g, double jac[], int rowno, const int jacnum[], int mode, int ignerr, int *errcnt, int numvar, int numjac, int thread) override
defines the nonlinearities of the model by returning numerical values.
int SDDir(const double x[], const double dx[], double d2g[], int rowno, const int jacnum[], int *nodrv, int numvar, int numjac, int thread) override
computes the directional second derivative for a single constraint
void buildModel(int T, const std::vector< double > &xkeep, const std::vector< int > &xstat, const std::vector< int > &estat)
adds the variables and constraints for the problem
int addVariable(double lower, double upper, double curr=0, int varstatus=-1)
adds a variable to the model. The non-zero coefficients are added later.
void setObjectiveElement(ConoptObjectiveElement elem, int elemindex)
sets the index for the objective variable or constraint
int addConstraint(ConoptConstraintType constype, double rhs, int slackstatus=-1)
adds a constraint to the problem. The non-zero coefficients are added later
void setOptimizationSense(ConoptSense sense)
sets the optimisation direction.
void setSDLagrangianStructure(const std::vector< int > &rownum, const std::vector< int > &colnum)
sets the structure of the second derivatives of the Lagrangian
const ConoptConstraint & getConstraint(int index) const
returns a reference to the constraint object
const ConoptVariable & getVariable(int index) const
returns a reference to the variable object
double xkeep[Tmax *Tmax *Vpp]
#define CONS_SEQ
#define CONS_DREV
void cpp_log(Conopt &conopt, std::string msg, int code)
Definition std.cpp:111
std::string getProgramName(char *execname)
Definition std.cpp:95