From 400d4e361530b9427761540fc44e1f965e86a3c4 Mon Sep 17 00:00:00 2001 From: ethiril Date: Wed, 7 Oct 2026 21:02:29 +0100 Subject: [PATCH 1/4] New UI --- README.md | 54 +++--- SNP_Evolution/Application/ComposeService.cs | 24 +-- SNP_Evolution/Application/Settings.cs | 11 ++ SNP_Evolution/Cli/BenchmarkMenu.cs | 89 ---------- SNP_Evolution/Cli/Commands/AdviseCommand.cs | 13 +- SNP_Evolution/Cli/Commands/BenchmarkArgs.cs | 21 ++- SNP_Evolution/Cli/Commands/Command.cs | 3 + SNP_Evolution/Cli/Commands/CommandArgs.cs | 15 +- SNP_Evolution/Cli/Commands/CommandRegistry.cs | 3 + SNP_Evolution/Cli/Commands/ComposeCommand.cs | 9 +- SNP_Evolution/Cli/Commands/EvolveCommand.cs | 48 ++++- .../Cli/Commands/EvolvePartsCommand.cs | 9 +- SNP_Evolution/Cli/Commands/Option.cs | 12 ++ SNP_Evolution/Cli/Commands/RunCommand.cs | 66 +++++++ SNP_Evolution/Cli/Commands/TargetArgs.cs | 56 +++++- SNP_Evolution/Cli/Commands/ValueKind.cs | 34 +++- SNP_Evolution/Cli/Commands/VerifyCommand.cs | 2 +- SNP_Evolution/Cli/CompileMenu.cs | 72 -------- SNP_Evolution/Cli/EvolveMenu.cs | 150 ---------------- SNP_Evolution/Cli/MainMenu.cs | 53 ------ SNP_Evolution/Cli/Menus/CommandForm.cs | 71 ++++++++ SNP_Evolution/Cli/Menus/CommandScreen.cs | 165 ++++++++++++++++++ SNP_Evolution/Cli/Menus/FollowUpItems.cs | 103 +++++++++++ SNP_Evolution/Cli/Menus/MainMenu.cs | 74 ++++++++ SNP_Evolution/Cli/Menus/MenuItem.cs | 106 +++++++++++ SNP_Evolution/Cli/{ => Menus}/MenuPrompts.cs | 6 - SNP_Evolution/Cli/{ => Menus}/RedoMenu.cs | 10 +- SNP_Evolution/Cli/{ => Menus}/SavedRuns.cs | 0 SNP_Evolution/Cli/Menus/SettingsMenu.cs | 91 ++++++++++ SNP_Evolution/Cli/{ => Menus}/SettingsPage.cs | 3 - SNP_Evolution/Cli/{ => Menus}/TargetMenu.cs | 29 +-- SNP_Evolution/Cli/PartsMenu.cs | 43 ----- SNP_Evolution/Cli/Program.cs | 2 +- SNP_Evolution/Cli/RunMenu.cs | 76 -------- SNP_Evolution/Cli/SearchMenu.cs | 63 ------- SNP_Evolution/Cli/SettingOption.cs | 106 +++++++++++ SNP_Evolution/Cli/SettingOptions.cs | 163 ++++++++--------- SNP_Evolution/Cli/SettingsMenu.cs | 87 --------- .../Cli/CommandArgsTests.cs | 8 +- .../Cli/Menus/CommandFormTests.cs | 104 +++++++++++ .../Cli/Menus/MainMenuTests.cs | 53 ++++++ .../Cli/RunCommandTests.cs | 31 ++++ 42 files changed, 1294 insertions(+), 844 deletions(-) delete mode 100644 SNP_Evolution/Cli/BenchmarkMenu.cs create mode 100644 SNP_Evolution/Cli/Commands/RunCommand.cs delete mode 100644 SNP_Evolution/Cli/CompileMenu.cs delete mode 100644 SNP_Evolution/Cli/EvolveMenu.cs delete mode 100644 SNP_Evolution/Cli/MainMenu.cs create mode 100644 SNP_Evolution/Cli/Menus/CommandForm.cs create mode 100644 SNP_Evolution/Cli/Menus/CommandScreen.cs create mode 100644 SNP_Evolution/Cli/Menus/FollowUpItems.cs create mode 100644 SNP_Evolution/Cli/Menus/MainMenu.cs create mode 100644 SNP_Evolution/Cli/Menus/MenuItem.cs rename SNP_Evolution/Cli/{ => Menus}/MenuPrompts.cs (80%) rename SNP_Evolution/Cli/{ => Menus}/RedoMenu.cs (77%) rename SNP_Evolution/Cli/{ => Menus}/SavedRuns.cs (100%) create mode 100644 SNP_Evolution/Cli/Menus/SettingsMenu.cs rename SNP_Evolution/Cli/{ => Menus}/SettingsPage.cs (80%) rename SNP_Evolution/Cli/{ => Menus}/TargetMenu.cs (72%) delete mode 100644 SNP_Evolution/Cli/PartsMenu.cs delete mode 100644 SNP_Evolution/Cli/RunMenu.cs delete mode 100644 SNP_Evolution/Cli/SearchMenu.cs create mode 100644 SNP_Evolution/Cli/SettingOption.cs delete mode 100644 SNP_Evolution/Cli/SettingsMenu.cs create mode 100644 SNP_Evolution/SNP_Evolution.Tests/Cli/Menus/CommandFormTests.cs create mode 100644 SNP_Evolution/SNP_Evolution.Tests/Cli/Menus/MainMenuTests.cs create mode 100644 SNP_Evolution/SNP_Evolution.Tests/Cli/RunCommandTests.cs diff --git a/README.md b/README.md index fc6ec3f..9a227b6 100644 --- a/README.md +++ b/README.md @@ -36,56 +36,66 @@ dotnet tool install --global --add-source ./nupkg SNP_Evolution To remove the command, run `dotnet tool uninstall --global SNP_Evolution`. Evolved networks are saved under the folder you run the command from. -## Using the GUI +## Using the menu -Move with the arrow keys and press Enter to select, or press an option's number. ESC, Backspace or the left arrow goes back a level. Every submenu stays open until you leave it. The top of each screen shows the current task, search settings and simulation settings. +Run the program with no command (`dotnet run --project Cli`, `snp-evolution`, or by double-clicking the built executable on Windows) to open the menu. Move with the arrow keys and press Enter to select, or press an option's number. ESC, Backspace or the left arrow goes back a level. Every page stays open until you leave it. The top of each screen shows the current task, search settings and simulation settings. + +The menu and the [commands](#commands) are one program and share their code: every menu entry that runs something runs one of the commands below, the same way it runs from the command line. Choosing an entry opens the command's form: + +- **Run** parses the form as a command line and runs the command. The form shows that line, `$ snp-evolution ...`, so the same run can be scripted. It lists the form's options and every setting the command takes whose menu value is not the default. +- The command's own options follow, such as `--target`, `--seed` or `--part`. Pick one to type its value, or to choose from its values. Leave a value empty to take the option off. Some entries fill options from the settings, such as the selected target or task. +- Then a page for each group of settings the command takes (Evolution, Search, Simulation, Benchmark). Settings changed on a form apply to that command's runs only. Settings changed in **Settings** apply to every run. + +Commands start from the menu's settings where the command line starts from the defaults. The pages: - **Evolve a system** - - *Match a target*: type the output you want and a maximum number of generations (1000 if left empty), then evolve a network for it from scratch. A target is one of three kinds: + - *Match the target* or *For the task*: `evolve` for the task chosen in Settings > Evolution, either a target or a suite task. A target is one of three kinds: - **Set**: the numbers a run can produce, in any order, e.g. `2,4,6,8`. Each run gives one number: the steps between the output neuron's first two spikes. - **Sequence**: the gaps between successive output spikes, in order and with repeats, e.g. `1,1,2,3,5,8,13`. - **Binary word**: the output spike train step by step, 1 for a spike, e.g. `001001001001`. - - *For the selected task*: evolve from scratch for the task chosen in Settings > Evolution: the target or a suite task. - - *Starting from the natural numbers or even numbers network*: evolve a hand-designed network towards the target. To evolve only its rules, as in the original paper, first pick a "rule expressions only" algorithm in Settings > Evolution. - - *Suggest settings*: show what the advisor recommends for the selected task, apply it if you agree, and optionally run a quick pilot that picks the algorithm. *Match a target* does this before every run. - - *Compile a target, then shrink it*: type a sequence or set target, then build a network that is correct by construction and evolve it smaller (see [Compile, then shrink](#compile-then-shrink)). For a set you can give a register program file, or leave it empty to evolve one. Leave the shrink generations empty for 300, or enter 0 to only compile. - - *Evolve the first library parts*: run `evolve-parts` (see [Evolving library parts](#evolving-library-parts)) with a seed you give, 1 if left empty. - - *Redo a saved run*: after a run you can save it under a name. Saved runs can be run again as they were, have their settings loaded to change first, or be deleted. -- **Run a network**: run the natural numbers or even numbers network, or import one from a JSON file. -- **Benchmark**: run every algorithm on the task suite, or find the best algorithm for the selected task. + - *Starting from the natural numbers or even numbers network*: `evolve --start natural` or `--start even`, which evolves a hand-designed network towards the target. To evolve only its rules, as in the original paper, pick a "rule expressions only" algorithm. + - *Suggest settings*: `advise` for the selected task, then an offer to apply the suggestions to the settings. To apply them and evolve in one go, set `--advise on` on the evolve form; `--pilot on` picks the algorithm with a quick pilot. + - *Compile a target, then shrink it*: `compile` (see [Compile, then shrink](#compile-then-shrink)). + - *Compare setups on a target*: `reach`. + - *Redo a saved run*: after an evolve run you can save it under a name. Saved runs can be run again as they were, have their settings loaded to change first, or be deleted. +- **Library parts**: `evolve-parts` (see [Evolving library parts](#evolving-library-parts)), `compose` for a suite task, and `verify`. +- **Run a network**: `run` on the natural numbers or even numbers network, or on a saved network file. +- **Export**: `export-verilog`, `export-nir` and `export-uppaal` (see [Exporting to hardware](#exporting-to-hardware)). +- **Benchmark**: `benchmark`, which also saves the table to a run folder; `select`, which offers to use the winner from then on; and the `tasks` and `algorithms` lists. - **Settings**: grouped into: - **Evolution**: task, target, fitness function, algorithm, population, mutation rate, generations, maximum neurons and experimental rules. - - **Search**: iterative evolution and its stages, stagnation recovery, genome limits (delay, spikes produced, initial spikes, duplicate neurons), lexicase parents, modules (build from modules, freeze, triggered, incubation, and module files that start the library), and composition search (part library folder, part copies, glue, proposing parts when stalled, and starting from the hand-built parts). - - **Simulation**: engine, steps, runs per network, rule form and output timing. - - **Benchmarks**. + - **Search**: iterative evolution and its stages, stagnation recovery, genome limits (delay, spikes produced, initial spikes, duplicate neurons), lexicase parents, modules (build from modules, freeze, triggered, incubation, and module files that start the library), the evaluations per library part, and composition search (part library folder, part copies, glue, proposing parts when stalled, and starting from the hand-built parts). + - **Simulation**: engine, steps, runs per network, rule form, output timing and the hardware profile. + - **Benchmark**: seeds, evaluations per run and population. - *Reset to defaults* restores the default configuration. + *Reset to defaults* restores the default configuration. Every setting is also an option of the commands that use it, so a run set up in the menu can be repeated from a script. Sequence and binary targets have some limits: - Only a network that gives the output on every sampled run solves the target. Spike trains are always sampled, even on the exhaustive engine. - Runs are lengthened automatically to fit the whole target. - Small SN P systems produce spike trains that eventually repeat. An evolved network matches the numbers you typed but need not continue the pattern after them. For example, one evolved network for `1,1,2,3,5,8,13` continued with `6,8`. -- The default algorithm, MAP-Elites, evolves structure as well as rules. If you pick a rule-only algorithm, the menu offers to switch back before evolving from scratch, since a random network's structure would never change. Long or irregular targets need a larger population than the default. +- The default algorithm, MAP-Elites, evolves structure as well as rules. If you pick a rule-only algorithm for a run from scratch, `evolve` warns that a random network's structure never changes. Long or irregular targets need a larger population than the default. ## Commands -Every menu run also runs without the menu, from scripts. Each command declares its options, and an unknown option, a missing value or a value the option cannot take is refused with a message naming it. Commands exit with 0 on success, 1 for a bad command line or input they cannot use, 2 when a run solved nothing or a proof found a counterexample, and 3 when an outside tool's check differs from our engine. Options in brackets are optional; `NAME` matches any task, search or contract whose name contains it, ignoring case, unless one name is exactly `NAME`. +Every menu run is one of these commands, so it also runs without the menu, from scripts. Each command declares its options, and an unknown option, a missing value or a value the option cannot take is refused with a message naming it. Commands exit with 0 on success, 1 for a bad command line or input they cannot use, 2 when a run solved nothing or a proof found a counterexample, and 3 when an outside tool's check differs from our engine. Options in brackets are optional; `NAME` matches any task, search or contract whose name contains it, ignoring case, unless one name is exactly `NAME`. | Command | What it does | Options | |---|---|---| -| `evolve` | Evolves a network from scratch for a target and saves the run; exits with 2 when no network solved it. | `--target VALUES` `[--kind set\|sequence\|binary]` `[--seed N]` `[--advise on\|off]` `[--pilot on\|off]` `[--generations N]` `[--population N]` `[--neurons N]` `[--patience N]` `[--iterative on\|off]` `[--lexicase on\|off]` `[--profile hardware\|none]` `[--modules on\|off]` `[--freeze on\|off]` `[--triggered on\|off]` `[--incubate N]` `[--evaluations N]` `[--library DIR]` `[--hand-built on\|off\|leaves]` `[--propose on\|off]` `[--proposal-budget N]` `[--max-parts N]` `[--glue N]` `[--glue-weight X]` `[--module-files a.json,b.json]` `[--algorithm NAME]` | -| `advise` | Prints the settings the advisor suggests for a target, without evolving. | `--target VALUES` `[--kind set\|sequence\|binary]` `[--generations N]` `[--population N]` `[--neurons N]` `[--patience N]` `[--iterative on\|off]` `[--lexicase on\|off]` `[--profile hardware\|none]` `[--modules on\|off]` `[--freeze on\|off]` `[--triggered on\|off]` `[--incubate N]` `[--evaluations N]` `[--library DIR]` `[--hand-built on\|off\|leaves]` `[--propose on\|off]` `[--proposal-budget N]` `[--max-parts N]` `[--glue N]` `[--glue-weight X]` `[--module-files a.json,b.json]` `[--algorithm NAME]` | +| `evolve` | Evolves a network for a target or a suite task and saves the run; exits with 2 when no network solved it. | `[--target VALUES]` `[--kind set\|sequence\|binary]` `[--task NAME]` `[--start scratch\|natural\|even]` `[--seed N]` `[--advise on\|off]` `[--pilot on\|off]` `[--generations N]` `[--population N]` `[--neurons N]` `[--mutation-rate X]` `[--experimental on\|off]` `[--fitness NAME]` `[--patience N]` `[--recovery on\|off]` `[--iterative on\|off]` `[--first-stage N]` `[--stage-step N]` `[--max-delay N]` `[--max-produce N]` `[--initial-spikes N]` `[--duplicates on\|off]` `[--lexicase on\|off]` `[--profile hardware\|none]` `[--rule-form legacy\|standard\|mixed]` `[--modules on\|off]` `[--freeze on\|off]` `[--triggered on\|off]` `[--incubate N]` `[--evaluations N]` `[--library DIR]` `[--hand-built on\|off\|leaves]` `[--propose on\|off]` `[--proposal-budget N]` `[--max-parts N]` `[--glue N]` `[--glue-weight X]` `[--module-files a.json,b.json]` `[--algorithm NAME]` `[--simulator NAME]` `[--steps N]` `[--repetitions N]` `[--timing legacy\|interval]` | +| `advise` | Prints the settings the advisor suggests for a target or a suite task, without evolving. | `[--target VALUES]` `[--kind set\|sequence\|binary]` `[--task NAME]` `[--generations N]` `[--population N]` `[--neurons N]` `[--mutation-rate X]` `[--experimental on\|off]` `[--fitness NAME]` `[--patience N]` `[--recovery on\|off]` `[--iterative on\|off]` `[--first-stage N]` `[--stage-step N]` `[--max-delay N]` `[--max-produce N]` `[--initial-spikes N]` `[--duplicates on\|off]` `[--lexicase on\|off]` `[--profile hardware\|none]` `[--rule-form legacy\|standard\|mixed]` `[--modules on\|off]` `[--freeze on\|off]` `[--triggered on\|off]` `[--incubate N]` `[--evaluations N]` `[--library DIR]` `[--hand-built on\|off\|leaves]` `[--propose on\|off]` `[--proposal-budget N]` `[--max-parts N]` `[--glue N]` `[--glue-weight X]` `[--module-files a.json,b.json]` `[--algorithm NAME]` `[--simulator NAME]` `[--steps N]` `[--repetitions N]` `[--timing legacy\|interval]` | | `compile` | Compiles a sequence target's recurrence or a set target's register program into a network that is correct by construction, then shrinks it. | `--target VALUES` `[--kind set\|sequence\|binary]` `[--program FILE]` `[--generations N]` `[--lexicase on\|off]` `[--shrink N]` `[--seed N]` `[--population N]` | -| `reach` | Runs each setup on seeds 1 to N with the same budget and compares how far into the target they get. | `--target VALUES` `--evaluations N` `[--kind set\|sequence\|binary]` `[--setups flat,modules,composition]` `[--seeds N]` `[--charge-parts on\|off]` `[--generations N]` `[--population N]` `[--neurons N]` `[--patience N]` `[--iterative on\|off]` `[--lexicase on\|off]` `[--profile hardware\|none]` `[--modules on\|off]` `[--freeze on\|off]` `[--triggered on\|off]` `[--incubate N]` `[--library DIR]` `[--hand-built on\|off\|leaves]` `[--propose on\|off]` `[--proposal-budget N]` `[--max-parts N]` `[--glue N]` `[--glue-weight X]` `[--module-files a.json,b.json]` `[--algorithm NAME]` | +| `reach` | Runs each setup on seeds 1 to N with the same budget and compares how far into the target they get. | `--target VALUES` `--evaluations N` `[--kind set\|sequence\|binary]` `[--setups flat,modules,composition]` `[--seeds N]` `[--charge-parts on\|off]` `[--generations N]` `[--population N]` `[--neurons N]` `[--mutation-rate X]` `[--experimental on\|off]` `[--fitness NAME]` `[--patience N]` `[--recovery on\|off]` `[--iterative on\|off]` `[--first-stage N]` `[--stage-step N]` `[--max-delay N]` `[--max-produce N]` `[--initial-spikes N]` `[--duplicates on\|off]` `[--lexicase on\|off]` `[--profile hardware\|none]` `[--rule-form legacy\|standard\|mixed]` `[--modules on\|off]` `[--freeze on\|off]` `[--triggered on\|off]` `[--incubate N]` `[--library DIR]` `[--hand-built on\|off\|leaves]` `[--propose on\|off]` `[--proposal-budget N]` `[--max-parts N]` `[--glue N]` `[--glue-weight X]` `[--module-files a.json,b.json]` `[--algorithm NAME]` `[--simulator NAME]` `[--steps N]` `[--repetitions N]` `[--timing legacy\|interval]` | | `evolve-parts` | Evolves, verifies, shrinks and saves a part for each first-part contract the library has no part for, and reports robustness to jitter. | `[--seed N]` `[--budget N]` `[--only "NAME,NAME"]` `[--library DIR]` `[--engine exact\|sampled]` `[--configurations N]` `[--redo on\|off]` `[--profile hardware\|none]` `[--robust J]` | -| `compose` | Composition search for one suite task; a solved contract is promoted to a part and the library saved. | `--task NAME` `[--seed N]` `[--generations N]` `[--population N]` `[--neurons N]` `[--patience N]` `[--iterative on\|off]` `[--lexicase on\|off]` `[--profile hardware\|none]` `[--modules on\|off]` `[--freeze on\|off]` `[--triggered on\|off]` `[--incubate N]` `[--evaluations N]` `[--library DIR]` `[--hand-built on\|off\|leaves]` `[--propose on\|off]` `[--proposal-budget N]` `[--max-parts N]` `[--glue N]` `[--glue-weight X]` `[--module-files a.json,b.json]` `[--algorithm NAME]` | +| `compose` | Composition search for one suite task; a solved contract is promoted to a part and the library saved. | `--task NAME` `[--seed N]` `[--generations N]` `[--population N]` `[--neurons N]` `[--mutation-rate X]` `[--experimental on\|off]` `[--fitness NAME]` `[--patience N]` `[--recovery on\|off]` `[--iterative on\|off]` `[--first-stage N]` `[--stage-step N]` `[--max-delay N]` `[--max-produce N]` `[--initial-spikes N]` `[--duplicates on\|off]` `[--lexicase on\|off]` `[--profile hardware\|none]` `[--rule-form legacy\|standard\|mixed]` `[--modules on\|off]` `[--freeze on\|off]` `[--triggered on\|off]` `[--incubate N]` `[--evaluations N]` `[--library DIR]` `[--hand-built on\|off\|leaves]` `[--propose on\|off]` `[--proposal-budget N]` `[--max-parts N]` `[--glue N]` `[--glue-weight X]` `[--module-files a.json,b.json]` `[--algorithm NAME]` `[--simulator NAME]` `[--steps N]` `[--repetitions N]` `[--timing legacy\|interval]` | | `verify` | Proves each part's contract for every input up to a bound, raised until the time per part runs out, and records it in the part's file. | `[--part FILE]` `[--library DIR]` `[--only "NAME,NAME"]` `[--seconds N]` `[--bound N]` | | `export-verilog` | Writes a deterministic network as Verilog with a testbench, and co-simulates it under iverilog when installed. | `[--part FILE]` `[--network FILE]` `[--steps N]` `[--out DIR]` `[--check on\|off]` | | `export-nir` | Writes a hardware-profile network for tools/snp_nir.py, which makes the NIR file and co-simulates it in norse. | `[--part FILE]` `[--network FILE]` `[--steps N]` `[--out DIR]` | | `export-uppaal` | Writes a part as Uppaal timed automata with queries for its contract, and model-checks them with verifyta when installed. | `--part FILE` `[--out DIR]` `[--check on\|off]` | | `benchmark` | Runs every matching search on every matching suite task over several seeds, with a budget of evaluations per run, and prints the table. | `[--task NAME]` `[--algorithm NAME]` `[--engine exact\|sampled]` `[--configurations N]` `[--lexicase on\|off]` `[--budget N]` `[--seeds N]` `[--population N]` `[--repetitions N]` `[--library DIR]` `[--hand-built on\|off\|leaves]` | | `select` | Picks the best of the matching searches for one suite task by successive halving. | `--task NAME` `[--algorithm NAME]` `[--engine exact\|sampled]` `[--configurations N]` `[--lexicase on\|off]` `[--budget N]` `[--seeds N]` `[--population N]` `[--repetitions N]` `[--library DIR]` `[--hand-built on\|off\|leaves]` | +| `run` | Runs a saved or reference network and prints the numbers it generated and one run's spike train, or its score on the task when it has inputs. | `--network FILE\|natural\|even` `[--target VALUES]` `[--kind set\|sequence\|binary]` `[--task NAME]` `[--seed N]` `[--simulator NAME]` `[--steps N]` `[--repetitions N]` `[--timing legacy\|interval]` | | `tasks` | Lists the suite tasks. | | | `algorithms` | Lists the searches. | | @@ -101,7 +111,7 @@ When evolving, the console shows the best network after every generation: its ne Sequence and binary lines add "(varies between runs)" when the network is nondeterministic. With the MAP-Elites algorithm, the end of the run also lists the fittest network of each size. -Running a network shows the numbers it generated, one run's spike train with the intervals between its spikes, and how long the run took. For a network with input neurons, it shows its score on the selected task instead of the spike train. Evolved networks are saved to a timestamped folder inside `runs/` at the root of the repository (or of the working directory outside one), named in the message at the end of a run; git ignores it. To load one, choose *Run a network > Import* and give that path, such as `../runs/6234234242322/TargetNet.json` from the `SNP_Evolution` folder. `Test Data/`, `Combined Data/` and `CompositeLowHighGen/` hold earlier runs. +Running a network shows the numbers it generated, one run's spike train with the intervals between its spikes, and how long the run took. For a network with input neurons, it shows its score on the selected task instead of the spike train. Evolved networks are saved to a timestamped folder inside `runs/` at the root of the repository (or of the working directory outside one), named in the message at the end of a run; git ignores it. To run one again, choose *Run a network > A network from a file* and give that path, or run `run --network ../runs/6234234242322/TargetNet.json` from the `SNP_Evolution` folder. `Test Data/`, `Combined Data/` and `CompositeLowHighGen/` hold earlier runs. ## Rule forms diff --git a/SNP_Evolution/Application/ComposeService.cs b/SNP_Evolution/Application/ComposeService.cs index eb2ec31..998c96a 100644 --- a/SNP_Evolution/Application/ComposeService.cs +++ b/SNP_Evolution/Application/ComposeService.cs @@ -1,6 +1,5 @@ using System; using SnpEvolution.Search; -using SnpEvolution.Search.Benchmarking; namespace SnpEvolution.Application { @@ -9,21 +8,16 @@ public static class ComposeService { public const string FileStem = "ComposedNet"; - // The settings compose starts from, before any options: the task's rule form and timing, composition search with - // tournament selection and lexicase parents, and a budget large enough for the arithmetic contracts. - public static Settings SettingsFor(CatalogEntry task) + // The settings compose starts from, before its task and options: composition search with tournament selection and + // lexicase parents, and a budget large enough for the arithmetic contracts. + public static Settings Starting(Settings settings) { - BenchmarkTask suiteTask = task.Create(new Settings()); - return new Settings - { - Task = task, - RuleForm = suiteTask.RuleForm, - OutputTiming = suiteTask.Timing, - Algorithm = SearchCatalog.CompositionTournament, - MaxEvaluations = 30_000, - MaxGenerations = 5_000, - Lexicase = true, - }; + Settings starting = settings.Copy(); + starting.Algorithm = SearchCatalog.CompositionTournament; + starting.MaxEvaluations = 30_000; + starting.MaxGenerations = 5_000; + starting.Lexicase = true; + return starting; } // Why these settings cannot compose, or null when they can. diff --git a/SNP_Evolution/Application/Settings.cs b/SNP_Evolution/Application/Settings.cs index 798b03b..3f5f60a 100644 --- a/SNP_Evolution/Application/Settings.cs +++ b/SNP_Evolution/Application/Settings.cs @@ -92,6 +92,17 @@ public sealed class Settings public IReadOnlyList MutationTemplates => ExperimentalRules ? ExpressionGenerator.ExperimentalTemplates : ExpressionGenerator.SimpleTemplates; + // Makes the task the one to evolve for; a suite task brings the rule form and timing it is meant for. + public void UseTask(CatalogEntry task) + { + Task = task; + if (task != Catalog.TargetTask) + { + BenchmarkTask chosen = task.Create(this); + (RuleForm, OutputTiming) = (chosen.RuleForm, chosen.Timing); + } + } + // The selected task, built with the rule form and output timing chosen here. public BenchmarkTask SelectedTask => Task.Create(this) with { RuleForm = RuleForm, Timing = OutputTiming }; diff --git a/SNP_Evolution/Cli/BenchmarkMenu.cs b/SNP_Evolution/Cli/BenchmarkMenu.cs deleted file mode 100644 index 61e1a82..0000000 --- a/SNP_Evolution/Cli/BenchmarkMenu.cs +++ /dev/null @@ -1,89 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using SnpEvolution.Application; -using SnpEvolution.Model; -using SnpEvolution.Search; -using SnpEvolution.Search.Benchmarking; -using SnpEvolution.Search.Fitness; - -namespace SnpEvolution.Cli -{ - // Both race the searches that start from nothing, as the benchmark and select commands do, on the settings' engine. - internal static class BenchmarkMenu - { - public static void Show(MenuState state) - { - int selection = 0; - while (ConsoleUi.Choose(state.Settings, "Benchmark", new[] { "Every algorithm on the task suite", "Find the best algorithm for the selected task" }, selection) is int choice) - { - selection = choice; - if (choice == 0) - { - RunBenchmark(state.Settings); - } - else - { - SelectAlgorithm(state.Settings); - } - } - } - - private static void RunBenchmark(Settings settings) - { - Console.Clear(); - BenchmarkSettings benchmark = settings.BenchmarkSettings; - Console.WriteLine("Runs {0} algorithms on {1} tasks, {2} seeds each, with up to {3} evaluations per run, on the {4} engine.", - SearchCatalog.FromScratch.Count, TaskSuite.All.Count, benchmark.Seeds, benchmark.EvaluationBudget, settings.Engine.Name); - if (!ConsoleInput.WaitForEnterOrEscape("Press enter to start, or ESC to go back; this can take a while.") || Plan(settings) is not BenchmarkPlan plan) - { - return; - } - Stopwatch stopwatch = Stopwatch.StartNew(); - IReadOnlyList rows = BenchmarkService.Run(plan, TaskSuite.All, Console.WriteLine); - Console.WriteLine("\n{0}\nTime elapsed: {1}", Benchmark.FormatTable(rows), stopwatch.Elapsed); - BenchmarkService.Save(rows); - ConsoleInput.WaitForEnter("Press enter to return to the menu."); - } - - private static void SelectAlgorithm(Settings settings) - { - Console.Clear(); - BenchmarkTask task = settings.SelectedTask; - Console.WriteLine("Successive halving over {0} algorithms for: {1}, starting at {2} evaluations per run.", - SearchCatalog.FromScratch.Count, task.Name, BenchmarkService.InitialBudget(settings.BenchmarkSettings)); - if (!ConsoleInput.WaitForEnterOrEscape("Press enter to start, or ESC to go back; this can take a while.") || Plan(settings) is not BenchmarkPlan plan) - { - return; - } - SelectionResult> result = BenchmarkService.Select(plan, task, Console.WriteLine); - Console.WriteLine("\nBest algorithm for {0}: {1}", task.Name, result.Winner.Name); - if (result.BestFound is Individual best) - { - Console.WriteLine("Best network found (fitness {0}, {1}):\n{2}", best.Fitness, best.Description, NetworkNotation.Format(best.Genes)); - } - ConsoleInput.WaitForEnter("Press enter to continue."); - if (result.Winner is EvolutionSearch winner && ConsoleUi.Confirm(settings, $"Use {winner.Name} from now on?")) - { - settings.Algorithm = winner; - } - } - - // Null, after showing why, when composition search's part library cannot be read. - private static BenchmarkPlan? Plan(Settings settings) - { - Loaded plan = BenchmarkService.Plan(settings, settings.BenchmarkSettings, SearchCatalog.FromScratch); - if (plan.Value == null) - { - Console.WriteLine(plan.Error); - ConsoleInput.WaitForEnter("Press enter to return to the menu."); - return null; - } - if (plan.Value.PartsNote != null) - { - Console.WriteLine(plan.Value.PartsNote); - } - return plan.Value; - } - } -} diff --git a/SNP_Evolution/Cli/Commands/AdviseCommand.cs b/SNP_Evolution/Cli/Commands/AdviseCommand.cs index 1548f9f..f5c76e7 100644 --- a/SNP_Evolution/Cli/Commands/AdviseCommand.cs +++ b/SNP_Evolution/Cli/Commands/AdviseCommand.cs @@ -9,20 +9,23 @@ internal sealed class AdviseCommand : Command { public override string Name => "advise"; - public override string Summary => "Prints the settings the advisor suggests for a target, without evolving."; + public override string Summary => "Prints the settings the advisor suggests for a target or a suite task, without evolving."; public override IReadOnlyList