Exemple #1
0
        public override GPNode NewRootedTree(IEvolutionState state, GPType type, int thread, IGPNodeParent parent,
                                             GPFunctionSet funcs, int argPosition, int requestedSize)
        {
            var n = GrowNode(state, 0, state.Random[thread].NextInt(MaxDepth - MinDepth + 1) + MinDepth, type, thread, parent, argPosition, funcs);

            return(n);
        }
Exemple #2
0
        public override GPNode NewRootedTree(IEvolutionState state,
                                             GPType type,
                                             int thread,
                                             IGPNodeParent parent,
                                             GPFunctionSet set,
                                             int argPosition,
                                             int requestedSize)
        {
            int t = type.Type;

            GPNode[] terminals    = set.Terminals[t];
            GPNode[] nonterminals = set.Nonterminals[t];

            if (requestedSize == NOSIZEGIVEN)
            {
                requestedSize = PickSize(state, thread);
            }

            GPNode n;

            if (requestedSize == 1)
            {
                // pick a random terminal
                n = terminals[state.Random[thread].NextInt(terminals.Length)].LightClone();
            }
            else
            {
                n = nonterminals[state.Random[thread].NextInt(nonterminals.Length)]
                    .LightClone(); // it's always going to be the Dummy

                // do decomposition
                byte           pos  = 0;                   // THIS WILL HAVE TO BE MODIFIED TO AN INT LATER ON AND THIS WILL AFFECT ARGPOSITIONS!!!
                IList <GPNode> list = new List <GPNode>(); // dunno if this is too expensive

                while (requestedSize >= 1)
                {
                    int amount = state.Random[thread].NextInt(requestedSize) + 1;
                    requestedSize -= amount;
                    GPNode f = NewRootedTree(state, type, thread, parent, set, pos, amount);
                    list.Add(f);
                }

                // shuffle and reassign argument position
                n.Children = list.ToArray();
                n.Children = Shuffle(n.Children, state, thread);

                for (int i = 0; i < n.Children.Length; i++)
                {
                    n.Children[i].ArgPosition = (byte)i;
                }
            }

            n.ResetNode(state, thread); // give ERCs a chance to randomize
            n.ArgPosition = (byte)argPosition;
            n.Parent      = parent;

            return(n);
        }
Exemple #3
0
        public override GPNode NewRootedTree(IEvolutionState state, GPType type, int thread, IGPNodeParent parent,
                                             GPFunctionSet funcs, int argPosition, int requestedSize)
        {
            if (state.Random[thread].NextDouble() < PickGrowProbability)
            {
                return(GrowNode(state, 0, state.Random[thread].NextInt(MaxDepth - MinDepth + 1) + MinDepth, type, thread, parent, argPosition, funcs));
            }

            return(FullNode(state, 0, state.Random[thread].NextInt(MaxDepth - MinDepth + 1) + MinDepth, type, thread, parent, argPosition, funcs));
        }
Exemple #4
0
 public override GPNode NewRootedTree(IEvolutionState state, GPType type, int thread, IGPNodeParent parent,
                                      GPFunctionSet funcs, int argPosition, int requestedSize)
 {
     if (requestedSize == NOSIZEGIVEN)
     {
         // pick from the distribution
         return(randomBranch(state, type, PickSize(state, thread), thread, parent, argPosition, funcs));
     }
     if (requestedSize < 1)
     {
         state.Output.Fatal("ec.gp.build.RandomBranch requested to build a tree, but a requested size was given that is < 1.");
     }
     return(randomBranch(state, type, requestedSize, thread, parent, argPosition, funcs));
 }
