/*
* JABM - Java Agent-Based Modeling Toolkit
* Copyright (C) 2013 Steve Phelps
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 3 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*/
package net.sourceforge.jabm.gametheory;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import net.sourceforge.jabm.Population;
import net.sourceforge.jabm.SpringSimulationController;
import net.sourceforge.jabm.agent.Agent;
import net.sourceforge.jabm.init.AgentInitialiser;
import net.sourceforge.jabm.init.StrategyInitialiser;
import net.sourceforge.jabm.report.*;
import net.sourceforge.jabm.strategy.Strategy;
import net.sourceforge.jabm.util.MutableStringWrapper;
import org.apache.commons.math3.stat.descriptive.StatisticalSummary;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.annotation.Required;
/**
* A simulation controller which can be used to generate a heuristic payoff
* matrix, as described in the following paper:
*
* Wellman, M. P. (2006). Methods for Empirical Game-Theoretic Analysis.
* Twenty-First National Conference on Artificial Intelligence (AAAI-06) (pp.
* 1152-1155). Boston, Massachusetts.
*
* @author Seve Phelps
*
*/
public class GameTheoreticSimulationController extends SpringSimulationController
implements Serializable, AgentInitialiser {
protected CompressedPayoffMatrix payoffMatrix;
protected List<Strategy> strategies;
protected List<StrategyInitialiser> strategyInitialisers;
protected PayoffByStrategyReportVariables payoffByStrategy;
protected CompressedPayoffMatrix.Entry currentEntry;
protected String csvFileName;
protected MutableStringWrapper fileNamePrefix;
protected String binFileName;
protected CSVWriter csvOut;
protected ObjectOutputStream binaryOut;
static Logger logger = Logger.getLogger(GameTheoreticSimulationController.class);
public GameTheoreticSimulationController() {
}
public void initialise() {
strategies = new ArrayList<Strategy>(strategyInitialisers.size());
for (StrategyInitialiser init : strategyInitialisers) {
ObjectFactory<Strategy> factory = init.getStrategyFactory();
strategies.add(factory.getObject());
}
int numAgents = getPopulation().getAgents().size();
payoffMatrix = new CompressedPayoffMatrix(strategies, numAgents);
}
public void resize(int numAgents) {
payoffMatrix = new CompressedPayoffMatrix(strategies, numAgents);
Population population = getPopulation();
population.setSize(numAgents);
population.reset();
}
@Override
public void run() {
initialiseOutput();
Iterator<CompressedPayoffMatrix.Entry> i = payoffMatrix
.compressedEntryIterator();
while (i.hasNext()) {
this.currentEntry = i.next();
logger.info("Computing payoffs for " + this.currentEntry);
AggregatePayoffMap aggregatePayoffs = (AggregatePayoffMap) payoffMatrix.getCompressedPayoffs(currentEntry);
payoffByStrategy.setPayoffMap(new ContributingPayoffMap(aggregatePayoffs, strategies));
payoffByStrategy.initialise();
super.run();
// updatePayoffs(this.currentEntry);
logger.info("done.");
}
logger.info("completed payoff matrix.");
exportPayoffPatrix();
}
// @Override
// protected void constructSimulation() {
// super.constructSimulation();
// initialiseAgents(this.currentEntry);
// }
//
public StatisticalSummary getPayoffDistribution(Strategy strategy) {
return payoffByStrategy.getPayoffMap().getPayoffDistribution(strategy);
}
// public void updatePayoffs(CompressedPayoffMatrix.Entry entry) {
// try {
// PayoffMap payoffs = payoffByStrategy.getPayoffMap();
// payoffMatrix.updateWithPayoffs(entry, payoffs);
// } catch (CloneNotSupportedException e) {
// throw new RuntimeException(e);
// }
// }
public void initialiseAgents(CompressedPayoffMatrix.Entry entry, Population population) {
logger.debug("Initialising agents for entry " + entry);
// TODO: ?
// initialiseAgents();
Iterator<Agent> agentIterator = population.getAgents().iterator();
for (int s = 0; s < strategies.size(); s++) {
int n = entry.numAgentsPerStrategy[s];
if (n == 0) {
continue;
}
Population subPopulation = new Population();
subPopulation.setSize(n);
for (int i = 0; i < n; i++) {
Agent agent = agentIterator.next();
Strategy oldStrategy = agent.getStrategy();
if (oldStrategy != null) {
//TODO: Check this!
// oldStrategy.setAgent(null);
// agent.setStrategy(null);
}
subPopulation.add(agent);
}
AgentInitialiser initialiser = strategyInitialisers.get(s);
if (logger.isDebugEnabled())
logger.debug("Initialising " + subPopulation + " with strategy " + s);
initialiser.initialise(subPopulation);
}
}
public CompressedPayoffMatrix getPayoffMatrix() {
return payoffMatrix;
}
public void setPayoffMatrix(CompressedPayoffMatrix payoffMatrix) {
this.payoffMatrix = payoffMatrix;
}
public List<Strategy> getStrategies() {
return strategies;
}
public Collection<Agent> getAgents() {
return getPopulation().getAgents();
}
public List<StrategyInitialiser> getStrategyInitialisers() {
return strategyInitialisers;
}
@Required
public void setStrategyInitialisers(
List<StrategyInitialiser> strategyInitialisers) {
this.strategyInitialisers = strategyInitialisers;
}
@Required
public PayoffByStrategyReportVariables getPayoffByStrategy() {
return payoffByStrategy;
}
@Required
public void setPayoffByStrategy(
PayoffByStrategyReportVariables payoffByStrategy) {
this.payoffByStrategy = payoffByStrategy;
}
public String getCsvFileName() {
return csvFileName;
}
public void setCsvFileName(String csvFileName) {
this.csvFileName = csvFileName;
}
public MutableStringWrapper getFileNamePrefix() {
return fileNamePrefix;
}
public void setFileNamePrefix(MutableStringWrapper fileNamePrefix) {
this.fileNamePrefix = fileNamePrefix;
}
public String getBinFileName() {
return binFileName;
}
public void setBinFileName(String binFileName) {
this.binFileName = binFileName;
}
public void exportPayoffPatrix() {
try {
if (csvOut != null) {
payoffMatrix.export(csvOut);
csvOut.flush();
}
if (this.binaryOut != null) {
binaryOut.writeObject(payoffMatrix);
binaryOut.close();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public void initialiseOutput() {
try {
if (csvFileName != null) {
int numStrategies = payoffMatrix.getNumStrategies();
String fullFileName = this.fileNamePrefix + this.csvFileName;
this.csvOut = new CSVWriter(new FileOutputStream(
fullFileName), numStrategies * 4, '\t');
}
if (binFileName != null) {
this.binaryOut = new ObjectOutputStream(
new FileOutputStream(binFileName));
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@Override
public void afterPropertiesSet() throws Exception {
super.afterPropertiesSet();
initialise();
}
@Override
public void initialise(Population population) {
initialiseAgents(this.currentEntry, population);
}
}