diff --git a/.idea/misc.xml b/.idea/misc.xml index dd5f484..d4b854b 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -3,5 +3,7 @@ - + + + \ No newline at end of file diff --git a/README.md b/README.md index bfff7e5..92399bb 100644 --- a/README.md +++ b/README.md @@ -44,4 +44,4 @@ See also the list of [contributors](https://github.com/neuralm/Neuralm-Java-Clie ## License -This project is licensed under the MIT License - see the [LICENSE.md](LICENSE.md) file for details +This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details diff --git a/src/main/java/net/neuralm/client/NeuralmClient.java b/src/main/java/net/neuralm/client/NeuralmClient.java index c80b868..1a8005f 100644 --- a/src/main/java/net/neuralm/client/NeuralmClient.java +++ b/src/main/java/net/neuralm/client/NeuralmClient.java @@ -31,10 +31,10 @@ public class NeuralmClient { private final int port; private final ISerializer serializer; private final ReadHandler readHandler; - AtomicBoolean isWriting = new AtomicBoolean(false); + final AtomicBoolean isWriting = new AtomicBoolean(false); private AsynchronousTlsChannel channel; private ByteBuffer writeBuffer = ByteBuffer.allocate(0); - private Queue sendQueue = new LinkedBlockingDeque<>(); + private final Queue sendQueue = new LinkedBlockingDeque<>(); /** diff --git a/src/main/java/net/neuralm/client/ReadHandler.java b/src/main/java/net/neuralm/client/ReadHandler.java index 469518c..026c136 100644 --- a/src/main/java/net/neuralm/client/ReadHandler.java +++ b/src/main/java/net/neuralm/client/ReadHandler.java @@ -1,18 +1,21 @@ package net.neuralm.client; -import java.nio.ByteBuffer; -import java.nio.channels.CompletionHandler; import net.neuralm.client.messages.Message; import net.neuralm.client.messages.MessageHeader; import net.neuralm.client.messages.responses.Response; import net.neuralm.client.messages.serializer.ISerializer; +import java.nio.ByteBuffer; +import java.nio.channels.CompletionHandler; + public class ReadHandler implements CompletionHandler { private final NeuralmClient client; MessageHeader currentHeader; - ISerializer serializer; + final ISerializer serializer; + + ByteBuffer currentBody; public ReadHandler(NeuralmClient client, ISerializer serializer) { this.client = client; @@ -36,19 +39,24 @@ public void completed(Integer result, ByteBuffer attachment) { } client.startReading(currentHeader.getBodySize()); + currentBody = ByteBuffer.allocate(currentHeader.getBodySize()); } else { + currentBody.put(bytes); + client.startReading(); - Object response = Message.deconstructMessageBody(serializer, currentHeader, bytes); - if (response instanceof Response) { - client.addResponse((Response) response); - } else { - System.err.println(String.format("Received response that wasn't a response! Bytes: %s", bytes)); - } + if (currentBody.position() == currentBody.capacity()) { + Object response = Message.deconstructMessageBody(serializer, currentHeader, currentBody.array()); - currentHeader = null; - } + if (response instanceof Response) { + client.addResponse((Response) response); + } else { + System.err.println(String.format("Received response that wasn't a response! Bytes: %s", currentBody.array())); + } + currentHeader = null; + } + } } @Override diff --git a/src/main/java/net/neuralm/client/entities/TrainingSession.java b/src/main/java/net/neuralm/client/entities/TrainingSession.java index 7a5384e..5895ebe 100644 --- a/src/main/java/net/neuralm/client/entities/TrainingSession.java +++ b/src/main/java/net/neuralm/client/entities/TrainingSession.java @@ -1,14 +1,15 @@ package net.neuralm.client.entities; -import java.util.UUID; import net.neuralm.client.neat.TrainingRoom; +import java.util.UUID; + public class TrainingSession { - public UUID Id; - public String StartedTimestamp; - public String EndedTimestamp; //TODO: Make this an actual date object if possible, or maybe unix time - public UUID UserId; + public UUID id; + public String startedTimestamp; + public String endedTimestamp; //TODO: Make this an actual date object if possible, or maybe unix time + public UUID userId; public TrainingRoom trainingRoom; } diff --git a/src/main/java/net/neuralm/client/messages/Message.java b/src/main/java/net/neuralm/client/messages/Message.java index 360a362..992699e 100644 --- a/src/main/java/net/neuralm/client/messages/Message.java +++ b/src/main/java/net/neuralm/client/messages/Message.java @@ -1,9 +1,10 @@ package net.neuralm.client.messages; +import net.neuralm.client.messages.serializer.ISerializer; + import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.charset.StandardCharsets; -import net.neuralm.client.messages.serializer.ISerializer; public class Message { @@ -15,6 +16,13 @@ private Message(byte[] headerBytes, byte[] bodyBytes) { this.bodyBytes = bodyBytes; } + /** + * Construct a message object from the given object with the given serializer. + * It will be turned into bytes and a header will be created. + * @param serializer The serializer to use. + * @param message The object that should be turned into a message + * @return The message with the headerBytes and bodyBytes. + */ public static Message constructMessage(ISerializer serializer, Object message) { byte[] bodyBytes = serializer.serialize(message); byte[] messageTypeBytes = message.getClass().getSimpleName().getBytes(StandardCharsets.UTF_8); @@ -25,6 +33,14 @@ public static Message constructMessage(ISerializer serializer, Object message) { return new Message(headerBytes, bodyBytes); } + /** + * Turn a byte array representing an object into that object. + * It will deserialize the bytes using the given serializer. + * @param serializer The serializer to use. + * @param header The header corresponding to the data being deserialized. + * @param bodyBytes The data to deserialize + * @return null if the serializer fails or no class corresponding to {@link MessageHeader#getTypeName()} is found. + */ public static Object deconstructMessageBody(ISerializer serializer, MessageHeader header, byte[] bodyBytes) { Class clazz; try { diff --git a/src/main/java/net/neuralm/client/messages/MessageHeader.java b/src/main/java/net/neuralm/client/messages/MessageHeader.java index bac7c48..9a11138 100644 --- a/src/main/java/net/neuralm/client/messages/MessageHeader.java +++ b/src/main/java/net/neuralm/client/messages/MessageHeader.java @@ -7,7 +7,7 @@ public class MessageHeader { private final int bodySize; - private String typeName; + private final String typeName; private MessageHeader(int bodySize, String typeName) { this.bodySize = bodySize; diff --git a/src/main/java/net/neuralm/client/messages/requests/GetOrganismsRequest.java b/src/main/java/net/neuralm/client/messages/requests/GetOrganismsRequest.java index 0aae376..289c042 100644 --- a/src/main/java/net/neuralm/client/messages/requests/GetOrganismsRequest.java +++ b/src/main/java/net/neuralm/client/messages/requests/GetOrganismsRequest.java @@ -4,9 +4,9 @@ public class GetOrganismsRequest extends Request { - public UUID trainingSessionID; + public final UUID trainingSessionID; - public int amount; + public final int amount; public GetOrganismsRequest(UUID trainingSessionID, int amount) { this.trainingSessionID = trainingSessionID; diff --git a/src/main/java/net/neuralm/client/messages/requests/PostOrganismsScoreRequest.java b/src/main/java/net/neuralm/client/messages/requests/PostOrganismsScoreRequest.java index 8958057..e8a46fe 100644 --- a/src/main/java/net/neuralm/client/messages/requests/PostOrganismsScoreRequest.java +++ b/src/main/java/net/neuralm/client/messages/requests/PostOrganismsScoreRequest.java @@ -1,16 +1,17 @@ package net.neuralm.client.messages.requests; +import net.neuralm.client.neat.Organism; + import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.UUID; -import net.neuralm.client.neat.Organism; public class PostOrganismsScoreRequest extends Request { - public UUID trainingSessionId; + public final UUID trainingSessionId; - public Map organismScores; + public final Map organismScores; /** * Create a PostOrganismsScoreRequest to send the organisms' score to the server @@ -33,7 +34,7 @@ public PostOrganismsScoreRequest(UUID trainingSessionId, List organism this(trainingSessionId, new HashMap<>(organisms.size())); for (Organism organism : organisms) { - organismScores.put(organism.id, organism.score); + organismScores.put(organism.getId(), organism.getScore()); } } } diff --git a/src/main/java/net/neuralm/client/messages/requests/Request.java b/src/main/java/net/neuralm/client/messages/requests/Request.java index fa0a78b..6abcda9 100644 --- a/src/main/java/net/neuralm/client/messages/requests/Request.java +++ b/src/main/java/net/neuralm/client/messages/requests/Request.java @@ -14,6 +14,7 @@ public class Request { public Request() { id = UUID.randomUUID(); ZonedDateTime now = ZonedDateTime.now(ZoneOffset.UTC); + //noinspection SpellCheckingInspection date = now.format(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss'.'SSSSSSS'Z'")); } diff --git a/src/main/java/net/neuralm/client/messages/responses/Response.java b/src/main/java/net/neuralm/client/messages/responses/Response.java index dfc293b..fe954d7 100644 --- a/src/main/java/net/neuralm/client/messages/responses/Response.java +++ b/src/main/java/net/neuralm/client/messages/responses/Response.java @@ -30,6 +30,7 @@ public UUID getRequestId() { * The time date this response was send. * @return The date as a string in the following format: "yyyy-MM-dd'T'HH:mm:ss'.'SSSSSSS'Z'" */ + @SuppressWarnings("SpellCheckingInspection") public String getDateTime() { return dateTime; } diff --git a/src/main/java/net/neuralm/client/messages/serializer/JsonSerializer.java b/src/main/java/net/neuralm/client/messages/serializer/JsonSerializer.java index 06c1016..0320657 100644 --- a/src/main/java/net/neuralm/client/messages/serializer/JsonSerializer.java +++ b/src/main/java/net/neuralm/client/messages/serializer/JsonSerializer.java @@ -3,6 +3,8 @@ import com.google.gson.FieldNamingPolicy; import com.google.gson.Gson; import com.google.gson.GsonBuilder; +import com.google.gson.JsonSyntaxException; + import java.nio.charset.StandardCharsets; public class JsonSerializer implements ISerializer { @@ -13,6 +15,9 @@ public JsonSerializer() { this.gson = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE).create(); } + /** + * {@inheritDoc} + */ @Override public byte[] serialize(Object message) { String json = gson.toJson(message); @@ -20,10 +25,21 @@ public byte[] serialize(Object message) { return json.getBytes(StandardCharsets.UTF_8); } + /** + * {@inheritDoc} + * + * @return The deserialized object, or null if a {@link JsonSyntaxException} occurred. + */ @Override public T deserialize(byte[] bytes, Class type) { String json = new String(bytes, StandardCharsets.UTF_8); - return gson.fromJson(json, type); + try { + return gson.fromJson(json, type); + } catch (JsonSyntaxException exception) { + System.err.println(json); + exception.printStackTrace(); + return null; + } } } diff --git a/src/main/java/net/neuralm/client/neat/Brain.java b/src/main/java/net/neuralm/client/neat/Brain.java deleted file mode 100644 index 761614a..0000000 --- a/src/main/java/net/neuralm/client/neat/Brain.java +++ /dev/null @@ -1,119 +0,0 @@ -package net.neuralm.client.neat; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.UUID; -import net.neuralm.client.neat.neurons.AbstractNeuron; -import net.neuralm.client.neat.neurons.HiddenNeuron; -import net.neuralm.client.neat.neurons.InputNeuron; -import net.neuralm.client.neat.neurons.OutputNeuron; - -public class Brain { - - UUID id; - UUID trainingRoomId; - UUID organismId; - private List connectionGenes = new ArrayList<>(); - - private final List outputNeurons = new ArrayList<>(); - private final List inputNeurons = new ArrayList<>(); - private final HashMap neurons = new HashMap<>(); - - private boolean buildStructure = false; - private TrainingRoom trainingRoom; - private Organism organism; - - public Brain() { - - } - - /** - * Create a brain with the given trainingRoom and the given genes. - * - * @param trainingRoom The trainingRoom this brain is part of - * @param genes Amount of genes - */ - public Brain(TrainingRoom trainingRoom, List genes) { - this.trainingRoom = trainingRoom; - this.connectionGenes = genes; - } - - /** - * Evaluate the brain with the given inputs - * - * @param inputs A double array with the size {@link TrainingRoomSettings#getInputCount()} - * @return A double array with size {@link TrainingRoomSettings#getOutputCount()} where index i has the output value of the output neuron with id {@link TrainingRoomSettings#getInputCount}+i - */ - public double[] evaluate(double[] inputs) { - if (trainingRoom == null) { - throw new NullPointerException("trainingRoom is null, make sure Organism#initialize is called!"); - } - - if (!buildStructure) { - for (int i = 0; i < trainingRoom.trainingRoomSettings.getInputCount(); i++) { - InputNeuron neuron = new InputNeuron(); - inputNeurons.add(neuron); - neurons.put(i, neuron); - } - - for (int i = 0; i < trainingRoom.trainingRoomSettings.getOutputCount(); i++) { - OutputNeuron neuron = new OutputNeuron(); - outputNeurons.add(neuron); - neurons.put(trainingRoom.trainingRoomSettings.getInputCount() + i, neuron); - } - - for (ConnectionGene connectionGene : connectionGenes) { - connectionGene.initializeStructure(this); - } - buildStructure = true; - } - - if (inputs.length != inputNeurons.size()) { - throw new IllegalArgumentException(String.format("Input size %s does not match number of input neurons %s", inputs.length, inputNeurons.size())); - } - - for (int i = 0; i < inputNeurons.size(); i++) { - inputNeurons.get(i).setValue(inputs[i]); - } - - double[] outputs = new double[outputNeurons.size()]; - for (int i = 0; i < outputNeurons.size(); i++) { - outputs[i] = outputNeurons.get(i).getValue(); - } - - return outputs; - } - - /** - * Get a neuron with the given id or generate a new one if none exist. - * - * @param neuronId The neuron's id - * @return A neuron - */ - AbstractNeuron getNeuronOrCreate(int neuronId) { - if (!neurons.containsKey(neuronId)) { - neurons.put(neuronId, new HiddenNeuron()); - } - - return neurons.get(neuronId); - } - - /** - * Initialize the brain, this will make sure it is ready to be used. - * - * @param trainingRoom The trainingroom this brain is in. - * @param organism The organism whose brain this is - */ - public void initialize(TrainingRoom trainingRoom, Organism organism) { - if (!trainingRoom.id.equals(trainingRoomId)) { - throw new IllegalArgumentException(String.format("The given trainingRoomID %s does not match the expected trainingRoomID %s", trainingRoom.id, id)); - } - if (!organism.id.equals(organismId)) { - throw new IllegalArgumentException(String.format("The given organismId %s does not match the expected organismId %s", organism.id, organismId)); - } - - this.trainingRoom = trainingRoom; - this.organism = organism; - } -} diff --git a/src/main/java/net/neuralm/client/neat/ConnectionGene.java b/src/main/java/net/neuralm/client/neat/ConnectionGene.java index 97ede6e..20e6143 100644 --- a/src/main/java/net/neuralm/client/neat/ConnectionGene.java +++ b/src/main/java/net/neuralm/client/neat/ConnectionGene.java @@ -1,42 +1,59 @@ package net.neuralm.client.neat; +import net.neuralm.client.neat.nodes.AbstractNode; + import java.util.UUID; -import net.neuralm.client.neat.neurons.AbstractNeuron; public class ConnectionGene { private UUID id; - private UUID brainId; - private int inID; - private int outID; + private UUID organismId; private int innovationNumber; - private double weight; - private boolean enabled; - private AbstractNeuron inputNeuron; - private AbstractNeuron outputNeuron; + public final int inNodeIdentifier; + public final int outNodeIdentifier; + public final double weight; + public final boolean enabled; - public ConnectionGene() { + private AbstractNode in; + private AbstractNode out; + public ConnectionGene(int inNodeIdentifier, int outNodeIdentifier, double weight, boolean enabled, int innovationNumber, UUID id, UUID organismId) { + this(inNodeIdentifier, outNodeIdentifier, weight, enabled); + this.id = id; + this.organismId = organismId; + this.innovationNumber = innovationNumber; } - public ConnectionGene(int inId, int outId, double weight, boolean enabled) { - this.inID = inId; - this.outID = outId; + public ConnectionGene(int inNodeIdentifier, int outNodeIdentifier, double weight, boolean enabled) { + this.inNodeIdentifier = inNodeIdentifier; + this.outNodeIdentifier = outNodeIdentifier; this.weight = weight; this.enabled = enabled; } + public void buildStructure(Organism organism) { + if (!enabled) return; + + this.in = organism.getNodeFromIdentifier(inNodeIdentifier); + this.out = organism.getNodeFromIdentifier(outNodeIdentifier); + this.out.addDependency(this); + } + public double getValue() { - return inputNeuron.getValue() * weight; + return in.getValue() * weight; } - void initializeStructure(Brain brain) { - if (enabled) { - inputNeuron = brain.getNeuronOrCreate(inID); - outputNeuron = brain.getNeuronOrCreate(outID); + public UUID getId() { + return id; + } + + public UUID getOrganismId() { + return organismId; + } - outputNeuron.addDependency(this); - } + public int getInnovationNumber() { + return innovationNumber; } + } diff --git a/src/main/java/net/neuralm/client/neat/Organism.java b/src/main/java/net/neuralm/client/neat/Organism.java index 6a76085..4f2ef66 100644 --- a/src/main/java/net/neuralm/client/neat/Organism.java +++ b/src/main/java/net/neuralm/client/neat/Organism.java @@ -1,42 +1,155 @@ package net.neuralm.client.neat; -import java.util.UUID; +import net.neuralm.client.neat.nodes.AbstractNode; +import net.neuralm.client.neat.nodes.HiddenNode; +import net.neuralm.client.neat.nodes.InputNode; +import net.neuralm.client.neat.nodes.OutputNode; + +import java.util.*; public class Organism { - public UUID id; + private final List connectionGenes; + private final List inputNodes; + private final List outputNodes; + private List hiddenNodes; + private UUID id; + private double score; + private String name; + private int generation; - public UUID speciesId; + public Organism(List connectionGenes, int inputCount, int outputCount, UUID id, double score, String name, int generation) { + this(connectionGenes, inputCount, outputCount); + this.id = id; + this.score = score; + this.name = name; + this.generation = generation; + } - public UUID brainId; + public Organism(List connectionGenes, int inputCount, int outputCount) { + this.connectionGenes = connectionGenes; - public UUID trainingRoomId; + this.inputNodes = new ArrayList<>(); + this.outputNodes = new ArrayList<>(); - public Brain brain; + for (int i = 0; i < inputCount; i++) { + InputNode a = new InputNode(i); + this.inputNodes.add(a); + } - public double score; + for (int i = 0; i < outputCount; i++) { + OutputNode a = new OutputNode(i + inputCount); + this.outputNodes.add(a); + } - public String name; + this.initialize(); + } - public int generation; + public List getInputNodes() { + return Collections.unmodifiableList(inputNodes); + } - TrainingRoom trainingRoom; + public List getOutputNodes() { + return Collections.unmodifiableList(outputNodes); + } + + public List getHiddenNodes() { + return Collections.unmodifiableList(hiddenNodes); + } + + public UUID getId() { + return id; + } + + public String getName() { + return name; + } + + public int getGeneration() { + return generation; + } + + public double getScore() { + return score; + } + + public void setScore(double score) { + this.score = score; + } + + public int getInputCount() { + return inputNodes.size(); + } + + public int getOutputCount() { + return outputNodes.size(); + } + + public List getConnectionGenes() { + return Collections.unmodifiableList(connectionGenes); + } /** - * Initialize the organism, this will set its trainingRoom and make sure the brain is ready to be used. + * Initialize the organism so it can be used. + * This will build the internal brain structure. + */ + public void initialize() { + for (ConnectionGene connectionGene : connectionGenes) { + connectionGene.buildStructure(this); + } + } + + /** + * Evaluate the organism, this will give the internal brain the given inputs and calculate the outputs. * - * @param trainingRoom The trainingroom this organism is part of. + * @param inputs The inputs for the brain. + * @return A double array with size of {@link #outputNodes} */ - public void initialize(TrainingRoom trainingRoom) { - if (!trainingRoom.id.equals(trainingRoomId)) { - throw new IllegalArgumentException(String.format("The given trainingRoomID %s does not match the expected trainingRoomID %s", trainingRoom.id, id)); + public double[] evaluate(double[] inputs) { + if (inputs.length != inputNodes.size()) { + throw new IllegalArgumentException(String.format("inputs length ( %s ) should match inputnodes length ( %s )", inputs.length, inputNodes.size())); } - this.trainingRoom = trainingRoom; - this.brain.initialize(trainingRoom, this); + for (int i = 0; i < inputs.length; i++) { + inputNodes.get(i).setValue(inputs[i]); + } + + double[] outputs = new double[outputNodes.size()]; + + for (int i = 0; i < outputNodes.size(); i++) { + outputs[i] = outputNodes.get(i).getValue(); + } + + return outputs; } - public double[] evaluate(double[] inputs) { - return this.brain.evaluate(inputs); + AbstractNode getNodeFromIdentifier(int nodeIdentifier) { + Optional optional = inputNodes.stream().filter(n -> n.nodeIdentifier == nodeIdentifier).findAny(); + + if (optional.isPresent()) { + return optional.get(); + } + + Optional outputNode = outputNodes.stream().filter(n -> n.nodeIdentifier == nodeIdentifier).findAny(); + + if (outputNode.isPresent()) { + return outputNode.get(); + } + + if (hiddenNodes == null) { + hiddenNodes = new ArrayList<>(); + } + + return hiddenNodes.stream().filter(n -> n.nodeIdentifier == nodeIdentifier).findAny().orElseGet( + () -> createAndAddNode(nodeIdentifier) + ); + } + + private HiddenNode createAndAddNode(int nodeIdentifier) { + HiddenNode node = new HiddenNode(nodeIdentifier); + + hiddenNodes.add(node); + + return node; } } diff --git a/src/main/java/net/neuralm/client/neat/TrainingRoom.java b/src/main/java/net/neuralm/client/neat/TrainingRoom.java index 5d5c8c8..63c1426 100644 --- a/src/main/java/net/neuralm/client/neat/TrainingRoom.java +++ b/src/main/java/net/neuralm/client/neat/TrainingRoom.java @@ -1,8 +1,9 @@ package net.neuralm.client.neat; -import java.util.UUID; import net.neuralm.client.entities.User; +import java.util.UUID; + public class TrainingRoom { public UUID id; @@ -10,8 +11,5 @@ public class TrainingRoom { public User owner; public int generation; public TrainingRoomSettings trainingRoomSettings; - public double highestScore; - public double lowestScore; - public double averageScore; } diff --git a/src/main/java/net/neuralm/client/neat/TrainingRoomSettings.java b/src/main/java/net/neuralm/client/neat/TrainingRoomSettings.java index 882f3d7..ec8b384 100644 --- a/src/main/java/net/neuralm/client/neat/TrainingRoomSettings.java +++ b/src/main/java/net/neuralm/client/neat/TrainingRoomSettings.java @@ -5,15 +5,15 @@ public class TrainingRoomSettings { - static Random random = new Random(); + static final Random random = new Random(); private UUID id = UUID.randomUUID(); private int organismCount = 100; private int inputCount = 3; private int outputCount = 1; - private double c1 = 1; - private double c2 = 0.4; - private double c3 = 0.4; + private double speciesExcessGeneWeight = 1; + private double speciesDisjointGeneWeight = 0.4; + private double speciesAverageWeightDiffWeight = 0.4; private double threshold = 3; private double addConnectionChance = 0.05; private double addNodeChance = 0.03; @@ -62,30 +62,30 @@ public TrainingRoomSettings setOutputCount(int outputCount) { return this; } - public double getC1() { - return c1; + public double getSpeciesExcessGeneWeight() { + return speciesExcessGeneWeight; } - public TrainingRoomSettings setC1(double c1) { - this.c1 = c1; + public TrainingRoomSettings setSpeciesExcessGeneWeight(double speciesExcessGeneWeight) { + this.speciesExcessGeneWeight = speciesExcessGeneWeight; return this; } - public double getC2() { - return c2; + public double getSpeciesDisjointGeneWeight() { + return speciesDisjointGeneWeight; } - public TrainingRoomSettings setC2(double c2) { - this.c2 = c2; + public TrainingRoomSettings setSpeciesDisjointGeneWeight(double speciesDisjointGeneWeight) { + this.speciesDisjointGeneWeight = speciesDisjointGeneWeight; return this; } - public double getC3() { - return c3; + public double getSpeciesAverageWeightDiffWeight() { + return speciesAverageWeightDiffWeight; } - public TrainingRoomSettings setC3(double c3) { - this.c3 = c3; + public TrainingRoomSettings setSpeciesAverageWeightDiffWeight(double speciesAverageWeightDiffWeight) { + this.speciesAverageWeightDiffWeight = speciesAverageWeightDiffWeight; return this; } diff --git a/src/main/java/net/neuralm/client/neat/neurons/HiddenNeuron.java b/src/main/java/net/neuralm/client/neat/neurons/HiddenNeuron.java deleted file mode 100644 index 932d537..0000000 --- a/src/main/java/net/neuralm/client/neat/neurons/HiddenNeuron.java +++ /dev/null @@ -1,5 +0,0 @@ -package net.neuralm.client.neat.neurons; - -public class HiddenNeuron extends AbstractNeuron { - -} diff --git a/src/main/java/net/neuralm/client/neat/neurons/OutputNeuron.java b/src/main/java/net/neuralm/client/neat/neurons/OutputNeuron.java deleted file mode 100644 index 64ddccf..0000000 --- a/src/main/java/net/neuralm/client/neat/neurons/OutputNeuron.java +++ /dev/null @@ -1,5 +0,0 @@ -package net.neuralm.client.neat.neurons; - -public class OutputNeuron extends AbstractNeuron { - -} diff --git a/src/main/java/net/neuralm/client/neat/neurons/AbstractNeuron.java b/src/main/java/net/neuralm/client/neat/nodes/AbstractNode.java similarity index 55% rename from src/main/java/net/neuralm/client/neat/neurons/AbstractNeuron.java rename to src/main/java/net/neuralm/client/neat/nodes/AbstractNode.java index feadad3..d72c9fb 100644 --- a/src/main/java/net/neuralm/client/neat/neurons/AbstractNeuron.java +++ b/src/main/java/net/neuralm/client/neat/nodes/AbstractNode.java @@ -1,14 +1,29 @@ -package net.neuralm.client.neat.neurons; +package net.neuralm.client.neat.nodes; + +import net.neuralm.client.neat.ConnectionGene; import java.util.ArrayList; import java.util.List; -import net.neuralm.client.neat.ConnectionGene; -public abstract class AbstractNeuron { +public abstract class AbstractNode { + + public final int nodeIdentifier; + private List dependencies; + + public AbstractNode() { + this(-1); + } - private List dependencies = new ArrayList(); + AbstractNode(int nodeIdentifier) { + this.dependencies = new ArrayList<>(); + this.nodeIdentifier = nodeIdentifier; + } public double getValue() { + if(dependencies == null) { + dependencies = new ArrayList<>(); + } + if (dependencies.size() == 0) { return activationFunction(0); } @@ -19,6 +34,7 @@ public double getValue() { for (ConnectionGene gene : dependencies) { total += gene.getValue(); count++; + } return activationFunction(total / count); @@ -29,6 +45,10 @@ private double activationFunction(double x) { } public void addDependency(ConnectionGene connectionGene) { + if(dependencies == null) { + dependencies = new ArrayList<>(); + } + dependencies.add(connectionGene); } } diff --git a/src/main/java/net/neuralm/client/neat/nodes/HiddenNode.java b/src/main/java/net/neuralm/client/neat/nodes/HiddenNode.java new file mode 100644 index 0000000..97e5625 --- /dev/null +++ b/src/main/java/net/neuralm/client/neat/nodes/HiddenNode.java @@ -0,0 +1,8 @@ +package net.neuralm.client.neat.nodes; + +public class HiddenNode extends AbstractNode { + + public HiddenNode(int nodeIdentifier) { + super(nodeIdentifier); + } +} diff --git a/src/main/java/net/neuralm/client/neat/neurons/InputNeuron.java b/src/main/java/net/neuralm/client/neat/nodes/InputNode.java similarity index 60% rename from src/main/java/net/neuralm/client/neat/neurons/InputNeuron.java rename to src/main/java/net/neuralm/client/neat/nodes/InputNode.java index 881bcaa..1852868 100644 --- a/src/main/java/net/neuralm/client/neat/neurons/InputNeuron.java +++ b/src/main/java/net/neuralm/client/neat/nodes/InputNode.java @@ -1,11 +1,15 @@ -package net.neuralm.client.neat.neurons; +package net.neuralm.client.neat.nodes; import net.neuralm.client.neat.ConnectionGene; -public class InputNeuron extends AbstractNeuron { +public class InputNode extends AbstractNode { private double value; + public InputNode(int nodeIdentifier) { + super(nodeIdentifier); + } + @Override public double getValue() { return value; @@ -18,5 +22,6 @@ public void setValue(double value) { @Override public void addDependency(ConnectionGene connectionGene) { System.err.println("Trying to add a dependency to an input!"); + throw new IllegalArgumentException("Trying to add a dependency to an input!"); } } diff --git a/src/main/java/net/neuralm/client/neat/nodes/OutputNode.java b/src/main/java/net/neuralm/client/neat/nodes/OutputNode.java new file mode 100644 index 0000000..b4cae39 --- /dev/null +++ b/src/main/java/net/neuralm/client/neat/nodes/OutputNode.java @@ -0,0 +1,8 @@ +package net.neuralm.client.neat.nodes; + +public class OutputNode extends AbstractNode { + + public OutputNode(int nodeIdentifier) { + super(nodeIdentifier); + } +} diff --git a/src/test/java/net/neuralm/client/NeuralmClientMain.java b/src/test/java/net/neuralm/client/NeuralmClientMain.java index 107e15d..742339e 100644 --- a/src/test/java/net/neuralm/client/NeuralmClientMain.java +++ b/src/test/java/net/neuralm/client/NeuralmClientMain.java @@ -1,36 +1,22 @@ package net.neuralm.client; -import java.io.IOException; -import java.util.Arrays; -import java.util.Random; -import java.util.UUID; import net.neuralm.client.entities.TrainingSession; -import net.neuralm.client.messages.requests.AuthenticateRequest; -import net.neuralm.client.messages.requests.CreateTrainingRoomRequest; -import net.neuralm.client.messages.requests.EndTrainingSessionRequest; -import net.neuralm.client.messages.requests.GetEnabledTrainingRoomsRequest; -import net.neuralm.client.messages.requests.GetOrganismsRequest; -import net.neuralm.client.messages.requests.PostOrganismsScoreRequest; -import net.neuralm.client.messages.requests.RegisterRequest; -import net.neuralm.client.messages.requests.Request; -import net.neuralm.client.messages.requests.StartTrainingSessionRequest; -import net.neuralm.client.messages.responses.AuthenticateResponse; -import net.neuralm.client.messages.responses.CreateTrainingRoomResponse; -import net.neuralm.client.messages.responses.GetEnabledTrainingRoomsResponse; -import net.neuralm.client.messages.responses.GetOrganismsResponse; -import net.neuralm.client.messages.responses.PostOrganismsScoreResponse; -import net.neuralm.client.messages.responses.Response; -import net.neuralm.client.messages.responses.StartTrainingSessionResponse; +import net.neuralm.client.messages.requests.*; +import net.neuralm.client.messages.responses.*; import net.neuralm.client.messages.serializer.JsonSerializer; import net.neuralm.client.neat.Organism; import net.neuralm.client.neat.TrainingRoom; import net.neuralm.client.neat.TrainingRoomSettings; +import java.io.IOException; +import java.util.Random; +import java.util.UUID; + public class NeuralmClientMain { private static UUID userId; private static TrainingSession trainingSession; - private static int i; + private static int organismBatchesProcessed; public static void main(String... args) throws IOException, InterruptedException { String host = args.length >= 1 ? args[0] : "127.0.0.1"; @@ -54,7 +40,8 @@ public static void main(String... args) throws IOException, InterruptedException System.out.println(response.isSuccess() ? "Authenticated..." : String.format("Authenticating failed: %s", response.getMessage())); userId = response.getUserId(); System.out.println(String.format("Creating room with name %s", trainingRoomName)); - client.send(new CreateTrainingRoomRequest(response.getUserId(), trainingRoomName, new TrainingRoomSettings().setOrganismCount(20).setInputCount(3).setOutputCount(1))); + client.send(new CreateTrainingRoomRequest(response.getUserId(), trainingRoomName, new TrainingRoomSettings().setOrganismCount(20).setInputCount(3).setOutputCount(1).setSeed(10).setAddConnectionChance(1).setAddNodeChance(1 + ))); }); client.addListener("CreateTrainingRoomResponse", (changeEvent) -> { @@ -89,7 +76,7 @@ public static void main(String... args) throws IOException, InterruptedException if (response.isSuccess()) { trainingSession = response.getTrainingSession(); - Request getOrganismRequest = new GetOrganismsRequest(trainingSession.Id, 10); + Request getOrganismRequest = new GetOrganismsRequest(trainingSession.id, 10); client.send(getOrganismRequest); } else { System.err.println(String.format("StartTrainingSessionResponse failed %s", response.getMessage())); @@ -104,12 +91,12 @@ public static void main(String... args) throws IOException, InterruptedException Random random = new Random(); for (Organism organism : response.getOrganisms()) { - organism.score = random.nextDouble() + 0.00001; - organism.initialize(trainingSession.trainingRoom); - System.out.println(organism.name + " has output: " + Arrays.toString(organism.evaluate(new double[]{0, 1, 2}))); + organism.setScore(random.nextDouble() + 0.00001); + organism.initialize(); +// System.out.println(organism.name + " has output: " + Arrays.toString(organism.getValue(new double[]{0, 1, 2}))); } - Request postOrganismsScoreRequest = new PostOrganismsScoreRequest(trainingSession.Id, response.getOrganisms()); + Request postOrganismsScoreRequest = new PostOrganismsScoreRequest(trainingSession.id, response.getOrganisms()); client.send(postOrganismsScoreRequest); } else { System.err.println(String.format("GetOrganismsResponse failed %s", response.getMessage())); @@ -120,12 +107,12 @@ public static void main(String... args) throws IOException, InterruptedException PostOrganismsScoreResponse response = (PostOrganismsScoreResponse) changeEvent.getNewValue(); System.out.println(String.format("PostOrganismsScoreResponse was %s", response.isSuccess() ? "successful" : "unsuccessful")); - i++; - if (i == 3) { - Request request = new EndTrainingSessionRequest(trainingSession.Id); + organismBatchesProcessed++; + if (organismBatchesProcessed == 3) { + Request request = new EndTrainingSessionRequest(trainingSession.id); client.send(request); } else { - Request getOrganismRequest = new GetOrganismsRequest(trainingSession.Id, 10); + Request getOrganismRequest = new GetOrganismsRequest(trainingSession.id, 10); client.send(getOrganismRequest); } }); diff --git a/src/test/java/net/neuralm/client/NeuralmClientTest.java b/src/test/java/net/neuralm/client/NeuralmClientTest.java new file mode 100644 index 0000000..3cb2e57 --- /dev/null +++ b/src/test/java/net/neuralm/client/NeuralmClientTest.java @@ -0,0 +1,13 @@ +package net.neuralm.client; + +import org.junit.jupiter.api.Test; + +class NeuralmClientTest { + + @Test + void start() { +// NeuralmClient client = new NeuralmClient("api.neuralm.com", 9999, new JsonSerializer(), true, 5 * 1000); +// +// assertDoesNotThrow(client::start); + } +} \ No newline at end of file diff --git a/src/test/java/net/neuralm/client/neat/BrainTest.java b/src/test/java/net/neuralm/client/neat/BrainTest.java deleted file mode 100644 index 4b21336..0000000 --- a/src/test/java/net/neuralm/client/neat/BrainTest.java +++ /dev/null @@ -1,28 +0,0 @@ -package net.neuralm.client.neat; - -import java.util.Arrays; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.CsvFileSource; - -class BrainTest { - - @ParameterizedTest - @CsvFileSource(resources = "/evaluateTest.csv") - void evaluate(double inA, double inB, double inC, double expected) { - TrainingRoom room = new TrainingRoom(); - room.trainingRoomSettings = new TrainingRoomSettings().setInputCount(3).setOutputCount(1); - Brain brain = new Brain(room, Arrays.asList( - - new ConnectionGene(0, 3, 1, true), - new ConnectionGene(1, 3, 1, false), - new ConnectionGene(2, 3, 1, true), - new ConnectionGene(1, 4, 1, true), - new ConnectionGene(4, 3, 1, true), - new ConnectionGene(0, 4, 1, true) - - )); - - Assertions.assertEquals(expected, brain.evaluate(new double[]{inA, inB, inC})[0], 0.0000000001); - } -} \ No newline at end of file diff --git a/src/test/java/net/neuralm/client/neat/OrganismTest.java b/src/test/java/net/neuralm/client/neat/OrganismTest.java new file mode 100644 index 0000000..44fab34 --- /dev/null +++ b/src/test/java/net/neuralm/client/neat/OrganismTest.java @@ -0,0 +1,56 @@ +package net.neuralm.client.neat; + +import com.google.gson.*; +import net.neuralm.client.messages.serializer.JsonSerializer; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvFileSource; + +import java.nio.charset.StandardCharsets; +import java.util.Arrays; + +class OrganismTest { + + @ParameterizedTest + @CsvFileSource(resources = "/evaluateTest.csv") + void getValue(double inA, double inB, double inC, double expected) { + Organism organism = new Organism(Arrays.asList( + + new ConnectionGene(0, 3, 1, true), + new ConnectionGene(1, 3, 1, false), + new ConnectionGene(2, 3, 1, true), + new ConnectionGene(1, 4, 1, true), + new ConnectionGene(4, 3, 1, true), + new ConnectionGene(0, 4, 1, true) + + ), 3, 1); + + Assertions.assertEquals(expected, organism.evaluate(new double[]{inA, inB, inC})[0], 0.0000000001); + } + + @Test + void parseJson() { + String json = "{\"Organisms\":[{\"Id\":\"1110df35-52f0-4bb5-8ce4-c68de3f50717\",\"ConnectionGenes\":[{\"Id\":\"ab1f8a88-f22c-49ce-e69c-08d7a435cc56\",\"OrganismId\":\"1110df35-52f0-4bb5-8ce4-c68de3f50717\",\"InNodeIdentifier\":0,\"OutNodeIdentifier\":2,\"Weight\":0.9468057444071425,\"Enabled\":true},{\"Id\":\"608c8dba-cb98-4e0d-e69d-08d7a435cc56\",\"OrganismId\":\"1110df35-52f0-4bb5-8ce4-c68de3f50717\",\"InNodeIdentifier\":1,\"OutNodeIdentifier\":2,\"Weight\":0.8501794032054857,\"Enabled\":true}],\"InputNodes\":[{\"Id\":\"23b86cf7-9feb-4e83-9b66-52ee08f002bb\",\"Layer\":0,\"NodeIdentifier\":1},{\"Id\":\"b29a8f7e-e9a9-4bea-b177-c41556650edd\",\"Layer\":0,\"NodeIdentifier\":0}],\"OutputNodes\":[{\"Id\":\"cbf2e2d9-edb9-4a22-be06-fc7c81a08d9b\",\"Layer\":0,\"NodeIdentifier\":2}],\"Score\":0,\"Name\":\"hah\",\"Generation\":2},{\"Id\":\"5f58a628-d6f9-4c89-894c-cc0cc67b4b58\",\"ConnectionGenes\":[{\"Id\":\"5e10a17e-d5ed-4f43-e6be-08d7a435cc56\",\"OrganismId\":\"5f58a628-d6f9-4c89-894c-cc0cc67b4b58\",\"InNodeIdentifier\":1,\"OutNodeIdentifier\":2,\"Weight\":0.8874416885839037,\"Enabled\":true},{\"Id\":\"2ce5cf89-401f-45f4-e6bf-08d7a435cc56\",\"OrganismId\":\"5f58a628-d6f9-4c89-894c-cc0cc67b4b58\",\"InNodeIdentifier\":0,\"OutNodeIdentifier\":2,\"Weight\":0.9468057444071425,\"Enabled\":true}],\"InputNodes\":[{\"Id\":\"04263382-c8a1-4d9b-ad8d-78ebd11d1634\",\"Layer\":0,\"NodeIdentifier\":1},{\"Id\":\"8f09d844-d41b-4aef-b518-bbb3b81ea4d1\",\"Layer\":0,\"NodeIdentifier\":0}],\"OutputNodes\":[{\"Id\":\"d9b4add4-8a76-4c13-91e4-30187428af54\",\"Layer\":0,\"NodeIdentifier\":2}],\"Score\":0,\"Name\":\"huv\",\"Generation\":2},{\"Id\":\"233ca2a9-016a-4165-9f04-d0cd30599466\",\"ConnectionGenes\":[{\"Id\":\"de88f87c-a903-4d91-e6c6-08d7a435cc56\",\"OrganismId\":\"233ca2a9-016a-4165-9f04-d0cd30599466\",\"InNodeIdentifier\":0,\"OutNodeIdentifier\":2,\"Weight\":-0.8599432335979972,\"Enabled\":true},{\"Id\":\"13c275df-3ca7-4ad7-e6c7-08d7a435cc56\",\"OrganismId\":\"233ca2a9-016a-4165-9f04-d0cd30599466\",\"InNodeIdentifier\":1,\"OutNodeIdentifier\":2,\"Weight\":0.9279808662496418,\"Enabled\":true}],\"InputNodes\":[{\"Id\":\"aab6743b-bd78-4601-8f44-36ced34d525c\",\"Layer\":0,\"NodeIdentifier\":0},{\"Id\":\"6c38d04f-568d-4ed4-9030-652c5fdb3f0b\",\"Layer\":0,\"NodeIdentifier\":1}],\"OutputNodes\":[{\"Id\":\"f7a8d5ee-2833-4c80-9454-6ffdf5586b9c\",\"Layer\":0,\"NodeIdentifier\":2}],\"Score\":0,\"Name\":\"meev\",\"Generation\":2},{\"Id\":\"a100859d-5c5f-4b32-bc4b-cf0f65744add\",\"ConnectionGenes\":[{\"Id\":\"84660026-932a-4d41-e6b8-08d7a435cc56\",\"OrganismId\":\"a100859d-5c5f-4b32-bc4b-cf0f65744add\",\"InNodeIdentifier\":1,\"OutNodeIdentifier\":2,\"Weight\":0.5511769361566645,\"Enabled\":true},{\"Id\":\"8937ed99-3ea7-4fe0-e6b9-08d7a435cc56\",\"OrganismId\":\"a100859d-5c5f-4b32-bc4b-cf0f65744add\",\"InNodeIdentifier\":0,\"OutNodeIdentifier\":2,\"Weight\":-0.6720582465045425,\"Enabled\":true}],\"InputNodes\":[{\"Id\":\"8f7a517c-39dc-421b-9718-163eb7c90d89\",\"Layer\":0,\"NodeIdentifier\":0},{\"Id\":\"ddc31fdb-cd5a-47b9-a256-7d43aaf7cb3e\",\"Layer\":0,\"NodeIdentifier\":1}],\"OutputNodes\":[{\"Id\":\"7428049a-dd70-4430-8ec1-6a3687d2814a\",\"Layer\":0,\"NodeIdentifier\":2}],\"Score\":0,\"Name\":\"wopoom\",\"Generation\":2},{\"Id\":\"879c8309-4542-4882-9ae0-f49aaee1ded1\",\"ConnectionGenes\":[{\"Id\":\"08544f7b-eafb-4d78-e6b0-08d7a435cc56\",\"OrganismId\":\"879c8309-4542-4882-9ae0-f49aaee1ded1\",\"InNodeIdentifier\":0,\"OutNodeIdentifier\":2,\"Weight\":-0.911530219908585,\"Enabled\":true},{\"Id\":\"8a42569d-1f19-421f-e6b1-08d7a435cc56\",\"OrganismId\":\"879c8309-4542-4882-9ae0-f49aaee1ded1\",\"InNodeIdentifier\":1,\"OutNodeIdentifier\":2,\"Weight\":0.5396867401617051,\"Enabled\":true}],\"InputNodes\":[{\"Id\":\"ecf569b1-9cc1-46b2-a070-27462634b1ba\",\"Layer\":0,\"NodeIdentifier\":1},{\"Id\":\"cc5293ae-d3e2-41af-8d5f-e23472e10638\",\"Layer\":0,\"NodeIdentifier\":0}],\"OutputNodes\":[{\"Id\":\"80461bd3-e8e6-4150-a38c-c78ec6a3b0ff\",\"Layer\":0,\"NodeIdentifier\":2}],\"Score\":0,\"Name\":\"kixityc\",\"Generation\":2},{\"Id\":\"dd44e9ea-6e1c-42f2-a713-de9f60f36e0f\",\"ConnectionGenes\":[{\"Id\":\"70978ca8-01a0-4ad3-e6ca-08d7a435cc56\",\"OrganismId\":\"dd44e9ea-6e1c-42f2-a713-de9f60f36e0f\",\"InNodeIdentifier\":0,\"OutNodeIdentifier\":2,\"Weight\":0.3642462377269968,\"Enabled\":true},{\"Id\":\"269e36a6-4185-421c-e6cb-08d7a435cc56\",\"OrganismId\":\"dd44e9ea-6e1c-42f2-a713-de9f60f36e0f\",\"InNodeIdentifier\":1,\"OutNodeIdentifier\":2,\"Weight\":0.8933658557913107,\"Enabled\":true}],\"InputNodes\":[{\"Id\":\"cf286c7e-df70-4f20-9705-81b37a71790b\",\"Layer\":0,\"NodeIdentifier\":0},{\"Id\":\"c65a7bc1-d0d4-4b1f-a495-f87cbadcf847\",\"Layer\":0,\"NodeIdentifier\":1}],\"OutputNodes\":[{\"Id\":\"c988fd4d-e05b-40a0-8e32-78f19fc5f751\",\"Layer\":0,\"NodeIdentifier\":2}],\"Score\":0,\"Name\":\"haafeezaab\",\"Generation\":2},{\"Id\":\"e9e90ef8-5c77-4c4f-9214-eeecbc890cc5\",\"ConnectionGenes\":[{\"Id\":\"fcbf70b3-6255-448e-e6aa-08d7a435cc56\",\"OrganismId\":\"e9e90ef8-5c77-4c4f-9214-eeecbc890cc5\",\"InNodeIdentifier\":0,\"OutNodeIdentifier\":2,\"Weight\":0.7500601238804219,\"Enabled\":true},{\"Id\":\"1646d659-0670-41cc-e6ab-08d7a435cc56\",\"OrganismId\":\"e9e90ef8-5c77-4c4f-9214-eeecbc890cc5\",\"InNodeIdentifier\":1,\"OutNodeIdentifier\":2,\"Weight\":0.9267026316498884,\"Enabled\":true}],\"InputNodes\":[{\"Id\":\"39ee22e9-1be8-44cf-bf2c-9334b4741a57\",\"Layer\":0,\"NodeIdentifier\":0},{\"Id\":\"45ea4559-3f38-48bd-b337-e3105225573e\",\"Layer\":0,\"NodeIdentifier\":1}],\"OutputNodes\":[{\"Id\":\"0051c8eb-ef42-4852-bc57-b2897cc9d73b\",\"Layer\":0,\"NodeIdentifier\":2}],\"Score\":0,\"Name\":\"cous\",\"Generation\":2},{\"Id\":\"cc95b2f0-b498-4291-b9fd-d6d1654b7459\",\"ConnectionGenes\":[{\"Id\":\"9c738b6b-7efd-480d-e6a6-08d7a435cc56\",\"OrganismId\":\"cc95b2f0-b498-4291-b9fd-d6d1654b7459\",\"InNodeIdentifier\":0,\"OutNodeIdentifier\":2,\"Weight\":0.8646167163572352,\"Enabled\":true},{\"Id\":\"3702122f-1df3-4761-e6a7-08d7a435cc56\",\"OrganismId\":\"cc95b2f0-b498-4291-b9fd-d6d1654b7459\",\"InNodeIdentifier\":1,\"OutNodeIdentifier\":2,\"Weight\":0.8874416885839037,\"Enabled\":true}],\"InputNodes\":[{\"Id\":\"1a4c974f-f4f3-4bab-bcba-675e0c222d44\",\"Layer\":0,\"NodeIdentifier\":1},{\"Id\":\"c028f4b5-3475-46a9-bf6d-d4ba999a9728\",\"Layer\":0,\"NodeIdentifier\":0}],\"OutputNodes\":[{\"Id\":\"985cc945-e4bd-44f1-b45c-bc14cb0af9f4\",\"Layer\":0,\"NodeIdentifier\":2}],\"Score\":0,\"Name\":\"gan\",\"Generation\":2},{\"Id\":\"9704e91d-ae1e-4ff7-9a02-c67d4f86182f\",\"ConnectionGenes\":[{\"Id\":\"1c65a50e-2c21-439e-e6ac-08d7a435cc56\",\"OrganismId\":\"9704e91d-ae1e-4ff7-9a02-c67d4f86182f\",\"InNodeIdentifier\":1,\"OutNodeIdentifier\":2,\"Weight\":-0.8779935286743537,\"Enabled\":false},{\"Id\":\"b9e266da-932b-4eeb-e6ad-08d7a435cc56\",\"OrganismId\":\"9704e91d-ae1e-4ff7-9a02-c67d4f86182f\",\"InNodeIdentifier\":0,\"OutNodeIdentifier\":2,\"Weight\":0.3642462377269968,\"Enabled\":true},{\"Id\":\"7f27e42d-778e-4fba-e6ae-08d7a435cc56\",\"OrganismId\":\"9704e91d-ae1e-4ff7-9a02-c67d4f86182f\",\"InNodeIdentifier\":1,\"OutNodeIdentifier\":3,\"Weight\":1,\"Enabled\":true},{\"Id\":\"68d79c3c-cf40-438b-e6af-08d7a435cc56\",\"OrganismId\":\"9704e91d-ae1e-4ff7-9a02-c67d4f86182f\",\"InNodeIdentifier\":3,\"OutNodeIdentifier\":2,\"Weight\":-0.8672354359027163,\"Enabled\":true}],\"InputNodes\":[{\"Id\":\"cccf3da0-cf42-4fb6-9749-660eb011359a\",\"Layer\":0,\"NodeIdentifier\":1},{\"Id\":\"06b715ea-adaa-40e3-8e7a-7f1dbecd069b\",\"Layer\":0,\"NodeIdentifier\":0}],\"OutputNodes\":[{\"Id\":\"0a7901ff-2a01-44be-adc9-8ffca05d8000\",\"Layer\":0,\"NodeIdentifier\":2}],\"Score\":0,\"Name\":\"hyz\",\"Generation\":2},{\"Id\":\"cb6d22f5-4d6c-4add-81ad-d7f518634fcc\",\"ConnectionGenes\":[{\"Id\":\"7474d31c-073d-4b39-e69b-08d7a435cc56\",\"OrganismId\":\"cb6d22f5-4d6c-4add-81ad-d7f518634fcc\",\"InNodeIdentifier\":0,\"OutNodeIdentifier\":2,\"Weight\":-0.36319920670390093,\"Enabled\":true}],\"InputNodes\":[{\"Id\":\"cc2f4aaa-79f1-40f5-bef2-4f8788269440\",\"Layer\":0,\"NodeIdentifier\":0},{\"Id\":\"3c2f4a2d-767a-4807-af5f-a40a3104dc64\",\"Layer\":0,\"NodeIdentifier\":1}],\"OutputNodes\":[{\"Id\":\"1b106372-4f1a-4200-9ada-4a3c5bc39a25\",\"Layer\":0,\"NodeIdentifier\":2}],\"Score\":0,\"Name\":\"piebacocauv\",\"Generation\":2}],\"Id\":\"33236a35-9ad4-46cb-aa07-8d68aef87fc4\",\"RequestId\":\"b873fb68-e983-47c8-a846-83b65846afb2\",\"DateTime\":\"2020-01-29T19:17:13.1786668Z\",\"Message\":\"The requested amount of organisms are not all available. The training room is close to a new generation.\",\"Success\":true}"; + + JsonParser parser = new JsonParser(); + JsonObject object = parser.parse(json).getAsJsonObject(); + JsonArray organisms = object.getAsJsonArray("Organisms"); + + Gson gson = new GsonBuilder().setFieldNamingStrategy(FieldNamingPolicy.UPPER_CAMEL_CASE).create(); + for(int i = 0; i < organisms.size(); i++) { + System.out.println(organisms.get(i).toString()); + Organism organism = gson.fromJson(organisms.get(i), Organism.class); + organism.initialize(); + } + } + + @ParameterizedTest + @CsvFileSource(resources = "/loadOrganismTest.csv") + void parseFromJsonEvaluate(String json, double inA, double inB, double inC, double expected) { + Organism organism = new JsonSerializer().deserialize(json.getBytes(StandardCharsets.UTF_8), Organism.class); + organism.initialize(); + + Assertions.assertEquals(expected, organism.evaluate(new double[]{inA, inB, inC})[0], 0.0000000001); + } +} \ No newline at end of file diff --git a/src/test/resources/loadOrganismTest.csv b/src/test/resources/loadOrganismTest.csv new file mode 100644 index 0000000..8fe6a5d --- /dev/null +++ b/src/test/resources/loadOrganismTest.csv @@ -0,0 +1,9 @@ +"{""Id"":""db63e5a8-c360-486b-a565-1762c06af5a5"",""ConnectionGenes"":[{""Id"":""00000000-0000-0000-0000-000000000000"",""OrganismId"":""4bde222f-ef61-4bb9-a362-60abafbe5dba"",""InNodeIdentifier"":1,""OutNodeIdentifier"":3,""InnovationNumber"":1,""Weight"":0.077578324814130739,""Enabled"":false},{""Id"":""00000000-0000-0000-0000-000000000000"",""OrganismId"":""4bde222f-ef61-4bb9-a362-60abafbe5dba"",""InNodeIdentifier"":1,""OutNodeIdentifier"":7,""InnovationNumber"":13,""Weight"":1.0,""Enabled"":true},{""Id"":""00000000-0000-0000-0000-000000000000"",""OrganismId"":""4bde222f-ef61-4bb9-a362-60abafbe5dba"",""InNodeIdentifier"":7,""OutNodeIdentifier"":3,""InnovationNumber"":14,""Weight"":0.21575169973808883,""Enabled"":true}],""InputNodes"":[{""Id"":""4081e0ef-8c81-43cc-a321-01d35dd0a656"",""Layer"":0,""NodeIdentifier"":0},{""Id"":""5bfa5705-1475-4b18-9f45-5a8470a4be84"",""Layer"":0,""NodeIdentifier"":1},{""Id"":""37c0fe8e-7fcd-4454-9271-72a8ba9b4a77"",""Layer"":0,""NodeIdentifier"":2}],""OutputNodes"":[{""Id"":""b59f7079-2235-4730-9004-aa090d0bb7cd"",""Layer"":0,""NodeIdentifier"":3}],""Score"":0.0,""Name"":""qeel"",""Generation"":8}", 1, 2, 3, 0.5473659097472284 +"{""Id"":""db63e5a8-c360-486b-a565-1762c06af5a5"",""ConnectionGenes"":[{""Id"":""00000000-0000-0000-0000-000000000000"",""OrganismId"":""4bde222f-ef61-4bb9-a362-60abafbe5dba"",""InNodeIdentifier"":1,""OutNodeIdentifier"":3,""InnovationNumber"":1,""Weight"":0.077578324814130739,""Enabled"":false},{""Id"":""00000000-0000-0000-0000-000000000000"",""OrganismId"":""4bde222f-ef61-4bb9-a362-60abafbe5dba"",""InNodeIdentifier"":1,""OutNodeIdentifier"":7,""InnovationNumber"":13,""Weight"":1.0,""Enabled"":true},{""Id"":""00000000-0000-0000-0000-000000000000"",""OrganismId"":""4bde222f-ef61-4bb9-a362-60abafbe5dba"",""InNodeIdentifier"":7,""OutNodeIdentifier"":3,""InnovationNumber"":14,""Weight"":0.21575169973808883,""Enabled"":true}],""InputNodes"":[{""Id"":""4081e0ef-8c81-43cc-a321-01d35dd0a656"",""Layer"":0,""NodeIdentifier"":0},{""Id"":""5bfa5705-1475-4b18-9f45-5a8470a4be84"",""Layer"":0,""NodeIdentifier"":1},{""Id"":""37c0fe8e-7fcd-4454-9271-72a8ba9b4a77"",""Layer"":0,""NodeIdentifier"":2}],""OutputNodes"":[{""Id"":""b59f7079-2235-4730-9004-aa090d0bb7cd"",""Layer"":0,""NodeIdentifier"":3}],""Score"":0.0,""Name"":""qeel"",""Generation"":8}", 1, 2, 5, 0.5473659097472284 +"{""Id"":""db63e5a8-c360-486b-a565-1762c06af5a5"",""ConnectionGenes"":[{""Id"":""00000000-0000-0000-0000-000000000000"",""OrganismId"":""4bde222f-ef61-4bb9-a362-60abafbe5dba"",""InNodeIdentifier"":1,""OutNodeIdentifier"":3,""InnovationNumber"":1,""Weight"":0.077578324814130739,""Enabled"":false},{""Id"":""00000000-0000-0000-0000-000000000000"",""OrganismId"":""4bde222f-ef61-4bb9-a362-60abafbe5dba"",""InNodeIdentifier"":1,""OutNodeIdentifier"":7,""InnovationNumber"":13,""Weight"":1.0,""Enabled"":true},{""Id"":""00000000-0000-0000-0000-000000000000"",""OrganismId"":""4bde222f-ef61-4bb9-a362-60abafbe5dba"",""InNodeIdentifier"":7,""OutNodeIdentifier"":3,""InnovationNumber"":14,""Weight"":0.21575169973808883,""Enabled"":true}],""InputNodes"":[{""Id"":""4081e0ef-8c81-43cc-a321-01d35dd0a656"",""Layer"":0,""NodeIdentifier"":0},{""Id"":""5bfa5705-1475-4b18-9f45-5a8470a4be84"",""Layer"":0,""NodeIdentifier"":1},{""Id"":""37c0fe8e-7fcd-4454-9271-72a8ba9b4a77"",""Layer"":0,""NodeIdentifier"":2}],""OutputNodes"":[{""Id"":""b59f7079-2235-4730-9004-aa090d0bb7cd"",""Layer"":0,""NodeIdentifier"":3}],""Score"":0.0,""Name"":""qeel"",""Generation"":8}", 1, -1, 3, 0.5145020735663703 + +"{""Id"":""db63e5a8-c360-486b-a565-1762c06af5a5"",""ConnectionGenes"":[{""Id"":""00000000-0000-0000-0000-000000000000"",""OrganismId"":""4bde222f-ef61-4bb9-a362-60abafbe5dba"",""InNodeIdentifier"":0,""OutNodeIdentifier"":3,""InnovationNumber"":0,""Weight"":1,""Enabled"":true},{""Id"":""00000000-0000-0000-0000-000000000000"",""OrganismId"":""4bde222f-ef61-4bb9-a362-60abafbe5dba"",""InNodeIdentifier"":1,""OutNodeIdentifier"":3,""InnovationNumber"":1,""Weight"":1.0,""Enabled"":false},{""Id"":""00000000-0000-0000-0000-000000000000"",""OrganismId"":""4bde222f-ef61-4bb9-a362-60abafbe5dba"",""InNodeIdentifier"":2,""OutNodeIdentifier"":3,""InnovationNumber"":2,""Weight"":1,""Enabled"":true},{""Id"":""00000000-0000-0000-0000-000000000000"",""OrganismId"":""4bde222f-ef61-4bb9-a362-60abafbe5dba"",""InNodeIdentifier"":1,""OutNodeIdentifier"":4,""InnovationNumber"":3,""Weight"":1,""Enabled"":true},{""Id"":""00000000-0000-0000-0000-000000000000"",""OrganismId"":""4bde222f-ef61-4bb9-a362-60abafbe5dba"",""InNodeIdentifier"":4,""OutNodeIdentifier"":3,""InnovationNumber"":4,""Weight"":1,""Enabled"":true},{""Id"":""00000000-0000-0000-0000-000000000000"",""OrganismId"":""4bde222f-ef61-4bb9-a362-60abafbe5dba"",""InNodeIdentifier"":0,""OutNodeIdentifier"":4,""InnovationNumber"":5,""Weight"":1,""Enabled"":true}],""InputNodes"":[{""Id"":""4081e0ef-8c81-43cc-a321-01d35dd0a656"",""Layer"":0,""NodeIdentifier"":0},{""Id"":""5bfa5705-1475-4b18-9f45-5a8470a4be84"",""Layer"":0,""NodeIdentifier"":1},{""Id"":""37c0fe8e-7fcd-4454-9271-72a8ba9b4a77"",""Layer"":0,""NodeIdentifier"":2}],""OutputNodes"":[{""Id"":""b59f7079-2235-4730-9004-aa090d0bb7cd"",""Layer"":0,""NodeIdentifier"":3}],""Score"":0.0,""Name"":""qeel"",""Generation"":8}", 1 ,2 ,3 ,0.8328355518722748 +"{""Id"":""db63e5a8-c360-486b-a565-1762c06af5a5"",""ConnectionGenes"":[{""Id"":""00000000-0000-0000-0000-000000000000"",""OrganismId"":""4bde222f-ef61-4bb9-a362-60abafbe5dba"",""InNodeIdentifier"":0,""OutNodeIdentifier"":3,""InnovationNumber"":0,""Weight"":1,""Enabled"":true},{""Id"":""00000000-0000-0000-0000-000000000000"",""OrganismId"":""4bde222f-ef61-4bb9-a362-60abafbe5dba"",""InNodeIdentifier"":1,""OutNodeIdentifier"":3,""InnovationNumber"":1,""Weight"":1.0,""Enabled"":false},{""Id"":""00000000-0000-0000-0000-000000000000"",""OrganismId"":""4bde222f-ef61-4bb9-a362-60abafbe5dba"",""InNodeIdentifier"":2,""OutNodeIdentifier"":3,""InnovationNumber"":2,""Weight"":1,""Enabled"":true},{""Id"":""00000000-0000-0000-0000-000000000000"",""OrganismId"":""4bde222f-ef61-4bb9-a362-60abafbe5dba"",""InNodeIdentifier"":1,""OutNodeIdentifier"":4,""InnovationNumber"":3,""Weight"":1,""Enabled"":true},{""Id"":""00000000-0000-0000-0000-000000000000"",""OrganismId"":""4bde222f-ef61-4bb9-a362-60abafbe5dba"",""InNodeIdentifier"":4,""OutNodeIdentifier"":3,""InnovationNumber"":4,""Weight"":1,""Enabled"":true},{""Id"":""00000000-0000-0000-0000-000000000000"",""OrganismId"":""4bde222f-ef61-4bb9-a362-60abafbe5dba"",""InNodeIdentifier"":0,""OutNodeIdentifier"":4,""InnovationNumber"":5,""Weight"":1,""Enabled"":true}],""InputNodes"":[{""Id"":""4081e0ef-8c81-43cc-a321-01d35dd0a656"",""Layer"":0,""NodeIdentifier"":0},{""Id"":""5bfa5705-1475-4b18-9f45-5a8470a4be84"",""Layer"":0,""NodeIdentifier"":1},{""Id"":""37c0fe8e-7fcd-4454-9271-72a8ba9b4a77"",""Layer"":0,""NodeIdentifier"":2}],""OutputNodes"":[{""Id"":""b59f7079-2235-4730-9004-aa090d0bb7cd"",""Layer"":0,""NodeIdentifier"":3}],""Score"":0.0,""Name"":""qeel"",""Generation"":8}", 3 ,2 ,1 ,0.8377227092646183 +"{""Id"":""db63e5a8-c360-486b-a565-1762c06af5a5"",""ConnectionGenes"":[{""Id"":""00000000-0000-0000-0000-000000000000"",""OrganismId"":""4bde222f-ef61-4bb9-a362-60abafbe5dba"",""InNodeIdentifier"":0,""OutNodeIdentifier"":3,""InnovationNumber"":0,""Weight"":1,""Enabled"":true},{""Id"":""00000000-0000-0000-0000-000000000000"",""OrganismId"":""4bde222f-ef61-4bb9-a362-60abafbe5dba"",""InNodeIdentifier"":1,""OutNodeIdentifier"":3,""InnovationNumber"":1,""Weight"":1.0,""Enabled"":false},{""Id"":""00000000-0000-0000-0000-000000000000"",""OrganismId"":""4bde222f-ef61-4bb9-a362-60abafbe5dba"",""InNodeIdentifier"":2,""OutNodeIdentifier"":3,""InnovationNumber"":2,""Weight"":1,""Enabled"":true},{""Id"":""00000000-0000-0000-0000-000000000000"",""OrganismId"":""4bde222f-ef61-4bb9-a362-60abafbe5dba"",""InNodeIdentifier"":1,""OutNodeIdentifier"":4,""InnovationNumber"":3,""Weight"":1,""Enabled"":true},{""Id"":""00000000-0000-0000-0000-000000000000"",""OrganismId"":""4bde222f-ef61-4bb9-a362-60abafbe5dba"",""InNodeIdentifier"":4,""OutNodeIdentifier"":3,""InnovationNumber"":4,""Weight"":1,""Enabled"":true},{""Id"":""00000000-0000-0000-0000-000000000000"",""OrganismId"":""4bde222f-ef61-4bb9-a362-60abafbe5dba"",""InNodeIdentifier"":0,""OutNodeIdentifier"":4,""InnovationNumber"":5,""Weight"":1,""Enabled"":true}],""InputNodes"":[{""Id"":""4081e0ef-8c81-43cc-a321-01d35dd0a656"",""Layer"":0,""NodeIdentifier"":0},{""Id"":""5bfa5705-1475-4b18-9f45-5a8470a4be84"",""Layer"":0,""NodeIdentifier"":1},{""Id"":""37c0fe8e-7fcd-4454-9271-72a8ba9b4a77"",""Layer"":0,""NodeIdentifier"":2}],""OutputNodes"":[{""Id"":""b59f7079-2235-4730-9004-aa090d0bb7cd"",""Layer"":0,""NodeIdentifier"":3}],""Score"":0.0,""Name"":""qeel"",""Generation"":8}", 0 ,0 ,0 ,0.5415704832167999 +"{""Id"":""db63e5a8-c360-486b-a565-1762c06af5a5"",""ConnectionGenes"":[{""Id"":""00000000-0000-0000-0000-000000000000"",""OrganismId"":""4bde222f-ef61-4bb9-a362-60abafbe5dba"",""InNodeIdentifier"":0,""OutNodeIdentifier"":3,""InnovationNumber"":0,""Weight"":1,""Enabled"":true},{""Id"":""00000000-0000-0000-0000-000000000000"",""OrganismId"":""4bde222f-ef61-4bb9-a362-60abafbe5dba"",""InNodeIdentifier"":1,""OutNodeIdentifier"":3,""InnovationNumber"":1,""Weight"":1.0,""Enabled"":false},{""Id"":""00000000-0000-0000-0000-000000000000"",""OrganismId"":""4bde222f-ef61-4bb9-a362-60abafbe5dba"",""InNodeIdentifier"":2,""OutNodeIdentifier"":3,""InnovationNumber"":2,""Weight"":1,""Enabled"":true},{""Id"":""00000000-0000-0000-0000-000000000000"",""OrganismId"":""4bde222f-ef61-4bb9-a362-60abafbe5dba"",""InNodeIdentifier"":1,""OutNodeIdentifier"":4,""InnovationNumber"":3,""Weight"":1,""Enabled"":true},{""Id"":""00000000-0000-0000-0000-000000000000"",""OrganismId"":""4bde222f-ef61-4bb9-a362-60abafbe5dba"",""InNodeIdentifier"":4,""OutNodeIdentifier"":3,""InnovationNumber"":4,""Weight"":1,""Enabled"":true},{""Id"":""00000000-0000-0000-0000-000000000000"",""OrganismId"":""4bde222f-ef61-4bb9-a362-60abafbe5dba"",""InNodeIdentifier"":0,""OutNodeIdentifier"":4,""InnovationNumber"":5,""Weight"":1,""Enabled"":true}],""InputNodes"":[{""Id"":""4081e0ef-8c81-43cc-a321-01d35dd0a656"",""Layer"":0,""NodeIdentifier"":0},{""Id"":""5bfa5705-1475-4b18-9f45-5a8470a4be84"",""Layer"":0,""NodeIdentifier"":1},{""Id"":""37c0fe8e-7fcd-4454-9271-72a8ba9b4a77"",""Layer"":0,""NodeIdentifier"":2}],""OutputNodes"":[{""Id"":""b59f7079-2235-4730-9004-aa090d0bb7cd"",""Layer"":0,""NodeIdentifier"":3}],""Score"":0.0,""Name"":""qeel"",""Generation"":8}", -1,-2,-3,0.2188253499884587 +"{""Id"":""db63e5a8-c360-486b-a565-1762c06af5a5"",""ConnectionGenes"":[{""Id"":""00000000-0000-0000-0000-000000000000"",""OrganismId"":""4bde222f-ef61-4bb9-a362-60abafbe5dba"",""InNodeIdentifier"":0,""OutNodeIdentifier"":3,""InnovationNumber"":0,""Weight"":1,""Enabled"":true},{""Id"":""00000000-0000-0000-0000-000000000000"",""OrganismId"":""4bde222f-ef61-4bb9-a362-60abafbe5dba"",""InNodeIdentifier"":1,""OutNodeIdentifier"":3,""InnovationNumber"":1,""Weight"":1.0,""Enabled"":false},{""Id"":""00000000-0000-0000-0000-000000000000"",""OrganismId"":""4bde222f-ef61-4bb9-a362-60abafbe5dba"",""InNodeIdentifier"":2,""OutNodeIdentifier"":3,""InnovationNumber"":2,""Weight"":1,""Enabled"":true},{""Id"":""00000000-0000-0000-0000-000000000000"",""OrganismId"":""4bde222f-ef61-4bb9-a362-60abafbe5dba"",""InNodeIdentifier"":1,""OutNodeIdentifier"":4,""InnovationNumber"":3,""Weight"":1,""Enabled"":true},{""Id"":""00000000-0000-0000-0000-000000000000"",""OrganismId"":""4bde222f-ef61-4bb9-a362-60abafbe5dba"",""InNodeIdentifier"":4,""OutNodeIdentifier"":3,""InnovationNumber"":4,""Weight"":1,""Enabled"":true},{""Id"":""00000000-0000-0000-0000-000000000000"",""OrganismId"":""4bde222f-ef61-4bb9-a362-60abafbe5dba"",""InNodeIdentifier"":0,""OutNodeIdentifier"":4,""InnovationNumber"":5,""Weight"":1,""Enabled"":true}],""InputNodes"":[{""Id"":""4081e0ef-8c81-43cc-a321-01d35dd0a656"",""Layer"":0,""NodeIdentifier"":0},{""Id"":""5bfa5705-1475-4b18-9f45-5a8470a4be84"",""Layer"":0,""NodeIdentifier"":1},{""Id"":""37c0fe8e-7fcd-4454-9271-72a8ba9b4a77"",""Layer"":0,""NodeIdentifier"":2}],""OutputNodes"":[{""Id"":""b59f7079-2235-4730-9004-aa090d0bb7cd"",""Layer"":0,""NodeIdentifier"":3}],""Score"":0.0,""Name"":""qeel"",""Generation"":8}", -3,-2,-1,0.21281378940936574 \ No newline at end of file