public static void main(String[] args) { // tests the ABK rule int[] ABK = { 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; var state = new EvolutionState { Random = new IMersenneTwister[] { new MersenneTwisterFast(500) } }; var ga = new MajorityGA(); ga.Setup(state, new Parameter("")); var bvi = new BitVectorIndividual { Fitness = new SimpleFitness(), genome = new bool[128] }; for (int i = 0; i < 128; i++) { bvi.genome[i] = ABK[i] != 0; } ga.Evaluate(state, bvi, 0, 0); Console.Error.WriteLine("ABK Rule"); ga.Describe(state, bvi, 0, 0, 1); }
public override void evaluate(EvolutionState state, Individual ind, int subpopulation, int threadnum) { try { this.state = state; this.ind = ((GPIndividual)ind); this.subpopulation = subpopulation; this.threadnum = threadnum; model.problem = this; // Signal model to start simulation model._signal.Set(); // Model plays out scene with individual and sets fitness _signal.WaitOne(); Debug.Log("Fitness " + model.fitness + " Result " + model.result + " = " + this.ind.trees [0].child.makeCTree(true, true, true)); KozaFitness f = ((KozaFitness)ind.fitness); f.setStandardizedFitness(state, model.fitness); f.hits = 0; ind.evaluated = true; } catch (Exception e) { Debug.LogError(e.Message); throw new Exception("Error while evaluating: ", e); } }
public void Describe(EvolutionState state, Individual ind, int subpopulation, int threadnum, int log) { // we do the testing set here state.Output.PrintLn("\n\nPerformance of Best Individual on Testing Set:\n", log); var hits = 0; var sum = 0.0; for (var y = 0; y < testingInputs.Length; y++) { currentValue = testingInputs[y]; ((GPIndividual)ind).Trees[0].Child.Eval(state, threadnum, data, Stack, (GPIndividual)ind, this); var err = error(data.x, testingOutputs[y]); // We'll keep the auxillary hits measure for tradition only const double HIT_LEVEL = 0.01; if (err <= HIT_LEVEL) { hits++; } sum += err; } // the fitness better be KozaFitness! var f = (KozaFitness)ind.Fitness.Clone(); // make a copy, we're just printing it out f.SetStandardizedFitness(state, sum); f.Hits = hits; f.PrintFitnessForHumans(state, log); }
public int GetRandomIndividual(int number, int subpopulation, EvolutionState state, int thread) { //var oldinds = state.Population.Subpops[subpopulation].Individuals; var archiveSize = ((SimpleBreeder)state.Breeder).NumElites(state, subpopulation); var archiveStart = state.Population.Subpops[subpopulation].Individuals.Count - archiveSize; return(archiveStart + state.Random[thread].NextInt(archiveSize)); }
public void Randomize(EvolutionState state, int thread) { IMersenneTwister random = state.Random[thread]; for (int i = 0; i < _ca.Length; i++) { _ca[i] = random.NextBoolean() ? 0 : 1; } }
// In one paper, there is a parameter for scaling, ie the fitness // contribution of each Xi can be uniform, or linearly or // exponentially scaled. We don't do that in this version. public void Describe( EvolutionState state, Individual ind, int subpopulation, int threadnum, int log) { state.Output.PrintLn( "\n\nBest Individual: output = " + phenotypeToString(GetSemanticOutput(((GPIndividual)ind).Trees[0])), log); }
protected void GatherExtraSubpopStatistics(EvolutionState state, int subpop, int individual) { var i = (GPIndividual)(state.Population.Subpops[subpop].Individuals[individual]); for (var z = 0; z < i.Trees.Length; z++) { _totalDepthThisGenTree[subpop][z] += i.Trees[z].Child.Depth; _totalDepthSoFarTree[subpop][z] += _totalDepthThisGenTree[subpop][z]; _totalSizeThisGenTree[subpop][z] += i.Trees[z].Child.NumNodes(GPNode.NODESEARCH_ALL); _totalSizeSoFarTree[subpop][z] += _totalSizeThisGenTree[subpop][z]; } }
protected void PrepareStatistics(EvolutionState state) { _totalDepthThisGenTree = new long[state.Population.Subpops.Count][]; _totalSizeThisGenTree = new long[state.Population.Subpops.Count][]; for (var x = 0; x < state.Population.Subpops.Count; x++) { var i = (GPIndividual)(state.Population.Subpops[x].Individuals[0]); _totalDepthThisGenTree[x] = new long[i.Trees.Length]; _totalSizeThisGenTree[x] = new long[i.Trees.Length]; } }
public static void HandleArgs(EvolutionState engine, EvolvingSpaceShooter game) { lock (syncLock) { if (!processed) { // get the list of arguments string[] args = Environment.GetCommandLineArgs(); bool show_help = false; OptionSet parser = new OptionSet() { "Usage: ", "", { "batchmode", "run in batchmode", v => batchmode = v != null }, { "level=", "the number of the {Level} to use.", (int v) => game.levelNumber = v }, { "generations=", "the number of generations to execute.", (int v) => engine.numGenerations = v }, { "probm=", "the mutation probability.", (float v) => engine.mutationProbability = v }, { "probc=", "the crossover probability.", (float v) => engine.crossoverProbability = v }, { "mutType=", "the mutation type", (int v) => engine.mutationType = (MutationType)v }, { "crossType=", "the crossover type", (int v) => engine.crossoverType = (CrossoverType)v }, { "tournSize=", "the tournament size", (int v) => engine.tournamentSize = v }, { "tournK", "probability of tournament selection optimising", (float v) => engine.tournamentK = v }, { "n_cuts=", "number of cuts in the n-crossover", (int v) => engine.N_cutsCrossover = v }, { "elitism=", "number of preserved individuals", (int v) => engine.preservedIndividualsElitism = v }, { "log=", "the logger output filename to use.", v => engine.statsFilename = v }, { "h|help", "show this message and exit", v => show_help = v != null }, }; try { parser.Parse(args); processed = true; } catch (OptionException e) { Console.Write("sokoban: "); Console.WriteLine(e.Message); Console.WriteLine("Try `sokoban --help' for more information."); Application.Quit(); return; } if (show_help) { parser.WriteOptionDescriptions(Console.Out); Application.Quit(); return; } } } }
/// <summary> /// A simple testing fcility. /// </summary> public static void Main(string[] args) { // make a dummy EvolutionState that just has an output for testing var state = new EvolutionState { Output = new Output(true) }; state.Output.AddLog(Log.D_STDOUT, false); state.Output.AddLog(Log.D_STDERR, true); var gp = new GrammarParser(); gp.ParseRules(state, new StreamReader(new FileStream(args[0], FileMode.Open, FileAccess.Read, FileShare.Read)), null); gp.ValidateRules(); Console.WriteLine(gp); }
///** Return the number of simulation have done with current individual. */ //public int numOfObservations() // { // return numOfObservations; // } /** * Record the result of the new simulation. This will update some of the * statistics of the current fitness value. */ public double RecordObservation(EvolutionState state, double result) { Sum += result; SumSquared += result * result; NumOfObservations++; Mean = Sum / NumOfObservations; if (NumOfObservations == 1) { Variance = 0; } else { Variance = (SumSquared - NumOfObservations * Mean * Mean) / (NumOfObservations - 1); } SetFitness(state, Mean, false); return(Mean); }
public void SetToMeanOf(EvolutionState state, Fitness[] fitnesses) { // this is not numerically stable. Perhaps we should have a numerically stable algorithm for sums // we're presuming it's not a very large number of elements, so it's probably not a big deal, // since this function is meant to be used mostly for gathering trials together. double f = 0; long h = 0; for (var i = 0; i < fitnesses.Length; i++) { var fit = (KozaFitness)fitnesses[i]; f += fit._standardizedFitness; h += fit.Hits; } f /= fitnesses.Length; h /= fitnesses.Length; _standardizedFitness = (double)f; Hits = (int)h; }
protected void PrintExtraPopStatisticsBefore(EvolutionState state) { var totalDepthThisGenTreePop = new long[_totalDepthSoFarTree[0].Length]; var totalSizeThisGenTreePop = new long[_totalSizeSoFarTree[0].Length]; // will assume each subpop has the same tree size long totalIndsThisGenPop = 0; //long totalDepthThisGenPop = 0; //long totalDepthSoFarPop = 0; int subpops = state.Population.Subpops.Count; for (var y = 0; y < subpops; y++) { totalIndsThisGenPop += TotalIndsThisGen[y]; for (var z = 0; z < totalSizeThisGenTreePop.Length; z++) { totalSizeThisGenTreePop[z] += _totalSizeThisGenTree[y][z]; } for (var z = 0; z < totalDepthThisGenTreePop.Length; z++) { totalDepthThisGenTreePop[z] += _totalDepthThisGenTree[y][z]; } } if (DoDepth) { state.Output.Print("[ ", StatisticsLog); foreach (var t in totalDepthThisGenTreePop) { state.Output.Print("" + (totalIndsThisGenPop > 0 ? ((double)t) / totalIndsThisGenPop : 0) + " ", StatisticsLog); } state.Output.Print("] ", StatisticsLog); } if (DoSize) { state.Output.Print("[ ", StatisticsLog); foreach (var t in totalSizeThisGenTreePop) { state.Output.Print("" + (totalIndsThisGenPop > 0 ? ((double)t) / totalIndsThisGenPop : 0) + " ", StatisticsLog); } state.Output.Print("] ", StatisticsLog); } }
protected void PrintExtraSubpopStatisticsBefore(EvolutionState state, int subpop) { if (DoDepth) { state.Output.Print("[ ", StatisticsLog); for (var z = 0; z < _totalDepthThisGenTree[subpop].Length; z++) { state.Output.Print("" + (TotalIndsThisGen[subpop] > 0 ? ((double)_totalDepthThisGenTree[subpop][z]) / TotalIndsThisGen[subpop] : 0) + " ", StatisticsLog); } state.Output.Print("] ", StatisticsLog); } if (DoSize) { state.Output.Print("[ ", StatisticsLog); for (var z = 0; z < _totalSizeThisGenTree[subpop].Length; z++) { state.Output.Print("" + (TotalIndsThisGen[subpop] > 0 ? ((double)_totalSizeThisGenTree[subpop][z]) / TotalIndsThisGen[subpop] : 0) + " ", StatisticsLog); } state.Output.Print("] ", StatisticsLog); } }
public void Describe(EvolutionState state, Individual ind, int subpopulation, int threadnum, int log) { // the default implementation works just like the default implementation of modifyParameters(...) state.Output.PrintLn("\nParameters:", log); if (!(ind is DoubleVectorIndividual)) { state.Output.Fatal("Meta-individual is not a DoubleVectorIndividual."); } var individual = (DoubleVectorIndividual)ind; var species = (FloatVectorSpecies)individual.Species; double[] genome = individual.genome; IParameter pb = ParamBase.Push(P_PARAM); for (int i = 0; i < genome.Length; i++) { IParameter p = pb.Push("" + i); String param = state.Parameters.GetString(p, null); if (param == null) { state.Output.Fatal("Meta parameter number " + i + " missing.", p); } // print it state.Output.PrintLn("" + param + " = " + Map(state, genome, species, i), log); } // We need to do a lock here, which is rare in ECJ. This is because the // bestUnderlyingIndividual array is shared among MetaProblem instances lock (Lock) { if (BestUnderlyingIndividual[subpopulation] != null) { state.Output.PrintLn("\nUnderlying Individual:", log); BestUnderlyingIndividual[subpopulation].PrintIndividualForHumans(state, log); } } }
public void Setup(EvolutionState state, Parameter paramBase) { base.Setup(state, paramBase); K = state.Parameters.GetInt(paramBase.Push(P_K), null, 0); if (K < 0) { state.Output.Fatal("k must be > 0", paramBase.Push(P_K)); } P = state.Parameters.GetInt(paramBase.Push(P_P), null, 0); if (P < 0) { state.Output.Fatal("p must be > 0", paramBase.Push(P_P)); } Rc = state.Parameters.GetInt(paramBase.Push(P_RC), null, 0); if (Rc < 0) { state.Output.Fatal("rc must be > 0", paramBase.Push(P_RC)); } }
// default form does nothing public void Setup(EvolutionState state, IParameter paramBase) { base.Setup(state, paramBase); this.ParamBase = paramBase; var file = state.Parameters.GetFile(paramBase.Push(P_FILE), null); try { p_database = new ParameterDatabase(file, new[] { "-file", file.FullName }); // command line has just the parameter database } catch (IOException e) { state.Output.Fatal("Exception loading meta-parameter-database:\n" + e, paramBase.Push(P_FILE)); } Runs = state.Parameters.GetInt(paramBase.Push(P_RUNS), null, 1); if (Runs < 1) { state.Output.Fatal("Number of runs must be >= 1", paramBase.Push(P_RUNS)); } ReevaluateIndividuals = state.Parameters.GetBoolean(paramBase.Push(P_REEVALUATE_INDIVIDUALS), null, true); if (state.Parameters.ParameterExists(paramBase.Push(P_MUZZLE), null)) { state.Output.Warning("" + paramBase.Push(P_MUZZLE) + " no longer exists. Use 'silent' in the lower-level EA parameters instead."); } IParameter pop = new Parameter(Initializer.P_POP); int subpopsLength = state.Parameters.GetInt(pop.Push(Population.P_SIZE), null, 1); BestUnderlyingIndividual = new Individual[subpopsLength]; SetRandom = state.Parameters.GetBoolean(paramBase.Push(P_SET_RANDOM), null, false); LoadDomain(state, paramBase); }
//Awake is always called before any Start functions void Awake() { if (instance == null) { instance = this; } else if (instance != this) { Destroy(gameObject); } DontDestroyOnLoad(gameObject); scoreText.text = ""; if (restartText) { restartText.text = "1/1"; } if (gameOverText) { gameOverText.text = ""; } evolEngine = this.GetComponentInParent <EvolutionState> (); BatchmodeConfig.HandleArgs(evolEngine, this); lvl = new Level(); lvl.load(levelNumber); evolEngine.populationSize = 50; evolEngine.individualSize = lvl.calcNumberOfMoves(); evolEngine.InitPopulation(); init(); }
protected override void ThreadFunction() { //TestProblem p = new TestProblem (); //Type t = typeof(TestProblem); //Debug.Log (t.AssemblyQualifiedName); try { Debug.Log("ECJ job started"); FileInputStream input = new FileInputStream(new File("erc.params")); state = Evolve.initialize(new ParameterDatabase( input), 0); state.setup(state, null); // Make sure problem has the model in so when it gets cloned it can be used. ((UnityProblem)state.evaluator.p_problem).model = unityModel; state.run(EvolutionState.C_STARTED_FRESH); Debug.Log("ECJ job finished. " + state); } catch (Exception e) { Debug.Log ("ERROR in ecjJob: " + e.ToString ()); throw e; } }
public int GetRandomIndividual(int number, int subpop, EvolutionState state, int thread) { var sp = state.Population.Subpops[subpop]; if (!(sp is ISpace)) { state.Output.Fatal("Subpopulation " + subpop + " is not a spatially-embedded subpopulation.\n"); } var space = (ISpace)(state.Population.Subpops[subpop]); var index = space.GetIndex(thread); if (number == 0 && IndCompetes) // Should we just return the individual? { return(index); } // Should we pick randomly in the space up to the given distance? if (type == TYPE_UNIFORM) { return(space.GetIndexRandomNeighbor(state, thread, NeighborhoodSize)); } // if (type == TYPE_RANDOM_WALK) // Should we do a random walk? var oldIndex = index; for (var x = 0; x < NeighborhoodSize; x++) { space.SetIndex(thread, space.GetIndexRandomNeighbor(state, thread, 1)); } var val = space.GetIndex(thread); space.SetIndex(thread, oldIndex); // just in case we weren't supposed to mess around with that return(val); }
public static void HandleArgs(EvolutionState engine, EvolvingSpaceShooter game) { lock (syncLock) { if (!processed) { // get the list of arguments string[] args = Environment.GetCommandLineArgs(); bool show_help = false; OptionSet parser = new OptionSet() { "Usage: ", "", { "batchmode", "run in batchmode", v => batchmode = v != null }, { "random=", "random generator number", (int v) => engine.random = v }, { "level=", "the number of the {Level} to use.", (int v) => game.levelNumber = v }, { "generations=", "the number of generations to execute.", (int v) => engine.numGenerations = v }, { "probm=", "the mutation probability.", (float v) => engine.mutationProbability = v }, { "probc=", "the crossover probability.", (float v) => engine.crossoverProbability = v }, { "log=", "the logger output filename to use.", v => engine.statsFilename = v }, { "tsize=", "the tournament size to use.", (int v) => engine.tournamentSize = v }, { "elitism=", "the elitism number to use.", (int v) => engine.elitismAffected = v }, { "seed=", "the seed to use.", (int v) => engine.random = v }, { "cuts=", "Number of cuts for selection.", (int v) => engine.ncortes = v }, { "tournament=", "true=Tournament || false=Random", (bool v) => engine.flagSelection = v }, { "h|help", "show this message and exit", v => show_help = v != null }, }; try{ parser.Parse(args); processed = true; Console.WriteLine(engine.statsFilename); Debug.Log(engine.statsFilename); } catch (OptionException e) { Console.Write("sokoban: "); Console.WriteLine(e.Message); Console.WriteLine("Try `sokoban --help' for more information."); Application.Quit(); return; } if (show_help) { parser.WriteOptionDescriptions(Console.Out); Application.Quit(); return; } } } }
public void CloseContacts(EvolutionState state, int result) { Problem.CloseContacts(state, result); }
public void ReinitializeContacts(EvolutionState state) { Problem.ReinitializeContacts(state); }
public bool BetterThan(Individual first, Individual second, int subpop, EvolutionState state, int thread) { return(first.Fitness.BetterThan(second.Fitness) || (first.Fitness.EquivalentTo(second.Fitness) && first.Size < second.Size)); }
public void Evaluate(IEvolutionState state, Individual ind, int subpopulation, int threadnum) { if (ind.Evaluated && !ReevaluateIndividuals) { return; } var fits = new ArrayList(); Individual bestOfRuns = null; for (int run = 0; run < Runs; run++) { // too annoying //state.Output.message("Thread " + threadnum + " Run " + run); try { // The following uses BinaryFormatter to create a separate copy of the ParameterDatabase. CurrentDatabase = (ParameterDatabase)p_database.DeepClone(); } catch (Exception e) { state.Output.Fatal("Exception copying database.\n" + e); } ModifyParameters(state, CurrentDatabase, run, ind); var output = new Output(false); // do not store messages, just print them output.AddLog(Log.D_STDOUT, false); output.AddLog(Log.D_STDERR, true); output.ThrowsErrors = true; // don't do System.exit(1); EvolutionState evaluatedState = null; try { evaluatedState = Evolve.Initialize(CurrentDatabase, 0, output); // should we override the seeds? if (SetRandom) { // we use the random number generator to seed the generators // of the underlying process. This isn't optimal but it should // probably do okay. To be extra careful we prime the generators. for (int i = 0; i < evaluatedState.Random.Length; i++) { int seed = state.Random[threadnum].NextInt(); evaluatedState.Random[i] = Evolve.PrimeGenerator(new MersenneTwisterFast(seed)); } } evaluatedState.Run(EvolutionState.C_STARTED_FRESH); // Issue a warning if there's more than one subpopulation if (evaluatedState.Population.Subpops.Count > 1) { state.Output.WarnOnce( "MetaProblem used, but underlying evolution state has more than one subpopulation: only the results from subpopulation 0 will be considered."); } // Identify the best fitness of the underlying EvolutionState run, // we can only easily detect if the underlying EvolutionState has a proper Statistics // object we can use AFTER we've run it because the Statistics object is set up during // run(). We could modify this but I'm too lazy to do so, so... Individual[] inds = null; // will get set, don't worry if (evaluatedState.Statistics != null && (evaluatedState.Statistics is SimpleStatistics || evaluatedState.Statistics is SimpleShortStatistics)) { inds = null; // obviously we need an interface here rather than this nonsense if (evaluatedState.Statistics is SimpleStatistics) { inds = ((SimpleStatistics)evaluatedState.Statistics).GetBestSoFar(); } else { inds = ((SimpleShortStatistics)evaluatedState.Statistics).GetBestSoFar(); } if (inds == null) { state.Output.Fatal( "Underlying evolution state has a Statistics object which provides a null best-so-far array. Can't extract fitness."); } fits.Add((Fitness)(inds[0].Fitness)); //System.err.println("" + inds[0] + " " + inds[0].fitness); } else if (evaluatedState.Statistics == null) { state.Output.Fatal( "Underlying evolution state has a null Statistics object. Can't extract fitness."); } else { state.Output.Fatal( "Underlying evolution state has a Statistics object which doesn't implement ProvidesBestSoFar. Can't extract fitness."); } // Now we need to suck out the best individual discovered so far. If the underlying // evoluationary system itself has a MetaProblem, we need to do this recursively. // We presume that the MetaProblem exists in subpopulation 0. if (evaluatedState.Evaluator.p_problem is MetaProblem) { var mp = (MetaProblem)evaluatedState.Evaluator.p_problem; lock (mp.Lock) { Individual bestind = mp.BestUnderlyingIndividual[0]; if (bestOfRuns == null || bestind.Fitness.BetterThan(bestOfRuns.Fitness)) { bestOfRuns = (Individual)bestind.Clone(); } } } // otherwise we grab the best individual found in the underlying evolutionary run, // gathered from the inds array we used earlier. else { // gather the best individual found during the runs if (bestOfRuns == null || inds[0].Fitness.BetterThan(bestOfRuns.Fitness)) { bestOfRuns = (Individual)(inds[0].Clone()); } } // now clean up Evolve.Cleanup(evaluatedState); } catch (OutputExitException e) { // looks like an error occurred. state.Output.Warning( "Error occurred in underlying evolutionary run. NOTE: multiple threads may still be running:\n" + e.Message); } catch (OutOfMemoryException e) { // Let's try fixing things evaluatedState = null; //System.gc(); GC.Collect(); GC.WaitForPendingFinalizers(); GC.Collect(); GC.WaitForPendingFinalizers(); state.Output.Warning( "An Out of Memory error occurred in underlying evolutionary run. Attempting to recover and reset. NOTE: multiple threads may still be running:\n" + e.Message); } } // Load the fitness into our individual var fits2 = new IFitness[fits.Count]; for (var i = 0; i < fits2.Length; i++) { fits2[i] = (IFitness)fits[i]; } Combine(state, fits2, ind.Fitness); ind.Evaluated = true; // store the best individual found during the runs if it's superior. // We need to do a lock here, which is rare in ECJ. This is because the // bestUnderlyingIndividual array is shared among MetaProblem instances lock (Lock) { if (bestOfRuns != null && (BestUnderlyingIndividual[subpopulation] == null || bestOfRuns.Fitness.BetterThan(BestUnderlyingIndividual[subpopulation].Fitness))) { BestUnderlyingIndividual[subpopulation] = bestOfRuns; // no clone necessary } } }
protected void LoadDomain(EvolutionState state, IParameter paraBase) { // Load domain and check for parameters int numParams = state.Parameters.GetInt(ParamBase.Push(P_NUM_PARAMS), null, 1); if (numParams < 1) { state.Output.Fatal("Number of parameters must be >= 1", ParamBase.Push(P_NUM_PARAMS)); } Domain = new Object[numParams]; IParameter pb = ParamBase.Push(P_PARAM); for (int i = 0; i < numParams; i++) // just keep rising { // check parameter IParameter p = pb.Push("" + i); if (!state.Parameters.ParameterExists(p, null)) // guess that's it { break; } // load parameter domain else if (state.Parameters.ParameterExists(p.Push(P_TYPE), null)) { String type = state.Parameters.GetString(p.Push(P_TYPE), null); if (type.Equals(V_INTEGER, StringComparison.InvariantCultureIgnoreCase)) { Domain[i] = new int[0]; } else if (type.Equals(V_FLOAT, StringComparison.InvariantCultureIgnoreCase)) { Domain[i] = new double[0]; } else if (type.Equals(V_BOOLEAN, StringComparison.InvariantCultureIgnoreCase)) { Domain[i] = new bool[0]; } else { state.Output.Fatal("Meta parameter number " + i + " has a malformed type declaration.", p.Push(P_TYPE), null); } // double-check if (state.Parameters.ParameterExists(p.Push(P_NUM_VALS), null)) { state.Output.Fatal( "Meta parameter number " + i + " has both a type declaration and a num-vals declaration.", p.Push(P_TYPE), p.Push(P_NUM_VALS)); } } else if (state.Parameters.ParameterExists(p.Push(P_NUM_VALS), null)) { int len = state.Parameters.GetInt(p.Push(P_NUM_VALS), null, 1); if (len > 0) { var tags = new String[len]; for (int j = 0; j < len; j++) { tags[j] = state.Parameters.GetString(p.Push(P_VAL).Push("" + j), null); if (tags[j] == null) { state.Output.Fatal("Meta parameter number " + i + " is missing value number " + j + ".", p.Push(P_VAL).Push("" + j)); } } Domain[i] = tags; } else { state.Output.Fatal("Meta parameter number " + i + " has a malformed domain.", p.Push(P_NUM_VALS)); } } else { state.Output.Fatal( "Meta parameter number " + i + " has no type declaration or num-vals declaration.", p.Push(P_TYPE), p.Push(P_NUM_VALS)); } } }