CoevolutionGraphs.java 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. // Create some graphs/plots
  2. //
  3. // 1. Use log-file to create graph of fitness against time
  4. // 2. Use similarities to create a heat map of the different models
  5. // 3. Use multi-dimensional scaling to generate a 2D representation of models
  6. // - plot this with optional clustering
  7. //
  8. // TODO: Investigate if DBScan is a better way to get clusters
  9. import java.nio.file.Files;
  10. import java.nio.file.Path;
  11. import java.io.IOException;
  12. import java.io.Reader;
  13. import java.util.ArrayList;
  14. import java.util.List;
  15. import java.util.Optional;
  16. import mdsj.MDSJ;
  17. import org.apache.commons.csv.CSVFormat;
  18. import org.apache.commons.csv.CSVRecord;
  19. import org.apache.commons.math3.ml.clustering.KMeansPlusPlusClusterer;
  20. import org.apache.commons.math3.ml.clustering.Clusterable;
  21. import org.knowm.xchart.SwingWrapper;
  22. import org.knowm.xchart.HeatMapChart;
  23. import org.knowm.xchart.HeatMapChartBuilder;
  24. import org.knowm.xchart.HeatMapSeries;
  25. import org.knowm.xchart.XYChart;
  26. import org.knowm.xchart.XYChartBuilder;
  27. import org.knowm.xchart.XYSeries;
  28. import org.knowm.xchart.style.colors.XChartSeriesColors;
  29. import org.knowm.xchart.style.markers.SeriesMarkers;
  30. public class CoevolutionGraphs {
  31. public static void main (String[] args) {
  32. fitnessGraph(Path.of("log-baseline.csv"));
  33. heatmapGraph(Path.of("baseline-models.txt"));
  34. modelSimilarityGraph(Path.of("baseline-models.txt"), 3);
  35. }
  36. static void fitnessGraph(Path filepath) {
  37. try (Reader in = Files.newBufferedReader (filepath)) {
  38. // read in data
  39. List<LogFileEntry> data = CSVFormat.RFC4180.parse(in).stream()
  40. .map(LogFileEntry::fromCSVRecord)
  41. .flatMap(Optional::stream)
  42. .toList();
  43. // plot chart
  44. XYChart chart = new XYChartBuilder()
  45. .width(800)
  46. .height(600)
  47. .title("Fitness Against Generation: " + filepath.getFileName())
  48. .xAxisTitle("Generation")
  49. .yAxisTitle("Fitness")
  50. .build();
  51. chart.getStyler().setXAxisTickMarkSpacingHint(100);
  52. var xAxis = data.stream()
  53. .map(LogFileEntry::generation)
  54. .toList();
  55. var fitnessOverall = data.stream()
  56. .map(LogFileEntry::fitnessOverall)
  57. .toList();
  58. var fitnessAccuracy = data.stream()
  59. .map(LogFileEntry::fitnessAccuracy)
  60. .toList();
  61. var fitnessResponseTime = data.stream()
  62. .map(LogFileEntry::fitnessResponseTime)
  63. .toList();
  64. var fitnessProgramSize = data.stream()
  65. .map(LogFileEntry::fitnessProgramSize)
  66. .toList();
  67. XYSeries series = chart.addSeries("Fitness", xAxis, fitnessOverall);
  68. series.setLineColor(XChartSeriesColors.BLACK);
  69. series.setMarker(SeriesMarkers.NONE);
  70. series = chart.addSeries("Accuracy", xAxis, fitnessAccuracy);
  71. series.setLineColor(XChartSeriesColors.BLUE);
  72. series.setMarker(SeriesMarkers.NONE);
  73. series = chart.addSeries("Response Time", xAxis, fitnessResponseTime);
  74. series.setLineColor(XChartSeriesColors.RED);
  75. series.setMarker(SeriesMarkers.NONE);
  76. series = chart.addSeries("Program Size", xAxis, fitnessProgramSize);
  77. series.setLineColor(XChartSeriesColors.GREEN);
  78. series.setMarker(SeriesMarkers.NONE);
  79. new SwingWrapper<XYChart>(chart).displayChart();
  80. } catch (IOException ioe) {
  81. System.out.println("Exception: " + ioe);
  82. System.exit(-1);
  83. }
  84. }
  85. static void heatmapGraph (Path filepath) {
  86. var data = new ModelSimilarities (filepath);
  87. // plot chart
  88. HeatMapChart chart = new HeatMapChartBuilder()
  89. .width(800)
  90. .height(600)
  91. .title("Model Similarity: " + filepath.getFileName())
  92. .xAxisTitle("Individual")
  93. .yAxisTitle("Individual")
  94. .build();
  95. HeatMapSeries series = chart.addSeries("Similarities", data.xData, data.yData, data.similarities);
  96. new SwingWrapper<HeatMapChart>(chart).displayChart();
  97. }
  98. static void modelSimilarityGraph (Path filepath, int numClusters) {
  99. var data = new ModelSimilarities (filepath);
  100. var model = new KMeansPlusPlusClusterer<ModelSimilarities.Coord>(numClusters);
  101. var clusters = model.cluster (data.multiDimensionalScaling ());
  102. XYChart chart = new XYChartBuilder()
  103. .width(800)
  104. .height(600)
  105. .title("Model Similarity Visualisation: " + filepath.getFileName())
  106. .xAxisTitle("x")
  107. .yAxisTitle("y")
  108. .build();
  109. chart.getStyler().setDefaultSeriesRenderStyle(XYSeries.XYSeriesRenderStyle.Scatter);
  110. chart.getStyler().setLegendVisible(false);
  111. chart.getStyler().setMarkerSize(16);
  112. for (int c = 0; c < clusters.size (); c += 1) {
  113. var cluster = clusters.get (c);
  114. var xData = new double[cluster.getPoints().size ()];
  115. var yData = new double[cluster.getPoints().size ()];
  116. for (int i = 0; i < cluster.getPoints().size (); i += 1) {
  117. xData[i] = cluster.getPoints().get(i).x ();
  118. yData[i] = cluster.getPoints().get(i).y ();
  119. }
  120. chart.addSeries("Model Coordinate: " + c, xData, yData);
  121. }
  122. new SwingWrapper<XYChart>(chart).displayChart();
  123. }
  124. }
  125. record LogFileEntry(
  126. int generation,
  127. double fitnessOverall,
  128. double accuracy,
  129. double fitnessAccuracy,
  130. double responseTime,
  131. double fitnessResponseTime,
  132. double programSize,
  133. double fitnessProgramSize,
  134. double phase
  135. ) {
  136. static Optional<LogFileEntry> fromCSVRecord (CSVRecord record) {
  137. if (record.size() == 9) { // ensure we have enough parts
  138. try {
  139. int generation = Integer.parseInt(record.get(0));
  140. double fitnessOverall = Double.parseDouble(record.get(1));
  141. double accuracy = Double.parseDouble(record.get(2));
  142. double fitnessAccuracy = Double.parseDouble(record.get(3));
  143. double responseTime = Double.parseDouble(record.get(4));
  144. double fitnessResponseTime = Double.parseDouble(record.get(5));
  145. double programSize = Double.parseDouble(record.get(6));
  146. double fitnessProgramSize = Double.parseDouble(record.get(7));
  147. double phase = Double.parseDouble(record.get(8));
  148. return Optional.of(new LogFileEntry(
  149. generation,
  150. fitnessOverall,
  151. accuracy,
  152. fitnessAccuracy,
  153. responseTime,
  154. fitnessResponseTime,
  155. programSize,
  156. fitnessProgramSize,
  157. phase
  158. ));
  159. } catch (NumberFormatException e) {
  160. System.out.println("Exception: " + e);
  161. }
  162. }
  163. return Optional.empty();
  164. }
  165. }
  166. class ModelSimilarities {
  167. int[] xData;
  168. int[] yData;
  169. int[][] similarities;
  170. double[][] dissimilarities;
  171. ModelSimilarities (Path filepath) {
  172. try (Reader in = Files.newBufferedReader (filepath)) {
  173. // read in data
  174. List<ModelSimilarityEntry> data = CSVFormat.Builder
  175. .create(CSVFormat.RFC4180)
  176. .setDelimiter(' ')
  177. .build()
  178. .parse(in).stream()
  179. .map(ModelSimilarityEntry::fromCSVRecord)
  180. .flatMap(Optional::stream)
  181. .toList();
  182. xData = data.stream()
  183. .map(ModelSimilarityEntry::modelX)
  184. .distinct()
  185. .sorted()
  186. .mapToInt(i->i)
  187. .toArray();
  188. yData = data.stream()
  189. .map(ModelSimilarityEntry::modelY)
  190. .distinct()
  191. .sorted()
  192. .mapToInt(i->i)
  193. .toArray();
  194. similarities = new int[xData.length][yData.length];
  195. dissimilarities = new double[xData.length][yData.length];
  196. for (var entry : data) {
  197. similarities[entry.modelX()][entry.modelY()] = (int)Math.round(100 * entry.similarity());
  198. dissimilarities[entry.modelX()][entry.modelY()] = 1.0 - entry.similarity();
  199. }
  200. } catch (IOException ioe) {
  201. System.out.println("Model Similarities exception: " + ioe);
  202. System.exit(-1);
  203. }
  204. }
  205. List<Coord> multiDimensionalScaling () {
  206. var coords = MDSJ.classicalScaling(dissimilarities);
  207. var result = new ArrayList<Coord> ();
  208. for (int i = 0; i < coords[0].length; i += 1) {
  209. result.add (new Coord(coords[0][i], coords[1][i], new double[]{coords[0][i], coords[1][i]}));
  210. }
  211. return result;
  212. }
  213. record Coord(
  214. double x,
  215. double y,
  216. double[] point
  217. ) implements Clusterable {
  218. public double[] getPoint () {
  219. return point;
  220. }
  221. }
  222. record ModelSimilarityEntry(
  223. int modelX,
  224. int modelY,
  225. double similarity
  226. ) {
  227. static Optional<ModelSimilarityEntry> fromCSVRecord (CSVRecord record) {
  228. if (record.size() == 3) { // ensure we have enough parts
  229. try {
  230. int modelX = Integer.parseInt(record.get(0));
  231. int modelY = Integer.parseInt(record.get(1));
  232. double similarity = Double.parseDouble(record.get(2));
  233. return Optional.of(new ModelSimilarityEntry(
  234. modelX,
  235. modelY,
  236. similarity
  237. ));
  238. } catch (NumberFormatException e) {
  239. System.out.println("Exception: " + e);
  240. }
  241. }
  242. return Optional.empty();
  243. }
  244. }
  245. }