Skip to content

Commit

Permalink
Implemented migration. The observed impact of this change is that mas…
Browse files Browse the repository at this point in the history
…s extinctions are extremely rare now, and Locations get many more agents. (In fact, agents may be too survivable under current conditions.)

1. Added a migration event (based on PayUpkeepEvent).
2. Added Size to IAgent, and implemented the method in AgentBase
3. Added MigrationBaseChance to the ISimulation, and pushed the property through SimulationBase and GridSimulation
4. Implemented the migration logic in SimulationBase.
5. Updated the GUI with the new Migration setting.
  • Loading branch information
andrewanderson committed Sep 18, 2010
1 parent 804d979 commit 8d18236
Show file tree
Hide file tree
Showing 10 changed files with 142 additions and 12 deletions.
11 changes: 11 additions & 0 deletions Cas/Core/AgentBase.cs
Expand Up @@ -48,6 +48,17 @@ public void SetInteractionContactPoint()
currentInteractionContactPoint = Cells.GetRandom();
}

/// <summary>
/// Retrieves the total size of the agent's genome, including all sub-agents/cells.
/// </summary>
public int Size
{
get
{
return this.Cells.Sum(cell => cell.Size) + this.Agents.Sum(agent => agent.Size);
}
}

/// <summary>
/// The number of generations that an agent has existed for.
/// </summary>
Expand Down
1 change: 1 addition & 0 deletions Cas/Core/Core.csproj
Expand Up @@ -76,6 +76,7 @@
<Compile Include="Events\DeathEvent.cs" />
<Compile Include="Events\EventBase.cs" />
<Compile Include="Events\IEvent.cs" />
<Compile Include="Events\MigrationEvent.cs" />
<Compile Include="Events\PayUpkeepEvent.cs" />
<Compile Include="Events\ReproductionEvent.cs" />
<Compile Include="Events\TargetedEvent.cs" />
Expand Down
23 changes: 23 additions & 0 deletions Cas/Core/Events/MigrationEvent.cs
@@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Cas.Core.Events
{
public class MigrationEvent : PayUpkeepEvent
{
public Guid OriginLocationId { get; set; }

public MigrationEvent(Guid agentId, Guid originLocationId, Guid destinationLocationId, int cost, int generation)
: base(agentId, destinationLocationId, cost, generation, "Migration")
{
this.OriginLocationId = originLocationId;
}

public override string ToString()
{
return string.Format("{0}: Migrated at a cost of {1} from location {2} to {3}", this.Generation, this.Cost, this.OriginLocationId, this.LocationId);
}
}
}
7 changes: 5 additions & 2 deletions Cas/Core/Events/PayUpkeepEvent.cs
Expand Up @@ -6,8 +6,11 @@ public class PayUpkeepEvent : EventBase
{
public int Cost { get; private set; }

public PayUpkeepEvent(Guid agentId, Guid locationId, int cost, int generation)
: base(agentId, locationId, "Paid Upkeep", generation)
public PayUpkeepEvent(Guid agentId, Guid locationId, int cost, int generation)
: this(agentId, locationId, cost, generation, "Paid Upkeep") { }

protected PayUpkeepEvent(Guid agentId, Guid locationId, int cost, int generation, string description)
: base(agentId, locationId, description, generation)
{
this.Cost = cost;
}
Expand Down
5 changes: 5 additions & 0 deletions Cas/Core/Interfaces/IAgent.cs
Expand Up @@ -36,6 +36,11 @@ public interface IAgent : IBoundary, IInteractable, IIsAlive
/// </summary>
void SetInteractionContactPoint();

/// <summary>
/// Retrieves the total size of the agent's genome, including all sub-agents/cells.
/// </summary>
int Size { get; }

/// <summary>
/// The number of generations that an agent has existed for.
/// </summary>
Expand Down
5 changes: 5 additions & 0 deletions Cas/Core/Interfaces/ISimulation.cs
Expand Up @@ -75,6 +75,11 @@ public interface ISimulation : IDisposable
/// </summary>
double ReproductionInheritance { get; }

/// <summary>
/// The base percent chance (0-1) that an agent decides to migrate to a new location, per generation.
/// </summary>
double MigrationBaseChance { get; }

#endregion

}
Expand Down
67 changes: 61 additions & 6 deletions Cas/Core/SimulationBase.cs
Expand Up @@ -21,9 +21,10 @@ public abstract class SimulationBase : ISimulation
#endregion

protected SimulationBase()
: this(1.5, 4, 0.25, 1.75, 0.2) { }
: this(1.5, 4, 0.25, 1.75, 0.2, 0.005) { }

protected SimulationBase(double interactionsPerGenerationFactor, int maximumUpkeepCostPerLocation, double upkeepChance, double reproductionThreshold, double reproductionInheritance)
protected SimulationBase(double interactionsPerGenerationFactor, int maximumUpkeepCostPerLocation, double upkeepChance,
double reproductionThreshold, double reproductionInheritance, double migrationBaseChance)
{
// Set some defaults
InteractionsPerGenerationFactor = interactionsPerGenerationFactor;
Expand All @@ -32,6 +33,8 @@ protected SimulationBase(double interactionsPerGenerationFactor, int maximumUpke

ReproductionThreshold = reproductionThreshold;
ReproductionInheritance = reproductionInheritance;

MigrationBaseChance = migrationBaseChance;
}

#region ISimulation Members
Expand Down Expand Up @@ -140,6 +143,8 @@ public void Reset()

public double ReproductionInheritance { get; set; }

public double MigrationBaseChance { get; set; }

#endregion

#region RunGeneration
Expand All @@ -160,9 +165,10 @@ public void RunGeneration()
ProcessLocation(location, pendingMigrations);
}

