Program Listing for File epec_cutandplay.h

Return to documentation for file (include/games/algorithms/EPEC/epec_cutandplay.h)

/* #############################################
 *             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
 * #############################################*/


#pragma once

#include "epec_polybase.h"
#include "zero.h"
#include <armadillo>
#include <gurobi_c++.h>
#include <iostream>
#include <memory>
#include <set>
#include <string>

namespace Algorithms::EPEC {

  class OuterTree {
  public:
     friend Algorithms::EPEC::CutAndPlay;
     struct Node {
     public:
        friend class OuterTree;

        explicit Node(unsigned int encSize);

        Node(Node &parent, unsigned int idComp, unsigned long int id);
        Node(Node &parent, std::vector<int> idComps, unsigned long int id);

        inline unsigned long int getCumulativeBranches() const {
          return std::count(this->AllowedBranchings.begin(), this->AllowedBranchings.end(), false);
        }

        inline std::vector<bool> getEncoding() const {
          return this->Encoding;
        }

        inline std::vector<bool> getAllowedBranchings() const {
          return this->AllowedBranchings;
        }


     private:
        std::vector<unsigned int> IdComps;
        std::vector<bool> Encoding;

        std::vector<bool> AllowedBranchings;
        unsigned long int Id;
        Node *            Parent{};
     };

  private:
     Node         Root         = Node(0);
     unsigned int EncodingSize = 0;
     unsigned int NodeCounter = 1;

     std::vector<Node> Nodes{};
     bool isPure{false};
     bool isFeasible{
          false};

     unsigned int nextIdentifier() {
        this->NodeCounter++;
        return (this->NodeCounter - 1);
     }

  protected:
     std::unique_ptr<GRBModel> MembershipLP;
     std::unique_ptr<MathOpt::PolyLCP> OriginalLCP;

     arma::sp_mat V{};
     arma::sp_mat R{};
     unsigned int VertexCounter  = 0;
     unsigned int RayCounter     = 0;
     bool         containsOrigin = false;

  public:
     OuterTree(unsigned int encSize, GRBEnv *env) : MembershipLP(new GRBModel(*env)) {
        this->Root         = Node(encSize);
        this->EncodingSize = encSize;
        this->Nodes.push_back(this->Root);
     }


     inline void resetFeasibility() {
        this->isPure     = false;
        this->isFeasible = false;
     }

     inline bool getPure() const { return this->isPure; }

     inline void setFeasible() {
        this->isFeasible = true;
     }

     inline void setPure() { this->isPure = true; }

     inline unsigned int getEncodingSize() const {
        return this->EncodingSize;
     }

     inline const arma::sp_mat *getV() { return &this->V; }

     inline const arma::sp_mat *getR() { return &this->R; }

     inline unsigned int getVertexCount() const {
        return this->VertexCounter;
     }
     inline unsigned int getRayCount() const {
        return this->RayCounter;
     }



     inline bool addVertex(const arma::vec &vertex, bool checkDuplicates);

     inline void addRay(const arma::vec &ray);

     inline Node *getRoot() { return &this->Root; }

     inline std::vector<Node> *getNodes() { return &this->Nodes; };

     void denyBranchingLocation(Node &node, const unsigned int &location) const;

     std::vector<long int> singleBranch(unsigned int idComp, Node &t);
  };

  class CutAndPlay : public PolyBase {

  public:
     explicit CutAndPlay(GRBEnv *env, Game::EPEC *EPECObject) : PolyBase(env, EPECObject){};
     CutAndPlay() = delete;
     double getTol() const {
        return this->Tolerance;
     }
     void setTol(double tol) { this->Tolerance = tol; }

     void        solve() override;
     void        printCurrentApprox();
     static void printBranchingLog(std::vector<int> vector);

     bool isSolved(double tol = 1e-4) override;
     bool isFeasible(bool &addedCuts);
     bool isPureStrategy(double tol = 1e-4) const;


  private:
     std::vector<OuterTree *>       Trees;
     std::vector<OuterTree::Node *> Incumbent;
     bool                           Feasible{false};
     double Tolerance = 3 * 1e-5;

     std::vector<int> getNextBranchLocation(unsigned int player, OuterTree::Node *node);
     int              getFirstBranchLocation(const unsigned int player, OuterTree::Node *node);

  protected:
     void after();

     void                      updateMembership(const unsigned int &player, const arma::vec &xOfI);
     int                       hybridBranching(unsigned int player, OuterTree::Node *node);
     int                       infeasibleBranching(unsigned int player, const OuterTree::Node *node);
     int                       deviationBranching(unsigned int player, const OuterTree::Node *node);
     std::unique_ptr<GRBModel> getFeasibilityQP(const unsigned int player, const arma::vec &x);
     void addValueCut(unsigned int player, double RHS, const arma::vec &xMinusI);
     bool equilibriumOracle(
          arma::vec &xOfI, arma::vec &x, unsigned int player, int budget, bool &addedCuts);
     bool isFeasiblePure(const unsigned int player, const arma::vec &x);
     void originFeasibility(unsigned int player);
  };
} // namespace Algorithms::EPEC