Exemple #5
0
        public override GPNode NewRootedTree(IEvolutionState state, GPType type, int thread, IGPNodeParent parent, GPFunctionSet funcs, int ArgPosition, int requestedSize)
        {
            if (!(funcs is IPTCFunctionSet))
            {
                state.Output.Fatal("Set " + funcs.Name + " is not of the form ec.gp.build.IPTCFunctionSet, and so cannot be used with PTC Nodebuilders.");
            }

            // build the tree
            if (requestedSize == NOSIZEGIVEN) // use the default
            {
                return(Ptc1(state, 0, type, thread, parent, ArgPosition, funcs, (IPTCFunctionSet)funcs, ((IPTCFunctionSet)funcs).NonterminalSelectionProbabilities(ExpectedSize)));
            }
            if (requestedSize < 1)
            {
                state.Output.Fatal("ec.gp.build.PTC1 was requested to build a tree, but a requested size was given that is < 1.");
            }
            return(Ptc1(state, 0, type, thread, parent, ArgPosition, funcs, (IPTCFunctionSet)funcs,
                        ((IPTCFunctionSet)funcs).NonterminalSelectionProbabilities(requestedSize)));
        }
Exemple #6
0
        public override GPNode NewRootedTree(IEvolutionState state, GPType type, int thread, IGPNodeParent parent,
                                             GPFunctionSet funcs, int argPosition, int requestedSize)
        {
            var valid = false;

            var treeSize = PickSize(state, thread);

            if (!AritySetupDone)
            {
                SetupArities(state, funcs);
            }

            var temp = new int[Arities.Length];

            Permutations = new List <int[]>();
            Permute(0, temp, treeSize - 1);
            if (Permutations.Count == 0)
            {
                state.Output.Fatal("Not able to build combination of nodes.");
            }
            var scheme = Select(Permutations, treeSize);
            var word   = BuildDyckWord(treeSize, Arities, scheme, state, thread);
            var cycle  = 0;

            while (!valid)
            {
                valid = CheckDyckWord(word);
                if (!valid)
                {
                    word = String.Concat(word.Substring(word.Length - 1, word.Length),
                                         word.Substring(0, word.Length - 1));
                    cycle++;
                    if (cycle >= (treeSize * 2) - 1)
                    {
                        state.Output.Fatal("Not able to find valid permutation for generated Dyck word: " + word);
                    }
                }
            }
            return(BuildTree(state, thread, parent, argPosition, funcs, word));
        }
Exemple #7
0
        /// <summary>
        /// Returns a node which is swap-compatible with returntype,
        /// and whose arguments are swap-compatible with the current children of original.
        /// You need to clone this node.
        /// </summary>
        private static GPNode PickCompatibleNode(GPNode original, GPFunctionSet funcs, IEvolutionState state, GPType returntype, int thread)
        {
            // an expensive procedure: we will linearly search for a valid node
            var numValidNodes = 0;

            var  type        = returntype.Type;
            var  initializer = ((GPInitializer)state.Initializer);
            var  len         = original.Constraints(initializer).ChildTypes.Length;
            bool failed;

            if (initializer.NumAtomicTypes + initializer.NumSetTypes == 1)
            {
                // easy
                numValidNodes = funcs.NodesByArity[type][len].Length;
            }
            else
            {
                for (var x = 0; x < funcs.NodesByArity[type][len].Length; x++)
                // ugh, the hard way -- nodes swap-compatible with type, and of arity len
                {
                    failed = funcs.NodesByArity[type][len][x].Constraints(initializer).ChildTypes
                             .Where((t, y) => !t.CompatibleWith(initializer, original.Children[y].Constraints(initializer).ReturnType)).Any();
                    if (!failed)
                    {
                        numValidNodes++;
                    }
                }
            }

            // we must have at least success -- the node itself.  Otherwise we're
            // in deep doo-doo.

            // now pick a random node number
            var nodenum = state.Random[thread].NextInt(numValidNodes);

            // find and return that node
            var prosnode = 0;

            if (numValidNodes == funcs.NodesByArity[type][len].Length)
            {
                // easy
                return(funcs.NodesByArity[type][len][nodenum]);
            }

            for (var x = 0; x < funcs.NodesByArity[type][len].Length; x++)
            // ugh, the hard way -- nodes swap-compatible with type, and of arity len
            {
                failed = funcs.NodesByArity[type][len][x].Constraints(initializer).ChildTypes
                         .Where((t, y) => !t.CompatibleWith(initializer, original.Children[y].Constraints(initializer).ReturnType)).Any();
                if (failed)
                {
                    continue;
                }
                if (prosnode == nodenum)
                {
                    // got it!
                    return(funcs.NodesByArity[type][len][x]);
                }
                prosnode++;
            }
            // should never be able to get here
            throw new ApplicationException("Invalid execution path!"); // whoops!
        }
Exemple #8
0
        /// <summary>
        /// A private function which recursively returns a GROW tree to NewRootedTree(...)
        /// </summary>
        private GPNode Ptc1(IEvolutionState state, int current, GPType type, int thread, IGPNodeParent parent,
                            int argPosition, GPFunctionSet funcs, IPTCFunctionSet pfuncs, double[] nonterminalSelectProbs)
        {
            // ptc1 can mess up if there are no available terminals for a given type.  If this occurs,
            // and we find ourselves unable to pick a terminal when we want to do so, we will issue a warning,
            // and pick a nonterminal, violating the PTC1 size and depth contracts.  This can lead to pathological situations
            // where the system will continue to go on and on unable to stop because it can't pick a terminal,
            // resulting in running out of memory or some such.  But there are cases where we'd want to let
            // this work itself out.
            var triedTerminals = false;

            var t            = type.Type;
            var terminals    = funcs.Terminals[t];
            var nonterminals = funcs.Nonterminals[t];
            var nodes        = funcs.Nodes[t];

            if (nodes.Length == 0)
            {
                ErrorAboutNoNodeWithType(type, state); // total failure
            }
            // Now pick if we're at max depth
            // OR if we're below p_y
            // OR if there are NO nonterminals!
            // [first set triedTerminals]
            // AND if there are available terminals
            if (((current + 1 >= MaxDepth) ||
                 !(state.Random[thread].NextBoolean(nonterminalSelectProbs[t])) ||
                 WarnAboutNonterminal(nonterminals.Length == 0, type, false, state)) &&
                (triedTerminals = true) && terminals.Length != 0)
            {
                var n = terminals[RandomChoice.PickFromDistribution(pfuncs.TerminalProbabilities(t),
                                                                    state.Random[thread].NextDouble())].LightClone();

                n.ResetNode(state, thread); // give ERCs a chance to randomize
                n.ArgPosition = (sbyte)argPosition;
                n.Parent      = parent;
                return(n);
            }
            // above p_y, pick a nonterminal by q_ny probabilities
            else
            {
                if (triedTerminals)
                {
                    WarnAboutNoTerminalWithType(type, false, state); // we tried terminals and we're here because there were none!
                }
                var n = nonterminals[RandomChoice.PickFromDistribution(pfuncs.NonterminalProbabilities(t),
                                                                       state.Random[thread].NextDouble())].LightClone();

                n.ResetNode(state, thread); // give ERCs a chance to randomize
                n.ArgPosition = (sbyte)argPosition;
                n.Parent      = parent;

                // Populate the node...
                var childtypes = n.Constraints((GPInitializer)state.Initializer).ChildTypes;
                for (var x = 0; x < childtypes.Length; x++)
                {
                    n.Children[x] = Ptc1(state, current + 1, childtypes[x], thread, n, x, funcs, pfuncs, nonterminalSelectProbs);
                }

                return(n);
            }
        }
 public override bool CompatibleWith(GPInitializer initializer, GPType t)
 {
     return(t.Type == Type ? true : false);
 }
Exemple #10
0
        public override GPNode NewRootedTree(IEvolutionState state, GPType type, int thread,
                                             IGPNodeParent parent, GPFunctionSet funcs, int argPosition, int requestedSize)
        {
            // ptc2 can mess up if there are no available terminals for a given type.  If this occurs,
            // and we find ourselves unable to pick a terminal when we want to do so, we will issue a warning,
            // and pick a nonterminal, violating the ptc2 size and depth contracts.  This can lead to pathological situations
            // where the system will continue to go on and on unable to stop because it can't pick a terminal,
            // resulting in running out of memory or some such.  But there are cases where we'd want to let
            // this work itself out.
            var triedTerminals = false;

            if (!(funcs is IPTCFunctionSet))
            {
                state.Output.Fatal("Set " + funcs.Name
                                   + " is not of the class ec.gp.build.IPTCFunctionSet, and so cannot be used with PTC Nodebuilders.");
            }

            var pfuncs = (IPTCFunctionSet)funcs;

            // pick a size from the distribution
            if (requestedSize == NOSIZEGIVEN)
            {
                requestedSize = PickSize(state, thread);
            }

            GPNode root;

            var t            = type.Type;
            var terminals    = funcs.Terminals[t];
            var nonterminals = funcs.Nonterminals[t];
            var nodes        = funcs.Nodes[t];

            if (nodes.Length == 0)
            {
                ErrorAboutNoNodeWithType(type, state); // total failure
            }
            // return a terminal
            // Now pick a terminal if our size is 1
            // OR if there are NO nonterminals!
            // [first set triedTerminals]
            // AND if there are available terminals
            if ((requestedSize == 1 || WarnAboutNonterminal(nonterminals.Length == 0, type, false, state)) &&
                (triedTerminals = true) && terminals.Length != 0)
            {
                root = terminals[RandomChoice.PickFromDistribution(pfuncs.TerminalProbabilities(t),
                                                                   state.Random[thread].NextDouble())].LightClone();

                root.ResetNode(state, thread); // give ERCs a chance to randomize
                root.ArgPosition = (sbyte)argPosition;
                root.Parent      = parent;
            }
            // return a nonterminal-rooted tree
            else
            {
                if (triedTerminals)
                {
                    WarnAboutNoTerminalWithType(type, false, state); // we tried terminals and we're here because there were none!
                }
                // pick a nonterminal
                root = nonterminals[RandomChoice.PickFromDistribution(pfuncs.NonterminalProbabilities(t),
                                                                      state.Random[thread].NextDouble())].LightClone();

                root.ResetNode(state, thread); // give ERCs a chance to randomize
                root.ArgPosition = (sbyte)argPosition;
                root.Parent      = parent;

                // set the depth, size, and enqueuing, and reset the random dequeue

                s_size = 0; // pretty critical!
                var s           = 1;
                var initializer = ((GPInitializer)state.Initializer);
                var childtypes  = root.Constraints(initializer).ChildTypes;

                for (var x = 0; x < childtypes.Length; x++)
                {
                    Enqueue(root, x, 1); /* depth 1 */
                }
                while (s_size > 0)
                {
                    triedTerminals = false;
                    RandomDequeue(state, thread);
                    type = DequeueNode.Constraints(initializer).ChildTypes[DequeueArgpos];

                    var y = type.Type;
                    terminals    = funcs.Terminals[y];
                    nonterminals = funcs.Nonterminals[y];
                    nodes        = funcs.Nodes[y];

                    if (nodes.Length == 0)
                    {
                        ErrorAboutNoNodeWithType(type, state); // total failure
                    }
                    // pick a terminal
                    // if we need no nonterminal nodes
                    // OR if we're at max depth and must pick a terminal
                    // OR if there are NO nonterminals!
                    // [first set triedTerminals]
                    // AND if there are available terminals
                    if ((s_size + s >= requestedSize || DequeueDepth == MaxDepth ||
                         WarnAboutNonterminal(nonterminals.Length == 0, type, false, state)) &&
                        (triedTerminals = true) && terminals.Length != 0)
                    {
                        var n = terminals[RandomChoice.PickFromDistribution(pfuncs.TerminalProbabilities(y),
                                                                            state.Random[thread].NextDouble())].LightClone();

                        DequeueNode.Children[DequeueArgpos] = n;
                        n.ResetNode(state, thread); // give ERCs a chance to randomize
                        n.ArgPosition = (sbyte)DequeueArgpos;
                        n.Parent      = DequeueNode;
                    }
                    // pick a nonterminal and enqueue its children
                    else
                    {
                        if (triedTerminals)
                        {
                            WarnAboutNoTerminalWithType(type, false, state); // we tried terminals and we're here because there were none!
                        }
                        var n = nonterminals[RandomChoice.PickFromDistribution(pfuncs.NonterminalProbabilities(y),
                                                                               state.Random[thread].NextDouble())].LightClone();

                        DequeueNode.Children[DequeueArgpos] = n;
                        n.ResetNode(state, thread); // give ERCs a chance to randomize
                        n.ArgPosition = (sbyte)DequeueArgpos;
                        n.Parent      = DequeueNode;

                        childtypes = n.Constraints(initializer).ChildTypes;
                        for (var x = 0; x < childtypes.Length; x++)
                        {
                            Enqueue(n, x, DequeueDepth + 1);
                        }
                    }
                    s++;
                }
            }

            return(root);
        }
        /// <summary>
        /// Returns a brand-new tree which is swap-compatible with returntype,
        /// created by making nodes "compatible" with the equivalent nodes in the tree rooted at original.
        /// You need to set the parent and argumentposition of the root yourself.
        /// </summary>
        private static GPNode GenerateCompatibleTree(GPNode original, GPFunctionSet funcs, IEvolutionState state, GPType returntype, int thread)
        {
            // pick a new node and clone it
            var node = PickCompatibleNode(original, funcs, state, returntype, thread).LightClone();

            // reset it
            node.ResetNode(state, thread);

            // fill in its children
            var initializer = ((GPInitializer)state.Initializer);

            for (var x = 0; x < node.Children.Length; x++)
            {
                node.Children[x]             = GenerateCompatibleTree(original.Children[x], funcs, state, original.Constraints(initializer).ChildTypes[x], thread);
                node.Children[x].Parent      = node;
                node.Children[x].ArgPosition = (sbyte)x;
            }
            return(node);
        }
