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;

            // grab n individuals from our source and stick 'em right into inds.
            // we'll modify them from there
            var n = Sources[0].Produce(min, max, subpop, inds, state, thread, misc);

            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;
            }

            // should we bother?
            if (!state.Random[thread].NextBoolean(Likelihood))
            {
                return(n);
            }

            var initializer = (GPInitializer)state.Initializer;

            for (var q = start; q < n + start; q++)
            {
                var i = (GPIndividual)inds[q];

                if (Tree1 != TREE_UNFIXED && (Tree1 < 0 || Tree1 >= i.Trees.Length))
                {
                    // uh oh
                    state.Output.Fatal("Internal 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 >= i.Trees.Length))
                {
                    // uh oh
                    state.Output.Fatal("Internal 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");
                }

                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 (i.Trees.Length > 1)
                            {
                                t1 = state.Random[thread].NextInt(i.Trees.Length);
                            }
                            else
                            {
                                t1 = 0;
                            }
                        }
                        else
                        {
                            t1 = Tree1;
                        }

                        if (Tree2 == TREE_UNFIXED)
                        {
                            if (i.Trees.Length > 1)
                            {
                                t2 = state.Random[thread].NextInt(i.Trees.Length);
                            }
                            else
                            {
                                t2 = 0;
                            }
                        }
                        else
                        {
                            t2 = Tree2;
                        }
                    }while (i.Trees[t1].Constraints(initializer) != i.Trees[t2].Constraints(initializer));
                }
                else
                {
                    t1 = Tree1;
                    t2 = Tree2;
                    // make sure the constraints are okay
                    if (i.Trees[t1].Constraints(initializer) != i.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");
                    }
                }


                // prepare the nodeselectors
                NodeSelect0.Reset();
                NodeSelect1.Reset();


                // pick some nodes

                GPNode p1  = null;
                GPNode p2  = null;
                var    res = false;

                for (var x = 0; x < NumTries; x++)
                {
                    // pick a node in individual 1
                    p1 = NodeSelect0.PickNode(state, subpop, thread, i, i.Trees[t1]);

                    // pick a node in individual 2
                    p2 = NodeSelect1.PickNode(state, subpop, thread, i, i.Trees[t2]);

                    // make sure they're not the same node
                    res = (p1 != p2 &&
                           (t1 != t2 || NoContainment(p1, p2)) &&
                           VerifyPoints(initializer, p1, p2) &&
                           VerifyPoints(initializer, p2, p1)); // 2 goes into 1
                    if (res)
                    {
                        break; // got one
                    }
                }

                // if res, then it's time to cross over!
                if (res)
                {
                    var oldparent      = p1.Parent;
                    var oldArgPosition = p1.ArgPosition;

                    p1.Parent      = p2.Parent;
                    p1.ArgPosition = p2.ArgPosition;
                    p2.Parent      = oldparent;
                    p2.ArgPosition = oldArgPosition;

                    if (p1.Parent is GPNode)
                    {
                        ((GPNode)(p1.Parent)).Children[p1.ArgPosition] = p1;
                    }
                    else
                    {
                        ((GPTree)(p1.Parent)).Child = p1;
                    }

                    if (p2.Parent is GPNode)
                    {
                        ((GPNode)(p2.Parent)).Children[p2.ArgPosition] = p2;
                    }
                    else
                    {
                        ((GPTree)(p2.Parent)).Child = p2;
                    }

                    i.Evaluated = false; // we've modified it
                }

                // add the individuals to the population
                //inds[q] = i;
                inds.Add(i);
                if (preserveParents != null)
                {
                    parentparents[0].AddAll(parentparents[1]);
                    preserveParents[q] = new IntBag(parentparents[0]);
                }
            }
            return(n);
        }
Esempio n. 2
0
        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);
        }