EPEC solve
Solving Equilibrium Problems with Equilibrium Constraints (EPECs)
src/EPEC.cpp
Go to the documentation of this file.
1 #include "models.h"
2 #include <boost/log/core.hpp>
3 #include <boost/log/expressions.hpp>
4 #include <boost/log/trivial.hpp>
5 #include <boost/program_options.hpp>
6 #include <chrono>
7 #include <cstdlib>
8 #include <gurobi_c++.h>
9 #include <iostream>
10 #include <iterator>
11 
12 using namespace std;
13 namespace logging = boost::log;
14 using namespace boost::program_options;
15 namespace po = boost::program_options;
16 
17 int main(int argc, char **argv) {
18  string resFile, instanceFile = "", logFile;
19  int writeLevel, nThreads, verbosity, bigM, algorithm, aggressiveness, add{0},
20  recover;
21  double timeLimit, boundBigM;
22  bool bound, pure;
23 
24  po::options_description desc("EPEC: Allowed options");
25  desc.add_options()("help,h", "Shows this help message")("version,v",
26  "Shows EPEC version")(
27  "input,i", po::value<string>(&instanceFile),
28  "Sets the input path/filename of the instance file (.json appended "
29  "automatically)")(
30  "pure,p", po::value<bool>(&pure)->default_value(false),
31  "Controls whether the algorithm should seek for a pure NE or not. If "
32  "algorithm is combinatorialPNE, this is automatically true.")(
33  "recover,r", po::value<int>(&recover)->default_value(0),
34  "If innerApproximation is used along with pureNE, which strategy should "
35  "be used to retrive a pure NE. 0: incrementalEnumeration, "
36  "1:combinatorialPNE")("algorithm,a", po::value<int>(&algorithm),
37  "Sets the algorithm. 0: fullEnumeration, "
38  "1:innerApproximation, 2:combinatorialPNE")(
39  "solution,s", po::value<string>(&resFile)->default_value("dat/Solution"),
40  "Sets the output path/filename of the solution file (.json appended "
41  "automatically)")(
42  "log,l", po::value<string>(&logFile)->default_value("dat/Results.csv"),
43  "Sets the output path/filename of the csv log file")(
44  "timelimit,tl", po::value<double>(&timeLimit)->default_value(-1.0),
45  "Sets the timelimit for solving the Nash Equilibrium model")(
46  "writelevel,w", po::value<int>(&writeLevel)->default_value(0),
47  "Sets the writeLevel param. 0: only Json. 1: only human-readable. 2: "
48  "both")("message,m", po::value<int>(&verbosity)->default_value(0),
49  "Sets the verbosity level for info and warning messages. 0: "
50  "warning and critical. 1: info. 2: debug. 3: trace")(
51  "bigM", po::value<int>(&bigM)->default_value(0),
52  "Replaces indicator constraints with bigM.")(
53  "threads,t", po::value<int>(&nThreads)->default_value(1),
54  "Sets the number of Threads for Gurobi. (int): number of threads. 0: "
55  "auto (number of processors)")(
56  "aggr,ag", po::value<int>(&aggressiveness)->default_value(1),
57  "Sets the aggressiveness for the innerApproximation, namely the number "
58  "of random polyhedra added if no deviation is found. (int)")(
59  "bound,bo", po::value<bool>(&bound)->default_value(false),
60  "Decides whether primal variables should be bounded or not.")(
61  "boundBigM,bbm", po::value<double>(&boundBigM)->default_value(1e5),
62  "Set the bounding bigM related to the parameter --bound")(
63  "add,ad", po::value<int>(&add)->default_value(0),
64  "Sets the EPECAddPolyMethod for the innerApproximation. 0: sequential. "
65  "1: reverse_sequential. 2:random.");
66 
67  po::variables_map vm;
68  po::store(po::parse_command_line(argc, argv, desc), vm);
69  po::store(po::command_line_parser(argc, argv).options(desc).run(), vm);
70  po::notify(vm);
71 
72  if (vm.count("help")) {
73  cout << desc;
74  return EXIT_SUCCESS;
75  }
76  if (instanceFile == "") {
77  cout << "-i [--input] option missing.\n Use with --help for help on list "
78  "of arguments\n";
79  return EXIT_SUCCESS;
80  }
81  switch (verbosity) {
82  case 0:
83  logging::core::get()->set_filter(logging::trivial::severity >
84  logging::trivial::info);
85  break;
86  case 1:
87  logging::core::get()->set_filter(logging::trivial::severity >=
88  logging::trivial::info);
89  break;
90  case 2:
91  logging::core::get()->set_filter(logging::trivial::severity >=
92  logging::trivial::debug);
93  break;
94  case 3:
95  logging::core::get()->set_filter(logging::trivial::severity >=
96  logging::trivial::trace);
97  break;
98  default:
99  BOOST_LOG_TRIVIAL(warning)
100  << "Invalid option for --message (-m). Setting default value: 0";
101  verbosity = 0;
102  logging::core::get()->set_filter(logging::trivial::severity >
103  logging::trivial::info);
104  break;
105  }
106  if (verbosity >= 2) {
107  arma::arma_version ver;
108  int major, minor, technical;
109  GRBversion(&major, &minor, &technical);
110  BOOST_LOG_TRIVIAL(info) << "Dependencies:";
111  BOOST_LOG_TRIVIAL(info) << "\tARMAdillo: " << ver.as_string();
112  BOOST_LOG_TRIVIAL(info)
113  << "\tGurobi: " << to_string(major) << "." << to_string(minor);
114  BOOST_LOG_TRIVIAL(info) << "\tBoost: " << to_string(BOOST_VERSION / 100000)
115  << "." << to_string(BOOST_VERSION / 100 % 1000);
116  }
117  // --------------------------------
118  // LOADING INSTANCE
119  // --------------------------------
120  Models::EPECInstance Instance(instanceFile);
121  if (Instance.Countries.empty()) {
122  cerr << "Error: instance is empty\n";
123  return 1;
124  }
125 
126  // --------------------------------
127  // TEST STARTS
128  // --------------------------------
129  auto time_start = std::chrono::high_resolution_clock::now();
130  GRBEnv env = GRBEnv();
131 
132  // OPTIONS
133  //------------
134  Models::EPEC epec(&env);
135  // Indicator constraints
136  if (bigM == 1)
137  epec.setIndicators(false);
138  // Num Threads
139  if (nThreads != 0)
140  epec.setNumThreads(nThreads);
141  // Pure NE
142  if (pure)
143  epec.setPureNE(true);
144  // timeLimit
145  epec.setTimeLimit(timeLimit);
146  // bound QPs
147  if (bound) {
148  epec.setBoundPrimals(true);
149  epec.setBoundBigM(boundBigM);
150  }
151 
152  // Algorithm
153 
154  switch (algorithm) {
155  case 1: {
157  if (aggressiveness != 1)
158  epec.setAggressiveness(aggressiveness);
159  switch (add) {
160  case 1:
161  epec.setAddPolyMethod(EPECAddPolyMethod::reverse_sequential);
162  break;
163  case 2:
164  epec.setAddPolyMethod(EPECAddPolyMethod::random);
165  break;
166  default:
167  epec.setAddPolyMethod(EPECAddPolyMethod::sequential);
168  }
169  if (recover != 0)
170  epec.setRecoverStrategy(EPECRecoverStrategy::combinatorial);
171  break;
172  }
173  case 2: {
175  break;
176  }
177  default:
179  }
180 
181  //------------
182 
183  for (unsigned int j = 0; j < Instance.Countries.size(); ++j)
184  epec.addCountry(Instance.Countries.at(j));
185  epec.addTranspCosts(Instance.TransportationCosts);
186  epec.finalize();
187  // epec.make_country_QP();
188  try {
189  epec.findNashEq();
190  } catch (string &s) {
191  std::cerr << "Error while finding Nash equilibrium: " << s << '\n';
192  ;
193  } catch (exception &e) {
194  std::cerr << "Error while finding Nash equilibrium: " << e.what() << '\n';
195  ;
196  }
197  auto time_stop = std::chrono::high_resolution_clock::now();
198  std::chrono::duration<double> time_diff = time_stop - time_start;
199  double WallClockTime = time_diff.count();
200  int realThreads = nThreads > 0 ? env.get(GRB_IntParam_Threads) : nThreads;
201 
202  // --------------------------------
203  // WRITING STATISTICS AND SOLUTION
204  // --------------------------------
205  Game::EPECStatistics stat = epec.getStatistics();
207  epec.writeSolution(writeLevel, resFile);
208  ifstream existCheck(logFile);
209  std::ofstream results(logFile, ios::app);
210 
211  if (!existCheck.good()) {
212  results << "Instance;Algorithm;Countries;Followers;isPureNE;RequiredPureNE;"
213  "Status;"
214  "numFeasiblePolyhedra;"
215  "numVar;numConstraints;numNonZero;ClockTime"
216  "(s);Threads;Indicators;numInnerIterations;lostIntermediateEq;"
217  "Aggressiveness;"
218  "AddPolyMethod;numericalIssuesEncountered;bound;boundBigM;"
219  "recoveryStrategy\n";
220  }
221  existCheck.close();
222 
223  stringstream PolyT;
224  copy(stat.feasiblePolyhedra.begin(), stat.feasiblePolyhedra.end(),
225  ostream_iterator<int>(PolyT, " "));
226 
227  results << instanceFile << ";" << to_string(epec.getAlgorithm()) << ";"
228  << Instance.Countries.size() << ";[";
229  for (auto &Countrie : Instance.Countries)
230  results << " " << Countrie.n_followers;
231 
232  results << " ];" << to_string(epec.getStatistics().pureNE) << ";"
233  << to_string(pure) << ";" << to_string(stat.status) << ";[ "
234  << PolyT.str() << "];" << stat.numVar << ";" << stat.numConstraints
235  << ";" << stat.numNonZero << ";" << WallClockTime << ";"
236  << realThreads << ";" << to_string(epec.getIndicators());
238  results << ";" << epec.getStatistics().numIteration << ";"
239  << epec.getStatistics().lostIntermediateEq << ";"
240  << epec.getAggressiveness() << ";"
241  << to_string(epec.getAddPolyMethod()) << ";"
243  << to_string(epec.getBoundPrimals()) << ";" << epec.getBoundBigM()
244  << ";" << to_string(epec.getRecoverStrategy());
245  } else {
246  results << ";-;-;-;-;-;-;-;-";
247  }
248  results << "\n";
249  results.close();
250 
251  return EXIT_SUCCESS;
252 }
bool pureNE
True if the equilibrium is a pure NE.
Definition: games.h:468
std::vector< unsigned int > feasiblePolyhedra
Definition: games.h:464
void setAggressiveness(unsigned int a)
Definition: games.h:608
string to_string(const Game::EPECsolveStatus st)
Definition: Games.cpp:2474
void setBoundBigM(double val)
Definition: games.h:637
bool getBoundPrimals() const
Definition: games.h:634
int main(int argc, char **argv)
Definition: src/EPEC.cpp:17
void writeSolution(const int writeLevel, std::string filename) const
Definition: Models.cpp:1237
int lostIntermediateEq
Definition: games.h:459
std::vector< Models::LeadAllPar > Countries
LeadAllPar vector.
Definition: models.h:114
void setIndicators(bool val)
Definition: games.h:627
int numNonZero
matrix of findNashEq model
Definition: games.h:457
void findNashEq()
Definition: Games.cpp:2182
bool getIndicators() const
Definition: games.h:628
Definition: games.h:702
int numVar
Number of variables in findNashEq model.
Definition: games.h:453
void finalize()
Finalizes the creation of a Game::EPEC object.
Definition: Games.cpp:1226
void setNumThreads(unsigned int t)
Definition: games.h:614
Stores statistics for a (solved) EPEC instance.
Definition: games.h:451
Game::EPECsolveStatus status
Definition: games.h:452
void setTimeLimit(double val)
Definition: games.h:639
Game::EPECalgorithm getAlgorithm() const
Definition: games.h:601
arma::sp_mat TransportationCosts
Transportation costs matrix.
Definition: models.h:115
void setAddPolyMethod(Game::EPECAddPolyMethod add)
Definition: games.h:641
Stores a single Instance.
Definition: models.h:113
Solution found for the instance.
unsigned int getAggressiveness() const
Definition: games.h:611
void setRecoverStrategy(Game::EPECRecoverStrategy strategy)
Definition: Games.cpp:2282
EPEC & addTranspCosts(const arma::sp_mat &costs)
Adds intercountry transportation costs matrix.
Definition: Models.cpp:639
double getBoundBigM() const
Definition: games.h:638
Game::EPECRecoverStrategy getRecoverStrategy() const
Definition: games.h:605
bool numericalIssuesEncountered
Definition: games.h:461
Time limit reached, nash equilibrium not found.
void setBoundPrimals(bool val)
Definition: games.h:631
void setPureNE(bool val)
Definition: games.h:629
int numConstraints
Number of constraints in findNashEq model.
Definition: games.h:456
Game::EPECAddPolyMethod getAddPolyMethod() const
Definition: games.h:644
EPEC & addCountry(LeadAllPar Params, const unsigned int addnlLeadVars=0)
Models a Standard Nash-Cournot game within a country
Definition: Models.cpp:445
void setAlgorithm(Game::EPECalgorithm algorithm)
Definition: Games.cpp:2274
const EPECStatistics getStatistics() const
Get the EPECStatistics object for the current instance.
Definition: games.h:599