Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/master'
Browse files Browse the repository at this point in the history
# Conflicts:
#	src/io/github/ethankelly/graph/Graph.java
#	test/io/github/ethankelly/graph/GraphTest.java
  • Loading branch information
Ethan-CS committed Jun 15, 2021
2 parents 779daa1 + c4ec432 commit 7bf218a
Show file tree
Hide file tree
Showing 7 changed files with 302 additions and 174 deletions.
10 changes: 10 additions & 0 deletions .idea/libraries/org_apache_commons_commons_math3_3_6_1.xml

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

1 change: 1 addition & 0 deletions Equations.iml
Original file line number Diff line number Diff line change
Expand Up @@ -60,5 +60,6 @@
<SOURCES />
</library>
</orderEntry>
<orderEntry type="library" name="org.apache.commons:commons-math3:3.6.1" level="project" />
</component>
</module>
24 changes: 18 additions & 6 deletions src/io/github/ethankelly/Equations.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,18 @@
import io.github.ethankelly.graph.Graph;
import io.github.ethankelly.graph.GraphGenerator;
import io.github.ethankelly.graph.Vertex;
import io.github.ethankelly.graph.VertexState;
import io.github.ethankelly.symbols.Greek;
import io.github.ethankelly.symbols.Maths;
import org.apache.commons.math3.exception.DimensionMismatchException;
import org.apache.commons.math3.exception.MaxCountExceededException;
import org.apache.commons.math3.ode.FirstOrderDifferentialEquations;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

