Program Listing for File epec_polybase.cpp

Return to documentation for file (src/games/algorithms/EPEC/epec_polybase.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 "games/algorithms/EPEC/epec_polybase.h"


bool Algorithms::EPEC::PolyBase::isSolved(unsigned int *player,
                                                        arma::vec *   profitableDeviation,
                                                        double        tol) const

{

  if (!this->EPECObject->NashEquilibrium)
     return false;
  tol = this->EPECObject->Stats.AlgorithmData.DeviationTolerance.get();
  if (tol < 0)
     tol = 1e-5;
  this->EPECObject->TheNashGame->isSolved(
        this->EPECObject->SolutionX, *player, *profitableDeviation, tol);
  arma::vec objvals =
        this->EPECObject->TheNashGame->computeQPObjectiveValues(this->EPECObject->SolutionX, true);
  for (unsigned int i = 0; i < this->EPECObject->NumPlayers; ++i) {
     double val =
          this->EPECObject->bestResponse(*profitableDeviation, i, this->EPECObject->SolutionX);
     if (val == GRB_INFINITY)
        return false;
     if (!Utils::isEqual(val, objvals.at(i), tol, 1 - tol)) {
        *player = i;
        LOG_S(0) << "Algorithms::EPEC::PolyBase::isSolved: deviation for player " << i << " -- of "
                    << std::abs(val - objvals.at(i));
        return false;
     }
  }
  return true;
}

bool Algorithms::EPEC::PolyBase::isSolved(double tol) {
  unsigned int countryNumber;
  arma::vec    ProfDevn;
  bool         ret = this->isSolved(&countryNumber, &ProfDevn, tol);
  return ret;
}

unsigned int Algorithms::EPEC::PolyBase::getPositionLeadFollPoly(const unsigned int i,
                                                                                      const unsigned int j,
                                                                                      const unsigned int k) const {
  const auto LeaderStart = this->EPECObject->TheNashGame->getPrimalLoc(i);
  const auto FollPoly    = this->PolyLCP.at(i).get()->convPolyPosition(k, true);
  return LeaderStart + FollPoly + j;
}


unsigned int Algorithms::EPEC::PolyBase::getPositionLeadLeadPoly(const unsigned int i,
                                                                                      const unsigned int j,
                                                                                      const unsigned int k) const {
  const auto LeaderStart = this->EPECObject->TheNashGame->getPrimalLoc(i);
  const auto FollPoly    = this->PolyLCP.at(i).get()->convPolyPosition(k, true);
  return LeaderStart + FollPoly + this->PolyLCP.at(i)->getLStart() + j;
}


unsigned long int Algorithms::EPEC::PolyBase::getNumPolyLead(const unsigned int i) const {
  return this->PolyLCP.at(i).get()->convNumPoly(true);
}


unsigned int Algorithms::EPEC::PolyBase::getPositionProbab(const unsigned int i,
                                                                              const unsigned int k) const {
  const auto PolyProbab = dynamic_cast<MathOpt::PolyLCP *>(this->EPECObject->PlayersLCP.at(i).get())
                                        ->convPolyWeight(k, true);
  if (PolyProbab == 0)
     return 0;
  const auto LeaderStart = this->EPECObject->TheNashGame->getPrimalLoc(i);
  return LeaderStart + PolyProbab;
}

bool Algorithms::EPEC::PolyBase::isPureStrategy(const double tol) const {
  for (unsigned int i = 0; i < this->EPECObject->getNumPlayers(); ++i) {
     if (!isPureStrategy(i, tol))
        return false;
  }
  return true;
}


bool Algorithms::EPEC::PolyBase::isPureStrategy(const unsigned int i, const double tol) const {
  const unsigned int nPoly = this->getNumPolyLead(i);
  for (unsigned int j = 0; j < nPoly; j++) {
     const double probab = this->getValProbab(i, j);
     if (probab > 1 - tol) // Current Strategy is a pure strategy!
        return true;
  }
  return false;
}

std::vector<unsigned int> Algorithms::EPEC::PolyBase::mixedStrategyPoly(const unsigned int i,
                                                                                                const double tol) const {
  std::vector<unsigned int> polys{};
  const unsigned int        nPoly = this->getNumPolyLead(i);
  for (unsigned int j = 0; j < nPoly; j++) {
     const double probab = this->getValProbab(i, j);
     if (probab > tol)
        polys.push_back(j);
  }
  std::cout << "\n";
  return polys;
}


double Algorithms::EPEC::PolyBase::getValProbab(const unsigned int i, const unsigned int k) const {
  const unsigned int varname{this->getPositionProbab(i, k)};
  if (varname == 0)
     return 1;
  return this->EPECObject->SolutionX.at(varname);
}



double Algorithms::EPEC::PolyBase::getValLeadFollPoly(const unsigned int i,
                                                                        const unsigned int j,
                                                                        const unsigned int k,
                                                                        const double       tol) const {
  if (!this->EPECObject->LCPModel)
     throw ZEROException(ZEROErrorCode::Assertion, "LCPModel not made nor solved");
  const double probab = this->getValProbab(i, k);
  if (probab > 1 - tol)
     return this->EPECObject->getValLeadFoll(i, j);
  else
     return this->EPECObject->SolutionX.at(this->getPositionLeadFollPoly(i, j, k)) / probab;
}



double Algorithms::EPEC::PolyBase::getValLeadLeadPoly(const unsigned int i,
                                                                        const unsigned int j,
                                                                        const unsigned int k,
                                                                        const double       tol) const {
  if (!this->EPECObject->LCPModel)
     throw ZEROException(ZEROErrorCode::Assertion, "LCPModel not made nor solved");
  const double probab = this->getValProbab(i, k);
  if (probab > 1 - tol)
     return this->EPECObject->getValLeadLead(i, j);
  else
     return this->EPECObject->SolutionX.at(this->getPositionLeadLeadPoly(i, j, k)) / probab;
}


void Algorithms::EPEC::PolyBase::makeThePureLCP() {
  try {
     LOG_S(1) << "Game::EPEC::makeThePureLCP: editing the LCP model.";
     this->EPECObject->LCPModelBase =
          std::unique_ptr<GRBModel>(new GRBModel(*this->EPECObject->LCPModel));
     const unsigned int nPolyLead = [this]() {
        unsigned int ell = 0;
        for (unsigned int i = 0; i < this->EPECObject->getNumPlayers(); ++i)
          ell += (this->getNumPolyLead(i));
        return ell;
     }();

     // Add a binary variable for each polyhedron of each leader
     GRBVar       pure_bin[nPolyLead];
     GRBLinExpr   objectiveTerm{0};
     unsigned int count{0}, i, j;
     for (i = 0; i < this->EPECObject->getNumPlayers(); i++) {
        for (j = 0; j < this->getNumPolyLead(i); ++j) {
          pure_bin[count] = this->EPECObject->LCPModel->addVar(
                0, 1, 0, GRB_BINARY, "pureBin_" + std::to_string(i) + "_" + std::to_string(j));
          this->EPECObject->LCPModel->addGenConstrIndicator(
                pure_bin[count],
                1,
                this->EPECObject->LCPModel->getVarByName("x_" +
                                                                      std::to_string(this->getPositionProbab(i, j))),
                GRB_EQUAL,
                0,
                "Indicator_PNE_" + std::to_string(count));
          objectiveTerm += pure_bin[count];
          count++;
        }
     }
     this->EPECObject->LCPModel->setObjective(objectiveTerm, GRB_MAXIMIZE);
  } catch (GRBException &e) {
     throw ZEROException(ZEROErrorCode::SolverError,
                                std::to_string(e.getErrorCode()) + e.getMessage());
  }
}