CONOPT
Loading...
Searching...
No Matches
pinadd2err.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
383 /* the row index for this entry is an error. */
384 hscol.push_back(vard[t]);
385 hsrow.push_back(vard[t]);
386
387 /* these entries are correct */
388 hscol.push_back(vard[t]);
389 hsrow.push_back(varp[t]);
390 hscol.push_back(varr[t]);
391 hsrow.push_back(varr[t]);
392 }
393 setSDLagrangianStructure(hsrow, hscol);
394 }
395
400 int FDEval(const double x[], double *g, double jac[], int rowno, const int jacnum[], int mode,
401 int ignerr, int *errcnt, int numvar, int numjac, int thread) override
402 {
403 /* returning an iterator based on the row number.
404 * NOTE: a map is just an array of pairs. So for the iterator, the
405 * first element is the key and the second is the value. In our case,
406 * then value is also a pair.
407 */
408 auto itr = consmapping.find(rowno);
409 if (itr == consmapping.end())
410 return 0;
411
412 /* storing the value (a pair) as a separate variable to make the
413 * extraction easier
414 */
415 auto conspair = itr->second;
416 /* I think that this will be a .first and .second. It could be ->first
417 * and ->second
418 */
419 int consset = conspair.first;
420 int t = conspair.second;
421 assert(consset == CONS_SEQ || consset == CONS_DREV);
422
423 if (consset == CONS_SEQ)
424 {
425 double h1, h2;
426 /* seq equation. Nonlinear term = -(1.1+0.1*p(t))*1.02**(-cs(t)/7) */
427
428 h1 = (1.1 + 0.1 * x[varp[t]]);
429 h2 = pow(1.02, -x[varcs[t]] / 7.0);
430 if (1 == mode || 3 == mode)
431 *g = -h1 * h2;
432 if (2 == mode || 3 == mode)
433 {
434 jac[varcs[t]] = h1 * h2 * log(1.02) / 7.0;
435 jac[varp[t]] = -h2 * 0.1;
436 }
437 }
438 else if (consset == CONS_DREV)
439 {
440 /* drev equation. Nonlinear term = -d(to)*(p(to)-250/r(to)) */
441
442 if (1 == mode || 3 == mode)
443 *g = -x[vard[t]] * (x[varp[t]] - 250. / x[varr[t]]);
444 if (2 == mode || 3 == mode)
445 {
446 jac[vard[t]] = -(x[varp[t]] - 250. / x[varr[t]]);
447 jac[varr[t]] = -x[vard[t]] * 250. / pow(x[varr[t]], 2);
448 jac[varp[t]] = -x[vard[t]];
449 }
450 }
451
452 return 0;
453 }
454
459 int SDLagrVal(const double x[], const double u[], const int hsrw[], const int hscl[],
460 double hsvl[], int *nodrv, int numvar, int numcon, int nhess) override
461 {
462 double cs, d, r, p;
463 double h1, h2;
464
465 /* Normal Evaluation mode */
466 for (int t = 0; t < T; t++)
467 {
468 int hessidx = hessianstart[t];
469 cs = x[varcs[t]];
470 d = x[vard[t]];
471 r = x[varr[t]];
472 p = x[varp[t]];
473
474 h1 = 1.1 + 0.1 * p;
475 h2 = pow(1.02, -cs / 7.0);
476 /* the second derivative of the SEQ equations */
477 hsvl[hessidx] = -h1 * h2 * pow(log(1.02) / 7.0, 2) * u[constseq[t]];
478 hsvl[hessidx + 1] = 0.1 * h2 * (log(1.02) / 7.) * u[constseq[t]];
479
480 /* the second derivative of the DREV equations */
481 hsvl[hessidx + 2] = -250.0 / pow(r, 2) * u[constdrev[t]];
482 hsvl[hessidx + 3] = -1.0 * u[constdrev[t]];
483 hsvl[hessidx + 4] = 500.0 * d / pow(r, 3) * u[constdrev[t]];
484 }
485
486 return 0;
487 }
488};
489
490#include "std.cpp"
491
495int main(int argc, char **argv)
496{
497 int COI_Error = 0;
498
499 // getting the program name from the executable path
500 std::string pname = getProgramName(argv[0]);
501
502 // initialising the Conopt Object
504 Tut_MessageHandler msghandler(pname);
505
506 // adding the message handler to the conopt interface
507 conopt.setMessageHandler(msghandler);
508
509 /* Turn debugging of FDEval on or off: -1 means first call only */
510 conopt.debugFV(-1);
511
512 for (int i = 16; i <= 20; i++)
513 {
514
515 PADD2ERR_ModelData modeldata;
516
517 auto xkeep = conopt.getVariableValues();
518 auto xstat = conopt.getVariableStatus();
519 auto estat = conopt.getConstraintStatus();
520
521 // building the model
522 modeldata.buildModel(i, xkeep, xstat, estat); // Add T, and other vectors as parameters
523
524 // loading the model in the conopt object
525 conopt.loadModel(modeldata);
526
527#if defined(CONOPT_LICENSE_INT_1) && defined(CONOPT_LICENSE_INT_2) && defined(CONOPT_LICENSE_INT_3) && defined(CONOPT_LICENSE_TEXT)
528 std::string license = CONOPT_LICENSE_TEXT;
529 COI_Error += conopt.setLicense(CONOPT_LICENSE_INT_1, CONOPT_LICENSE_INT_2, CONOPT_LICENSE_INT_3, license);
530#endif
531
532 if (COI_Error)
533 {
534 conopt.sendMessage(
535 "Skipping COI_Solve due to setup errors. COI_Error = " + std::to_string(COI_Error));
536 cpp_log(conopt, "Skipping Solve due to setup errors", COI_Error);
537 }
538
539 if (i == 16)
540 {
547 conopt.debug2D(-1);
548 COI_Error = conopt.solve(); /* Optimize */
549 conopt.sendMessage("After solving. COI_Error = " + std::to_string(COI_Error));
550
551 if (COI_Error)
552 {
553 cpp_log(conopt, "Errors encountered during first solve", COI_Error);
554 }
555
556 else if (conopt.modelStatus() < 6 || conopt.modelStatus() > 7 ||
557 conopt.solutionStatus() != 5)
558 {
559 cpp_log(conopt, "Incorrect Model or Solver Status during first solve", -1);
560 };
561
562 conopt.printStatus();
563 }
564
565 else
566 {
567 /* Turn debugging of 2nd derivative off again. */
568 /* We should expect a proper optimal solution even with an incorrect */
569 /* 2DLagr routine so we test for (local) optimality after the solve. */
570 conopt.debug2D(0);
571 COI_Error = conopt.solve(); /* Optimize */
572 conopt.sendMessage("After solving. COI_Error = " + std::to_string(COI_Error));
573
574 if (conopt.modelStatus() != 2 || conopt.solutionStatus() != 1)
575 cpp_log(conopt, "Incorrect Model or Solver Status", -1);
576
577 conopt.printStatus();
578 }
579 }
580 cpp_log(conopt, "Successful Solve", COI_Error);
581}
The Conopt class.
Definition conopt.hpp:27
static constexpr double Infinity
Definition conopt.hpp:30
std::vector< int > vars
std::vector< int > varcs
std::vector< int > constseq
std::vector< int > varr
std::vector< int > constreq
std::map< int, std::pair< int, int > > consmapping
std::vector< int > vartd
std::vector< int > varrev
std::vector< int > consttdeq
std::vector< int > vard
std::vector< int > constdrev
std::vector< double > demand
std::vector< int > constcseq
std::vector< int > varp
std::vector< int > hessianstart
std::vector< int > constdeq
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 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 main(int argc, char **argv)
Main program. A simple setup and call of CONOPT.
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.
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