// Relocate the migrants
// Relocate the migrants and charge them upkeep at their new location
foreach (var migration in pendingMigrations)
{
migration.Key.RemoveResources(migration.Value.UpkeepCost);
migration.Value.Agents.Add(migration.Key);
}

Expand All @@ -187,6 +193,9 @@ private void ProcessLocation(ILocation location, List<KeyValuePair<IAgent, ILoca
int interactionsToPerform = (int)(location.Agents.Count*InteractionsPerGenerationFactor);
DoInteractions(location, interactionsToPerform);

// Prior to upkeep, select agents for migration
QueueForMigration(location, pendingMigrations);

// Change upkeep for the location
if (location.UpkeepCost > 0 && RandomProvider.NextDouble() < this.UpkeepChance)
{
Expand Down Expand Up @@ -274,13 +283,59 @@ private void DoReproduction(ILocation location, List<IAgent> breeders)

protected abstract void DoOneReproduction(ILocation location, List<IAgent> breeders);

/// <summary>
/// Selects agents from the location at random, and queues them to
/// move into a new location at the end of this generation.
///
/// As suggested in Hidden Order pg 151, agents with relatively less fitness
/// have a better chance at migrating.
/// </summary>
/// <param name="location">
/// The location to perform migration actions on
/// </param>
/// <param name="pendingMigrations">
/// A list to add all migrants to.
/// </param>
private void QueueForMigration(ILocation location, List<KeyValuePair<IAgent, ILocation>> pendingMigrations)
{
if (location == null) throw new ArgumentNullException("location");
if (pendingMigrations == null) throw new ArgumentNullException("pendingMigrations");

if (location.Connections.Count == 0) return;

var migrants = location.Agents
.Where(agent => (RandomProvider.NextDouble() < CalculateMigrationChance(agent)))
.Select(agent => new KeyValuePair<IAgent, ILocation>(agent, location.Connections.GetRandom()))
.ToList();

migrants.ForEach(kvp =>
{
var agent = kvp.Key;
var destination = kvp.Value;
location.Agents.Remove(agent);
agent.History.Add(new MigrationEvent(agent.Id, location.Id, destination.Id, destination.UpkeepCost, this.CurrentGeneration));
pendingMigrations.Add(kvp);
});
}

/// <summary>
/// Determines the chance that an agent has to migrate, based on
/// it's relative fitness.
/// </summary>
protected virtual double CalculateMigrationChance(IAgent agent)
{
const double maxBonus = 0.02;

double percentFull = Math.Max(1, agent.CurrentResourceCount / agent.Size);

return MigrationBaseChance + ((1 - percentFull) * maxBonus);
}

/// <summary>
/// Retrieves a random target from the supplied list, ensuring that it
/// does not match the supplied actor.
/// </summary>
/// <param name="allTargets"></param>
/// <param name="actor"></param>
/// <returns></returns>
protected static TBase SelectRandomTarget<TBase, TSpecific>(List<TBase> allTargets, TSpecific actor) where TBase : class
{
if (allTargets == null) throw new ArgumentNullException("allTargets");
Expand Down
7 changes: 4 additions & 3 deletions Cas/TestCas/GridSimulation.cs
Expand Up @@ -20,10 +20,11 @@ public class GridSimulation : SimulationBase
private readonly IInteraction<ICell, ICell, IList<ICell>> multipointCrossoverInteraction;
private readonly IInteraction<ICell, ICell, ICell> asexualReproductionInteraction;

public GridSimulation(int length, int width) : this(length, width, 4, 0.25, 1.5, 1.75, 0.2) { }
public GridSimulation(int length, int width) : this(length, width, 4, 0.25, 1.5, 1.75, 0.2, 0.05) { }

public GridSimulation(int length, int width, int maximumUpkeepCostPerLocation, double upkeepChance, double interactionsPerGeneration, double reproductionThreshold, double reproductionInheritance)
: base(interactionsPerGeneration, maximumUpkeepCostPerLocation, upkeepChance, reproductionThreshold, reproductionInheritance)
public GridSimulation(int length, int width, int maximumUpkeepCostPerLocation, double upkeepChance, double interactionsPerGeneration,
double reproductionThreshold, double reproductionInheritance, double migrationBaseChance)
: base(interactionsPerGeneration, maximumUpkeepCostPerLocation, upkeepChance, reproductionThreshold, reproductionInheritance, migrationBaseChance)
{
if (length <= 0) throw new ArgumentException("length");
if (width <= 0) throw new ArgumentException("width");
Expand Down
25 changes: 25 additions & 0 deletions Cas/WebCritters/WebCrittersForm.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion Cas/WebCritters/WebCrittersForm.cs
Expand Up @@ -52,7 +52,8 @@ private void CreateSimulationFromLoadControls()
int.Parse(upkeepPercent.Text) / 100.0,
double.Parse(interactionsPerGeneration.Text),
int.Parse(reproductionThresholdPercent.Text) / 100.0,
int.Parse(reproductionInheritancePercent.Text) / 100.0);
int.Parse(reproductionInheritancePercent.Text) / 100.0,
double.Parse(migrationBaseChance.Text) / 100.0);

CasSimulation.GenerationFinished += new EventHandler(CasSimulation_GenerationFinished);

Expand Down

0 comments on commit 8d18236

Please sign in to comment.