Skip to content
Snippets Groups Projects
Commit 367dba30 authored by AxelCarayon's avatar AxelCarayon
Browse files

more code refactoring

parent 42be6aaf
Branches
Tags
No related merge requests found
Showing
with 238 additions and 253 deletions
import agents.RandomWalkingAgent;
import agents.SEIRSAgent;
import agents.states.InfectedSEIRSState;
import environment.SEIRSEnvironment;
import models.Parameters;
import scheduler.FairAsynchronousScheduler;
import scheduler.FairSynchronousScheduler;
import scheduler.Scheduler;
import sma.SEIRS_SMA;
import sma.SMA;
import utils.YamlReader;
import java.awt.*;
import java.util.Random;
public class RunExperiment {
public static void main(String[] args) {
SMA sma = new SEIRS_SMA();
Parameters parameters = YamlReader.getParams();
Random r = new Random(parameters.getSeed());
SEIRSAgent[] agents = new RandomWalkingAgent[parameters.getPopulation()];
Scheduler scheduler;
SEIRSEnvironment environment = new SEIRSEnvironment(parameters.getSize(),agents);
//Populate agents
for (int i = 0; i<parameters.getPopulation();i++) {
Point position = new Point(r.nextInt(parameters.getSize()),r.nextInt(parameters.getSize()));
RandomWalkingAgent agent = new RandomWalkingAgent(position,parameters.getSeed()+i,environment);
agents[i] = agent;
}
//Infect agents
for (int i=0 ; i< parameters.getNbOfPatientZero(); i++) {
SEIRSAgent agent = agents[(r.nextInt(parameters.getPopulation()))];
while (agent.getState() instanceof InfectedSEIRSState) {
agent = agents[(r.nextInt(parameters.getPopulation()))];
}
agent.changeState(new InfectedSEIRSState(agent));
}
//create scheduler
if (parameters.isSynchronousMode()) {
scheduler = new FairSynchronousScheduler(parameters.getSeed());
} else {
scheduler = new FairAsynchronousScheduler();
}
sma.init(environment,scheduler,agents);
sma.run();
}
}
package agents;
import agents.states.InfectedSEIRSState;
import agents.states.SEIRSState;
import agents.states.SuceptibleSEIRSState;
import environment.SquareEnvironment2D;
import environment.ChunkedSEIRSEnvironment;
import environment.SEIRSEnvironment;
import utils.YamlReader;
......@@ -15,23 +14,23 @@ public class RandomWalkingAgent implements SEIRSAgent {
private Point position;
private final Random r;
private final SEIRSEnvironment environment;
private SEIRSState SEIRSState;
private SEIRSState state;
public RandomWalkingAgent(Point position, int seed, SEIRSEnvironment environment) {
this.position = position;
this.SEIRSState = new SuceptibleSEIRSState(this);
this.state = new SuceptibleSEIRSState(this);
this.environment = environment;
this.r = new Random(seed);
}
private void move() {
SEIRSState.onMovement();
state.onMovement();
int move = r.nextInt(4);
Point newPosition = switch (move) {
case SquareEnvironment2D.LEFT -> new Point(position.x- SEIRSEnvironment.RADIUS,position.y);
case SquareEnvironment2D.RIGHT -> new Point(position.x+ SEIRSEnvironment.RADIUS,position.y);
case SquareEnvironment2D.UP -> new Point(position.x,position.y- SEIRSEnvironment.RADIUS);
case SquareEnvironment2D.DOWN -> new Point(position.x,position.y+ SEIRSEnvironment.RADIUS);
case SEIRSEnvironment.LEFT -> new Point(position.x- ChunkedSEIRSEnvironment.RADIUS,position.y);
case SEIRSEnvironment.RIGHT -> new Point(position.x+ ChunkedSEIRSEnvironment.RADIUS,position.y);
case SEIRSEnvironment.UP -> new Point(position.x,position.y- ChunkedSEIRSEnvironment.RADIUS);
case SEIRSEnvironment.DOWN -> new Point(position.x,position.y+ ChunkedSEIRSEnvironment.RADIUS);
default -> throw new IllegalStateException("Unexpected value: " + move);
};
if (newPosition.x <= environment.getSize()-1 && newPosition.x >= 0 && newPosition.y <= environment.getSize()-1 && newPosition.y >=0 ) {
......@@ -47,17 +46,15 @@ public class RandomWalkingAgent implements SEIRSAgent {
@Override
public void changeState(SEIRSState SEIRSState) { this.SEIRSState = SEIRSState; }
public void changeState(SEIRSState SEIRSState) { this.state = SEIRSState; }
@Override
public boolean isExposed() {
boolean isExposed = false;
for (SEIRSAgent neighbor: environment.getNeighbors(position)) {
if ((neighbor).getState() instanceof InfectedSEIRSState) {
int roll = r.nextInt(10000)+1;
if (roll <= YamlReader.getParams().getInfectionRate()*10000) {
isExposed = true;
}
for (int i = 0 ; i<environment.getInfectedNeighbors(position).size() ; i++) {
int roll = r.nextInt(10000)+1;
if (roll <= YamlReader.getParams().getInfectionRate()*10000) {
isExposed = true;
}
}
return isExposed;
......@@ -94,7 +91,7 @@ public class RandomWalkingAgent implements SEIRSAgent {
}
@Override
public SEIRSState getState() { return this.SEIRSState; }
public SEIRSState getState() { return this.state; }
@Override
public Point getPosition() { return position; }
......
package agents.states;
import agents.SEIRSAgent;
public class ExposedSEIRSState extends SEIRSState {
public ExposedSEIRSState(agents.SEIRSAgent SEIRSAgent) {
super(SEIRSAgent);
public ExposedSEIRSState(SEIRSAgent agent) {
super(agent);
}
@Override
......
package agents.states;
import agents.SEIRSAgent;
public class InfectedSEIRSState extends SEIRSState {
public InfectedSEIRSState(agents.SEIRSAgent SEIRSAgent) {
super(SEIRSAgent);
public InfectedSEIRSState(SEIRSAgent agent) {
super(agent);
}
@Override
......
......@@ -4,8 +4,8 @@ import agents.SEIRSAgent;
public class RecoveredSEIRSState extends SEIRSState {
public RecoveredSEIRSState(SEIRSAgent SEIRSAgent) {
super(SEIRSAgent);
public RecoveredSEIRSState(SEIRSAgent agent) {
super(agent);
}
@Override
......
package agents.states;
import agents.SEIRSAgent;
public class SuceptibleSEIRSState extends SEIRSState {
public SuceptibleSEIRSState(agents.SEIRSAgent SEIRSAgent) {
super(SEIRSAgent);
public SuceptibleSEIRSState(SEIRSAgent agent) {
super(agent);
}
@Override
......
package environment;
import agents.Agent2D;
import agents.SEIRSAgent;
import agents.states.InfectedSEIRSState;
import agents.states.SEIRSState;
import java.awt.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@SuppressWarnings("unchecked")
public class ChunkedSEIRSEnvironment implements SEIRSEnvironment {
public final static int RADIUS = 10;
public final static int CHUNK_SIZE = 2*RADIUS;
public final int size;
private final SEIRSAgent[] agents;
private List<SEIRSAgent>[][] chunks;
public ChunkedSEIRSEnvironment(int size, SEIRSAgent[] agents) {
this.agents = agents;
this.size = size;
}
private void initiateChunks() {
chunks = new ArrayList[(size/CHUNK_SIZE)][(size/CHUNK_SIZE)];
for (int i = 0; i < chunks.length; i++) {
for (int j = 0; j < chunks[i].length; j++) {
chunks[i][j] = new ArrayList<>();
}
}
for (SEIRSAgent agent : agents) {
int x = agent.getPosition().x/CHUNK_SIZE;
int y = agent.getPosition().y/CHUNK_SIZE;
chunks[x][y].add(agent);
}
}
private Boolean detectCollision(Point pos1, Point pos2) {
double xDif = pos1.x - pos2.x;
double yDif = pos1.y - pos2.y;
double distanceSquared = xDif * xDif + yDif * yDif;
return distanceSquared < (2*RADIUS) * (2*RADIUS);
}
private Point getRelativePoint(int relativeTo, Point p) {
return switch (relativeTo) {
case LEFT -> new Point(p.x-1,p.y);
case RIGHT -> new Point(p.x+1,p.y);
case UP -> new Point(p.x,p.y-1);
case DOWN -> new Point(p.x,p.y+1);
case CENTER -> p;
case UP_LEFT -> new Point(p.x-1,p.y-1);
case UP_RIGHT -> new Point(p.x+1,p.y-1);
case DOWN_LEFT -> new Point(p.x-1,p.y+1);
case DOWN_RIGHT -> new Point(p.x+1,p.y+1);
default -> throw new IllegalStateException("Unexpected value: " + relativeTo);
};
}
private List<SEIRSAgent> getInfectedChunkNeighbors(int relativeTo, Point p) {
Point newPosition = getRelativePoint(relativeTo,p);
Point chunk = new Point(newPosition.x/CHUNK_SIZE,newPosition.y/CHUNK_SIZE);
List<SEIRSAgent> neighbors = new ArrayList<>();
try{
for (SEIRSAgent agent : chunks[chunk.x][chunk.y]) {
if (detectCollision(p, agent.getPosition())) {
if (agent.getState() instanceof InfectedSEIRSState) {
neighbors.add(agent);
}
}
}
}catch (Exception e) {
return neighbors;
}
return neighbors;
}
@Override
public void notifyNewPosition(Point oldPosition, Point newPosition, Agent2D agent) {
if (chunks == null) {
initiateChunks();
}
if (oldPosition.x/CHUNK_SIZE != newPosition.x/CHUNK_SIZE || oldPosition.y/CHUNK_SIZE != newPosition.y/CHUNK_SIZE) {
chunks[oldPosition.x/CHUNK_SIZE][oldPosition.y/CHUNK_SIZE].remove((SEIRSAgent) agent);
chunks[newPosition.x/CHUNK_SIZE][newPosition.y/CHUNK_SIZE].add((SEIRSAgent) agent);
}
}
@Override
public List<SEIRSAgent> getInfectedNeighbors(Point p) {
if (chunks == null) {
initiateChunks();
}
var neighbors = new ArrayList<SEIRSAgent>();
for (int i = 0; i < MAX_CHUNK; i++) {
neighbors.addAll(getInfectedChunkNeighbors(i,p));
}
return neighbors;
}
@Override
public HashMap<String,Integer> getAgentsStatus() {
if (chunks == null) {
initiateChunks();
}
var map = new HashMap<String,Integer>();
map.put(SEIRSState.EXPOSED,0);
map.put(SEIRSState.INFECTED,0);
map.put(SEIRSState.RECOVERED,0);
map.put(SEIRSState.SUCEPTIBLE,0);
for (SEIRSAgent SEIRSAgent : agents) {
String state = SEIRSAgent.getState().toString();
map.put(state,map.get(state)+1);
}
return map;
}
@Override
public int getSize() {
return size;
}
}
package environment;
import agents.Agent;
import agents.Agent2D;
import java.awt.*;
public interface Environment2D extends Environment {
void notifyNewPosition(Point oldPosition, Point newPosition, Agent agent);
int LEFT = 0;
int RIGHT = 1;
int UP = 2;
int DOWN = 3;
int CENTER = 4;
int UP_LEFT = 5;
int UP_RIGHT = 6;
int DOWN_LEFT = 7;
int DOWN_RIGHT = 8;
int MAX_CHUNK = 9;
void notifyNewPosition(Point oldPosition, Point newPosition, Agent2D agent);
int getSize();
}
package environment;
import agents.Agent;
import agents.SEIRSAgent;
import agents.states.SEIRSState;
import java.awt.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@SuppressWarnings("unchecked")
public class SEIRSEnvironment implements SquareEnvironment2D {
public interface SEIRSEnvironment extends Environment2D {
List<SEIRSAgent> getInfectedNeighbors(Point p);
public final static int RADIUS = 10;
public final static int CHUNK_SIZE = 2*RADIUS;
public final int size;
private final SEIRSAgent[] agents;
private List<SEIRSAgent>[][] chunks;
public SEIRSEnvironment(int size, SEIRSAgent[] agents) {
this.agents = agents;
this.size = size;
}
public void initiateChunks() {
chunks = new ArrayList[(size/CHUNK_SIZE)][(size/CHUNK_SIZE)];
for (int i = 0; i < chunks.length; i++) {
for (int j = 0; j < chunks[i].length; j++) {
chunks[i][j] = new ArrayList<>();
}
}
for (SEIRSAgent agent : agents) {
int x = agent.getPosition().x/CHUNK_SIZE;
int y = agent.getPosition().y/CHUNK_SIZE;
chunks[x][y].add(agent);
}
}
private Boolean detectCollision(Point pos1, Point pos2) {
double xDif = pos1.x - pos2.x;
double yDif = pos1.y - pos2.y;
double distanceSquared = xDif * xDif + yDif * yDif;
return distanceSquared < (2*RADIUS) * (2*RADIUS);
}
private Point getRelativePoint(int relativeTo, Point p) {
return switch (relativeTo) {
case LEFT -> new Point(p.x-1,p.y);
case RIGHT -> new Point(p.x+1,p.y);
case UP -> new Point(p.x,p.y-1);
case DOWN -> new Point(p.x,p.y+1);
case CENTER -> p;
case UP_LEFT -> new Point(p.x-1,p.y-1);
case UP_RIGHT -> new Point(p.x+1,p.y-1);
case DOWN_LEFT -> new Point(p.x-1,p.y+1);
case DOWN_RIGHT -> new Point(p.x+1,p.y+1);
default -> throw new IllegalStateException("Unexpected value: " + relativeTo);
};
}
private List<SEIRSAgent> getChunkNeighbors(int relativeTo, Point p) {
Point newPosition = getRelativePoint(relativeTo,p);
Point chunk = new Point(newPosition.x/CHUNK_SIZE,newPosition.y/CHUNK_SIZE);
List<SEIRSAgent> neighbors = new ArrayList<>();
try{
for (SEIRSAgent agent : chunks[chunk.x][chunk.y]) {
if (detectCollision(p, agent.getPosition())) {
neighbors.add(agent);
}
}
}catch (Exception e) {
return neighbors;
}
return neighbors;
}
public List<SEIRSAgent> getNeighbors(Point position) {
if (chunks == null) {
throw new IllegalStateException("Chunks aren't initialized, you should use the initiateMethod() first.");
}
var neighbors = new ArrayList<SEIRSAgent>();
for (int i = 0; i < MAX_CHUNK; i++) {
neighbors.addAll(getChunkNeighbors(i,position));
}
return neighbors;
}
public void notifyNewPosition(Point oldPosition, Point newPosition, Agent agent) {
if (chunks == null) {
throw new IllegalStateException("Chunks aren't initialized, you should use the initiateMethod() first.");
}
if (oldPosition.x/CHUNK_SIZE != newPosition.x/CHUNK_SIZE || oldPosition.y/CHUNK_SIZE != newPosition.y/CHUNK_SIZE) {
chunks[oldPosition.x/CHUNK_SIZE][oldPosition.y/CHUNK_SIZE].remove((SEIRSAgent) agent);
chunks[newPosition.x/CHUNK_SIZE][newPosition.y/CHUNK_SIZE].add((SEIRSAgent) agent);
}
}
public HashMap<String,Integer> getAgentStatus() {
var map = new HashMap<String,Integer>();
map.put(SEIRSState.EXPOSED,0);
map.put(SEIRSState.INFECTED,0);
map.put(SEIRSState.RECOVERED,0);
map.put(SEIRSState.SUCEPTIBLE,0);
for (SEIRSAgent SEIRSAgent : agents) {
String state = SEIRSAgent.getState().toString();
map.put(state,map.get(state)+1);
}
return map;
}
@Override
public int getSize() {
return size;
}
HashMap<String, Integer> getAgentsStatus();
}
package environment;
public interface SquareEnvironment2D extends Environment2D {
int LEFT = 0;
int RIGHT = 1;
int UP = 2;
int DOWN = 3;
int CENTER = 4;
int UP_LEFT = 5;
int UP_RIGHT = 6;
int DOWN_LEFT = 7;
int DOWN_RIGHT = 8;
int MAX_CHUNK = 9;
int getSize();
}
package scheduler;
public abstract class AsynchronousScheduler implements Scheduler {
}
......@@ -9,7 +9,7 @@ import java.util.concurrent.*;
import java.util.function.Function;
import java.util.stream.Collectors;
public class FairAsynchronousScheduler extends AsynchronousScheduler {
public class FairAsynchronousScheduler implements Scheduler {
private final ExecutorService executor = Executors.newSingleThreadExecutor();
private Queue<Agent> queue;
......
......@@ -4,13 +4,14 @@ import agents.Agent;
import java.util.*;
public class FairSynchronousScheduler extends SynchronousScheduler {
public class FairSynchronousScheduler implements Scheduler {
private Agent[] agents;
private Stack<Integer> executionOrder;
private final Random r;
public FairSynchronousScheduler(int seed) {
super(seed);
r = new Random(seed);
}
private void generateExecutionOrder() {
......
package scheduler;
import java.util.Random;
public abstract class SynchronousScheduler implements Scheduler {
protected final Random r;
public SynchronousScheduler(int seed) {
r = new Random(seed);
}
}
package sma;
import agents.Agent;
import environment.Environment;
import agents.SEIRSAgent;
import agents.states.InfectedSEIRSState;
import environment.SEIRSEnvironment;
import models.Parameters;
import agents.RandomWalkingAgent;
import environment.SEIRSEnvironment;
import environment.ChunkedSEIRSEnvironment;
import scheduler.FairAsynchronousScheduler;
import scheduler.FairSynchronousScheduler;
import scheduler.Scheduler;
import utils.StatsRecorder;
import utils.YamlReader;
......@@ -12,29 +15,27 @@ import view.DisplaySquaredEnvironment;
import view.FrameBuilder;
import view.StatisticsCanvas;
import java.awt.*;
import java.io.IOException;
import java.time.Duration;
import java.time.Instant;
import java.util.Date;
import java.util.HashMap;
import java.util.Random;
@SuppressWarnings("InfiniteLoopStatement")
public class SEIRS_SMA implements SMA{
private final Parameters parameters;
private Parameters parameters;
private RandomWalkingAgent[] agents;
private SEIRSEnvironment environment;
private Scheduler scheduler;
private StatisticsCanvas statisticsCanvas;
private DisplaySquaredEnvironment display;
private Random r;
private HashMap<String,Integer> stats;
public SEIRS_SMA() {
parameters = YamlReader.getParams();
agents = new RandomWalkingAgent[parameters.getPopulation()];
}
private void initGraphics() {
statisticsCanvas = new StatisticsCanvas(500,500);
display = new DisplaySquaredEnvironment(environment,agents);
......@@ -43,7 +44,7 @@ public class SEIRS_SMA implements SMA{
frameBuilder.addComponent(display,FrameBuilder.TOP);
frameBuilder.addComponent(statisticsCanvas,FrameBuilder.RIGHT);
frameBuilder.buildWindow();
statisticsCanvas.updateValues(environment.getAgentStatus());
statisticsCanvas.updateValues(environment.getAgentsStatus());
statisticsCanvas.repaint();
}
......@@ -55,7 +56,7 @@ public class SEIRS_SMA implements SMA{
private void doNextCycle(){
scheduler.doNextCycle();
stats = environment.getAgentStatus();
stats = environment.getAgentsStatus();
try{
StatsRecorder.writeToCSV(stats,"src/main/resources/output.csv");
} catch (IOException e) {
......@@ -74,13 +75,43 @@ public class SEIRS_SMA implements SMA{
}
}
@Override
public void init(Environment environment, Scheduler scheduler, Agent[] agents) {
this.agents = (RandomWalkingAgent[]) agents;
this.scheduler = scheduler;
private void initPopulation() {
for (int i = 0; i<parameters.getPopulation();i++) {
Point position = new Point(r.nextInt(parameters.getSize()),r.nextInt(parameters.getSize()));
RandomWalkingAgent agent = new RandomWalkingAgent(position,parameters.getSeed()+i,environment);
agents[i] = agent;
}
}
private void infectPatientZero() {
for (int i=0 ; i< parameters.getNbOfPatientZero(); i++) {
SEIRSAgent agent = agents[(r.nextInt(parameters.getPopulation()))];
while (agent.getState() instanceof InfectedSEIRSState) {
agent = agents[(r.nextInt(parameters.getPopulation()))];
}
agent.changeState(new InfectedSEIRSState(agent));
}
}
private void initScheduler() {
if (parameters.isSynchronousMode()) {
scheduler = new FairSynchronousScheduler(parameters.getSeed());
} else {
scheduler = new FairAsynchronousScheduler();
}
scheduler.init(agents);
this.environment = (SEIRSEnvironment)environment;
this.environment.initiateChunks();
}
@Override
public void init() {
parameters = YamlReader.getParams();
r = new Random(parameters.getSeed());
agents = new RandomWalkingAgent[parameters.getPopulation()];
environment = new ChunkedSEIRSEnvironment(parameters.getSize(),agents);
initPopulation();
infectPatientZero();
initScheduler();
initGraphics();
}
......@@ -106,4 +137,10 @@ public class SEIRS_SMA implements SMA{
System.exit(0);
}
}
public static void main(String[] args) {
SMA sma = new SEIRS_SMA();
sma.init();
sma.run();
}
}
package sma;
import agents.Agent;
import environment.Environment;
import scheduler.Scheduler;
public interface SMA{
void init(Environment environment, Scheduler scheduler, Agent[] agents);
void init();
void run();
}
......@@ -2,6 +2,7 @@ package view;
import agents.SEIRSAgent;
import agents.states.SEIRSState;
import environment.ChunkedSEIRSEnvironment;
import environment.SEIRSEnvironment;
import javax.swing.*;
......@@ -15,14 +16,14 @@ public class DisplaySquaredEnvironment extends JPanel {
public DisplaySquaredEnvironment(SEIRSEnvironment environment, SEIRSAgent[] SEIRSAgents) {
this.setDoubleBuffered(true);
this.SEIRSAgents = SEIRSAgents;
setSize(environment.size,environment.size);
setSize(environment.getSize(),environment.getSize());
setVisible(true);
}
private void drawCenteredCircle(Graphics g, int x, int y) {
x = x-(SEIRSEnvironment.RADIUS /2);
y = y-(SEIRSEnvironment.RADIUS /2);
g.fillOval(x,y, SEIRSEnvironment.RADIUS, SEIRSEnvironment.RADIUS);
x = x-(ChunkedSEIRSEnvironment.RADIUS /2);
y = y-(ChunkedSEIRSEnvironment.RADIUS /2);
g.fillOval(x,y, ChunkedSEIRSEnvironment.RADIUS, ChunkedSEIRSEnvironment.RADIUS);
}
......
......@@ -8,5 +8,5 @@ nbOfPatientZero: 10
population: 5000
seed: 120
size: 500
synchronousMode: false
timeBetweenCycles: 0
synchronousMode: true
timeBetweenCycles: 0
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment