/// <summary> /// Construct the program node. /// </summary> /// <param name="theOwner">The owner of the node.</param> /// <param name="theTemplate">The opcode that this node is based on.</param> /// <param name="theArgs">The child nodes to this node.</param> public ProgramNode(EncogProgram theOwner, IProgramExtensionTemplate theTemplate, ITreeNode[] theArgs) { _owner = theOwner; _data = new ExpressionValue[theTemplate.DataSize]; _template = theTemplate; AddChildNodes(theArgs); for (int i = 0; i < _data.Length; i++) { _data[i] = new ExpressionValue((long) 0); } }
/// <summary> /// This method is used when parsing an expression. Consider x>=2. The parser /// first sees the > symbol. But it must also consider the =. So we first /// look for a 2-char operator, in this case there is one. /// </summary> /// <param name="ch1">The first character of the potential operator.</param> /// <param name="ch2">The second character of the potential operator. Zero if none.</param> /// <returns>The expression template for the operator found.</returns> public IProgramExtensionTemplate FindOperator(char ch1, char ch2) { // if ch2==0 then we are only looking for a single char operator. // this is rare, but supported. if (ch2 == 0) { return(FindOperatorExact("" + ch1)); } // first, see if we can match an operator with both ch1 and ch2 IProgramExtensionTemplate result = FindOperatorExact("" + ch1 + ch2) ?? FindOperatorExact("" + ch1); // return the operator if we have one. return(result); }
/// <summary> /// Factor a new program node, based on an opcode name and arguments. /// </summary> /// <param name="name">The name of the opcode.</param> /// <param name="program">The program to factor for.</param> /// <param name="args">The arguements.</param> /// <returns>The newly created ProgramNode.</returns> public ProgramNode FactorProgramNode(String name, EncogProgram program, ProgramNode[] args) { String key = EncogOpcodeRegistry.CreateKey(name, args.Length); if (!_templateMap.ContainsKey(key)) { throw new EACompileError("Undefined function/operator: " + name + " with " + args.Length + " args."); } IProgramExtensionTemplate temp = _templateMap[key]; return(new ProgramNode(program, temp, args)); }
/// <summary> /// Add an opcode to the function factory from the opcode registry. /// </summary> /// <param name="name">The name of the opcode.</param> /// <param name="args">The number of arguments.</param> public void AddExtension(String name, int args) { String key = EncogOpcodeRegistry.CreateKey(name, args); if (!_templateMap.ContainsKey(key)) { IProgramExtensionTemplate temp = EncogOpcodeRegistry.Instance .FindOpcode(name, args); if (temp == null) { throw new EACompileError("Unknown extension " + name + " with " + args + " arguments."); } _opcodes.Add(temp); _templateMap[key] = temp; } }
private void handleSymbol() { char ch1 = this.parser.ReadChar(); // handle unary if (this.unary) { if (ch1 == '+') { return; } else if (ch1 == '-') { this.functionStack.Push(StandardExtensions.EXTENSION_NEG); return; } } // handle regular operator char ch2 = (char)0; if (!this.parser.EOL()) { ch2 = this.parser.Peek(); } IProgramExtensionTemplate temp = this.holder.Functions.FindOperator(ch1, ch2); // did we find anything? if (temp != null) { // if we found a 2-char operator, then advance beyond the 2nd // char if (temp.Name.Length > 1) { this.parser.Advance(); } functionQueue(temp); } else { throw new EACompileError("Unknown symbol: " + ch1); } }
private void functionQueue(IProgramExtensionTemplate f) { // while there is an operator token, o2, at the top of the stack, and // either o1 is left-associative and o1 has precedence less than or // equal to that of o2, // or o1 has precedence less than that of o2, while (this.functionStack.Count != 0 && this.functionStack.Peek().NodeType != NodeType.None && ((f.NodeType == NodeType.OperatorLeft && f .Precedence >= this.functionStack.Peek() .Precedence) || f.Precedence > this.functionStack .Peek().Precedence)) { OutputQueue(this.functionStack.Pop()); } functionStack.Push(f); }
/// <summary> /// Create a terminal node. /// </summary> /// <param name="rnd">A random number generator.</param> /// <param name="program">The program to generate for.</param> /// <param name="types">The types that we might generate.</param> /// <returns>The terminal program node.</returns> public ProgramNode CreateTerminalNode(EncogRandom rnd, EncogProgram program, IList <EPLValueType> types) { IProgramExtensionTemplate temp = GenerateRandomOpcode( rnd, Context.Functions.FindOpcodes(types, _context, true, false)); if (temp == null) { throw new EACompileError("No opcodes exist for the type: " + types); } var result = new ProgramNode(program, temp, new ProgramNode[] {}); temp.Randomize(rnd, types, result, MinConst, MaxConst); return(result); }
private void OutputQueue(IProgramExtensionTemplate opp) { if (opp == this.LEFT_PAREN) { throw new EACompileError("Unmatched parentheses"); } ProgramNode[] args = new ProgramNode[opp.ChildNodeCount]; for (int i = args.Length - 1; i >= 0; i--) { if (this.outputStack.Count == 0) { throw new EACompileError("Not enough arguments"); } args[i] = this.outputStack.Pop(); } this.rootNode = this.holder.Functions.FactorProgramNode(opp, this.holder, args); outputStack.Push(rootNode); }
/// <summary> /// Factor a new program node, based in a template object. /// </summary> /// <param name="temp">The opcode.</param> /// <param name="program">The program.</param> /// <param name="args">The arguments for this node.</param> /// <returns>The newly created ProgramNode.</returns> public ProgramNode FactorProgramNode(IProgramExtensionTemplate temp, EncogProgram program, ProgramNode[] args) { return(new ProgramNode(program, temp, args)); }
public ProgramNode Parse(String expression) { this.parser = new SimpleParser(expression); this.unary = true; while (!parser.EOL()) { parser.EatWhiteSpace(); char ch = parser.Peek(); if (ch == '.' || char.IsDigit(ch)) { HandleNumeric(); this.unary = false; } else if (char.IsLetter(ch)) { handleAlpha(false); this.unary = false; } else if (ch == '(') { this.parser.Advance(); this.functionStack.Push(LEFT_PAREN); this.unary = true; } else if (ch == ')') { handleRightParen(); this.unary = false; } else if ("<>^*/+-=&|".IndexOf(ch) != -1) { handleSymbol(); this.unary = true; } else if (ch == '\"') { handleString(); this.unary = false; } else if (ch == ',') { HandleFunctionSeparator(); this.unary = true; } else { throw new EACompileError("Unparsable character: " + ch); } } // pop off any functions still on the stack while (this.functionStack.Count > 0) { IProgramExtensionTemplate f = this.functionStack.Pop(); OutputQueue(f); } // were there no operators? if (this.rootNode == null) { this.rootNode = this.outputStack.Pop(); } return(this.rootNode); }
public ProgramNode Parse(String expression) { this.parser = new SimpleParser(expression); while (!this.parser.EOL()) { this.parser.EatWhiteSpace(); // read in the command if (this.parser.ReadChar() != '[') { throw new EACompileError("Expected ["); } this.parser.EatWhiteSpace(); StringBuilder cmd = new StringBuilder(); while (this.parser.Peek() != ']' && !this.parser.EOL()) { cmd.Append(this.parser.ReadChar()); } if (this.parser.Peek() != ']') { throw new EACompileError("Expected ]"); } this.parser.Advance(); // parse out the command string[] tok = cmd.ToString().Split(':'); int idx = 0; String name = tok[idx++]; int childCount = int.Parse(tok[idx++]); IProgramExtensionTemplate temp = EncogOpcodeRegistry.Instance.FindOpcode(name, childCount); if (temp == null) { throw new EACompileError("Invalid instruction: " + name); } // build the arguments ProgramNode[] args = new ProgramNode[childCount]; for (int i = args.Length - 1; i >= 0; i--) { args[i] = this.nodeStack.Pop(); } // factor the node ProgramNode node = this.holder.Functions.FactorProgramNode(name, this.holder, args); this.nodeStack.Push(node); // add any needed data to the node for (int i = 0; i < temp.DataSize; i++) { String str = tok[idx++].Trim(); int strIdx = str.IndexOf('#'); if (strIdx != -1) { int enumType = int.Parse(str.Substring(0, strIdx)); int enumVal = int.Parse(str.Substring(strIdx + 1)); node.Data[0] = new ExpressionValue(enumType, enumVal); } // is it boolean? else if (str.Length == 1 && "tf".IndexOf(char.ToLower(str[0])) != -1) { node.Data[i] = new ExpressionValue(string.Compare(str, "t", true)); } // is it a string? else if (str[0] == '\"') { node.Data[i] = new ExpressionValue(str.Substring(1, str.Length - 1)); } // is it an integer else if (str.IndexOf('.') == -1 && str.ToLower().IndexOf('e') == -1) { long l; try { l = long.Parse(str); } catch (FormatException ex) { // sometimes C# will output a long value that is larger than can be parsed // this is very likely not a useful genome and we just set it to zero so that // the population load does not fail. l = 0; } node.Data[i] = new ExpressionValue(l); } // At this point, must be a float else { node.Data[i] = new ExpressionValue(CSVFormat.EgFormat.Parse(str)); } } } return(this.nodeStack.Pop()); }
/// <summary> /// Factor a new program node, based in a template object. /// </summary> /// <param name="temp">The opcode.</param> /// <param name="program">The program.</param> /// <param name="args">The arguments for this node.</param> /// <returns>The newly created ProgramNode.</returns> public ProgramNode FactorProgramNode(IProgramExtensionTemplate temp, EncogProgram program, ProgramNode[] args) { return new ProgramNode(program, temp, args); }
/// <summary> /// Add an opcode to the function factory. The opcode must exist in the /// opcode registry. /// </summary> /// <param name="ext">The opcode to add.</param> public void AddExtension(IProgramExtensionTemplate ext) { AddExtension(ext.Name, ext.ChildNodeCount); }
/// <summary> /// Add an opcode. User programs should add opcodes here. /// </summary> /// <param name="ext">The opcode to add.</param> public void Add(IProgramExtensionTemplate ext) { _registry[ CreateKey(ext.Name, ext.ChildNodeCount)] = ext; }
/// <summary> /// Create a random note according to the specified paramaters. /// </summary> /// <param name="rnd">A random number generator.</param> /// <param name="program">The program to generate for.</param> /// <param name="depthRemaining">The depth remaining to generate.</param> /// <param name="types">The types to generate.</param> /// <param name="includeTerminal">Should we include terminal nodes.</param> /// <param name="includeFunction">Should we include function nodes.</param> /// <returns>The generated program node.</returns> public ProgramNode CreateRandomNode(EncogRandom rnd, EncogProgram program, int depthRemaining, IList <EPLValueType> types, bool includeTerminal, bool includeFunction) { // if we've hit the max depth, then create a terminal nodes, so it stops // here if (depthRemaining == 0) { return(CreateTerminalNode(rnd, program, types)); } // choose which opcode set we might create the node from IList <IProgramExtensionTemplate> opcodeSet = Context.Functions.FindOpcodes(types, Context, includeTerminal, includeFunction); // choose a random opcode IProgramExtensionTemplate temp = GenerateRandomOpcode(rnd, opcodeSet); if (temp == null) { throw new EACompileError( "Trying to generate a random opcode when no opcodes exist."); } // create the child nodes int childNodeCount = temp.ChildNodeCount; var children = new ProgramNode[childNodeCount]; if (EncogOpcodeRegistry.IsOperator(temp.NodeType) && children.Length >= 2) { // for an operator of size 2 or greater make sure all children are // the same time IList <EPLValueType> childTypes = temp.Params[0] .DetermineArgumentTypes(types); EPLValueType selectedType = childTypes[rnd .Next(childTypes.Count)]; childTypes.Clear(); childTypes.Add(selectedType); // now create the children of a common type for (int i = 0; i < children.Length; i++) { children[i] = CreateNode(rnd, program, depthRemaining - 1, childTypes); } } else { // otherwise, let the children have their own types for (int i = 0; i < children.Length; i++) { IList <EPLValueType> childTypes = temp.Params[i] .DetermineArgumentTypes(types); children[i] = CreateNode(rnd, program, depthRemaining - 1, childTypes); } } // now actually create the node var result = new ProgramNode(program, temp, children); temp.Randomize(rnd, types, result, MinConst, MaxConst); return(result); }
/// <summary> /// Construct using an extension template. /// </summary> /// <param name="temp">The template.</param> public ScriptOpcode(IProgramExtensionTemplate temp) : this(temp.Name, temp.ChildNodeCount) { }
private void handleAlpha(bool neg) { StringBuilder varName = new StringBuilder(); while (char.IsLetterOrDigit(this.parser.Peek())) { varName.Append(this.parser.ReadChar()); } this.parser.EatWhiteSpace(); if (varName.ToString().Equals("true")) { if (neg) { throw new EACompileError("Invalid negative sign."); } ProgramNode v = this.holder.Functions.FactorProgramNode("#const", holder, new ProgramNode[] { }); v.Data[0] = new ExpressionValue(true); OutputQueue(v); } else if (varName.ToString().Equals("false")) { if (neg) { throw new EACompileError("Invalid negative sign."); } ProgramNode v = this.holder.Functions.FactorProgramNode("#const", holder, new ProgramNode[] { }); v.Data[0] = new ExpressionValue(false); OutputQueue(v); } else if (this.parser.Peek() != '(') { ProgramNode v; // either a variable or a const, see which if (this.holder.Functions.IsDefined(varName.ToString(), 0)) { v = this.holder.Functions.FactorProgramNode( varName.ToString(), holder, new ProgramNode[] { }); } else { this.holder.Variables.SetVariable(varName.ToString(), new ExpressionValue((long)0)); v = this.holder.Functions.FactorProgramNode("#var", holder, new ProgramNode[] { }); v.Data[0] = new ExpressionValue((int)this.holder.Variables .GetVariableIndex(varName.ToString())); } if (neg) { v = this.holder.Functions.FactorProgramNode("-", holder, new ProgramNode[] { v }); } OutputQueue(v); } else { IProgramExtensionTemplate temp = this.holder.Functions .FindFunction(varName.ToString()); if (temp == null) { throw new EACompileError("Undefined function: " + varName.ToString()); } functionQueue(temp); } }