/*$$ * Copyright (c) 1999, Trustees of the University of Chicago * All rights reserved. * * Redistribution and use in source and binary forms, with * or without modification, are permitted provided that the following * conditions are met: * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of the University of Chicago nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE TRUSTEES OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *$$*/ // import java.awt.Color; import java.util.ArrayList; import java.util.Iterator; import java.util.ListIterator; // import java.util.TreeSet; import java.util.Vector; // import java.lang.Math; import uchicago.src.reflector.BooleanPropertyDescriptor; import uchicago.src.sim.analysis.DataSource; import uchicago.src.sim.analysis.DataRecorder; import uchicago.src.sim.analysis.Histogram; //import uchicago.src.sim.analysis.OpenHistogram; import uchicago.src.sim.analysis.OpenSequenceGraph; import uchicago.src.sim.analysis.OpenStats; import uchicago.src.sim.analysis.Sequence; import uchicago.src.sim.analysis.BinDataSource; import uchicago.src.sim.analysis.plot.OpenGraph; import uchicago.src.sim.analysis.Plot; // import uchicago.src.sim.engine.BasicAction; import uchicago.src.sim.engine.Schedule; import uchicago.src.sim.engine.SimInit; import uchicago.src.sim.engine.SimModelImpl; import uchicago.src.sim.gui.ColorMap; // import uchicago.src.sim.gui.DisplaySurface; // import uchicago.src.sim.gui.Object2DDisplay; // import uchicago.src.sim.gui.Value2DDisplay; // import uchicago.src.sim.space.Object2DTorus; import uchicago.src.sim.util.SimUtilities; import uchicago.src.sim.util.Random; // import cern.jet.random.Uniform; // import cern.jet.random.Normal; // Simulation models should extend SimModelImpl which does some basic setup // and allows a controller easy access to a simulations initial parameters. public class FoodModel extends SimModelImpl { // Every model must have a schedule private Schedule schedule; // A list of all the agents. Convenient for any method that // iterates through a list of agents. A least one list like // this is common to most simulations. See below for examples // of its use. private ArrayList agentList = new ArrayList(); // A list of TaggedAgents who have been "birthed" and should // be introduced to the simulation in the next turn private Vector birthList = new Vector(); // A queue that tracks dead agents. private Vector reaperQueue = new Vector(); // A DataRecorder allows data generated by a simulation to be written // to a file private DataRecorder recorder; private DataRecorder finalRecorder; // initial starting parameters of the model private int initialPopSize = 0; private int maxTime = 10; private int numPairings = 6; private double probMutVal = 0.05; private double sdMut = 0.05; private int maxNumNew = 2; private double donationCost = 1; private double donationBenefit = 0.95; // private int foodPerInitialPop = 2; // private int numFood = initialPopSize * foodPerInitialPop; private int numFood = 200; private int realNumFood = numFood; private int numFoodTypes = 2; private int maxTagAge = 30; private int maxStartAge = 0; private double initialFood = 1; private double foodOfTypeNecessaryForReproduction = 4; private double foodOfTypeBelowWhichTagDies = 0; private double foodOfTypeAboveWhichIsExtra = 5; private double foodUsageRate = 0.25; private double maxReservoir = 7.5; private double maxTol = 0.05; private double reproductionNoiseSd = 0.0001; private int lastMaxDataSet = 0; // variables for statistics private int numDonationPackages; private double sumNumDonationPackages; private int numDonationEvents; private double sumNumDonationEvents; private double sumDonationRate; private int numCloneDonationPackages; private double sumCloneDonationRate; private int numBirths; private double sumNumBirths; private int numAgeDeaths; private double sumNumAgeDeaths; private int numStarveDeaths; private double sumNumStarveDeaths; private double gathered; private double excess; private double sumAvExcess; private double totalDonationAmount; private int sumNumAgents; private int totalNumPairings; private double sumAvTolerance; private double sumAvGathered; private double sumAvDonationAmount; private double sumTotalResources; private boolean popLow; private int countPopLow; private boolean bornOfAllTypes; private int countNotBornOfAllTypes; private int finalStartClick = 1000; { assert finalStartClick <= maxTime; } private int[] numAgentType; // various switches for recording and display private boolean write = true; private boolean writeFinal = false; private boolean display = false; private boolean profile = false; private ColorMap colorMap = new ColorMap(); private boolean histogram = false; private boolean subPops = false; // extra switches for testing code private boolean withDeath = true; private boolean withAsexualReproduction = true; private boolean withReproductionNoise = false; private boolean withNew = true; private boolean withValMut = true; private boolean withSkillMut = false; private boolean withTagVariety = true; private boolean withRandomFoodScatter = true; private boolean withRandomInitialSkills = true; /** * @return Returns the write. */ public boolean isWrite() { return write; } /** * @param write * The write to set. */ public void setWrite(boolean write) { this.write = write; } public boolean isWriteFinal() { return writeFinal; } public void setWriteFinal(boolean writeFinal) { this.writeFinal = writeFinal; } public int getFinalStartClick() { return finalStartClick; } public void setFinalStartClick(int finalStartClick) { this.finalStartClick = finalStartClick; } // public int getFoodPerInitialPop() { // return foodPerInitialPop; // } // // public void setFoodPerInitialPop(int foodPerInitialPop) { // this.foodPerInitialPop = foodPerInitialPop; // } public boolean isProfile() { return profile; } public void setProfile(boolean profile) { this.profile = profile; } public boolean isDisplay() { return display; } public void setDisplay(boolean display) { this.display = display; } public boolean isHistogram() { return histogram; } public void setHistogram(boolean histogram) { this.histogram = histogram; } public boolean isSubPops() { return subPops; } public void setSubPops(boolean subPops) { this.subPops = subPops; } public boolean isWithDeath() { return withDeath; } public void setWithDeath(boolean withDeath) { this.withDeath = withDeath; } public boolean isWithAsexualReproduction() { return withAsexualReproduction; } public void setWithAsexualReproduction(boolean withAsexualReproduction) { this.withAsexualReproduction = withAsexualReproduction; } public boolean isWithReproductionNoise() { return withReproductionNoise; } public void setWithReproductionNoise(boolean withReproductionNoise) { this.withReproductionNoise = withReproductionNoise; } public boolean isWithNew() { return withNew; } public void setWithNew(boolean withNew) { this.withNew = withNew; } public boolean isWithValMut() { return withValMut; } public void setWithValMut(boolean withValMut) { this.withValMut = withValMut; } public boolean isWithSkillMut() { return withSkillMut; } public void setWithSkillMut(boolean withSkillMut) { this.withSkillMut = withSkillMut; } public boolean isWithTagVariety() { return withTagVariety; } public void setWithTagVariety(boolean withTagVariety) { this.withTagVariety = withTagVariety; } public boolean isWithRandomFoodScatter() { return withRandomFoodScatter; } public void setWithRandomFoodScatter(boolean withRandomFoodScatter) { this.withRandomFoodScatter = withRandomFoodScatter; } public boolean isWithRandomInitialSkills() { return withRandomInitialSkills; } public void setWithRandomInitialSkills(boolean withRandomInitialSkills) { this.withRandomInitialSkills = withRandomInitialSkills; } public double getReproductionNoiseSd() { return reproductionNoiseSd; } public void setReproductionNoiseSd(double reproductionNoiseSd) { this.reproductionNoiseSd = reproductionNoiseSd; } private OpenSequenceGraph graph; private Plot profilePlot; private OpenSequenceGraph subPopsGraph; private Histogram histogramGraph; // All simulations should have a no argument constructor - this // is empty and thus not strictly necessary public FoodModel() { BooleanPropertyDescriptor bd = new BooleanPropertyDescriptor( "Replacement", false); descriptors.put("Replacement", bd); Random.createNormal(0.0, sdMut); Random.createUniform(); } private void buildModel() { numDonationPackages = 0; numDonationEvents = 0; numCloneDonationPackages = 0; numAgentType = new int[numFoodTypes]; foodVals = new double[numFoodTypes]; for (int i = 0; i < numAgentType.length; i++) numAgentType[i] = 0; agentList = new ArrayList(); birthList = new Vector(); reaperQueue = new Vector(); for (int i = 0; i < initialPopSize; i++) { int skill = -1; if (!withRandomInitialSkills) { skill = i % numFoodTypes; } addNewAgent(skill); } if (write) { recorder = new DataRecorder("./output/food_model_data.csv", this); recorder.addObjectDataSource("pop", new DataSource() { public Object execute() { return new Integer(agentList.size()); } }); recorder.addObjectDataSource("don", new DataSource() { public Object execute() { double rate = (double) numDonationPackages / (numPairings * agentList.size()); return new Double(rate); } }); recorder.addObjectDataSource("clone", new DataSource() { public Object execute() { double rate = (double) numCloneDonationPackages / (numPairings * agentList.size()); return new Double(rate); } }); recorder.addObjectDataSource("tol", new DataSource() { public Object execute() { double tol = 0; for (int i = 0; i < agentList.size(); i++) tol += agentList.get(i).getTolerance(); return new Double(tol / agentList.size()); } }); recorder.addObjectDataSource("births", new DataSource() { public Object execute() { return new Integer(numBirths); } }); recorder.addObjectDataSource("deaths", new DataSource() { public Object execute() { return new Integer(numAgeDeaths + numStarveDeaths); } }); recorder.addObjectDataSource("old", new DataSource() { public Object execute() { return new Integer(numAgeDeaths); } }); recorder.addObjectDataSource("starve", new DataSource() { public Object execute() { return new Integer(numStarveDeaths); } }); recorder.addObjectDataSource("tdons", new DataSource() { public Object execute() { return new Integer(numDonationPackages); } }); recorder.addObjectDataSource("avGath", new DataSource() { public Object execute() { return new Double(gathered / agentList.size()); } }); recorder.addObjectDataSource("avExcess", new DataSource() { public Object execute() { return new Double(excess / (numFoodTypes * agentList.size())); } }); recorder.addObjectDataSource("avDonAmount", new DataSource() { public Object execute() { if (numDonationEvents != 0) {return new Double(totalDonationAmount / numDonationEvents); } else {return (double) 0; } } }); recorder.addObjectDataSource("tres", new DataSource() { public Object execute() { double resources = 0; for (int i = 0; i < agentList.size(); i++) resources += agentList.get(i).getFood(); return new Double(resources); } }); // attempt at un-hard coding of the above code for (int i = 0; i < numFoodTypes; i++) { final int ii = i; recorder.addObjectDataSource("Proportion with skill " + i, new DataSource() { public Object execute() { return new Double((double) numAgentType[ii] / agentList.size()); } }); } } if (writeFinal) { final int base = maxTime - finalStartClick + 1; // final int base = 1; sumDonationRate = 0; sumNumDonationPackages = 0; sumCloneDonationRate = 0; sumNumBirths = 0; sumNumAgeDeaths = 0; sumNumStarveDeaths = 0; sumAvGathered = 0; sumAvExcess = 0; sumNumAgents = 0; totalNumPairings = 0; sumAvTolerance = 0; sumAvGathered = 0; sumAvExcess = 0; sumAvDonationAmount = 0; sumTotalResources = 0; countPopLow = 0; countNotBornOfAllTypes = 0; finalRecorder = new DataRecorder( "./output/food_model_final_data.csv", this); finalRecorder.addObjectDataSource("pop", new DataSource() { public Object execute() { return new Double((double) sumNumAgents / (double) base); } }); finalRecorder.addObjectDataSource("don", new DataSource() { public Object execute() { return new Double(sumDonationRate / base); } }); finalRecorder.addObjectDataSource("clone", new DataSource() { public Object execute() { return new Double(sumCloneDonationRate / base); } }); finalRecorder.addObjectDataSource("tol", new DataSource() { public Object execute() { return new Double(sumAvTolerance / base); } }); finalRecorder.addObjectDataSource("births", new DataSource() { public Object execute() { return new Double(sumNumBirths / base); } }); finalRecorder.addObjectDataSource("deaths", new DataSource() { public Object execute() { return new Double( (sumNumAgeDeaths + sumNumStarveDeaths) / base); } }); finalRecorder.addObjectDataSource( "starve", new DataSource() { public Object execute() { return new Double(sumNumStarveDeaths / base); } }); finalRecorder.addObjectDataSource("old", new DataSource() { public Object execute() { return new Double(sumNumAgeDeaths / base); } }); finalRecorder.addObjectDataSource("tdons", new DataSource() { public Object execute() { return new Double(sumNumDonationPackages / base); } }); finalRecorder.addObjectDataSource("avGath", new DataSource() { public Object execute() { return new Double(sumAvGathered / base); } }); finalRecorder.addObjectDataSource("avExcess", new DataSource() { public Object execute() { return new Double(sumAvExcess / base); } }); finalRecorder.addObjectDataSource("avDonAmount", new DataSource() { public Object execute() { return new Double(sumAvDonationAmount / base); } }); finalRecorder.addObjectDataSource("tres", new DataSource() { public Object execute() { return new Double(sumTotalResources / base); } }); finalRecorder.addObjectDataSource("prop time pop low", new DataSource() { public Object execute() { return new Double((double) countPopLow / base); } }); finalRecorder.addObjectDataSource("prop time not born of all types", new DataSource() { public Object execute() { return new Double((double) countNotBornOfAllTypes / base); } }); } } private void buildDisplay() { final double maxPop = (double) realNumFood / ((double) numFoodTypes * foodUsageRate); if (display) { // final double maxPop = (double)numFood / ((double)numFoodTypes * // foodUsageRate); graph.addSequence("Size", new Sequence() { public double getSValue() { return (double) agentList.size() / maxPop; } }, OpenGraph.PLUS_SIGN); graph.addSequence("Av. tol.", new Sequence() { public double getSValue() { double tol = 0; for (int i = 0; i < agentList.size(); i++) tol += agentList.get(i).getTolerance(); return tol / (agentList.size() * maxTol); } }, OpenGraph.PLUS_SIGN); graph.addSequence("Don. rate", new Sequence() { public double getSValue() { return (double) numDonationPackages / (numPairings * agentList.size()); } }, OpenGraph.PLUS_SIGN); graph.setAxisTitles("Time", "Proportion of Maximum"); graph.setXRange(0, 100); graph.setYRange(0.05, 0.95); graph.setYIncrement(0.05); graph.setSize(400, 250); } if (histogram) { BinDataSource source = new BinDataSource() { public double getBinValue(Object o) { TaggedAgent agent = (TaggedAgent) o; return agent.getTag(); } }; histogramGraph.createHistogramItem("Number", agentList, source); histogramGraph.setBarWidth(0.01); histogramGraph.setStatsVisible(false); histogramGraph.setXIncrement(0); histogramGraph.setYRange(0, maxPop); } if (subPops) { for (int i = 0; i < numFoodTypes; i++) { final int ii = i; subPopsGraph.addSequence("Skill" + ii, new Sequence() { public double getSValue() { return (double) numAgentType[ii]; } }, colorMap.getColor(ii), OpenGraph.PLUS_SIGN); } subPopsGraph.setAxisTitles("Time", "Size"); subPopsGraph.setXRange(0, 1); subPopsGraph.setYRange(0, 100); subPopsGraph.setYIncrement(0.05); subPopsGraph.setSize(400, 250); } if (profile) { profilePlot.setAxisTitles("Tag values", "Age"); profilePlot.setXRange(0.01, 0.99); profilePlot.setYRange(0.75, maxTagAge - 1); profilePlot.setSize(400, 600); } } // buildSchedule builds the schedule that changes the simulation's // state. Under this scheme, a simulation is a state machine // where all transitions between states are the result of actions // initiated by a schedule. private void buildSchedule() { // this is a static schedule (no need to add or replace actions) // so we can create an inner class that extends from basic // action. The execute method of the inner class will execute // all the methods that we wish to schedule on the agents and // the environment. schedule.scheduleActionBeginning(0, this, "step"); // On a pause in the simulation run, call the writeToFile method // on the recorder object. (Writes the data collected by the // recorder to a file. if (write) schedule.scheduleActionAtPause(recorder, "writeToFile"); if (display) schedule.scheduleActionAtPause(graph, "writeToFile"); // When the simulation run ends, call the writeToFile method // on the recorder object. (Writes the data collected by the recorder // to a file. if (write) schedule.scheduleActionAtEnd(recorder, "writeToFile"); if (writeFinal) schedule.scheduleActionAtEnd(finalRecorder, "writeToFile"); if (display) schedule.scheduleActionAtEnd(graph, "writeToFile"); schedule.scheduleActionAt(maxTime, this, "stop"); } public void step() { numDonationPackages = 0; numCloneDonationPackages = 0; numBirths = 0; numAgeDeaths = 0; numStarveDeaths = 0; excess = 0; totalDonationAmount = 0; // Add the new individuals for this generation if (withNew) for (int i = 0; i < maxNumNew; i++) addNewAgent(-1); // Now kill the agents that should die, // and for those that should, give birth for (int i = 0; i < agentList.size(); i++) { TaggedAgent agent = agentList.get(i); // agent.age(); if (withAsexualReproduction && agent .shouldReproduce(foodOfTypeNecessaryForReproduction)) { int dummy = 1; if (this.getTickCount() > 5) { dummy = 0; } agentBirth(agent.giveBirth(probMutVal, sdMut, initialFood, withValMut, withReproductionNoise, reproductionNoiseSd, maxStartAge)); if (!withTagVariety) { agent.setTolerance(1); } if (withSkillMut && Random.uniform.nextDouble() < probMutVal) { agent.setSkill(Random.uniform.nextIntFromTo(0, numFoodTypes - 1)); } numBirths++; } } // call the birthAgents methods on this model birthAgents(); // call the shuffleAgents method on this model shuffleAgents(); int numAgents = agentList.size(); // put fresh food in the world genFood(); // Distribute each food type evenly between agents with that skill gathered = 0; for (int i = 0; i < numAgents; i++) { TaggedAgent agent = agentList.get(i); int type = agent.getSkill(); agent.harvestFood(foodVals[type] / numAgentType[type]); gathered += foodVals[type] / numAgentType[type]; } // Now for each agent, choose a random set of potential recipients for (int i = 0; i < numAgents; i++) { TaggedAgent agent = agentList.get(i); ArrayList pairings = new ArrayList(numPairings); for (int j = 0; j < numPairings && j < agentList.size() - 1; j++) { Integer next = Integer.valueOf(Random.uniform.nextIntFromTo(0, numAgents - 1)); while (next.intValue() == i || pairings.contains(next)) next = Integer.valueOf(Random.uniform.nextIntFromTo(0, numAgents - 1)); pairings.add(next); } // And then for each of these, if they are similar enough // and this original agent has surplus, donate food. int j = 0; while (j < pairings.size()) { TaggedAgent potential = agentList.get(Integer.valueOf(pairings .get(j))); if (agent.shouldDonate(potential.getTag())) j++; else pairings.remove(j); } double[] excesses = new double[numFoodTypes]; boolean hasExcess = false; for (int type = 0; type < numFoodTypes; type++) { excesses[type] = agent.excessFood(type, foodOfTypeAboveWhichIsExtra); if (excesses[type] > 0) hasExcess = true; excess += excesses[type]; } if (hasExcess) { int n = pairings.size(); numDonationPackages += n; for (j = 0; j < n; j++) { TaggedAgent potential = agentList.get(Integer .valueOf(pairings.get(j))); if (potential.getTag() == agent.getTag()) numCloneDonationPackages++; for (int type = 0; type < numFoodTypes; type++) { if (excesses[type] > 0) { numDonationEvents += n; double donAmount = excesses[type] / n; totalDonationAmount += donAmount; agent.donateFood(type, donAmount * donationCost); potential.receiveDonation(type, donAmount * donationBenefit); } } } } } for (TaggedAgent agent : agentList) { agent.age(); agent.consumeFood(foodUsageRate); if (withDeath) { if (agent.reachedAge(maxTagAge)) { agentDeath(agent); numAgeDeaths++; } else if (agent.isStarved(foodOfTypeBelowWhichTagDies)) { agentDeath(agent); numStarveDeaths++; } } } // displays won't be in synch with what it displays // at end or at pause. if (display) graph.step(); if (histogram) histogramGraph.step(); if (subPops) subPopsGraph.step(); if (profile) { ArrayList> agedAgentList = new ArrayList>( maxTagAge + 1); for (int age = 0; age < maxTagAge + 1; age++) { agedAgentList.add(new ArrayList()); } for (TaggedAgent thisAgent : agentList) { int thisAge = thisAgent.getCurrentAge(); ArrayList thisList = agedAgentList .get(thisAge - 1); thisList.add(thisAgent); } for (int i = 0; i < lastMaxDataSet; i++) profilePlot.clear(i); int dataSet = 0; for (int age = 0; age < maxTagAge + 1; age++) { ArrayList agentsThisAge = agedAgentList.get(age); int size = agentsThisAge.size(); int numSoFar = 0; Iterator theseAgents = agentsThisAge.iterator(); while (theseAgents.hasNext()) { TaggedAgent thisAgent = theseAgents.next(); double tag = thisAgent.getTag(); double tol = thisAgent.getTolerance(); int skill = thisAgent.getSkill(); double yPos = 0.001 + (double) age + ((double) numSoFar / ((double) size + (double) 2)); profilePlot.clear(dataSet); profilePlot.setConnected(true, dataSet); profilePlot.plotPoint(this.bound(tag - tol, 0, 1), yPos, dataSet); profilePlot.plotPoint(this.bound(tag + tol, 0, 1), yPos, dataSet); profilePlot.plotPoint(tag, yPos, dataSet); profilePlot.addLegend(dataSet, "", colorMap.getColor(skill), OpenGraph.PLUS_SIGN); dataSet++; numSoFar++; } } lastMaxDataSet = dataSet; profilePlot.step(); } if (write) recorder.record(); if (writeFinal && (int) this.getTickCount() >= finalStartClick) { // update the sums for final statistics: sumDonationRate += (double) numDonationPackages / ((double) numPairings * (double) agentList.size()); sumNumDonationPackages += numDonationPackages; sumCloneDonationRate += (double) numCloneDonationPackages / ((double) numPairings * (double) agentList.size()); sumNumBirths += numBirths; sumNumAgeDeaths += numAgeDeaths; sumNumStarveDeaths += numStarveDeaths; sumNumAgents += agentList.size(); totalNumPairings = agentList.size() * numPairings; double ttol = 0; for (int i = 0; i < agentList.size(); i++) ttol += agentList.get(i).getTolerance(); sumAvTolerance += ttol / (double) agentList.size(); sumAvGathered += (double) gathered / (double) agentList.size(); sumAvExcess += excess / (numFoodTypes * agentList.size()); if (numDonationPackages != 0) sumAvDonationAmount += (double) totalDonationAmount / (double) numDonationEvents; double tresources = 0; for (int i = 0; i < agentList.size(); i++) tresources += agentList.get(i).getFood(); final double maxPop = (double) realNumFood / ((double) numFoodTypes * foodUsageRate); sumTotalResources += tresources; if ((this.agentList.size() / maxPop) < (double) 1 / 5) countPopLow++; ArrayList bornOfType = new ArrayList(numFoodTypes); for (int i = 0; i < numFoodTypes; i++) bornOfType.add(false); for (TaggedAgent ag : agentList) { if (ag.isBorn()) { bornOfType.set(ag.getSkill(), true); } } bornOfAllTypes = true; for (boolean bornOfThis : bornOfType) if (bornOfThis == false) bornOfAllTypes = false; if (! bornOfAllTypes) countNotBornOfAllTypes++; if ((int) this.getTickCount() == maxTime) // if ((int)this.getTickCount() >= finalStartClick) finalRecorder.record(); } reapAgents(); if (agentList.size() == 0) {stop();} } private double[] foodVals; private int mod(double num, double base) { return 1; } // Generate fresh food, randomly distributed between types public void genFood() { for (int i = 0; i < foodVals.length; i++) foodVals[i] = 0; for (int i = 0; i < realNumFood; i++) { int box = 0; if (withRandomFoodScatter) { box = Random.uniform.nextIntFromTo(0, foodVals.length - 1); } else { box = i % numFoodTypes; } foodVals[box]++; } } // Randomize the order of the object (the TaggedAgents) in the agentList public void shuffleAgents() { SimUtilities.shuffle(agentList); } // Add a new agent. public void addNewAgent(int skill) { TaggedAgent agent = new TaggedAgent(numFoodTypes, initialFood, maxReservoir, maxTol, maxStartAge); agent.setBorn(false); agentBirth(agent); if (skill >= 0) { agent.setSkill(skill); } if (!withTagVariety) { agent.setTolerance(1); } } public void agentBirth(TaggedAgent agent) { numAgentType[agent.getSkill()]++; if (this.getTickCount() == 0) { agentList.add(agent); } else { birthList.add(agent); } } public void birthAgents() { agentList.addAll(birthList); birthList.clear(); } // When an agent "dies" it is added to the reaperQueue public void agentDeath(TaggedAgent agent) { numAgentType[agent.getSkill()]--; reaperQueue.add(agent); } public void reapAgents() { ListIterator li = reaperQueue.listIterator(); while (li.hasNext()) { TaggedAgent agent = (TaggedAgent) li.next(); agentList.remove(agent); } reaperQueue.clear(); } public int getInitialPopSize() { return initialPopSize; } public void setInitialPopSize(int num) { initialPopSize = num; } public int getMaxTime() { return maxTime; } public void setMaxTime(int num) { this.maxTime = num; } public int getNumPairings() { return numPairings; } public void setNumPairings(int num) { this.numPairings = num; } public int getMaxNumNew() { return maxNumNew; } public void setMaxNumNew(int num) { this.maxNumNew = num; } public int getNumFood() { return numFood; } public void setNumFood(int num) { this.numFood = num; } public int getNumFoodTypes() { return numFoodTypes; } public void setNumFoodTypes(int num) { this.numFoodTypes = num; } public int getMaxTagAge() { return maxTagAge; } public void setMaxTagAge(int num) { this.maxTagAge = num; } public int getMaxStartAge() { return maxStartAge; } public void setMaxStartAge(int num) { this.maxStartAge = num; } public double getProbMutVal() { return probMutVal; } public void setProbMutVal(double num) { this.probMutVal = num; } public double getSdMut() { return sdMut; } public void setSdMut(double num) { this.sdMut = num; } public double getDonationCost() { return donationCost; } public void setDonationCost(double num) { this.donationCost = num; } public double getDonationBenefit() { return donationBenefit; } public void setDonationBenefit(double num) { this.donationBenefit = num; } public double getInitialFood() { return initialFood; } public void setInitialFood(double num) { this.initialFood = num; } public double getFoodOfTypeNecessaryForReproduction() { return foodOfTypeNecessaryForReproduction; } public void setFoodOfTypeNecessaryForReproduction(double num) { this.foodOfTypeNecessaryForReproduction = num; } public double getFoodOfTypeBelowWhichTagDies() { return foodOfTypeBelowWhichTagDies; } public void setFoodOfTypeBelowWhichTagDies(double num) { this.foodOfTypeBelowWhichTagDies = num; } public double getFoodOfTypeAboveWhichIsExtra() { return foodOfTypeAboveWhichIsExtra; } public void setFoodOfTypeAboveWhichIsExtra(double num) { this.foodOfTypeAboveWhichIsExtra = num; } public double getFoodUsageRate() { return foodUsageRate; } public void setFoodUsageRate(double num) { this.foodUsageRate = num; } public double getMaxReservoir() { return maxReservoir; } public void setMaxReservoir(double num) { this.maxReservoir = num; } public double getMaxTol() { return maxTol; } public void setMaxTol(double num) { this.maxTol = num; } private double bound(double val, double min, double max) { if (val > max) return max; if (val < min) return min; return val; } public String[] getInitParam() { String[] params = { "InitialPopSize", "MaxTime", "NumPairings", "ProbMutVal", "SdMut", "MaxNumNew", "DonationCost", "DonationBenefit", "NumFood", "NumFoodTypes", "NumSkillBits", "NumNutritionBits", "MaxTagAge", "MaxStartAge", "InitialFood", "FoodOfTypeNecessaryForReproduction", "FoodOfTypeBelowWhichTagDies", "FoodOfTypeAboveWhichIsExtra", "FoodUsageRate", "MaxReservoir", "MaxTol", "Display", "Write", "WriteFinal", "FinalStartClick", "Profile", "Histogram", "SubPops", "withDeath", "withAsexualReproduction", "withReproductionNoise", "reproductionNoiseSd", "withNew", "withValMut", "withSkillMut", "withTagVariety", "withRandomFoodScatter", "withRandomInitialSkills" }; return params; } public void begin() { buildModel(); buildDisplay(); buildSchedule(); if (display) graph.display(); if (histogram) histogramGraph.display(); if (subPops) subPopsGraph.display(); if (profile) { profilePlot.display(); lastMaxDataSet = 0; } } public void setup() { schedule = null; if (graph != null) graph.dispose(); graph = null; if (profilePlot != null) profilePlot.dispose(); profilePlot = null; if (subPopsGraph != null) subPopsGraph.dispose(); subPopsGraph = null; if (histogramGraph != null) histogramGraph.dispose(); histogramGraph = null; colorMap.mapColor(0, ColorMap.green); colorMap.mapColor(1, ColorMap.red); colorMap.mapColor(2, ColorMap.blue); colorMap.mapColor(3, ColorMap.black); colorMap.mapColor(4, ColorMap.cyan); colorMap.mapColor(5, ColorMap.orange); colorMap.mapColor(6, ColorMap.yellow); colorMap.mapColor(7, ColorMap.pink); //if (bar != null) //bar.dispose(); //bar = null; System.gc(); // create a schedule with an interval of one. schedule = new Schedule(1); // Create a sequence graph called Agent Attributes and allow the // data plotted by this graph to be written to the file // ./graph_data.txt in comma delimited format. // if (display) graph = new OpenSequenceGraph("Agent Attributes", this, "./output/food_graph_data.csv", OpenStats.CSV); histogramGraph = new Histogram("Tag distribution", 100, 0, 1, this); subPopsGraph = new OpenSequenceGraph("Sub Populations", this); // Create a plot for the tag profile profilePlot = new Plot("Profile of tag population", this); // profilePlot.setConnected(false); this.registerMediaProducer("Plot", graph); this.registerMediaProducer("Profile", profilePlot); this.registerMediaProducer("SubPops", subPopsGraph); this.registerMediaProducer("Histogram", histogramGraph); } // a required method public Schedule getSchedule() { return schedule; } // a required method - displayed on the Controller toolbar. public String getName() { return "Symbiotic Sharing"; } public static void main(String[] args) { SimInit init = new SimInit(); FoodModel model = new FoodModel(); init.loadModel(model, "", false); } }