/// <summary> /// If the given test is true, issues a warning that no terminal was found with a return type of the given type, and that an algorithm /// had requested one. If fail is true, then a fatal is issued rather than a warning. The warning takes /// the form of a one-time big explanatory message, followed by a one-time-per-type message. Returns the value of the test. /// This form makes it easy to insert warnings into if-statements. /// </summary> protected internal virtual bool WarnAboutNonterminal(bool test, GPType type, bool fail, IEvolutionState state) { if (test) { WarnAboutNonTerminalWithType(type, fail, state); } return(test); }
public override bool CompatibleWith(GPInitializer initializer, GPType t) { // if the type is me, then I'm compatible with it if (t.Type == Type) { return(true); } // if the type an atomic type, then return false if (t.Type < initializer.NumAtomicTypes) { return(false); } // if the type is < 0 (it's a set type), then I'm compatible // if I'm contained in it. Use its sparse array. return(((GPSetType)t).TypesSparse[Type]); }
/// <summary> /// Assigns unique integers to each atomic type, and sets up compatibility /// arrays for set types. If you add new types (heaven forbid), you /// should call this method again to get all the types set up properly. /// However, you will have to set up the function sets again as well, /// as their arrays are based on these type numbers. /// </summary> public virtual void PostProcessTypes() { // assign positive integers and 0 to atomic types var x = 0; var e = TypeRepository.Values.GetEnumerator(); while (e.MoveNext()) { var t = (GPType)(e.Current); if (t is GPAtomicType) { t.Type = x; x++; } } // at this point, x holds the number of atomic types. NumAtomicTypes = x; // assign additional positive integers to set types // and set up arrays for the set types e = TypeRepository.Values.GetEnumerator(); while (e.MoveNext()) { var t = (GPType)(e.Current); if (t is GPSetType) { ((GPSetType)t).PostProcessSetType(NumAtomicTypes); t.Type = x; x++; } } // at this point, x holds the number of set types + atomic types NumSetTypes = x - NumAtomicTypes; // make an array for convenience. Presently rarely used. Types = new GPType[NumSetTypes + NumAtomicTypes]; e = TypeRepository.Values.GetEnumerator(); while (e.MoveNext()) { var t = (GPType)(e.Current); Types[t.Type] = t; } }
/// <summary> /// Issues a warning that no nonterminal was found with a return type of the given type, and that an algorithm /// had requested one. If fail is true, then a fatal is issued rather than a warning. The warning takes /// the form of a one-time big explanatory message, followed by a one-time-per-type message. /// </summary> protected internal virtual void WarnAboutNonTerminalWithType(GPType type, bool fail, IEvolutionState state) { // big explanation -- appears only once state.Output.WarnOnce("A GPNodeBuilder has been requested at least once to generate a one-node tree with " + "a return value type-compatable with a certain type; but there is no NON-TERMINAL which is type-compatable " + "in this way. As a result, the algorithm was forced to use a TERMINAL, making the tree larger than " + "requested, and exposing more child slots to fill, which if not carefully considered, could " + "recursively repeat this problem and eventually fill all memory."); // shorter explanation -- appears for each node builder and type combo if (fail) { state.Output.Fatal("" + GetType() + " can't find a terminal type-compatable with " + type + " and cannot replace it with a nonterminal. You may need to try a different node-builder algorithm."); } else { state.Output.WarnOnce("" + GetType() + " can't find a terminal type-compatable with " + type); } }
public override bool CompatibleWith(GPInitializer initializer, GPType t) { // if the type is me, then I'm compatible with it. if (t.Type == Type) { return(true); } // if the type is an atomic type, then I'm compatible with it if I contain it. // Use the sparse array. if (t.Type < initializer.NumAtomicTypes) { // atomic type, faster than doing instanceof return(TypesSparse[t.Type]); } // else the type is a set type. I'm compatible with it if we contain // an atomic type in common. Use the sorted packed array. var s = (GPSetType)t; var x = 0; var y = 0; for (; x < TypesPacked.Length && y < s.TypesPacked.Length;) { if (TypesPacked[x] == s.TypesPacked[y]) { return(true); } if (TypesPacked[x] < s.TypesPacked[y]) { x++; } else { y++; } } return(false); }
/// <summary> /// When completed, done will hold all the types which are needed /// in the function set -- you can then check to make sure that /// they contain at least one terminal and (hopefully) at least /// one nonterminal. /// </summary> private void CheckFunctionSetValidity(IEvolutionState state, Hashtable done, GPType type) { // put type in the hashtable -- it's being used done[type] = type; // Grab the array in nodes var i = FunctionSet.Nodes[type.Type]; // For each argument type in a node in i, if it's not in done, // then add it to done and call me on it var initializer = ((GPInitializer)state.Initializer); foreach (var node in i) { foreach (var t in node.Constraints(initializer).ChildTypes) { if (done[t] == null) { CheckFunctionSetValidity(state, done, t); } } } }
/// <summary> /// Issues a fatal error that no node (nonterminal or terminal) /// was found with a return type of the given type, and that an algorithm /// had requested one. /// </summary> protected internal virtual void ErrorAboutNoNodeWithType(GPType type, IEvolutionState state) { state.Output.Fatal("" + GetType() + " could find no terminal or nonterminal type-compatable with " + type); }
/// <summary> /// Produces a new rooted tree of GPNodes whose root's return type is /// swap-compatible with <i>type</i>. When you build a brand-new /// tree out of GPNodes cloned from the /// prototypes stored in the GPNode[] arrays, you must remember /// to call resetNode() on each cloned GPNode. This gives ERCs a chance /// to randomize themselves and set themselves up. /// <p/>requestedSize is an /// optional argument which differs based on the GPNodeBuilder used. /// Typically it is set to a tree size that the calling method wants /// the GPNodeBuilder to produce; the GPNodeBuilder is not obligated to /// produce a tree of this size, but it should attempt to interpret this /// argument as appropriate for the given algorithm. To indicate that /// you don't care what size the tree should be, you can pass NOSIZEGIVEN. /// However if the algorithm <i>requires</i> you to provide a size, it /// will generate a fatal error to let you know. /// </summary> public abstract GPNode NewRootedTree(IEvolutionState state, GPType type, int thread, IGPNodeParent parent, GPFunctionSet funcs, int argPosition, int requestedSize);
/// <summary> /// Am I compatible with ("fit" with) <i>t</i>? For two atomic /// types, this is done by direct pointer equality. For /// two set types, this is done by determining if the intersection /// is nonempty. A set type is compatible with an atomic type /// if it contains the atomic type in its set. /// </summary> public abstract bool CompatibleWith(GPInitializer initializer, GPType t);
/// <summary> /// This must be called <i>after</i> the GPTypes and GPFunctionSets /// have been set up. /// </summary> public void Setup(IEvolutionState state, IParameter paramBase) { // What's my name? Name = state.Parameters.GetString(paramBase.Push(P_NAME), null); if (Name == null) { state.Output.Fatal("No name was given for this function set.", paramBase.Push(P_NAME)); } // Register me var tempObject = ((GPInitializer)state.Initializer).TreeConstraintRepository[Name]; ((GPInitializer)state.Initializer).TreeConstraintRepository[Name] = this; var oldConstraints = (GPTreeConstraints)(tempObject); if (oldConstraints != null) { state.Output.Fatal("The GP tree constraint \"" + Name + "\" has been defined multiple times.", paramBase.Push(P_NAME)); } // Load my initializing builder Init = (GPNodeBuilder)(state.Parameters.GetInstanceForParameter(paramBase.Push(P_INIT), null, typeof(GPNodeBuilder))); Init.Setup(state, paramBase.Push(P_INIT)); // Load my return type var s = state.Parameters.GetString(paramBase.Push(P_RETURNS), null); if (s == null) { state.Output.Fatal("No return type given for the GPTreeConstraints " + Name, paramBase.Push(P_RETURNS)); } TreeType = GPType.TypeFor(s, state); // Load my function set s = state.Parameters.GetString(paramBase.Push(P_FUNCTIONSET), null); if (s == null) { state.Output.Fatal("No function set given for the GPTreeConstraints " + Name, paramBase.Push(P_RETURNS)); } FunctionSet = GPFunctionSet.FunctionSetFor(s, state); state.Output.ExitIfErrors(); // otherwise checkFunctionSetValidity might crash below // Determine the validity of the function set // the way we do that is by gathering all the types that // are transitively used, starting with treetype, as in: var typ = Hashtable.Synchronized(new Hashtable()); CheckFunctionSetValidity(state, typ, TreeType); // next we make sure that for every one of these types, // there's a terminal with that return type, and *maybe* // a nonterminal var e = typ.Values.GetEnumerator(); while (e.MoveNext()) { var t = (GPType)(e.Current); var i = FunctionSet.Nodes[t.Type]; if (i.Length == 0) // yeesh { state.Output.Error("In function set " + FunctionSet + " for the GPTreeConstraints " + this + ", no nodes at all are given with the return type " + t + " which is required by other functions in the function set or by the tree's return type." + " This almost certainly indicates a serious typing error.", paramBase); } else { i = FunctionSet.Terminals[t.Type]; if (i.Length == 0) // uh oh { state.Output.Warning("In function set " + FunctionSet + " for the GPTreeConstraints " + this + ", no terminals are given with the return type " + t + " which is required by other functions in the function set or by the tree's return type." + " Nearly all tree-builders in ECJ require the ability to add a terminal of any type for which " + " there is a nonterminal, and at any time. Without terminals, your code may not work." + " One common indication that a tree-builder has failed due to this problem is if you get" + " the MersenneTwister error 'n must be positive'.", paramBase); } i = FunctionSet.Nonterminals[t.Type]; if (i.Length == 0) // uh oh { state.Output.Warning("In function set " + FunctionSet + " for the GPTreeConstraints " + this + ", no *nonterminals* are given with the return type " + t + " which is required by other functions in the function set or by the tree's return type." + " This may or may not be a problem for you.", paramBase); } } } state.Output.ExitIfErrors(); }