commit 57e65981b6ca3b27ed3fd20f7be7722be96c646e Author: BlackLight Date: Tue Nov 2 16:54:28 2010 +0100 First commit for nash diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..239d9fb --- /dev/null +++ b/Makefile @@ -0,0 +1,6 @@ +all: + g++ -o nash main.cpp nash.cpp -g + +clean: + rm tags + rm nash diff --git a/README b/README new file mode 100644 index 0000000..25126e2 --- /dev/null +++ b/README @@ -0,0 +1,62 @@ +This is a small software that simulates the behaviour of a set of individuals +placed (for sake of simplicity) over a matrix where each individual can choose +between two strategies: + +- Being cooperative with the other individuals +- Being in competition with the other individuals + +From a certain starting point, in which each individuals has its own strategy +independantly from the one chosen by the others, the algorithm goes on, and a +certain individual x changes its strategy if there is a neighbour having a +different strategy and a higher "gain" value (i.e. that strategy takes more +benefit). The algorithm is repeated as long as an equilibrium point is reached +(Nash's equilibrium) in which no individual will change its strategy anymore as +no change is convenient anymore. This balance point won't be always reached +anyway, and the algorithm recognizes a scenario that has no Nash's equilibrium +point when a loop occurs (i.e. when it takes in exam a configuration that was +already met). + +Usage of the program: compile simply issuing `make', then start it with +./nash + +where + +- environment_file is a file containing the starting configuration of the +environment (an example is included in the file `environment'). In this file the +collaborating individuals are marked by a dot `.', and the ones in competition +are marked by a `X'. Starting from here you can easily create your environment +file; + +- coop_coop_gain: Score gained when the individual x cooperates and its neighbour +cooperates as well; + +- coop_comp_gain: Score gained when the individual x cooperates and its neighbour +is in competition; + +- comp_coop_gain: Score gained when the individual x is in competition and its +neighbour cooperates; + +- comp_comp_gain: Score gained when both the individual x and its neighbour are +in competition. + +An example is the problem of the two prisoners: + +- When A doesn't confess and B doesn't confess too, they both get 8 years of +prison (coop_coop_gain = -8); + +- When A doesn't confess and B confesses, A gets 20 years of prison and B is +free (coop_comp_gain = -20); + +- When A confesses and B doesn't, A is free and B gets 20 years of prison +(comp_coop_gain = 0); + +- When both A and B confess, they both get 14 years of prison (comp_comp_gain = +-14). + +For running a simulation of the two prisoners' problem over the example +environment just type + +./nash environment -8 -20 0 -14 + +Have fun. + diff --git a/environment b/environment new file mode 100644 index 0000000..828f643 --- /dev/null +++ b/environment @@ -0,0 +1,11 @@ +. . . . . . . . . . . +. . . . . . . . . . . +. . . . . . . . . . . +. . . . . . . . . . . +. . . . . . . . . . . +. . . . . X . . . . . +. . . . . . . . . . . +. . . . . . . . . . . +. . . . . . . . . . . +. . . . . . . . . . . +. . . . . . . . . . . diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..1073ef6 --- /dev/null +++ b/main.cpp @@ -0,0 +1,79 @@ +/* + * ===================================================================================== + * + * Filename: main.cpp + * + * Description: Main file for the simulation of a Nash's environment + * + * Version: 0.1 + * Created: 01/11/2010 13:23:03 + * Revision: none + * Compiler: gcc + * + * Author: BlackLight (http://0x00.ath.cx), + * Licence: GNU GPL v.3 + * Company: DO WHAT YOU WANT CAUSE A PIRATE IS FREE, YOU ARE A PIRATE! + * + * ===================================================================================== + */ + +#include +#include +#include "nash.h" + +using std::cout; +using std::cerr; +using std::endl; + +/** + * \brief Main function for the program + */ + +int +main ( int argc, char *argv[] ) +{ + NashEnvironment *nash = NULL; + + if ( argc < 6 ) + { + cerr << "Usage: " << argv[0] << " " << endl; + return 1; + } + + nash = new NashEnvironment ( argv[1] ); + + nash->init_costs ( + strtod ( argv[2], NULL ), + strtod ( argv[3], NULL ), + strtod ( argv[4], NULL ), + strtod ( argv[5], NULL ) + ); + + nash->print(); + + try + { + while ( nash->refresh_strategies() ) + { + cout << endl; + + for ( int i=0; i < nash->getCols(); i++ ) + cout << "=="; + + cout << endl; + nash->print(); + } + } + + catch ( NashException e ) + { + cerr << endl << e.what() << endl; + delete nash; + return 1; + } + + cout << endl << "Nash's equilibrium configuration found" << endl; + delete nash; + return 0; +} /* ---------- end of function main ---------- */ + diff --git a/nash.cpp b/nash.cpp new file mode 100644 index 0000000..4c284b3 --- /dev/null +++ b/nash.cpp @@ -0,0 +1,259 @@ +/* + * ===================================================================================== + * + * Filename: nash.cpp + * + * Description: Simulation of a cooperative-competitive environemnt of individuals + * using Nash's models + * + * Version: 0.1 + * Created: 31/10/2010 18:35:14 + * Revision: none + * Compiler: gcc + * + * Author: BlackLight (http://0x00.ath.cx), + * Licence: GNU GPL v.3 + * Company: DO WHAT YOU WANT CAUSE A PIRATE IS FREE, YOU ARE A PIRATE! + * + * ===================================================================================== + */ + +#include +#include +#include +#include "nash.h" + +using std::cout; +using std::endl; +using std::vector; +using std::ifstream; + +NashEnvironment::NashEnvironment ( int rows, int cols ) +{ + this->rows = rows; + this->cols = cols; + + for ( int i=0; i < rows; i++ ) + { + vector row; + + for ( int j=0; j < cols; j++ ) + { + row.push_back(coop); + } + + matrix.push_back(row); + } +} + +NashEnvironment::NashEnvironment ( const char *file ) +{ + vector row; + char ch; + + rows = 0; + cols = 0; + + ifstream in ( file ); + + if ( !in ) + { + throw NashException("Could not open the specified file"); + } + + while ( !in.eof() ) + { + ch = (char) in.get(); + + if ( ch == '\n' ) + { + if ( cols == 0 ) + { + cols = row.size(); + } else { + if ( row.size() != 0 && cols != row.size() ) + { + throw NashException("The size of the rows does not match"); + } + } + + if ( row.size() != 0 ) + { + rows++; + matrix.push_back( row ); + row.clear(); + } + } else if ( ch == '.' ) { + row.push_back( coop ); + } else if ( ch == 'X' ) { + row.push_back( comp ); + } + } + + if ( !row.empty() ) + { + matrix.push_back( row ); + row.clear(); + } + + if ( rows == 0 ) + { + throw NashException("Invalid or empty strategy file"); + } +} + +const int +NashEnvironment::getRows() +{ + return rows; +} + +const int +NashEnvironment::getCols() +{ + return cols; +} + +void +NashEnvironment::init_costs ( double coop_coop, double coop_comp, double comp_coop, double comp_comp ) +{ + costs[coop][coop] = coop_coop; + costs[comp][comp] = comp_comp; + costs[comp][coop] = comp_coop; + costs[coop][comp] = coop_comp; +} /* ----- end of function nash_init_costs ----- */ + +void +NashEnvironment::print () +{ + for ( int i=0; i < rows; i++ ) + { + for ( int j=0; j < cols; j++ ) + { + cout << (( matrix[i][j] == coop ) ? "." : "X" ) << " "; + } + + cout << endl; + } +} /* ----- end of function nash_print_matrix ----- */ + +void +NashEnvironment::update_utilities ( vector< vector< double > >& utilities ) +{ + for ( int x=0; x < rows; x++ ) + { + for ( int y=0; y < cols; y++ ) + { + utilities[x][y] = 0.0; + + for ( int i = (( x == 0 ) ? x : x-1 ); i <= (( x == rows-1 ) ? x : x+1 ); i++ ) + { + for ( int j = (( y == 0 ) ? y : y-1 ); j <= (( y == cols-1 ) ? y : y+1 ); j++ ) + { + if ( !( x == i && y == j )) + { + utilities[x][y] += costs [matrix[x][y]] [matrix[i][j]]; + } + } + } + } + } +} + +bool +NashEnvironment::refresh_strategies () +{ + double best_utility = 0.0; + int best_x = 0, best_y = 0; + vector< vector > changes; + vector< vector > utilities; + + for ( int i=0; i < rows; i++ ) + { + vector row(cols); + utilities.push_back(row); + } + + update_utilities ( utilities ); + + for ( int x=0; x < rows; x++ ) + { + for ( int y=0; y < cols; y++ ) + { + best_x = x; + best_y = y; + best_utility = utilities[best_x][best_y]; + + for ( int i = (( x == 0 ) ? x : x-1 ); i <= (( x == rows-1 ) ? x : x+1 ); i++ ) + { + for ( int j = (( y == 0 ) ? y : y-1 ); j <= (( y == cols-1 ) ? y : y+1 ); j++ ) + { + if ( !( x == i && y == j )) + { + if ( utilities[i][j] > best_utility ) + { + best_x = i; + best_y = j; + best_utility = utilities[best_x][best_y]; + } + } + } + } + + if ( matrix[best_x][best_y] != matrix[x][y] ) + { + vector pair(2); + pair[0] = x; + pair[1] = y; + changes.push_back (pair); + } + } + } + + for ( int i=0; i < changes.size(); i++ ) + { + matrix[changes[i][0]][changes[i][1]] = ( matrix[changes[i][0]][changes[i][1]] == coop ) ? comp : coop; + } + + if ( changes.size() > 0 ) + { + if ( check_loop() ) + { + throw NashException ("Loop detected - No Nash's equilibrium is possible for this configuration"); + } + } + + visited_combinations.push_back(matrix); + return ( changes.size() > 0 ); +} /* ----- end of function nash_refresh_strategies ----- */ + + +bool +NashEnvironment::check_loop () +{ + bool found = false; + + for ( int n=0; n < visited_combinations.size(); n++ ) + { + found = true; + + for ( int i=0; i < rows && found; i++ ) + { + for ( int j=0; j < cols && found; j++ ) + { + if ( matrix[i][j] != visited_combinations[n][i][j] ) + { + found = false; + } + } + } + + if ( found ) + { + return true; + } + } + + return false; +} /* ----- end of function check_loop ----- */ + diff --git a/nash.h b/nash.h new file mode 100644 index 0000000..7eca7d1 --- /dev/null +++ b/nash.h @@ -0,0 +1,100 @@ +/* + * ===================================================================================== + * + * Filename: nash.h + * + * Description: Header file for the simulation of Nash's model + * + * Version: 0.1 + * Created: 01/11/2010 13:20:44 + * Revision: none + * Compiler: gcc + * + * Author: BlackLight (http://0x00.ath.cx), + * Licence: GNU GPL v.3 + * Company: DO WHAT YOU WANT CAUSE A PIRATE IS FREE, YOU ARE A PIRATE! + * + * ===================================================================================== + */ + +#include +#include +typedef enum { coop, comp } nash_strategy; + +class NashException : public std::exception +{ + const char *message; + +public: + NashException ( const char *m ) + { + message = m; + } + + virtual const char* what() + { + return message; + } +}; + +class NashEnvironment +{ + int rows; + int cols; + double costs[2][2]; + std::vector< std::vector< nash_strategy > > matrix; + std::vector< std::vector< std::vector< nash_strategy > > > visited_combinations; + + /** + * \brief Verify if a certain scenario has already been visited, for avoiding loops in environments without Nash's balance + * \return True if the current scenario was already analyzed, false otherwise + */ + bool check_loop (); + + /** + * \brief Update the utility costs on the matrix + * \param utilities Reference to the utilities matrix to be updated + */ + void update_utilities ( std::vector< std::vector >& utilities ); + +public: + + /** + * \brief Constructor for the class + * \param rows Rows of the Nash environment's matrix + * \param cols Cols of the Nash environment's matrix + */ + NashEnvironment ( int rows, int cols ); + + /** + * \brief Constructor for the class + */ + NashEnvironment ( const char *file ); + + /** + * \brief Number of rows in the matrix + */ + const int getRows(); + + /** + * \brief Number of cols in the matrix + */ + const int getCols(); + + /** + * \brief Initialize the costs of the matrix of strategy costs + */ + void init_costs ( double coop_coop, double coop_comp, double comp_coop, double comp_comp ); + + /** + * \brief Print the current status of the matrix of strategies + */ + void print (); + + /** + * \brief Refresh the matrix of the utility values + * \return True if there were strategy changes, false otherwise + */ + bool refresh_strategies (); +}; +