EPEC solve
Solving Equilibrium Problems with Equilibrium Constraints (EPECs)
LCPtoLP.cpp
Go to the documentation of this file.
1 #include "lcptolp.h"
2 #include <algorithm>
3 #include <armadillo>
4 #include <boost/log/trivial.hpp>
5 #include <boost/program_options.hpp>
6 #include <cmath>
7 #include <gurobi_c++.h>
8 #include <iostream>
9 #include <memory>
10 #include <random>
11 #include <set>
12 #include <string>
13 
14 using namespace std;
15 using namespace Utils;
16 
17 bool operator==(vector<short int> Fix1, vector<short int> Fix2)
24 {
25  if (Fix1.size() != Fix2.size())
26  return false;
27  for (unsigned int i = 0; i < Fix1.size(); i++) {
28  if (Fix1.at(i) != Fix2.at(i))
29  return false;
30  }
31  return true;
32 }
33 
34 bool operator<(vector<short int> Fix1, vector<short int> Fix2)
45 {
46  if (Fix1.size() != Fix2.size())
47  return false;
48  for (unsigned int i = 0; i < Fix1.size(); i++) {
49  if (Fix1.at(i) != Fix2.at(i) && Fix1.at(i) * Fix2.at(i) != 0) {
50  return false; // Fix1 is not a child of Fix2
51  }
52  }
53  return true; // Fix1 is a child of Fix2
54 }
55 
56 bool operator>(vector<int> Fix1, vector<int> Fix2) { return (Fix2 < Fix1); }
57 
58 void Game::LCP::defConst(GRBEnv *env)
64 {
65  this->Ai = unique_ptr<spmat_Vec>(new spmat_Vec());
66  this->bi = unique_ptr<vec_Vec>(new vec_Vec());
67  this->RlxdModel.set(GRB_IntParam_OutputFlag, VERBOSE);
68  this->env = env;
69  this->nR = this->M.n_rows;
70  this->nC = this->M.n_cols;
71 }
72 
74  GRBEnv *env,
75  arma::sp_mat M,
76  arma::vec q,
77  perps Compl,
78  arma::sp_mat A,
79  arma::vec b
80  )
81  : M{M}, q{q}, _A{A}, _b{b}, RlxdModel(*env)
83 {
84  defConst(env);
85  this->Compl = perps(Compl);
86  std::sort(
87  this->Compl.begin(), this->Compl.end(),
88  [](pair<unsigned int, unsigned int> a,
89  pair<unsigned int, unsigned int> b) { return a.first < b.first; });
90  for (auto p : this->Compl)
91  if (p.first != p.second) {
92  this->LeadStart = p.first;
93  this->LeadEnd = p.second - 1;
94  this->nLeader = this->LeadEnd - this->LeadStart + 1;
95  this->nLeader = this->nLeader > 0 ? this->nLeader : 0;
96  break;
97  }
98  this->initializeNotProcessed();
99 }
100 
102  GRBEnv *env,
103  arma::sp_mat M,
104  arma::vec q,
105  unsigned int LeadStart,
106  unsigned LeadEnd,
108  arma::sp_mat A,
110  arma::vec b
111  )
112  : M{M}, q{q}, _A{A}, _b{b}, RlxdModel(*env)
114 
118 {
119  defConst(env);
120  this->LeadStart = LeadStart;
121  this->LeadEnd = LeadEnd;
122  this->nLeader = this->LeadEnd - this->LeadStart + 1;
123  this->nLeader = this->nLeader > 0 ? this->nLeader : 0;
124  for (unsigned int i = 0; i < M.n_rows; i++) {
125  unsigned int count = i < LeadStart ? i : i + nLeader;
126  this->Compl.push_back({i, count});
127  }
128  std::sort(
129  this->Compl.begin(), this->Compl.end(),
130  [](pair<unsigned int, unsigned int> a,
131  pair<unsigned int, unsigned int> b) { return a.first < b.first; });
132  this->initializeNotProcessed();
133 }
134 
135 Game::LCP::LCP(GRBEnv *env, const NashGame &N)
136  : RlxdModel(*env)
145 {
146  arma::sp_mat M;
147  arma::vec q;
148  perps Compl;
149  N.FormulateLCP(M, q, Compl);
150  // LCP(env, M, q, Compl, N.RewriteLeadCons(), N.getMCLeadRHS());
151 
152  this->M = M;
153  this->q = q;
154  this->_A = N.RewriteLeadCons();
155  this->_b = N.getMCLeadRHS();
156  defConst(env);
157  this->Compl = perps(Compl);
158  sort(this->Compl.begin(), this->Compl.end(),
159  [](pair<unsigned int, unsigned int> a,
160  pair<unsigned int, unsigned int> b) { return a.first < b.first; });
161  // Delete no more!
162  for (auto p : this->Compl) {
163  if (p.first != p.second) {
164  this->LeadStart = p.first;
165  this->LeadEnd = p.second - 1;
166  this->nLeader = this->LeadEnd - this->LeadStart + 1;
167  this->nLeader = this->nLeader > 0 ? this->nLeader : 0;
168  break;
169  }
170  }
171  this->initializeNotProcessed();
172 }
173 
178 {}
179 
186 {
187  try {
188  if (this->madeRlxdModel)
189  return;
190  BOOST_LOG_TRIVIAL(trace)
191  << "Game::LCP::makeRelaxed: Creating a model with : " << nR
192  << " variables and " << nC << " constraints";
193  GRBVar x[nC], z[nR];
194  BOOST_LOG_TRIVIAL(trace)
195  << "Game::LCP::makeRelaxed: Initializing variables";
196  for (unsigned int i = 0; i < nC; i++)
197  x[i] = RlxdModel.addVar(0, GRB_INFINITY, 1, GRB_CONTINUOUS,
198  "x_" + to_string(i));
199  for (unsigned int i = 0; i < nR; i++)
200  z[i] = RlxdModel.addVar(0, GRB_INFINITY, 1, GRB_CONTINUOUS,
201  "z_" + to_string(i));
202  BOOST_LOG_TRIVIAL(trace) << "Game::LCP::makeRelaxed: Added variables";
203  for (unsigned int i = 0; i < nR; i++) {
204  GRBLinExpr expr = 0;
205  for (auto v = M.begin_row(i); v != M.end_row(i); ++v)
206  expr += (*v) * x[v.col()];
207  expr += q(i);
208  RlxdModel.addConstr(expr, GRB_EQUAL, z[i], "z_" + to_string(i) + "_def");
209  }
210  BOOST_LOG_TRIVIAL(trace)
211  << "Game::LCP::makeRelaxed: Added equation definitions";
212  // If @f$Ax \leq b@f$ constraints are there, they should be included too!
213  if (this->_A.n_nonzero != 0 && this->_b.n_rows != 0) {
214  if (_A.n_cols != nC || _A.n_rows != _b.n_rows) {
215  BOOST_LOG_TRIVIAL(trace) << "(" << _A.n_rows << "," << _A.n_cols
216  << ")\t" << _b.n_rows << " " << nC;
217  throw string("Game::LCP::makeRelaxed: A and b are incompatible! Thrown "
218  "from makeRelaxed()");
219  }
220  for (unsigned int i = 0; i < _A.n_rows; i++) {
221  GRBLinExpr expr = 0;
222  for (auto a = _A.begin_row(i); a != _A.end_row(i); ++a)
223  expr += (*a) * x[a.col()];
224  RlxdModel.addConstr(expr, GRB_LESS_EQUAL, _b(i),
225  "commonCons_" + to_string(i));
226  }
227  BOOST_LOG_TRIVIAL(trace)
228  << "Game::LCP::makeRelaxed: Added common constraints";
229  }
230  RlxdModel.update();
231  this->madeRlxdModel = true;
232  } catch (const char *e) {
233  cerr << "Error in Game::LCP::makeRelaxed: " << e << '\n';
234  throw;
235  } catch (string e) {
236  cerr << "String: Error in Game::LCP::makeRelaxed: " << e << '\n';
237  throw;
238  } catch (exception &e) {
239  cerr << "Exception: Error in Game::LCP::makeRelaxed: " << e.what() << '\n';
240  throw;
241  } catch (GRBException &e) {
242  cerr << "GRBException: Error in Game::LCP::makeRelaxed: "
243  << e.getErrorCode() << "; " << e.getMessage() << '\n';
244  throw;
245  }
246 }
247 
248 unique_ptr<GRBModel> Game::LCP::LCP_Polyhed_fixed(
249  vector<unsigned int>
250  FixEq,
251  vector<unsigned int>
252  FixVar
253  )
270 {
271  makeRelaxed();
272  unique_ptr<GRBModel> model(new GRBModel(this->RlxdModel));
273  for (auto i : FixEq) {
274  if (i >= nR)
275  throw "Game::LCP::LCP_Polyhed_fixed: Element in FixEq is greater than nC";
276  model->getVarByName("z_" + to_string(i)).set(GRB_DoubleAttr_UB, 0);
277  }
278  for (auto i : FixVar) {
279  if (i >= nC)
280  throw "Game::LCP::LCP_Polyhed_fixed: Element in FixEq is greater than nC";
281  model->getVarByName("z_" + to_string(i)).set(GRB_DoubleAttr_UB, 0);
282  }
283  return model;
284 }
285 
286 unique_ptr<GRBModel> Game::LCP::LCP_Polyhed_fixed(
287  arma::Col<int> FixEq,
288  arma::Col<int> FixVar
289  )
305 {
306  makeRelaxed();
307  unique_ptr<GRBModel> model{new GRBModel(this->RlxdModel)};
308  for (unsigned int i = 0; i < nC; i++)
309  if (FixVar[i])
310  model->getVarByName("x_" + to_string(i)).set(GRB_DoubleAttr_UB, 0);
311  for (unsigned int i = 0; i < nR; i++)
312  if (FixEq[i])
313  model->getVarByName("z_" + to_string(i)).set(GRB_DoubleAttr_UB, 0);
314  model->update();
315  return model;
316 }
317 
318 unique_ptr<GRBModel> Game::LCP::LCPasMIP(
319  vector<short int>
320  Fixes,
321  bool solve
323  )
335 {
336  if (Fixes.size() != this->nR)
337  throw string(
338  "Game::LCP::LCPasMIP: Bad size for Fixes in Game::LCP::LCPasMIP");
339  vector<unsigned int> FixVar, FixEq;
340  for (unsigned int i = 0; i < nR; i++) {
341  if (Fixes[i] == 1)
342  FixEq.push_back(i);
343  if (Fixes[i] == -1)
344  FixVar.push_back(i > this->LeadStart ? i + this->nLeader : i);
345  }
346  return this->LCPasMIP(FixEq, FixVar, solve);
347 }
348 
349 unique_ptr<GRBModel> Game::LCP::LCPasMIP(
350  vector<unsigned int> FixEq,
351  vector<unsigned int> FixVar,
352  bool solve
353  )
364 {
365  makeRelaxed();
366  unique_ptr<GRBModel> model{new GRBModel(this->RlxdModel)};
367  // Creating the model
368  try {
369  GRBVar x[nC], z[nR], u[nR], v[nR];
370  // Get hold of the Variables and Eqn Variables
371  for (unsigned int i = 0; i < nC; i++)
372  x[i] = model->getVarByName("x_" + to_string(i));
373  for (unsigned int i = 0; i < nR; i++)
374  z[i] = model->getVarByName("z_" + to_string(i));
375  // Define binary variables for bigM
376  for (unsigned int i = 0; i < nR; i++)
377  u[i] = model->addVar(0, 1, 0, GRB_BINARY, "u_" + to_string(i));
378  if (this->useIndicators)
379  for (unsigned int i = 0; i < nR; i++)
380  v[i] = model->addVar(0, 1, 0, GRB_BINARY, "v_" + to_string(i));
381  // Include ALL Complementarity constraints using bigM
382 
383  if (this->useIndicators) {
384  BOOST_LOG_TRIVIAL(trace)
385  << "Using indicator constraints for complementarities.";
386  } else {
387  BOOST_LOG_TRIVIAL(trace)
388  << "Using bigM for complementarities with M=" << this->bigM;
389  }
390 
391  GRBLinExpr expr = 0;
392  for (const auto p : Compl) {
393  // z[i] <= Mu constraint
394 
395  // u[j]=0 --> z[i] <=0
396  if (!this->useIndicators) {
397  expr = bigM * u[p.first];
398  model->addConstr(expr, GRB_GREATER_EQUAL, z[p.first],
399  "z" + to_string(p.first) + "_L_Mu" +
400  to_string(p.first));
401  } else {
402  model->addGenConstrIndicator(
403  u[p.first], 1, z[p.first], GRB_LESS_EQUAL, 0,
404  "z_ind_" + to_string(p.first) + "_L_Mu_" + to_string(p.first));
405  }
406  // x[i] <= M(1-u) constraint
407  if (!this->useIndicators) {
408  expr = bigM - bigM * u[p.first];
409  model->addConstr(expr, GRB_GREATER_EQUAL, x[p.second],
410  "x" + to_string(p.first) + "_L_MuDash" +
411  to_string(p.first));
412  } else {
413  model->addGenConstrIndicator(
414  v[p.first], 1, x[p.second], GRB_LESS_EQUAL, 0,
415  "x_ind_" + to_string(p.first) + "_L_MuDash_" + to_string(p.first));
416  }
417 
418  if (this->useIndicators)
419  model->addConstr(u[p.first] + v[p.first], GRB_EQUAL, 1,
420  "uv_sum_" + to_string(p.first));
421  }
422  // If any equation or variable is to be fixed to zero, that happens here!
423  for (auto i : FixVar)
424  model->addConstr(x[i], GRB_EQUAL, 0.0);
425  for (auto i : FixEq)
426  model->addConstr(z[i], GRB_EQUAL, 0.0);
427  model->update();
428  if (!this->useIndicators) {
429  model->set(GRB_DoubleParam_IntFeasTol, this->eps_int);
430  model->set(GRB_DoubleParam_FeasibilityTol, this->eps);
431  model->set(GRB_DoubleParam_OptimalityTol, this->eps);
432  }
433  // Get first Equilibrium
434  model->set(GRB_IntParam_SolutionLimit, 1);
435  if (solve)
436  model->optimize();
437  return model;
438  } catch (const char *e) {
439  cerr << "Error in Game::LCP::LCPasMIP: " << e << '\n';
440  throw;
441  } catch (string e) {
442  cerr << "String: Error in Game::LCP::LCPasMIP: " << e << '\n';
443  throw;
444  } catch (exception &e) {
445  cerr << "Exception: Error in Game::LCP::LCPasMIP: " << e.what() << '\n';
446  throw;
447  } catch (GRBException &e) {
448  cerr << "GRBException: Error in Game::LCP::LCPasMIP: " << e.getErrorCode()
449  << "; " << e.getMessage() << '\n';
450  throw;
451  }
452  return nullptr;
453 }
454 
456  bool throwErr
457 ) const
463 {
464  const unsigned int nR = M.n_rows;
465  const unsigned int nC = M.n_cols;
466  if (throwErr) {
467  if (nR != q.n_rows)
468  throw "Game::LCP::errorCheck: M and q have unequal number of rows";
469  if (nR + nLeader != nC)
470  throw "Game::LCP::errorCheck: Inconsistency between number of leader "
471  "vars " +
472  to_string(nLeader) + ", number of rows " + to_string(nR) +
473  " and number of cols " + to_string(nC);
474  }
475  return (nR == q.n_rows && nR + nLeader == nC);
476 }
477 
478 void Game::LCP::print(string end) {
479  cout << "LCP with " << this->nR << " rows and " << this->nC << " columns."
480  << end;
481 }
482 
483 unsigned int
484 Game::LCP::ConvexHull(arma::sp_mat &A,
485  arma::vec &b)
487 
491 {
492  const std::vector<arma::sp_mat *> tempAi = [](spmat_Vec &uv) {
493  std::vector<arma::sp_mat *> v{};
494  for (const auto &x : uv)
495  v.push_back(x.get());
496  return v;
497  }(*this->Ai);
498  const std::vector<arma::vec *> tempbi = [](vec_Vec &uv) {
499  std::vector<arma::vec *> v{};
500  std::for_each(uv.begin(), uv.end(),
501  [&v](const std::unique_ptr<arma::vec> &ptr) {
502  v.push_back(ptr.get());
503  });
504  return v;
505  }(*this->bi);
506  arma::sp_mat A_common;
507  A_common = arma::join_cols(this->_A, -this->M);
508  arma::vec b_common = arma::join_cols(this->_b, this->q);
509  if (Ai->size() == 1) {
510  A.zeros(Ai->at(0)->n_rows + A_common.n_rows,
511  Ai->at(0)->n_cols + A_common.n_cols);
512  b.zeros(bi->at(0)->n_rows + b_common.n_rows);
513  A = arma::join_cols(*Ai->at(0), A_common);
514  b = arma::join_cols(*bi->at(0), b_common);
515  return 1;
516  } else
517  return Game::ConvexHull(&tempAi, &tempbi, A, b, A_common, b_common);
518 };
519 
520 unsigned int Game::ConvexHull(
521  const vector<arma::sp_mat *>
522  *Ai,
523  const vector<arma::vec *>
525  *bi,
526  arma::sp_mat &A,
528  arma::vec &b,
529  const arma::sp_mat
530  Acom,
531  const arma::vec bcom
532  )
546 {
547  // Count number of polyhedra and the space we are in!
548  const unsigned int nPoly{static_cast<unsigned int>(Ai->size())};
549  // Error check
550  if (nPoly == 0)
551  throw string(
552  "Game::ConvexHull: Empty vector of polyhedra given! Problem might be "
553  "infeasible."); // There should be at least 1 polyhedron to
554  // consider
555  const unsigned int nC{static_cast<unsigned int>(Ai->front()->n_cols)};
556  const unsigned int nComm{static_cast<unsigned int>(Acom.n_rows)};
557 
558  if (nComm > 0 && Acom.n_cols != nC)
559  throw string("Game::ConvexHull: Inconsistent number of variables in the "
560  "common polyhedron");
561  if (nComm > 0 && nComm != bcom.n_rows)
562  throw string("Game::ConvexHull: Inconsistent number of rows in LHS and RHS "
563  "in the common polyhedron");
564 
565  // Count the number of variables in the convex hull.
566  unsigned int nFinCons{0}, nFinVar{0};
567  if (nPoly != bi->size())
568  throw string(
569  "Game::ConvexHull: Inconsistent number of LHS and RHS for polyhedra");
570  for (unsigned int i = 0; i != nPoly; i++) {
571  if (Ai->at(i)->n_cols != nC)
572  throw string("Game::ConvexHull: Inconsistent number of variables in the "
573  "polyhedra ") +
574  to_string(i) + "; " + to_string(Ai->at(i)->n_cols) +
575  "!=" + to_string(nC);
576  if (Ai->at(i)->n_rows != bi->at(i)->n_rows)
577  throw string("Game::ConvexHull: Inconsistent number of rows in LHS and "
578  "RHS of polyhedra ") +
579  to_string(i) + ";" + to_string(Ai->at(i)->n_rows) +
580  "!=" + to_string(bi->at(i)->n_rows);
581  nFinCons += Ai->at(i)->n_rows;
582  }
583  // For common constraint copy
584  nFinCons += nPoly * nComm;
585 
586  const unsigned int FirstCons = nFinCons;
587 
588  // 2nd constraint in Eqn 4.31 of Conforti - twice so we have 2 ineq instead of
589  // 1 eq constr
590  nFinCons += nC * 2;
591  // 3rd constr in Eqn 4.31. Again as two ineq constr.
592  nFinCons += 2;
593  // Common constraints
594  // nFinCons += Acom.n_rows;
595 
596  nFinVar = nPoly * nC + nPoly +
597  nC; // All x^i variables + delta variables+ original x variables
598  A.zeros(nFinCons, nFinVar);
599  b.zeros(nFinCons);
600  // A.zeros(nFinCons, nFinVar); b.zeros(nFinCons);
601  // Implements the first constraint more efficiently using better constructors
602  // for sparse matrix
603  Game::compConvSize(A, nFinCons, nFinVar, Ai, bi, Acom, bcom);
604 
605  // Counting rows completed
606  /****************** SLOW LOOP BEWARE *******************/
607  for (unsigned int i = 0; i < nPoly; i++) {
608  BOOST_LOG_TRIVIAL(trace) << "Game::ConvexHull: Handling Polyhedron "
609  << i + 1 << " out of " << nPoly;
610  // First constraint in (4.31)
611  // A.submat(complRow, i*nC, complRow+nConsInPoly-1, (i+1)*nC-1) =
612  // *Ai->at(i); // Slowest line. Will arma improve this? First constraint RHS
613  // A.submat(complRow, nPoly*nC+i, complRow+nConsInPoly-1, nPoly*nC+i) =
614  // -*bi->at(i); Second constraint in (4.31)
615  for (unsigned int j = 0; j < nC; j++) {
616  A.at(FirstCons + 2 * j, nC + (i * nC) + j) = 1;
617  A.at(FirstCons + 2 * j + 1, nC + (i * nC) + j) = -1;
618  }
619  // Third constraint in (4.31)
620  A.at(FirstCons + nC * 2, nC + nPoly * nC + i) = 1;
621  A.at(FirstCons + nC * 2 + 1, nC + nPoly * nC + i) = -1;
622  }
623  /****************** SLOW LOOP BEWARE *******************/
624  // Second Constraint RHS
625  for (unsigned int j = 0; j < nC; j++) {
626  A.at(FirstCons + 2 * j, j) = -1;
627  A.at(FirstCons + 2 * j + 1, j) = 1;
628  }
629  // Third Constraint RHS
630  b.at(FirstCons + nC * 2) = 1;
631  b.at(FirstCons + nC * 2 + 1) = -1;
632  return nPoly;
633 }
635 
636 void Game::compConvSize(
637  arma::sp_mat &A,
638  const unsigned int nFinCons,
639  const unsigned int nFinVar,
640  const vector<arma::sp_mat *>
641  *Ai,
642  const vector<arma::vec *>
644  *bi,
645  const arma::sp_mat
647  &Acom,
648  const arma::vec &bcom
649  )
659 {
660  const unsigned int nPoly{static_cast<unsigned int>(Ai->size())};
661  const unsigned int nC{static_cast<unsigned int>(Ai->front()->n_cols)};
662  unsigned int N{0}; // Total number of nonzero elements in the final matrix
663  const unsigned int nCommnz{
664  static_cast<unsigned int>(Acom.n_nonzero + bcom.n_rows)};
665  for (unsigned int i = 0; i < nPoly; i++) {
666  N += Ai->at(i)->n_nonzero;
667  N += bi->at(i)->n_rows;
668  }
669  N += nCommnz *
670  nPoly; // The common constraints have to be copied for each polyhedron.
671 
672  // Now computed N which is the total number of nonzeros.
673  arma::umat locations; // location of nonzeros
674  arma::vec val; // nonzero values
675  locations.zeros(2, N);
676  val.zeros(N);
677 
678  unsigned int count{0}, rowCount{0}, colCount{nC};
679  for (unsigned int i = 0; i < nPoly; i++) {
680  for (auto it = Ai->at(i)->begin(); it != Ai->at(i)->end();
681  ++it) // First constraint
682  {
683  locations(0, count) = rowCount + it.row();
684  locations(1, count) = colCount + it.col();
685  val(count) = *it;
686  ++count;
687  }
688  for (unsigned int j = 0; j < bi->at(i)->n_rows;
689  ++j) // RHS of first constraint
690  {
691  locations(0, count) = rowCount + j;
692  locations(1, count) = nC + nC * nPoly + i;
693  val(count) = -bi->at(i)->at(j);
694  ++count;
695  }
696  rowCount += Ai->at(i)->n_rows;
697 
698  // For common constraints
699  for (auto it = Acom.begin(); it != Acom.end(); ++it) // First constraint
700  {
701  locations(0, count) = rowCount + it.row();
702  locations(1, count) = colCount + it.col();
703  val(count) = *it;
704  ++count;
705  }
706  for (unsigned int j = 0; j < bcom.n_rows; ++j) // RHS of first constraint
707  {
708  locations(0, count) = rowCount + j;
709  locations(1, count) = nC + nC * nPoly + i;
710  val(count) = -bcom.at(j);
711  ++count;
712  }
713  rowCount += Acom.n_rows;
714 
715  colCount += nC;
716  }
717  A = arma::sp_mat(locations, val, nFinCons, nFinVar);
718 }
719 
720 arma::vec
721 Game::LPSolve(const arma::sp_mat &A,
722  const arma::vec &b,
723  const arma::vec &c,
724  int &status,
726  bool Positivity
728  )
734 {
735  unsigned int nR, nC;
736  nR = A.n_rows;
737  nC = A.n_cols;
738  if (c.n_rows != nC)
739  throw "Game::LPSolve: Inconsistency in no of Vars in isFeas()";
740  if (b.n_rows != nR)
741  throw "Game::LPSolve: Inconsistency in no of Constr in isFeas()";
742 
743  arma::vec sol = arma::vec(c.n_rows, arma::fill::zeros);
744  const double lb = Positivity ? 0 : -GRB_INFINITY;
745 
746  GRBEnv env;
747  GRBModel model = GRBModel(env);
748  GRBVar x[nC];
749  GRBConstr a[nR];
750  // Adding Variables
751  for (unsigned int i = 0; i < nC; i++)
752  x[i] = model.addVar(lb, GRB_INFINITY, c.at(i), GRB_CONTINUOUS,
753  "x_" + to_string(i));
754  // Adding constraints
755  for (unsigned int i = 0; i < nR; i++) {
756  GRBLinExpr lin{0};
757  for (auto j = A.begin_row(i); j != A.end_row(i); ++j)
758  lin += (*j) * x[j.col()];
759  a[i] = model.addConstr(lin, GRB_LESS_EQUAL, b.at(i));
760  }
761  model.set(GRB_IntParam_OutputFlag, VERBOSE);
762  model.set(GRB_IntParam_DualReductions, 0);
763  model.optimize();
764  status = model.get(GRB_IntAttr_Status);
765  if (status == GRB_OPTIMAL)
766  for (unsigned int i = 0; i < nC; i++)
767  sol.at(i) = x[i].get(GRB_DoubleAttr_X);
768  return sol;
769 }
770 
772  GRBModel *model,
773  arma::vec &z,
775  arma::vec &x,
776  bool extractZ
777 ) const
783 {
784  if (model->get(GRB_IntAttr_Status) == GRB_LOADED)
785  model->optimize();
786  auto status = model->get(GRB_IntAttr_Status);
787  if (!(status == GRB_OPTIMAL || status == GRB_SUBOPTIMAL ||
788  status == GRB_SOLUTION_LIMIT))
789  return false;
790  x.zeros(nC);
791  if (extractZ)
792  z.zeros(nR);
793  for (unsigned int i = 0; i < nR; i++) {
794  x[i] = model->getVarByName("x_" + to_string(i)).get(GRB_DoubleAttr_X);
795  if (extractZ)
796  z[i] = model->getVarByName("z_" + to_string(i)).get(GRB_DoubleAttr_X);
797  }
798  for (unsigned int i = nR; i < nC; i++)
799  x[i] = model->getVarByName("x_" + to_string(i)).get(GRB_DoubleAttr_X);
800  return true;
801 }
802 
803 std::vector<short int> Game::LCP::solEncode(const arma::vec &x) const
815 {
816  return this->solEncode(this->M * x + this->q, x);
817 }
818 
819 vector<short int> Game::LCP::solEncode(const arma::vec &z,
820  const arma::vec &x
821 ) const
824 {
825  vector<short int> solEncoded(nR, 0);
826  for (const auto p : Compl) {
827  unsigned int i, j;
828  i = p.first;
829  j = p.second;
830  if (isZero(z(i)))
831  solEncoded.at(i)++;
832  if (isZero(x(j)))
833  solEncoded.at(i)--;
834  if (!isZero(x(j)) && !isZero(z(i)))
835  BOOST_LOG_TRIVIAL(error) << "Infeasible point given! Stay alert! " << x(j)
836  << " " << z(i) << " with i=" << i;
837  };
838  // std::stringstream enc_str;
839  // for(auto vv:solEncoded) enc_str << vv <<" ";
840  // BOOST_LOG_TRIVIAL (debug) << "Game::LCP::solEncode: Handling deviation with
841  // encoding: "<< enc_str.str() << '\n';
842  return solEncoded;
843 }
844 
845 vector<short int> Game::LCP::solEncode(GRBModel *model) const
851 {
852  arma::vec x, z;
853  if (!this->extractSols(model, z, x, true))
854  return {}; // If infeasible model, return empty!
855  else
856  return this->solEncode(z, x);
857 }
858 
859 LCP &Game::LCP::addPolyFromX(const arma::vec &x, bool &ret)
866 {
867  const unsigned int nCompl = this->Compl.size();
868  vector<short int> encoding = this->solEncode(x);
869  std::stringstream enc_str;
870  for (auto vv : encoding)
871  enc_str << vv << " ";
872  BOOST_LOG_TRIVIAL(trace)
873  << "Game::LCP::addPolyFromX: Handling deviation with encoding: "
874  << enc_str.str() << '\n';
875  // Check if the encoding polyhedron is already in this->AllPolyhedra
876  for (const auto &i : AllPolyhedra) {
877  std::vector<short int> bin = num_to_vec(i, nCompl);
878  if (encoding < bin) {
879  BOOST_LOG_TRIVIAL(trace) << "LCP::addPolyFromX: Encoding " << i
880  << " already in All Polyhedra! ";
881  ret = false;
882  return *this;
883  }
884  }
885 
886  BOOST_LOG_TRIVIAL(trace)
887  << "LCP::addPolyFromX: New encoding not in All Polyhedra! ";
888  // If it is not in AllPolyhedra
889  // First change any zero indices of encoding to 1
890  for (short &i : encoding) {
891  if (i == 0)
892  ++i;
893  }
894  // And then add the relevant polyhedra
895  ret = this->FixToPoly(encoding, false);
896  // ret = true;
897  return *this;
898 }
899 
901  const vector<short int>
902  Fix,
903  bool checkFeas,
905  bool custom,
907  spmat_Vec *custAi,
909  vec_Vec *custbi
911  )
926 {
927  unsigned int FixNumber = vec_to_num(Fix);
928  BOOST_LOG_TRIVIAL(trace) << "Game::LCP::FixToPoly: Working on polyhedron"
929  << FixNumber;
930 
931  if (knownInfeas.find(FixNumber) != knownInfeas.end()) {
932  BOOST_LOG_TRIVIAL(trace) << "Game::LCP::FixToPoly: Previously known "
933  "infeasible polyhedron. Not added"
934  << FixNumber;
935  return false;
936  }
937 
938  if (!custom && !AllPolyhedra.empty()) {
939  if (AllPolyhedra.find(FixNumber) != AllPolyhedra.end()) {
940  BOOST_LOG_TRIVIAL(trace)
941  << "Game::LCP::FixToPoly: Previously added polyhedron. Not added "
942  << FixNumber;
943  return false;
944  }
945  }
946 
947  unique_ptr<arma::sp_mat> Aii =
948  unique_ptr<arma::sp_mat>(new arma::sp_mat(nR, nC));
949  Aii->zeros();
950  unique_ptr<arma::vec> bii =
951  unique_ptr<arma::vec>(new arma::vec(nR, arma::fill::zeros));
952  for (unsigned int i = 0; i < this->nR; i++) {
953  if (Fix.at(i) == 0) {
954  throw string(
955  "Error in Game::LCP::FixToPoly. 0s not allowed in argument vector");
956  }
957  if (Fix.at(i) == 1) // Equation to be fixed top zero
958  {
959  for (auto j = this->M.begin_row(i); j != this->M.end_row(i); ++j)
960  if (!this->isZero((*j)))
961  Aii->at(i, j.col()) =
962  (*j); // Only mess with non-zero elements of a sparse matrix!
963  bii->at(i) = -this->q(i);
964  } else // Variable to be fixed to zero, i.e. x(j) <= 0 constraint to be
965  // added
966  {
967  unsigned int varpos = (i >= this->LeadStart) ? i + this->nLeader : i;
968  Aii->at(i, varpos) = 1;
969  bii->at(i) = 0;
970  }
971  }
972  bool add = !checkFeas;
973  if (checkFeas) {
974  add = this->checkPolyFeas(Fix);
975  }
976  if (add) {
977  if (custom) {
978  custAi->push_back(std::move(Aii));
979  custbi->push_back(std::move(bii));
980  } else {
981  AllPolyhedra.insert(FixNumber);
982  this->Ai->push_back(std::move(Aii));
983  this->bi->push_back(std::move(bii));
984  }
985  return true; // Successfully added
986  }
987  return false;
988 }
989 
991  const unsigned long int
992  &decimalEncoding
993 ) {
994  return this->checkPolyFeas(num_to_vec(decimalEncoding, this->Compl.size()));
995 }
996 
998  const vector<short int> &Fix
999 ) {
1001 
1002  unsigned long int FixNumber = vec_to_num(Fix);
1003  if (knownInfeas.find(FixNumber) != knownInfeas.end()) {
1004  BOOST_LOG_TRIVIAL(trace) << "Game::LCP::checkPolyFeas: Previously known "
1005  "infeasible polyhedron. "
1006  << FixNumber;
1007  return false;
1008  }
1009 
1010  if (feasiblePoly.find(FixNumber) != feasiblePoly.end()) {
1011  BOOST_LOG_TRIVIAL(trace) << "Game::LCP::checkPolyFeas: Previously known "
1012  "feasible polyhedron."
1013  << FixNumber;
1014  return true;
1015  }
1016 
1017  unsigned int count{0};
1018  try {
1019  makeRelaxed();
1020  GRBModel model(this->RlxdModel);
1021  for (auto i : Fix) {
1022  if (i > 0)
1023  model.getVarByName("z_" + to_string(count)).set(GRB_DoubleAttr_UB, 0);
1024  if (i < 0)
1025  model
1026  .getVarByName("x_" + to_string(count >= this->LeadStart
1027  ? count + nLeader
1028  : count))
1029  .set(GRB_DoubleAttr_UB, 0);
1030  count++;
1031  }
1032  model.set(GRB_IntParam_OutputFlag, VERBOSE);
1033  model.optimize();
1034  if (model.get(GRB_IntAttr_Status) == GRB_OPTIMAL) {
1035  feasiblePoly.insert(FixNumber);
1036  return true;
1037  } else {
1038  BOOST_LOG_TRIVIAL(trace)
1039  << "Game::LCP::checkPolyFeas: Detected infeasibility of " << FixNumber
1040  << " (GRB_STATUS=" << model.get(GRB_IntAttr_Status) << ")";
1041  knownInfeas.insert(FixNumber);
1042  return false;
1043  }
1044  } catch (const char *e) {
1045  cerr << "Error in Game::LCP::FixToPoly: " << e << '\n';
1046  throw;
1047  } catch (string e) {
1048  cerr << "String: Error in Game::LCP::FixToPoly: " << e << '\n';
1049  throw;
1050  } catch (exception &e) {
1051  cerr << "Exception: Error in Game::LCP::FixToPoly: " << e.what() << '\n';
1052  throw;
1053  } catch (GRBException &e) {
1054  cerr << "GRBException: Error in Game::LCP::FixToPoly: " << e.getErrorCode()
1055  << ": " << e.getMessage() << '\n';
1056  throw;
1057  }
1058  return false;
1059 }
1060 
1062  const vector<short int>
1063  Fix,
1064  bool checkFeas,
1066  bool custom,
1068  spmat_Vec *custAi,
1070  vec_Vec *custbi
1072  )
1088 {
1089  bool flag = false; // flag that there may be multiple polyhedra, i.e. 0 in
1090  // some Fix entry
1091  vector<short int> MyFix(Fix);
1092  unsigned int i;
1093  for (i = 0; i < this->nR; i++) {
1094  if (Fix.at(i) == 0) {
1095  flag = true;
1096  break;
1097  }
1098  }
1099  if (flag) {
1100  MyFix[i] = 1;
1101  this->FixToPolies(MyFix, checkFeas, custom, custAi, custbi);
1102  MyFix[i] = -1;
1103  this->FixToPolies(MyFix, checkFeas, custom, custAi, custbi);
1104  } else
1105  this->FixToPoly(Fix, checkFeas, custom, custAi, custbi);
1106  return *this;
1107 }
1108 
1116  switch (method) {
1118  while (this->sequentialPolyCounter < this->maxTheoreticalPoly) {
1119  const bool isAll =
1120  AllPolyhedra.find(this->sequentialPolyCounter) != AllPolyhedra.end();
1121  const bool isInfeas =
1122  knownInfeas.find(this->sequentialPolyCounter) != knownInfeas.end();
1123  this->sequentialPolyCounter++;
1124  if (!isAll && !isInfeas) {
1125  return this->sequentialPolyCounter - 1;
1126  }
1127  }
1128  return this->maxTheoreticalPoly;
1129  } break;
1131  while (this->reverseSequentialPolyCounter >= 0) {
1132  const bool isAll =
1134  AllPolyhedra.end();
1135  const bool isInfeas =
1137  knownInfeas.end();
1139  if (!isAll && !isInfeas) {
1140  return this->reverseSequentialPolyCounter + 1;
1141  }
1142  }
1143  return this->maxTheoreticalPoly;
1144  } break;
1146  static std::mt19937 engine{this->addPolyMethodSeed};
1147  std::uniform_int_distribution<unsigned long int> dist(
1148  0, this->maxTheoreticalPoly - 1);
1149  if ((knownInfeas.size() + AllPolyhedra.size()) == this->maxTheoreticalPoly)
1150  return this->maxTheoreticalPoly;
1151  while (true) {
1152  unsigned long int randomPolyId = dist(engine);
1153  const bool isAll = AllPolyhedra.find(randomPolyId) != AllPolyhedra.end();
1154  const bool isInfeas = knownInfeas.find(randomPolyId) != knownInfeas.end();
1155  if (!isAll && !isInfeas)
1156  return randomPolyId;
1157  }
1158  }
1159  default: {
1160  BOOST_LOG_TRIVIAL(error)
1161  << "Error in Game::LCP::getNextPoly: unrecognized method "
1162  << to_string(method);
1163  throw;
1164  }
1165  }
1166 }
1167 
1168 std::set<std::vector<short int>>
1169 Game::LCP::addAPoly(unsigned long int nPoly, Game::EPECAddPolyMethod method,
1170  std::set<std::vector<short int>> Polys) {
1180  // We already have polyhedrain AllPolyhedra and polyhedra in
1181  // knownInfeas, that are known to be infeasible.
1182  // Effective maximum of number of polyhedra that can be added
1183  // at most
1184  const unsigned int nCompl = this->Compl.size();
1185 
1186  if (this->maxTheoreticalPoly <
1187  nPoly) { // If you cannot add that many polyhedra
1188  BOOST_LOG_TRIVIAL(warning) // Then issue a warning
1189  << "Warning in Game::LCP::randomPoly: "
1190  << "Cannot add " << nPoly << " polyhedra. Promising a maximum of "
1191  << this->maxTheoreticalPoly;
1192  nPoly = this->maxTheoreticalPoly; // and update maximum possibly addable
1193  }
1194 
1195  if (nPoly == 0) // If nothing to be added, then nothing to be done
1196  return Polys;
1197 
1198  if (nPoly < 0) // There is no way that this can happen!
1199  {
1200  BOOST_LOG_TRIVIAL(error) << "nPoly can't be negative, i.e., " << nPoly;
1201  throw string(
1202  "Error in Game::LCP::addAPoly: nPoly reached a negative value!");
1203  }
1204 
1205  bool complete{false};
1206  while (!complete) {
1207  unsigned long int choice_decimal = this->getNextPoly(method);
1208  if (choice_decimal >= this->maxTheoreticalPoly)
1209  return Polys;
1210 
1211  const std::vector<short int> choice = num_to_vec(choice_decimal, nCompl);
1212  auto added = this->FixToPoly(choice, true);
1213  if (added) // If choice is added to All Polyhedra
1214  {
1215  Polys.insert(choice); // Add it to set of added polyhedra
1216  if (Polys.size() == nPoly) {
1217  complete = true;
1218  return Polys;
1219  }
1220  }
1221  }
1222  return Polys;
1223 }
1224 bool Game::LCP::addThePoly(const unsigned long int &decimalEncoding) {
1225  if (this->maxTheoreticalPoly < decimalEncoding) {
1226  // This polyhedron does not exist
1227  BOOST_LOG_TRIVIAL(warning)
1228  << "Warning in Game::LCP::addThePoly: Cannot add " << decimalEncoding
1229  << " polyhedra, since it does not exist!";
1230  return false;
1231  }
1232  const unsigned int nCompl = this->Compl.size();
1233  const std::vector<short int> choice = num_to_vec(decimalEncoding, nCompl);
1234  return this->FixToPoly(choice, true);
1235 }
1236 
1238  const bool
1239  solveLP
1240  )
1246 {
1247  vector<short int> Fix = vector<short int>(nR, 0);
1248  this->Ai->clear();
1249  this->bi->clear();
1250  this->FixToPolies(Fix, solveLP);
1251  if (this->Ai->empty()) {
1252  BOOST_LOG_TRIVIAL(warning)
1253  << "Empty vector of polyhedra given! Problem might be infeasible."
1254  << '\n';
1255  // 0 <= -1 for infeasability
1256  unique_ptr<arma::sp_mat> A(new arma::sp_mat(1, this->M.n_cols));
1257  unique_ptr<arma::vec> b(new arma::vec(1));
1258  b->at(0) = -1;
1259  this->Ai->push_back(std::move(A));
1260  this->bi->push_back(std::move(b));
1261  }
1262  return *this;
1263 }
1264 
1267  &QP_obj,
1268  Game::QP_Param &QP
1270 
1272 ) {
1273  // Original sizes
1274  if (this->Ai->empty())
1275  return *this;
1276  const unsigned int Nx_old{static_cast<unsigned int>(QP_obj.C.n_cols)};
1277 
1278  Game::QP_constraints QP_cons;
1279  this->feasiblePolyhedra = this->ConvexHull(QP_cons.B, QP_cons.b);
1280  BOOST_LOG_TRIVIAL(trace) << "LCP::makeQP: No. feasible polyhedra: "
1281  << this->feasiblePolyhedra;
1282  // Updated size after convex hull has been computed.
1283  const unsigned int Ncons{static_cast<unsigned int>(QP_cons.B.n_rows)};
1284  const unsigned int Ny{static_cast<unsigned int>(QP_cons.B.n_cols)};
1285  // Resizing entities.
1286  QP_cons.A.zeros(Ncons, Nx_old);
1287  QP_obj.c = resize_patch(QP_obj.c, Ny, 1);
1288  QP_obj.C = resize_patch(QP_obj.C, Ny, Nx_old);
1289  QP_obj.Q = resize_patch(QP_obj.Q, Ny, Ny);
1290  // Setting the QP_Param object
1291  QP.set(QP_obj, QP_cons);
1292  return *this;
1293 }
1294 
1295 unique_ptr<GRBModel> Game::LCP::LCPasQP(bool solve)
1304 {
1305  this->makeRelaxed();
1306  unique_ptr<GRBModel> model(new GRBModel(this->RlxdModel));
1307  GRBQuadExpr obj = 0;
1308  GRBVar x[this->nR];
1309  GRBVar z[this->nR];
1310  for (const auto p : this->Compl) {
1311  unsigned int i = p.first;
1312  unsigned int j = p.second;
1313  z[i] = model->getVarByName("z_" + to_string(i));
1314  x[i] = model->getVarByName("x_" + to_string(j));
1315  obj += x[i] * z[i];
1316  }
1317  model->setObjective(obj, GRB_MINIMIZE);
1318  if (solve) {
1319  try {
1320  model->optimize();
1321  int status = model->get(GRB_IntAttr_Status);
1322  if (status != GRB_OPTIMAL ||
1323  model->get(GRB_DoubleAttr_ObjVal) > this->eps)
1324  throw "Game::LCP::LCPasQP: LCP infeasible";
1325  } catch (const char *e) {
1326  cerr << "Error in Game::LCP::LCPasQP: " << e << '\n';
1327  throw;
1328  } catch (string e) {
1329  cerr << "String: Error in Game::LCP::LCPasQP: " << e << '\n';
1330  throw;
1331  } catch (exception &e) {
1332  cerr << "Exception: Error in Game::LCP::LCPasQP: " << e.what() << '\n';
1333  throw;
1334  } catch (GRBException &e) {
1335  cerr << "GRBException: Error in Game::LCP::LCPasQP: " << e.getErrorCode()
1336  << "; " << e.getMessage() << '\n';
1337  throw;
1338  }
1339  }
1340  return model;
1341 }
1342 
1343 unique_ptr<GRBModel> Game::LCP::LCPasMIP(bool solve)
1352 {
1353  return this->LCPasMIP({}, {}, solve);
1354 }
1355 
1356 unique_ptr<GRBModel>
1357 Game::LCP::MPECasMILP(const arma::sp_mat &C, const arma::vec &c,
1358  const arma::vec &x_minus_i, bool solve)
1369 {
1370  unique_ptr<GRBModel> model = this->LCPasMIP(true);
1371  // Reset the solution limit. We need to solve to optimality
1372  model->set(GRB_IntParam_SolutionLimit, GRB_MAXINT);
1373  if (C.n_cols != x_minus_i.n_rows)
1374  throw string("Game::LCP::LCPasMILP: Bad size of x_minus_i");
1375  if (c.n_rows != C.n_rows)
1376  throw string("Game::LCP::LCPasMILP: Bad size of c");
1377  arma::vec Cx(c.n_rows, arma::fill::zeros);
1378  try {
1379  Cx = C * x_minus_i;
1380  } catch (exception &e) {
1381  cerr << "Exception in Game::LCP::MPECasMIQP: " << e.what() << '\n';
1382  throw;
1383  } catch (string &e) {
1384  cerr << "Exception in Game::LCP::MPECasMIQP: " << e << '\n';
1385  throw;
1386  }
1387  arma::vec obj = c + Cx;
1388  GRBLinExpr expr{0};
1389  for (unsigned int i = 0; i < obj.n_rows; i++)
1390  expr += obj.at(i) * model->getVarByName("x_" + to_string(i));
1391  model->setObjective(expr, GRB_MINIMIZE);
1392  model->set(GRB_IntParam_OutputFlag, VERBOSE);
1393  if (solve)
1394  model->optimize();
1395  return model;
1396 }
1397 
1398 unique_ptr<GRBModel>
1399 Game::LCP::MPECasMIQP(const arma::sp_mat &Q, const arma::sp_mat &C,
1400  const arma::vec &c, const arma::vec &x_minus_i,
1401  bool solve)
1412 {
1413  auto model = this->MPECasMILP(C, c, x_minus_i, false);
1417  if (Q.n_nonzero != 0) // If Q is zero, then just solve MIP as opposed to MIQP!
1418  {
1419  GRBLinExpr linexpr = model->getObjective(0);
1420  GRBQuadExpr expr{linexpr};
1421  for (auto it = Q.begin(); it != Q.end(); ++it)
1422  expr += (*it) * model->getVarByName("x_" + to_string(it.row())) *
1423  model->getVarByName("x_" + to_string(it.col()));
1424  model->setObjective(expr, GRB_MINIMIZE);
1425  }
1426  if (solve)
1427  model->optimize();
1428  return model;
1429 }
1430 
1431 void Game::LCP::write(string filename, bool append) const {
1432  ofstream outfile(filename, append ? ios::app : ios::out);
1433 
1434  outfile << nR << " rows and " << nC << " columns in the LCP\n";
1435  outfile << "LeadStart: " << LeadStart << " \nLeadEnd: " << LeadEnd
1436  << " \nnLeader: " << nLeader << "\n\n";
1437 
1438  outfile << "M: " << this->M;
1439  outfile << "q: " << this->q;
1440  outfile << "Complementarity: \n";
1441  for (const auto &p : this->Compl)
1442  outfile << "<" << p.first << ", " << p.second << ">"
1443  << "\t";
1444  outfile << "A: " << this->_A;
1445  outfile << "b: " << this->_b;
1446  outfile.close();
1447 }
1448 
1449 void Game::LCP::save(string filename, bool erase) const {
1450  Utils::appendSave(string("LCP"), filename, erase);
1451  Utils::appendSave(this->M, filename, string("LCP::M"), false);
1452  Utils::appendSave(this->q, filename, string("LCP::q"), false);
1453 
1454  Utils::appendSave(this->LeadStart, filename, string("LCP::LeadStart"), false);
1455  Utils::appendSave(this->LeadEnd, filename, string("LCP::LeadEnd"), false);
1456 
1457  Utils::appendSave(this->_A, filename, string("LCP::_A"), false);
1458  Utils::appendSave(this->_b, filename, string("LCP::_b"), false);
1459 
1460  BOOST_LOG_TRIVIAL(trace) << "Saved LCP to file " << filename;
1461 }
1462 
1463 long int Game::LCP::load(string filename, long int pos) {
1464  if (!this->env)
1465  throw string("Error in LCP::load: To load LCP from file, it has to be "
1466  "constructed using LCP(GRBEnv*) constructor");
1467 
1468  string headercheck;
1469  pos = Utils::appendRead(headercheck, filename, pos);
1470  if (headercheck != "LCP")
1471  throw string("Error in LCP::load: In valid header - ") + headercheck;
1472 
1473  arma::sp_mat M, A;
1474  arma::vec q, b;
1475  unsigned int LeadStart, LeadEnd;
1476  pos = Utils::appendRead(M, filename, pos, string("LCP::M"));
1477  pos = Utils::appendRead(q, filename, pos, string("LCP::q"));
1478  pos = Utils::appendRead(LeadStart, filename, pos, string("LCP::LeadStart"));
1479  pos = Utils::appendRead(LeadEnd, filename, pos, string("LCP::LeadEnd"));
1480  pos = Utils::appendRead(A, filename, pos, string("LCP::_A"));
1481  pos = Utils::appendRead(b, filename, pos, string("LCP::_b"));
1482 
1483  this->M = M;
1484  this->q = q;
1485  this->_A = A;
1486  this->_b = b;
1487  defConst(env);
1488  this->LeadStart = LeadStart;
1489  this->LeadEnd = LeadEnd;
1490 
1491  this->nLeader = this->LeadEnd - this->LeadStart + 1;
1492  this->nLeader = this->nLeader > 0 ? this->nLeader : 0;
1493  for (unsigned int i = 0; i < M.n_rows; i++) {
1494  unsigned int count = i < LeadStart ? i : i + nLeader;
1495  Compl.push_back({i, count});
1496  }
1497  std::sort(Compl.begin(), Compl.end(),
1498  [](std::pair<unsigned int, unsigned int> a,
1499  std::pair<unsigned int, unsigned int> b) {
1500  return a.first <= b.first;
1501  });
1502  this->initializeNotProcessed();
1503  return pos;
1504 }
1505 
1506 std::string Game::LCP::feas_detail_str() const {
1507  std::stringstream ss;
1508  ss << "\tProven feasible: ";
1509  for (auto vv : this->AllPolyhedra)
1510  ss << vv << ' ';
1511  // ss << "\tProven infeasible: ";
1512  // for (auto vv : this->knownInfeas)
1513  // ss << vv << ' ';
1514 
1515  return ss.str();
1516 }
1517 
1518 unsigned int Game::LCP::conv_Npoly() const {
1524  return this->AllPolyhedra.size();
1525 }
1526 
1527 unsigned int Game::LCP::conv_PolyPosition(const unsigned long int i) const {
1532  const unsigned int nPoly = this->conv_Npoly();
1533  if (i > nPoly) {
1534  BOOST_LOG_TRIVIAL(error) << "Error in Game::LCP::conv_PolyPosition: "
1535  "Invalid argument. Out of bounds for i";
1536  throw std::string("Error in Game::LCP::conv_PolyPosition: Invalid "
1537  "argument. Out of bounds for i");
1538  }
1539  const unsigned int nC = this->M.n_cols;
1540  return nC + i * nC;
1541 }
1542 
1543 unsigned int Game::LCP::conv_PolyWt(const unsigned long int i) const {
1552  const unsigned int nPoly = this->conv_Npoly();
1553  if (nPoly <= 1) {
1554  return 0;
1555  }
1556  if (i > nPoly) {
1557  throw std::string("Error in Game::LCP::conv_PolyWt: "
1558  "Invalid argument. Out of bounds for i");
1559  }
1560  const unsigned int nC = this->M.n_cols;
1561 
1562  return nC + nPoly * nC + i;
1563 }
arma::vec c
Definition: games.h:42
std::set< unsigned long int > AllPolyhedra
Decimal encoding of polyhedra that have been enumerated.
Definition: lcptolp.h:65
bool operator>(vector< int > Fix1, vector< int > Fix2)
Definition: LCPtoLP.cpp:56
std::set< unsigned long int > knownInfeas
Decimal encoding of polyhedra known to be infeasible.
Definition: lcptolp.h:69
unsigned int conv_PolyWt(const unsigned long int i) const
Definition: LCPtoLP.cpp:1543
Class to handle parameterized quadratic programs(QP)
Definition: games.h:146
std::set< unsigned long int > feasiblePoly
Decimal encoding of polyhedra that have been enumerated.
Definition: lcptolp.h:67
string to_string(const Game::EPECsolveStatus st)
Definition: Games.cpp:2474
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="")
LCP & EnumerateAll(bool solveLP=true)
Brute force computation of LCP feasible region.
Definition: LCPtoLP.cpp:1237
bool checkPolyFeas(const unsigned long int &decimalEncoding)
Definition: LCPtoLP.cpp:990
long double eps_int
Definition: lcptolp.h:119
GRBModel RlxdModel
Definition: lcptolp.h:76
bool FixToPoly(const std::vector< short int > Fix, bool checkFeas=false, bool custom=false, spmat_Vec *custAi={}, vec_Vec *custbi={})
Computes the equation of the feasibility polyhedron corresponding to the given Fix.
Definition: LCPtoLP.cpp:900
void defConst(GRBEnv *env)
Assign default values to LCP attributes.
Definition: LCPtoLP.cpp:58
unsigned int LeadStart
Definition: lcptolp.h:51
arma::vec LPSolve(const arma::sp_mat &A, const arma::vec &b, const arma::vec &c, int &status, bool Positivity=false)
Definition: LCPtoLP.cpp:721
unsigned long int maxTheoreticalPoly
Definition: lcptolp.h:71
unsigned long int vec_to_num(std::vector< short int > binary)
Definition: Utils.cpp:357
LCP & makeQP(Game::QP_objective &QP_obj, Game::QP_Param &QP)
Definition: LCPtoLP.cpp:1265
struct to handle the constraint params of MP_Param/QP_Param
Definition: games.h:46
void write(std::string filename, bool append=true) const
Definition: LCPtoLP.cpp:1431
arma::sp_mat M
M in that defines the LCP.
Definition: lcptolp.h:48
void compConvSize(arma::sp_mat &A, const unsigned int nFinCons, const unsigned int nFinVar, const std::vector< arma::sp_mat *> *Ai, const std::vector< arma::vec *> *bi, const arma::sp_mat &Acom, const arma::vec &bcom)
bool errorCheck(bool throwErr=true) const
Definition: LCPtoLP.cpp:455
void appendSave(const vec &matrix, const std::string out, const std::string header="", bool erase=false)
Definition: games.h:702
long double eps
The threshold for optimality and feasability tollerances.
Definition: lcptolp.h:117
std::unique_ptr< GRBModel > MPECasMILP(const arma::sp_mat &C, const arma::vec &c, const arma::vec &x_minus_i, bool solve=false)
Helps solving an LCP as an MIP.
Definition: LCPtoLP.cpp:1357
std::vector< std::pair< unsigned int, unsigned int > > perps
Definition: epecsolve.h:15
#define VERBOSE
Definition: epecsolve.h:7
std::vector< std::unique_ptr< arma::sp_mat > > spmat_Vec
Definition: lcptolp.h:42
unsigned int LeadEnd
Definition: lcptolp.h:51
arma::vec q
q in that defines the LCP
Definition: lcptolp.h:49
arma::sp_mat A
Definition: games.h:47
arma::vec _b
Definition: lcptolp.h:53
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
unsigned int ConvexHull(const std::vector< arma::sp_mat *> *Ai, const std::vector< arma::vec *> *bi, arma::sp_mat &A, arma::vec &b, const arma::sp_mat Acom={}, const arma::vec bcom={})
int reverseSequentialPolyCounter
Definition: lcptolp.h:62
GRBEnv * env
Gurobi env.
Definition: lcptolp.h:47
std::unique_ptr< GRBModel > LCPasQP(bool solve=false)
Solves the LCP as a QP using Gurobi.
Definition: LCPtoLP.cpp:1295
long int addPolyMethodSeed
Definition: lcptolp.h:124
std::unique_ptr< vec_Vec > bi
Vector to contain the RHS of inner approx polyhedra.
Definition: lcptolp.h:75
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
bool madeRlxdModel
Keep track if LCP::RlxdModel is made.
Definition: lcptolp.h:56
perps Compl
Compl stores data in <Eqn, Var> form.
Definition: lcptolp.h:50
bool isZero(const T val) const
Definition: lcptolp.h:99
Class to handle and solve linear complementarity problems.
Definition: lcptolp.h:41
unsigned int conv_PolyPosition(const unsigned long int i) const
Definition: LCPtoLP.cpp:1527
unsigned int nR
Definition: lcptolp.h:57
std::unique_ptr< GRBModel > LCPasMIP(std::vector< unsigned int > FixEq={}, std::vector< unsigned int > FixVar={}, bool solve=false)
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
~LCP()
Destructor of LCP.
Definition: LCPtoLP.cpp:174
bool useIndicators
constraints. BigM formulation otherwise
Definition: lcptolp.h:121
std::string feas_detail_str() const
Definition: LCPtoLP.cpp:1506
Adds the next polyhedra by selecting random feasible one.
bool extractSols(GRBModel *model, arma::vec &z, arma::vec &x, bool extractZ=false) const
Extracts variable and equation values from a solved Gurobi model for LCP.
Definition: LCPtoLP.cpp:771
std::vector< short int > solEncode(GRBModel *model) const
Given a Gurobi model, extracts variable values and equation values, encodes it in 0/+1/-1 format and ...
Definition: LCPtoLP.cpp:845
Adds polyhedra by selecting them in order.
std::unique_ptr< spmat_Vec > Ai
Vector to contain the LHS of inner approx polyhedra.
Definition: lcptolp.h:73
LCP()=delete
Class has no default constructors.
LCP & FixToPolies(const std::vector< short int > Fix, bool checkFeas=false, bool custom=false, spmat_Vec *custAi={}, vec_Vec *custbi={})
Computes the equation of the feasibility polyhedron corresponding to the given Fix.
Definition: LCPtoLP.cpp:1061
long int load(std::string filename, long int pos=0)
Definition: LCPtoLP.cpp:1463
arma::vec b
Definition: games.h:48
unsigned int conv_Npoly() const
Definition: LCPtoLP.cpp:1518
unsigned int sequentialPolyCounter
Definition: lcptolp.h:61
void print(std::string end="\)
Print a summary of the LCP.
Definition: LCPtoLP.cpp:478
EPECAddPolyMethod
Definition: epecsolve.h:34
unsigned int ConvexHull(arma::sp_mat &A, arma::vec &b)
Definition: LCPtoLP.cpp:484
struct to handle the objective params of MP_Param/QP_Param
Definition: games.h:39
arma::vec getMCLeadRHS() const
Definition: games.h:363
void makeRelaxed()
Makes a Gurobi object that relaxes complementarity constraints in an LCP.
Definition: LCPtoLP.cpp:180
bool addThePoly(const unsigned long int &decimalEncoding)
Definition: LCPtoLP.cpp:1224
std::unique_ptr< GRBModel > MPECasMIQP(const arma::sp_mat &Q, const arma::sp_mat &C, const arma::vec &c, const arma::vec &x_minus_i, bool solve=false)
Helps solving an LCP as an MIQPs.
Definition: LCPtoLP.cpp:1399
std::vector< std::unique_ptr< arma::vec > > vec_Vec
Definition: lcptolp.h:43
long double bigM
bigM used to rewrite the LCP as MIP
Definition: lcptolp.h:116
unsigned int nLeader
Definition: lcptolp.h:51
unsigned long int getNextPoly(Game::EPECAddPolyMethod method)
Definition: LCPtoLP.cpp:1109
std::unique_ptr< GRBModel > LCP_Polyhed_fixed(std::vector< unsigned int > FixEq={}, std::vector< unsigned int > FixVar={})
void save(std::string filename, bool erase=true) const
Definition: LCPtoLP.cpp:1449
std::set< std::vector< short int > > addAPoly(unsigned long int nPoly=1, Game::EPECAddPolyMethod method=Game::EPECAddPolyMethod::sequential, std::set< std::vector< short int >> Polys={})
Definition: LCPtoLP.cpp:1169
arma::sp_mat B
Definition: games.h:47
Class to model Nash-cournot games with each player playing a QP.
Definition: games.h:249
Definition: utils.h:14
bool operator==(vector< short int > Fix1, vector< short int > Fix2)
Checks if two vector<int> are of same size and hold same values in the same order.
Definition: LCPtoLP.cpp:17
unsigned int feasiblePolyhedra
Definition: lcptolp.h:60
arma::sp_mat _A
Definition: lcptolp.h:52
void initializeNotProcessed()
Definition: lcptolp.h:82
LCP & addPolyFromX(const arma::vec &x, bool &ret)
Definition: LCPtoLP.cpp:859
std::vector< short int > num_to_vec(unsigned long int number, const unsigned int &nCompl)
Definition: Utils.cpp:369
unsigned int nC
Definition: lcptolp.h:57