/// <summary> /// Computes the max depth of the tree /// </summary> /// <param name="node">Root of the tree</param> /// <returns>Depth of the tree</returns> protected int ComputeDepth(GPNode node) { int nMaxChild = 0; if (node == null) { return(0); } // // Only need to probe further if we have a function node with children if (node is GPNodeFunction) { GPNodeFunction nodeFunc = (GPNodeFunction)node; // // Determine the child with the maximum depth for (int nChild = 0; nChild < nodeFunc.Children.Count; nChild++) { int nCurrentChild = ComputeDepth(nodeFunc.Children[nChild]); if (nCurrentChild > nMaxChild) { nMaxChild = nCurrentChild; } } } return(nMaxChild + 1); // +1 is the current node depth }
/// <summary> /// Counts the number of leaf nodes in the branch /// </summary> /// <param name="node">Root of the tree</param> /// <returns>Number of leaf nodes in the branch</returns> protected ushort DoCountLeafNodes(GPNode node) { if (node == null) { return(0); } // // If a terminal node, that's it, plus, it's also a leaf node by definition if (node is GPNodeTerminal) { return(1); } // // Otherwise, we have a functional node, so count up leafs in the children GPNodeFunction nodeFunc = (GPNodeFunction)node; ushort countChild = 0; for (int nChild = 0; nChild < nodeFunc.Children.Count; nChild++) { countChild += DoCountLeafNodes(nodeFunc.Children[nChild]); } // // If this is a functional node with no children, it is a terminal, so count it. if (nodeFunc.Children.Count == 0) { return((ushort)(countChild + 1)); } return(countChild); }
/// <summary> /// Used to determine if a UDF correctly compiles. If the function doesn't /// successfully compile, the errors are returned through the Errors parameter. /// </summary> /// <param name="Name">Name of the function</param> /// <param name="FunctionCode">function code to test</param> /// <param name="Errors">Array of errors, if any</param> /// <returns>True/False upon success/failure</returns> public bool ValidateUserFunction(string Name, string FunctionCode, out string[] Errors) { GPNodeFunction func = CompileUserFunction(FunctionCode, Name, out Errors); if (func == null) { return(false); } return(true); }
/// <summary> /// ICloneable interface /// </summary> /// <returns>Clone of the object</returns> public override Object Clone() { GPNodeFunction obj = (GPNodeFunction)this.MemberwiseClone(); obj.m_TerminalParameters = this.TerminalParameters; obj.m_Children = new List <GPNode>(); // // Go through the children and start copying them foreach (GPNode child in m_Children) { obj.m_Children.Add((GPNode)child.Clone()); } return(obj); }
/// <summary> /// Add a new function to the set. This accepts the C# code of the function, /// gets it compiled and added to the set. /// </summary> /// <param name="Name"></param> /// <param name="Arity"></param> /// <param name="UserCode"></param> /// <returns></returns> public bool AddFunction(String Name, short Arity, bool TerminalParameters, String UserCode) { // // Make sure we don't already have the function if (m_FunctionSet.ContainsKey(Name.ToUpper())) { // // Just return true, it's not really an error, but we don't need // a duplicate either. return(true); } // // Write the function String FunctionCode = m_Compiler.WriteUserFunction(Name, Arity, UserCode); // // Get it compiled String[] Errors = null; GPNodeFunction node = m_Compiler.CompileUserFunction(FunctionCode, Name, out Errors); node.TerminalParameters = TerminalParameters; if (node == null) { return(false); } // // Add it to our set! m_FunctionSet.Add(Name.ToUpper(), node); // // We also keep a collection of the keys in a List<> collection // so we can have an 'int' indexer for the function set m_FunctionSetKeys.Add(Name.ToUpper()); // // Check to see if the code uses "InputHistory", if it does, indicate // this function set requires the input history of data to be built. if (UserCode.Contains("InputHistory")) { m_UseInputHistory = true; } return(true); }
/// <summary> /// Constructs a Function node based upon the XML specification /// </summary> /// <param name="FunctionNode"></param> /// <returns></returns> private GPNode CreateFunction(XmlNode FunctionNode) { XmlNode xmlType = FunctionNode.SelectSingleNode("Function"); XmlNodeList listParams = FunctionNode.SelectNodes("GPNode"); GPNodeFunction gpFunction = null; // // See if we have an ADF if (xmlType.InnerText == "ADF") { XmlNode xmlWhichADF = FunctionNode.SelectSingleNode("WhichFunction"); int WhichADF = Convert.ToInt32(xmlWhichADF.InnerText); gpFunction = new GPNodeFunctionADF(WhichADF, (byte)listParams.Count); } else if (xmlType.InnerText == "ADL") // Check for an ADL { XmlNode xmlWhichADL = FunctionNode.SelectSingleNode("WhichFunction"); int WhichADL = Convert.ToInt32(xmlWhichADL.InnerText); gpFunction = new GPNodeFunctionADL(WhichADL, (byte)listParams.Count); } else if (xmlType.InnerText == "ADR") // Check for an ADR { XmlNode xmlWhichADR = FunctionNode.SelectSingleNode("WhichFunction"); int WhichADR = Convert.ToInt32(xmlWhichADR.InnerText); gpFunction = new GPNodeFunctionADR(WhichADR, (byte)listParams.Count); } else { // // Get the correct function node type created GPNodeFunction func = (GPNodeFunction)m_FunctionSet[xmlType.InnerText.ToUpper()]; gpFunction = (GPNodeFunction)func.Clone(); } // // Build the list of parameters to this node foreach (XmlNode ParamNode in listParams) { gpFunction.Children.Add(ReadGPNode(ParamNode)); } return(gpFunction); }
/// <summary> /// Unfortunately, this is essentially a linear search, I should really label each /// node so we have a BST tree to speed up the search. /// </summary> /// <param name="parent"></param> /// <param name="node"></param> /// <param name="nFindLabel"></param> /// <returns></returns> protected FindResult FindNode(GPNode parent, GPNode node, int nFindLabel) { // // Termination Criteria: If FindLabel and the node label match if (node.Label == nFindLabel) { FindResult find = new FindResult(); find.Parent = (GPNodeFunction)parent; find.Node = node; // // Figure out which child of the parent this is if (parent != null) { GPNodeFunction nodeFunc = (GPNodeFunction)parent; for (int nChild = 0; nChild < nodeFunc.Children.Count; nChild++) { if (node == nodeFunc.Children[nChild]) { find.ChildNumber = nChild; } } } return(find); } // // Search the children if (node is GPNodeFunction) { GPNodeFunction nodeFunc = (GPNodeFunction)node; for (int nChild = 0; nChild < nodeFunc.Children.Count; nChild++) { FindResult find = FindNode(nodeFunc, nodeFunc.Children[nChild], nFindLabel); if (find != null) { return(find); } } } return(null); }
/// <summary> /// Internal recursive method that does the actual work of counting the /// nodes in the tree. /// </summary> /// <param name="node"></param> private void DoCountNodesInternal(GPNode node) { if (node == null) { return; } // // If we made it this far, count the node node.Label = m_CountLabel++; // // Update the ADF and ADL counts if (node is GPNodeFunctionADF) { m_CountADFNodes++; } if (node is GPNodeFunctionADL) { m_CountADLNodes++; } if (node is GPNodeFunctionADR) { m_CountADRNodes++; } // // If a terminal node, that's it, just count the node if (node is GPNodeTerminal) { return; } // // Otherwise, we have a functional node, so count up the children GPNodeFunction nodeFunc = (GPNodeFunction)node; for (int nChild = 0; nChild < nodeFunc.Children.Count; nChild++) { DoCountNodesInternal(nodeFunc.Children[nChild]); } }
/// <summary> /// Custom build function that creates the result producing branch /// of the genetic program. /// </summary> /// <param name="TreeBuild"></param> /// <param name="MaxDepth"></param> /// <param name="CurrentDepth"></param> /// <param name="TerminalParameters"></param> /// <returns></returns> private GPNode BuildInternal(GPEnums.TreeBuild TreeBuild, int MaxDepth, int CurrentDepth, bool TerminalParameters) { // // Randomly create this node GPNode newNode = CreateNode(TreeBuild, MaxDepth, CurrentDepth, TerminalParameters); // // If we just created a function, build its children if (newNode is GPNodeFunction) { GPNodeFunction node = (GPNodeFunction)newNode; // // Need to generate the appropriate number of nodes for the operation for (int Child = 0; Child < node.NumberArgs; Child++) { node.Children.Add(BuildInternal(TreeBuild, MaxDepth - 1, CurrentDepth + 1, node.TerminalParameters)); } } return(newNode); }
/// /// <summary> /// Take the CSharp code, compile it to an assembly and then return an instance /// of the class (Classname). This method absolutely assumes it is compiling /// a GPNodeFunction derived object. /// </summary> /// <param name="CSharpCode">The C# code to compile</param> /// <param name="FunctionName">Name of the user defined function</param> /// <param name="Errors">List of compilation errors</param> /// <returns>in-memory instance of the code ready for execution</returns> public GPNodeFunction CompileUserFunction(String CSharpCode, String FunctionName, out String[] Errors) { CSharpCodeProvider csProvider = new CSharpCodeProvider(); CompilerParameters csParams = new CompilerParameters(); csParams.GenerateExecutable = false; csParams.GenerateInMemory = true; csParams.TreatWarningsAsErrors = false; // // We derive from GPNodeFunction, have to reference the GPServer.exe assembly csParams.ReferencedAssemblies.Add(Application.StartupPath + "\\GPServer.exe"); // // This does the actual compilation of the source code CompilerResults results = csProvider.CompileAssemblyFromSource(csParams, CSharpCode); // // See if there are any errors Errors = null; if (results.Errors.Count > 0) { // // Convert the errors into a string array that is send back Errors = new String[results.Errors.Count]; for (int Item = 0; Item < results.Errors.Count; Item++) { Errors[Item] = (Item + 1).ToString() + ": " + results.Errors[Item].ErrorText; } return(null); } // // Given the assembly, create an instance of the object from it GPNodeFunction codeInstance = (GPNodeFunction)results.CompiledAssembly.CreateInstance("GPStudio.Server.GPNodeFunction" + FunctionName); return(codeInstance); }
/// <summary> /// Restores a node from the array representation back into a tree representation /// </summary> /// <param name="FunctionSet"></param> /// <returns>Reference to the converted tree</returns> public GPNode ConvertNode(IGPFunctionSet FunctionSet) { // // Determine the type of the node // < 200 : User Defined function // 200 to 210 : Terminal // 253 : ADR // 254 : ADL // 255 : ADF if (m_TreeArrayNew[m_ArrayPos] == 255) { m_ArrayPos++; byte WhichADF = m_TreeArrayNew[m_ArrayPos++]; byte NumberArgs = m_TreeArrayNew[m_ArrayPos++]; GPNodeFunctionADF NodeNew = new GPNodeFunctionADF(WhichADF, NumberArgs); // // Build up the children before returning for (byte Child = 0; Child < NumberArgs; Child++) { NodeNew.Children.Add(ConvertNode(FunctionSet)); } return(NodeNew); } else if (m_TreeArrayNew[m_ArrayPos] == 254) { m_ArrayPos++; byte WhichADL = m_TreeArrayNew[m_ArrayPos++]; byte NumberArgs = m_TreeArrayNew[m_ArrayPos++]; GPNodeFunctionADL NodeNew = new GPNodeFunctionADL(WhichADL, NumberArgs); // // Build up the children before returning for (byte Child = 0; Child < NumberArgs; Child++) { NodeNew.Children.Add(ConvertNode(FunctionSet)); } return(NodeNew); } else if (m_TreeArrayNew[m_ArrayPos] == 253) { m_ArrayPos++; byte WhichADR = m_TreeArrayNew[m_ArrayPos++]; byte NumberArgs = m_TreeArrayNew[m_ArrayPos++]; GPNodeFunctionADR NodeNew = new GPNodeFunctionADR(WhichADR, NumberArgs); // // Build up the children before returning for (byte Child = 0; Child < NumberArgs; Child++) { NodeNew.Children.Add(ConvertNode(FunctionSet)); } return(NodeNew); } else if (m_TreeArrayNew[m_ArrayPos] < 200) { GPNodeFunction NodeNew = (GPNodeFunction)((GPNodeFunction)FunctionSet[m_TreeArrayNew[m_ArrayPos++]]).Clone(); // // Build up this node's children first byte ChildCount = m_TreeArrayNew[m_ArrayPos++]; for (byte Child = 0; Child < ChildCount; Child++) { NodeNew.Children.Add(ConvertNode(FunctionSet)); } return(NodeNew); } else // Terminal { switch (m_TreeArrayNew[m_ArrayPos++]) { case 200: byte WhichADFParam = m_TreeArrayNew[m_ArrayPos++]; GPNodeTerminalADFParam NodeADF = new GPNodeTerminalADFParam(WhichADFParam); return(NodeADF); case 201: byte WhichUserDefined = m_TreeArrayNew[m_ArrayPos++]; GPNodeTerminalUserDefined NodeUser = new GPNodeTerminalUserDefined(WhichUserDefined); return(NodeUser); case 202: double dValue; unsafe { byte *ptr = (byte *)&dValue; for (int pos = 0; pos < sizeof(double); pos++) { ptr[pos] = m_TreeArrayNew[m_ArrayPos++]; } } GPNodeTerminalDouble NodeDouble = new GPNodeTerminalDouble(dValue); return(NodeDouble); case 203: int nValue; unsafe { byte *ptr = (byte *)&nValue; for (int pos = 0; pos < sizeof(int); pos++) { ptr[pos] = m_TreeArrayNew[m_ArrayPos++]; } } GPNodeTerminalInteger NodeInteger = new GPNodeTerminalInteger(nValue); return(NodeInteger); } } // // TODO: Throw an exception, instead of this lazy crap! :) return(null); }
/// <summary> /// Converts a tree node into an array based representation. For functions /// an byte lookup is used into the FunctionSet, for terminals, the type /// is recorded along with whatever extra data may be needed. /// TODO: Get rid of the unsafe code. I know there is a bit conversion /// function, I just couldn't find it quickly. /// </summary> /// <param name="Node">The node to convert</param> /// <param name="FunctionSet"></param> private void StoreNode(GPNode Node, IGPFunctionSet FunctionSet) { // // Figure out what kind of node we have and store it accordingly. if (Node is GPNodeFunction) { GPNodeFunction NodeFunction = (GPNodeFunction)Node; if (NodeFunction is GPNodeFunctionADF) { GPNodeFunctionADF adf = (GPNodeFunctionADF)NodeFunction; // // For an ADF node,record it as value 255 and then store the which // ADF it refers to and the number of arguments. m_TreeArrayNew.Add((byte)255); m_TreeArrayNew.Add((byte)adf.WhichFunction); m_TreeArrayNew.Add(adf.NumberArgs); } else if (NodeFunction is GPNodeFunctionADL) { GPNodeFunctionADL adl = (GPNodeFunctionADL)NodeFunction; // // For an ADL node,record it as value 254 and then store the which // ADL it refers to and the number of arguments. m_TreeArrayNew.Add((byte)254); m_TreeArrayNew.Add((byte)adl.WhichFunction); m_TreeArrayNew.Add(adl.NumberArgs); } else if (NodeFunction is GPNodeFunctionADR) { GPNodeFunctionADR adr = (GPNodeFunctionADR)NodeFunction; // // For an ADR node,record it as value 253 and then store the which // ADR it refers to and the number of arguments. m_TreeArrayNew.Add((byte)253); m_TreeArrayNew.Add((byte)adr.WhichFunction); m_TreeArrayNew.Add(adr.NumberArgs); } else { // // Store the index of the function and then the number of children // for this function m_TreeArrayNew.Add((byte)FunctionSet.IndexOfKey(NodeFunction.ToStringUpper())); m_TreeArrayNew.Add((byte)((GPNodeFunction)Node).Children.Count); } // // Store each of the children foreach (GPNode NodeChild in NodeFunction.Children) { StoreNode(NodeChild, FunctionSet); } } else // Terminal Node { // // Depending upon the type of the terminal, set the appropriate value if (Node is GPNodeTerminalADFParam) { m_TreeArrayNew.Add(200); m_TreeArrayNew.Add((byte)((GPNodeTerminalADFParam)Node).WhichParameter); } else if (Node is GPNodeTerminalUserDefined) { m_TreeArrayNew.Add(201); m_TreeArrayNew.Add((byte)((GPNodeTerminalUserDefined)Node).WhichUserDefined); } else if (Node is GPNodeTerminalDouble) { m_TreeArrayNew.Add(202); double dValue = ((GPNodeTerminalDouble)Node).Value; unsafe { byte *ptr = (byte *)&dValue; for (int pos = 0; pos < sizeof(double); pos++) { m_TreeArrayNew.Add(ptr[pos]); } } } else if (Node is GPNodeTerminalInteger) { m_TreeArrayNew.Add(203); int dValue = ((GPNodeTerminalInteger)Node).Value; unsafe { byte *ptr = (byte *)&dValue; for (int pos = 0; pos < sizeof(int); pos++) { m_TreeArrayNew.Add(ptr[pos]); } } } } }
/// <summary> /// This is a simple factory function that selects from the available /// list of functions and creates a class of that type. /// </summary> /// <param name="UseADF">Select from ADFs</param> /// <param name="StartADF">Which ADF to start choosing from</param> /// <param name="UseADL">Select from ADLs</param> /// <param name="StartADL">Which ADL to start choosing from</param> /// <param name="UseADR">Select from ADRs</param> /// <param name="StartADR">Which ADR to start choosing from</param> protected GPNode CreateNodeFunction(bool UseADF, int StartADF, bool UseADL, int StartADL, bool UseADR, int StartADR) { // // Add up all the different function types that we can choose from // *"Regular" function types sent over from the client // *ADFs // *ADLs // *ADRs int Count = m_Config.FunctionSet.Count; if (UseADF) { Count += m_Branch.Parent.ADF.Count - StartADF; } if (UseADL) { Count += m_Branch.Parent.ADL.Count - StartADL; } if (UseADR) { Count += m_Branch.Parent.ADR.Count - StartADR; } // // Randomly select from the function node choices. int Function = GPUtilities.rngNextInt(Count); // // See if we chose a "regular" function if (Function < m_Config.FunctionSet.Count) { GPNodeFunction Type = (GPNodeFunction)m_Config.FunctionSet[Function]; return((GPNodeFunction)Type.Clone()); } // // See if we chose an ADF Function -= m_Config.FunctionSet.Count; if (Function < (m_Branch.Parent.ADF.Count - StartADF)) { int WhichADF = StartADF + Function; byte NumberArgs = m_Branch.Parent.ADF[WhichADF].NumberArgs; GPNodeFunctionADF adfFunc = new GPNodeFunctionADF(WhichADF, NumberArgs); return(adfFunc); } // // See if we chose an ADL Function -= m_Config.ADFSet.Count; if (Function < (m_Branch.Parent.ADL.Count - StartADL)) { int WhichADL = StartADL + Function; byte NumberArgs = m_Branch.Parent.ADL[WhichADL].NumberArgs; GPNodeFunctionADL adlFunc = new GPNodeFunctionADL(WhichADL, NumberArgs); return(adlFunc); } // // See if we chose an ADR Function -= m_Config.ADLSet.Count; if (Function < (m_Branch.Parent.ADR.Count - StartADR)) { int WhichADR = StartADR + Function; byte NumberArgs = m_Branch.Parent.ADR[WhichADR].NumberArgs; GPNodeFunctionADR adrFunc = new GPNodeFunctionADR(WhichADR, NumberArgs); return(adrFunc); } return(null); }
// // Gets the function nodes written out private void WriteFunctionNodeBody(GPNode node) { GPNodeFunction nodeFunc = (GPNodeFunction)node; String sType = node.GetType().ToString(); if (node is GPNodeFunctionADF) { GPNodeFunctionADF nodeADF = (GPNodeFunctionADF)nodeFunc; m_xmlWriter.WriteStartElement("Function"); m_xmlWriter.WriteValue("ADF"); m_xmlWriter.WriteEndElement(); // // Write out "which" ADF function this is m_xmlWriter.WriteStartElement("WhichFunction"); m_xmlWriter.WriteValue(nodeADF.WhichFunction); m_xmlWriter.WriteEndElement(); for (int nParam = 0; nParam < nodeADF.NumberArgs; nParam++) { WriteProgramNode(nodeADF.Children[nParam]); } } else if (node is GPNodeFunctionADL) { GPNodeFunctionADL nodeADL = (GPNodeFunctionADL)nodeFunc; m_xmlWriter.WriteStartElement("Function"); m_xmlWriter.WriteValue("ADL"); m_xmlWriter.WriteEndElement(); // // Write out "which" ADL function this is m_xmlWriter.WriteStartElement("WhichFunction"); m_xmlWriter.WriteValue(nodeADL.WhichFunction); m_xmlWriter.WriteEndElement(); for (int nParam = 0; nParam < nodeADL.NumberArgs; nParam++) { WriteProgramNode(nodeADL.Children[nParam]); } } else if (node is GPNodeFunctionADR) { GPNodeFunctionADR nodeADR = (GPNodeFunctionADR)nodeFunc; m_xmlWriter.WriteStartElement("Function"); m_xmlWriter.WriteValue("ADR"); m_xmlWriter.WriteEndElement(); // // Write out "which" ADR function this is m_xmlWriter.WriteStartElement("WhichFunction"); m_xmlWriter.WriteValue(nodeADR.WhichFunction); m_xmlWriter.WriteEndElement(); for (int nParam = 0; nParam < nodeADR.NumberArgs; nParam++) { WriteProgramNode(nodeADR.Children[nParam]); } } else { m_xmlWriter.WriteStartElement("Function"); m_xmlWriter.WriteValue(nodeFunc.ToString()); m_xmlWriter.WriteEndElement(); // // Write out its children for (int nParam = 0; nParam < nodeFunc.NumberArgs; nParam++) { WriteProgramNode(nodeFunc.Children[nParam]); } } }