package io.vivarium.experiment;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.LinkedList;
import com.google.common.collect.Lists;
import io.vivarium.client.TaskClient;
import io.vivarium.client.task.CreateJobTask;
import io.vivarium.client.task.UploadResourceTask;
import io.vivarium.core.CreatureBlueprint;
import io.vivarium.core.GridWorldBlueprint;
import io.vivarium.core.processor.NeuralNetworkBlueprint;
import io.vivarium.net.jobs.CreateWorldJob;
import io.vivarium.net.jobs.Job;
import io.vivarium.net.jobs.SimulationJob;
import io.vivarium.serialization.VivariumObjectCollection;
import io.vivarium.util.UUID;
public class NormalizationConvergence
{
private static int worldSize = 50;
private static int worldCountPerGroup = 24;
private static long totalTicksPerWorld = 20_000_000;
private static int snapshotsPerWorld = 100;
private static long ticksPerSnapshot = totalTicksPerWorld / snapshotsPerWorld;
/**
* Sets up the NormalizationConvergence experiment on a Vivarium research server.
*
* Hypothesis: Normalizing creature genomes will cause speedier convergence and produce creatures with higher
* average fitness by reducing genetic drift in 'inactive' genes. Genetic drift in inactive genes is hypothesized to
* be dangerous because offspring have the risk of inheriting an active version when recombined from parents with
* sufficiently distant inactive genes (this is a product of the Gaussian recombination of scalar genes used in
* offspring creation)
*
* @param args
* @throws URISyntaxException
*/
public static void main(String[] args) throws URISyntaxException
{
// Make the blueprints with the default behavior
GridWorldBlueprint defaultWorldBlueprint = GridWorldBlueprint.makeDefault();
defaultWorldBlueprint.setSize(worldSize);
ArrayList<CreatureBlueprint> defaultCreatureBlueprints = new ArrayList<>();
CreatureBlueprint defaultCreatureBlueprint = CreatureBlueprint.makeDefault();
defaultCreatureBlueprints.add(defaultCreatureBlueprint);
defaultWorldBlueprint.setCreatureBlueprints(defaultCreatureBlueprints);
// Save the default blueprints
TaskClient defaultUploadClient = new TaskClient(
new UploadResourceTask(defaultWorldBlueprint.getUUID(), defaultWorldBlueprint));
defaultUploadClient.connect();
// Make the blueprints with the normalizing behavior
GridWorldBlueprint normalizingWorldBlueprint = GridWorldBlueprint.makeDefault();
normalizingWorldBlueprint.setSize(50);
ArrayList<CreatureBlueprint> normalizingCreatureBlueprints = new ArrayList<>();
CreatureBlueprint normalizingCreatureBlueprint = CreatureBlueprint.makeDefault();
((NeuralNetworkBlueprint) normalizingCreatureBlueprint.getProcessorBlueprints()[0])
.setNormalizeAfterMutation(1);
normalizingCreatureBlueprints.add(normalizingCreatureBlueprint);
normalizingWorldBlueprint.setCreatureBlueprints(normalizingCreatureBlueprints);
// Save the normalizing blueprints
TaskClient normalizingUploadClient = new TaskClient(
new UploadResourceTask(normalizingWorldBlueprint.getUUID(), normalizingWorldBlueprint));
normalizingUploadClient.connect();
// Pre-allocate the resource snapshots
UUID[] defaultWorldSnapshots = new UUID[snapshotsPerWorld];
UUID[] normalizingWorldSnapshots = new UUID[snapshotsPerWorld];
for (int i = 0; i < snapshotsPerWorld; i++)
{
defaultWorldSnapshots[i] = UUID.randomUUID();
normalizingWorldSnapshots[i] = UUID.randomUUID();
new TaskClient(new UploadResourceTask(defaultWorldSnapshots[i], new VivariumObjectCollection())).connect();
new TaskClient(new UploadResourceTask(normalizingWorldSnapshots[i], new VivariumObjectCollection()))
.connect();
carelessSleep(100);
}
// Make all of the simulations simulations!
for (int i = 1; i <= worldCountPerGroup; i++)
{
// Create world creation jobs
Job createDefaultWorldJob = new CreateWorldJob(Lists.newArrayList(defaultWorldBlueprint.getUUID()),
Lists.newArrayList(defaultWorldSnapshots[0]), new LinkedList<>());
TaskClient createDefaultWorlClient = new TaskClient(new CreateJobTask(createDefaultWorldJob));
createDefaultWorlClient.connect();
// Create world creation jobs
Job createNormalizingWorldJob = new CreateWorldJob(Lists.newArrayList(normalizingWorldBlueprint.getUUID()),
Lists.newArrayList(normalizingWorldSnapshots[0]), new LinkedList<>());
TaskClient createNormalizingWorlClient = new TaskClient(new CreateJobTask(createNormalizingWorldJob));
createNormalizingWorlClient.connect();
carelessSleep(100);
long endTick = ticksPerSnapshot;
UUID defaultJobDependency = createDefaultWorldJob.getJobID();
UUID normalizingJobDependency = createNormalizingWorldJob.getJobID();
UUID defaultInputResource = defaultWorldBlueprint.getUUID();
UUID normalizingInputResource = normalizingWorldBlueprint.getUUID();
// Create simulation jobs
for (int j = 0; j < snapshotsPerWorld; j++)
{
// Create simulation jobs
Job defaultSimulateJob = new SimulationJob(Lists.newArrayList(defaultInputResource),
Lists.newArrayList(defaultWorldSnapshots[j]), Lists.newArrayList(defaultJobDependency),
endTick);
new TaskClient(new CreateJobTask(defaultSimulateJob)).connect();
// Create simulation jobs
Job normalizingSimulateJob = new SimulationJob(Lists.newArrayList(normalizingInputResource),
Lists.newArrayList(normalizingWorldSnapshots[j]), Lists.newArrayList(normalizingJobDependency),
endTick);
new TaskClient(new CreateJobTask(normalizingSimulateJob)).connect();
carelessSleep(100);
// Update dependencies for next pass
defaultJobDependency = defaultSimulateJob.getJobID();
normalizingJobDependency = normalizingSimulateJob.getJobID();
defaultInputResource = defaultWorldSnapshots[j];
normalizingInputResource = normalizingWorldSnapshots[j];
// Update end tick for next pass
endTick += ticksPerSnapshot;
}
// Done, wait for connections to finish writing if they need and then exit.
System.out.println("DONE!");
carelessSleep(5000);
System.exit(0);
}
}
private static void carelessSleep(long ms)
{
try
{
Thread.sleep(ms);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
}