Program Listing for File epec.cpp
↰ Return to documentation for file (src/shells/epec.cpp
)
/* #############################################
* This file is part of
* ZERO
*
* Copyright (c) 2020
* Released under the Creative Commons
* CC BY-NC-SA 4.0 License
*
* Find out more at
* https://github.com/ds4dm/ZERO
* #############################################*/
#include "boost/program_options.hpp"
#include "zero.h"
using namespace std;
namespace po = boost::program_options;
int main(int argc, char **argv) {
string resFile, instanceFile, logFile;
int writeLevel = 0, nThreads = 0, verbosity = 0, algorithm = 0, aggressiveness = 0, add{0},
recover = 0, branching = 0;
double timeLimit = NAN, boundBigM = NAN, devtol = NAN;
bool bound = false, pure = false;
po::options_description desc("ZERO-EPEC: Allowed options");
desc.add_options()(
"help,h", "Shows this help message")("version,v",
"Shows ZERO version")("input,i",
po::value<string>(&instanceFile),
"Sets the input path/filename of "
"the instance file (.json "
"appended "
"automatically)")("pure,p",
po::value<bool>(
&pure)
->default_value(
false),
"Controls "
"whether the "
"Algorithm "
"should "
"seek for a "
"pure NE or "
"not. If "
"Algorithm is "
"CombinatorialPN"
"E, this is "
"automatically "
"true.")("recove"
"r,r",
po::value<
int>(
&recover)
->default_value(
0),
"If "
"InnerA"
"pproxi"
"mati"
"on is "
"used "
"along "
"with "
"PureNa"
"shEqui"
"libr"
"ium, "
"which "
"strate"
"gy "
"should"
" "
"be "
"used "
"to "
"retrie"
"ve a "
"pure "
"NE. "
"0: "
"Increm"
"entalE"
"nume"
"ration"
", "
"1:"
"Combin"
"atoria"
"lPN"
"E")("A"
"l"
"g"
"o"
"r"
"i"
"t"
"h"
"m"
","
"a",
po::value<
int>(
&algorithm),
"S"
"e"
"t"
"s"
" "
"t"
"h"
"e"
" "
"A"
"l"
"g"
"o"
"r"
"i"
"t"
"h"
"m"
"."
" "
"0"
":"
"F"
"u"
"l"
"l"
"E"
"n"
"u"
"m"
"e"
"r"
"a"
"t"
"i"
"o"
"n"
","
" "
"1"
":"
"I"
"n"
"n"
"e"
"r"
"A"
"p"
"p"
"r"
"o"
"x"
"i"
"m"
"a"
"t"
"i"
"o"
"n"
","
" "
"2"
":"
"C"
"o"
"m"
"b"
"i"
"n"
"a"
"t"
"o"
"r"
"i"
"a"
"l"
"P"
"N"
"E"
","
" "
"3"
":"
"O"
"u"
"t"
"e"
"r"
"A"
"p"
"p"
"r"
"o"
"x"
"i"
"m"
"a"
"t"
"i"
"o"
"n")("solution,s",
po::value<
string>(
&resFile)
->default_value(
"dat/Solution"),
"Sets the output path/filename of the solution file (.json appended "
"automatically)")("log,l",
po::value<
string>(
&logFile)
->default_value(
"dat/Results.csv"),
"Sets the output path/filename of the csv log file")("timelimit,tl",
po::value<
double>(
&timeLimit)
->default_value(
-1.0),
"Sets the timelimit for solving the Nash Equilibrium model")("writelevel,w",
po::value<
int>(
&writeLevel)
->default_value(
0),
"Sets the writeLevel param. 0: only Json. 1: only human-readable. 2: "
"both")("message,m",
po::value<
int>(
&verbosity)
->default_value(
0),
"Sets the verbosity level for info and warning messages. 0: "
"warning and critical. 1: info. 2: debug. 3: trace")("Threads,t",
po::value<
int>(
&nThreads)
->default_value(
1),
"Sets the number of Threads for Gurobi. (int): number of Threads. 0: "
"auto (number of processors)")("aggr,ag",
po::value<
int>(
&aggressiveness)
->default_value(
1),
"Sets the Aggressiveness for the InnerApproximation, namely the number "
"of Random polyhedra added if no deviation is found. (int)")("bound,bo",
po::value<
bool>(
&bound)
->default_value(
false),
"Decides whether primal variables should be bounded or not.")("devtol,dt",
po::value<
double>(
&devtol)
->default_value(
-1.0),
"Sets the deviation tolerance.")("BoundBigM,bbm",
po::value<
double>(
&boundBigM)
->default_value(
1e5),
"Set the bounding BigM related to the parameter --bound")("add,ad",
po::
value<
int>(
&add)
->default_value(0),
"Sets the Game::EPECAddPolyMethod for the InnerApproximation. 0: "
"Sequential. "
"1: ReverseSequential. 2:Random.")("branching,br",
po::value<
int>(
&branching)
->default_value(
0),
"Sets the Branching Strategy for the CutAndPlay. 0: "
"Hybrid. "
"1: Deviation.");
po::variables_map vm;
po::store(po::parse_command_line(argc, argv, desc), vm);
po::store(po::command_line_parser(argc, argv).options(desc).run(), vm);
po::notify(vm);
if (vm.count("help")) {
cout << desc;
return EXIT_SUCCESS;
}
if (vm.count("version") || verbosity >= 2) {
string M, m, p;
ZEROVersion(M, m, p);
LOG_S(INFO) << "ZERO Version: " << M << "." << m << "." << p;
if (vm.count("version"))
return EXIT_SUCCESS;
}
if (instanceFile.empty()) {
cout << "-i [--input] option missing.\n Use with --help for help on list "
"of arguments\n";
return EXIT_SUCCESS;
}
loguru::g_stderr_verbosity = verbosity;
// --------------------------------
// LOADING INSTANCE
// --------------------------------
Models::EPEC::EPECInstance instance(instanceFile);
if (instance.Countries.empty()) {
cerr << "Error: instance is empty\n";
return 1;
}
// --------------------------------
// TEST STARTS
// --------------------------------
auto timeStart = std::chrono::high_resolution_clock::now();
try {
GRBEnv env = GRBEnv();
//As to have consistency among results
env.set(GRB_IntParam_Seed,420);
// OPTIONS
//------------
Models::EPEC::EPEC epec(&env);
// Num Threads
if (nThreads != 0)
epec.setNumThreads(nThreads);
// Pure NE
if (pure)
epec.setPureNashEquilibrium(true);
// TimeLimit
epec.setTimeLimit(timeLimit);
// bound QPs
if (devtol > 0)
epec.setDeviationTolerance(devtol);
// Algorithm
switch (algorithm) {
case 1: {
epec.setAlgorithm(Data::EPEC::Algorithms::InnerApproximation);
if (aggressiveness != 1)
epec.setAggressiveness(aggressiveness);
switch (add) {
case 1:
epec.setAddPolyMethod(Data::LCP::PolyhedraStrategy::ReverseSequential);
break;
case 2:
epec.setAddPolyMethod(Data::LCP::PolyhedraStrategy::Random);
break;
default:
epec.setAddPolyMethod(Data::LCP::PolyhedraStrategy::Sequential);
}
if (recover != 0)
epec.setRecoverStrategy(Data::EPEC::RecoverStrategy::Combinatorial);
break;
}
case 2: {
epec.setAlgorithm(Data::EPEC::Algorithms::CombinatorialPne);
break;
}
case 3: {
epec.setAlgorithm(Data::EPEC::Algorithms::OuterApproximation);
switch (branching) {
case 0:
epec.setBranchingStrategy(Data::EPEC::BranchingStrategy::HybridBranching);
break;
default:
epec.setBranchingStrategy(Data::EPEC::BranchingStrategy::DeviationBranching);
}
break;
}
default:
epec.setAlgorithm(Data::EPEC::Algorithms::FullEnumeration);
}
//------------
for (auto &Countrie : instance.Countries)
epec.addCountry(Countrie);
epec.addTranspCosts(instance.TransportationCosts);
epec.finalize();
epec.findNashEq();
auto timeStop = std::chrono::high_resolution_clock::now();
std::chrono::duration<double> timeDiff = timeStop - timeStart;
double wallClockTime = timeDiff.count();
int realThreads = nThreads > 0 ? env.get(GRB_IntParam_Threads) : nThreads;
// --------------------------------
// WRITING STATISTICS AND SOLUTION
// --------------------------------
auto stat = epec.getStatistics();
if (stat.Status.get() == ZEROStatus::NashEqFound)
epec.writeSolution(writeLevel, resFile);
ifstream existCheck(logFile);
std::ofstream results(logFile, ios::app);
if (!existCheck.good()) {
results << "instance;Algorithm;Countries;Followers;isPureNE;RequiredPureNE;"
"Status;"
"numFeasiblePolyhedra/Complementarities;"
"NumVar;NumConstraints;NumNonZero;ClockTime"
"(s);Threads;numInnerIterations;LostIntermediateEq;"
"Aggressiveness;"
"AddPolyMethod;NumericalIssues;"
"recoveryStrategy;branchingStrategy\n";
}
existCheck.close();
std::stringstream polyT;
std::vector<unsigned int> target;
if (stat.AlgorithmData.Algorithm.get() != Data::EPEC::Algorithms::OuterApproximation)
target = stat.AlgorithmData.FeasiblePolyhedra.get();
else
target = stat.AlgorithmData.OuterComplementarities.get();
copy(target.begin(), target.end(), ostream_iterator<int>(polyT, " "));
auto test2 = polyT.str();
results << instanceFile << ";" << to_string(stat.AlgorithmData.Algorithm.get()) << ";"
<< instance.Countries.size() << ";[";
for (auto &countrie : instance.Countries)
results << " " << countrie.n_followers;
results << " ];" << to_string(epec.getStatistics().PureNashEquilibrium.get()) << ";"
<< to_string(pure) << ";" << to_string(stat.Status.get()) << ";[ " << polyT.str()
<< "];" << stat.NumVar.get() << ";" << stat.NumConstraints.get() << ";"
<< stat.NumNonZero.get() << ";" << wallClockTime << ";" << realThreads;
if (stat.AlgorithmData.Algorithm.get() == Data::EPEC::Algorithms::InnerApproximation) {
results << ";" << stat.NumIterations.get() << ";"
<< epec.getStatistics().AlgorithmData.LostIntermediateEq.get() << ";"
<< stat.AlgorithmData.Aggressiveness.get() << ";"
<< to_string(stat.AlgorithmData.PolyhedraStrategy.get()) << ";"
<< stat.NumericalIssues.get() << ";"
<< to_string(stat.AlgorithmData.RecoverStrategy.get()) << ";-";
} else {
results << ";-;-;-;-;-;-;" << std::to_string(stat.AlgorithmData.BranchingStrategy.get());
}
results << "\n";
results.close();
} catch (ZEROException &e) {
std::cerr << "" << e.what() << "--" << e.more();
throw ZEROException(e);
} catch (GRBException &e) {
std::cerr << "" << e.getErrorCode() << "--" << e.getMessage();
throw;
}
return EXIT_SUCCESS;
}