public override object Clone() { SizeFairCrossoverPipeline c = (SizeFairCrossoverPipeline)(base.Clone()); // deep-cloned stuff c.NodeSelect1 = (IGPNodeSelector)NodeSelect1.Clone(); c.NodeSelect2 = (IGPNodeSelector)NodeSelect2.Clone(); c.Parents = Parents.ToList(); return(c); }
public void Setup(IEvolutionState state, Parameter paramBase) { base.Setup(state, paramBase); IParameter def = DefaultBase; IParameter p = paramBase.Push(P_NODESELECTOR).Push("0"); IParameter d = def.Push(P_NODESELECTOR).Push("0"); NodeSelect1 = (IGPNodeSelector)state.Parameters.GetInstanceForParameter(p, d, typeof(IGPNodeSelector)); NodeSelect1.Setup(state, p); p = paramBase.Push(P_NODESELECTOR).Push("1"); d = def.Push(P_NODESELECTOR).Push("1"); if (state.Parameters.ParameterExists(p, d) && state.Parameters.GetString(p, d).Equals(V_SAME)) { // can't just copy it this time; the selectors // use internal caches. So we have to clone it no matter what NodeSelect2 = (IGPNodeSelector)NodeSelect1.Clone(); } else { NodeSelect2 = (IGPNodeSelector)state.Parameters.GetInstanceForParameter(p, d, typeof(IGPNodeSelector)); NodeSelect2.Setup(state, p); } NumTries = state.Parameters.GetInt(paramBase.Push(P_NUM_TRIES), def.Push(P_NUM_TRIES), 1); if (NumTries == 0) { state.Output.Fatal("GPCrossover Pipeline has an invalid number of tries (it must be >= 1).", paramBase.Push(P_NUM_TRIES), def.Push(P_NUM_TRIES)); } MaxDepth = state.Parameters.GetInt(paramBase.Push(P_MAXDEPTH), def.Push(P_MAXDEPTH), 1); if (MaxDepth == 0) { state.Output.Fatal("GPCrossover Pipeline has an invalid maximum depth (it must be >= 1).", paramBase.Push(P_MAXDEPTH), def.Push(P_MAXDEPTH)); } Tree1 = TREE_UNFIXED; if (state.Parameters.ParameterExists(paramBase.Push(P_TREE).Push("" + 0), def.Push(P_TREE).Push("" + 0))) { Tree1 = state.Parameters.GetInt(paramBase.Push(P_TREE).Push("" + 0), def.Push(P_TREE).Push("" + 0), 0); if (Tree1 == -1) { state.Output.Fatal("Tree fixed value, if defined, must be >= 0"); } } Tree2 = TREE_UNFIXED; if (state.Parameters.ParameterExists(paramBase.Push(P_TREE).Push("" + 1), def.Push(P_TREE).Push("" + 1))) { Tree2 = state.Parameters.GetInt(paramBase.Push(P_TREE).Push("" + 1), def.Push(P_TREE).Push("" + 1), 0); if (Tree2 == -1) { state.Output.Fatal("Tree fixed value, if defined, must be >= 0"); } } TossSecondParent = state.Parameters.GetBoolean(paramBase.Push(P_TOSS), def.Push(P_TOSS), false); if (state.Parameters.ParameterExists(paramBase.Push(P_HOMOLOGOUS), null)) { //get the parameter Homologous = state.Parameters.GetBoolean(paramBase.Push(P_HOMOLOGOUS), null, false); } }
public override int Produce( int min, int max, int subpop, IList <Individual> inds, IEvolutionState state, int thread, IDictionary <string, object> misc) { int start = inds.Count; // how many individuals should we make? var n = TypicalIndsProduced; if (n < min) { n = min; } if (n > max) { n = max; } // should we bother? if (!state.Random[thread].NextBoolean(Likelihood)) { // just load from source 0 and clone 'em Sources[0].Produce(n, n, subpop, inds, state, thread, misc); return(n); } IntBag[] parentparents = null; IntBag[] preserveParents = null; if (misc != null && misc.ContainsKey(KEY_PARENTS)) { preserveParents = (IntBag[])misc[KEY_PARENTS]; parentparents = new IntBag[2]; misc[KEY_PARENTS] = parentparents; } var initializer = (GPInitializer)state.Initializer; for (var q = start; q < n + start;) // keep on going until we're filled up { Parents.Clear(); // grab two individuals from our sources if (Sources[0] == Sources[1]) { // grab from the same source Sources[0].Produce(2, 2, subpop, Parents, state, thread, misc); } // grab from different sources else { Sources[0].Produce(1, 1, subpop, Parents, state, thread, misc); Sources[1].Produce(1, 1, subpop, Parents, state, thread, misc); } // at this point, Parents[] contains our two selected individuals // are our tree values valid? if (Tree1 != TREE_UNFIXED && (Tree1 < 0 || Tree1 >= ((GPIndividual)Parents[0]).Trees.Length)) { // uh oh state.Output.Fatal("GP Crossover Pipeline attempted to fix tree.0 to a value which was out of bounds" + " of the array of the individual's trees. Check the pipeline's fixed tree values" + " -- they may be negative or greater than the number of trees in an individual"); } if (Tree2 != TREE_UNFIXED && (Tree2 < 0 || Tree2 >= ((GPIndividual)Parents[1]).Trees.Length)) { // uh oh state.Output.Fatal("GP Crossover Pipeline attempted to fix tree.1 to a value which was out of bounds" + " of the array of the individual's trees. Check the pipeline's fixed tree values" + " -- they may be negative or greater than the number of trees in an individual"); } var t1 = 0; var t2 = 0; if (Tree1 == TREE_UNFIXED || Tree2 == TREE_UNFIXED) { do // pick random trees -- their GPTreeConstraints must be the same { if (Tree1 == TREE_UNFIXED) { if (((GPIndividual)Parents[0]).Trees.Length > 1) { t1 = state.Random[thread].NextInt(((GPIndividual)Parents[0]).Trees.Length); } else { t1 = 0; } } else { t1 = Tree1; } if (Tree2 == TREE_UNFIXED) { if (((GPIndividual)Parents[1]).Trees.Length > 1) { t2 = state.Random[thread].NextInt(((GPIndividual)Parents[1]).Trees.Length); } else { t2 = 0; } } else { t2 = Tree2; } }while (((GPIndividual)Parents[0]).Trees[t1].Constraints(initializer) != ((GPIndividual)Parents[1]).Trees[t2].Constraints(initializer)); } else { t1 = Tree1; t2 = Tree2; // make sure the constraints are okay if (((GPIndividual)Parents[0]).Trees[t1].Constraints(initializer) != ((GPIndividual)Parents[1]).Trees[t2].Constraints(initializer)) { // uh oh state.Output.Fatal("GP Crossover Pipeline's two tree choices are both specified by the user" + " -- but their GPTreeConstraints are not the same"); } } // validity results... var res1 = false; var res2 = false; // prepare the nodeselectors NodeSelect1.Reset(); NodeSelect2.Reset(); // pick some nodes GPNode p1 = null; GPNode p2 = null; for (var x = 0; x < NumTries; x++) { // pick a node in individual 1 p1 = NodeSelect1.PickNode(state, subpop, thread, (GPIndividual)Parents[0], ((GPIndividual)Parents[0]).Trees[t1]); // pick a node in individual 2 p2 = NodeSelect2.PickNode(state, subpop, thread, (GPIndividual)Parents[1], ((GPIndividual)Parents[1]).Trees[t2]); // check for depth and swap-compatibility limits res1 = VerifyPoints(initializer, p2, p1); // p2 can fill p1's spot -- order is important! if (n - (q - start) < 2 || TossSecondParent) { res2 = true; } else { res2 = VerifyPoints(initializer, p1, p2); // p1 can fill p2's spot -- order is important! } // did we get something that had both nodes verified? // we reject if EITHER of them is invalid. This is what lil-gp does. // Koza only has NumTries set to 1, so it's compatible as well. if (res1 && res2) { break; } } // at this point, res1 AND res2 are valid, OR either res1 // OR res2 is valid and we ran out of tries, OR neither is // valid and we ran out of tries. So now we will transfer // to a tree which has res1 or res2 valid, otherwise it'll // just get replicated. This is compatible with both Koza // and lil-gp. // at this point I could check to see if my sources were breeding // pipelines -- but I'm too lazy to write that code (it's a little // complicated) to just swap one individual over or both over, // -- it might still entail some copying. Perhaps in the future. // It would make things faster perhaps, not requiring all that // cloning. // Create some new individuals based on the old ones -- since // GPTree doesn't deep-clone, this should be just fine. Perhaps we // should change this to proto off of the main species prototype, but // we have to then copy so much stuff over; it's not worth it. var j1 = ((GPIndividual)Parents[0]).LightClone(); GPIndividual j2 = null; if (n - (q - start) >= 2 && !TossSecondParent) { j2 = ((GPIndividual)Parents[1]).LightClone(); } // Fill in various tree information that didn't get filled in there j1.Trees = new GPTree[((GPIndividual)Parents[0]).Trees.Length]; if (n - (q - start) >= 2 && !TossSecondParent) { j2.Trees = new GPTree[((GPIndividual)Parents[1]).Trees.Length]; } // at this point, p1 or p2, or both, may be null. // If not, swap one in. Else just copy the parent. for (var x = 0; x < j1.Trees.Length; x++) { if (x == t1 && res1) // we've got a tree with a kicking cross position! { j1.Trees[x] = ((GPIndividual)Parents[0]).Trees[x].LightClone(); j1.Trees[x].Owner = j1; j1.Trees[x].Child = ((GPIndividual)Parents[0]).Trees[x].Child.CloneReplacing(p2, p1); j1.Trees[x].Child.Parent = j1.Trees[x]; j1.Trees[x].Child.ArgPosition = 0; j1.Evaluated = false; } // it's changed else { j1.Trees[x] = ((GPIndividual)Parents[0]).Trees[x].LightClone(); j1.Trees[x].Owner = j1; j1.Trees[x].Child = (GPNode)((GPIndividual)Parents[0]).Trees[x].Child.Clone(); j1.Trees[x].Child.Parent = j1.Trees[x]; j1.Trees[x].Child.ArgPosition = 0; } } if (n - (q - start) >= 2 && !TossSecondParent) { for (var x = 0; x < j2.Trees.Length; x++) { if (x == t2 && res2) // we've got a tree with a kicking cross position! { j2.Trees[x] = ((GPIndividual)Parents[1]).Trees[x].LightClone(); j2.Trees[x].Owner = j2; j2.Trees[x].Child = ((GPIndividual)Parents[1]).Trees[x].Child.CloneReplacing(p1, p2); j2.Trees[x].Child.Parent = j2.Trees[x]; j2.Trees[x].Child.ArgPosition = 0; j2.Evaluated = false; } // it's changed else { j2.Trees[x] = ((GPIndividual)Parents[1]).Trees[x].LightClone(); j2.Trees[x].Owner = j2; j2.Trees[x].Child = (GPNode)((GPIndividual)Parents[1]).Trees[x].Child.Clone(); j2.Trees[x].Child.Parent = j2.Trees[x]; j2.Trees[x].Child.ArgPosition = 0; } } } // add the individuals to the population inds.Add(j1); q++; if (q < n + start && !TossSecondParent) { inds.Add(j2); if (preserveParents != null) { parentparents[0].AddAll(parentparents[1]); preserveParents[q] = parentparents[0]; } q++; } } return(n); }