Exemple #12
0
        /// <summary>
        /// A private function which recursively returns a GROW tree to NewRootedTree(...)
        /// </summary>
        protected internal virtual GPNode GrowNode(IEvolutionState state, int current, int max, GPType type, int thread,
                                                   IGPNodeParent parent, int argPosition, GPFunctionSet funcs)
        {
            // growNode can mess up if there are no available terminals for a given type.  If this occurs,
            // and we find ourselves unable to pick a terminal when we want to do so, we will issue a warning,
            // and pick a nonterminal, violating the maximum-depth contract.  This can lead to pathological situations
            // where the system will continue to go on and on unable to stop because it can't pick a terminal,
            // resulting in running out of memory or some such.  But there are cases where we'd want to let
            // this work itself out.
            var triedTerminals = false;

            var t = type.Type;

            GPNode[] terminals = funcs.Terminals[t];
            //GPNode[] nonterminals = funcs.Nonterminals[t];
            GPNode[] nodes = funcs.Nodes[t];

            if (nodes.Length == 0)
            {
                ErrorAboutNoNodeWithType(type, state); // total failure
            }
            // pick a terminal when we're at max depth or if there are NO nonterminals
            if (current + 1 >= max
                // this will freak out the static checkers
                && (triedTerminals = true) && // [first set triedTerminals]
                terminals.Length != 0)     // AND if there are available terminals
            {
                var n = terminals[state.Random[thread].NextInt(terminals.Length)].LightClone();
                n.ResetNode(state, thread); // give ERCs a chance to randomize
                n.ArgPosition = (sbyte)argPosition;
                n.Parent      = parent;
                return(n);
            }
            // else pick a random node
            else
            {
                if (triedTerminals)
                {
                    WarnAboutNoTerminalWithType(type, false, state); // we tried terminals and we're here because there were none!
                }
                var n = nodes[state.Random[thread].NextInt(nodes.Length)].LightClone();
                n.ResetNode(state, thread); // give ERCs a chance to randomize
                n.ArgPosition = (sbyte)argPosition;
                n.Parent      = parent;

                // Populate the node...
                var childtypes = n.Constraints(((GPInitializer)state.Initializer)).ChildTypes;
                for (var x = 0; x < childtypes.Length; x++)
                {
                    n.Children[x] = GrowNode(state, current + 1, max, childtypes[x], thread, n, x, funcs);
                }

                return(n);
            }
        }