@SuppressWarnings("DuplicatedCode")
public class Equations {
public class Equations implements FirstOrderDifferentialEquations {

public static List<String> generateEquations(Tuple tuples) {
List<String> equations = new ArrayList<>();
Expand All @@ -26,15 +28,15 @@ public static List<String> generateEquations(Tuple tuples) {
Arrays.sort(sir);
Arrays.sort(sip);
Arrays.sort(sirp);
int numVertices = tuples.getGraph().getNumVertices();

if (Arrays.equals(states, sir)) states = si;
else if (Arrays.equals(states, sirp)) states = sip;

for (List<VertexState> tuple : tuples.getTuples()) {
int numVertices = tuples.getGraph().getNumVertices();

for (List<Vertex> tuple : tuples.getTuples()) {
StringBuilder eqn = new StringBuilder(); // The String representation of the equation of the tuples
eqn.append(tuple.toString()).append(" = ");
for (VertexState vs : tuple) {
for (Vertex vs : tuple) {
switch (Character.toUpperCase(vs.getState())) {
case 'S' -> {
if (new String(states).contains("P")) {
Expand Down Expand Up @@ -136,4 +138,14 @@ public static void main(String[] args) {
System.out.println(subGraph);
}
}

@Override
public int getDimension() {
return 1;
}

@Override
public void computeDerivatives(double v, double[] doubles, double[] doubles1) throws MaxCountExceededException, DimensionMismatchException {

}
}
61 changes: 38 additions & 23 deletions src/io/github/ethankelly/Tuple.java
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
package io.github.ethankelly;

import io.github.ethankelly.graph.Graph;
import io.github.ethankelly.graph.VertexState;
import io.github.ethankelly.graph.Vertex;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.*;

/**
* The {@code Tuple} class is used to determine and represent the number of differential equations required to fully
Expand All @@ -18,7 +15,7 @@
*/
@SuppressWarnings("DuplicatedCode")
public class Tuple {
private List<List<VertexState>> tuples;
private List<List<Vertex>> tuples;
private final Graph graph;
private final char[] states;
private boolean closures;
Expand All @@ -36,12 +33,12 @@ public Tuple(Graph graph, char[] states, boolean closures) {
this.closures = closures;
}

public List<List<VertexState>> getTuples() {
public List<List<Vertex>> getTuples() {
return this.tuples;
}

@SuppressWarnings("unused")
public void setTuples(List<List<VertexState>> tuples) {
public void setTuples(List<List<Vertex>> tuples) {
this.tuples = tuples;
}

Expand All @@ -52,7 +49,7 @@ public void setTuples(List<List<VertexState>> tuples) {
* @param equations the equations to find the numbers of each length.
* @return An array with the number of equations of each size required to exactly describe the SIR system.
*/
public int[] findNumbers(List<List<VertexState>> equations) {
public int[] findNumbers(List<List<Vertex>> equations) {
// The array needs as many elements as there are different sizes in the equations list,
// So initialise to (1 less than) the size of the largest (final) sub-list.
int[] sizes = new int[equations.get(equations.size() - 1).size()];
Expand All @@ -63,13 +60,31 @@ public int[] findNumbers(List<List<VertexState>> equations) {
return sizes;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Tuple tuple = (Tuple) o;
return closures == tuple.closures &&
Objects.equals(getTuples(), tuple.getTuples()) &&
Objects.equals(getGraph(), tuple.getGraph()) &&
Arrays.equals(getStates(), tuple.getStates());
}

@Override
public int hashCode() {
int result = Objects.hash(getTuples(), getGraph(), closures);
result = 31 * result + Arrays.hashCode(getStates());
return result;
}

/**
* Using the states required in the model and the number of vertices in the graph, this method determines the full
* list of single termed equations that are involved in describing the model exactly.
*
* @return the number of single-probability differential equations required by the model.
*/
public List<VertexState> findSingles() {
public List<Vertex> findSingles() {
// Get states, graph and the vertices in the associated graph for the model
char[] states = this.getStates();
Arrays.sort(states);
Expand All @@ -91,20 +106,20 @@ public List<VertexState> findSingles() {
Arrays.setAll(vertices, i -> i);

// We need an equation for the probability of each vertex being in each state
List<VertexState> verticesWeNeed = new ArrayList<>();
List<Vertex> verticesWeNeed = new ArrayList<>();
for (char c : states) {
for (int v : vertices) {
verticesWeNeed.add(new VertexState(c, v));
verticesWeNeed.add(new Vertex(c, v));
}
}
return verticesWeNeed;
}

// Recursive helper method to generate the total equations we need
private void generateTuples(List<VertexState> items,
List<VertexState> selected,
private void generateTuples(List<Vertex> items,
List<Vertex> selected,
int index,
List<List<VertexState>> result) {
List<List<Vertex>> result) {
if (index >= items.size()) {
result.add(new ArrayList<>(selected));
} else {
Expand All @@ -121,10 +136,10 @@ private void generateTuples(List<VertexState> items,
*
* @return a list of each n-tuple we are required to express to exactly detail the model system dynamics.
*/
public List<List<VertexState>> generateTuples(boolean closures) {
List<VertexState> items = this.findSingles();
List<List<VertexState>> result = new ArrayList<>();
List<VertexState> selected = new ArrayList<>();
public List<List<Vertex>> generateTuples(boolean closures) {
List<Vertex> items = this.findSingles();
List<List<Vertex>> result = new ArrayList<>();
List<Vertex> selected = new ArrayList<>();
generateTuples(items, selected, 0, result);

// The helper method gives us all combinations, so remove the ones that don't
Expand All @@ -144,11 +159,11 @@ public List<List<VertexState>> generateTuples(boolean closures) {
* @param toAdd the potential tuple we are considering adding to the system dynamics.
* @return true if the tuple is essential to expressing the system dynamics, false otherwise.
*/
private boolean isValidTuple(List<VertexState> toAdd, boolean closures) {
private boolean isValidTuple(List<Vertex> toAdd, boolean closures) {
Graph g = this.getGraph();
return VertexState.areStatesDifferent(toAdd, closures)
&& VertexState.areLocationsDifferent(toAdd)
&& VertexState.areAllConnected(toAdd, g);
return Vertex.areStatesDifferent(toAdd, closures)
&& Vertex.areLocationsDifferent(toAdd)
&& Vertex.areAllConnected(toAdd, g);
}

/**
Expand Down
150 changes: 131 additions & 19 deletions src/io/github/ethankelly/graph/Vertex.java
Original file line number Diff line number Diff line change
@@ -1,36 +1,75 @@
package io.github.ethankelly.graph;

import io.github.ethankelly.symbols.Maths;

import java.util.List;
import java.util.Objects;
import java.util.stream.IntStream;


/**
* The {@code Vertex} class represents a vertex of a graph.
* The {@code VertexState} class represents an instance of a vertex being in a particular state in a compartmental
* epidemiological model. Each vertex object has a state (for instance, {@code 'S'} for "Susceptible") and a numerical
* location in the graph we are interested in.
*/
public class Vertex implements Comparable<Vertex> {
private int location;
private char state;

public Vertex(int location) {
this.location = location;
this.state = ' ';
}

public int getLocation() {
return location;
public Vertex(char state, int location) {
this.state = state;
this.location = location;
}

public void setLocation(int newLocation) {
this.location = newLocation;
/**
* Given a list of vertices (some tuple), this method checks whether all of the states are the same. If they are the
* same, we do not have to consider the associated equation of the tuple in the final system of equations that
* describes our compartmental model.
*
* @param toCheck the tuple we wish to verify has at least two different states in its elements.
* @return true if at least one vertex state is different to that of the others, false if they are all the same.
*/
public static boolean areStatesDifferent(List<Vertex> toCheck, boolean reqClosures) {
boolean statesDifferent = false;
// If there's only one vertex in the list, by definition we require it
// in the system of equations so we ensure this method returns true.
if (toCheck.size() == 1) statesDifferent = true;
else {
// We only need to find two different states to know that the states are
// at least not all the same, returning true.
for (Vertex v : toCheck) {
for (Vertex w : toCheck) {
if (v.getState() != w.getState()) {
statesDifferent = true;
break;
} else if (reqClosures) {
if ((v.getState() == 'S') || (w.getState() == 'S')) {
statesDifferent = true;
break;
}
}
}
}
}
return statesDifferent;
}

@Override
public String toString() {
return String.valueOf(location);
public char getState() {
return this.state;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;

Vertex vertex = (Vertex) o;
public int getLocation() {
return location;
}

return this.location == vertex.location;
public void setLocation(int newLocation) {
this.location = newLocation;
}

@Override
Expand All @@ -42,11 +81,6 @@ public Vertex clone() {
}
}

@Override
public int hashCode() {
return location;
}

/**
* Gives a method to compare two vertices. This comparison is done using the numerical index locations of the two
* vertices we wish to compare.
Expand Down Expand Up @@ -74,4 +108,82 @@ public int compareTo(Vertex that) {
return EQUAL;
}

/**
* Given some list of vertices (some tuple), this method checks whether the index locations of every element of the
* tuple are all distinct. If even two of the vertices have the same location, it is not a valid tuple for our
* purposes and we will not hve to consider the associated equation in the final system of equations that describes
* our compartmental model.
*
* @param vertices the tuple we wish to verify has no repeated vertex locations.
* @return true if no index location is repeated in the vertices, false otherwise.
*/
public static boolean areLocationsDifferent(List<Vertex> vertices) {
boolean locationsDifferent = true;
// Only need to find two vertices in the list with same index location
// to know we don't have a required tuple, returning false.
for (Vertex v : vertices) {
if (vertices.stream().anyMatch(w -> v.getLocation() == w.getLocation() && v != w)) {
locationsDifferent = false;
break;
}
}
return locationsDifferent;
}

/**
* Given some list of vertices (tuple), this method verifies that all of the vertices in the graph given are in fact
* connected. That is, we are only interested in a tuple of vertices that constitute some manner of path (cycle or
* such like) - if not, then we do not have to consider the associated equation in the final system of equations
* that describes our compartmental model and we can discount the given tuple.
*
* @param toCheck the tuple we wish to check constitutes some kind of path.
* @param g the graph in which the tuple exists.
* @return true if the tuple forms a path in some way, false otherwise.
*/
public static boolean areAllConnected(List<Vertex> toCheck, Graph g) {
// If there's only one vertex in the list, required in the system of equations - ensure this returns true.
// If more than one vertex, return whether they all have some path between them.
return toCheck.size() == 1 || IntStream.range(0, toCheck.size() - 1).allMatch(
i -> g.hasEdge(new Vertex(toCheck.get(i).getLocation()),
new Vertex(toCheck.get(i + 1).getLocation()))
);
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
Vertex that = (Vertex) o;
return getState() == that.getState() && getLocation() == that.getLocation();
}

@Override
public int hashCode() {
return Objects.hash(super.hashCode(), getState(), getLocation());
}

// @Override
// public int compareTo(VertexState that) {
// int comparison = 0;
// int stateComparison = String.valueOf(this.getState()).compareTo(String.valueOf(that.getState()));
// int locationComparison = Integer.compare(this.getLocation(), that.getLocation());
//
// if (stateComparison == locationComparison) comparison = stateComparison;
// else if (stateComparison == 0) comparison = locationComparison;
// else if (locationComparison == 0) comparison = stateComparison;
//
// return comparison;
// }


/**
* Represents a given vertex textually, for printing to standard output.
*
* @return a String representation of the vertex.
*/
@Override
public String toString() {
return Maths.LANGLE.uni() + this.getState() + this.getLocation() + Maths.RANGLE.uni();
}
}
Loading

0 comments on commit 7bf218a

Please sign in to comment.