/// <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(); // whoops! }
/// <summary> /// Determines the GPNode from the function set by the name. If there is more than /// one such node (which shouldn't be the case) then only the first such node is /// used. Stores the prototype. /// </summary> public GrammarFunctionNode(GPFunctionSet gpfs, String name) : base(name) { _prototype = ((GPNode[])gpfs.NodesByName[name])[0]; }
/// <summary> /// Parses each of a rule's production choices. /// </summary> void ParseProductions(IEvolutionState state, GrammarRuleNode retResult, IGELexer lexer, GPFunctionSet gpfs) { do { var token = lexer.NextToken(); if (lexer.MatchingIndex == RULE) { retResult.AddChoice(GetRule(_rules, token)); token = lexer.NextToken(); } else { if (lexer.MatchingIndex != LPAREN) //first expect '(' { state.Output.Fatal("GE Grammar Error - Unexpected token for rule: " + retResult.Head + "Expecting '('."); } token = lexer.NextToken(); if (lexer.MatchingIndex != FUNCTION) //now expecting function { state.Output.Fatal("GE Grammar Error - Expecting a function name after first '(' for rule: " + retResult.Head + " Error: " + token); } else { if (!gpfs.NodesByName.ContainsKey(token)) { state.Output.Fatal("GPNode " + token + " is not defined in the function set."); } var grammarfuncnode = new GrammarFunctionNode(gpfs, token); token = lexer.NextToken(); while (lexer.MatchingIndex != RPAREN) { if (lexer.MatchingIndex != RULE) //this better be the name of a rule node { state.Output.Fatal( "GE Grammar Error - Expecting a rule name as argument for function definition: " + grammarfuncnode.Head + " Error on : " + token); } grammarfuncnode.AddArgument(GetRule(_rules, token)); token = lexer.NextToken(); } retResult.AddChoice(grammarfuncnode); } //after right paren, should see either '|' or newline token = lexer.NextToken(); if (lexer.MatchingIndex != PIPE && lexer.MatchingIndex != Constants.GE_LEXER_FAILURE) { state.Output.Fatal("GE Grammar Error - Expecting either '|' delimiter or newline. Error on : " + token); } } } while (lexer.MatchingIndex == PIPE); }
/// <summary> /// This function parses the dyck word and puts random nodes into their slots. /// </summary> private static GPNode BuildTree(IEvolutionState state, int thread, IGPNodeParent parent, int argPosition, GPFunctionSet funcs, string dyckWord) { var s = new List <GPNode>(); // Parsing dyck word from left to right and building tree for (var counter = 0; counter < dyckWord.Length; counter++) { char nextChar; if (counter < dyckWord.Length - 1) { nextChar = dyckWord[counter + 1]; } else { nextChar = '*'; } if ((nextChar == 'x') || (nextChar == '*')) /* terminal node */ { var nn = funcs.Terminals[0]; var n = nn[state.Random[thread].NextInt(nn.Length)].LightClone(); n.ResetNode(state, thread); // give ERCs a chance to randomize s.Add(n); } else if (nextChar == 'y') /* non-terminal */ { // finding arity of connection var ycount = 0; /* arity */ var nextCharY = (nextChar == 'y'); counter++; while ((counter < dyckWord.Length) && (nextCharY)) { if (dyckWord[counter] == 'y') { ycount++; } if (counter < dyckWord.Length - 1) { nextCharY = (dyckWord[counter + 1] == 'y'); } counter++; } //Arity found. Now just choose non terminal at random. var nonTerms = funcs.NodesByArity[0][ycount]; var nT = nonTerms[state.Random[thread].NextInt(nonTerms.Length)].LightClone(); // Non terminal chosen, now attaching children var childcount = ycount; while (childcount > 0) { childcount--; if (s.Count == 0) { state.Output.Fatal("Stack underflow when building tree."); } var child = Pop(s); child.Parent = nT; child.ArgPosition = (sbyte)childcount; nT.Children[childcount] = child; } nT.ArgPosition = 0; nT.Parent = null; s.Add(nT); if (counter != dyckWord.Length) { counter--; } } } return(Pop(s)); }
/// <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); } }
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); } }
public virtual void Preprocess(IEvolutionState state, int maxTreeSize) { state.Output.Message("Determining Tree Sizes"); MaxTreeSize = maxTreeSize; var functionSetRepository = ((GPInitializer)state.Initializer).FunctionSetRepository; // Put each function set into the arrays FunctionSets = new GPFunctionSet[functionSetRepository.Count]; FunctionSetsHash = Hashtable.Synchronized(new Hashtable()); var e = functionSetRepository.Values.GetEnumerator(); var count = 0; while (e.MoveNext()) { var funcs = (GPFunctionSet)e.Current; FunctionSetsHash[funcs] = count; FunctionSets[count++] = funcs; } // For each function set, assign each GPNode to a unique integer // so we can keep track of it (ick, this will be inefficient!) FuncNodesHash = Hashtable.Synchronized(new Hashtable()); var t_nodes = Hashtable.Synchronized(new Hashtable()); count = 0; MaxArity = 0; for (var x = 0; x < FunctionSets.Length; x++) { GPNode n; // hash all the nodes so we can remove duplicates for (var typ = 0; typ < FunctionSets[x].Nodes.Length; typ++) { for (var nod = 0; nod < FunctionSets[x].Nodes[typ].Length; nod++) { t_nodes[n = FunctionSets[x].Nodes[typ][nod]] = n; } } // rehash with Integers, yuck e = t_nodes.Values.GetEnumerator(); GPNode tmpn; while (e.MoveNext()) { tmpn = (GPNode)e.Current; if (MaxArity < tmpn.Children.Length) { MaxArity = tmpn.Children.Length; } if (!FuncNodesHash.ContainsKey(tmpn)) // don't remap the node; it'd make holes { FuncNodesHash[tmpn] = count++; } } } NumFuncNodes = FuncNodesHash.Count; var initializer = (GPInitializer)state.Initializer; var numAtomicTypes = initializer.NumAtomicTypes; var numSetTypes = initializer.NumSetTypes; var functionSetsLength = FunctionSets.Length; var atomicPlusSetTypes = numAtomicTypes + numSetTypes; var maxTreeSizePlusOne = MaxTreeSize + 1; // set up the arrays // NUMTREESOFTYPE NUMTREESOFTYPE = TensorFactory.Create <BigInteger>(functionSetsLength, atomicPlusSetTypes, maxTreeSizePlusOne); // NUMTREESROOTEDBYNODE NUMTREESROOTEDBYNODE = TensorFactory.Create <BigInteger>(functionSetsLength, NumFuncNodes, maxTreeSizePlusOne); // NUMCHILDPERMUTATIONS NUMCHILDPERMUTATIONS = TensorFactory.Create <BigInteger>(functionSetsLength, NumFuncNodes, maxTreeSizePlusOne, maxTreeSizePlusOne, MaxArity); // ROOT_D ROOT_D = TensorFactory.CreateOpenEnded <UniformGPNodeStorage>(functionSetsLength, atomicPlusSetTypes, maxTreeSizePlusOne); // 4D OpenEnded // ROOT_D_ZERO ROOT_D_ZERO = TensorFactory.Create <bool>(functionSetsLength, atomicPlusSetTypes, maxTreeSizePlusOne); // CHILD_D CHILD_D = TensorFactory.CreateOpenEnded <double>(functionSetsLength, NumFuncNodes, maxTreeSizePlusOne, maxTreeSizePlusOne); // 5D OpenEnded var types = ((GPInitializer)(state.Initializer)).Types; // _TrueSizesBigInt TrueSizesBigInt = TensorFactory.Create <BigInteger>(functionSetsLength, atomicPlusSetTypes, maxTreeSizePlusOne); // Go through each function set and determine numbers // (this will take quite a while! Thankfully it's offline) for (var x = 0; x < FunctionSets.Length; x++) { for (var y = 0; y < numAtomicTypes + numSetTypes; y++) { for (var z = 1; z <= MaxTreeSize; z++) { state.Output.Message("FunctionSet: " + FunctionSets[x].Name + ", Type: " + types[y].Name + ", Size: " + z + " num: " + (TrueSizesBigInt[x][y][z] = NumTreesOfType(initializer, x, y, z))); } } } state.Output.Message("Compiling Distributions"); TrueSizes = TensorFactory.Create <double>(functionSetsLength, atomicPlusSetTypes, maxTreeSizePlusOne); // convert to doubles and organize distribution for (var x = 0; x < FunctionSets.Length; x++) { for (var y = 0; y < numAtomicTypes + numSetTypes; y++) { for (var z = 1; z <= MaxTreeSize; z++) { TrueSizes[x][y][z] = (double)TrueSizesBigInt[x][y][z]; // BRS : DOES THIS TRUNCATE ANYTHING ??? } // and if this is all zero (a possibility) we should be forgiving (hence the 'true') -- I *think* RandomChoice.OrganizeDistribution(TrueSizes[x][y], true); } } // compute our percentages ComputePercentages(); }
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); } }