public SpeciesBreedingPool(GenomeNEAT genome, int id) { agentList = new List <Agent>(); templateGenome = genome; speciesID = id; nextAgentIndex = 0; }
public GenomeNEAT InitializeRandomBrain(int numInputNodes, int numOutputNodes) { sourceGenome = new GenomeNEAT(numInputNodes, numOutputNodes); // create blank genome with no connections sourceGenome.CreateMinimumRandomConnections(); // Add links to each output node froma random input node return(sourceGenome); }
public void SortAgentIntoBreedingPool(Agent agent) { bool speciesGenomeMatch = false; for (int s = 0; s < speciesBreedingPoolList.Count; s++) { float geneticDistance = GenomeNEAT.MeasureGeneticDistance(agent.brainGenome, speciesBreedingPoolList[s].templateGenome, 0.425f, 0.425f, 0.15f, 0f, 0f, 1f); if (geneticDistance < 1f) //speciesSimilarityThreshold) { // !!! figure out how/where to place this attribute or get a ref from crossoverManager { speciesGenomeMatch = true; //agent.speciesID = speciesBreedingPoolList[s].speciesID; // this is done inside the AddNewAgent method below v v v speciesBreedingPoolList[s].AddNewAgent(agent); //Debug.Log("SortAgentIntoBreedingPool dist: " + geneticDistance.ToString() + ", speciesIDs: " + agent.speciesID.ToString() + ", " + speciesBreedingPoolList[s].speciesID.ToString()); break; } } if (!speciesGenomeMatch) { //Debug.Log("POPULATION SortAgentIntoBreedingPool NO MATCH!!! -- creating new BreedingPool "); SpeciesBreedingPool newSpeciesBreedingPool = new SpeciesBreedingPool(agent.brainGenome, GetNextSpeciesID()); // creates new speciesPool modeled on this agent's genome newSpeciesBreedingPool.AddNewAgent(agent); // add this agent to breeding pool speciesBreedingPoolList.Add(newSpeciesBreedingPool); // add new speciesPool to the population's list of all active species } }
public Species(Agent newAgent) { id = nextID; nextID++; templateGenome = newAgent.brainGenome; AddNewMember(newAgent); }
public override object Read(ES2Reader reader) { GenomeNEAT data = new GenomeNEAT(); Read(reader, data); return(data); }
public GenomeNEAT InitializeNewBrain(int numInputNodes, int numHiddenNodes, int numOutputNodes, float connectedness, bool randomWeights) { sourceGenome = new GenomeNEAT(numInputNodes, numHiddenNodes, numOutputNodes); // create blank genome with no connections sourceGenome.CreateInitialConnections(connectedness, randomWeights); //Debug.Log("InitializeBlankBrain #nodes: " + sourceGenome.nodeNEATList.Count.ToString() + ", #links: " + sourceGenome.linkNEATList.Count.ToString()); return(sourceGenome); }
public override void Write(object obj, ES2Writer writer) { GenomeNEAT data = (GenomeNEAT)obj; // Add your writer.Write calls here. writer.Write(0); // Version 0 is current version number // Make sure to edit Read() function to properly handle version control! // VERSION 0: writer.Write(data.nodeNEATList); writer.Write(data.linkNEATList); }
public override void Read(ES2Reader reader, object c) { GenomeNEAT data = (GenomeNEAT)c; // Add your reader.Read calls here to read the data into the object. // Read the version number. int fileVersion = reader.Read <int>(); // VERSION 0: if (fileVersion >= 0) { data.nodeNEATList = reader.ReadList <GeneNodeNEAT>(); data.linkNEATList = reader.ReadList <GeneLinkNEAT>(); } }
public GenomeNEAT InitializeBlankBrain(int numInputNodes, int numOutputNodes) { sourceGenome = new GenomeNEAT(numInputNodes, numOutputNodes); // create blank genome with no connections /*int numNewLinks = 0; * int numNewNodes = 0; * for(int i = 0; i < numNewLinks; i++) { * sourceGenome.AddNewRandomLink(0); * } * for (int j = 0; j < numNewNodes; j++) { * sourceGenome.AddNewRandomNode(0); * }*/ //Debug.Log("InitializeBlankBrain #nodes: " + sourceGenome.nodeNEATList.Count.ToString() + ", #links: " + sourceGenome.linkNEATList.Count.ToString()); return(sourceGenome); }
public void PerformBodyMutation(ref CritterGenome bodyGenome, ref GenomeNEAT brainGenome) { int numBodyMutations = 0; //float attachDirMutationMultiplier = 0.1f; //float restAngleDirMutationMultiplier = 0.1f; float jointAngleTypeMultiplier = 0.5f; List<int> nodesToDelete = new List<int>(); for (int i = 0; i < bodyGenome.CritterNodeList.Count; i++) { // Segment Proportions: if(CheckForMutation(segmentProportionChance * bodyMutationBlastModifier)) { // X bodyGenome.CritterNodeList[i].dimensions.x = MutateBodyFloatMult(bodyGenome.CritterNodeList[i].dimensions.x); numBodyMutations++; } if (CheckForMutation(segmentProportionChance * bodyMutationBlastModifier)) { // Y bodyGenome.CritterNodeList[i].dimensions.y = MutateBodyFloatMult(bodyGenome.CritterNodeList[i].dimensions.y); numBodyMutations++; } if (CheckForMutation(segmentProportionChance * bodyMutationBlastModifier)) { // Z bodyGenome.CritterNodeList[i].dimensions.z = MutateBodyFloatMult(bodyGenome.CritterNodeList[i].dimensions.z); numBodyMutations++; } if(i > 0) { // NOT THE ROOT SEGMENT!: // REMOVE SEGMENT!!!! if(CheckForMutation(removeSegmentChance * bodyMutationBlastModifier)) { // Can't delete Root Segment // Add this nodeID into queue for deletion at the end of mutation, to avoid shortening NodeList while traversing it: nodesToDelete.Add(i); } else { // Segment Attach Settings: if (CheckForMutation(segmentAttachSettingsChance * bodyMutationBlastModifier)) { // Position X bodyGenome.CritterNodeList[i].jointLink.attachDir = MutateBodyVector3Normalized(bodyGenome.CritterNodeList[i].jointLink.attachDir); numBodyMutations++; } if (CheckForMutation(segmentAttachSettingsChance * bodyMutationBlastModifier)) { // Orientation X bodyGenome.CritterNodeList[i].jointLink.restAngleDir = MutateBodyVector3Normalized(bodyGenome.CritterNodeList[i].jointLink.restAngleDir); numBodyMutations++; } // Joint Settings: if (CheckForMutation(jointSettingsChance * bodyMutationBlastModifier)) { bodyGenome.CritterNodeList[i].jointLink.jointLimitPrimary = MutateBodyFloatMult(bodyGenome.CritterNodeList[i].jointLink.jointLimitPrimary); } if (CheckForMutation(jointSettingsChance * bodyMutationBlastModifier)) { bodyGenome.CritterNodeList[i].jointLink.jointLimitSecondary = MutateBodyFloatMult(bodyGenome.CritterNodeList[i].jointLink.jointLimitSecondary); } if (CheckForMutation(jointSettingsChance * bodyMutationBlastModifier)) { bodyGenome.CritterNodeList[i].jointLink.recursionScalingFactor = MutateBodyFloatMult(bodyGenome.CritterNodeList[i].jointLink.recursionScalingFactor); } // Joint Hinge TYPE!!!! --- how to handle this??? if (CheckForMutation(jointSettingsChance * jointAngleTypeMultiplier * bodyMutationBlastModifier)) { int jointTypeInt = Mathf.RoundToInt(UnityEngine.Random.Range(0f, 4f)); bodyGenome.CritterNodeList[i].jointLink.jointType = (CritterJointLink.JointType)jointTypeInt; Debug.Log(i.ToString() + " Mutated to JointType: " + bodyGenome.CritterNodeList[i].jointLink.jointType); } // RECURSION: if (CheckForMutation(recursionChance * bodyMutationBlastModifier)) { int addRemove = Mathf.RoundToInt(UnityEngine.Random.Range(0f, 1f)) * 2 - 1; // either -1 or 1 //addRemove = 1; // TEMPORARY!!! testing add recursion if (bodyGenome.CritterNodeList[i].jointLink.numberOfRecursions + addRemove < 0 || bodyGenome.CritterNodeList[i].jointLink.numberOfRecursions + addRemove > 3) { // Do Nothing, tried to change numRecursions beyond the CAP } else { // It's all good -- PROCEED: bodyGenome.CritterNodeList[i].jointLink.numberOfRecursions += addRemove; numBodyMutations++; if (addRemove > 0) { // Created an additional Recursion -- Need to ADD new BrainNodes: //int numNodesBefore = brainGenome.nodeNEATList.Count; //brainGenome.AdjustBrainAfterBodyChange(bodyGenome); //int numNodesAfter = brainGenome.nodeNEATList.Count; //Debug.Log("MUTATION RECURSION! b4#: " + numNodesBefore.ToString() + ", after#: " + numNodesAfter.ToString()); } else { // REMOVED a Recursion -- Need to REMOVE BrainNodes: //brainGenome.AdjustBrainRemovedRecursion(bodyGenome, i); } } // NEED TO FIX BRAIN!!! -- how to preserve existing wiring while adding new neurons that may re-order? // Do I need to save a reference to segment/nodes within each input/output neuron? } // SYMMETRY if (CheckForMutation(symmetryChance * bodyMutationBlastModifier)) { int symmetryType = Mathf.RoundToInt(UnityEngine.Random.Range(0f, 2f)); // 0=none,1=x, or 2=y Debug.Log("Mutated Symmetry! " + bodyGenome.CritterNodeList[i].jointLink.symmetryType.ToString() + " => " + ((CritterJointLink.SymmetryType)symmetryType).ToString()); bodyGenome.CritterNodeList[i].jointLink.symmetryType = (CritterJointLink.SymmetryType)symmetryType; } // EXTRA -- recursion forward, only attach to tail } // CREATE NEW ADD-ON!! On this segment if (CheckForMutation(newAddonChance * bodyMutationBlastModifier)) { // Which types can be created automatically?? // int randomAddon = Mathf.RoundToInt(UnityEngine.Random.Range(0f, 1f)); switch (randomAddon) { case 0: AddonOscillatorInput newOscillatorInput = new AddonOscillatorInput(i, GetNextAddonInnov()); bodyGenome.addonOscillatorInputList.Add(newOscillatorInput); break; case 1: AddonValueInput newValueInput = new AddonValueInput(i, GetNextAddonInnov()); bodyGenome.addonValueInputList.Add(newValueInput); break; default: break; } Debug.Log("NEW ADDON! " + randomAddon.ToString() + ", segmentNode: " + i.ToString()); } } } for(int i = 0; i < nodesToDelete.Count; i++) { Debug.Log("DELETE SEGMENT NODE! " + i.ToString()); bodyGenome.DeleteNode(nodesToDelete[i]); bodyGenome.RenumberNodes(); } List<int> nodesToAddTo = new List<int>(); // After Deleting nodes, check all remaining nodes for a chance to have a child segment added: for (int i = 0; i < bodyGenome.CritterNodeList.Count; i++) { if (CheckForMutation(newSegmentChance * bodyMutationBlastModifier)) { nodesToAddTo.Add(i); } } for (int i = 0; i < nodesToAddTo.Count; i++) { Vector3 attachDir = Vector3.Slerp(new Vector3(0f, 0f, 1f), UnityEngine.Random.onUnitSphere, UnityEngine.Random.Range(0f, 1f)); //ConvertWorldSpaceToAttachDir(selectedSegment, rightClickWorldPosition); int nextID = bodyGenome.CritterNodeList.Count; bodyGenome.AddNewNode(bodyGenome.CritterNodeList[nodesToAddTo[i]], attachDir, new Vector3(0f, 0f, 0f), nextID, GetNextNodeInnov()); // Init joint type: bodyGenome.CritterNodeList[bodyGenome.CritterNodeList.Count - 1].jointLink.jointType = (CritterJointLink.JointType)Mathf.RoundToInt(UnityEngine.Random.Range(1, 4)); // Auto-Add-ons: -- New Segment starts with a joint angle sensor and joint Motor by default: AddonJointAngleSensor newJointAngleSensor = new AddonJointAngleSensor(nextID, GetNextAddonInnov()); bodyGenome.addonJointAngleSensorList.Add(newJointAngleSensor); // Motor: AddonJointMotor newJointMotor = new AddonJointMotor(nextID, GetNextAddonInnov()); bodyGenome.addonJointMotorList.Add(newJointMotor); Debug.Log("New SEGMENT! : " + nodesToAddTo[i].ToString()); } // Addon Mutation: PerformAddonMutation(ref bodyGenome, ref brainGenome); //Debug.Log("NumBodyMutations: " + numBodyMutations.ToString()); }
public static float MeasureGeneticDistance(GenomeNEAT genomeA, GenomeNEAT genomeB, float neuronCoefficient, float linkCoefficient, float weightCoefficient, float normNeuron, float normLink, float normWeight) { int indexA = 0; int indexB = 0; float weightDeltaTotal = 0f; float maxGenes = Mathf.Max((float)genomeA.linkNEATList.Count, (float)genomeB.linkNEATList.Count); float matchingGenes = 0f; //float disjointGenes = 0f; //float excessGenes = 0f; float linkGenes = 0f; float neuronGenes = 0f; int matchingNeurons = 0; //float smallestWeightValue = 0f; float largestWeightDelta = 0f; // matching Links // matching nodes/neurons // matching activation functions? // difference in weights // difference in add-on settings? // -- NEED TO GO BY BODY GENOME????? // LINKS::: for (int i = 0; i < genomeA.linkNEATList.Count + genomeB.linkNEATList.Count; i++) { if (indexA < genomeA.linkNEATList.Count) { if (indexB < genomeB.linkNEATList.Count) // both good { if (genomeA.linkNEATList[indexA].innov < genomeB.linkNEATList[indexB].innov) { // disjoint A linkGenes++; indexA++; } else if (genomeA.linkNEATList[indexA].innov > genomeB.linkNEATList[indexB].innov) { // disjoint B linkGenes++; indexB++; } else if (genomeA.linkNEATList[indexA].innov == genomeB.linkNEATList[indexB].innov) { // match! float weightDelta = Mathf.Abs(genomeA.linkNEATList[indexA].weight - genomeB.linkNEATList[indexB].weight); weightDeltaTotal += weightDelta; matchingGenes++; //Debug.Log("!@$#!$#!@$#!@$# MeasureGeneticDistance! innov MATCHING GENE: weightA: " + genomeA.linkNEATList[indexA].weight.ToString() + ", weightB: " + genomeB.linkNEATList[indexB].weight.ToString()); indexA++; indexB++; largestWeightDelta = Mathf.Max(largestWeightDelta, weightDelta); } } else // A is good, B is finished { linkGenes++; indexA++; } } else // A done { if (indexB < genomeB.linkNEATList.Count) // A is finished, B is good { linkGenes++; indexB++; } else // both done { break; } } } for (int i = 0; i < genomeA.nodeNEATList.Count; i++) { Int3 nodeID = new Int3(genomeA.nodeNEATList[i].sourceAddonInno, genomeA.nodeNEATList[i].sourceAddonRecursionNum, genomeA.nodeNEATList[i].sourceAddonChannelNum); if (genomeB.GetNodeIndexFromInt3(nodeID) != -1) // if genomeB has the same neuron: { matchingNeurons++; } } int totalNeurons = (genomeA.nodeNEATList.Count + genomeB.nodeNEATList.Count); int totalLinks = (genomeA.linkNEATList.Count + genomeB.linkNEATList.Count); if (totalNeurons > 0) { neuronGenes = Mathf.Lerp((float)((totalNeurons) - matchingNeurons * 2), (float)((totalNeurons) - matchingNeurons * 2) / (float)(totalNeurons), normNeuron); // get proportion of neurons that match between the two genomes, should be 0-1 } if (totalLinks > 0) { linkGenes = Mathf.Lerp(((float)(totalLinks) - matchingGenes * 2f), ((float)(totalLinks) - matchingGenes * 2f) / (float)(totalLinks), normLink); } //float weightSpan = largestWeightValue - smallestWeightValue; float distance = 0f; if (true) // maxGenes > 0f //float excessComponent = excessCoefficient * Mathf.Lerp(excessGenes, excessGenes / maxGenes, normExcess); //float disjointComponent = disjointCoefficient * Mathf.Lerp(disjointGenes, disjointGenes / maxGenes, normDisjoint); //float weightComponent = weightCoefficient * Mathf.Lerp(weightDeltaTotal, weightDeltaTotal / Mathf.Max((float)matchingGenes, 1f), normWeight); { float totalPie = neuronCoefficient + linkCoefficient + weightCoefficient; float weightComponent = 0f; if (largestWeightDelta > 0f) { weightComponent = Mathf.Lerp(weightDeltaTotal / largestWeightDelta, weightDeltaTotal / Mathf.Max((float)matchingGenes, 1f) / largestWeightDelta, normWeight); } // OLD //distance = excessComponent + disjointComponent + weightComponent; distance = neuronGenes * (neuronCoefficient / totalPie) + linkGenes * (linkCoefficient / totalPie) + weightComponent * (weightCoefficient / totalPie); //Debug.Log("MeasureGeneticDistance! neuronGenes: " + (neuronGenes).ToString() + " (" + genomeA.nodeNEATList.Count.ToString() + "," + genomeB.nodeNEATList.Count.ToString() + // "), linkGenes: " + (linkGenes).ToString() + " (" + genomeA.linkNEATList.Count.ToString() + "," + genomeB.linkNEATList.Count.ToString() + // "), weight: " + weightComponent.ToString() + ", largestWeightDelta: " + largestWeightDelta.ToString() + ", weightDeltaTotal: " + weightDeltaTotal.ToString() + "weightMatches: " + matchingGenes.ToString() + // ", distance: " + distance.ToString()); //Debug.Log("MeasureGeneticDistance! disjoint: " + (disjointGenes).ToString() + ", excess: " + (excessGenes).ToString() + ", weight: " + (weightDeltaTotal / Mathf.Max((float)matchingGenes, 1f)).ToString() + ", distance: " + distance.ToString()); } // else stays 0f; return(distance); }
public void PerformAddonMutation(ref CritterGenome bodyGenome, ref GenomeNEAT brainGenome) { // Chance to Remove an existing Add-on: // Chance to Mutate Add-On Settings: for (int i = bodyGenome.addonPhysicalAttributesList.Count - 1; i >= 0; i--) { if (CheckForMutation(removeAddonChance * bodyMutationBlastModifier)) { // DELETE THIS ADD-ON!!! bodyGenome.addonPhysicalAttributesList.RemoveAt(i); } else { if (CheckForMutation(addonSettingsChance * bodyMutationBlastModifier)) { bodyGenome.addonPhysicalAttributesList[i].bounciness[0] = MutateBodyFloatMult(bodyGenome.addonPhysicalAttributesList[i].bounciness[0], 0f, 1f); } if (CheckForMutation(addonSettingsChance * bodyMutationBlastModifier)) { bodyGenome.addonPhysicalAttributesList[i].dynamicFriction[0] = MutateBodyFloatMult(bodyGenome.addonPhysicalAttributesList[i].dynamicFriction[0], 0f, 1f); } if (CheckForMutation(addonSettingsChance * bodyMutationBlastModifier)) { bodyGenome.addonPhysicalAttributesList[i].staticFriction[0] = MutateBodyFloatMult(bodyGenome.addonPhysicalAttributesList[i].staticFriction[0], 0f, 1f); } /*if (CheckForMutation(addonSettingsChance)) { bodyGenome.addonPhysicalAttributesList[i].freezePositionX[0] = MutateBodyBool(bodyGenome.addonPhysicalAttributesList[i].freezePositionX[0]); } if (CheckForMutation(addonSettingsChance)) { bodyGenome.addonPhysicalAttributesList[i].freezePositionY[0] = MutateBodyBool(bodyGenome.addonPhysicalAttributesList[i].freezePositionY[0]); } if (CheckForMutation(addonSettingsChance)) { bodyGenome.addonPhysicalAttributesList[i].freezePositionZ[0] = MutateBodyBool(bodyGenome.addonPhysicalAttributesList[i].freezePositionZ[0]); } if (CheckForMutation(addonSettingsChance)) { bodyGenome.addonPhysicalAttributesList[i].freezeRotationX[0] = MutateBodyBool(bodyGenome.addonPhysicalAttributesList[i].freezeRotationX[0]); } if (CheckForMutation(addonSettingsChance)) { bodyGenome.addonPhysicalAttributesList[i].freezeRotationY[0] = MutateBodyBool(bodyGenome.addonPhysicalAttributesList[i].freezeRotationY[0]); } if (CheckForMutation(addonSettingsChance)) { bodyGenome.addonPhysicalAttributesList[i].freezeRotationZ[0] = MutateBodyBool(bodyGenome.addonPhysicalAttributesList[i].freezeRotationZ[0]); }*/ } } for (int i = bodyGenome.addonJointAngleSensorList.Count - 1; i >= 0; i--) { if (CheckForMutation(removeAddonChance * bodyMutationBlastModifier)) { // DELETE THIS ADD-ON!!! bodyGenome.addonJointAngleSensorList.RemoveAt(i); } else { if (CheckForMutation(addonSettingsChance * bodyMutationBlastModifier)) { bodyGenome.addonJointAngleSensorList[i].sensitivity[0] = MutateBodyFloatMult(bodyGenome.addonJointAngleSensorList[i].sensitivity[0], 0.001f, 100f); } // ################# How to handle MEasureVel Checkbox?? It adds a Neuron!!!!!!!!! // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% } } for (int i = bodyGenome.addonContactSensorList.Count - 1; i >= 0; i--) { if (CheckForMutation(removeAddonChance * bodyMutationBlastModifier)) { // DELETE THIS ADD-ON!!! bodyGenome.addonContactSensorList.RemoveAt(i); } else { if (CheckForMutation(addonSettingsChance * bodyMutationBlastModifier)) { bodyGenome.addonContactSensorList[i].contactSensitivity[0] = MutateBodyFloatMult(bodyGenome.addonContactSensorList[i].contactSensitivity[0], 0.01f, 10f); } } } for (int i = bodyGenome.addonRaycastSensorList.Count - 1; i >= 0; i--) { if (CheckForMutation(removeAddonChance * bodyMutationBlastModifier)) { // DELETE THIS ADD-ON!!! bodyGenome.addonRaycastSensorList.RemoveAt(i); } else { if (CheckForMutation(addonSettingsChance * bodyMutationBlastModifier)) { bodyGenome.addonRaycastSensorList[i].forwardVector[0] = MutateBodyVector3Normalized(bodyGenome.addonRaycastSensorList[i].forwardVector[0]); } if (CheckForMutation(addonSettingsChance * bodyMutationBlastModifier)) { bodyGenome.addonRaycastSensorList[i].maxDistance[0] = MutateBodyFloatMult(bodyGenome.addonRaycastSensorList[i].maxDistance[0], 0.01f, 100f); } } } for (int i = bodyGenome.addonCompassSensor1DList.Count - 1; i >= 0; i--) { if (CheckForMutation(removeAddonChance * bodyMutationBlastModifier)) { // DELETE THIS ADD-ON!!! bodyGenome.addonCompassSensor1DList.RemoveAt(i); } else { if (CheckForMutation(addonSettingsChance * bodyMutationBlastModifier)) { bodyGenome.addonCompassSensor1DList[i].forwardVector[0] = MutateBodyVector3Normalized(bodyGenome.addonCompassSensor1DList[i].forwardVector[0]); } } } for (int i = bodyGenome.addonCompassSensor3DList.Count - 1; i >= 0; i--) { if (CheckForMutation(removeAddonChance * bodyMutationBlastModifier)) { // DELETE THIS ADD-ON!!! bodyGenome.addonCompassSensor3DList.RemoveAt(i); } else { } } for (int i = bodyGenome.addonPositionSensor1DList.Count - 1; i >= 0; i--) { if (CheckForMutation(removeAddonChance * bodyMutationBlastModifier)) { // DELETE THIS ADD-ON!!! bodyGenome.addonPositionSensor1DList.RemoveAt(i); } else { if (CheckForMutation(addonSettingsChance * bodyMutationBlastModifier)) { bodyGenome.addonPositionSensor1DList[i].forwardVector[0] = MutateBodyVector3Normalized(bodyGenome.addonPositionSensor1DList[i].forwardVector[0]); } if (CheckForMutation(addonSettingsChance * bodyMutationBlastModifier)) { bodyGenome.addonPositionSensor1DList[i].relative[0] = MutateBodyBool(bodyGenome.addonPositionSensor1DList[i].relative[0]); } if (CheckForMutation(addonSettingsChance * bodyMutationBlastModifier)) { bodyGenome.addonPositionSensor1DList[i].sensitivity[0] = MutateBodyFloatMult(bodyGenome.addonPositionSensor1DList[i].sensitivity[0], 0.01f, 100f); } } } for (int i = bodyGenome.addonPositionSensor3DList.Count - 1; i >= 0; i--) { if (CheckForMutation(removeAddonChance * bodyMutationBlastModifier)) { // DELETE THIS ADD-ON!!! bodyGenome.addonPositionSensor3DList.RemoveAt(i); } else { if (CheckForMutation(addonSettingsChance * bodyMutationBlastModifier)) { bodyGenome.addonPositionSensor3DList[i].sensitivity[0] = MutateBodyFloatMult(bodyGenome.addonPositionSensor3DList[i].sensitivity[0], 0.01f, 100f); } if (CheckForMutation(addonSettingsChance * bodyMutationBlastModifier)) { bodyGenome.addonPositionSensor3DList[i].relative[0] = MutateBodyBool(bodyGenome.addonPositionSensor3DList[i].relative[0]); } } } for (int i = bodyGenome.addonRotationSensor1DList.Count - 1; i >= 0; i--) { if (CheckForMutation(removeAddonChance * bodyMutationBlastModifier)) { // DELETE THIS ADD-ON!!! bodyGenome.addonRotationSensor1DList.RemoveAt(i); } else { if (CheckForMutation(addonSettingsChance * bodyMutationBlastModifier)) { bodyGenome.addonRotationSensor1DList[i].localAxis[0] = MutateBodyVector3Normalized(bodyGenome.addonRotationSensor1DList[i].localAxis[0]); } if (CheckForMutation(addonSettingsChance * bodyMutationBlastModifier)) { bodyGenome.addonRotationSensor1DList[i].sensitivity[0] = MutateBodyFloatMult(bodyGenome.addonRotationSensor1DList[i].sensitivity[0], 0.01f, 100f); } } } for (int i = bodyGenome.addonRotationSensor3DList.Count - 1; i >= 0; i--) { if (CheckForMutation(removeAddonChance * bodyMutationBlastModifier)) { // DELETE THIS ADD-ON!!! bodyGenome.addonRotationSensor3DList.RemoveAt(i); } else { if (CheckForMutation(addonSettingsChance * bodyMutationBlastModifier)) { bodyGenome.addonRotationSensor3DList[i].sensitivity[0] = MutateBodyFloatMult(bodyGenome.addonRotationSensor3DList[i].sensitivity[0], 0.01f, 100f); } } } for (int i = bodyGenome.addonVelocitySensor1DList.Count - 1; i >= 0; i--) { if (CheckForMutation(removeAddonChance * bodyMutationBlastModifier)) { // DELETE THIS ADD-ON!!! bodyGenome.addonVelocitySensor1DList.RemoveAt(i); } else { if (CheckForMutation(addonSettingsChance * bodyMutationBlastModifier)) { bodyGenome.addonVelocitySensor1DList[i].sensitivity[0] = MutateBodyFloatMult(bodyGenome.addonVelocitySensor1DList[i].sensitivity[0], 0.01f, 100f); } if (CheckForMutation(addonSettingsChance * bodyMutationBlastModifier)) { bodyGenome.addonVelocitySensor1DList[i].forwardVector[0] = MutateBodyVector3Normalized(bodyGenome.addonVelocitySensor1DList[i].forwardVector[0]); } if (CheckForMutation(addonSettingsChance * bodyMutationBlastModifier)) { bodyGenome.addonVelocitySensor1DList[i].relative[0] = MutateBodyBool(bodyGenome.addonVelocitySensor1DList[i].relative[0]); } } } for (int i = bodyGenome.addonVelocitySensor3DList.Count - 1; i >= 0; i--) { if (CheckForMutation(removeAddonChance * bodyMutationBlastModifier)) { // DELETE THIS ADD-ON!!! bodyGenome.addonVelocitySensor3DList.RemoveAt(i); } else { if (CheckForMutation(addonSettingsChance * bodyMutationBlastModifier)) { bodyGenome.addonVelocitySensor3DList[i].sensitivity[0] = MutateBodyFloatMult(bodyGenome.addonVelocitySensor3DList[i].sensitivity[0], 0.01f, 100f); } if (CheckForMutation(addonSettingsChance * bodyMutationBlastModifier)) { bodyGenome.addonVelocitySensor3DList[i].relative[0] = MutateBodyBool(bodyGenome.addonVelocitySensor3DList[i].relative[0]); } } } for (int i = bodyGenome.addonAltimeterList.Count - 1; i >= 0; i--) { if (CheckForMutation(removeAddonChance * bodyMutationBlastModifier)) { // DELETE THIS ADD-ON!!! bodyGenome.addonAltimeterList.RemoveAt(i); } else { } } for (int i = bodyGenome.addonEarBasicList.Count - 1; i >= 0; i--) { if (CheckForMutation(removeAddonChance * bodyMutationBlastModifier)) { // DELETE THIS ADD-ON!!! bodyGenome.addonEarBasicList.RemoveAt(i); } else { if (CheckForMutation(addonSettingsChance * bodyMutationBlastModifier)) { bodyGenome.addonEarBasicList[i].sensitivity[0] = MutateBodyFloatMult(bodyGenome.addonEarBasicList[i].sensitivity[0], 0.01f, 100f); } } } for (int i = bodyGenome.addonGravitySensorList.Count - 1; i >= 0; i--) { if (CheckForMutation(removeAddonChance * bodyMutationBlastModifier)) { // DELETE THIS ADD-ON!!! bodyGenome.addonGravitySensorList.RemoveAt(i); } else { } } for (int i = bodyGenome.addonOscillatorInputList.Count - 1; i >= 0; i--) { if (CheckForMutation(removeAddonChance * bodyMutationBlastModifier)) { // DELETE THIS ADD-ON!!! bodyGenome.addonOscillatorInputList.RemoveAt(i); } else { if (CheckForMutation(addonSettingsChance * bodyMutationBlastModifier)) { bodyGenome.addonOscillatorInputList[i].amplitude[0] = MutateBodyFloatMult(bodyGenome.addonOscillatorInputList[i].amplitude[0], 0.01f, 100f); } if (CheckForMutation(addonSettingsChance * bodyMutationBlastModifier)) { bodyGenome.addonOscillatorInputList[i].frequency[0] = MutateBodyFloatMult(bodyGenome.addonOscillatorInputList[i].frequency[0], 0.01f, 50f); } if (CheckForMutation(addonSettingsChance * bodyMutationBlastModifier)) { bodyGenome.addonOscillatorInputList[i].offset[0] = MutateBodyFloatMult(bodyGenome.addonOscillatorInputList[i].offset[0], -50f, 50f); } } } for (int i = bodyGenome.addonValueInputList.Count - 1; i >= 0; i--) { if (CheckForMutation(removeAddonChance * bodyMutationBlastModifier)) { // DELETE THIS ADD-ON!!! bodyGenome.addonValueInputList.RemoveAt(i); } else { if (CheckForMutation(addonSettingsChance * bodyMutationBlastModifier)) { bodyGenome.addonValueInputList[i].value[0] = MutateBodyFloatMult(bodyGenome.addonValueInputList[i].value[0], -100f, 100f); } } } for (int i = bodyGenome.addonTimerInputList.Count - 1; i >= 0; i--) { if (CheckForMutation(removeAddonChance * bodyMutationBlastModifier)) { // DELETE THIS ADD-ON!!! bodyGenome.addonTimerInputList.RemoveAt(i); } else { } } //======================= OUTPUTS ===================== OUTPUTS ======================= OUTPUTS ===================================================== for (int i = bodyGenome.addonJointMotorList.Count - 1; i >= 0; i--) { if (CheckForMutation(removeAddonChance * bodyMutationBlastModifier)) { // DELETE THIS ADD-ON!!! bodyGenome.addonJointMotorList.RemoveAt(i); } else { if (CheckForMutation(addonSettingsChance * bodyMutationBlastModifier)) { bodyGenome.addonJointMotorList[i].motorForce[0] = MutateBodyFloatMult(bodyGenome.addonJointMotorList[i].motorForce[0], 0.01f, 200f); } if (CheckForMutation(addonSettingsChance * bodyMutationBlastModifier)) { bodyGenome.addonJointMotorList[i].motorSpeed[0] = MutateBodyFloatMult(bodyGenome.addonJointMotorList[i].motorSpeed[0], 0.01f, 200f); } } } for (int i = bodyGenome.addonThrusterEffector1DList.Count - 1; i >= 0; i--) { if (CheckForMutation(removeAddonChance * bodyMutationBlastModifier)) { // DELETE THIS ADD-ON!!! bodyGenome.addonThrusterEffector1DList.RemoveAt(i); } else { if (CheckForMutation(addonSettingsChance * bodyMutationBlastModifier)) { bodyGenome.addonThrusterEffector1DList[i].forwardVector[0] = MutateBodyVector3Normalized(bodyGenome.addonThrusterEffector1DList[i].forwardVector[0]); } if (CheckForMutation(addonSettingsChance * bodyMutationBlastModifier)) { bodyGenome.addonThrusterEffector1DList[i].maxForce[0] = MutateBodyFloatMult(bodyGenome.addonThrusterEffector1DList[i].maxForce[0], 0.01f, 100f); } } } for (int i = bodyGenome.addonThrusterEffector3DList.Count - 1; i >= 0; i--) { if (CheckForMutation(removeAddonChance * bodyMutationBlastModifier)) { // DELETE THIS ADD-ON!!! bodyGenome.addonThrusterEffector3DList.RemoveAt(i); } else { if (CheckForMutation(addonSettingsChance * bodyMutationBlastModifier)) { bodyGenome.addonThrusterEffector3DList[i].maxForce[0] = MutateBodyFloatMult(bodyGenome.addonThrusterEffector3DList[i].maxForce[0], 0.01f, 100f); } } } for (int i = bodyGenome.addonTorqueEffector1DList.Count - 1; i >= 0; i--) { if (CheckForMutation(removeAddonChance * bodyMutationBlastModifier)) { // DELETE THIS ADD-ON!!! bodyGenome.addonTorqueEffector1DList.RemoveAt(i); } else { if (CheckForMutation(addonSettingsChance * bodyMutationBlastModifier)) { bodyGenome.addonTorqueEffector1DList[i].maxTorque[0] = MutateBodyFloatMult(bodyGenome.addonTorqueEffector1DList[i].maxTorque[0], 0.01f, 100f); } if (CheckForMutation(addonSettingsChance * bodyMutationBlastModifier)) { bodyGenome.addonTorqueEffector1DList[i].axis[0] = MutateBodyVector3Normalized(bodyGenome.addonTorqueEffector1DList[i].axis[0]); } } } for (int i = bodyGenome.addonTorqueEffector3DList.Count - 1; i >= 0; i--) { if (CheckForMutation(removeAddonChance * bodyMutationBlastModifier)) { // DELETE THIS ADD-ON!!! bodyGenome.addonTorqueEffector3DList.RemoveAt(i); } else { if (CheckForMutation(addonSettingsChance * bodyMutationBlastModifier)) { bodyGenome.addonTorqueEffector3DList[i].maxTorque[0] = MutateBodyFloatMult(bodyGenome.addonTorqueEffector3DList[i].maxTorque[0], 0.01f, 100f); } } } for (int i = bodyGenome.addonMouthBasicList.Count - 1; i >= 0; i--) { if (CheckForMutation(removeAddonChance * bodyMutationBlastModifier)) { // DELETE THIS ADD-ON!!! bodyGenome.addonMouthBasicList.RemoveAt(i); } else { } } for (int i = bodyGenome.addonNoiseMakerBasicList.Count - 1; i >= 0; i--) { if (CheckForMutation(removeAddonChance * bodyMutationBlastModifier)) { // DELETE THIS ADD-ON!!! bodyGenome.addonNoiseMakerBasicList.RemoveAt(i); } else { if (CheckForMutation(addonSettingsChance * bodyMutationBlastModifier)) { bodyGenome.addonNoiseMakerBasicList[i].amplitude[0] = MutateBodyFloatMult(bodyGenome.addonNoiseMakerBasicList[i].amplitude[0], 0.01f, 100f); } } } for (int i = bodyGenome.addonStickyList.Count - 1; i >= 0; i--) { if (CheckForMutation(removeAddonChance * bodyMutationBlastModifier)) { // DELETE THIS ADD-ON!!! bodyGenome.addonStickyList.RemoveAt(i); } else { } } for (int i = bodyGenome.addonWeaponBasicList.Count - 1; i >= 0; i--) { if (CheckForMutation(removeAddonChance * bodyMutationBlastModifier)) { // DELETE THIS ADD-ON!!! bodyGenome.addonWeaponBasicList.RemoveAt(i); } else { if (CheckForMutation(addonSettingsChance * bodyMutationBlastModifier)) { bodyGenome.addonWeaponBasicList[i].strength[0] = MutateBodyFloatMult(bodyGenome.addonWeaponBasicList[i].strength[0], 0.01f, 100f); } } } // UPDATE BRAIN/BODY: brainGenome.AdjustBrainAfterBodyChange(ref bodyGenome); }
public Population BreedPopulation(ref Population sourcePopulation, int currentGeneration) { #region Pre-Crossover, Figuring out how many agents to breed etc. int LifetimeGeneration = currentGeneration + sourcePopulation.trainingGenerations; int totalNumWeightMutations = 0; //float totalWeightChangeValue = 0f; // go through species list and adjust fitness List<SpeciesBreedingPool> childSpeciesPoolsList = new List<SpeciesBreedingPool>(); // will hold agents in an internal list to facilitate crossover for (int s = 0; s < sourcePopulation.speciesBreedingPoolList.Count; s++) { SpeciesBreedingPool newChildSpeciesPool = new SpeciesBreedingPool(sourcePopulation.speciesBreedingPoolList[s].templateGenome, sourcePopulation.speciesBreedingPoolList[s].speciesID); // create Breeding Pools // copies the existing breeding pools but leaves their agentLists empty for future children childSpeciesPoolsList.Add(newChildSpeciesPool); // Add to list of pools } sourcePopulation.RankAgentArray(); // based on modified species fitness score, so compensated for species sizes Agent[] newAgentArray = new Agent[sourcePopulation.masterAgentArray.Length]; // Calculate total fitness score: float totalScore = 0f; if (survivalByRaffle) { for (int a = 0; a < sourcePopulation.populationMaxSize; a++) { // iterate through all agents totalScore += sourcePopulation.masterAgentArray[a].fitnessScoreSpecies; } } // Figure out How many Agents survive int numSurvivors = Mathf.RoundToInt(survivalRate * (float)sourcePopulation.populationMaxSize); //Depending on method, one at a time, select an Agent to survive until the max Number is reached int newChildIndex = 0; // For ( num Agents ) { for (int i = 0; i < numSurvivors; i++) { // If survival is by fitness score ranking: if (survivalByRank) { // Pop should already be ranked, so just traverse from top (best) to bottom (worst) newAgentArray[newChildIndex] = sourcePopulation.masterAgentArray[newChildIndex]; SpeciesBreedingPool survivingAgentBreedingPool = sourcePopulation.GetBreedingPoolByID(childSpeciesPoolsList, newAgentArray[newChildIndex].speciesID); survivingAgentBreedingPool.AddNewAgent(newAgentArray[newChildIndex]); //SortNewAgentIntoSpecies(newAgentArray[newChildIndex], childSpeciesList); // sorts this surviving agent into next generation's species' newChildIndex++; } // if survival is completely random, as a control: if (survivalStochastic) { int randomAgent = UnityEngine.Random.Range(0, numSurvivors - 1); // Set next newChild slot to a randomly-chosen agent within the survivor faction -- change to full random? newAgentArray[newChildIndex] = sourcePopulation.masterAgentArray[randomAgent]; SpeciesBreedingPool survivingAgentBreedingPool = sourcePopulation.GetBreedingPoolByID(childSpeciesPoolsList, newAgentArray[newChildIndex].speciesID); survivingAgentBreedingPool.AddNewAgent(newAgentArray[newChildIndex]); //SortNewAgentIntoSpecies(newAgentArray[newChildIndex], childSpeciesList); // sorts this surviving agent into next generation's species' newChildIndex++; } // if survival is based on a fitness lottery: if (survivalByRaffle) { // Try when Fitness is normalized from 0-1 float randomSlicePosition = UnityEngine.Random.Range(0f, totalScore); float accumulatedFitness = 0f; for (int a = 0; a < sourcePopulation.populationMaxSize; a++) { // iterate through all agents accumulatedFitness += sourcePopulation.masterAgentArray[a].fitnessScoreSpecies; // if accum fitness is on slicePosition, copy this Agent //Debug.Log("NumSurvivors: " + numSurvivors.ToString() + ", Surviving Agent " + a.ToString() + ": AccumFitness: " + accumulatedFitness.ToString() + ", RafflePos: " + randomSlicePosition.ToString() + ", TotalScore: " + totalScore.ToString() + ", newChildIndex: " + newChildIndex.ToString()); if (accumulatedFitness >= randomSlicePosition) { newAgentArray[newChildIndex] = sourcePopulation.masterAgentArray[a]; // add to next gen's list of agents SpeciesBreedingPool survivingAgentBreedingPool = sourcePopulation.GetBreedingPoolByID(childSpeciesPoolsList, newAgentArray[newChildIndex].speciesID); survivingAgentBreedingPool.AddNewAgent(newAgentArray[newChildIndex]); //SortNewAgentIntoSpecies(newAgentArray[newChildIndex], childSpeciesList); // sorts this surviving agent into next generation's species' newChildIndex++; break; } } } } // Figure out how many new agents must be created to fill up the new population: int numNewChildAgents = sourcePopulation.populationMaxSize - numSurvivors; int numEligibleBreederAgents = Mathf.RoundToInt(breedingRate * (float)sourcePopulation.populationMaxSize); int currentRankIndex = 0; // Once the agents are ranked, trim the BreedingPools of agents that didn't make the cut for mating: if(useSpeciation) { for (int s = 0; s < sourcePopulation.speciesBreedingPoolList.Count; s++) { int index = 0; int failsafe = 0; int numAgents = sourcePopulation.speciesBreedingPoolList[s].agentList.Count; while (index < numAgents) { if (index < sourcePopulation.speciesBreedingPoolList[s].agentList.Count) { if (sourcePopulation.speciesBreedingPoolList[s].agentList[index].fitnessRank >= numEligibleBreederAgents) { sourcePopulation.speciesBreedingPoolList[s].agentList.RemoveAt(index); } else { index++; } } else { break; } failsafe++; if (failsafe > 500) { Debug.Log("INFINITE LOOP! hit failsafe 500 iters -- Trimming BreedingPools!"); break; } } //Debug.Log("BreedPopulation -- TRIMSpeciesPool# " + s.ToString() + ", id: " + sourcePopulation.speciesBreedingPoolList[s].speciesID.ToString() + ", Count: " + sourcePopulation.speciesBreedingPoolList[s].agentList.Count.ToString()); // } } float totalScoreBreeders = 0f; if (breedingByRaffle) { // calculate total fitness scores to determine lottery weights for (int a = 0; a < numEligibleBreederAgents; a++) { // iterate through all agents totalScoreBreeders += sourcePopulation.masterAgentArray[a].fitnessScoreSpecies; } } #endregion // Iterate over numAgentsToCreate : int newChildrenCreated = 0; while (newChildrenCreated < numNewChildAgents) { // Find how many parents random number btw min/max: int numParentAgents = 2; // UnityEngine.Random.Range(minNumParents, maxNumParents); int numChildAgents = 1; // defaults to one child, but: if (numNewChildAgents - newChildrenCreated >= 2) { // room for two more! numChildAgents = 2; } Agent[] parentAgentsArray = new Agent[numParentAgents]; // assume 2 for now? yes, so far.... List<GeneNodeNEAT>[] parentNodeListArray = new List<GeneNodeNEAT>[numParentAgents]; List<GeneLinkNEAT>[] parentLinkListArray = new List<GeneLinkNEAT>[numParentAgents]; Agent firstParentAgent = SelectAgentFromPopForBreeding(sourcePopulation, numEligibleBreederAgents, ref currentRankIndex); parentAgentsArray[0] = firstParentAgent; List<GeneNodeNEAT> firstParentNodeList = firstParentAgent.brainGenome.nodeNEATList; List<GeneLinkNEAT> firstParentLinkList = firstParentAgent.brainGenome.linkNEATList; //List<GeneNodeNEAT> firstParentNodeList = new List<GeneNodeNEAT>(); //List<GeneLinkNEAT> firstParentLinkList = new List<GeneLinkNEAT>(); //firstParentNodeList = firstParentAgent.brainGenome.nodeNEATList; //firstParentLinkList = firstParentAgent.brainGenome.linkNEATList; parentNodeListArray[0] = firstParentNodeList; parentLinkListArray[0] = firstParentLinkList; Agent secondParentAgent; SpeciesBreedingPool parentAgentBreedingPool = sourcePopulation.GetBreedingPoolByID(sourcePopulation.speciesBreedingPoolList, firstParentAgent.speciesID); if (useSpeciation) { //parentAgentBreedingPool float randBreedOutsideSpecies = UnityEngine.Random.Range(0f, 1f); if (randBreedOutsideSpecies < interspeciesBreedingRate) { // Attempts to Found a new species // allowed to breed outside its own species: secondParentAgent = SelectAgentFromPopForBreeding(sourcePopulation, numEligibleBreederAgents, ref currentRankIndex); } else { // Selects mate only from within its own species: secondParentAgent = SelectAgentFromPoolForBreeding(parentAgentBreedingPool); } } else { secondParentAgent = SelectAgentFromPopForBreeding(sourcePopulation, numEligibleBreederAgents, ref currentRankIndex); } parentAgentsArray[1] = secondParentAgent; List<GeneNodeNEAT> secondParentNodeList = secondParentAgent.brainGenome.nodeNEATList; List<GeneLinkNEAT> secondParentLinkList = secondParentAgent.brainGenome.linkNEATList; //List<GeneNodeNEAT> secondParentNodeList = new List<GeneNodeNEAT>(); //List<GeneLinkNEAT> secondParentLinkList = new List<GeneLinkNEAT>(); //secondParentNodeList = secondParentAgent.brainGenome.nodeNEATList; //secondParentLinkList = secondParentAgent.brainGenome.linkNEATList; parentNodeListArray[1] = secondParentNodeList; parentLinkListArray[1] = secondParentLinkList; // Iterate over ChildArray.Length : // how many newAgents created for (int c = 0; c < numChildAgents; c++) { // for number of child Agents in floatArray[][]: Agent newChildAgent = new Agent(); List<GeneNodeNEAT> childNodeList = new List<GeneNodeNEAT>(); List<GeneLinkNEAT> childLinkList = new List<GeneLinkNEAT>(); GenomeNEAT childBrainGenome = new GenomeNEAT(); childBrainGenome.nodeNEATList = childNodeList; childBrainGenome.linkNEATList = childLinkList; int numEnabledLinkGenes = 0; if (useCrossover) { int nextLinkInnoA = 0; int nextLinkInnoB = 0; //int nextBodyNodeInno = 0; //int nextBodyAddonInno = 0; int failsafeMax = 500; int failsafe = 0; int parentListIndexA = 0; int parentListIndexB = 0; //int parentBodyNodeIndex = 0; bool parentDoneA = false; bool parentDoneB = false; bool endReached = false; int moreFitParent = 0; // which parent is more Fit if (parentAgentsArray[0].fitnessScoreSpecies < parentAgentsArray[1].fitnessScoreSpecies) { moreFitParent = 1; } else if (parentAgentsArray[0].fitnessScoreSpecies == parentAgentsArray[1].fitnessScoreSpecies) { moreFitParent = Mathf.RoundToInt(UnityEngine.Random.Range(0f, 1f)); } // MATCH UP Links between both agents, if they have a gene with matching Inno#, then mixing can occur while (!endReached) { failsafe++; if(failsafe > failsafeMax) { Debug.Log("failsafe reached!"); break; } // inno# of next links: if(parentLinkListArray[0].Count > parentListIndexA) { nextLinkInnoA = parentLinkListArray[0][parentListIndexA].innov; } else { parentDoneA = true; } if (parentLinkListArray[1].Count > parentListIndexB) { nextLinkInnoB = parentLinkListArray[1][parentListIndexB].innov; } else { parentDoneB = true; } int innoDelta = nextLinkInnoA - nextLinkInnoB; // 0=match, neg= Aextra, pos= Bextra if (parentDoneA && !parentDoneB) { innoDelta = 1; } if (parentDoneB && !parentDoneA) { innoDelta = -1; } if (parentDoneA && parentDoneB) { // reached end of both parent's linkLists endReached = true; break; } if (innoDelta < 0) { // Parent A has an earlier link mutation //Debug.Log("newChildIndex: " + newChildIndex.ToString() + ", IndexA: " + parentListIndexA.ToString() + ", IndexB: " + parentListIndexB.ToString() + ", innoDelta < 0 (" + innoDelta.ToString() + ") -- moreFitP: " + moreFitParent.ToString() + ", nextLinkInnoA: " + nextLinkInnoA.ToString() + ", nextLinkInnoB: " + nextLinkInnoB.ToString()); if (moreFitParent == 0) { // Parent A is more fit: GeneLinkNEAT newChildLink = new GeneLinkNEAT(parentLinkListArray[0][parentListIndexA].fromNodeID, parentLinkListArray[0][parentListIndexA].toNodeID, parentLinkListArray[0][parentListIndexA].weight, parentLinkListArray[0][parentListIndexA].enabled, parentLinkListArray[0][parentListIndexA].innov, parentLinkListArray[0][parentListIndexA].birthGen); childLinkList.Add(newChildLink); if (parentLinkListArray[0][parentListIndexA].enabled) numEnabledLinkGenes++; } else { if(CheckForMutation(crossoverRandomLinkChance)) { // was less fit parent, but still passed on a gene!: GeneLinkNEAT newChildLink = new GeneLinkNEAT(parentLinkListArray[0][parentListIndexA].fromNodeID, parentLinkListArray[0][parentListIndexA].toNodeID, parentLinkListArray[0][parentListIndexA].weight, parentLinkListArray[0][parentListIndexA].enabled, parentLinkListArray[0][parentListIndexA].innov, parentLinkListArray[0][parentListIndexA].birthGen); childLinkList.Add(newChildLink); } } parentListIndexA++; } if (innoDelta > 0) { // Parent B has an earlier link mutation //Debug.Log("newChildIndex: " + newChildIndex.ToString() + ", IndexA: " + parentListIndexA.ToString() + ", IndexB: " + parentListIndexB.ToString() + ", innoDelta > 0 (" + innoDelta.ToString() + ") -- moreFitP: " + moreFitParent.ToString() + ", nextLinkInnoA: " + nextLinkInnoA.ToString() + ", nextLinkInnoB: " + nextLinkInnoB.ToString()); if (moreFitParent == 1) { // Parent B is more fit: GeneLinkNEAT newChildLink = new GeneLinkNEAT(parentLinkListArray[1][parentListIndexB].fromNodeID, parentLinkListArray[1][parentListIndexB].toNodeID, parentLinkListArray[1][parentListIndexB].weight, parentLinkListArray[1][parentListIndexB].enabled, parentLinkListArray[1][parentListIndexB].innov, parentLinkListArray[1][parentListIndexB].birthGen); childLinkList.Add(newChildLink); if (parentLinkListArray[1][parentListIndexB].enabled) numEnabledLinkGenes++; } else { if (CheckForMutation(crossoverRandomLinkChance)) { // was less fit parent, but still passed on a gene!: GeneLinkNEAT newChildLink = new GeneLinkNEAT(parentLinkListArray[1][parentListIndexB].fromNodeID, parentLinkListArray[1][parentListIndexB].toNodeID, parentLinkListArray[1][parentListIndexB].weight, parentLinkListArray[1][parentListIndexB].enabled, parentLinkListArray[1][parentListIndexB].innov, parentLinkListArray[1][parentListIndexB].birthGen); childLinkList.Add(newChildLink); } } parentListIndexB++; } if (innoDelta == 0) { // Match! float randParentIndex = UnityEngine.Random.Range(0f, 1f); float newWeightValue; if (randParentIndex < 0.5) { // ParentA wins: newWeightValue = parentLinkListArray[0][parentListIndexA].weight; } else { // ParentB wins: newWeightValue = parentLinkListArray[1][parentListIndexB].weight; } //Debug.Log("newChildIndex: " + newChildIndex.ToString() + ", IndexA: " + parentListIndexA.ToString() + ", IndexB: " + parentListIndexB.ToString() + ", innoDelta == 0 (" + innoDelta.ToString() + ") -- moreFitP: " + moreFitParent.ToString() + ", nextLinkInnoA: " + nextLinkInnoA.ToString() + ", nextLinkInnoB: " + nextLinkInnoB.ToString() + ", randParent: " + randParentIndex.ToString() + ", weight: " + newWeightValue.ToString()); GeneLinkNEAT newChildLink = new GeneLinkNEAT(parentLinkListArray[0][parentListIndexA].fromNodeID, parentLinkListArray[0][parentListIndexA].toNodeID, newWeightValue, parentLinkListArray[0][parentListIndexA].enabled, parentLinkListArray[0][parentListIndexA].innov, parentLinkListArray[0][parentListIndexA].birthGen); childLinkList.Add(newChildLink); if (parentLinkListArray[0][parentListIndexA].enabled) numEnabledLinkGenes++; parentListIndexA++; parentListIndexB++; } } // once childLinkList is built -- use nodes of the moreFit parent: for (int i = 0; i < parentNodeListArray[moreFitParent].Count; i++) { // iterate through all nodes in the parent List and copy them into fresh new geneNodes: GeneNodeNEAT clonedNode = new GeneNodeNEAT(parentNodeListArray[moreFitParent][i].id, parentNodeListArray[moreFitParent][i].nodeType, parentNodeListArray[moreFitParent][i].activationFunction, parentNodeListArray[moreFitParent][i].sourceAddonInno, parentNodeListArray[moreFitParent][i].sourceAddonRecursionNum, false, parentNodeListArray[moreFitParent][i].sourceAddonChannelNum); childNodeList.Add(clonedNode); } if (useMutation) { // BODY MUTATION: //PerformBodyMutation(ref childBodyGenome, ref childBrainGenome); // NEED TO ADJUST BRAINS IF MUTATION CHANGES #NODES!!!! // BRAIN MUTATION: if (numEnabledLinkGenes < 1) numEnabledLinkGenes = 1; for (int k = 0; k < childLinkList.Count; k++) { float mutateChance = mutationBlastModifier * masterMutationRate / (1f + (float)numEnabledLinkGenes * 0.15f); if (LifetimeGeneration - childLinkList[k].birthGen < newLinkBonusDuration) { float t = 1 - ((LifetimeGeneration - childLinkList[k].birthGen) / (float)newLinkBonusDuration); // t=0 means age of gene is same as bonusDuration, t=1 means it is brand new mutateChance = Mathf.Lerp(mutateChance, mutateChance * newLinkMutateBonus, t); } if (CheckForMutation(mutateChance)) { // Weight Mutation! //Debug.Log("Weight Mutation Link[" + k.ToString() + "] weight: " + childLinkList[k].weight.ToString() + ", mutate: " + MutateFloat(childLinkList[k].weight).ToString()); childLinkList[k].weight = MutateFloat(childLinkList[k].weight); totalNumWeightMutations++; } } if (CheckForMutation(mutationBlastModifier * mutationRemoveLinkChance)) { //Debug.Log("Remove Link Mutation Agent[" + newChildIndex.ToString() + "]"); childBrainGenome.RemoveRandomLink(); } if (CheckForMutation(mutationBlastModifier * mutationAddNodeChance)) { // Adds a new node //Debug.Log("Add Node Mutation Agent[" + newChildIndex.ToString() + "]"); childBrainGenome.AddNewRandomNode(LifetimeGeneration, GetNextAddonInnov()); } if (CheckForMutation(mutationBlastModifier * mutationRemoveNodeChance)) { // Adds a new node //Debug.Log("Add Node Mutation Agent[" + newChildIndex.ToString() + "]"); childBrainGenome.RemoveRandomNode(); } if (CheckForMutation(mutationBlastModifier * mutationAddLinkChance)) { // Adds new connection //Debug.Log("Add Link Mutation Agent[" + newChildIndex.ToString() + "]"); if (CheckForMutation(existingNetworkBias)) { childBrainGenome.AddNewExtraLink(existingFromNodeBias, LifetimeGeneration); } else { childBrainGenome.AddNewRandomLink(LifetimeGeneration); } } if (CheckForMutation(mutationBlastModifier * mutationActivationFunctionChance)) { TransferFunctions.TransferFunction newFunction; int randIndex = Mathf.RoundToInt(UnityEngine.Random.Range(0f, childNodeList.Count - 1)); int randomTF = (int)UnityEngine.Random.Range(0f, 12f); switch (randomTF) { case 0: newFunction = TransferFunctions.TransferFunction.RationalSigmoid; break; case 1: newFunction = TransferFunctions.TransferFunction.Linear; break; case 2: newFunction = TransferFunctions.TransferFunction.Gaussian; break; case 3: newFunction = TransferFunctions.TransferFunction.Abs; break; case 4: newFunction = TransferFunctions.TransferFunction.Cos; break; case 5: newFunction = TransferFunctions.TransferFunction.Sin; break; case 6: newFunction = TransferFunctions.TransferFunction.Tan; break; case 7: newFunction = TransferFunctions.TransferFunction.Square; break; case 8: newFunction = TransferFunctions.TransferFunction.Threshold01; break; case 9: newFunction = TransferFunctions.TransferFunction.ThresholdNegPos; break; case 10: newFunction = TransferFunctions.TransferFunction.RationalSigmoid; break; case 11: newFunction = TransferFunctions.TransferFunction.RationalSigmoid; break; case 12: newFunction = TransferFunctions.TransferFunction.RationalSigmoid; break; default: newFunction = TransferFunctions.TransferFunction.RationalSigmoid; break; } if (childNodeList[randIndex].nodeType != GeneNodeNEAT.GeneNodeType.Out) { // keep outputs -1 to 1 range Debug.Log("ActivationFunction Mutation Node[" + randIndex.ToString() + "] prev: " + childNodeList[randIndex].activationFunction.ToString() + ", new: " + newFunction.ToString()); childNodeList[randIndex].activationFunction = newFunction; } } } else { Debug.Log("Mutation Disabled!"); } // THE BODY ==========!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!====================================================================================== CritterGenome childBodyGenome = new CritterGenome(); // create new body genome for Child // This creates the ROOT NODE!!!! // Clone Nodes & Addons from more fit parent to create new child body genome // crossover is on, so check for matching Nodes and Add-ons (based on Inno#'s) to determine when to mix Settings/Attributes: // Iterate over the nodes of the more fit parent: for (int i = 0; i < parentAgentsArray[moreFitParent].bodyGenome.CritterNodeList.Count; i++) { int currentNodeInno = parentAgentsArray[moreFitParent].bodyGenome.CritterNodeList[i].innov; if (i == 0) { // if this is the ROOT NODE: childBodyGenome.CritterNodeList[0].CopySettingsFromNode(parentAgentsArray[moreFitParent].bodyGenome.CritterNodeList[0]); // The root node was already created during the Constructor method of the CritterGenome, // ... so instead of creating a new one, just copy the settings } else { // NOT the root node, proceed normally: // Create new cloned node defaulted to the settings of the source( more-fit parent's) Node: CritterNode clonedCritterNode = parentAgentsArray[moreFitParent].bodyGenome.CritterNodeList[i].CloneThisCritterNode(); // Check other parent for same node: for (int j = 0; j < parentAgentsArray[1 - moreFitParent].bodyGenome.CritterNodeList.Count; j++) { if (parentAgentsArray[1 - moreFitParent].bodyGenome.CritterNodeList[j].innov == currentNodeInno) { // CROSSOVER NODE SETTINGS HERE!!! ---- If random dice roll > 0.5, use less fit parent's settings, otherwise leave as default BodyCrossover(ref clonedCritterNode, parentAgentsArray[1 - moreFitParent].bodyGenome.CritterNodeList[j]); } } childBodyGenome.CritterNodeList.Add(clonedCritterNode); } } // ADD-ONS!!!!!!!!!!!!!!!!!!!!!! BreedCritterAddons(ref childBodyGenome, ref parentAgentsArray[moreFitParent].bodyGenome, ref parentAgentsArray[1 - moreFitParent].bodyGenome); newChildAgent.bodyGenome = childBodyGenome; // ????? if (useMutation) { // BODY MUTATION: PerformBodyMutation(ref childBodyGenome, ref childBrainGenome); } } else { // no crossover: //=============================================================================================== for (int i = 0; i < parentNodeListArray[0].Count; i++) { // iterate through all nodes in the parent List and copy them into fresh new geneNodes: GeneNodeNEAT clonedNode = new GeneNodeNEAT(parentNodeListArray[0][i].id, parentNodeListArray[0][i].nodeType, parentNodeListArray[0][i].activationFunction, parentNodeListArray[0][i].sourceAddonInno, parentNodeListArray[0][i].sourceAddonRecursionNum, false, parentNodeListArray[0][i].sourceAddonChannelNum); childNodeList.Add(clonedNode); } for (int j = 0; j < parentLinkListArray[0].Count; j++) { //same thing with connections GeneLinkNEAT clonedLink = new GeneLinkNEAT(parentLinkListArray[0][j].fromNodeID, parentLinkListArray[0][j].toNodeID, parentLinkListArray[0][j].weight, parentLinkListArray[0][j].enabled, parentLinkListArray[0][j].innov, parentLinkListArray[0][j].birthGen); childLinkList.Add(clonedLink); if (parentLinkListArray[0][j].enabled) numEnabledLinkGenes++; } // MUTATION: if (useMutation) { // BODY MUTATION: //childBrainGenome.nodeNEATList = childNodeList //PerformBodyMutation(ref childBodyGenome, ref childBrainGenome); // BRAIN MUTATION: if (numEnabledLinkGenes < 1) numEnabledLinkGenes = 1; for (int k = 0; k < childLinkList.Count; k++) { float mutateChance = mutationBlastModifier * masterMutationRate / (1f + (float)numEnabledLinkGenes * 0.15f); if (LifetimeGeneration - childLinkList[k].birthGen < newLinkBonusDuration) { float t = 1 - ((LifetimeGeneration - childLinkList[k].birthGen) / (float)newLinkBonusDuration); // t=0 means age of gene is same as bonusDuration, t=1 means it is brand new mutateChance = Mathf.Lerp(mutateChance, mutateChance * newLinkMutateBonus, t); } if (CheckForMutation(mutateChance)) { // Weight Mutation! //Debug.Log("Weight Mutation Link[" + k.ToString() + "] weight: " + childLinkList[k].weight.ToString() + ", mutate: " + MutateFloat(childLinkList[k].weight).ToString()); childLinkList[k].weight = MutateFloat(childLinkList[k].weight); totalNumWeightMutations++; } } if (CheckForMutation(mutationBlastModifier * mutationRemoveLinkChance)) { //Debug.Log("Remove Link Mutation Agent[" + newChildIndex.ToString() + "]"); childBrainGenome.RemoveRandomLink(); } if (CheckForMutation(mutationBlastModifier * mutationAddNodeChance)) { // Adds a new node //Debug.Log("Add Node Mutation Agent[" + newChildIndex.ToString() + "]"); childBrainGenome.AddNewRandomNode(LifetimeGeneration, GetNextAddonInnov()); } if (CheckForMutation(mutationBlastModifier * mutationAddLinkChance)) { // Adds new connection //Debug.Log("Add Link Mutation Agent[" + newChildIndex.ToString() + "]"); if(CheckForMutation(existingNetworkBias)) { childBrainGenome.AddNewExtraLink(existingFromNodeBias, LifetimeGeneration); } else { childBrainGenome.AddNewRandomLink(LifetimeGeneration); } } if (CheckForMutation(mutationBlastModifier * mutationActivationFunctionChance)) { TransferFunctions.TransferFunction newFunction; int randIndex = Mathf.RoundToInt(UnityEngine.Random.Range(0f, childNodeList.Count - 1)); int randomTF = (int)UnityEngine.Random.Range(0f, 12f); switch (randomTF) { case 0: newFunction = TransferFunctions.TransferFunction.RationalSigmoid; break; case 1: newFunction = TransferFunctions.TransferFunction.Linear; break; case 2: newFunction = TransferFunctions.TransferFunction.Gaussian; break; case 3: newFunction = TransferFunctions.TransferFunction.Abs; break; case 4: newFunction = TransferFunctions.TransferFunction.Cos; break; case 5: newFunction = TransferFunctions.TransferFunction.Sin; break; case 6: newFunction = TransferFunctions.TransferFunction.Tan; break; case 7: newFunction = TransferFunctions.TransferFunction.Square; break; case 8: newFunction = TransferFunctions.TransferFunction.Threshold01; break; case 9: newFunction = TransferFunctions.TransferFunction.ThresholdNegPos; break; case 10: newFunction = TransferFunctions.TransferFunction.RationalSigmoid; break; case 11: newFunction = TransferFunctions.TransferFunction.RationalSigmoid; break; case 12: newFunction = TransferFunctions.TransferFunction.RationalSigmoid; break; default: newFunction = TransferFunctions.TransferFunction.RationalSigmoid; break; } if (childNodeList[randIndex].nodeType != GeneNodeNEAT.GeneNodeType.Out) { // keep outputs -1 to 1 range Debug.Log("ActivationFunction Mutation Node[" + randIndex.ToString() + "] prev: " + childNodeList[randIndex].activationFunction.ToString() + ", new: " + newFunction.ToString()); childNodeList[randIndex].activationFunction = newFunction; } } //for (int t = 0; t < childNodeList.Count; t++) { //} } else { Debug.Log("Mutation Disabled!"); } // THE BODY!!!!! ++++++++++++++++++++++================+++++++++++++++++++===============+++++++++++++++++++===================+++++++++++++++++============== CritterGenome childBodyGenome = new CritterGenome(); // create new body genome for Child // Iterate over the nodes of the more fit parent: for (int i = 0; i < parentAgentsArray[0].bodyGenome.CritterNodeList.Count; i++) { int currentNodeInno = parentAgentsArray[0].bodyGenome.CritterNodeList[i].innov; if (i == 0) { // if this is the ROOT NODE: childBodyGenome.CritterNodeList[0].CopySettingsFromNode(parentAgentsArray[0].bodyGenome.CritterNodeList[0]); // The root node was already created during the Constructor method of the CritterGenome, // ... so instead of creating a new one, just copy the settings } else { // NOT the root node, proceed normally: // Create new cloned node defaulted to the settings of the source( more-fit parent's) Node: CritterNode clonedCritterNode = parentAgentsArray[0].bodyGenome.CritterNodeList[i].CloneThisCritterNode(); childBodyGenome.CritterNodeList.Add(clonedCritterNode); } } // ADD-ONS!!!!!!!!!!!!!!!!!!!!!! BreedCritterAddons(ref childBodyGenome, ref parentAgentsArray[0].bodyGenome, ref parentAgentsArray[0].bodyGenome); newChildAgent.bodyGenome = childBodyGenome; if (useMutation) { // BODY MUTATION: PerformBodyMutation(ref childBodyGenome, ref childBrainGenome); } } newChildAgent.brainGenome = childBrainGenome; //newChildAgent.brainGenome.nodeNEATList = childNodeList; //newChildAgent.brainGenome.linkNEATList = childLinkList; BrainNEAT childBrain = new BrainNEAT(newChildAgent.brainGenome); childBrain.BuildBrainNetwork(); newChildAgent.brain = childBrain; //Debug.Log("NEW CHILD numNodes: " + newChildAgent.brainGenome.nodeNEATList.Count.ToString() + ", #Neurons: " + newChildAgent.brain.neuronList.Count.ToString()); //newChildAgent.bodyGenome.PreBuildCritter(0.8f); // Species: if (useSpeciation) { float randAdoption = UnityEngine.Random.Range(0f, 1f); if (randAdoption < adoptionRate) { // Attempts to Found a new species bool speciesGenomeMatch = false; for (int s = 0; s < childSpeciesPoolsList.Count; s++) { float geneticDistance = GenomeNEAT.MeasureGeneticDistance(newChildAgent.brainGenome, childSpeciesPoolsList[s].templateGenome, neuronWeight, linkWeight, weightWeight, normalizeExcess, normalizeDisjoint, normalizeLinkWeight); if (geneticDistance < speciesSimilarityThreshold) { speciesGenomeMatch = true; //agent.speciesID = speciesBreedingPoolList[s].speciesID; // this is done inside the AddNewAgent method below v v v childSpeciesPoolsList[s].AddNewAgent(newChildAgent); //Debug.Log(" NEW CHILD (" + newChildIndex.ToString() + ") SortAgentIntoBreedingPool dist: " + geneticDistance.ToString() + ", speciesIDs: " + newChildAgent.speciesID.ToString() + ", " + childSpeciesPoolsList[s].speciesID.ToString() + ", speciesCount: " + childSpeciesPoolsList[s].agentList.Count.ToString()); break; } } if (!speciesGenomeMatch) { SpeciesBreedingPool newSpeciesBreedingPool = new SpeciesBreedingPool(newChildAgent.brainGenome, sourcePopulation.GetNextSpeciesID()); // creates new speciesPool modeled on this agent's genome newSpeciesBreedingPool.AddNewAgent(newChildAgent); // add this agent to breeding pool childSpeciesPoolsList.Add(newSpeciesBreedingPool); // add new speciesPool to the population's list of all active species //Debug.Log(" NEW CHILD (" + newChildIndex.ToString() + ") SortAgentIntoBreedingPool NO MATCH!!! -- creating new BreedingPool " + newSpeciesBreedingPool.speciesID.ToString() + ", newChildAgentSpeciesID: " + newChildAgent.speciesID.ToString()); } } else { // joins parent species automatically: SpeciesBreedingPool newSpeciesBreedingPool = sourcePopulation.GetBreedingPoolByID(childSpeciesPoolsList, parentAgentBreedingPool.speciesID); newSpeciesBreedingPool.AddNewAgent(newChildAgent); // add this agent to breeding pool //Debug.Log(" NEW CHILD (" + newChildIndex.ToString() + ") NO ADOPTION SortAgentIntoBreedingPool speciesIDs: " + newChildAgent.speciesID.ToString() + ", " + newSpeciesBreedingPool.speciesID.ToString() + ", speciesCount: " + newSpeciesBreedingPool.agentList.Count.ToString()); } } else { // joins parent species automatically: SpeciesBreedingPool newSpeciesBreedingPool = sourcePopulation.GetBreedingPoolByID(childSpeciesPoolsList, parentAgentBreedingPool.speciesID); newSpeciesBreedingPool.AddNewAgent(newChildAgent); // add this agent to breeding pool } newChildAgent.parentFitnessScoreA = sourcePopulation.masterAgentArray[newChildIndex].fitnessScore; newAgentArray[newChildIndex] = newChildAgent; newChildIndex++; // new child created! newChildrenCreated++; } } /*Debug.Log("Finished Crossover! childSpeciesPoolsList:"); for (int i = 0; i < sourcePopulation.speciesBreedingPoolList.Count; i++) { string poolString = " Child Species ID: " + sourcePopulation.speciesBreedingPoolList[i].speciesID.ToString(); for (int j = 0; j < sourcePopulation.speciesBreedingPoolList[i].agentList.Count; j++) { poolString += ", member# " + j.ToString() + ", species: " + sourcePopulation.speciesBreedingPoolList[i].agentList[j].speciesID.ToString() + ", fitRank: " + sourcePopulation.speciesBreedingPoolList[i].agentList[j].fitnessRank.ToString(); } Debug.Log(poolString); }*/ // Clear out extinct species: int listIndex = 0; for (int s = 0; s < childSpeciesPoolsList.Count; s++) { if (listIndex >= childSpeciesPoolsList.Count) { Debug.Log("end childSpeciesPoolsList " + childSpeciesPoolsList.Count.ToString() + ", index= " + listIndex.ToString()); break; } else { if (childSpeciesPoolsList[listIndex].agentList.Count == 0) { // if empty: //Debug.Log("Species " + childSpeciesPoolsList[listIndex].speciesID.ToString() + " WENT EXTINCT!!! --- childSpeciesPoolsList[" + listIndex.ToString() + "] old Count: " + childSpeciesPoolsList.Count.ToString() + ", s: " + s.ToString()); childSpeciesPoolsList.RemoveAt(listIndex); //s--; // see if this works } else { listIndex++; } } } Debug.Log("Finished Crossover! totalNumWeightMutations: " + totalNumWeightMutations.ToString() + ", mutationBlastModifier: " + mutationBlastModifier.ToString() + ", bodyMutationBlastModifier: " + bodyMutationBlastModifier.ToString() + ", LifetimeGeneration: " + LifetimeGeneration.ToString() + ", currentGeneration: " + currentGeneration.ToString() + ", sourcePopulation.trainingGenerations: " + sourcePopulation.trainingGenerations.ToString()); sourcePopulation.masterAgentArray = newAgentArray; sourcePopulation.speciesBreedingPoolList = childSpeciesPoolsList; /*Debug.Log("Finished Crossover! sourcePopulation.speciesBreedingPoolList:"); for (int i = 0; i < sourcePopulation.speciesBreedingPoolList.Count; i++) { string poolString = "New Species ID: " + sourcePopulation.speciesBreedingPoolList[i].speciesID.ToString(); for (int j = 0; j < sourcePopulation.speciesBreedingPoolList[i].agentList.Count; j++) { poolString += ", member# " + j.ToString() + ", species: " + sourcePopulation.speciesBreedingPoolList[i].agentList[j].speciesID.ToString() + ", fitRank: " + sourcePopulation.speciesBreedingPoolList[i].agentList[j].fitnessRank.ToString(); } Debug.Log(poolString); }*/ return sourcePopulation; }
public BrainNEAT(GenomeNEAT newGenome) { sourceGenome = newGenome; visitedNodes = new List<NeuronNEAT>(); completedNodes = new List<NeuronNEAT>(); }
public void InitializeBrainFromGenome(GenomeNEAT newGenome) { sourceGenome = newGenome; }
public GenomeNEAT InitializeBlankBrain(int numInputNodes, int numOutputNodes) { sourceGenome = new GenomeNEAT(numInputNodes, numOutputNodes); // create blank genome with no connections /*int numNewLinks = 0; int numNewNodes = 0; for(int i = 0; i < numNewLinks; i++) { sourceGenome.AddNewRandomLink(0); } for (int j = 0; j < numNewNodes; j++) { sourceGenome.AddNewRandomNode(0); }*/ //Debug.Log("InitializeBlankBrain #nodes: " + sourceGenome.nodeNEATList.Count.ToString() + ", #links: " + sourceGenome.linkNEATList.Count.ToString()); return sourceGenome; }
public GenomeNEAT InitializeNewBrain(CritterGenome critterBodyGenome, int numHiddenNodes, float connectedness, bool randomWeights) { // OLD //sourceGenome = new GenomeNEAT(numInputNodes, numHiddenNodes, numOutputNodes); // create blank genome with no connections sourceGenome = new GenomeNEAT(critterBodyGenome, numHiddenNodes); // create blank genome with no connections sourceGenome.CreateInitialConnections(connectedness, randomWeights); //Debug.Log("InitializeBlankBrain #nodes: " + sourceGenome.nodeNEATList.Count.ToString() + ", #links: " + sourceGenome.linkNEATList.Count.ToString()); return sourceGenome; }
public GenomeNEAT InitializeRandomBrain(int numInputNodes, int numOutputNodes) { sourceGenome = new GenomeNEAT(numInputNodes, numOutputNodes); // create blank genome with no connections sourceGenome.CreateMinimumRandomConnections(); // Add links to each output node froma random input node return sourceGenome; }
public BrainNEAT(GenomeNEAT newGenome) { sourceGenome = newGenome; visitedNodes = new List <NeuronNEAT>(); completedNodes = new List <NeuronNEAT>(); }
public void ApplyTrainingModifierEffects(Trainer trainer) { int currentGen = trainer.PlayingCurGeneration; if (trainer.loadedTrainingSave != null) { currentGen += trainer.loadedTrainingSave.endGeneration; } //Debug.Log("ApplyTrainingModifierEffects currentGen: " + currentGen.ToString()); CrossoverManager crossoverManager = trainer.PlayerList[0].masterCupid; int numModifiers = activeTrainingModifierList.Count; crossoverManager.mutationBlastModifier = 1f; crossoverManager.bodyMutationBlastModifier = 1f; if (numModifiers > 0) { for (int i = numModifiers - 1; i >= 0; i--) { float t = 0f; switch (activeTrainingModifierList[i].modifierType) { case TrainingModifier.TrainingModifierType.LinkExplosion: // go through all agents and pump them up -- THIS WILL NEED IMPROVEMENTS!!!! for (int a = 0; a < trainer.PlayerList[0].masterPopulation.masterAgentArray.Length; a++) { GenomeNEAT genome = trainer.PlayerList[0].masterPopulation.masterAgentArray[a].brainGenome; int numNodes = genome.nodeNEATList.Count; int numNewLinks = (int)((float)numNodes * activeTrainingModifierList[i].linksPerNode); for (int n = 0; n < numNewLinks; n++) { genome.AddNewRandomLink(currentGen); } int numLinks = genome.linkNEATList.Count; int numNewNodes = (int)((float)numLinks * activeTrainingModifierList[i].nodesPerLink); for (int b = 0; b < numNewNodes; b++) { genome.AddNewRandomNode(currentGen, crossoverManager.GetNextAddonInnov()); } } activeTrainingModifierList.RemoveAt(i); break; case TrainingModifier.TrainingModifierType.MutationBlast: t = ((float)currentGen - (float)activeTrainingModifierList[i].startGen) / (float)activeTrainingModifierList[i].duration; crossoverManager = trainer.PlayerList[0].masterCupid; if (t > 1f) { if (activeTrainingModifierList[i].liveForever) { t = 1f; } else { // Duration has expired, and the live forever flag if false, so remove this modifier crossoverManager.mutationBlastModifier = 1f; activeTrainingModifierList.RemoveAt(i); break; } } crossoverManager.mutationBlastModifier = Mathf.Lerp(1f, activeTrainingModifierList[i].minMultiplier, t); break; case TrainingModifier.TrainingModifierType.BodyMutationBlast: t = ((float)currentGen - (float)activeTrainingModifierList[i].startGen) / (float)activeTrainingModifierList[i].duration; crossoverManager = trainer.PlayerList[0].masterCupid; if (t > 1f) { if (activeTrainingModifierList[i].liveForever) { t = 1f; } else { // Duration has expired, and the live forever flag if false, so remove this modifier crossoverManager.bodyMutationBlastModifier = 1f; activeTrainingModifierList.RemoveAt(i); break; } } crossoverManager.bodyMutationBlastModifier = Mathf.Lerp(1f, activeTrainingModifierList[i].minMultiplier, t); break; case TrainingModifier.TrainingModifierType.PruneBrain: t = ((float)currentGen - (float)activeTrainingModifierList[i].startGen) / (float)activeTrainingModifierList[i].duration; crossoverManager = trainer.PlayerList[0].masterCupid; if (t > 1f) { t = 1f; } t = 1f - t; crossoverManager.largeBrainPenalty = activeTrainingModifierList[i].largeBrainPenalty * t; crossoverManager.mutationRemoveLinkChance = activeTrainingModifierList[i].removeLinkChance * t; crossoverManager.mutationRemoveNodeChance = activeTrainingModifierList[i].removeNodeChance * t; break; case TrainingModifier.TrainingModifierType.TargetCone: break; case TrainingModifier.TrainingModifierType.TargetForward: break; case TrainingModifier.TrainingModifierType.TargetOmni: break; case TrainingModifier.TrainingModifierType.VariableTrialTimes: t = ((float)currentGen - (float)activeTrainingModifierList[i].startGen) / (float)activeTrainingModifierList[i].duration; Trial trial = trainer.PlayerList[0].masterTrialsList[0]; if (t > 1f) { if (activeTrainingModifierList[i].liveForever) { t = 1f; } else { // Remove this modifier activeTrainingModifierList.RemoveAt(i); } } int minSteps = (int)Mathf.Lerp(activeTrainingModifierList[i].beginMinTime, activeTrainingModifierList[i].endMinTime, t); int maxSteps = (int)Mathf.Lerp(activeTrainingModifierList[i].beginMaxTime, activeTrainingModifierList[i].endMaxTime, t); trial.maxEvaluationTimeSteps = maxSteps; // (int)UnityEngine.Random.Range(minSteps, maxSteps); trial.minEvaluationTimeSteps = minSteps; break; case TrainingModifier.TrainingModifierType.WideSearch: t = ((float)currentGen - (float)activeTrainingModifierList[i].startGen) / (float)activeTrainingModifierList[i].duration; crossoverManager = trainer.PlayerList[0].masterCupid; if (t > 1f) { t = 1f; } t = 1f - t; //crossoverManager.largeBrainPenalty = activeTrainingModifierList[i].largeBrainPenalty * t; //crossoverManager.mutationRemoveLinkChance = activeTrainingModifierList[i].removeLinkChance * t; //crossoverManager.mutationRemoveNodeChance = activeTrainingModifierList[i].removeNodeChance * t; break; default: Debug.Log("Modifier type not found!!! SWITCH DEFAULT CASE"); break; } } } }
public SpeciesBreedingPool(GenomeNEAT genome, int id) { agentList = new List<Agent>(); templateGenome = genome; speciesID = id; nextAgentIndex = 0; }
public static float MeasureGeneticDistance(GenomeNEAT genomeA, GenomeNEAT genomeB, float neuronCoefficient, float linkCoefficient, float weightCoefficient, float normNeuron, float normLink, float normWeight) { int indexA = 0; int indexB = 0; float weightDeltaTotal = 0f; float maxGenes = Mathf.Max((float)genomeA.linkNEATList.Count, (float)genomeB.linkNEATList.Count); float matchingGenes = 0f; //float disjointGenes = 0f; //float excessGenes = 0f; float linkGenes = 0f; float neuronGenes = 0f; int matchingNeurons = 0; //float smallestWeightValue = 0f; float largestWeightDelta = 0f; // matching Links // matching nodes/neurons // matching activation functions? // difference in weights // difference in add-on settings? // -- NEED TO GO BY BODY GENOME????? // LINKS::: for(int i = 0; i < genomeA.linkNEATList.Count + genomeB.linkNEATList.Count; i++) { if(indexA < genomeA.linkNEATList.Count) { if (indexB < genomeB.linkNEATList.Count) { // both good if (genomeA.linkNEATList[indexA].innov < genomeB.linkNEATList[indexB].innov) { // disjoint A linkGenes++; indexA++; } else if (genomeA.linkNEATList[indexA].innov > genomeB.linkNEATList[indexB].innov) { // disjoint B linkGenes++; indexB++; } else if (genomeA.linkNEATList[indexA].innov == genomeB.linkNEATList[indexB].innov) { // match! float weightDelta = Mathf.Abs(genomeA.linkNEATList[indexA].weight - genomeB.linkNEATList[indexB].weight); weightDeltaTotal += weightDelta; matchingGenes++; //Debug.Log("!@$#!$#!@$#!@$# MeasureGeneticDistance! innov MATCHING GENE: weightA: " + genomeA.linkNEATList[indexA].weight.ToString() + ", weightB: " + genomeB.linkNEATList[indexB].weight.ToString()); indexA++; indexB++; largestWeightDelta = Mathf.Max(largestWeightDelta, weightDelta); } } else { // A is good, B is finished linkGenes++; indexA++; } } else { // A done if (indexB < genomeB.linkNEATList.Count) { // A is finished, B is good linkGenes++; indexB++; } else { // both done break; } } } for (int i = 0; i < genomeA.nodeNEATList.Count; i++) { Int3 nodeID = new Int3(genomeA.nodeNEATList[i].sourceAddonInno, genomeA.nodeNEATList[i].sourceAddonRecursionNum, genomeA.nodeNEATList[i].sourceAddonChannelNum); if(genomeB.GetNodeIndexFromInt3(nodeID) != -1) { // if genomeB has the same neuron: matchingNeurons++; } } int totalNeurons = (genomeA.nodeNEATList.Count + genomeB.nodeNEATList.Count); int totalLinks = (genomeA.linkNEATList.Count + genomeB.linkNEATList.Count); if(totalNeurons > 0) { neuronGenes = Mathf.Lerp((float)((totalNeurons) - matchingNeurons * 2), (float)((totalNeurons) - matchingNeurons * 2) / (float)(totalNeurons), normNeuron); // get proportion of neurons that match between the two genomes, should be 0-1 } if(totalLinks > 0) { linkGenes = Mathf.Lerp(((float)(totalLinks) - matchingGenes * 2f), ((float)(totalLinks) - matchingGenes * 2f) / (float)(totalLinks), normLink); } //float weightSpan = largestWeightValue - smallestWeightValue; float distance = 0f; if(true) { // maxGenes > 0f //float excessComponent = excessCoefficient * Mathf.Lerp(excessGenes, excessGenes / maxGenes, normExcess); //float disjointComponent = disjointCoefficient * Mathf.Lerp(disjointGenes, disjointGenes / maxGenes, normDisjoint); //float weightComponent = weightCoefficient * Mathf.Lerp(weightDeltaTotal, weightDeltaTotal / Mathf.Max((float)matchingGenes, 1f), normWeight); float totalPie = neuronCoefficient + linkCoefficient + weightCoefficient; float weightComponent = 0f; if(largestWeightDelta > 0f) weightComponent = Mathf.Lerp(weightDeltaTotal / largestWeightDelta, weightDeltaTotal / Mathf.Max((float)matchingGenes, 1f) / largestWeightDelta, normWeight); // OLD //distance = excessComponent + disjointComponent + weightComponent; distance = neuronGenes * (neuronCoefficient / totalPie) + linkGenes * (linkCoefficient / totalPie) + weightComponent * (weightCoefficient / totalPie); //Debug.Log("MeasureGeneticDistance! neuronGenes: " + (neuronGenes).ToString() + " (" + genomeA.nodeNEATList.Count.ToString() + "," + genomeB.nodeNEATList.Count.ToString() + // "), linkGenes: " + (linkGenes).ToString() + " (" + genomeA.linkNEATList.Count.ToString() + "," + genomeB.linkNEATList.Count.ToString() + // "), weight: " + weightComponent.ToString() + ", largestWeightDelta: " + largestWeightDelta.ToString() + ", weightDeltaTotal: " + weightDeltaTotal.ToString() + "weightMatches: " + matchingGenes.ToString() + // ", distance: " + distance.ToString()); //Debug.Log("MeasureGeneticDistance! disjoint: " + (disjointGenes).ToString() + ", excess: " + (excessGenes).ToString() + ", weight: " + (weightDeltaTotal / Mathf.Max((float)matchingGenes, 1f)).ToString() + ", distance: " + distance.ToString()); } // else stays 0f; return distance; }
public Species(Species baseSpecies) { id = baseSpecies.id; currentMemberCount = 0; templateGenome = baseSpecies.templateGenome; }
public override object Read(ES2Reader reader) { GenomeNEAT data = new GenomeNEAT(); Read(reader, data); return data; }