EPEC solve
Solving Equilibrium Problems with Equilibrium Constraints (EPECs)
Models.cpp
Go to the documentation of this file.
1 // #include "models.h"
2 #include "models.h"
3 #include <armadillo>
4 #include <boost/log/trivial.hpp>
5 #include <boost/program_options.hpp>
6 #include <gurobi_c++.h>
7 #include <iomanip>
8 #include <iostream>
9 #include <map>
10 #include <memory>
11 #include <rapidjson/document.h>
12 #include <rapidjson/istreamwrapper.h>
13 #include <rapidjson/prettywriter.h>
14 #include <rapidjson/stringbuffer.h>
15 #include <vector>
16 
17 using namespace rapidjson;
18 using namespace std;
19 
20 ostream &Models::operator<<(ostream &ost, const Models::prn l) {
21  switch (l) {
22  case Models::prn::label:
23  ost << std::left << std::setw(50);
24  break;
25  case Models::prn::val:
26  ost << std::right << std::setprecision(2) << std::setw(16) << std::fixed;
27  break;
28  default:
29  break;
30  }
31  return ost;
32 }
33 
34 ostream &Models::operator<<(ostream &ost, const Models::FollPar P) {
35  ost << "Follower Parameters: " << '\n';
36  ost << "********************" << '\n';
37  ost << Models::prn::label << "Linear Costs"
38  << ":\t";
39  for (auto a : P.costs_lin)
40  ost << Models::prn::val << a;
41  ost << '\n'
42  << Models::prn::label << "Quadratic costs"
43  << ":\t";
44  for (auto a : P.costs_quad)
45  ost << Models::prn::val << a;
46  ost << '\n'
47  << Models::prn::label << "Production capacities"
48  << ":\t";
49  for (auto a : P.capacities)
50  ost << Models::prn::val
51  << (a < 0 ? std::numeric_limits<double>::infinity() : a);
52  ost << '\n'
53  << Models::prn::label << "Tax Caps"
54  << ":\t";
55  for (auto a : P.tax_caps)
56  ost << Models::prn::val
57  << (a < 0 ? std::numeric_limits<double>::infinity() : a);
58  ost << '\n';
59  return ost;
60 }
61 
62 ostream &Models::operator<<(ostream &ost, const Models::DemPar P) {
63  ost << "Demand Parameters: " << '\n';
64  ost << "******************" << '\n';
65  ost << "Price\t\t =\t\t " << P.alpha << "\t-\t" << P.beta << " x Quantity"
66  << '\n';
67  return ost;
68 }
69 
70 ostream &Models::operator<<(ostream &ost, const Models::LeadPar P) {
71  ost << "Leader Parameters: " << '\n';
72  ost << "******************" << '\n';
73  ost << std::fixed;
74  ost << Models::prn::label << "Export Limit"
75  << ":" << Models::prn::val
76  << (P.export_limit < 0 ? std::numeric_limits<double>::infinity()
77  : P.export_limit);
78  ost << '\n';
79  ost << Models::prn::label << "Import Limit"
80  << ":" << Models::prn::val
81  << (P.import_limit < 0 ? std::numeric_limits<double>::infinity()
82  : P.import_limit);
83  ost << '\n';
84  ost << Models::prn::label << "Price limit"
85  << ":" << Models::prn::val
86  << (P.price_limit < 0 ? std::numeric_limits<double>::infinity()
87  : P.price_limit);
88  ost << '\n';
89  return ost;
90 }
91 
92 ostream &Models::operator<<(ostream &ost, const Models::EPECInstance I) {
93  ost << "EPEC Instance: " << '\n';
94  ost << "******************" << '\n';
95  for (auto a : I.Countries)
96  ost << a << '\n';
97  ost << "Transportation Costs:" << '\n' << I.TransportationCosts << '\n';
98  return ost;
99 }
100 
101 ostream &Models::operator<<(ostream &ost, const Models::LeadAllPar P) {
102  ost << "\n\n";
103  ost << "***************************"
104  << "\n";
105  ost << "Leader Complete Description"
106  << "\n";
107  ost << "***************************"
108  << "\n"
109  << "\n";
110  ost << Models::prn::label << "Number of followers"
111  << ":" << Models::prn::val << P.n_followers << "\n "
112  << "\n";
113  ost << '\n'
114  << P.LeaderParam << '\n'
115  << P.FollowerParam << '\n'
116  << P.DemandParam << "\n";
117  ost << "***************************"
118  << "\n"
119  << "\n";
120  return ost;
121 }
122 
123 ostream &Models::operator<<(ostream &ost, const Models::LeaderVars l) {
124  switch (l) {
126  ost << "Models::LeaderVars::FollowerStart";
127  break;
129  ost << "Models::LeaderVars::NetImport";
130  break;
132  ost << "Models::LeaderVars::NetExport";
133  break;
135  ost << "Models::LeaderVars::CountryImport";
136  break;
138  ost << "Models::LeaderVars::Caps";
139  break;
141  ost << "Models::LeaderVars::Tax";
142  break;
144  ost << "Models::LeaderVars::TaxQuad";
145  break;
147  ost << "Models::LeaderVars::DualVar";
148  break;
150  ost << "Models::LeaderVars::ConvHullDummy";
151  break;
153  ost << "Models::LeaderVars::End";
154  break;
155  default:
156  cerr << "Incorrect argument to ostream& operator<<(ostream& ost, const "
157  "LeaderVars l)";
158  };
159  return ost;
160 }
161 
163  const Models::FollPar &F2) {
164  std::vector<double> cq, cl, cap, ec, tc;
165  std::vector<std::string> nm;
166 
167  cq.insert(cq.end(), F1.costs_quad.begin(), F1.costs_quad.end());
168  cq.insert(cq.end(), F2.costs_quad.begin(), F2.costs_quad.end());
169 
170  cl.insert(cl.end(), F1.costs_lin.begin(), F1.costs_lin.end());
171  cl.insert(cl.end(), F2.costs_lin.begin(), F2.costs_lin.end());
172 
173  cap.insert(cap.end(), F1.capacities.begin(), F1.capacities.end());
174  cap.insert(cap.end(), F2.capacities.begin(), F2.capacities.end());
175 
176  ec.insert(ec.end(), F1.emission_costs.begin(), F1.emission_costs.end());
177  ec.insert(ec.end(), F2.emission_costs.begin(), F2.emission_costs.end());
178 
179  tc.insert(tc.end(), F1.tax_caps.begin(), F1.tax_caps.end());
180  tc.insert(tc.end(), F2.tax_caps.begin(), F2.tax_caps.end());
181 
182  nm.insert(nm.end(), F1.names.begin(), F1.names.end());
183  nm.insert(nm.end(), F2.names.begin(), F2.names.end());
184 
185  return Models::FollPar(cq, cl, cap, ec, tc, nm);
186 }
187 
189  const LeadAllPar &Params
190 ) const
200 {
201  if (Params.n_followers == 0)
202  throw "Error in EPEC::ParamValid(). 0 Followers?";
203  if (Params.FollowerParam.costs_lin.size() != Params.n_followers ||
204  Params.FollowerParam.costs_quad.size() != Params.n_followers ||
205  Params.FollowerParam.capacities.size() != Params.n_followers ||
206  Params.FollowerParam.tax_caps.size() != Params.n_followers ||
207  Params.FollowerParam.emission_costs.size() != Params.n_followers)
208  throw "Error in EPEC::ParamValid(). Size Mismatch";
209  if (Params.DemandParam.alpha <= 0 || Params.DemandParam.beta <= 0)
210  throw "Error in EPEC::ParamValid(). Invalid demand curve params";
211  // Country should have a name!
212  if (Params.name == "")
213  throw "Error in EPEC::ParamValid(). Country name empty";
214  // Country should have a unique name
215  for (const auto &p : this->AllLeadPars)
216  if (Params.name.compare(p.name) == 0) // i.e., if the strings are same
217  throw "Error in EPEC::ParamValid(). Country name repetition";
218  return true;
219 }
220 
222  const LeadAllPar &Params,
223  const unsigned int follower,
225  *Foll,
226  const Models::LeadLocs
227  &Loc
228 ) const noexcept
234 {
235  const unsigned int LeadVars =
236  Loc.at(Models::LeaderVars::End) - Params.n_followers;
237  arma::sp_mat Q(1, 1), C(1, LeadVars + Params.n_followers - 1);
238  // Two constraints. One saying that you should be less than capacity
239  // Another saying that you should be less than leader imposed cap!
240  arma::sp_mat A(1, Loc.at(Models::LeaderVars::End) - 1), B(1, 1);
241  arma::vec c(1), b(1);
242  c.fill(0);
243  b.fill(0);
244  A.zeros();
245  B.zeros();
246  C.zeros();
247  b.zeros();
248  Q.zeros();
249  c.zeros();
250  // Objective
251  Q(0, 0) = Params.FollowerParam.costs_quad.at(follower) +
252  2 * Params.DemandParam.beta;
253  c(0) = Params.FollowerParam.costs_lin.at(follower) - Params.DemandParam.alpha;
254 
255  arma::mat Ctemp(1, Loc.at(Models::LeaderVars::End) - 1, arma::fill::zeros);
256  Ctemp.cols(0, Params.n_followers - 1)
257  .fill(Params.DemandParam
258  .beta); // First n-1 entries and 1 more entry is Beta
259  Ctemp(0, Params.n_followers) = -Params.DemandParam.beta; // For q_exp
260 
261  // Scroll in Ctemp basing on the taxation paradigm
262  if (Params.LeaderParam.tax_type == Models::TaxType::StandardTax)
263  Ctemp(0, (Params.n_followers - 1) + 2 + Params.n_followers + follower) =
264  1; // q_{-i}, then import, export, then tilde q_i, then i-th tax
265  else if (Params.LeaderParam.tax_type == Models::TaxType::SingleTax)
266  Ctemp(0, (Params.n_followers - 1) + 2 + Params.n_followers + 0) =
267  1; // q_{-i}, then import, export, then tilde q_i, then only tax var
268  else if (Params.LeaderParam.tax_type == Models::TaxType::CarbonTax)
269  Ctemp(0, (Params.n_followers - 1) + 2 + Params.n_followers + 0) =
270  Params.FollowerParam.emission_costs.at(
271  follower); // q_{-i}, then import, export, then tilde q_i, then only
272  // tax var
273 
274  C = Ctemp;
275  // A(1, (Params.n_followers - 1) + 2 + follower) = 0;
276  // Produce positive (zero) quantities and less than the cap
277  B(0, 0) = 1;
278  b(0) = Params.FollowerParam.capacities.at(follower);
279 
280  Foll->set(std::move(Q), std::move(C), std::move(A), std::move(B),
281  std::move(c), std::move(b));
282 }
283 
285  arma::sp_mat
286  &LeadCons,
287  arma::vec &LeadRHS,
288  const LeadAllPar &Params,
289  const Models::LeadLocs &Loc,
290  const unsigned int import_lim_cons,
291  const unsigned int export_lim_cons,
293  const unsigned int price_lim_cons,
295  const unsigned int
297  activeTaxCaps
298 ) const noexcept
322 {
323  if (activeTaxCaps > 0) {
324  // Tax Caps are active
325  // Different tax caps
326  // Note that the loop is performed until this->taxVars is hit
327  for (unsigned int follower = 0; follower < this->taxVars; follower++) {
328  if (Params.FollowerParam.tax_caps.at(follower) >= 0) {
329  // Constraints for Tax limits
330  LeadCons(follower, Loc.at(Models::LeaderVars::Tax) + follower) = 1;
331  LeadRHS(follower) = Params.FollowerParam.tax_caps.at(follower);
332  }
333  }
334  }
335  // Export - import <= Local Production
336  // (28b)
337  for (unsigned int i = 0; i < Params.n_followers; i++)
338  LeadCons.at(Params.n_followers, i) = -1;
339  LeadCons.at(activeTaxCaps, Loc.at(Models::LeaderVars::NetExport)) = 1;
340  LeadCons.at(activeTaxCaps, Loc.at(Models::LeaderVars::NetImport)) = -1;
341  // Import limit - In more precise terms, everything that comes in minus
342  // everything that goes out should satisfy this limit (28c)
343  if (import_lim_cons) {
344  LeadCons(activeTaxCaps + import_lim_cons,
345  Loc.at(Models::LeaderVars::NetImport)) = 1;
346  LeadCons(activeTaxCaps + import_lim_cons,
347  Loc.at(Models::LeaderVars::NetExport)) = -1;
348  LeadRHS(activeTaxCaps + import_lim_cons) = Params.LeaderParam.import_limit;
349  }
350  // Export limit - In more precise terms, everything that goes out minus
351  // everything that comes in should satisfy this limit (28d)
352  if (export_lim_cons) {
353  LeadCons(activeTaxCaps + import_lim_cons + export_lim_cons,
354  Loc.at(Models::LeaderVars::NetExport)) = 1;
355  LeadCons(activeTaxCaps + import_lim_cons + export_lim_cons,
356  Loc.at(Models::LeaderVars::NetImport)) = -1;
357  LeadRHS(activeTaxCaps + import_lim_cons + export_lim_cons) =
358  Params.LeaderParam.export_limit;
359  }
360  // (28g)
361  if (price_lim_cons) {
362  for (unsigned int i = 0; i < Params.n_followers; i++)
363  LeadCons.at(activeTaxCaps + price_lim_cons + import_lim_cons +
364  export_lim_cons,
365  i) = -Params.DemandParam.beta;
366  LeadCons.at(
367  activeTaxCaps + price_lim_cons + import_lim_cons + export_lim_cons,
368  Loc.at(Models::LeaderVars::NetImport)) = -Params.DemandParam.beta;
369  LeadCons.at(
370  activeTaxCaps + price_lim_cons + import_lim_cons + export_lim_cons,
371  Loc.at(Models::LeaderVars::NetExport)) = Params.DemandParam.beta;
372  LeadRHS.at(activeTaxCaps + price_lim_cons + import_lim_cons +
373  export_lim_cons) =
374  Params.LeaderParam.price_limit - Params.DemandParam.alpha;
375  }
376  // revenue tax
377  if (Params.LeaderParam.tax_revenue) {
378 
379  // If taxation paradigm is not standard (0), then just one tax variable is
380  // used.
381  unsigned int standardTax = 1;
382  unsigned int carbonTax = 0;
383  if (Params.LeaderParam.tax_type != Models::TaxType::StandardTax) {
384  standardTax = 0;
385  // If carbon tax, we should modify McCornick inequalities
386  if (Params.LeaderParam.tax_type == Models::TaxType::CarbonTax)
387  carbonTax = 1;
388  }
389 
390  for (unsigned int i = 0; i < Params.n_followers; i++) {
391  double t_cap = (Params.FollowerParam.tax_caps.at(i * standardTax) >= 0
392  ? Params.FollowerParam.tax_caps.at(i * standardTax)
393  : 0);
394  double carbonCorrection =
395  (carbonTax == 1) ? Params.FollowerParam.emission_costs.at(i) : 1;
396  // -u_i + \bar{q}_it_i + \bar{t}_iq_i \le \bar{t}_i \bar{q}_i
397  LeadCons.at(activeTaxCaps + price_lim_cons + import_lim_cons +
398  export_lim_cons + i * 3 + 1,
399  Loc.at(Models::LeaderVars::TaxQuad) + i) = -1;
400  LeadCons.at(activeTaxCaps + price_lim_cons + import_lim_cons +
401  export_lim_cons + i * 3 + 1,
402  Loc.at(Models::LeaderVars::Tax) + i * standardTax) =
403  Params.FollowerParam.capacities.at(i) * carbonCorrection;
404  LeadCons.at(activeTaxCaps + price_lim_cons + import_lim_cons +
405  export_lim_cons + i * 3 + 1,
406  Loc.at(Models::LeaderVars::FollowerStart) + i) =
407  t_cap * carbonCorrection;
408  LeadRHS.at(activeTaxCaps + price_lim_cons + import_lim_cons +
409  export_lim_cons + i * 3 + 1) =
410  t_cap * Params.FollowerParam.capacities.at(i) * carbonCorrection;
411 
412  // -u_i + \bar{q}_it_i \le 0
413  LeadCons.at(activeTaxCaps + price_lim_cons + import_lim_cons +
414  export_lim_cons + i * 3 + 2,
415  Loc.at(Models::LeaderVars::TaxQuad) + i) = -1;
416  LeadCons.at(activeTaxCaps + price_lim_cons + import_lim_cons +
417  export_lim_cons + i * 3 + 2,
418  Loc.at(Models::LeaderVars::Tax) + i * standardTax) =
419  Params.FollowerParam.capacities.at(i) * carbonCorrection;
420  LeadRHS.at(activeTaxCaps + price_lim_cons + import_lim_cons +
421  export_lim_cons + i * 3 + 2) = 0;
422 
423  // -u_i + \bar{t}_iq_i \le 0
424  LeadCons.at(activeTaxCaps + price_lim_cons + import_lim_cons +
425  export_lim_cons + i * 3 + 3,
426  Loc.at(Models::LeaderVars::TaxQuad) + i) = -1;
427  LeadCons.at(activeTaxCaps + price_lim_cons + import_lim_cons +
428  export_lim_cons + i * 3 + 3,
429  Loc.at(Models::LeaderVars::FollowerStart) + i) =
430  t_cap * carbonCorrection;
431  LeadRHS.at(activeTaxCaps + price_lim_cons + import_lim_cons +
432  export_lim_cons + i * 3 + 3) = 0;
433  }
434  }
435  BOOST_LOG_TRIVIAL(trace) << "********** Price Limit constraint: "
436  << price_lim_cons;
437  BOOST_LOG_TRIVIAL(trace) << "********** Import Limit constraint: "
438  << import_lim_cons;
439  BOOST_LOG_TRIVIAL(trace) << "********** Export Limit constraint: "
440  << export_lim_cons;
441  BOOST_LOG_TRIVIAL(trace) << "********** Tax Limit constraints: "
442  << activeTaxCaps << "\n\t";
443 }
444 
446  const unsigned int addnlLeadVars)
484 {
485  if (this->finalized)
486  throw string(
487  "Error in Models::EPEC::addCountry: EPEC object finalized. Call "
488  "EPEC::unlock() to unlock this object first and then edit.");
489 
490  bool noError = false;
491  try {
492  noError = this->ParamValid(Params);
493  } catch (const char *e) {
494  cerr << "Error in Models::EPEC::addCountry: " << e << '\n';
495  } catch (string e) {
496  cerr << "String: Error in Models::EPEC::addCountry: " << e << '\n';
497  } catch (exception &e) {
498  cerr << "Exception: Error in Models::EPEC::addCountry: " << e.what()
499  << '\n';
500  }
501  if (!noError)
502  return *this;
503 
504  // Basing on the taxation paradigm, allocate the right number of taxVars in
505  // the class
507  BOOST_LOG_TRIVIAL(trace)
508  << "Country " << Params.name << " has a standard tax paradigm.";
509  this->taxVars = Params.n_followers;
510  } else {
512  BOOST_LOG_TRIVIAL(trace)
513  << "Country " << Params.name << " has a single tax paradigm.";
514  } else if (Params.LeaderParam.tax_type == Models::TaxType::CarbonTax) {
515  BOOST_LOG_TRIVIAL(trace)
516  << "Country " << Params.name << " has a carbon tax paradigm.";
517  }
518  this->taxVars = 1;
519  }
520 
521  const unsigned int LeadVars =
522  2 + (1 + Params.LeaderParam.tax_revenue) * Params.n_followers + taxVars +
523  addnlLeadVars;
524  // 2 for quantity imported and exported, n for imposed cap, taxVars for taxes
525  // and n for bilinear taxes.
526 
527  LeadLocs Loc;
528  Models::init(Loc);
529 
530  // Allocate so much space for each of these types of variables
531  Models::increaseVal(Loc, LeaderVars::FollowerStart, Params.n_followers);
532  Models::increaseVal(Loc, LeaderVars::NetImport, 1);
533  Models::increaseVal(Loc, LeaderVars::NetExport, 1);
534  Models::increaseVal(Loc, LeaderVars::Caps, Params.n_followers);
535  Models::increaseVal(Loc, LeaderVars::Tax, this->taxVars);
536  if (Params.LeaderParam.tax_revenue) {
537  BOOST_LOG_TRIVIAL(info)
538  << "Country " << Params.name << " has tax revenue in the objective.";
539  Models::increaseVal(Loc, LeaderVars::TaxQuad, Params.n_followers);
540  }
541 
542  // Leader Constraints
543  short int import_lim_cons{0}, export_lim_cons{0}, price_lim_cons{0};
544  if (Params.LeaderParam.import_limit >= 0)
545  import_lim_cons = 1;
546  if (Params.LeaderParam.export_limit >= 0)
547  export_lim_cons = 1;
548  if (Params.LeaderParam.price_limit >= 0)
549  price_lim_cons = 1;
550  unsigned int activeTaxCaps = 0;
552  // Since we have a standard taxation paradigm, we have to consider all
553  // different tax caps
554  activeTaxCaps = count_if(Params.FollowerParam.tax_caps.begin(),
555  Params.FollowerParam.tax_caps.end(),
556  [](double i) { return i >= 0; });
557  } else {
558  // There is no standard taxation paradigm (so we have carbon or single).
559  // Hence we want to consider just one caps, arbitrary the first
560  activeTaxCaps = count_if(Params.FollowerParam.tax_caps.begin(),
561  Params.FollowerParam.tax_caps.end(),
562  [](double i) { return i >= 0; });
563  if (activeTaxCaps >= 0) {
564  if (!std::equal(Params.FollowerParam.tax_caps.begin() + 1,
565  Params.FollowerParam.tax_caps.end(),
566  Params.FollowerParam.tax_caps.begin())) {
567  BOOST_LOG_TRIVIAL(warning)
568  << "Tax caps are not equal within a non-standard tax framework. "
569  "Using the first value as tax limit.";
570  }
571  activeTaxCaps = 1;
572  }
573  }
574 
575  arma::sp_mat LeadCons(import_lim_cons + // Import limit constraint
576  export_lim_cons + // Export limit constraint
577  price_lim_cons + // Price limit constraint
578  activeTaxCaps + // Tax limit constraints
579  Params.n_followers * 3 *
580  Params.LeaderParam.tax_revenue + // revenue tax
581  1, // Export - import <= Domestic production
583  arma::vec LeadRHS(
584  import_lim_cons + export_lim_cons + price_lim_cons + activeTaxCaps +
585  Params.n_followers * 3 * Params.LeaderParam.tax_revenue + 1,
586  arma::fill::zeros);
587 
588  vector<shared_ptr<Game::QP_Param>> Players{};
589  // Create the QP_Param* for each follower
590  try {
591  for (unsigned int follower = 0; follower < Params.n_followers; follower++) {
592  auto Foll = make_shared<Game::QP_Param>(this->env);
593  this->make_LL_QP(Params, follower, Foll.get(), Loc);
594  Players.push_back(Foll);
595  }
596  // Make Leader Constraints
597  this->make_LL_LeadCons(LeadCons, LeadRHS, Params, Loc, import_lim_cons,
598  export_lim_cons, price_lim_cons, activeTaxCaps);
599  } catch (const char *e) {
600  cerr << e << '\n';
601  throw;
602  } catch (string e) {
603  cerr << "String in Models::EPEC::addCountry : " << e << '\n';
604  throw;
605  } catch (GRBException &e) {
606  cerr << "GRBException in Models::EPEC::addCountry : " << e.getErrorCode()
607  << ": " << e.getMessage() << '\n';
608  throw;
609  } catch (exception &e) {
610  cerr << "Exception in Models::EPEC::addCountry : " << e.what() << '\n';
611  throw;
612  }
613 
614  // Lower level Market clearing constraints - empty
615  arma::sp_mat MC(0, LeadVars + Params.n_followers);
616  arma::vec MCRHS(0, arma::fill::zeros);
617 
618  // Convert the country QP to a NashGame
619  auto N = std::make_shared<Game::NashGame>(this->env, Players, MC, MCRHS,
620  LeadVars, LeadCons, LeadRHS);
621  this->name2nos[Params.name] = this->countries_LL.size();
622  this->countries_LL.push_back(N);
625  N->getNduals()); // N->getNduals() will sum the number of constraints in
626  // each lower level QP and provide the sum. Indeed, this
627  // is the number of dual variables for the lower level.
628  this->Locations.push_back(Loc);
629 
630  this->EPEC::LocEnds.push_back(&this->Locations.back().at(LeaderVars::End));
631  this->EPEC::convexHullVariables.push_back(0);
632 
633  this->LeadConses.push_back(N->RewriteLeadCons()); // Not mandatory!
634  this->AllLeadPars.push_back(Params);
635  this->Game::EPEC::n_MCVar++;
636  return *this;
637 }
638 
640  const arma::sp_mat &costs
641  )
648 {
649  if (this->finalized)
650  throw string(
651  "Error in Models::EPEC::addTranspCosts: EPEC object finalized. Call "
652  "EPEC::unlock() to unlock this object first and then edit.");
653  try {
654  if (this->getNcountries() != costs.n_rows ||
655  this->getNcountries() != costs.n_cols)
656  throw string("Error in EPEC::addTranspCosts. Invalid size of Q");
657  else
658  this->TranspCosts = arma::sp_mat(costs);
659  this->TranspCosts.diag()
660  .zeros(); // Doesn't make sense for it to have a nonzero diagonal!
661  } catch (const char *e) {
662  cerr << e << '\n';
663  throw;
664  } catch (string e) {
665  cerr << "String in Models::EPEC::addTranspCosts : " << e << '\n';
666  throw;
667  } catch (GRBException &e) {
668  cerr << "GRBException in Models::EPEC::addTranspCosts : "
669  << e.getErrorCode() << ": " << e.getMessage() << '\n';
670  throw;
671  } catch (exception &e) {
672  cerr << "Exception in Models::EPEC::addTranspCosts : " << e.what() << '\n';
673  throw;
674  }
675 
676  return *this;
677 }
678 
687  try {
688  /*
689  * Below for loop adds space for each country's quantity imported from
690  * variable
691  */
692  this->nImportMarkets = vector<unsigned int>(this->getNcountries());
693  for (unsigned int i = 0; i < this->getNcountries(); i++)
694  this->add_Leaders_tradebalance_constraints(i);
695  } catch (const char *e) {
696  cerr << e << '\n';
697  throw;
698  } catch (string e) {
699  cerr << "String in Models::EPEC::prefinalize : " << e << '\n';
700  throw;
701  } catch (GRBException &e) {
702  cerr << "GRBException in Models::EPEC::prefinalize : " << e.getErrorCode()
703  << ": " << e.getMessage() << '\n';
704  throw;
705  } catch (exception &e) {
706  cerr << "Exception in Models::EPEC::prefinalize : " << e.what() << '\n';
707  throw;
708  }
709 }
710 
721 {
722  if (i >= this->countries_LL.size())
723  throw string("Error in Models::EPEC::add_Leaders_tradebalance_constraints. "
724  "Bad argument");
725  int nImp = 0;
726  LeadLocs &Loc = this->Locations.at(i);
727  // Counts the number of countries from which the current country imports
728  for (auto val = TranspCosts.begin_col(i); val != TranspCosts.end_col(i);
729  ++val)
730  nImp++;
731  // substitutes that answer to nImportMarkets at the current position
732  this->nImportMarkets.at(i) = (nImp);
733  if (nImp > 0) {
734  Models::increaseVal(Loc, LeaderVars::CountryImport, nImp);
735 
736  Game::NashGame &LL_Nash = *this->countries_LL.at(i).get();
737 
738  // Adding the constraint that the sum of imports from all countries equals
739  // total imports
740  arma::vec a(Loc.at(Models::LeaderVars::End) - LL_Nash.getNduals(),
741  arma::fill::zeros);
742  a.at(Loc.at(Models::LeaderVars::NetImport)) = -1;
743  a.subvec(Loc.at(LeaderVars::CountryImport),
744  Loc.at(LeaderVars::CountryImport + 1) - 1)
745  .ones();
746 
747  LL_Nash.addDummy(nImp, Loc.at(Models::LeaderVars::CountryImport));
748  LL_Nash.addLeadCons(a, 0).addLeadCons(-a, 0);
749  } else {
750  Game::NashGame &LL_Nash = *this->countries_LL.at(i).get();
751 
752  // Set imports and exporta to zero
753  arma::vec a(Loc.at(Models::LeaderVars::End) - LL_Nash.getNduals(),
754  arma::fill::zeros);
755  a.at(Loc.at(Models::LeaderVars::NetImport)) = 1;
756  LL_Nash.addLeadCons(a, 0); // Export <= 0
757  a.at(Loc.at(Models::LeaderVars::NetImport)) = 0;
758  a.at(Loc.at(Models::LeaderVars::NetExport)) = 1;
759  LL_Nash.addLeadCons(a, 0); // Import <= 0
760  }
761 }
762 
763 void Models::EPEC::make_MC_cons(arma::sp_mat &MCLHS, arma::vec &MCRHS) const
767 {
768  if (!this->finalized)
769  throw string("Error in Models::EPEC::make_MC_cons: This function can be "
770  "run only AFTER calling finalize()");
771  // Transportation matrix
772  const arma::sp_mat &TrCo = this->TranspCosts;
773  // Output matrices
774  MCRHS.zeros(this->getNcountries());
775  MCLHS.zeros(this->getNcountries(), this->getnVarinEPEC());
776  // The MC constraint for each leader country
777  if (this->getNcountries() > 1) {
778  for (unsigned int i = 0; i < this->getNcountries(); ++i) {
779  MCLHS(i, this->getPosition(i, LeaderVars::NetExport)) = 1;
780  for (auto val = TrCo.begin_row(i); val != TrCo.end_row(i); ++val) {
781  const unsigned int j =
782  val.col(); // This is the country which is importing from "i"
783  unsigned int count{0};
784 
785  for (auto val2 = TrCo.begin_col(j); val2 != TrCo.end_col(j); ++val2)
786  // What position in the list of j's impoting from countries does i fall
787  // in?
788  {
789  if (val2.row() == i)
790  break;
791  else
792  count++;
793  }
794  MCLHS(i, this->getPosition(j, Models::LeaderVars::CountryImport) +
795  count) = -1;
796  }
797  }
798  }
799 }
800 
801 void Models::EPEC::make_MC_leader(const unsigned int i)
807 {
808  if (i >= this->getNcountries())
809  throw string("Error in Models::EPEC::add_Leaders_tradebalance_constraints. "
810  "Bad argument");
811  try {
812  const arma::sp_mat &TrCo = this->TranspCosts;
813  const unsigned int nEPECvars = this->getnVarinEPEC();
814  const unsigned int nThisMCvars = 1;
815  arma::sp_mat C(nThisMCvars, nEPECvars - nThisMCvars);
816 
817  C.at(0, this->getPosition(i, Models::LeaderVars::NetExport)) = 1;
818 
819  for (auto val = TrCo.begin_row(i); val != TrCo.end_row(i); ++val) {
820  const unsigned int j = val.col(); // This is the country which the
821  // country "i" is importing from
822  unsigned int count{0};
823 
824  for (auto val2 = TrCo.begin_col(j); val2 != TrCo.end_col(j); ++val2)
825  // What position in the list of j's impoting from countries does i fall
826  // in?
827  {
828  if (val2.row() == i)
829  break;
830  else
831  count++;
832  }
833 
834  C.at(0, this->getPosition(j, Models::LeaderVars::CountryImport) + count -
835  (j >= i ? nThisMCvars : 0)) = 1;
836  }
837 
838  this->MC_QP.at(i) = std::make_shared<Game::QP_Param>(this->env);
839  // Note Q = {{0}}, c={0}, the MC problem has no constraints. So A=B={{}},
840  // b={}.
841  this->MC_QP.at(i).get()->set(arma::sp_mat{1, 1}, // Q
842  std::move(C), // C
843  arma::sp_mat{0, nEPECvars - nThisMCvars}, // A
844  arma::sp_mat{0, nThisMCvars}, // B
845  arma::vec{0}, // c
846  arma::vec{} // b
847  );
848  } catch (const char *e) {
849  cerr << e << '\n';
850  throw;
851  } catch (string e) {
852  cerr << "String in Models::EPEC::make_MC_leader : " << e << '\n';
853  throw;
854  } catch (GRBException &e) {
855  cerr << "GRBException in Models::EPEC::make_MC_leader : "
856  << e.getErrorCode() << ": " << e.getMessage() << '\n';
857  throw;
858  } catch (exception &e) {
859  cerr << "Exception in Models::EPEC::make_MC_leader : " << e.what() << '\n';
860  throw;
861  }
862 }
863 
865  const bool
866  chkAllLeadPars,
867  const bool chkcountries_LL,
868  const bool chkMC_QP,
870  const bool
871  chkLeadConses,
872  const bool
873  chkLeadRHSes,
874  const bool chknImportMarkets,
875  const bool
877  chkLocations,
878  const bool
879  chkLeaderLocations,
880  const bool chkLeadObjec
882 ) const
887 {
888  if (!chkAllLeadPars && AllLeadPars.size() != this->getNcountries())
889  return false;
890  if (!chkcountries_LL && countries_LL.size() != this->getNcountries())
891  return false;
892  if (!chkMC_QP && MC_QP.size() != this->getNcountries())
893  return false;
894  if (!chkLeadConses && LeadConses.size() != this->getNcountries())
895  return false;
896  if (!chkLeadRHSes && LeadRHSes.size() != this->getNcountries())
897  return false;
898  if (!chknImportMarkets && nImportMarkets.size() != this->getNcountries())
899  return false;
900  if (!chkLocations && Locations.size() != this->getNcountries())
901  return false;
902  if (!chkLeaderLocations && LeaderLocations.size() != this->getNcountries())
903  return false;
904  if (!chkLeaderLocations && this->getnVarinEPEC() == 0)
905  return false;
906  if (!chkLeadObjec && LeadObjec.size() != this->getNcountries())
907  return false;
908  return true;
909 }
910 
911 unsigned int Models::EPEC::getPosition(const unsigned int countryCount,
912  const Models::LeaderVars var) const
916 {
917  if (countryCount >= this->getNcountries())
918  throw string("Error in Models::EPEC::getPosition: Bad Country Count");
919  return this->LeaderLocations.at(countryCount) +
920  this->Locations.at(countryCount).at(var);
921 }
922 
923 unsigned int Models::EPEC::getPosition(const string countryName,
924  const Models::LeaderVars var) const
929 {
930  return this->getPosition(name2nos.at(countryName), var);
931 }
932 
938 {
939  return this->countries_LL.at(i).get();
940 }
941 
950 {
951  this->finalized = false;
952  return *this;
953 }
954 
956  const unsigned int
957  i,
959  &QP_obj
960  )
964 {
965  const unsigned int nEPECvars = this->getnVarinEPEC();
966  const unsigned int nThisCountryvars =
967  this->Locations.at(i).at(Models::LeaderVars::End);
968  const LeadAllPar &Params = this->AllLeadPars.at(i);
969  const arma::sp_mat &TrCo = this->TranspCosts;
970  const LeadLocs &Loc = this->Locations.at(i);
971 
972  QP_obj.Q.zeros(nThisCountryvars, nThisCountryvars);
973  QP_obj.c.zeros(nThisCountryvars);
974  QP_obj.C.zeros(nThisCountryvars, nEPECvars - nThisCountryvars);
975  // emission term
976  for (unsigned int j = Loc.at(Models::LeaderVars::FollowerStart), count = 0;
977  count < Params.n_followers; j++, count++)
978  QP_obj.c.at(j) = Params.FollowerParam.emission_costs.at(count);
979 
980  // revenue tax
981  if (Params.LeaderParam.tax_revenue) {
982  for (unsigned int j = Loc.at(Models::LeaderVars::TaxQuad), count = 0;
983  count < this->taxVars; j++, count++)
984  QP_obj.c.at(j) = 1;
985  }
986 
987  if (this->getNcountries() > 1) {
988  // export revenue term
989 
990  QP_obj.C(
992  // this->getPosition(i, Models::LeaderVars::End) -
993  // nThisCountryvars) = -1;
994  this->getPosition(this->getNcountries() - 1, Models::LeaderVars::End) -
995  nThisCountryvars + i) = -1;
996 
997  // Import cost term.
998  unsigned int count{0};
999  for (auto val = TrCo.begin_col(i); val != TrCo.end_col(i); ++val, ++count) {
1000  // C^{tr}_{IA}*q^{I\to A}_{imp} term
1001  QP_obj.c.at(Loc.at(Models::LeaderVars::CountryImport) + count) = (*val);
1002  // \pi^I*q^{I\to A}_{imp} term
1003  QP_obj.C.at(Loc.at(Models::LeaderVars::CountryImport) + count,
1004  this->getPosition(this->getNcountries() - 1,
1006  nThisCountryvars + val.row()) = 1;
1007  // this->Locations.at(val.row()).at(Models::LeaderVars::End)) = 1;
1008  // this->getPosition(val.row(), Models::LeaderVars::End)) = 1;
1009  }
1010  }
1011 }
1012 
1013 unique_ptr<GRBModel> Models::EPEC::Respond(const string name,
1014  const arma::vec &x) const {
1015  return this->Game::EPEC::Respond(this->name2nos.at(name), x);
1016 }
1017 
1022 {
1023  for (unsigned int i = 0; i < this->getNcountries(); ++i) {
1024  LeadLocs &Loc = this->Locations.at(i);
1028  Models::increaseVal(Loc, Models::LeaderVars::ConvHullDummy,
1029  this->convexHullVariables.at(i));
1030  }
1031 }
1032 
1034  const unsigned int val, const bool startnext)
1038 {
1039  LeaderVars start_rl = startnext ? start + 1 : start;
1040  for (LeaderVars l = start_rl; l != Models::LeaderVars::End; l = l + 1)
1041  L[l] += val;
1042  L[Models::LeaderVars::End] += val;
1043  // BOOST_LOG_TRIVIAL(error)<<"End location changed to:
1044  // "<<L[Models::LeaderVars::End];
1045 }
1046 
1048  const unsigned int val, const bool startnext)
1052 {
1053  LeaderVars start_rl = startnext ? start + 1 : start;
1054  for (LeaderVars l = start_rl; l != Models::LeaderVars::End; l = l + 1)
1055  L[l] -= val;
1056  L[Models::LeaderVars::End] -= val;
1057  // BOOST_LOG_TRIVIAL(error)<<"End location changed to:
1058  // "<<L[Models::LeaderVars::End];
1059 }
1060 
1063  l != Models::LeaderVars::End; l = l + 1)
1064  L[l] = 0;
1065  L[Models::LeaderVars::End] = 0;
1066 }
1067 
1069  return static_cast<LeaderVars>(static_cast<int>(a) + b);
1070 }
1071 
1072 string to_string(const GRBConstr &cons, const GRBModel &model) {
1073  const GRBVar *vars = model.getVars();
1074  const int nVars = model.get(GRB_IntAttr_NumVars);
1075  ostringstream oss;
1076  oss << cons.get(GRB_StringAttr_ConstrName) << ":\t\t";
1077  constexpr double eps = 1e-5;
1078  // LHS
1079  for (int i = 0; i < nVars; ++i) {
1080  double coeff = model.getCoeff(cons, vars[i]);
1081  if (abs(coeff) > eps) {
1082  char sign = (coeff > eps) ? '+' : ' ';
1083  oss << sign << coeff << to_string(vars[i]) << "\t";
1084  }
1085  }
1086  // Inequality/Equality and RHS
1087  oss << cons.get(GRB_CharAttr_Sense) << "\t" << cons.get(GRB_DoubleAttr_RHS);
1088  return oss.str();
1089 }
1090 
1091 string to_string(const GRBVar &var) {
1092  string name = var.get(GRB_StringAttr_VarName);
1093  return name.empty() ? "unNamedvar" : name;
1094 }
1095 
1096 void Models::EPEC::write(const string filename, const unsigned int i,
1097  bool append) const {
1098  ofstream file;
1099  file.open(filename, append ? ios::app : ios::out);
1100  const LeadAllPar &Params = this->AllLeadPars.at(i);
1101  file << "**************************************************\n";
1102  file << "COUNTRY: " << Params.name << '\n';
1103  file << "- - - - - - - - - - - - - - - - - - - - - - - - - \n";
1104  file << Params;
1105  file << "**************************************************\n\n\n\n\n";
1106  file.close();
1107 }
1108 
1109 void Models::EPEC::write(const string filename, bool append) const {
1110  if (append) {
1111  ofstream file;
1112  file.open(filename, ios::app);
1113  file << "\n\n\n\n\n";
1114  file << "##################################################\n";
1115  file << "############### COUNTRY PARAMETERS ###############\n";
1116  file << "##################################################\n";
1117  }
1118  for (unsigned int i = 0; i < this->getNcountries(); ++i)
1119  this->write(filename, i, (append || i));
1120 }
1121 
1122 void Models::EPEC::writeSolutionJSON(string filename, const arma::vec x,
1123  const arma::vec z) const {
1129  StringBuffer s;
1130  PrettyWriter<StringBuffer> writer(s);
1131  writer.StartObject();
1132  writer.Key("Meta");
1133  writer.StartObject();
1134  writer.Key("isPureEquilibrium");
1135  writer.Bool(this->isPureStrategy());
1136  writer.Key("nCountries");
1137  writer.Uint(this->getNcountries());
1138  writer.Key("nFollowers");
1139  writer.StartArray();
1140  for (unsigned i = 0; i < this->getNcountries(); i++)
1141  writer.Uint(this->AllLeadPars.at(i).n_followers);
1142  writer.EndArray();
1143  writer.Key("Countries");
1144  writer.StartArray();
1145  for (unsigned i = 0; i < this->getNcountries(); i++) {
1146  writer.StartObject();
1147  writer.Key("FollowerStart");
1148  writer.Uint(this->getPosition(i, Models::LeaderVars::FollowerStart));
1149  writer.Key("NetImport");
1150  writer.Uint(this->getPosition(i, Models::LeaderVars::NetImport));
1151  writer.Key("NetExport");
1152  writer.Uint(this->getPosition(i, Models::LeaderVars::NetExport));
1153  writer.Key("CountryImport");
1154  writer.Uint(this->getPosition(i, Models::LeaderVars::CountryImport));
1155  writer.Key("Caps");
1156  writer.Uint(this->getPosition(i, Models::LeaderVars::Caps));
1157  writer.Key("Tax");
1158  writer.Uint(this->getPosition(i, Models::LeaderVars::Tax));
1159  if (this->AllLeadPars.at(i).LeaderParam.tax_revenue) {
1160  writer.Key("QuadraticTax");
1161  writer.Uint(this->getPosition(i, Models::LeaderVars::TaxQuad));
1162  }
1163  writer.Key("DualVar");
1164  writer.Uint(this->getPosition(i, Models::LeaderVars::DualVar));
1165  writer.Key("ConvHullDummy");
1166  writer.Uint(this->getPosition(i, Models::LeaderVars::ConvHullDummy));
1167  writer.Key("End");
1168  writer.Uint(this->getPosition(i, Models::LeaderVars::End));
1169  writer.Key("ShadowPrice");
1170  writer.Uint(
1171  this->getPosition(this->getNcountries() - 1, Models::LeaderVars::End) +
1172  i);
1173  writer.EndObject();
1174  }
1175  writer.EndArray();
1176  writer.EndObject();
1177  writer.Key("Solution");
1178  writer.StartObject();
1179  writer.Key("x");
1180  writer.StartArray();
1181  for (unsigned i = 0; i < x.size(); i++)
1182  writer.Double(x.at(i));
1183  writer.EndArray();
1184  writer.Key("z");
1185  writer.StartArray();
1186  for (unsigned i = 0; i < z.size(); i++)
1187  writer.Double(z.at(i));
1188  writer.EndArray();
1189  writer.EndObject();
1190  writer.EndObject();
1191  ofstream file(filename + ".json");
1192  file << s.GetString();
1193 }
1194 
1195 void Models::EPEC::readSolutionJSON(string filename) {
1199  ifstream ifs(filename + ".json");
1200  if (ifs.good()) {
1201  IStreamWrapper isw(ifs);
1202  Document d;
1203  try {
1204  d.ParseStream(isw);
1205  const Value &x = d["Solution"].GetObject()["x"];
1206  // const Value &z = d["Solution"].GetObject()["z"];
1207  arma::vec new_x;
1208  // arma::vec new_z;
1209  new_x.zeros(x.GetArray().Size());
1210  // new_z.zeros(z.GetArray().Size());
1211 
1212  for (SizeType i = 0; i < this->getnVarinEPEC(); i++)
1213  new_x.at(i) = x[i].GetDouble();
1214 
1215  // for (SizeType i = 0; i < this->getnVarinEPEC(); i++)
1216  // new_z.at(i) = z[i].GetDouble();
1217  ifs.close();
1218  this->warmstart(new_x);
1219  } catch (exception &e) {
1220  cerr << "Exception in Models::readSolutionJSON : cannot read instance "
1221  "file."
1222  << e.what() << '\n';
1223  throw;
1224  } catch (...) {
1225  cerr
1226  << "Exception in Models::readSolutionJSON: cannot read instance file."
1227  << '\n';
1228  throw;
1229  }
1230  } else {
1231  cerr << "Exception in Models::readSolutionJSON : file instance not found."
1232  << '\n';
1233  throw;
1234  }
1235 }
1236 
1237 void Models::EPEC::writeSolution(const int writeLevel, string filename) const {
1243  if (this->Stats.status == Game::EPECsolveStatus::nashEqFound) {
1244  if (writeLevel == 1 || writeLevel == 2) {
1245  this->WriteCountry(0, filename + ".txt", this->sol_x, false);
1246  for (unsigned int ell = 1; ell < this->getNcountries(); ++ell)
1247  this->WriteCountry(ell, filename + ".txt", this->sol_x, true);
1248  this->write(filename + ".txt", true);
1249  }
1250  if (writeLevel == 2 || writeLevel == 0)
1251  this->writeSolutionJSON(filename, this->sol_x, this->sol_z);
1252  } else {
1253  cerr << "Error in Models::EPEC::writeSolution: no solution to write."
1254  << '\n';
1255  }
1256 }
1257 
1258 void Models::EPECInstance::save(string filename) {
1264  StringBuffer s;
1265  PrettyWriter<StringBuffer> writer(s);
1266  writer.StartObject();
1267  writer.Key("nCountries");
1268  writer.Uint(this->Countries.size());
1269  writer.Key("Countries");
1270  writer.StartArray();
1271  for (unsigned i = 0; i < this->Countries.size(); i++) {
1272  writer.StartObject();
1273 
1274  writer.Key("nFollowers");
1275  writer.Uint(this->Countries.at(i).n_followers);
1276 
1277  writer.Key("Name");
1278  string currName = this->Countries.at(i).name;
1279  char nameArray[currName.length() + 1];
1280  strcpy(nameArray, currName.c_str());
1281  writer.String(nameArray);
1282 
1283  writer.Key("DemandParam");
1284  writer.StartObject();
1285  writer.Key("Alpha");
1286  writer.Double(this->Countries.at(i).DemandParam.alpha);
1287  writer.Key("Beta");
1288  writer.Double(this->Countries.at(i).DemandParam.beta);
1289  writer.EndObject();
1290 
1291  writer.Key("TransportationCosts");
1292  writer.StartArray();
1293  for (unsigned j = 0; j < this->Countries.size(); j++)
1294  writer.Double(this->TransportationCosts(i, j));
1295  writer.EndArray();
1296 
1297  writer.Key("LeaderParam");
1298  writer.StartObject();
1299  writer.Key("ImportLimit");
1300  writer.Double(this->Countries.at(i).LeaderParam.import_limit);
1301  writer.Key("ExportLimit");
1302  writer.Double(this->Countries.at(i).LeaderParam.export_limit);
1303  writer.Key("PriceLimit");
1304  writer.Double(this->Countries.at(i).LeaderParam.price_limit);
1305  writer.Key("TaxRevenue");
1306  writer.Bool(this->Countries.at(i).LeaderParam.tax_revenue);
1307  writer.Key("TaxationType");
1308  switch (this->Countries.at(i).LeaderParam.tax_type) {
1310  writer.Int(0);
1311  break;
1313  writer.Int(1);
1314  break;
1315  default:
1316  writer.Int(2);
1317  }
1318  writer.EndObject();
1319 
1320  writer.Key("Followers");
1321  writer.StartObject();
1322 
1323  writer.Key("Names");
1324  writer.StartArray();
1325  for (unsigned j = 0; j < this->Countries.at(i).n_followers; j++) {
1326  string currName = this->Countries.at(i).FollowerParam.names.at(j);
1327  char nameArray[currName.length() + 1];
1328  strcpy(nameArray, currName.c_str());
1329  writer.String(nameArray);
1330  }
1331  writer.EndArray();
1332 
1333  writer.Key("Capacities");
1334  writer.StartArray();
1335  for (unsigned j = 0; j < this->Countries.at(i).n_followers; j++)
1336  writer.Double(this->Countries.at(i).FollowerParam.capacities.at(j));
1337  writer.EndArray();
1338 
1339  writer.Key("LinearCosts");
1340  writer.StartArray();
1341  for (unsigned j = 0; j < this->Countries.at(i).n_followers; j++)
1342  writer.Double(this->Countries.at(i).FollowerParam.costs_lin.at(j));
1343  writer.EndArray();
1344 
1345  writer.Key("QuadraticCosts");
1346  writer.StartArray();
1347  for (unsigned j = 0; j < this->Countries.at(i).n_followers; j++)
1348  writer.Double(this->Countries.at(i).FollowerParam.costs_quad.at(j));
1349  writer.EndArray();
1350 
1351  writer.Key("EmissionCosts");
1352  writer.StartArray();
1353  for (unsigned j = 0; j < this->Countries.at(i).n_followers; j++)
1354  writer.Double(this->Countries.at(i).FollowerParam.emission_costs.at(j));
1355  writer.EndArray();
1356 
1357  writer.Key("TaxCaps");
1358  writer.StartArray();
1359  for (unsigned j = 0; j < this->Countries.at(i).n_followers; j++)
1360  writer.Double(this->Countries.at(i).FollowerParam.tax_caps.at(j));
1361  writer.EndArray();
1362 
1363  writer.EndObject();
1364 
1365  writer.EndObject();
1366  }
1367  writer.EndArray();
1368  writer.EndObject();
1369  ofstream file(filename + ".json");
1370  file << s.GetString();
1371  file.close();
1372 }
1373 
1374 void Models::EPECInstance::load(string filename) {
1380  ifstream ifs(filename + ".json");
1381  if (ifs.good()) {
1382  IStreamWrapper isw(ifs);
1383  Document d;
1384  try {
1385  d.ParseStream(isw);
1386  vector<Models::LeadAllPar> LAP = {};
1387  int nCountries = d["nCountries"].GetInt();
1388  arma::sp_mat TrCo;
1389  TrCo.zeros(nCountries, nCountries);
1390  for (int j = 0; j < nCountries; ++j) {
1391  const Value &c = d["Countries"].GetArray()[j].GetObject();
1392 
1393  Models::FollPar FP;
1394  const Value &cap = c["Followers"]["Capacities"];
1395  for (SizeType i = 0; i < cap.GetArray().Size(); i++) {
1396  FP.capacities.push_back(cap[i].GetDouble());
1397  }
1398  const Value &lc = c["Followers"]["LinearCosts"];
1399  for (SizeType i = 0; i < lc.GetArray().Size(); i++) {
1400  FP.costs_lin.push_back(lc[i].GetDouble());
1401  }
1402  const Value &qc = c["Followers"]["QuadraticCosts"];
1403  for (SizeType i = 0; i < qc.GetArray().Size(); i++) {
1404  FP.costs_quad.push_back(qc[i].GetDouble());
1405  }
1406  const Value &ec = c["Followers"]["EmissionCosts"];
1407  for (SizeType i = 0; i < ec.GetArray().Size(); i++) {
1408  FP.emission_costs.push_back(ec[i].GetDouble());
1409  }
1410  const Value &tc = c["Followers"]["TaxCaps"];
1411  for (SizeType i = 0; i < tc.GetArray().Size(); i++) {
1412  FP.tax_caps.push_back(tc[i].GetDouble());
1413  }
1414  const Value &nm = c["Followers"]["Names"];
1415  for (SizeType i = 0; i < nm.GetArray().Size(); i++) {
1416  FP.names.push_back(nm[i].GetString());
1417  }
1418  for (SizeType i = 0; i < c["TransportationCosts"].GetArray().Size();
1419  i++) {
1420  TrCo.at(j, i) = c["TransportationCosts"].GetArray()[i].GetDouble();
1421  }
1422  bool tax_revenue = false;
1423  if (c["LeaderParam"].HasMember("TaxRevenue")) {
1424  tax_revenue = c["LeaderParam"].GetObject()["TaxRevenue"].GetBool();
1425  }
1426  unsigned int tax_type = 0;
1427  if (c["LeaderParam"].HasMember("TaxationType")) {
1428  tax_type = c["LeaderParam"].GetObject()["TaxationType"].GetInt();
1429  }
1430  LAP.push_back(Models::LeadAllPar(
1431  FP.capacities.size(), c["Name"].GetString(), FP,
1432  {c["DemandParam"].GetObject()["Alpha"].GetDouble(),
1433  c["DemandParam"].GetObject()["Beta"].GetDouble()},
1434  {c["LeaderParam"].GetObject()["ImportLimit"].GetDouble(),
1435  c["LeaderParam"].GetObject()["ExportLimit"].GetDouble(),
1436  c["LeaderParam"].GetObject()["PriceLimit"].GetDouble(),
1437  tax_revenue, tax_type}));
1438  }
1439  ifs.close();
1440  this->Countries = LAP;
1441  this->TransportationCosts = TrCo;
1442  } catch (exception &e) {
1443  cerr << "Exception in Models::load : cannot read instance file."
1444  << e.what() << '\n';
1445  throw;
1446  } catch (...) {
1447  cerr << "Exception in Models::load : cannot read instance file." << '\n';
1448  throw;
1449  }
1450  } else {
1451  cerr << "Exception in Models::load : file instance not found." << '\n';
1452  throw;
1453  }
1454 }
1455 
1456 void Models::EPEC::WriteCountry(const unsigned int i, const string filename,
1457  const arma::vec x, const bool append) const {
1458  // if (!lcp) return;
1459  // const LeadLocs& Loc = this->Locations.at(i);
1460 
1461  ofstream file;
1462  file.open(filename, append ? ios::app : ios::out);
1463  // FILE OPERATIONS START
1464  const LeadAllPar &Params = this->AllLeadPars.at(i);
1465  file << "**************************************************\n";
1466  file << "COUNTRY: " << Params.name << '\n';
1467  file << "**************************************************\n\n";
1468  // Country Variables
1469  unsigned int foll_prod;
1470  foll_prod = this->getPosition(i, Models::LeaderVars::FollowerStart);
1471  // Domestic production
1472  double prod{0};
1473  for (unsigned int j = 0; j < Params.n_followers; ++j)
1474  prod += x.at(foll_prod + j);
1475  // Trade
1476  double Export{x.at(this->getPosition(i, Models::LeaderVars::NetExport))};
1477  double exportPrice{x.at(
1478  this->getPosition(this->getNcountries() - 1, Models::LeaderVars::End) +
1479  i)};
1480  double import{0};
1481  for (unsigned int j = this->getPosition(i, Models::LeaderVars::CountryImport);
1482  j < this->getPosition(i, Models::LeaderVars::CountryImport + 1); ++j)
1483  import += x.at(j);
1484  // Writing national level details
1485  file << "PureStrategy:" << this->isPureStrategy(i) << "\n";
1486  file << Models::prn::label << "Domestic production"
1487  << ":" << Models::prn::val << prod << "\n";
1488  if (Export >= import)
1489  file << Models::prn::label << "Net exports"
1490  << ":" << Models::prn::val << Export - import << "\n";
1491  else
1492  file << Models::prn::label << "Net imports"
1493  << ":" << Models::prn::val << import - Export << "\n";
1494  file << Models::prn::label << "Export price"
1495  << ":" << Models::prn::val << exportPrice << "\n";
1496  file << Models::prn::label << " -> Total Export"
1497  << ":" << Models::prn::val << Export << "\n";
1498  file << Models::prn::label << " -> Total Import"
1499  << ":" << Models::prn::val << import << '\n';
1500  file << Models::prn::label << "Domestic consumed quantity"
1501  << ":" << Models::prn::val << import - Export + prod << "\n";
1502  file << Models::prn::label << "Domestic price"
1503  << ":" << Models::prn::val
1504  << Params.DemandParam.alpha -
1505  Params.DemandParam.beta * (import - Export + prod)
1506  << "\n";
1507 
1508  file.close();
1509 
1510  // Follower productions
1511  file << "- - - - - - - - - - - - - - - - - - - - - - - - - \n";
1512  file << "FOLLOWER DETAILS:\n";
1513  for (unsigned int j = 0; j < Params.n_followers; ++j)
1514  this->WriteFollower(i, j, filename, x);
1515 
1516  file << "\n\n\n";
1517  // FILE OPERATIONS END
1518 }
1519 
1520 void Models::EPEC::WriteFollower(const unsigned int i, const unsigned int j,
1521  const string filename,
1522  const arma::vec x) const {
1523  ofstream file;
1524  file.open(filename, ios::app);
1525 
1526  // Country Variables
1527  const LeadAllPar &Params = this->AllLeadPars.at(i);
1528  unsigned int foll_prod, foll_tax, foll_lim, foll_taxQ;
1529  foll_prod = this->getPosition(i, Models::LeaderVars::FollowerStart);
1530  foll_tax = this->getPosition(i, Models::LeaderVars::Tax);
1531  foll_lim = this->getPosition(i, Models::LeaderVars::Caps);
1532  if (Params.LeaderParam.tax_revenue)
1533  foll_taxQ = this->getPosition(i, Models::LeaderVars::TaxQuad);
1534 
1535  string name;
1536  try {
1537  name = Params.name + " --- " + Params.FollowerParam.names.at(j);
1538  } catch (...) {
1539  name = "Follower " + to_string(j) + " of leader " + to_string(i);
1540  }
1541 
1542  file << "\n"
1543  << name << "\n\n"; //<<" named "<<Params.FollowerParam.names.at(j)<<"\n";
1544  double tax = -1;
1546  tax = x.at(foll_tax + j);
1547  else
1548  tax = x.at(foll_tax);
1549  const double q = x.at(foll_prod + j);
1550  double taxQ = 0;
1551  if (Params.LeaderParam.tax_revenue)
1552  taxQ = q > 0 ? x.at(foll_taxQ + j) / q : x.at(foll_taxQ + j);
1553  const double lim = x.at(foll_lim + j);
1554  const double lin = Params.FollowerParam.costs_lin.at(j);
1555  const double quad = Params.FollowerParam.costs_quad.at(j);
1556 
1557  file << Models::prn::label << "Quantity produced"
1558  << ":" << Models::prn::val << q << '\n';
1559  // file << "x(): " << foll_prod + j << '\n';
1560  file << Models::prn::label << "Capacity of production"
1561  << ":" << Models::prn::val << Params.FollowerParam.capacities.at(j)
1562  << "\n";
1563  file << Models::prn::label << "Limit on production"
1564  << ":" << Models::prn::val << lim << "\n";
1565  // file << "x(): " << foll_lim + j << '\n';
1566  file << Models::prn::label << "Tax imposed"
1567  << ":" << Models::prn::val << tax;
1569  tax = tax * Params.FollowerParam.emission_costs.at(j);
1570  file << " per unit emission; " << tax << " per unit energy";
1571  }
1572  file << "\n";
1573  if (Params.LeaderParam.tax_revenue)
1574  file << Models::prn::label << "Tax imposed (Q)"
1575  << ":" << Models::prn::val << taxQ << "\n";
1576  // file << Models::prn::label << "Tax cap" << ":" <<
1577  // Params.FollowerParam.tax_caps.at(j) << tax << "\n";
1578  // file << "x(): " << foll_tax + j << '\n';
1579  file << Models::prn::label << " -Production cost function"
1580  << ":"
1581  << "\t C(q) = (" << lin << " + " << tax << ")*q + 0.5*" << quad
1582  << "*q^2\n"
1583  << Models::prn::label << " "
1584  << "=" << Models::prn::val << (lin + tax) * q + 0.5 * quad * q * q
1585  << "\n";
1586  file << Models::prn::label << " -Marginal cost of production"
1587  << ":" << Models::prn::val << quad * q + lin + tax << "\n";
1588  file << Models::prn::label << "Emission cost"
1589  << ":" << Models::prn::val << Params.FollowerParam.emission_costs.at(j)
1590  << '\n';
1591 
1592  file.close();
1593 }
1594 
1595 void Models::EPEC::testLCP(const unsigned int i) {
1596  auto country = this->get_LowerLevelNash(i);
1597  LCP CountryLCP(this->env, *country);
1598  CountryLCP.write("dat/LCP_" + to_string(i));
1599  auto model = CountryLCP.LCPasMIP(true);
1600  model->write("dat/CountryLCP_" + to_string(i) + ".lp");
1601  model->write("dat/CountryLCP_" + to_string(i) + ".sol");
1602 }
arma::vec c
Definition: games.h:42
Models::FollPar operator+(const Models::FollPar &F1, const Models::FollPar &F2)
Definition: Models.cpp:162
double import_limit
Definition: models.h:60
Stores the parameters of the follower in a country model.
Definition: models.h:24
Class to handle parameterized quadratic programs(QP)
Definition: games.h:146
string to_string(const GRBConstr &cons, const GRBModel &model)
Definition: Models.cpp:1072
void make_MC_cons(arma::sp_mat &MCLHS, arma::vec &MCRHS) const override
Returns leader&#39;s Market clearing constraints in matrix form.
Definition: Models.cpp:763
double beta
Definition: models.h:53
void make_MC_leader(const unsigned int i)
Makes the market clearing constraint for country i.
Definition: Models.cpp:801
bool tax_revenue
Definition: models.h:70
unsigned int n_followers
Number of followers in the country.
Definition: models.h:99
void WriteFollower(const unsigned int i, const unsigned int j, const std::string filename, const arma::vec x) const
Definition: Models.cpp:1520
void writeSolution(const int writeLevel, std::string filename) const
Definition: Models.cpp:1237
std::vector< Models::LeadAllPar > Countries
LeadAllPar vector.
Definition: models.h:114
double price_limit
Government does not want the price to exceed this limit.
Definition: models.h:64
void write(std::string filename, bool append=true) const
Definition: LCPtoLP.cpp:1431
std::vector< double > costs_lin
Definition: models.h:28
bool dataCheck(const bool chkAllLeadPars=true, const bool chkcountriesLL=true, const bool chkMC_QP=true, const bool chkLeadConses=true, const bool chkLeadRHSes=true, const bool chknImportMarkets=true, const bool chkLocations=true, const bool chkLeaderLocations=true, const bool chkLeadObjec=true) const
Definition: Models.cpp:864
struct LeadAllPar LeadAllPar
Definition: models.h:19
Stores the parameters of the leader in a country model.
Definition: models.h:59
Definition: games.h:702
struct FollPar FollPar
Definition: models.h:16
void testLCP(const unsigned int i)
Definition: Models.cpp:1595
unsigned int getPosition(const unsigned int countryCount, const LeaderVars var=LeaderVars::FollowerStart) const
Gets position of a variable in a country.
Definition: Models.cpp:911
Models::DemPar DemandParam
A struct to hold Demand Parameters.
Definition: models.h:102
double alpha
Definition: models.h:51
std::map< LeaderVars, unsigned int > LeadLocs
Definition: models.h:156
void make_LL_LeadCons(arma::sp_mat &LeadCons, arma::vec &LeadRHS, const LeadAllPar &Param, const Models::LeadLocs &Loc={}, const unsigned int import_lim_cons=1, const unsigned int export_lim_cons=1, const unsigned int price_lim_cons=1, const unsigned int activeTaxCaps=0) const noexcept
Makes the leader constraint matrix and RHS.
Definition: Models.cpp:284
EPEC & unlock()
Unlocks an EPEC model.
Definition: Models.cpp:942
std::vector< double > costs_quad
Definition: models.h:25
Stores the parameters of a country model.
Definition: models.h:98
arma::sp_mat C
Definition: games.h:41
void writeSolutionJSON(std::string filename, const arma::vec x, const arma::vec z) const
Definition: Models.cpp:1122
void increaseVal(LeadLocs &L, const LeaderVars start, const unsigned int val, const bool startnext=true)
Definition: Models.cpp:1033
std::vector< double > capacities
Definition: models.h:31
unsigned int getNduals() const
Gets the number of dual variables in the problem.
Definition: games.h:331
Models::TaxType tax_type
Definition: models.h:67
std::vector< double > tax_caps
Individual tax caps for each follower.
Definition: models.h:37
void load(std::string filename)
Reads the EPECInstance from a file.
Definition: Models.cpp:1374
LeaderVars
Definition: models.h:131
std::string name
Country Name.
Definition: models.h:100
arma::sp_mat TransportationCosts
Transportation costs matrix.
Definition: models.h:115
Models::LeadPar LeaderParam
A struct to hold Leader Parameters.
Definition: models.h:103
void decreaseVal(LeadLocs &L, const LeaderVars start, const unsigned int val, const bool startnext=true)
Definition: Models.cpp:1047
arma::sp_mat Q
Definition: games.h:40
Models::FollPar FollowerParam
A struct to hold Follower Parameters.
Definition: models.h:101
Stores a single Instance.
Definition: models.h:113
Class to handle and solve linear complementarity problems.
Definition: lcptolp.h:41
Solution found for the instance.
double export_limit
Definition: models.h:62
void WriteCountry(const unsigned int i, const std::string filename, const arma::vec x, const bool append=true) const
Definition: Models.cpp:1456
std::vector< std::string > names
Optional Names for the Followers.
Definition: models.h:38
std::unique_ptr< GRBModel > Respond(const std::string name, const arma::vec &x) const
unsigned int n_MCVar
Definition: games.h:513
std::unique_ptr< GRBModel > LCPasMIP(std::vector< unsigned int > FixEq={}, std::vector< unsigned int > FixVar={}, bool solve=false)
virtual void updateLocs() override
Definition: Models.cpp:1018
EPEC & addTranspCosts(const arma::sp_mat &costs)
Adds intercountry transportation costs matrix.
Definition: Models.cpp:639
void add_Leaders_tradebalance_constraints(const unsigned int i)
Adds leaders&#39; trade balance constraints for import-exports.
Definition: Models.cpp:711
void make_obj_leader(const unsigned int i, Game::QP_objective &QP_obj) final
Definition: Models.cpp:955
void init(LeadLocs &L)
Definition: Models.cpp:1061
void readSolutionJSON(const std::string filename)
Definition: Models.cpp:1195
std::unique_ptr< GRBModel > Respond(const unsigned int i, const arma::vec &x) const
Definition: Games.cpp:1366
LeaderVars operator+(Models::LeaderVars a, int b)
Definition: Models.cpp:1068
struct to handle the objective params of MP_Param/QP_Param
Definition: games.h:39
NashGame & addDummy(unsigned int par=0, int position=-1)
Add dummy variables in a NashGame object.
Definition: Games.cpp:917
Game::NashGame * get_LowerLevelNash(const unsigned int i) const
Returns a non-owning pointer to the i -th country&#39;s lower level NashGame.
Definition: Models.cpp:933
bool ParamValid(const LeadAllPar &Param) const
Checks the Validity of Models::LeadAllPar object.
Definition: Models.cpp:188
void make_LL_QP(const LeadAllPar &Params, const unsigned int follower, Game::QP_Param *Foll, const LeadLocs &Loc) const noexcept
Makes the lower level quadratic program object for each follower.
Definition: Models.cpp:221
std::vector< double > emission_costs
Definition: models.h:34
void save(std::string filename)
Writes the EPECInstance from a file.
Definition: Models.cpp:1258
Stores the parameters of the demand curve in a country model.
Definition: models.h:50
Class to model Nash-cournot games with each player playing a QP.
Definition: games.h:249
NashGame & addLeadCons(const arma::vec &a, double b)
Adds Leader constraint to a NashGame object.
Definition: Games.cpp:967
void write(const std::string filename, const unsigned int i, bool append=true) const
EPEC & addCountry(LeadAllPar Params, const unsigned int addnlLeadVars=0)
Models a Standard Nash-Cournot game within a country
Definition: Models.cpp:445
std::ostream & operator<<(std::ostream &ost, const FollPar P)
virtual void prefinalize() override
Empty function - optionally reimplementable in derived class.
Definition: Models.cpp:679