#ifndef _Games_NashEquilibrium #define _Games_NashEquilibrium /* Solve for the pure-strategy Nash equilibrium of a J-player game where the action space is a single real variable. The game is described by a function, Info = Func(x,y) x is the vector of strategies, y is the returned vector on utilities, and the function returns a value not equal to zero in case of an error. A Nash equilibrium is a point x* such that for each j, y(j) is maximized by x*(j) holding all the other components of x* fixed. */ namespace NashEquilibriumSpace { int J; // Number of Players int j; // Current Player double DerivStep; // Step Size for Numerical Derivatives Vector x; // Current Vector of Strategies /* Function Describing Game */ int (*Func)(const Vector &, Vector &); /* One Dimensional Function */ double Func_j(double xj); double Func_j(double xj) { x[j] = xj; Vector f(J); int Info = Func(x,f); if(Info) return Inf; // Invalid Point return -f[j]; } /* One Dimensional Function */ int Func_j_2(double xj, double &fj); int Func_j_2(double xj, double &fj) { x[j] = xj; Vector f(J); int Info = Func(x,f); if(Info) return 1; // Invalid Point fj = -f[j]; return 0; } /* Derivative of Function */ int DFunc(const Vector &x, Vector &df); int DFunc(const Vector &x, Vector &df) { /* For Each Index, Compute First-Order Conditions */ Vector xCopy = x.Copy(); Vector fm(J),fp(J); for(int j=0; j x; // Vector of Strategies int (*Func)(const Vector &, Vector &); int (*DFunc)(const Vector &, Vector &); double DerivStep; int Option; // Option (1 = Best Response Iterations, 2 = Guass-Siedel, 3 = Guass Jacobi) int Method; // Optimization Method (1 = Brent's Method, 2 = Golden Section Search) double Lambda; // Dampening Factor int MaxIter; // Maximum Number of Iterations double TolX; // Tolerance for x int Min1DPrintLevel; int PrintLevel; int K; // Size of Grid Used for Each Player Vector Low; // Lower Bound of Grid for Each Player Vector High; // Upper Bound of Grid for Each Player bool AnalyticalFOC; // Analytical First-order Conditions Provided /* Constructor 1: No Analytical First-order Conditions Provided */ NashEquilibrium(int (*Func)(const Vector &, Vector &), int J) { this->J = J; this->Func = Func; x = Vector(J,Zero); DerivStep = MachEps3; Option = 1; Method = 2; Lambda = One; MaxIter = 100; TolX = 0.00000001; Min1DPrintLevel = 1; PrintLevel = 2; AnalyticalFOC = False; K = 11; Low = Vector(J,-One); Low.Name = "NashEquilibrium::Low"; High = Vector(J,One); High.Name = "NashEquilibrium::High"; } /* Constructor 2: Analytical First-order Conditions Provided */ NashEquilibrium(int (*Func)(const Vector &, Vector &), int (*DFunc)(const Vector &, Vector &), int J) { this->J = J; this->Func = Func; this->DFunc = DFunc; x = Vector(J,Zero); DerivStep = MachEps3; Option = 1; Method = 2; Lambda = One; MaxIter = 100; TolX = 0.00000001; Min1DPrintLevel = 1; PrintLevel = 2; AnalyticalFOC = True; K = 11; Low = Vector(J,-One); Low.Name = "NashEquilibrium::Low"; High = Vector(J,One); High.Name = "NashEquilibrium::High"; } void Solve() { Vector xPrev(J); Vector xNew(J); if(Option == 1) { /* Set Joint First-Order Conditions Equal to Zero */ if(AnalyticalFOC) { if(Method == 1) { /* Newton's Methods */ SolveNewton< Matrix > sn(DFunc,J); sn.NormType = 2; sn.Method = 5; sn.PrintLevel = PrintLevel; Copy(sn.x,x); sn.Solve(); Copy(x,sn.x); } else { /* Nelder Mead */ SolveNelderMead sn(DFunc,J); sn.TolX = 0.000000000001; sn.ScaleX = 0.1; sn.NormType = 2; sn.PrintLevel = PrintLevel; Copy(sn.x,x); sn.Solve(); Copy(x,sn.x); } } else { if(Method == 1) { /* Newton's Methods */ NashEquilibriumSpace::J = J; NashEquilibriumSpace::Func = Func; NashEquilibriumSpace::DerivStep = DerivStep; SolveNewton< Matrix > sn(NashEquilibriumSpace::DFunc,J); sn.NormType = 2; sn.Method = 5; sn.PrintLevel = PrintLevel; Copy(sn.x,x); sn.Solve(); Copy(x,sn.x); } else { /* Nelder Mead */ NashEquilibriumSpace::J = J; NashEquilibriumSpace::Func = Func; NashEquilibriumSpace::DerivStep = DerivStep; SolveNelderMead sn(NashEquilibriumSpace::DFunc,J); sn.TolX = 0.000000000001; sn.ScaleX = 0.1; sn.NormType = 2; sn.PrintLevel = PrintLevel; Copy(sn.x,x); sn.Solve(); Copy(x,sn.x); } } } else { /* Solve Using Guass-Seidel or Guass Jacobi */ NashEquilibriumSpace::J = J; NashEquilibriumSpace::x = Vector(J); NashEquilibriumSpace::Func = Func; Min1D m1(NashEquilibriumSpace::Func_j); m1.Option = 2; Vector< Vector > Grid1(J); Grid1.Name = "NashEquilibrium::Solve::Grid1"; for(int j=0; j 0) Print("Iter",Iter); if(PrintLevel > 0) Print("xPrev",x); if(Option == 2) { /* Guass-Siedel */ /* For Each Index.. */ for(int j=0; j 0) Print("x",x); if(PrintLevel > 0) Print("xNew",xNew); if(PrintLevel > 0) Print("xMax",xMax); Copy(x,xNew); if(xMax < TolX) { if(PrintLevel > 0) Print("Succesfully Exiting NashEquilibrium: Within Tolerance"); if(PrintLevel > 0) Print("x",x); if(PrintLevel > 0) Print("xMax",xMax); return; } } if(PrintLevel > 0) Print("Unsuccesfully Exiting NashEquilibrium: Too Many Iterations"); } } void GraphUtil(string FileName) { /* Graph the utility of each player, varying the player's strategy for Low(j) to High(j), and holding the other playres strategies constant. Save the results in a specified file. */ Vector fCurr(J); fCurr.Name = "NashEquilibrium::GraphUtil::fCurr"; Vector xCurr(J); xCurr.Name = "NashEquilibrium::GraphUtil::xCurr"; Matrix XGrid(J,K); XGrid.Name = "NashEquilibrium::GraphUtil::XGrid"; Matrix Util(J,K); Util.Name = "NashEquilibrium::GraphUtil::Util"; NashEquilibriumSpace::J = J; NashEquilibriumSpace::x = x; NashEquilibriumSpace::Func = Func; for(int j=0; j > xGrid(J); xGrid.Name = "NashEquilibrium::xGrid"; for(int j=0; j(J); Vector< Vector > Br(J); Br.Name = "NashEquilibrium::Br"; for(int j=0; j(K); Br(j).Name = "Br(" + ToString(j+1) + ")"; } for(int j=0; j fEq(J); fEq.Name = "NashEquilibrium1::Check::fEq"; Func(x,fEq); if(PrintLevel >= 1) Print("Checking Equilbrium"); Print("xEq",x); Print("fEq",fEq); Vector fCurr(J); fCurr.Name = "NashEquilibrium::Check::fCurr"; Vector xCurr(J); xCurr.Name = "NashEquilibrium::Check::xCurr"; Vector< Vector > xGrid(J); for(int j=0; j fEq[j]) { if(PrintLevel >= 1) Print("This is not an equilbrium: fCurr[j] > fEq[j]"); if(PrintLevel >= 1) Print("Player",j+1); if(PrintLevel >= 1) Print("k",k); if(PrintLevel >= 1) Print("xGrid(j)(k)",xGrid(j)(k)); if(PrintLevel >= 1) Print("fCurr(j)",fCurr(j)); if(PrintLevel >= 1) Print("fEq(j)",fEq(j)); Info = False; } } } if(PrintLevel >= 1) Print("Checked Equilbrium!"); return Info; } }; #endif