Exemple #13
0
        public override GPNode NewRootedTree(IEvolutionState state, GPType type, int thread, IGPNodeParent parent,
                                             GPFunctionSet funcs, int argPosition, int requestedSize)
        {
            var initializer = ((GPInitializer)state.Initializer);

            if (requestedSize == NOSIZEGIVEN)
            // pick from the distribution
            {
                var BOUNDARY = 20; // if we try 20 times and fail, check to see if it's possible to succeed
                var bound    = 0;

                var fset = (int)FunctionSetsHash[funcs];
                var siz  = PickSize(state, thread, fset, type.Type);
                var typ  = type.Type;

                // this code is confusing.  The idea is:
                // if the number of trees of our arbitrarily-picked size is zero, we try BOUNDARY
                // number of times to find a tree which will work, picking new sizes each
                // time.  If we still haven't found anything, we will continue to search
                // for a working tree only if we know for sure that one exists in the distribution.

                var checkState = false; // BRS : Can't call this "checked" as in ECJ because of the compiler keyword
                while (ROOT_D_ZERO[fset][typ][siz])
                {
                    if (++bound == BOUNDARY)
                    {
                        if (!checkState)
                        {
                            checkState = true;
                            for (var x = 0; x < ROOT_D_ZERO[fset][typ].Length; x++)
                            {
                                if (!ROOT_D_ZERO[fset][typ][x])
                                {
                                    goto check_brk; // BRS : TODO : This is different from ECJ "break check;" Is it equivalent?
                                } // found a non-zero
                            }
                            // uh oh, we're all zeroes
                            state.Output.Fatal("ec.gp.build.Uniform was asked to build a tree with functionset " + funcs
                                               + " rooted with type " + type + ", but cannot because for some reason there are no trees"
                                               + " of any valid size (within the specified size range) which exist for this function set and type.");
                        }
                        check_brk :;
                    }
                    siz = PickSize(state, thread, fset, typ);
                }

                // okay, now we have a valid size.
                var n = CreateTreeOfType(state, thread, initializer, fset, typ, siz, state.Random[thread]);
                n.Parent      = parent;
                n.ArgPosition = (sbyte)argPosition;
                return(n);
            }
            else if (requestedSize < 1)
            {
                state.Output.Fatal("ec.gp.build.Uniform requested to build a tree, but a requested size was given that is < 1.");
                return(null); // never happens
            }
            else
            {
                var fset = (int)FunctionSetsHash[funcs];
                var typ  = type.Type;
                var siz  = requestedSize;

                // if the number of trees of the requested size is zero, we first march up until we
                // find a tree size with non-zero numbers of trees.  Failing that, we march down to
                // find one.  If that still fails, we issue an error.  Otherwise we use the size
                // we discovered.

                if (ROOT_D_ZERO[fset][typ][siz])
                {
                    // march up
                    for (var x = siz + 1; x < ROOT_D_ZERO[fset][typ].Length; x++)
                    {
                        if (ROOT_D_ZERO[fset][typ][siz])
                        {
                            siz = x;
                            goto determineSize_brk;
                        }
                    }
                    // march down
                    for (var x = siz - 1; x >= 0; x--)
                    {
                        if (ROOT_D_ZERO[fset][typ][siz])
                        {
                            siz = x;
                            goto determineSize_brk;
                        }
                    }
                    // issue an error
                    state.Output.Fatal("ec.gp.build.Uniform was asked to build a tree with functionset " + funcs + " rooted with type "
                                       + type + ", and of size " + requestedSize + ", but cannot because for some reason there are no trees of any"
                                       + " valid size (within the specified size range) which exist for this function set and type.");
                }

                determineSize_brk :;


                var n = CreateTreeOfType(state, thread, initializer, fset, typ, siz, state.Random[thread]);
                n.Parent      = parent;
                n.ArgPosition = (sbyte)argPosition;
                return(n);
            }
        }
