EPEC solve
Solving Equilibrium Problems with Equilibrium Constraints (EPECs)
Games.cpp
Go to the documentation of this file.
1 #include "games.h"
2 #include <algorithm>
3 #include <armadillo>
4 #include <array>
5 #include <boost/log/trivial.hpp>
6 #include <boost/program_options.hpp>
7 #include <chrono>
8 #include <iostream>
9 #include <memory>
10 
11 using namespace std;
12 using namespace Utils;
13 
14 bool Game::isZero(arma::mat M, double tol) noexcept {
23  return (arma::min(arma::min(abs(M))) <= tol);
24 }
25 
26 bool Game::isZero(arma::sp_mat M, double tol) noexcept {
34  if (M.n_nonzero == 0)
35  return true;
36  return (arma::min(arma::min(abs(M))) <= tol);
37 }
38 
39 void Game::print(const perps &C) noexcept {
40  for (auto p : C)
41  cout << "<" << p.first << ", " << p.second << ">"
42  << "\t";
43 }
44 
45 ostream &operator<<(ostream &ost, const perps &C) {
46  for (auto p : C)
47  ost << "<" << p.first << ", " << p.second << ">"
48  << "\t";
49  return ost;
50 }
51 
52 ostream &Game::operator<<(ostream &os, const Game::QP_Param &Q) {
53  os << "Quadratic program with linear inequality constraints: " << '\n';
54  os << Q.getNy() << " decision variables parametrized by " << Q.getNx()
55  << " variables" << '\n';
56  os << Q.getb().n_rows << " linear inequalities" << '\n' << '\n';
57  return os;
58 }
59 
60 void Game::MP_Param::write(string filename, bool) const {
78  this->getQ().save(filename + "_Q.txt", arma::file_type::arma_ascii);
79  this->getC().save(filename + "_C.txt", arma::file_type::arma_ascii);
80  this->getA().save(filename + "_A.txt", arma::file_type::arma_ascii);
81  this->getB().save(filename + "_B.txt", arma::file_type::arma_ascii);
82  this->getc().save(filename + "_c.txt", arma::file_type::arma_ascii);
83  this->getb().save(filename + "_b.txt", arma::file_type::arma_ascii);
84 }
85 
86 void Game::QP_Param::write(string filename, bool append) const {
87  ofstream file;
88  file.open(filename, append ? ios::app : ios::out);
89  file << *this;
90  file << "\n\nOBJECTIVES\n";
91  file << "Q:" << this->getQ();
92  file << "C:" << this->getC();
93  file << "c\n" << this->getc();
94  file << "\n\nCONSTRAINTS\n";
95  file << "A:" << this->getA();
96  file << "B:" << this->getB();
97  file << "b\n" << this->getb();
98  file.close();
99 }
100 
101 Game::MP_Param &Game::MP_Param::addDummy(unsigned int pars, unsigned int vars,
102  int position)
110 {
111  this->Nx += pars;
112  this->Ny += vars;
113  if (vars) {
114  Q = resize_patch(Q, this->Ny, this->Ny);
115  B = resize_patch(B, this->Ncons, this->Ny);
116  c = resize_patch(c, this->Ny);
117  }
118  switch (position) {
119  case -1:
120  if (pars)
121  A = resize_patch(A, this->Ncons, this->Nx);
122  if (vars || pars)
123  C = resize_patch(C, this->Ny, this->Nx);
124  break;
125  case 0:
126  if (pars)
127  A = arma::join_rows(arma::zeros<arma::sp_mat>(this->Ncons, pars), A);
128  if (vars || pars) {
129  C = resize_patch(C, this->Ny, C.n_cols);
130  C = arma::join_rows(arma::zeros<arma::sp_mat>(this->Ny, pars), C);
131  }
132  break;
133  default:
134  if (pars) {
135  arma::sp_mat A_temp =
136  arma::join_rows(A.cols(0, position - 1),
137  arma::zeros<arma::sp_mat>(this->Ncons, pars));
138  if (static_cast<unsigned int>(position) < A.n_cols) {
139  A = arma::join_rows(A_temp, A.cols(position, A.n_cols - 1));
140  } else {
141  A = A_temp;
142  }
143  }
144  if (vars || pars) {
145  C = resize_patch(C, this->Ny, C.n_cols);
146  arma::sp_mat C_temp = arma::join_rows(
147  C.cols(0, position - 1), arma::zeros<arma::sp_mat>(this->Ny, pars));
148  if (static_cast<unsigned int>(position) < C.n_cols) {
149  C = arma::join_rows(C_temp, C.cols(position, C.n_cols - 1));
150  } else {
151  C = C_temp;
152  }
153  }
154  break;
155  };
156  return *this;
157 }
158 
159 unsigned int Game::MP_Param::size()
170 {
171  this->Ny = this->Q.n_rows;
172  this->Nx = this->C.n_cols;
173  this->Ncons = this->b.size();
174  return Ny;
175 }
176 
178 Game::MP_Param::set(const arma::sp_mat &Q, const arma::sp_mat &C,
179  const arma::sp_mat &A, const arma::sp_mat &B,
180  const arma::vec &c, const arma::vec &b)
182 {
183  this->Q = (Q);
184  this->C = (C);
185  this->A = (A);
186  this->B = (B);
187  this->c = (c);
188  this->b = (b);
189  if (!finalize())
190  throw string("Error in MP_Param::set: Invalid data");
191  return *this;
192 }
193 
194 Game::MP_Param &Game::MP_Param::set(arma::sp_mat &&Q, arma::sp_mat &&C,
195  arma::sp_mat &&A, arma::sp_mat &&B,
196  arma::vec &&c, arma::vec &&b)
198 {
199  this->Q = move(Q);
200  this->C = move(C);
201  this->A = move(A);
202  this->B = move(B);
203  this->c = move(c);
204  this->b = move(b);
205  if (!finalize())
206  throw string("Error in MP_Param::set: Invalid data");
207  return *this;
208 }
209 
211  const QP_constraints &cons) {
212  return this->set(obj.Q, obj.C, cons.A, cons.B, obj.c, cons.b);
213 }
214 
216  return this->set(obj.Q, obj.C, cons.A, cons.B, obj.c, cons.b);
217 }
218 
219 bool Game::MP_Param::dataCheck(bool forcesymm) const
235 {
236  if (forcesymm) {
237  }
238  if (this->Q.n_cols != Ny) {
239  return false;
240  }
241  if (this->A.n_cols != Nx) {
242  return false;
243  } // Rest are matrix size compatibility checks
244  if (this->B.n_cols != Ny) {
245  return false;
246  }
247  if (this->C.n_rows != Ny) {
248  return false;
249  }
250  if (this->c.size() != Ny) {
251  return false;
252  }
253  if (this->A.n_rows != Ncons) {
254  return false;
255  }
256  if (this->B.n_rows != Ncons) {
257  return false;
258  }
259  return true;
260 }
261 
263  const QP_constraints &cons, bool checkobj,
264  bool checkcons) {
265  unsigned int Ny = obj.Q.n_rows;
266  unsigned int Nx = obj.C.n_cols;
267  unsigned int Ncons = cons.b.size();
268  if (checkobj && obj.Q.n_cols != Ny) {
269  return false;
270  }
271  if (checkobj && obj.C.n_rows != Ny) {
272  return false;
273  }
274  if (checkobj && obj.c.size() != Ny) {
275  return false;
276  }
277  if (checkcons && cons.A.n_cols != Nx) {
278  return false;
279  } // Rest are matrix size compatibility checks
280  if (checkcons && cons.B.n_cols != Ny) {
281  return false;
282  }
283  if (checkcons && cons.A.n_rows != Ncons) {
284  return false;
285  }
286  if (checkcons && cons.B.n_rows != Ncons) {
287  return false;
288  }
289  return true;
290 }
291 
292 bool Game::QP_Param::operator==(const QP_Param &Q2) const {
293  if (!Game::isZero(this->Q - Q2.getQ()))
294  return false;
295  if (!Game::isZero(this->C - Q2.getC()))
296  return false;
297  if (!Game::isZero(this->A - Q2.getA()))
298  return false;
299  if (!Game::isZero(this->B - Q2.getB()))
300  return false;
301  if (!Game::isZero(this->c - Q2.getc()))
302  return false;
303  if (!Game::isZero(this->b - Q2.getb()))
304  return false;
305  return true;
306 }
307 
310 {
311  if (this->made_yQy)
312  return 0;
313  GRBVar y[this->Ny];
314  for (unsigned int i = 0; i < Ny; i++)
315  y[i] = this->QuadModel.addVar(0, GRB_INFINITY, 0, GRB_CONTINUOUS,
316  "y_" + to_string(i));
317  GRBQuadExpr yQy{0};
318  for (auto val = Q.begin(); val != Q.end(); ++val) {
319  unsigned int i, j;
320  double value = (*val);
321  i = val.row();
322  j = val.col();
323  yQy += 0.5 * y[i] * value * y[j];
324  }
325  QuadModel.setObjective(yQy, GRB_MINIMIZE);
326  QuadModel.update();
327  this->made_yQy = true;
328  return 0;
329 }
330 
331 unique_ptr<GRBModel> Game::QP_Param::solveFixed(
332  arma::vec x
333  )
341 {
342  this->make_yQy();
343  if (x.size() != this->Nx)
345  throw "Game::QP_Param::solveFixed: Invalid argument size: " +
346  to_string(x.size()) + " != " + to_string(Nx);
347  unique_ptr<GRBModel> model(new GRBModel(this->QuadModel));
348  try {
349  GRBQuadExpr yQy = model->getObjective();
350  arma::vec Cx, Ax;
351  Cx = this->C * x;
352  Ax = this->A * x;
353  GRBVar y[this->Ny];
354  for (unsigned int i = 0; i < this->Ny; i++) {
355  y[i] = model->getVarByName("y_" + to_string(i));
356  yQy += (Cx[i] + c[i]) * y[i];
357  }
358  model->setObjective(yQy, GRB_MINIMIZE);
359  for (unsigned int i = 0; i < this->Ncons; i++) {
360  GRBLinExpr LHS{0};
361  for (auto j = B.begin_row(i); j != B.end_row(i); ++j)
362  LHS += (*j) * y[j.col()];
363  model->addConstr(LHS, GRB_LESS_EQUAL, b[i] - Ax[i]);
364  }
365  model->update();
366  model->set(GRB_IntParam_OutputFlag, 0);
367  model->optimize();
368  } catch (const char *e) {
369  cerr << " Error in Game::QP_Param::solveFixed: " << e << '\n';
370  throw;
371  } catch (string e) {
372  cerr << "String: Error in Game::QP_Param::solveFixed: " << e << '\n';
373  throw;
374  } catch (exception &e) {
375  cerr << "Exception: Error in Game::QP_Param::solveFixed: " << e.what()
376  << '\n';
377  throw;
378  } catch (GRBException &e) {
379  cerr << "GRBException: Error in Game::QP_Param::solveFixed: "
380  << e.getErrorCode() << "; " << e.getMessage() << '\n';
381  throw;
382  }
383  return model;
384 }
385 
386 Game::QP_Param &Game::QP_Param::addDummy(unsigned int pars, unsigned int vars,
387  int position)
394 {
395  // if ((pars || vars))
396  // BOOST_LOG_TRIVIAL(trace)
397  // << "From Game::QP_Param::addDummyVars:\t You might have to rerun
398  // Games::QP_Param::KKT since you have now changed the number of variables in
399  // the NashGame.";
400 
401  // Call the superclass function
402  try {
403  MP_Param::addDummy(pars, vars, position);
404  } catch (const char *e) {
405  cerr << " Error in Game::QP_Param::addDummy: " << e << '\n';
406  throw;
407  } catch (string e) {
408  cerr << "String: Error in Game::QP_Param::addDummy: " << e << '\n';
409  throw;
410  } catch (exception &e) {
411  cerr << "Exception: Error in Game::QP_Param::addDummy: " << e.what()
412  << '\n';
413  throw;
414  }
415  return *this;
416 }
417 unsigned int Game::QP_Param::KKT(arma::sp_mat &M, arma::sp_mat &N,
418  arma::vec &q) const
420 
427 {
428  if (!this->dataCheck()) {
429  throw string("Inconsistent data for KKT of Game::QP_Param::KKT");
430  return 0;
431  }
432  M = arma::join_cols( // In armadillo join_cols(A, B) is same as [A;B] in
433  // Matlab
434  // join_rows(A, B) is same as [A B] in Matlab
435  arma::join_rows(this->Q, this->B.t()),
436  arma::join_rows(-this->B,
437  arma::zeros<arma::sp_mat>(this->Ncons, this->Ncons)));
438  // M.print_dense();
439  N = arma::join_cols(this->C, -this->A);
440  // N.print_dense();
441  q = arma::join_cols(this->c, this->b);
442  // q.print();
443  return M.n_rows;
444 }
445 
447 Game::QP_Param::set(const arma::sp_mat &Q, const arma::sp_mat &C,
448  const arma::sp_mat &A, const arma::sp_mat &B,
449  const arma::vec &c, const arma::vec &b)
451 {
452  this->made_yQy = false;
453  try {
454  MP_Param::set(Q, C, A, B, c, b);
455  } catch (string &e) {
456  cerr << "String: " << e << '\n';
457  throw string("Error in QP_Param::set: Invalid Data");
458  }
459  return *this;
460 }
461 
462 Game::QP_Param &Game::QP_Param::set(arma::sp_mat &&Q, arma::sp_mat &&C,
463  arma::sp_mat &&A, arma::sp_mat &&B,
464  arma::vec &&c, arma::vec &&b)
466 {
467  this->made_yQy = false;
468  try {
469  MP_Param::set(Q, C, A, B, c, b);
470  } catch (string &e) {
471  cerr << "String: " << e << '\n';
472  throw string("Error in QP_Param::set: Invalid Data");
473  }
474  return *this;
475 }
476 
480 {
481  return this->set(move(obj.Q), move(obj.C), move(cons.A), move(cons.B),
482  move(obj.c), move(cons.b));
483 }
484 
486  const QP_constraints &cons) {
487  return this->set(obj.Q, obj.C, cons.A, cons.B, obj.c, cons.b);
488 }
489 
490 double Game::QP_Param::computeObjective(const arma::vec &y, const arma::vec &x,
491  bool checkFeas, double tol) const {
498  if (y.n_rows != this->getNy())
499  throw string("Error in QP_Param::computeObjective: Invalid size of y");
500  if (x.n_rows != this->getNx())
501  throw string("Error in QP_Param::computeObjective: Invalid size of x");
502  if (checkFeas) {
503  arma::vec slack = A * x + B * y - b;
504  if (slack.n_rows) // if infeasible
505  if (slack.max() >= tol)
506  return GRB_INFINITY;
507  if (y.min() <= -tol) // if infeasible
508  return GRB_INFINITY;
509  }
510  arma::vec obj = 0.5 * y.t() * Q * y + (C * x).t() * y + c.t() * y;
511  return obj(0);
512 }
513 
514 void Game::QP_Param::save(string filename, bool erase) const {
519  Utils::appendSave(string("QP_Param"), filename, erase);
520  Utils::appendSave(this->Q, filename, string("QP_Param::Q"), false);
521  Utils::appendSave(this->A, filename, string("QP_Param::A"), false);
522  Utils::appendSave(this->B, filename, string("QP_Param::B"), false);
523  Utils::appendSave(this->C, filename, string("QP_Param::C"), false);
524  Utils::appendSave(this->b, filename, string("QP_Param::b"), false);
525  Utils::appendSave(this->c, filename, string("QP_Param::c"), false);
526  BOOST_LOG_TRIVIAL(trace) << "Saved QP_Param to file " << filename;
527 }
528 
529 long int Game::QP_Param::load(string filename, long int pos) {
547  arma::sp_mat Q, A, B, C;
548  arma::vec c, b;
549  string headercheck;
550  pos = Utils::appendRead(headercheck, filename, pos);
551  if (headercheck != "QP_Param")
552  throw string("Error in QP_Param::load: In valid header - ") + headercheck;
553  pos = Utils::appendRead(Q, filename, pos, string("QP_Param::Q"));
554  pos = Utils::appendRead(A, filename, pos, string("QP_Param::A"));
555  pos = Utils::appendRead(B, filename, pos, string("QP_Param::B"));
556  pos = Utils::appendRead(C, filename, pos, string("QP_Param::C"));
557  pos = Utils::appendRead(b, filename, pos, string("QP_Param::b"));
558  pos = Utils::appendRead(c, filename, pos, string("QP_Param::c"));
559  this->set(Q, C, A, B, c, b);
560  return pos;
561 }
562 Game::NashGame::NashGame(GRBEnv *e, vector<shared_ptr<QP_Param>> Players,
563  arma::sp_mat MC, arma::vec MCRHS,
564  unsigned int n_LeadVar, arma::sp_mat LeadA,
565  arma::vec LeadRHS)
566  : env{e}, LeaderConstraints{LeadA}, LeaderConsRHS{LeadRHS}
586 {
587  // Setting the class variables
588  this->n_LeadVar = n_LeadVar;
589  this->Nplayers = Players.size();
590  this->Players = Players;
591  this->MarketClearing = MC;
592  this->MCRHS = MCRHS;
593  // Setting the size of class variable vectors
594  this->primal_position.resize(this->Nplayers + 1);
595  this->dual_position.resize(this->Nplayers + 1);
596  this->set_positions();
597 }
598 
600  : env{N.env}, LeaderConstraints{N.LeaderConstraints},
601  LeaderConsRHS{N.LeaderConsRHS}, Nplayers{N.Nplayers}, Players{N.Players},
602  MarketClearing{N.MarketClearing}, MCRHS{N.MCRHS}, n_LeadVar{N.n_LeadVar} {
603  // Setting the size of class variable vectors
604  this->primal_position.resize(this->Nplayers + 1);
605  this->dual_position.resize(this->Nplayers + 1);
606  this->set_positions();
607 }
608 
609 void Game::NashGame::save(string filename, bool erase) const {
610  Utils::appendSave(string("NashGame"), filename, erase);
611  Utils::appendSave(this->Nplayers, filename, string("NashGame::Nplayers"),
612  false);
613  for (unsigned int i = 0; i < this->Nplayers; ++i)
614  this->Players.at(i)->save(filename, false);
615  Utils::appendSave(this->MarketClearing, filename,
616  string("NashGame::MarketClearing"), false);
617  Utils::appendSave(this->MCRHS, filename, string("NashGame::MCRHS"), false);
618  Utils::appendSave(this->LeaderConstraints, filename,
619  string("NashGame::LeaderConstraints"), false);
620  Utils::appendSave(this->LeaderConsRHS, filename,
621  string("NashGame::LeaderConsRHS"), false);
622  Utils::appendSave(this->n_LeadVar, filename, string("NashGame::n_LeadVar"),
623  false);
624  BOOST_LOG_TRIVIAL(trace) << "Saved NashGame to file " << filename;
625 }
626 
627 long int Game::NashGame::load(string filename, long int pos) {
647  if (!this->env)
648  throw string("Error in NashGame::load: To load NashGame from file, it has "
649  "to be constructed using NashGame(GRBEnv*) constructor");
650  string headercheck;
651  pos = Utils::appendRead(headercheck, filename, pos);
652  if (headercheck != "NashGame")
653  throw string("Error in NashGame::load: In valid header - ") + headercheck;
654  unsigned int Nplayers;
655  pos =
656  Utils::appendRead(Nplayers, filename, pos, string("NashGame::Nplayers"));
657  vector<shared_ptr<QP_Param>> Players;
658  Players.resize(Nplayers);
659  for (unsigned int i = 0; i < Nplayers; ++i) {
660  // Players.at(i) = std::make_shared<Game::QP_Param>(this->env);
661  auto temp = shared_ptr<Game::QP_Param>(new Game::QP_Param(this->env));
662  Players.at(i) = temp;
663  pos = Players.at(i)->load(filename, pos);
664  }
665  arma::sp_mat MarketClearing;
666  pos = Utils::appendRead(MarketClearing, filename, pos,
667  string("NashGame::MarketClearing"));
668  arma::vec MCRHS;
669  pos = Utils::appendRead(MCRHS, filename, pos, string("NashGame::MCRHS"));
670  arma::sp_mat LeaderConstraints;
671  pos = Utils::appendRead(LeaderConstraints, filename, pos,
672  string("NashGame::LeaderConstraints"));
673  arma::vec LeaderConsRHS;
674  pos = Utils::appendRead(LeaderConsRHS, filename, pos,
675  string("NashGame::LeaderConsRHS"));
676  unsigned int n_LeadVar;
677  pos = Utils::appendRead(n_LeadVar, filename, pos,
678  string("NashGame::n_LeadVar"));
679  // Setting the class variables
680  this->n_LeadVar = n_LeadVar;
681  this->Players = Players;
682  this->Nplayers = Nplayers;
683  this->MarketClearing = MarketClearing;
684  this->MCRHS = MCRHS;
685  // Setting the size of class variable vectors
686  this->primal_position.resize(this->Nplayers + 1);
687  this->dual_position.resize(this->Nplayers + 1);
688  this->set_positions();
689  return pos;
690 }
691 
700 {
701  // Defining the variable value
702  unsigned int pr_cnt{0},
703  dl_cnt{0}; // Temporary variables - primal count and dual count
704  for (unsigned int i = 0; i < Nplayers; i++) {
705  primal_position.at(i) = pr_cnt;
706  pr_cnt += Players.at(i)->getNy();
707  }
708 
709  // Pushing back the end of primal position
710  primal_position.at(Nplayers) = (pr_cnt);
711  dl_cnt = pr_cnt; // From now on, the space is for dual variables.
712  this->MC_dual_position = dl_cnt;
713  this->Leader_position = dl_cnt + MCRHS.n_rows;
714  dl_cnt += (MCRHS.n_rows + n_LeadVar);
715  for (unsigned int i = 0; i < Nplayers; i++) {
716  dual_position.at(i) = dl_cnt;
717  dl_cnt += Players.at(i)->getb().n_rows;
718  }
719  // Pushing back the end of dual position
720  dual_position.at(Nplayers) = (dl_cnt);
721 }
722 
724  arma::sp_mat &M,
725  arma::vec &q,
726  perps &Compl,
727  bool writeToFile,
728  string M_name,
729  string q_name
730 ) const {
734 
744  // To store the individual KKT conditions for each player.
745  vector<arma::sp_mat> Mi(Nplayers), Ni(Nplayers);
746  vector<arma::vec> qi(Nplayers);
747 
748  unsigned int NvarFollow{0}, NvarLead{0};
749  NvarLead =
750  this->dual_position.back(); // Number of Leader variables (all variables)
751  // Below is not strictly the follower variables,
752  // But the count of set of variables which dont have
753  // a matching complementarity eqn
754  NvarFollow = NvarLead - this->n_LeadVar;
755  M.zeros(NvarFollow, NvarLead);
756  q.zeros(NvarFollow);
757  // Get the KKT conditions for each player
758 
759  for (unsigned int i = 0; i < Nplayers; i++) {
760  this->Players[i]->KKT(Mi[i], Ni[i], qi[i]);
761  unsigned int Nprim, Ndual;
762  Nprim = this->Players[i]->getNy();
763  Ndual = this->Players[i]->getA().n_rows;
764  // Adding the primal equations
765  // Region 1 in Formulate LCP.ipe
766  BOOST_LOG_TRIVIAL(trace) << "Game::NashGame::FormulateLCP: Region 1";
767  if (i > 0) { // For the first player, no need to add anything 'before' 0-th
768  // position
769  M.submat(this->primal_position.at(i), 0,
770  this->primal_position.at(i + 1) - 1,
771  this->primal_position.at(i) - 1) =
772  Ni[i].submat(0, 0, Nprim - 1, this->primal_position.at(i) - 1);
773  }
774  // Region 2 in Formulate LCP.ipe
775  BOOST_LOG_TRIVIAL(trace) << "Game::NashGame::FormulateLCP: Region 2";
776  M.submat(this->primal_position.at(i), this->primal_position.at(i),
777  this->primal_position.at(i + 1) - 1,
778  this->primal_position.at(i + 1) - 1) =
779  Mi[i].submat(0, 0, Nprim - 1, Nprim - 1);
780  // Region 3 in Formulate LCP.ipe
781  BOOST_LOG_TRIVIAL(trace) << "Game::NashGame::FormulateLCP: Region 3";
782  if (this->primal_position.at(i + 1) != this->dual_position.at(0)) {
783  M.submat(this->primal_position.at(i), this->primal_position.at(i + 1),
784  this->primal_position.at(i + 1) - 1,
785  this->dual_position.at(0) - 1) =
786  Ni[i].submat(0, this->primal_position.at(i), Nprim - 1,
787  Ni[i].n_cols - 1);
788  }
789  // Region 4 in Formulate LCP.ipe
790  BOOST_LOG_TRIVIAL(trace) << "Game::NashGame::FormulateLCP: Region 4";
791  if (this->dual_position.at(i) != this->dual_position.at(i + 1)) {
792  M.submat(this->primal_position.at(i), this->dual_position.at(i),
793  this->primal_position.at(i + 1) - 1,
794  this->dual_position.at(i + 1) - 1) =
795  Mi[i].submat(0, Nprim, Nprim - 1, Nprim + Ndual - 1);
796  }
797  // RHS
798  BOOST_LOG_TRIVIAL(trace) << "Game::NashGame::FormulateLCP: Region RHS";
799  q.subvec(this->primal_position.at(i), this->primal_position.at(i + 1) - 1) =
800  qi[i].subvec(0, Nprim - 1);
801  for (unsigned int j = this->primal_position.at(i);
802  j < this->primal_position.at(i + 1); j++)
803  Compl.push_back({j, j});
804  // Adding the dual equations
805  // Region 5 in Formulate LCP.ipe
806  BOOST_LOG_TRIVIAL(trace) << "Game::NashGame::FormulateLCP: Region 5";
807  if (Ndual > 0) {
808  if (i > 0) // For the first player, no need to add anything 'before' 0-th
809  // position
810  M.submat(this->dual_position.at(i) - n_LeadVar, 0,
811  this->dual_position.at(i + 1) - n_LeadVar - 1,
812  this->primal_position.at(i) - 1) =
813  Ni[i].submat(Nprim, 0, Ni[i].n_rows - 1,
814  this->primal_position.at(i) - 1);
815  // Region 6 in Formulate LCP.ipe
816  BOOST_LOG_TRIVIAL(trace) << "Game::NashGame::FormulateLCP: Region 6";
817  M.submat(this->dual_position.at(i) - n_LeadVar,
818  this->primal_position.at(i),
819  this->dual_position.at(i + 1) - n_LeadVar - 1,
820  this->primal_position.at(i + 1) - 1) =
821  Mi[i].submat(Nprim, 0, Nprim + Ndual - 1, Nprim - 1);
822  // Region 7 in Formulate LCP.ipe
823  BOOST_LOG_TRIVIAL(trace) << "Game::NashGame::FormulateLCP: Region 7";
824  if (this->dual_position.at(0) != this->primal_position.at(i + 1)) {
825  M.submat(this->dual_position.at(i) - n_LeadVar,
826  this->primal_position.at(i + 1),
827  this->dual_position.at(i + 1) - n_LeadVar - 1,
828  this->dual_position.at(0) - 1) =
829  Ni[i].submat(Nprim, this->primal_position.at(i), Ni[i].n_rows - 1,
830  Ni[i].n_cols - 1);
831  }
832  // Region 8 in Formulate LCP.ipe
833  BOOST_LOG_TRIVIAL(trace) << "Game::NashGame::FormulateLCP: Region 8";
834  M.submat(this->dual_position.at(i) - n_LeadVar, this->dual_position.at(i),
835  this->dual_position.at(i + 1) - n_LeadVar - 1,
836  this->dual_position.at(i + 1) - 1) =
837  Mi[i].submat(Nprim, Nprim, Nprim + Ndual - 1, Nprim + Ndual - 1);
838  // RHS
839  BOOST_LOG_TRIVIAL(trace) << "Game::NashGame::FormulateLCP: Region RHS";
840  q.subvec(this->dual_position.at(i) - n_LeadVar,
841  this->dual_position.at(i + 1) - n_LeadVar - 1) =
842  qi[i].subvec(Nprim, qi[i].n_rows - 1);
843  for (unsigned int j = this->dual_position.at(i) - n_LeadVar;
844  j < this->dual_position.at(i + 1) - n_LeadVar; j++)
845  Compl.push_back({j, j + n_LeadVar});
846  }
847  }
848  BOOST_LOG_TRIVIAL(trace) << "Game::NashGame::FormulateLCP: MC RHS";
849  if (this->MCRHS.n_elem >= 1) // It is possible that it is a Cournot game and
850  // there are no MC conditions!
851  {
852  M.submat(this->MC_dual_position, 0, this->Leader_position - 1,
853  this->dual_position.at(0) - 1) = this->MarketClearing;
854  q.subvec(this->MC_dual_position, this->Leader_position - 1) = -this->MCRHS;
855  for (unsigned int j = this->MC_dual_position; j < this->Leader_position;
856  j++)
857  Compl.push_back({j, j});
858  }
859  if (writeToFile) {
860  M.save(M_name, arma::coord_ascii);
861  q.save(q_name, arma::arma_ascii);
862  }
863  return *this;
864 }
865 
874 {
875  arma::sp_mat A_in = this->LeaderConstraints;
876  arma::sp_mat A_out_expl, A_out_MC, A_out;
877  unsigned int NvarLead{0};
878  NvarLead =
879  this->dual_position.back(); // Number of Leader variables (all variables)
880  // NvarFollow = NvarLead - this->n_LeadVar;
881 
882  unsigned int n_Row, n_Col;
883  n_Row = A_in.n_rows;
884  n_Col = A_in.n_cols;
885  A_out_expl.zeros(n_Row, NvarLead);
886  A_out_MC.zeros(2 * this->MarketClearing.n_rows, NvarLead);
887 
888  try {
889  if (A_in.n_rows) {
890  // Primal variables i.e., everything before MCduals are the same!
891  A_out_expl.cols(0, this->MC_dual_position - 1) =
892  A_in.cols(0, this->MC_dual_position - 1);
893  A_out_expl.cols(this->Leader_position, this->dual_position.at(0) - 1) =
894  A_in.cols(this->MC_dual_position, n_Col - 1);
895  }
896  if (this->MCRHS.n_rows) {
897  // MC constraints can be written as if they are leader constraints
898  A_out_MC.submat(0, 0, this->MCRHS.n_rows - 1,
899  this->dual_position.at(0) - 1) = this->MarketClearing;
900  A_out_MC.submat(this->MCRHS.n_rows, 0, 2 * this->MCRHS.n_rows - 1,
901  this->dual_position.at(0) - 1) = -this->MarketClearing;
902  }
903  return arma::join_cols(A_out_expl, A_out_MC);
904  } catch (const char *e) {
905  cerr << "Error in NashGame::RewriteLeadCons: " << e << '\n';
906  throw;
907  } catch (string e) {
908  cerr << "String: Error in NashGame::RewriteLeadCons: " << e << '\n';
909  throw;
910  } catch (exception &e) {
911  cerr << "Exception: Error in NashGame::RewriteLeadCons: " << e.what()
912  << '\n';
913  throw;
914  }
915 }
916 
917 Game::NashGame &Game::NashGame::addDummy(unsigned int par, int position)
925 {
926  for (auto &q : this->Players)
927  q->addDummy(par, 0, position);
928 
929  this->n_LeadVar += par;
930  if (this->LeaderConstraints.n_rows) {
931  auto nnR = this->LeaderConstraints.n_rows;
932  auto nnC = this->LeaderConstraints.n_cols;
933  switch (position) {
934  case -1:
935  this->LeaderConstraints =
936  resize_patch(this->LeaderConstraints, nnR, nnC + par);
937  break;
938  case 0:
939  this->LeaderConstraints = arma::join_rows(
940  arma::zeros<arma::sp_mat>(nnR, par), this->LeaderConstraints);
941  break;
942  default:
943  arma::sp_mat lC = arma::join_rows(LeaderConstraints.cols(0, position - 1),
944  arma::zeros<arma::sp_mat>(nnR, par));
945 
946  this->LeaderConstraints =
947  arma::join_rows(lC, LeaderConstraints.cols(position, nnC - 1));
948  break;
949  };
950  }
951  if (this->MarketClearing.n_rows) {
952  auto nnR = this->MarketClearing.n_rows;
953  auto nnC = this->MarketClearing.n_cols;
954  switch (position) {
955  case -1:
956  this->MarketClearing = resize_patch(this->MarketClearing, nnR, nnC + par);
957  break;
958  default:
959  BOOST_LOG_TRIVIAL(error)
960  << "addDummy at non-final position not implemented";
961  }
962  }
963  this->set_positions();
964  return *this;
965 }
966 
967 Game::NashGame &Game::NashGame::addLeadCons(const arma::vec &a, double b)
974 {
975  auto nC = this->LeaderConstraints.n_cols;
976  if (a.n_elem != nC)
977  throw string("Error in NashGame::addLeadCons: Leader constraint size "
978  "incompatible --- ") +
979  to_string(a.n_elem) + string(" != ") + to_string(nC);
980  auto nR = this->LeaderConstraints.n_rows;
981  this->LeaderConstraints = resize_patch(this->LeaderConstraints, nR + 1, nC);
982  // (static_cast<arma::mat>(a)).t(); // Apparently this is not reqd! a.t()
983  // already works in newer versions of armadillo
984  LeaderConstraints.row(nR) = a.t();
985  this->LeaderConsRHS = resize_patch(this->LeaderConsRHS, nR + 1);
986  this->LeaderConsRHS(nR) = b;
987  return *this;
988 }
989 
990 void Game::NashGame::write(string filename, bool append, bool KKT) const {
991  ofstream file;
992  file.open(filename + ".nash", append ? ios::app : ios::out);
993  file << *this;
994  file << "\n\n\n\n\n\n\n";
995  file << "\nLeaderConstraints: " << this->LeaderConstraints;
996  file << "\nLeaderConsRHS\n" << this->LeaderConsRHS;
997  file << "\nMarketClearing: " << this->MarketClearing;
998  file << "\nMCRHS\n" << this->MCRHS;
999 
1000  file.close();
1001 
1002  // this->LeaderConstraints.save(filename+"_LeaderConstraints.txt",
1003  // arma::file_type::arma_ascii);
1004  // this->LeaderConsRHS.save(filename+"_LeaderConsRHS.txt",
1005  // arma::file_type::arma_ascii);
1006  // this->MarketClearing.save(filename+"_MarketClearing.txt",
1007  // arma::file_type::arma_ascii); this->MCRHS.save(filename+"_MCRHS.txt",
1008  // arma::file_type::arma_ascii);
1009 
1010  int count{0};
1011  for (const auto &pl : this->Players) {
1012  // pl->QP_Param::write(filename+"_Players_"+to_string(count++), append);
1013  file << "--------------------------------------------------\n";
1014  file.open(filename + ".nash", ios::app);
1015  file << "\n\n\n\n PLAYER " << count++ << "\n\n";
1016  file.close();
1017  pl->QP_Param::write(filename + ".nash", true);
1018  }
1019 
1020  file.open(filename + ".nash", ios::app);
1021  file << "--------------------------------------------------\n";
1022  file << "\nPrimal Positions:\t";
1023  for (const auto pos : primal_position)
1024  file << pos << " ";
1025  file << "\nDual Positions:\t";
1026  for (const auto pos : dual_position)
1027  file << pos << " ";
1028  file << "\nMC dual position:\t" << this->MC_dual_position;
1029  file << "\nLeader position:\t" << this->Leader_position;
1030  file << "\nnLeader:\t" << this->n_LeadVar;
1031 
1032  if (KKT) {
1033  arma::sp_mat M;
1034  arma::vec q;
1035  perps Compl;
1036  this->FormulateLCP(M, q, Compl);
1037  file << "\n\n\n KKT CONDITIONS - LCP\n";
1038  file << "\nM: " << M;
1039  file << "\nq:\n" << q;
1040  file << "\n Complementarities:\n";
1041  for (const auto &p : Compl)
1042  file << "<" << p.first << ", " << p.second << ">"
1043  << "\t";
1044  }
1045 
1046  file << "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n";
1047 
1048  file.close();
1049 }
1050 
1051 unique_ptr<GRBModel> Game::NashGame::Respond(
1052  unsigned int player,
1053  const arma::vec &x,
1054  bool fullvec
1056 ) const
1067 {
1068  arma::vec solOther;
1069  unsigned int nVar{this->getNprimals() + this->getNshadow() +
1070  this->getNleaderVars()};
1071  unsigned int nStart, nEnd;
1072  nStart = this->primal_position.at(
1073  player); // Start of the player-th player's primals
1074  nEnd = this->primal_position.at(
1075  player + 1); // Start of the player+1-th player's primals or LeaderVrs if
1076  // player is the last player.
1077  if (fullvec) {
1078  solOther.zeros(nVar - nEnd + nStart);
1079  if (nStart > 0)
1080  solOther.subvec(0, nStart - 1) = x.subvec(0, nStart - 1);
1081  if (nEnd < nVar)
1082  solOther.subvec(nStart, nVar + nStart - nEnd - 1) =
1083  x.subvec(nEnd,
1084  nVar - 1); // Discard any dual variables in x
1085  } else {
1086  solOther.zeros(nVar - nEnd + nStart);
1087  solOther = x.subvec(0, nVar - nEnd + nStart -
1088  1); // Discard any dual variables in x
1089  }
1090 
1091  return this->Players.at(player)->solveFixed(solOther);
1092 }
1093 
1095  arma::vec &sol,
1096  unsigned int player,
1097  const arma::vec &x,
1098  bool fullvec
1100 ) const {
1111  auto model = this->Respond(player, x, fullvec);
1112  // Check if the model is solved optimally
1113  const int status = model->get(GRB_IntAttr_Status);
1114  if (status == GRB_OPTIMAL) {
1115  unsigned int Nx =
1116  this->primal_position.at(player + 1) - this->primal_position.at(player);
1117  sol.zeros(Nx);
1118  for (unsigned int i = 0; i < Nx; ++i)
1119  sol.at(i) =
1120  model->getVarByName("y_" + to_string(i)).get(GRB_DoubleAttr_X);
1121 
1122  return model->get(GRB_DoubleAttr_ObjVal);
1123  } else
1124  return GRB_INFINITY;
1125 }
1126 
1127 arma::vec Game::NashGame::ComputeQPObjvals(const arma::vec &x,
1128  bool checkFeas) const {
1136  arma::vec vals;
1137  vals.zeros(this->Nplayers);
1138  for (unsigned int i = 0; i < this->Nplayers; ++i) {
1139  unsigned int nVar{this->getNprimals() + this->getNshadow() +
1140  this->getNleaderVars()};
1141  unsigned int nStart, nEnd;
1142  nStart = this->primal_position.at(i);
1143  nEnd = this->primal_position.at(i + 1);
1144 
1145  arma::vec x_i, x_minus_i;
1146 
1147  x_minus_i.zeros(nVar - nEnd + nStart);
1148  if (nStart > 0) {
1149  x_minus_i.subvec(0, nStart - 1) = x.subvec(0, nStart - 1);
1150  }
1151  if (nEnd < nVar) {
1152  x_minus_i.subvec(nStart, nVar + nStart - nEnd - 1) =
1153  x.subvec(nEnd,
1154  nVar - 1); // Discard any dual variables in x
1155  }
1156 
1157  x_i = x.subvec(nStart, nEnd - 1);
1158 
1159  vals.at(i) =
1160  this->Players.at(i)->computeObjective(x_i, x_minus_i, checkFeas);
1161  }
1162 
1163  return vals;
1164 }
1165 
1166 bool Game::NashGame::isSolved(const arma::vec &sol, unsigned int &violPlayer,
1167  arma::vec &violSol, double tol) const {
1179  arma::vec objvals = this->ComputeQPObjvals(sol, true);
1180  for (unsigned int i = 0; i < this->Nplayers; ++i) {
1181  double val = this->RespondSol(violSol, i, sol, true);
1182  if (val == GRB_INFINITY)
1183  return false;
1184  if (abs(val - objvals.at(i)) > tol) {
1185  violPlayer = i;
1186  return false;
1187  }
1188  }
1189  return true;
1190 }
1191 
1192 // EPEC stuff
1193 
1201 {}
1202 
1210 {}
1211 
1217  BOOST_LOG_TRIVIAL(warning) << "Game::EPEC::resetLCP: resetting LCPs.";
1218  for (unsigned int i = 0; i < this->nCountr; ++i) {
1219  if (this->countries_LCP.at(i))
1220  this->countries_LCP.at(i).reset();
1221  this->countries_LCP.at(i) = std::unique_ptr<Game::LCP>(
1222  new LCP(this->env, *this->countries_LL.at(i).get()));
1223  }
1224 }
1225 
1236 {
1237  if (this->finalized)
1238  cerr << "Warning in Game::EPEC::finalize: Model already finalized\n";
1239 
1240  this->nCountr = this->getNcountries();
1243  this->prefinalize();
1244 
1245  try {
1246  this->convexHullVariables = std::vector<unsigned int>(this->nCountr, 0);
1247  BOOST_LOG_TRIVIAL(trace) << "Finalizing...";
1248  this->Stats.feasiblePolyhedra = std::vector<unsigned int>(this->nCountr, 0);
1249  this->computeLeaderLocations(this->n_MCVar);
1250  // Initialize leader objective and country_QP
1251  this->LeadObjec = vector<shared_ptr<Game::QP_objective>>(nCountr);
1252  this->LeadObjec_ConvexHull =
1253  vector<shared_ptr<Game::QP_objective>>(nCountr);
1254  this->country_QP = vector<shared_ptr<Game::QP_Param>>(nCountr);
1255  this->countries_LCP = vector<unique_ptr<Game::LCP>>(nCountr);
1256  this->SizesWithoutHull = vector<unsigned int>(nCountr, 0);
1257  for (unsigned int i = 0; i < this->nCountr; i++) {
1258  BOOST_LOG_TRIVIAL(trace) << "Finalizing country " << i;
1259  this->add_Dummy_Lead(i);
1260  this->LeadObjec.at(i) = std::make_shared<Game::QP_objective>();
1261  this->LeadObjec_ConvexHull.at(i) = std::make_shared<Game::QP_objective>();
1262  this->make_obj_leader(i, *this->LeadObjec.at(i).get());
1263  this->countries_LCP.at(i) = std::unique_ptr<Game::LCP>(
1264  new LCP(this->env, *this->countries_LL.at(i).get()));
1265  this->SizesWithoutHull.at(i) = *this->LocEnds.at(i);
1266  }
1267  BOOST_LOG_TRIVIAL(trace) << "Finalized";
1268 
1269  } catch (const char *e) {
1270  cerr << e << '\n';
1271  throw;
1272  } catch (string e) {
1273  cerr << "String in Game::EPEC::finalize : " << e << '\n';
1274  throw;
1275  } catch (GRBException &e) {
1276  cerr << "GRBException in Game::EPEC::finalize : " << e.getErrorCode()
1277  << ": " << e.getMessage() << '\n';
1278  throw;
1279  } catch (exception &e) {
1280  cerr << "Exception in Game::EPEC::finalize : " << e.what() << '\n';
1281  throw;
1282  }
1283 
1284  this->finalized = true;
1285 
1288  this->postfinalize();
1289 }
1290 
1292  const unsigned int i
1293 ) {
1296  const unsigned int nEPECvars = this->nVarinEPEC;
1297  const unsigned int nThisCountryvars = *this->LocEnds.at(i);
1298  // this->Locations.at(i).at(Models::LeaderVars::End);
1299 
1300  if (nEPECvars < nThisCountryvars)
1301  throw string(
1302  "String in Game::EPEC::add_Dummy_Lead: Invalid variable counts " +
1303  to_string(nEPECvars) + " and " + to_string(nThisCountryvars));
1304 
1305  try {
1306  this->countries_LL.at(i).get()->addDummy(nEPECvars - nThisCountryvars);
1307  } catch (const char *e) {
1308  cerr << e << '\n';
1309  throw;
1310  } catch (string e) {
1311  cerr << "String in Game::EPEC::add_Dummy_All_Lead : " << e << '\n';
1312  throw;
1313  } catch (GRBException &e) {
1314  cerr << "GRBException in Game::EPEC::add_Dummy_All_Lead : "
1315  << e.getErrorCode() << ": " << e.getMessage() << '\n';
1316  throw;
1317  } catch (exception &e) {
1318  cerr << "Exception in Game::EPEC::add_Dummy_All_Lead : " << e.what()
1319  << '\n';
1320  throw;
1321  }
1322 }
1323 
1324 void Game::EPEC::computeLeaderLocations(const unsigned int addSpaceForMC) {
1325  this->LeaderLocations = vector<unsigned int>(this->nCountr);
1326  this->LeaderLocations.at(0) = 0;
1327  for (unsigned int i = 1; i < this->nCountr; i++) {
1328  this->LeaderLocations.at(i) =
1329  this->LeaderLocations.at(i - 1) + *this->LocEnds.at(i - 1);
1330  }
1331  this->nVarinEPEC =
1332  this->LeaderLocations.back() + *this->LocEnds.back() + addSpaceForMC;
1333 }
1334 
1335 void EPEC::get_x_minus_i(const arma::vec &x, const unsigned int &i,
1336  arma::vec &solOther) const {
1337  const unsigned int nEPECvars = this->nVarinEPEC;
1338  const unsigned int nThisCountryvars = *this->LocEnds.at(i);
1339  const unsigned int nThisCountryHullVars = this->convexHullVariables.at(i);
1340  const unsigned int nConvexHullVars = std::accumulate(
1341  this->convexHullVariables.rbegin(), this->convexHullVariables.rend(), 0);
1342 
1343  solOther.zeros(nEPECvars - // All variables in EPEC
1344  nThisCountryvars - // Subtracting this country's variables,
1345  // since we only want others'
1346  nConvexHullVars + // We don't want any convex hull variables
1347  nThisCountryHullVars); // We double subtracted our country's
1348  // convex hull vars
1349 
1350  for (unsigned int j = 0, count = 0, current = 0; j < this->nCountr; ++j) {
1351  if (i != j) {
1352  current = *this->LocEnds.at(j) - this->convexHullVariables.at(j);
1353  solOther.subvec(count, count + current - 1) =
1354  x.subvec(this->LeaderLocations.at(j),
1355  this->LeaderLocations.at(j) + current - 1);
1356  count += current;
1357  }
1358  // We need to keep track of MC_vars also for this country
1359  }
1360  for (unsigned int j = 0; j < this->n_MCVar; j++)
1361  solOther.at(solOther.n_rows - this->n_MCVar + j) =
1362  x.at(this->nVarinEPEC - this->n_MCVar + j);
1363  BOOST_LOG_TRIVIAL(debug) << "EPEC::get_x_minus_i: Over";
1364 }
1365 
1366 unique_ptr<GRBModel> Game::EPEC::Respond(const unsigned int i,
1367  const arma::vec &x) const {
1368  if (!this->finalized)
1369  throw string("Error in Game::EPEC::Respond: Model not finalized");
1370 
1371  if (i >= this->nCountr)
1372  throw string("Error in Game::EPEC::Respond: Invalid country number");
1373 
1374  arma::vec solOther;
1375  this->get_x_minus_i(x, i, solOther);
1376  return this->countries_LCP.at(i).get()->MPECasMILP(
1377  this->LeadObjec.at(i).get()->C, this->LeadObjec.at(i).get()->c, solOther,
1378  true);
1379 }
1381  arma::vec &sol,
1382  unsigned int player,
1383  const arma::vec &x,
1384  const arma::vec &prevDev = {}
1386  //< [in] if any, the vector of previous deviations.
1387 ) const {
1397  auto model = this->Respond(player, x);
1398  const int status = model->get(GRB_IntAttr_Status);
1399  if (status == GRB_UNBOUNDED || status == GRB_OPTIMAL) {
1400  unsigned int Nx = this->countries_LCP.at(player)->getNcol();
1401  sol.zeros(Nx);
1402  for (unsigned int i = 0; i < Nx; ++i)
1403  sol.at(i) =
1404  model->getVarByName("x_" + to_string(i)).get(GRB_DoubleAttr_X);
1405 
1406  if (status == GRB_UNBOUNDED) {
1407  BOOST_LOG_TRIVIAL(warning) << "Game::EPEC::Respondsol: deviation is "
1408  "unbounded.";
1409  GRBLinExpr obj = 0;
1410  model->setObjective(obj);
1411  model->optimize();
1412  if (!prevDev.empty()) {
1413  BOOST_LOG_TRIVIAL(trace)
1414  << "Generating an improvement basing on the extreme ray.";
1415  // Fetch objective function coefficients
1416  GRBQuadExpr QuadObj = model->getObjective();
1417  arma::vec objcoeff;
1418  for (unsigned int i = 0; i < QuadObj.size(); ++i)
1419  objcoeff.at(i) = QuadObj.getCoeff(i);
1420 
1421  // Create objective function objects
1422  arma::vec objvalue = prevDev * objcoeff;
1423  arma::vec newobjvalue{0};
1424  double improved{false};
1425 
1426  // improve following the unbounded ray
1427  while (!improved) {
1428  for (unsigned int i = 0; i < Nx; ++i)
1429  sol.at(i) = sol.at(i) + model->getVarByName("x_" + to_string(i))
1430  .get(GRB_DoubleAttr_UnbdRay);
1431  newobjvalue = sol * objcoeff;
1432  if (newobjvalue.at(0) < objvalue.at(0))
1433  improved = true;
1434  }
1435  return newobjvalue.at(0);
1436 
1437  } else {
1438  return model->get(GRB_DoubleAttr_ObjVal);
1439  }
1440  }
1441  if (status == GRB_OPTIMAL) {
1442  return model->get(GRB_DoubleAttr_ObjVal);
1443  }
1444  } else {
1445  return GRB_INFINITY;
1446  }
1447  return GRB_INFINITY;
1448 }
1449 
1450 bool Game::EPEC::isSolved(unsigned int *countryNumber, arma::vec *ProfDevn,
1451  double tol) const
1468 {
1469  if (!this->nashgame)
1470  return false;
1471  if (!this->nashEq)
1472  return false;
1473  this->nashgame->isSolved(this->sol_x, *countryNumber, *ProfDevn);
1474  arma::vec objvals = this->nashgame->ComputeQPObjvals(this->sol_x, true);
1475  for (unsigned int i = 0; i < this->nCountr; ++i) {
1476  double val = this->RespondSol(*ProfDevn, i, this->sol_x);
1477  if (val == GRB_INFINITY)
1478  return false;
1479  BOOST_LOG_TRIVIAL(debug) << "EPEC::isSolved: " << i << " Devnval: " << val
1480  << " Obj Val: " << objvals.at(i);
1481  if (abs(val - objvals.at(i)) > tol) {
1482  *countryNumber = i;
1483  // cout << "Proof - deviation: "<<*ProfDevn; //Sane
1484  // cout << "Current soln: "<<this->sol_x;
1485  return false;
1486  }
1487  }
1488  return true;
1489 }
1490 
1491 bool Game::EPEC::isSolved(double tol) const {
1492  unsigned int countryNumber;
1493  arma::vec ProfDevn;
1494  bool ret = this->isSolved(&countryNumber, &ProfDevn, tol);
1495  return ret;
1496 }
1497 
1498 void Game::EPEC::make_country_QP(const unsigned int i)
1510 {
1511  // BOOST_LOG_TRIVIAL(info) << "Starting Convex hull computation of the country
1512  // "
1513  // << this->AllLeadPars[i].name << '\n';
1514  if (!this->finalized)
1515  throw string("Error in Game::EPEC::make_country_QP: Model not finalized");
1516  if (i >= this->nCountr)
1517  throw string(
1518  "Error in Game::EPEC::make_country_QP: Invalid country number");
1519  // if (!this->country_QP.at(i).get())
1520  {
1521  this->country_QP.at(i) = std::make_shared<Game::QP_Param>(this->env);
1522  const auto &origLeadObjec = *this->LeadObjec.at(i).get();
1523 
1524  this->LeadObjec_ConvexHull.at(i).reset(new Game::QP_objective{
1525  origLeadObjec.Q, origLeadObjec.C, origLeadObjec.c});
1526 
1527  this->countries_LCP.at(i)->makeQP(*this->LeadObjec_ConvexHull.at(i).get(),
1528  *this->country_QP.at(i).get());
1529  this->Stats.feasiblePolyhedra.at(i) =
1530  this->countries_LCP.at(i)->getFeasiblePolyhedra();
1531  }
1532 }
1533 
1542 {
1543  for (unsigned int i = 0; i < this->nCountr; ++i) {
1544  this->Game::EPEC::make_country_QP(i);
1545  }
1546  for (unsigned int i = 0; i < this->nCountr; ++i) {
1547  // LeadLocs &Loc = this->Locations.at(i);
1548  // Adjusting "stuff" because we now have new convHull variables
1549  unsigned int originalSizeWithoutHull = this->LeadObjec.at(i)->Q.n_rows;
1550  unsigned int convHullVarCount =
1551  this->LeadObjec_ConvexHull.at(i)->Q.n_rows - originalSizeWithoutHull;
1552 
1553  BOOST_LOG_TRIVIAL(trace)
1554  << "Game::EPEC::make_country_QP: Added " << convHullVarCount
1555  << " convex hull variables to QP #" << i;
1556 
1557  // Location details
1558  this->convexHullVariables.at(i) = convHullVarCount;
1559  // All other players' QP
1560  try {
1561  if (this->nCountr > 1) {
1562  for (unsigned int j = 0; j < this->nCountr; j++) {
1563  if (i != j) {
1564  this->country_QP.at(j)->addDummy(
1565  convHullVarCount, 0,
1566  this->country_QP.at(j)->getNx() -
1567  this->n_MCVar); // The position to add parameters is towards
1568  // the end of all parameters, giving space
1569  // only for the n_MCVar number of market
1570  // clearing variables
1571  }
1572  }
1573  }
1574  } catch (const char *e) {
1575  cerr << e << '\n';
1576  throw;
1577  } catch (string e) {
1578  cerr << "String in Game::EPEC::make_country_QP : " << e << '\n';
1579  throw;
1580  } catch (GRBException &e) {
1581  cerr << "GRBException in Game::EPEC::make_country_QP : "
1582  << e.getErrorCode() << ": " << e.getMessage() << '\n';
1583  throw;
1584  } catch (exception &e) {
1585  cerr << "Exception in Game::EPEC::make_country_QP : " << e.what() << '\n';
1586  throw;
1587  }
1588  }
1589  this->updateLocs();
1590  this->computeLeaderLocations(this->n_MCVar);
1591 }
1592 
1594  std::vector<arma::vec>
1595  &devns,
1596  const arma::vec &guessSol,
1597  const std::vector<arma::vec>
1598  &prevDev //<[in] The previous vecrtor of deviations, if any exist.
1599 ) const
1607 {
1608  devns = std::vector<arma::vec>(this->nCountr);
1609 
1610  for (unsigned int i = 0; i < this->nCountr; ++i) { // For each country
1611  // If we cannot compute a deviation, it means model is infeasible!
1612  double objVal{0};
1613  objVal = this->RespondSol(devns.at(i), i, guessSol, prevDev.at(i));
1614  BOOST_LOG_TRIVIAL(debug) << "EPEC::getAllDevns: " << i << " " << objVal;
1615  if (objVal == GRB_INFINITY)
1616  return false;
1617  // cout << "Game::EPEC::getAllDevns: devns(i): " <<devns.at(i);
1618  }
1619  return true;
1620 }
1621 
1623  const std::vector<arma::vec>
1624  &devns,
1625  bool &infeasCheck
1627 ) const {
1641  infeasCheck = false;
1642  unsigned int added = 0;
1643  for (unsigned int i = 0; i < this->nCountr; ++i) { // For each country
1644  bool ret = false;
1645  if (!devns.at(i).empty())
1646  this->countries_LCP.at(i)->addPolyFromX(devns.at(i), ret);
1647  if (ret) {
1648  BOOST_LOG_TRIVIAL(debug)
1649  << "Game::EPEC::addDeviatedPolyhedron: added polyhedron for player "
1650  << i << " " << added;
1651  ++added;
1652  } else {
1653  infeasCheck = true;
1654  BOOST_LOG_TRIVIAL(trace) << "Game::EPEC::addDeviatedPolyhedron: NO "
1655  "polyhedron added for player "
1656  << i;
1657  }
1658  }
1659  return added;
1660 }
1661 
1662 bool Game::EPEC::addRandomPoly2All(unsigned int aggressiveLevel,
1663  bool stopOnSingleInfeasibility)
1679 {
1680  BOOST_LOG_TRIVIAL(trace) << "Adding random polyhedra to countries";
1681  bool infeasible{true};
1682  for (unsigned int i = 0; i < this->nCountr; i++) {
1683  auto addedPolySet = this->countries_LCP.at(i)->addAPoly(
1684  aggressiveLevel, this->Stats.AlgorithmParam.addPolyMethod);
1685  if (stopOnSingleInfeasibility && addedPolySet.empty()) {
1686  BOOST_LOG_TRIVIAL(info)
1687  << "Game::EPEC::addRandomPoly2All: No Nash equilibrium. due to "
1688  "infeasibility of country "
1689  << i;
1690  return false;
1691  }
1692  if (!addedPolySet.empty())
1693  infeasible = false;
1694  }
1695  return !infeasible;
1696 }
1697 
1699 
1700  // Set the initial point for all countries as 0 and solve the respective LCPs?
1701  this->sol_x.zeros(this->nVarinEPEC);
1702 
1703  bool solved = {false};
1704  bool addRandPoly{false};
1705  bool infeasCheck{false};
1706  // When true, a MNE has been found. The algorithm now tries to find a PNE, at
1707  // the cost of incrementally enumerating the remaining polyhedra, up to the
1708  // TimeLimit (if any).
1709  //
1710  bool incrementalEnumeration{false};
1711 
1712  std::vector<arma::vec> prevDevns(this->nCountr);
1713  this->Stats.numIteration = 0;
1714  if (this->Stats.AlgorithmParam.addPolyMethod == EPECAddPolyMethod::random) {
1715  for (unsigned int i = 0; i < this->nCountr; ++i) {
1716  long int seed = this->Stats.AlgorithmParam.addPolyMethodSeed < 0
1717  ? chrono::high_resolution_clock::now()
1718  .time_since_epoch()
1719  .count() +
1720  42 + this->countries_LCP.at(i)->getNrow()
1721  : this->Stats.AlgorithmParam.addPolyMethodSeed;
1722  this->countries_LCP.at(i)->addPolyMethodSeed = seed;
1723  }
1724  }
1725  if (this->Stats.AlgorithmParam.timeLimit > 0)
1726  this->initTime = std::chrono::high_resolution_clock::now();
1727 
1728  // Stay in this loop, till you find a Nash equilibrium or prove that there
1729  // does not exist a Nash equilibrium or you run out of time.
1730  while (!solved) {
1731  ++this->Stats.numIteration;
1732  BOOST_LOG_TRIVIAL(info) << "Game::EPEC::iterativeNash: Iteration "
1733  << to_string(this->Stats.numIteration);
1734 
1735  if (addRandPoly) {
1736  BOOST_LOG_TRIVIAL(info) << "Game::EPEC::iterativeNash: using "
1737  "heuristical polyhedra selection";
1738  bool success =
1739  this->addRandomPoly2All(this->Stats.AlgorithmParam.aggressiveness,
1740  this->Stats.numIteration == 1);
1741  if (!success) {
1742  this->Stats.status = Game::EPECsolveStatus::nashEqNotFound;
1743  solved = true;
1744  return;
1745  }
1746  } else { // else we are in the case of finding deviations.
1747  unsigned int deviatedCountry{0};
1748  arma::vec countryDeviation{};
1749  if (this->isSolved(&deviatedCountry, &countryDeviation, 20)) {
1750  this->Stats.status = Game::EPECsolveStatus::nashEqFound;
1751  this->Stats.pureNE = this->isPureStrategy();
1752  if ((this->Stats.AlgorithmParam.pureNE && !this->Stats.pureNE)) {
1753  BOOST_LOG_TRIVIAL(info)
1754  << "Game::EPEC::iterativeNash: pureNE control ";
1755  // We are seeking for a pure strategy. Then, here we switch between an
1756  // incremental
1757  // enumeration or combinations of pure strategies.
1758  if (this->Stats.AlgorithmParam.recoverStrategy ==
1760  BOOST_LOG_TRIVIAL(info)
1761  << "Game::EPEC::iterativeNash: triggering recover strategy "
1762  "(incrementalEnumeration)";
1763  incrementalEnumeration = true;
1764  } else if (this->Stats.AlgorithmParam.recoverStrategy ==
1766  BOOST_LOG_TRIVIAL(info) << "Game::EPEC::iterativeNash: triggering "
1767  "recover strategy (combinatorial)";
1768  // In this case, we want to try all the combinations of pure
1769  // strategies, except the ones between polyhedra we already tested.
1770  std::vector<std::set<unsigned long int>> excludeList;
1771  std::vector<long int> start;
1772  for (unsigned int j = 0; j < this->nCountr; ++j) {
1773  excludeList.push_back(
1774  this->countries_LCP.at(j)->getAllPolyhedra());
1775  start.push_back(-1);
1776  }
1777  this->combinatorialPNE(start, excludeList);
1778  return;
1779  }
1780 
1781  } else {
1782  solved = true;
1783  return;
1784  }
1785  }
1786  // Vector of deviations for the countries
1787  std::vector<arma::vec> devns = std::vector<arma::vec>(this->nCountr);
1788  this->getAllDevns(devns, this->sol_x, prevDevns);
1789  prevDevns = devns;
1790  unsigned int addedPoly = this->addDeviatedPolyhedron(devns, infeasCheck);
1791  if (addedPoly == 0 && this->Stats.numIteration > 1 &&
1793  BOOST_LOG_TRIVIAL(error)
1794  << " In Game::EPEC::iterativeNash: Not "
1795  "Solved, but no deviation? Error!\n This might be due to "
1796  "numerical issues (tollerances) "
1797  << addedPoly;
1798  this->Stats.status = EPECsolveStatus::numerical;
1799  solved = true;
1800  return;
1801  }
1802  if (infeasCheck && this->Stats.numIteration == 1) {
1803  BOOST_LOG_TRIVIAL(warning)
1804  << " In Game::EPEC::iterativeNash: Problem is infeasible";
1805  this->Stats.status = EPECsolveStatus::nashEqNotFound;
1806  solved = true;
1807  return;
1808  }
1809  }
1810  this->make_country_QP();
1811 
1812  // TimeLimit
1813  if (this->Stats.AlgorithmParam.timeLimit > 0) {
1814  const std::chrono::duration<double> timeElapsed =
1815  std::chrono::high_resolution_clock::now() - this->initTime;
1816  const double timeRemaining =
1817  this->Stats.AlgorithmParam.timeLimit - timeElapsed.count();
1818  addRandPoly = !this->computeNashEq(this->Stats.AlgorithmParam.pureNE,
1819  timeRemaining) &&
1821  } else {
1822  // No Time Limit
1823  addRandPoly = !this->computeNashEq(this->Stats.AlgorithmParam.pureNE) &&
1825  }
1826  if (addRandPoly)
1827  this->Stats.lostIntermediateEq++;
1828  for (unsigned int i = 0; i < this->nCountr; ++i) {
1829  BOOST_LOG_TRIVIAL(info) << "Game::EPEC::iterativeNash: Country " << i
1830  << this->countries_LCP.at(i)->feas_detail_str();
1831  }
1832  // This might be reached when a NashEq is found, and need to be verified.
1833  // Anyway, we are over the timeLimit and we should stop
1834  if (this->Stats.AlgorithmParam.timeLimit > 0) {
1835  const std::chrono::duration<double> timeElapsed =
1836  std::chrono::high_resolution_clock::now() - this->initTime;
1837  const double timeRemaining =
1838  this->Stats.AlgorithmParam.timeLimit - timeElapsed.count();
1839  if (timeRemaining <= 0) {
1840  solved = false;
1842  this->Stats.status = Game::EPECsolveStatus::timeLimit;
1843  return;
1844  }
1845  }
1846  }
1847 }
1848 
1850  const std::vector<long int> combination,
1851  const std::vector<std::set<unsigned long int>> &excludeList) {
1852 
1853  if ((this->Stats.status == EPECsolveStatus::nashEqFound &&
1854  this->Stats.pureNE == true) ||
1855  this->Stats.status == EPECsolveStatus::timeLimit)
1856  return;
1857 
1858  if (this->Stats.AlgorithmParam.timeLimit > 0) {
1859  const std::chrono::duration<double> timeElapsed =
1860  std::chrono::high_resolution_clock::now() - this->initTime;
1861  const double timeRemaining =
1862  this->Stats.AlgorithmParam.timeLimit - timeElapsed.count();
1863  if (timeRemaining <= 0) {
1864  this->Stats.status = Game::EPECsolveStatus::timeLimit;
1865  return;
1866  }
1867  }
1868 
1869  std::vector<long int> childCombination(combination);
1870  bool found{false};
1871  unsigned int i{0};
1872  for (i = 0; i < this->getNcountries(); i++) {
1873  if (childCombination.at(i) == -1) {
1874  found = true;
1875  break;
1876  }
1877  }
1878  if (found) {
1879  for (unsigned int j = 0;
1880  j < this->countries_LCP.at(i)->getNumTheoreticalPoly(); ++j) {
1881  if (this->countries_LCP.at(i)->checkPolyFeas(j)) {
1882  childCombination.at(i) = j;
1883  this->combinatorial_pure_NE(childCombination, excludeList);
1884  }
1885  }
1886  } else {
1887  // Combination is filled and ready!
1888  // Check that this combination is not in the excuded list
1889  BOOST_LOG_TRIVIAL(trace)
1890  << "Game::EPEC::combinatorial_pure_NE: considering a FULL combination";
1891  bool excluded = false;
1892  if (!excludeList.empty()) {
1893  excluded = true;
1894  for (unsigned int j = 0; j < this->nCountr; ++j) {
1895  if (excludeList.at(j).find(childCombination.at(j)) ==
1896  excludeList.at(j).end()) {
1897  excluded = false;
1898  }
1899  }
1900  }
1901 
1902  if (!excluded) {
1903  BOOST_LOG_TRIVIAL(trace)
1904  << "Game::EPEC::combinatorial_pure_NE: considering a "
1905  "FEASIBLE combination of polyhedra.";
1906  for (unsigned int j = 0; j < this->getNcountries(); ++j) {
1907  this->countries_LCP.at(j)->clearPolyhedra();
1908  this->countries_LCP.at(j)->addThePoly(childCombination.at(j));
1909  }
1910  this->make_country_QP();
1911  bool res = false;
1912  if (this->Stats.AlgorithmParam.timeLimit > 0) {
1913  const std::chrono::duration<double> timeElapsed =
1914  std::chrono::high_resolution_clock::now() - this->initTime;
1915  const double timeRemaining =
1916  this->Stats.AlgorithmParam.timeLimit - timeElapsed.count();
1917  res = this->computeNashEq(false, timeRemaining, true);
1918  } else
1919  res = this->computeNashEq(false, -1.0, true);
1920 
1921  if (res) {
1922  if (this->isSolved(20)) {
1923  // Check that the equilibrium is a pure strategy
1924  if ((this->isPureStrategy())) {
1925  BOOST_LOG_TRIVIAL(info)
1926  << "Game::EPEC::combinatorial_pure_NE: found a pure strategy.";
1927  this->Stats.status = Game::EPECsolveStatus::nashEqFound;
1928  this->Stats.pureNE = true;
1929  return;
1930  }
1931  }
1932  }
1933  } else {
1934  BOOST_LOG_TRIVIAL(trace)
1935  << "Game::EPEC::combinatorial_pure_NE: configuration pruned.";
1936  return;
1937  }
1938  }
1939 }
1940 
1941 void ::Game::EPEC::make_country_LCP() {
1942  if (this->country_QP.front() == nullptr) {
1943  BOOST_LOG_TRIVIAL(error) << "Exception in Game::EPEC::make_country_LCP : "
1944  "no country QP has been "
1945  "made."
1946  << '\n';
1947  throw;
1948  }
1949  // Preliminary set up to get the LCP ready
1950  int Nvar =
1951  this->country_QP.front()->getNx() + this->country_QP.front()->getNy();
1952  arma::sp_mat MC(0, Nvar), dumA(0, Nvar);
1953  arma::vec MCRHS, dumb;
1954  MCRHS.zeros(0);
1955  dumb.zeros(0);
1956  this->make_MC_cons(MC, MCRHS);
1957  BOOST_LOG_TRIVIAL(trace) << "Game::EPEC::make_country_LCP(): Market Clearing "
1958  "constraints are ready";
1959  this->nashgame = std::unique_ptr<Game::NashGame>(new Game::NashGame(
1960  this->env, this->country_QP, MC, MCRHS, 0, dumA, dumb));
1961  BOOST_LOG_TRIVIAL(trace)
1962  << "Game::EPEC::make_country_LCP(): NashGame is ready";
1963  this->lcp = std::unique_ptr<Game::LCP>(new Game::LCP(this->env, *nashgame));
1964  BOOST_LOG_TRIVIAL(trace) << "Game::EPEC::make_country_LCP(): LCP is ready";
1965  BOOST_LOG_TRIVIAL(trace)
1966  << "Game::EPEC::make_country_LCP(): indicators set to "
1967  << this->Stats.AlgorithmParam.indicators;
1968  this->lcp->useIndicators =
1969  this->Stats.AlgorithmParam.indicators; // Using indicator constraints
1970 
1971  this->lcpmodel = this->lcp->LCPasMIP(false);
1972 
1973  BOOST_LOG_TRIVIAL(trace) << *nashgame;
1974 }
1975 
1977  bool pureNE,
1978  double localTimeLimit,
1979  bool check
1980 ) {
1989  // Make the Nash Game between countries
1990  this->nashEq = false;
1991  BOOST_LOG_TRIVIAL(trace)
1992  << " Game::EPEC::computeNashEq: Making the Master LCP";
1993  this->make_country_LCP();
1994  BOOST_LOG_TRIVIAL(trace) << " Game::EPEC::computeNashEq: Made the Master LCP";
1995  if (localTimeLimit > 0) {
1996  this->lcpmodel->set(GRB_DoubleParam_TimeLimit, localTimeLimit);
1997  }
1998  if (this->Stats.AlgorithmParam.boundPrimals) {
1999  for (unsigned int c = 0; c < this->nashgame->getNprimals(); c++) {
2000  this->lcpmodel->getVarByName("x_" + to_string(c))
2001  .set(GRB_DoubleAttr_UB, this->Stats.AlgorithmParam.boundBigM);
2002  }
2003  }
2004 
2005  if (pureNE) {
2006  BOOST_LOG_TRIVIAL(info) << " Game::EPEC::computeNashEq: (pureNE flag is "
2007  "true) Searching for a pure NE.";
2008  this->make_pure_LCP();
2009  }
2010 
2011  // this->lcpmodel->set(GRB_IntParam_OutputFlag, 1);
2012  if (check)
2013  this->lcpmodel->set(GRB_IntParam_SolutionLimit, GRB_MAXINT);
2014  this->lcpmodel->optimize();
2015  this->Stats.wallClockTime += this->lcpmodel->get(GRB_DoubleAttr_Runtime);
2016 
2017  // Search just for a feasible point
2018  try { // Try finding a Nash equilibrium for the approximation
2019  this->nashEq =
2020  this->lcp->extractSols(this->lcpmodel.get(), sol_z, sol_x, true);
2021  } catch (GRBException &e) {
2022  BOOST_LOG_TRIVIAL(error)
2023  << "GRBException in Game::EPEC::computeNashEq : " << e.getErrorCode()
2024  << ": " << e.getMessage() << " ";
2025  }
2026  if (this->nashEq) { // If a Nash equilibrium is found, then update
2027  // appropriately
2028  if (check) {
2029  int scount = this->lcpmodel->get(GRB_IntAttr_SolCount);
2030  BOOST_LOG_TRIVIAL(info)
2031  << "Game::EPEC::computeNashEq: number of equilibria is " << scount;
2032  for (int k = 0, stop = 0; k < scount && stop == 0; ++k) {
2033  this->lcpmodel->getEnv().set(GRB_IntParam_SolutionNumber, k);
2034  this->nashEq =
2035  this->lcp->extractSols(this->lcpmodel.get(), sol_z, sol_x, true);
2036  if (this->isSolved(20)) {
2037  BOOST_LOG_TRIVIAL(info)
2038  << "Game::EPEC::computeNashEq: an Equilibrium has been found";
2039  stop = 1;
2040  }
2041  }
2042  } else {
2043  this->nashEq = true;
2044  BOOST_LOG_TRIVIAL(info)
2045  << "Game::EPEC::computeNashEq: an Equilibrium has been found";
2046  }
2047 
2048  } else { // If not, then update accordingly
2049  BOOST_LOG_TRIVIAL(info)
2050  << "Game::EPEC::computeNashEq: no equilibrium has been found.";
2051  int status = this->lcpmodel->get(GRB_IntAttr_Status);
2052  if (status == GRB_TIME_LIMIT)
2053  this->Stats.status = Game::EPECsolveStatus::timeLimit;
2054  else
2055  this->Stats.status = Game::EPECsolveStatus::nashEqNotFound;
2056  }
2057  return this->nashEq;
2058 }
2059 
2060 bool Game::EPEC::warmstart(const arma::vec x) {
2061 
2062  if (x.size() < this->getnVarinEPEC()) {
2063  BOOST_LOG_TRIVIAL(error)
2064  << "Exception in Game::EPEC::warmstart: number of variables "
2065  "does not fit this instance.";
2066  throw;
2067  }
2068  if (!this->finalized) {
2069  BOOST_LOG_TRIVIAL(error)
2070  << "Exception in Game::EPEC::warmstart: EPEC is not finalized.";
2071  throw;
2072  }
2073  if (this->country_QP.front() == nullptr) {
2074  BOOST_LOG_TRIVIAL(warning)
2075  << "Game::EPEC::warmstart: Generating QP as of warmstart.";
2076  }
2077 
2078  this->sol_x = x;
2079  std::vector<arma::vec> devns = std::vector<arma::vec>(this->nCountr);
2080  std::vector<arma::vec> prevDevns = std::vector<arma::vec>(this->nCountr);
2081  this->getAllDevns(devns, this->sol_x, prevDevns);
2082  this->make_country_QP();
2083 
2084  unsigned int c;
2085  arma::vec devn;
2086 
2087  if (this->isSolved(&c, &devn))
2088  BOOST_LOG_TRIVIAL(warning) << "Game::EPEC::warmstart: "
2089  "The loaded solution is optimal.";
2090  else
2091  BOOST_LOG_TRIVIAL(warning)
2092  << "Game::EPEC::warmstart: "
2093  "The loaded solution is NOT optimal. Trying to repair.";
2095  return true;
2096 }
2097 
2098 void Game::EPEC::make_pure_LCP(bool indicators) {
2109  try {
2110  BOOST_LOG_TRIVIAL(trace)
2111  << "Game::EPEC::make_pure_LCP: editing the LCP model.";
2112  this->lcpmodel_base = std::unique_ptr<GRBModel>(new GRBModel(*lcpmodel));
2113  const unsigned int nPolyLead = [this]() {
2114  unsigned int ell = 0;
2115  for (unsigned int i = 0; i < this->getNcountries(); ++i)
2116  ell += (this->getNPoly_Lead(i));
2117  return ell;
2118  }();
2119 
2120  // Add a binary variable for each polyhedron of each leader
2121  GRBVar pure_bin[nPolyLead];
2122  GRBLinExpr objectiveTerm{0};
2123  unsigned int count{0}, i, j;
2124  for (i = 0; i < this->getNcountries(); i++) {
2125  for (j = 0; j < this->getNPoly_Lead(i); ++j) {
2126  pure_bin[count] = this->lcpmodel->addVar(0, 1, 0, GRB_BINARY,
2127  "pureBin_" + to_string(i) +
2128  "_" + to_string(j));
2129  if (indicators) {
2130  this->lcpmodel->addGenConstrIndicator(
2131  pure_bin[count], 1,
2132  this->lcpmodel->getVarByName(
2133  "x_" + to_string(this->getPosition_Probab(i, j))),
2134  GRB_EQUAL, 0, "Indicator_PNE_" + to_string(count));
2135  } else {
2136  this->lcpmodel->addConstr(
2137  this->lcpmodel->getVarByName(
2138  "x_" + to_string(this->getPosition_Probab(i, j))),
2139  GRB_GREATER_EQUAL, pure_bin[count]);
2140  }
2141  objectiveTerm += pure_bin[count];
2142  count++;
2143  }
2144  }
2145  if (indicators) {
2146  this->lcpmodel->setObjective(objectiveTerm, GRB_MAXIMIZE);
2147  BOOST_LOG_TRIVIAL(trace)
2148  << "Game::EPEC::make_pure_LCP: using indicator constraints.";
2149  } else {
2150  this->lcpmodel->setObjective(objectiveTerm, GRB_MINIMIZE);
2151  BOOST_LOG_TRIVIAL(trace)
2152  << "Game::EPEC::make_pure_LCP: using indicator constraints.";
2153  }
2154  } catch (GRBException &e) {
2155  cerr << "GRBException in Game::EPEC::make_pure_LCP : " << e.getErrorCode()
2156  << ": " << e.getMessage() << '\n';
2157  throw;
2158  }
2159 }
2160 
2162  const std::vector<long int> combination,
2163  const std::vector<std::set<unsigned long int>> &excludeList) {
2164 
2165  if (this->Stats.AlgorithmParam.timeLimit > 0) {
2166  // Checking the function hasn't been called from innerApproximation
2167  if (this->Stats.numIteration <= 0) {
2168  this->initTime = std::chrono::high_resolution_clock::now();
2169  }
2170  }
2171  if (combination.empty()) {
2172  std::vector<long int> start;
2173  for (unsigned int j = 0; j < this->nCountr; ++j)
2174  start.push_back(-1);
2175  this->combinatorial_pure_NE(start, excludeList);
2176  } else
2177  this->combinatorial_pure_NE(combination, excludeList);
2178 
2179  return;
2180 }
2181 
2191  std::stringstream final_msg;
2192  if (!this->finalized)
2193  throw string("Error in Game::EPEC::iterativeNash: Object not yet "
2194  "finalized. ");
2195 
2196  if (this->Stats.status != Game::EPECsolveStatus::unInitialized) {
2197  BOOST_LOG_TRIVIAL(error)
2198  << "Game::EPEC::findNashEq: a Nash Eq was "
2199  "already found. Calling this findNashEq might lead to errors!";
2200  this->resetLCP();
2201  }
2202 
2203  // Choosing the appropriate algorithm
2204  switch (this->Stats.AlgorithmParam.algorithm) {
2205 
2207  this->iterativeNash();
2208  final_msg << "Inner approximation algorithm completed. ";
2209  break;
2210 
2212  this->combinatorialPNE();
2213  final_msg << "CombinatorialPNE algorithm completed. ";
2214  break;
2215 
2217  this->fullEnumerationNash();
2218  final_msg << "Full enumeration algorithm completed. ";
2219  break;
2220  }
2221  // Handing EPECStatistics object to track performance of algorithm
2222  if (this->lcpmodel) {
2223  this->Stats.numVar = this->lcpmodel->get(GRB_IntAttr_NumVars);
2224  this->Stats.numConstraints = this->lcpmodel->get(GRB_IntAttr_NumConstrs);
2225  this->Stats.numNonZero = this->lcpmodel->get(GRB_IntAttr_NumNZs);
2226  } // Assigning appropriate status messages after solving
2227 
2228  switch (this->Stats.status) {
2230  final_msg << "No Nash equilibrium exists.";
2231  break;
2233  final_msg << "Found a Nash equilibrium ("
2234  << (this->Stats.pureNE == 0 ? "MNE" : "PNE") << ").";
2235  break;
2237  final_msg << "Nash equilibrium not found. Time limit attained";
2238  break;
2240  final_msg << "Nash equilibrium not found. Numerical issues might affect "
2241  "this result.";
2242  break;
2243  default:
2244  final_msg << "Nash equilibrium not found. Time limit attained";
2245  break;
2246  }
2247  BOOST_LOG_TRIVIAL(info) << "Game::EPEC::findNashEq: " << final_msg.str();
2248 }
2250  for (unsigned int i = 0; i < this->nCountr; ++i)
2251  this->countries_LCP.at(i)->EnumerateAll(true);
2252  this->make_country_QP();
2253  BOOST_LOG_TRIVIAL(trace)
2254  << "Game::EPEC::findNashEq: Starting fullEnumeration search";
2255  BOOST_LOG_TRIVIAL(debug) << "EPEC::fullEnumerationNash: "
2256  << "Time limit: "
2257  << this->Stats.AlgorithmParam.timeLimit;
2258  this->computeNashEq(this->Stats.AlgorithmParam.pureNE,
2259  this->Stats.AlgorithmParam.timeLimit);
2260  BOOST_LOG_TRIVIAL(debug) << "EPEC::fullEnumerationNash: "
2261  << "computeNashEq completed "
2262  << std::to_string(this->Stats.status);
2263  // if (this->isSolved(200))
2264  {
2265  this->Stats.status = Game::EPECsolveStatus::nashEqFound;
2266  if (this->isPureStrategy())
2267  this->Stats.pureNE = true;
2268  }
2269  BOOST_LOG_TRIVIAL(debug) << "EPEC::fullEnumerationNash: "
2270  << "computeNashEq completed "
2271  << std::to_string(this->Stats.status);
2272 }
2273 
2279 {
2280  this->Stats.AlgorithmParam.algorithm = algorithm;
2281 }
2287 {
2288  this->Stats.AlgorithmParam.recoverStrategy = strategy;
2289 }
2290 
2291 unsigned int Game::EPEC::getPosition_LeadFoll(const unsigned int i,
2292  const unsigned int j) const {
2298  const auto LeaderStart = this->nashgame->getPrimalLoc(i);
2299  return LeaderStart + j;
2300 }
2301 
2302 unsigned int Game::EPEC::getPosition_LeadLead(const unsigned int i,
2303  const unsigned int j) const {
2309  const auto LeaderStart = this->nashgame->getPrimalLoc(i);
2310  return LeaderStart + this->countries_LCP.at(i)->getLStart() + j;
2311 }
2312 
2313 unsigned int Game::EPEC::getPosition_LeadFollPoly(const unsigned int i,
2314  const unsigned int j,
2315  const unsigned int k) const {
2322  const auto LeaderStart = this->nashgame->getPrimalLoc(i);
2323  const auto FollPoly = this->countries_LCP.at(i)->conv_PolyPosition(k);
2324  return LeaderStart + FollPoly + j;
2325 }
2326 
2327 unsigned int Game::EPEC::getPosition_LeadLeadPoly(const unsigned int i,
2328  const unsigned int j,
2329  const unsigned int k) const {
2336  const auto LeaderStart = this->nashgame->getPrimalLoc(i);
2337  const auto FollPoly = this->countries_LCP.at(i)->conv_PolyPosition(k);
2338  return LeaderStart + FollPoly + this->countries_LCP.at(i)->getLStart() + j;
2339 }
2340 
2341 unsigned int Game::EPEC::getNPoly_Lead(const unsigned int i) const {
2346  return this->countries_LCP.at(i)->conv_Npoly();
2347 }
2348 
2349 unsigned int Game::EPEC::getPosition_Probab(const unsigned int i,
2350  const unsigned int k) const {
2356  const auto PolyProbab = this->countries_LCP.at(i)->conv_PolyWt(k);
2357  if (PolyProbab == 0)
2358  return 0;
2359  const auto LeaderStart = this->nashgame->getPrimalLoc(i);
2360  return LeaderStart + PolyProbab;
2361 }
2362 
2363 bool Game::EPEC::isPureStrategy(const double tol) const {
2369  for (unsigned int i = 0; i < this->getNcountries(); ++i) {
2370  if (!isPureStrategy(i, tol))
2371  return false;
2372  }
2373  return true;
2374 }
2375 
2376 bool Game::EPEC::isPureStrategy(const unsigned int i, const double tol) const {
2382  const unsigned int nPoly = this->getNPoly_Lead(i);
2383  for (unsigned int j = 0; j < nPoly; j++) {
2384  const double probab = this->getVal_Probab(i, j);
2385  if (probab > 1 - tol) // Current Strategy is a pure strategy!
2386  return true;
2387  }
2388  return false;
2389 }
2390 
2391 std::vector<unsigned int> Game::EPEC::mixedStratPoly(const unsigned int i,
2392  const double tol) const
2397 {
2398  std::vector<unsigned int> polys{};
2399  const unsigned int nPoly = this->getNPoly_Lead(i);
2400  for (unsigned int j = 0; j < nPoly; j++) {
2401  const double probab = this->getVal_Probab(i, j);
2402  if (probab > tol)
2403  polys.push_back(j);
2404  }
2405  cout << "\n";
2406  return polys;
2407 }
2408 
2409 double Game::EPEC::getVal_Probab(const unsigned int i,
2410  const unsigned int k) const {
2411  const unsigned int varname{this->getPosition_Probab(i, k)};
2412  if (varname == 0)
2413  return 1;
2414  return this->lcpmodel->getVarByName("x_" + std::to_string(varname))
2415  .get(GRB_DoubleAttr_X);
2416 }
2417 
2418 double Game::EPEC::getVal_LeadFoll(const unsigned int i,
2419  const unsigned int j) const {
2420  if (!this->lcpmodel)
2421  throw std::string("Error in Game::EPEC::getVal_LeadFoll: "
2422  "Game::EPEC::lcpmodel not made and solved");
2423  return this->lcpmodel
2424  ->getVarByName("x_" + to_string(this->getPosition_LeadFoll(i, j)))
2425  .get(GRB_DoubleAttr_X);
2426 }
2427 
2428 double Game::EPEC::getVal_LeadLead(const unsigned int i,
2429  const unsigned int j) const {
2430  if (!this->lcpmodel)
2431  throw std::string("Error in Game::EPEC::getVal_LeadLead: "
2432  "Game::EPEC::lcpmodel not made and solved");
2433  return this->lcpmodel
2434  ->getVarByName("x_" + to_string(this->getPosition_LeadLead(i, j)))
2435  .get(GRB_DoubleAttr_X);
2436 }
2437 
2438 double Game::EPEC::getVal_LeadFollPoly(const unsigned int i,
2439  const unsigned int j,
2440  const unsigned int k,
2441  const double tol) const {
2442  if (!this->lcpmodel)
2443  throw std::string("Error in Game::EPEC::getVal_LeadFollPoly: "
2444  "Game::EPEC::lcpmodel not made and solved");
2445  const double probab = this->getVal_Probab(i, k);
2446  if (probab > 1 - tol)
2447  return this->getVal_LeadFoll(i, j);
2448  else
2449  return this->lcpmodel
2450  ->getVarByName(
2451  "x_" + to_string(this->getPosition_LeadFollPoly(i, j, k)))
2452  .get(GRB_DoubleAttr_X) /
2453  probab;
2454 }
2455 
2456 double Game::EPEC::getVal_LeadLeadPoly(const unsigned int i,
2457  const unsigned int j,
2458  const unsigned int k,
2459  const double tol) const {
2460  if (!this->lcpmodel)
2461  throw std::string("Error in Game::EPEC::getVal_LeadLeadPoly: "
2462  "Game::EPEC::lcpmodel not made and solved");
2463  const double probab = this->getVal_Probab(i, k);
2464  if (probab > 1 - tol)
2465  return this->getVal_LeadLead(i, j);
2466  else
2467  return this->lcpmodel
2468  ->getVarByName(
2469  "x_" + to_string(this->getPosition_LeadLeadPoly(i, j, k)))
2470  .get(GRB_DoubleAttr_X) /
2471  probab;
2472 }
2473 
2474 std::string std::to_string(const Game::EPECsolveStatus st) {
2475  switch (st) {
2477  return string("NO_NASH_EQ_FOUND");
2479  return string("NASH_EQ_FOUND");
2481  return string("TIME_LIMIT");
2483  return string("UNINITIALIZED");
2485  return string("NUMERICAL_ISSUES");
2486  default:
2487  return string("UNKNOWN_STATUS_") + to_string(static_cast<int>(st));
2488  }
2489 }
2490 std::string std::to_string(const Game::EPECalgorithm al) {
2491  switch (al) {
2493  return string("fullEnumeration");
2495  return string("innerApproximation");
2497  return string("combinatorialPNE");
2498  default:
2499  return string("UNKNOWN_ALGORITHM_") + to_string(static_cast<int>(al));
2500  }
2501 }
2502 std::string std::to_string(const Game::EPECRecoverStrategy strategy) {
2503  switch (strategy) {
2505  return string("incrementalEnumeration");
2507  return string("combinatorial");
2508  default:
2509  return string("UNKNOWN_RECOVER_STRATEGY_") +
2510  to_string(static_cast<int>(strategy));
2511  }
2512 }
2513 std::string std::to_string(const Game::EPECAddPolyMethod add) {
2514  switch (add) {
2516  return string("sequential");
2518  return string("reverse_sequential");
2520  return string("random");
2521  default:
2522  return string("UNKNOWN_ALGORITHM_") + to_string(static_cast<int>(add));
2523  }
2524 }
2526  std::stringstream ss;
2527  ss << "Algorithm: " << to_string(al.algorithm) << '\n';
2529  ss << "Aggressiveness: " << al.aggressiveness << '\n';
2530  ss << "AddPolyMethod: " << to_string(al.addPolyMethod) << '\n';
2531  }
2532  ss << "Time Limit: " << al.timeLimit << '\n';
2533  ss << "Indicators: " << std::boolalpha << al.indicators;
2534 
2535  return ss.str();
2536 }
arma::vec c
Definition: games.h:42
unsigned int getPosition_LeadFoll(const unsigned int i, const unsigned int j) const
Definition: Games.cpp:2291
std::ostream & operator<<(std::ostream &os, const QP_Param &Q)
arma::sp_mat MarketClearing
Market clearing constraints.
Definition: games.h:257
Class to handle parameterized quadratic programs(QP)
Definition: games.h:146
bool warmstart(const arma::vec x)
Warmstarts EPEC with a solution.
Definition: Games.cpp:2060
bool dataCheck(bool forcesymm=true) const
Check that the data for the MP_Param class is valid Always works after calls to MP_Param::size() Chec...
Definition: Games.cpp:219
void make_country_QP()
Makes the Game::QP_Param for all the countries.
Definition: Games.cpp:1534
string to_string(const Game::EPECsolveStatus st)
Definition: Games.cpp:2474
EPECRecoverStrategy
Definition: games.h:418
void write(std::string filename, bool append=true, bool KKT=false) const
Definition: Games.cpp:990
QP_Param & set(const arma::sp_mat &Q, const arma::sp_mat &C, const arma::sp_mat &A, const arma::sp_mat &B, const arma::vec &c, const arma::vec &b) final
Setting the data, while keeping the input objects intact.
Definition: Games.cpp:447
long int appendRead(vec &matrix, const std::string in, long int pos, const std::string header="")
arma::sp_mat getQ() const
Read-only access to the private variable Q.
Definition: games.h:74
arma::vec getc() const
Read-only access to the private variable c.
Definition: games.h:86
void set_positions()
Definition: Games.cpp:692
EPECalgorithm
Definition: games.h:408
std::vector< std::shared_ptr< QP_Param > > Players
The QP that each player solves.
Definition: games.h:256
unsigned int getPosition_LeadLeadPoly(const unsigned int i, const unsigned int j, const unsigned int k) const
Definition: Games.cpp:2327
class to handle parameterized mathematical programs(MP)
Definition: games.h:52
unsigned int getPosition_LeadLead(const unsigned int i, const unsigned int j) const
Definition: Games.cpp:2302
void resetLCP()
Definition: Games.cpp:1212
struct to handle the constraint params of MP_Param/QP_Param
Definition: games.h:46
NashGame(GRBEnv *e) noexcept
To be used only when NashGame is being loaded from a file.
Definition: games.h:278
void get_x_minus_i(const arma::vec &x, const unsigned int &i, arma::vec &solOther) const
Definition: Games.cpp:1335
unsigned int n_LeadVar
Definition: games.h:272
unsigned int aggressiveness
in EPEC::iterativeNash
Definition: games.h:443
double getVal_Probab(const unsigned int i, const unsigned int k) const
Definition: Games.cpp:2409
void findNashEq()
Definition: Games.cpp:2182
bool computeNashEq(bool pureNE=false, double localTimeLimit=-1.0, bool check=false)
Definition: Games.cpp:1976
void make_pure_LCP(bool indicators=false)
Definition: Games.cpp:2098
void appendSave(const vec &matrix, const std::string out, const std::string header="", bool erase=false)
Definition: games.h:702
std::vector< unsigned int > dual_position
Definition: games.h:265
std::vector< std::pair< unsigned int, unsigned int > > perps
Definition: epecsolve.h:15
void combinatorial_pure_NE(const std::vector< long int > combination, const std::vector< std::set< unsigned long int >> &excludeList)
Definition: Games.cpp:1849
bool isSolved(const arma::vec &sol, unsigned int &violPlayer, arma::vec &violSol, double tol=1e-4) const
Definition: Games.cpp:1166
void finalize()
Finalizes the creation of a Game::EPEC object.
Definition: Games.cpp:1226
GRBEnv * env
Definition: games.h:251
arma::vec ComputeQPObjvals(const arma::vec &x, bool checkFeas=false) const
Definition: Games.cpp:1127
void combinatorialPNE(const std::vector< long int > combination={}, const std::vector< std::set< unsigned long int >> &excludeList={})
Definition: Games.cpp:2161
double computeObjective(const arma::vec &y, const arma::vec &x, bool checkFeas=true, double tol=1e-6) const
Definition: Games.cpp:490
long int load(std::string filename, long int pos=0)
Loads the Game::QP_Param object stored in a file.
Definition: Games.cpp:529
arma::sp_mat A
Definition: games.h:47
unsigned int MC_dual_position
Definition: games.h:267
bool operator==(const QP_Param &Q2) const
Definition: Games.cpp:292
virtual void postfinalize()
Empty function - optionally reimplementable in derived class.
Definition: Games.cpp:1203
arma::sp_mat C
Definition: games.h:41
arma::sp_mat RewriteLeadCons() const
Rewrites leader constraint adjusting for dual variables. Rewrites leader constraints given earlier wi...
Definition: Games.cpp:866
std::unique_ptr< GRBModel > solveFixed(arma::vec x)
Definition: Games.cpp:331
arma::vec MCRHS
RHS to the Market Clearing constraints.
Definition: games.h:258
bool isZero(arma::mat M, double tol=1e-6) noexcept
Definition: Games.cpp:14
void save(std::string filename, bool erase=true) const
Saves the Game::QP_Param object in a loadable file.
Definition: Games.cpp:514
unsigned int getPosition_Probab(const unsigned int i, const unsigned int k) const
Definition: Games.cpp:2349
unsigned int getNx() const
Read-only access to the private variable Nx.
Definition: games.h:92
std::unique_ptr< GRBModel > Respond(unsigned int player, const arma::vec &x, bool fullvec=true) const
Given the decision of other players, find the optimal response for player in position player...
Definition: Games.cpp:1051
arma::sp_mat Q
Definition: games.h:40
arma::sp_mat resize_patch(const arma::sp_mat &Mat, const unsigned int nR, const unsigned int nC)
Definition: Utils.cpp:10
virtual void prefinalize()
Empty function - optionally reimplementable in derived class.
Definition: Games.cpp:1194
Class to handle and solve linear complementarity problems.
Definition: lcptolp.h:41
Solution found for the instance.
arma::sp_mat getA() const
Read-only access to the private variable A.
Definition: games.h:80
bool addRandomPoly2All(unsigned int aggressiveLevel=1, bool stopOnSingleInfeasibility=false)
Definition: Games.cpp:1662
void write(std::string filename, bool append) const
Writes a given parameterized Mathematical program to a set of files.
Definition: Games.cpp:86
unsigned int KKT(arma::sp_mat &M, arma::sp_mat &N, arma::vec &q) const
Compute the KKT conditions for the given QP.
Definition: Games.cpp:417
virtual MP_Param & addDummy(unsigned int pars, unsigned int vars=0, int position=-1)
Definition: Games.cpp:101
void setRecoverStrategy(Game::EPECRecoverStrategy strategy)
Definition: Games.cpp:2282
unsigned int size()
Calculates Nx, Ny and Ncons Computes parameters in MP_Param:
Definition: Games.cpp:159
const NashGame & FormulateLCP(arma::sp_mat &M, arma::vec &q, perps &Compl, bool writeToFile=false, std::string M_name="dat/LCP.txt", std::string q_name="dat/q.txt") const
Definition: Games.cpp:723
Adds the next polyhedra by selecting random feasible one.
double getVal_LeadLeadPoly(const unsigned int i, const unsigned int j, const unsigned int k, const double tol=1e-5) const
Definition: Games.cpp:2456
Adds polyhedra by selecting them in order.
arma::sp_mat getC() const
Read-only access to the private variable C.
Definition: games.h:77
EPECsolveStatus
Definition: games.h:397
Instance proved to be infeasible.
Not started to solve the problem.
virtual MP_Param & set(const arma::sp_mat &Q, const arma::sp_mat &C, const arma::sp_mat &A, const arma::sp_mat &B, const arma::vec &c, const arma::vec &b)
Setting the data, while keeping the input objects intact.
Definition: Games.cpp:178
double RespondSol(arma::vec &sol, unsigned int player, const arma::vec &x, bool fullvec=true) const
Definition: Games.cpp:1094
arma::vec b
Definition: games.h:48
int make_yQy()
Adds the Gurobi Quadratic objective to the Gurobi model QuadModel.
Definition: Games.cpp:308
void iterativeNash()
Definition: Games.cpp:1698
unsigned int getNleaderVars() const
Gets the number of leader variables.
Definition: games.h:329
void add_Dummy_Lead(const unsigned int i)
Add Dummy variables for the leaders.
Definition: Games.cpp:1291
arma::vec LeaderConsRHS
Upper level leader constraints RHS.
Definition: games.h:253
arma::sp_mat getB() const
Read-only access to the private variable B.
Definition: games.h:83
std::unique_ptr< GRBModel > Respond(const unsigned int i, const arma::vec &x) const
Definition: Games.cpp:1366
unsigned int getNPoly_Lead(const unsigned int i) const
Definition: Games.cpp:2341
EPECAddPolyMethod
Definition: epecsolve.h:34
Time limit reached, nash equilibrium not found.
unsigned int getPosition_LeadFollPoly(const unsigned int i, const unsigned int j, const unsigned int k) const
Definition: Games.cpp:2313
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
bool isPureStrategy(const unsigned int i, const double tol=1e-5) const
Definition: Games.cpp:2376
Add random polyhedra in each iteration.
unsigned int Leader_position
Definition: games.h:269
Game::EPECAddPolyMethod addPolyMethod
Definition: games.h:430
bool indicators
Uses bigM if false.
Definition: games.h:437
double getVal_LeadFoll(const unsigned int i, const unsigned int j) const
Definition: Games.cpp:2418
double RespondSol(arma::vec &sol, unsigned int player, const arma::vec &x, const arma::vec &prevDev) const
Definition: Games.cpp:1380
std::vector< unsigned int > mixedStratPoly(const unsigned int i, const double tol=1e-5) const
Definition: Games.cpp:2391
arma::sp_mat LeaderConstraints
Upper level leader constraints LHS.
Definition: games.h:252
ostream & operator<<(ostream &ost, const perps &C)
Definition: Games.cpp:45
std::vector< unsigned int > primal_position
Definition: games.h:262
unsigned int addDeviatedPolyhedron(const std::vector< arma::vec > &devns, bool &infeasCheck) const
Definition: Games.cpp:1622
unsigned int getNy() const
Read-only access to the private variable Ny.
Definition: games.h:95
void print(const perps &C) noexcept
Definition: Games.cpp:39
void write(std::string filename, bool append=true) const
Definition: Games.cpp:60
bool getAllDevns(std::vector< arma::vec > &devns, const arma::vec &guessSol, const std::vector< arma::vec > &prevDev={}) const
Given a potential solution vector, returns a profitable deviation (if it exists) for all players...
Definition: Games.cpp:1593
unsigned int Nplayers
Number of players in the Nash Game.
Definition: games.h:254
double timeLimit
Controls the timelimit for solve in Game::EPEC::findNashEq.
Definition: games.h:439
double getVal_LeadFollPoly(const unsigned int i, const unsigned int j, const unsigned int k, const double tol=1e-5) const
Definition: Games.cpp:2438
void computeLeaderLocations(const unsigned int addSpaceForMC=0)
Definition: Games.cpp:1324
arma::sp_mat B
Definition: games.h:47
QP_Param & addDummy(unsigned int pars, unsigned int vars=0, int position=-1) override
Definition: Games.cpp:386
Stores the configuration for EPEC algorithms.
Definition: games.h:425
Class to model Nash-cournot games with each player playing a QP.
Definition: games.h:249
Definition: utils.h:14
long int load(std::string filename, long int pos=0)
Loads the Game::NashGame object stored in a file.
Definition: Games.cpp:627
Game::EPECalgorithm algorithm
Definition: games.h:426
NashGame & addLeadCons(const arma::vec &a, double b)
Adds Leader constraint to a NashGame object.
Definition: Games.cpp:967
arma::vec getb() const
Read-only access to the private variable b.
Definition: games.h:89
void fullEnumerationNash()
Definition: Games.cpp:2249
unsigned int getNshadow() const
Gets the number of Market clearing Shadow prices.
Definition: games.h:323
double getVal_LeadLead(const unsigned int i, const unsigned int j) const
Definition: Games.cpp:2428
bool isSolved(unsigned int *countryNumber, arma::vec *ProfDevn, double tol=51e-4) const
Definition: Games.cpp:1450
unsigned int getNprimals() const
Return the number of primal variables.
Definition: games.h:311
void save(std::string filename, bool erase=true) const
Saves the Game::NashGame object in a loadable file.
Definition: Games.cpp:609
void setAlgorithm(Game::EPECalgorithm algorithm)
Definition: Games.cpp:2274