/// <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(); }