Exemple #14
0
        private GPNode randomBranch(IEvolutionState state, GPType type, int maxLength, int thread, IGPNodeParent parent, int argPosition, GPFunctionSet funcs)
        {
            // randomBranch can mess up if there are no available terminals for a given type.  If this occurs,
            // and we find ourselves unable to pick a terminal when we want to do so, we will issue a warning,
            // and pick a nonterminal, violating the maximum-size contract.  This can lead to pathological situations
            // where the system will continue to go on and on unable to stop because it can't pick a terminal,
            // resulting in running out of memory or some such.  But there are cases where we'd want to let
            // this work itself out.
            var triedTerminals = false;

            var t            = type.Type;
            var terminals    = funcs.Terminals[t];
            var nonterminals = funcs.Nonterminals[t];
            var nodes        = funcs.Nodes[t];

            if (nodes.Length == 0)
            {
                ErrorAboutNoNodeWithType(type, state); // total failure
            }
            // if the desired length is 1
            // OR if there are NO nonterminals!
            // [first set triedTerminals]
            // AND if there are available terminals
            if ((maxLength == 1 || WarnAboutNonterminal(nonterminals.Length == 0, type, false, state))
                // this will freak out the static checkers
                && (triedTerminals = true) &&
                terminals.Length != 0)
            {
                var n = terminals[state.Random[thread].NextInt(terminals.Length)].LightClone();
                n.ResetNode(state, thread); // give ERCs a chance to randomize
                n.ArgPosition = (sbyte)argPosition;
                n.Parent      = parent;
                return(n);
            }

            if (triedTerminals)
            {
                WarnAboutNoTerminalWithType(type, false, state); // we tried terminals and we're here because there were none!
            }
            // grab all the nodes whose arity is <= maxlength-1
            var len = funcs.NonterminalsUnderArity[type.Type].Length - 1;

            if (len > maxLength - 1)
            {
                len = maxLength - 1;
            }
            var okayNonterms = funcs.NonterminalsUnderArity[type.Type][len];

            if (okayNonterms.Length == 0)
            // no nodes, pick a terminal
            {
                if (terminals.Length == 0)
                {
                    ErrorAboutNoNodeWithType(type, state); // total failure
                }
                var n = terminals[state.Random[thread].NextInt(terminals.Length)].LightClone();
                n.ResetNode(state, thread); // give ERCs a chance to randomize
                n.ArgPosition = (sbyte)argPosition;
                n.Parent      = parent;
                return(n);
            }
            // we've got nonterminals, pick one at random
            else
            {
                var n = okayNonterms[state.Random[thread].NextInt(okayNonterms.Length)].LightClone();
                n.ResetNode(state, thread); // give ERCs a chance to randomize
                n.ArgPosition = (sbyte)argPosition;
                n.Parent      = parent;

                // Populate the node...
                var childtypes = n.Constraints((GPInitializer)state.Initializer).ChildTypes;
                for (var x = 0; x < childtypes.Length; x++)
                {
                    n.Children[x] = randomBranch(state, childtypes[x], (maxLength - 1) / childtypes.Length, thread, n, x, funcs);
                }
                return(n);
            }
        }