Commit 03866544 authored by Ant01n3's avatar Ant01n3

Added the classes to handle demographics.

They are not yet connected to the main simulation code.
parent 12fdc83b
...@@ -45,13 +45,12 @@ import org.miv.pherd.geom.Point3; ...@@ -45,13 +45,12 @@ import org.miv.pherd.geom.Point3;
* </p> * </p>
* *
* <p> * <p>
* The boid is in fact split in two parts, the {@link Boid} class itself and the * The boid is in fact split in two parts, the {@link Boid} class itself that
* {@link BoidParticle} inner class that represents the boid in the forces * represents the boid in the forces system. The boid particle in turn contains
* system. The boid particle in turn contains a {@link BoidForces} object that * a {@link BoidForces} object that represents all the forces exercising on the
* represents all the forces exercising on the boid. Globally, the {@link Boid} * boid. Globally, the {@link Boid} class acts on the graph and updates its
* class acts on the graph and updates its position, creating links toward other * position, creating links toward other boids/nodes that it sees, whereas
* boids/nodes that it sees, whereas the {@link BoidParticle} and the * the {@link BoidForces} are used to compute the boid position.
* {@link BoidForces} are used to compute the boid position.
* </p> * </p>
* *
* @author Guilhelm Savin * @author Guilhelm Savin
...@@ -59,9 +58,8 @@ import org.miv.pherd.geom.Point3; ...@@ -59,9 +58,8 @@ import org.miv.pherd.geom.Point3;
*/ */
public class Boid extends AdjacencyListNode { public class Boid extends AdjacencyListNode {
protected final BoidSpecies species;
/** Parameters of this group of boids. */ /** Parameters of this group of boids. */
protected final BoidSpecies species;
/** The set of forces acting on this particle. */ /** The set of forces acting on this particle. */
protected BoidForces forces; protected BoidForces forces;
......
...@@ -105,11 +105,6 @@ public abstract class BoidForces { ...@@ -105,11 +105,6 @@ public abstract class BoidForces {
* Compute the forces applied to a boid under the form of a barycenter that * Compute the forces applied to a boid under the form of a barycenter that
* the boids tries to reach (attraction), an overall direction for all the * the boids tries to reach (attraction), an overall direction for all the
* surrounding boids, an overall direction of all the surrounding boids. * surrounding boids, an overall direction of all the surrounding boids.
*
* @param source
* The boid the forces are computed on.
* @param startCell
* The start cell (usually the root cell of the n-tree).
*/ */
public void compute() { public void compute() {
Collection<Boid> neigh; Collection<Boid> neigh;
...@@ -203,13 +198,11 @@ public abstract class BoidForces { ...@@ -203,13 +198,11 @@ public abstract class BoidForces {
public void moveBarycenter(Point3 p) { public void moveBarycenter(Point3 p) {
barycenter.move(p); barycenter.move(p);
} }
/** /**
* A boid particle p2 that is visible by p1 as been found, integrate it in * A boid particle p2 that is visible by p1 as been found, integrate it in
* the forces that apply to the boid p1. * the forces that apply to the boid p1.
* *
* @param p1
* The source boid.
* @param b * @param b
* the boid visible by p1. * the boid visible by p1.
* @param rep * @param rep
...@@ -291,7 +284,7 @@ public abstract class BoidForces { ...@@ -291,7 +284,7 @@ public abstract class BoidForces {
* angle for example. * angle for example.
* </p> * </p>
* *
* @param source * @param boid
* The source boid. * The source boid.
* @param point * @param point
* The point to consider. * The point to consider.
......
...@@ -33,6 +33,7 @@ import java.io.FileNotFoundException; ...@@ -33,6 +33,7 @@ import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import org.graphstream.boids.forces.ntree.NTreeForcesFactory; import org.graphstream.boids.forces.ntree.NTreeForcesFactory;
...@@ -48,7 +49,7 @@ import org.miv.pherd.geom.Point3; ...@@ -48,7 +49,7 @@ import org.miv.pherd.geom.Point3;
import java.util.Random; import java.util.Random;
/** /**
* Shared data for boids. * Represents a boid simulation and their underlying interaction graph.
* *
* @author Damien Olivier * @author Damien Olivier
* @author Guilhelm Savin * @author Guilhelm Savin
...@@ -57,7 +58,7 @@ import java.util.Random; ...@@ -57,7 +58,7 @@ import java.util.Random;
public class BoidGraph extends AdjacencyListGraph { public class BoidGraph extends AdjacencyListGraph {
public static enum Parameter { public static enum Parameter {
MAX_STEPS, AREA, SLEEP_TIME, STORE_FORCES_ATTRIBUTES, REMOVE_CAUGHT_BOIDS, NORMALIZE_MODE, RANDOM_SEED MAX_STEPS, AREA, SLEEP_TIME, STORE_FORCES_ATTRIBUTES, NORMALIZE_MODE, RANDOM_SEED
} }
/** /**
...@@ -83,12 +84,7 @@ public class BoidGraph extends AdjacencyListGraph { ...@@ -83,12 +84,7 @@ public class BoidGraph extends AdjacencyListGraph {
protected boolean storeForcesAttributes; protected boolean storeForcesAttributes;
/** /**
* Remove the boids caught by a predator ?. * Normalize boids attraction/repulsion vectors (make the boids move
*/
protected boolean removeCaughtBoids;
/**
* Normalise boids attraction/repulsion vectors (make the boids move
* constantly, since very small vectors can be extended). * constantly, since very small vectors can be extended).
*/ */
protected boolean normalizeMode; protected boolean normalizeMode;
...@@ -118,10 +114,25 @@ public class BoidGraph extends AdjacencyListGraph { ...@@ -118,10 +114,25 @@ public class BoidGraph extends AdjacencyListGraph {
*/ */
protected Random random; protected Random random;
/**
* Factory for the forces model used in boids.
*/
protected BoidForcesFactory forcesFactory; protected BoidForcesFactory forcesFactory;
/**
* Lower point in space.
*/
protected Point3 lowAnchor; protected Point3 lowAnchor;
/**
* Higher point in space.
*/
protected Point3 highAnchor; protected Point3 highAnchor;
/**
* Listeners for boid-graph specific events.
*/
protected ArrayList<BoidGraphListener> listeners = new ArrayList<BoidGraphListener>();
/** /**
* New context. * New context.
...@@ -137,7 +148,6 @@ public class BoidGraph extends AdjacencyListGraph { ...@@ -137,7 +148,6 @@ public class BoidGraph extends AdjacencyListGraph {
highAnchor = new Point3(1, 1, 1); highAnchor = new Point3(1, 1, 1);
loop = false; loop = false;
normalizeMode = true; normalizeMode = true;
removeCaughtBoids = false;
storeForcesAttributes = false; storeForcesAttributes = false;
sleepTime = 20; sleepTime = 20;
area = 1; area = 1;
...@@ -239,14 +249,6 @@ public class BoidGraph extends AdjacencyListGraph { ...@@ -239,14 +249,6 @@ public class BoidGraph extends AdjacencyListGraph {
this.sleepTime = sleepTime; this.sleepTime = sleepTime;
} }
public boolean isCaughtBoidsRemoved() {
return removeCaughtBoids;
}
public void setRemoveCaughtBoids(boolean removeCaughtBoids) {
this.removeCaughtBoids = removeCaughtBoids;
}
public boolean isNormalizeMode() { public boolean isNormalizeMode() {
return normalizeMode; return normalizeMode;
} }
...@@ -366,9 +368,6 @@ public class BoidGraph extends AdjacencyListGraph { ...@@ -366,9 +368,6 @@ public class BoidGraph extends AdjacencyListGraph {
case STORE_FORCES_ATTRIBUTES: case STORE_FORCES_ATTRIBUTES:
setStoreForcesAttributes(Boolean.parseBoolean(value)); setStoreForcesAttributes(Boolean.parseBoolean(value));
break; break;
case REMOVE_CAUGHT_BOIDS:
setRemoveCaughtBoids(Boolean.parseBoolean(value));
break;
case NORMALIZE_MODE: case NORMALIZE_MODE:
setNormalizeMode(Boolean.parseBoolean(value)); setNormalizeMode(Boolean.parseBoolean(value));
break; break;
...@@ -408,6 +407,10 @@ public class BoidGraph extends AdjacencyListGraph { ...@@ -408,6 +407,10 @@ public class BoidGraph extends AdjacencyListGraph {
public void step() { public void step() {
stepBegins(step + 1); stepBegins(step + 1);
for(BoidGraphListener listener: listeners) {
listener.step(step + 1);
}
} }
@Override @Override
...@@ -435,6 +438,14 @@ public class BoidGraph extends AdjacencyListGraph { ...@@ -435,6 +438,14 @@ public class BoidGraph extends AdjacencyListGraph {
} catch (InterruptedException e) { } catch (InterruptedException e) {
} }
} }
/**
* Register a listener for boid specific events.
* @param listener The listener to register.
*/
public void addBoidGraphListener(BoidGraphListener listener) {
listeners.add(listener);
}
@Override @Override
protected void addNodeCallback(AbstractNode node) { protected void addNodeCallback(AbstractNode node) {
...@@ -442,6 +453,10 @@ public class BoidGraph extends AdjacencyListGraph { ...@@ -442,6 +453,10 @@ public class BoidGraph extends AdjacencyListGraph {
b.getSpecies().register(b); b.getSpecies().register(b);
super.addNodeCallback(node); super.addNodeCallback(node);
for(BoidGraphListener listener: listeners) {
listener.boidAdded(b);
}
} }
@Override @Override
...@@ -450,6 +465,10 @@ public class BoidGraph extends AdjacencyListGraph { ...@@ -450,6 +465,10 @@ public class BoidGraph extends AdjacencyListGraph {
b.getSpecies().unregister(b); b.getSpecies().unregister(b);
super.removeNodeCallback(node); super.removeNodeCallback(node);
for(BoidGraphListener listener: listeners) {
listener.boidDeleted(b);
}
} }
@Override @Override
......
package org.graphstream.boids;
/**
* Listener for boids specific events on the boid graph.
*
* <p>
* These are not GraphStream events.
* </p>
*
* @author Guilhelm Savin
* @author Antoine Dutot
*/
public interface BoidGraphListener {
/**
* One iteration passed. During an iteration, all boids are moved according to their
* forces model.
* @param time The current iteration time.
*/
void step(int time);
/**
* One boid was added.
* @param boid The added boid.
*/
void boidAdded(Boid boid);
/**
* One boid was removed.
* @param boid The removed boid.
*/
void boidDeleted(Boid boid);
}
\ No newline at end of file
...@@ -135,9 +135,19 @@ public class BoidSpecies implements Iterable<Boid> { ...@@ -135,9 +135,19 @@ public class BoidSpecies implements Iterable<Boid> {
*/ */
protected HashMap<String, Boid> boids; protected HashMap<String, Boid> boids;
/**
* Specify a CSS class for the species name for the GraphStream viewer.
*/
protected boolean addSpeciesNameInUIClass; protected boolean addSpeciesNameInUIClass;
/**
* Allow to create unique identifiers for boids.
*/
private int currentIndex = 0; private int currentIndex = 0;
/**
* Allow to create unique identifiers for boids.
*/
private long timestamp = System.nanoTime(); private long timestamp = System.nanoTime();
/** /**
......
package org.graphstream.boids;
import java.util.HashMap;
import java.util.LinkedList;
/**
* Handles the appearance and disappearance of boids.
*
* @author Guilhelm Savin
* @author Antoine Dutot
*/
public class DemographicManager implements BoidGraphListener {
/**
* The boid graph.
*/
protected BoidGraph ctx;
/**
* Allow to count time.
*/
protected int currentDate = 0;
/**
* List of boids marked for removal at each step.
* @see #check()
* @see #killAll()
*/
protected LinkedList<Boid> toRemove = new LinkedList<Boid>();
/**
* List of boids marked for reproduction at each step.
* @see #check()
* @see #makeLove()
*/
protected LinkedList<Boid> futureParents = new LinkedList<Boid>();
/**
* Date of birth of each active boid, according to {@link #currentDate}.
* @see #currentDate
*/
protected HashMap<Boid, Integer> birthdays = new HashMap<Boid, Integer>();
/**
* Probability function for boid reproduction.
*/
protected Probability reproduceProbability;
/**
* Probability function for boid death.
*/
protected Probability deathProbability;
public DemographicManager(BoidGraph ctx) {
this(ctx, new Probability.ConstantProbability(1), new Probability.DeathProbability());
}
public DemographicManager(BoidGraph ctx, Probability reproduceProbability, Probability deathProbability) {
this.ctx = ctx;
this.reproduceProbability = reproduceProbability;
this.deathProbability = deathProbability;
ctx.addBoidGraphListener(this);
}
/**
* Set the probability function for boid reproduction.
* @param rc The new probability.
*/
public void setReproduceCondition(Probability rc) {
this.reproduceProbability = rc;
}
/**
* Set the probability function for boid death.
* @param dp The new probability.
*/
public void setDeathProbability(Probability dp) {
this.deathProbability = dp;
}
/**
* Called by the boid graph each time a boid is added.
* @param b The boid to add.
*/
protected void register(Boid b) {
birthdays.put(b, currentDate);
}
/**
* Called by the boid graph each time a boid is removed.
* @param b The boid to remove.
*/
protected void unregister(Boid b) {
birthdays.remove(b);
}
/**
* Kill one boid.
* @param b The boid to remove.
*/
protected void kill(Boid b) {
unregister(b);
ctx.removeNode(b.getId());
}
/**
* Genocide all the boids marked for removed by {@link #check()}.
*/
protected void killAll() {
/*
* if( toRemove.size() > 0 ) System.err.printf( "[DM] kill %d boids\n",
* toRemove.size() );
*/
while (toRemove.size() > 0)
kill(toRemove.poll());
}
/**
* Create boids according to the list of future parents created by {@link #check()}.
*/
protected void makeLove() {
Boid b;
// int i = 0;
while (futureParents.size() > 0) {
b = futureParents.poll();
String id = b.getSpecies().createNewId();
ctx.addNode(id);
// ctx.addBoid(b.getSpecies(), b.getPosition().x, b.getPosition().y, b
// .getPosition().z);
// i++;
}
/*
* if( i > 0 ) System.err.printf("[DM] born %d boids\n", i );
*/
}
/**
* identifies boids succeptible to disapear or reproduce and remove/add them.
*/
protected void check() {
int age;
for (Boid b : birthdays.keySet()) {
age = currentDate - birthdays.get(b);
if (ctx.random.nextFloat() < deathProbability.getProbability(ctx, b, age)) {
toRemove.add(b);
} else if (ctx.random.nextFloat() < reproduceProbability .getProbability(ctx, b, age)) {
futureParents.add(b);
}
}
makeLove();
killAll();
currentDate++;
}
public void boidAdded(Boid boid) {
register(boid);
}
public void boidDeleted(Boid boid) {
unregister(boid);
}
/**
* Call this method after each step of boid computation, to add or remove boids according to
* reproduction rules.
*/
public void step(int time) {
check();
}
/**
* A demographic manager that handles boids species.
*
* @author Guilhelm Savin
* @author Antoine Dutot
*/
public static class SpeciesDemographicManager extends DemographicManager {
BoidSpecies species;
public SpeciesDemographicManager(BoidSpecies species, BoidGraph ctx) {
super(ctx);
this.species = species;
}
public SpeciesDemographicManager(BoidSpecies species, BoidGraph ctx,
Probability r, Probability d) {
super(ctx, r, d);
this.species = species;
}
@Override
protected void register(Boid b) {
if (b.getSpecies() == species)
super.register(b);
}
@Override
protected void unregister(Boid b) {
if (b.getSpecies() == species)
super.unregister(b);
}
}
}
\ No newline at end of file
package org.graphstream.boids;
/**
* Various probability distributions.
*
* @author Guilhelm Savin
*/
public interface Probability {
public static class ConstantProbability implements Probability {
double p;
public ConstantProbability(double p) {
this.p = p;
}
public double getProbability(BoidGraph ctx, Boid b, int age) {
return p;
}
}
public static abstract class SigmoidProbability implements Probability {
double lambda = 1;
double seuil = 0;
public SigmoidProbability(double lambda, double seuil) {
this.lambda = lambda;
this.seuil = seuil;
}
protected double getSigmoidValue(double x) {
return 1.0 / (1.0 + Math.exp(-lambda * (x - seuil)));
}
protected double getSigmoidValue(double x, double lambda, double seuil) {
return 1.0 / (1.0 + Math.exp(-lambda * (x - seuil)));
}
}
public static class DeathProbability extends SigmoidProbability {
public DeathProbability() {
super(0.3, 80);
}
public DeathProbability(int averageLifeHopeness) {
super(0.3, averageLifeHopeness);
}
public double getProbability(BoidGraph ctx, Boid b, int age) {
return getSigmoidValue(age);
}
}
// public static class EnergyDependentReproduceProbability extends
// Probability.SigmoidProbability {
// float reproduce;
//
// public EnergyDependentReproduceProbability(float reproduce) {
// super(0.1, 0);
// this.reproduce = reproduce;
// }
//
// public double getProbability(BoidGraph ctx, Boid b, int age) {
// return reproduce * getSigmoidValue(b.getForces().getEnergy());
// }
// }
//
// public static class EnergyDependentDeathProbability extends
// DeathProbability {
// double lunchAlpha = 0.4;
//
// public EnergyDependentDeathProbability(int averageLifeHopeness) {
// seuil = averageLifeHopeness;
// }
//
// @Override
// public double getProbability(BoidGraph ctx, Boid b, int age) {
// if (b.getForces().getEnergy() <= 0)
// return 1;
// else
// return super.getProbability(ctx, b, age);// Math.max(1-getSigmoidValue(b.getEnergy(),0.1,0),super.getProbability(ctx,b,age));
// }
// }