Compare commits
No commits in common. "main" and "dev" have entirely different histories.
3
.gitignore
vendored
3
.gitignore
vendored
@ -25,6 +25,3 @@ Cargo.lock
|
||||
# Added by cargo
|
||||
|
||||
/target
|
||||
|
||||
# GDB files
|
||||
.gdb_history
|
||||
|
@ -4,8 +4,7 @@ version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
rand = "0.9.1"
|
||||
rand = "0.9.0"
|
||||
paste = "1.0.15"
|
||||
rust_decimal = { version = "1.37", features = ["macros", "maths"] }
|
||||
rush_macro = { path = "rush_macro" }
|
||||
polars = { version = "0.46.0", features = ["lazy"]}
|
||||
rush_macro = { path = "rush_macro" }
|
12
README.md
12
README.md
@ -8,18 +8,6 @@ a better language to develop this in rather than Haskell.
|
||||
This is truly following the test-driven development model
|
||||
so each of the files should have its own tests module.
|
||||
|
||||
# Building
|
||||
|
||||
`cargo build` and it'll build.
|
||||
|
||||
### Adding new instructions
|
||||
|
||||
When adding new instructions, a python script generates the function lists and places them
|
||||
in `src/instructions/list.rs`. When creating new instructions, it is important to run
|
||||
`scripts/instruction_list.py` to add newly created instructions to their corresponding function
|
||||
lists. This script uses python 3.13. Must be ran from the root of the directory as
|
||||
`python scripts/instruction_list.py`.
|
||||
|
||||
## Link for later
|
||||
|
||||
https://miroslavtushev.medium.com/does-my-sample-have-to-be-normally-distributed-for-a-t-test-7ee91aaaca2a
|
||||
|
60
flake.lock
generated
60
flake.lock
generated
@ -1,39 +1,54 @@
|
||||
{
|
||||
"nodes": {
|
||||
"flake-utils": {
|
||||
"flake-parts": {
|
||||
"inputs": {
|
||||
"systems": "systems"
|
||||
"nixpkgs-lib": "nixpkgs-lib"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1731533236,
|
||||
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
|
||||
"lastModified": 1741352980,
|
||||
"narHash": "sha256-+u2UunDA4Cl5Fci3m7S643HzKmIDAe+fiXrLqYsR2fs=",
|
||||
"owner": "hercules-ci",
|
||||
"repo": "flake-parts",
|
||||
"rev": "f4330d22f1c5d2ba72d3d22df5597d123fdb60a9",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"owner": "hercules-ci",
|
||||
"repo": "flake-parts",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1745234285,
|
||||
"narHash": "sha256-GfpyMzxwkfgRVN0cTGQSkTC0OHhEkv3Jf6Tcjm//qZ0=",
|
||||
"owner": "NixOS",
|
||||
"lastModified": 1742422364,
|
||||
"narHash": "sha256-mNqIplmEohk5jRkqYqG19GA8MbQ/D4gQSK0Mu4LvfRQ=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "c11863f1e964833214b767f4a369c6e6a7aba141",
|
||||
"rev": "a84ebe20c6bc2ecbcfb000a50776219f48d134cc",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"owner": "nixos",
|
||||
"ref": "nixos-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs-lib": {
|
||||
"locked": {
|
||||
"lastModified": 1740877520,
|
||||
"narHash": "sha256-oiwv/ZK/2FhGxrCkQkB83i7GnWXPPLzoqFHpDD3uYpk=",
|
||||
"owner": "nix-community",
|
||||
"repo": "nixpkgs.lib",
|
||||
"rev": "147dee35aab2193b174e4c0868bd80ead5ce755c",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-community",
|
||||
"repo": "nixpkgs.lib",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs_2": {
|
||||
"locked": {
|
||||
"lastModified": 1736320768,
|
||||
@ -52,7 +67,7 @@
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils",
|
||||
"flake-parts": "flake-parts",
|
||||
"nixpkgs": "nixpkgs",
|
||||
"rust-overlay": "rust-overlay"
|
||||
}
|
||||
@ -74,21 +89,6 @@
|
||||
"repo": "rust-overlay",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"systems": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
|
118
flake.nix
118
flake.nix
@ -1,51 +1,81 @@
|
||||
{
|
||||
description = "Simple Rush nix flake";
|
||||
|
||||
inputs = {
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
|
||||
flake-parts.url = "github:hercules-ci/flake-parts";
|
||||
rust-overlay.url = "github:oxalica/rust-overlay";
|
||||
flake-utils.url = "github:numtide/flake-utils";
|
||||
};
|
||||
|
||||
outputs = { self, nixpkgs, rust-overlay, flake-utils, ... }:
|
||||
flake-utils.lib.eachDefaultSystem (system:
|
||||
let
|
||||
overlays = [ (import rust-overlay) ];
|
||||
pkgs = import nixpkgs {
|
||||
inherit system overlays;
|
||||
config.allowUnfree = true;
|
||||
outputs = inputs:
|
||||
inputs.flake-parts.lib.mkFlake { inherit inputs; } {
|
||||
systems = [ "x86_64-linux" ];
|
||||
perSystem = { config, self', pkgs, lib, system, ... }:
|
||||
let
|
||||
runtimeDeps = with pkgs; [ alsa-lib speechd ];
|
||||
buildDeps = with pkgs; [ pkg-config rustPlatform.bindgenHook ];
|
||||
devDeps = with pkgs; [ gdb ];
|
||||
|
||||
cargoToml = builtins.fromTOML (builtins.readFile ./Cargo.toml);
|
||||
msrv = cargoToml.package.rust-version;
|
||||
|
||||
rustPackage = features:
|
||||
(pkgs.makeRustPlatform {
|
||||
cargo = pkgs.rust-bin.stable.latest.minimal;
|
||||
rustc = pkgs.rust-bin.stable.latest.minimal;
|
||||
}).buildRustPackage {
|
||||
inherit (cargoToml.package) name version;
|
||||
src = ./.;
|
||||
cargoLock.lockFile = ./Cargo.lock;
|
||||
buildFeatures = features;
|
||||
buildInputs = runtimeDeps;
|
||||
nativeBuildInputs = buildDeps;
|
||||
# Uncomment if your cargo tests require networking or otherwise
|
||||
# don't play nicely with the Nix build sandbox:
|
||||
# doCheck = false;
|
||||
};
|
||||
|
||||
mkDevShell = rustc:
|
||||
pkgs.mkShell {
|
||||
shellHook = ''
|
||||
export RUST_SRC_PATH=${pkgs.rustPlatform.rustLibSrc}
|
||||
export SHELL=${pkgs.lib.getExe pkgs.bashInteractive}
|
||||
'';
|
||||
buildInputs = runtimeDeps;
|
||||
nativeBuildInputs = buildDeps ++ devDeps ++ [ rustc ];
|
||||
packages = with pkgs; [
|
||||
rust-analyzer
|
||||
lldb
|
||||
(vscode-with-extensions.override {
|
||||
vscode = vscodium;
|
||||
vscodeExtensions = with vscode-extensions; [
|
||||
rust-lang.rust-analyzer
|
||||
] ++ pkgs.vscode-utils.extensionsFromVscodeMarketplace [
|
||||
{
|
||||
name = "vscode-lldb";
|
||||
publisher = "vadimcn";
|
||||
version = "1.11.4";
|
||||
# sha256 = "1hp6gjh4xp2m1xlm1jsdzxw9d8frkiidhph6nvl24d0h8z34w49g";
|
||||
sha256 = "ylWlqKSiqsOL1S4vaFKLDck1wGm155bEGGL4+sKdBF8=";
|
||||
}
|
||||
];
|
||||
})
|
||||
];
|
||||
};
|
||||
in {
|
||||
_module.args.pkgs = import inputs.nixpkgs {
|
||||
inherit system;
|
||||
overlays = [ (import inputs.rust-overlay) ];
|
||||
};
|
||||
|
||||
packages.default = self'.packages.rush;
|
||||
devShells.default = self'.devShells.stable;
|
||||
|
||||
packages.rush = (rustPackage "rush");
|
||||
packages.rush-base = (rustPackage "");
|
||||
|
||||
devShells.nightly = (mkDevShell (pkgs.rust-bin.selectLatestNightlyWith
|
||||
(toolchain: toolchain.default)));
|
||||
devShells.stable = (mkDevShell pkgs.rust-bin.stable.latest.default);
|
||||
devShells.msrv = (mkDevShell pkgs.rust-bin.stable.${msrv}.default);
|
||||
};
|
||||
in
|
||||
{
|
||||
devShells.default = with pkgs; mkShell {
|
||||
buildInputs = [
|
||||
rust-bin.beta.latest.complete
|
||||
];
|
||||
packages = with pkgs; [
|
||||
gdb
|
||||
bacon
|
||||
python313Packages.pygments # for personal gdb-dashboard use
|
||||
];
|
||||
shellHook = ''
|
||||
export SHELL=${pkgs.lib.getExe pkgs.bashInteractive}
|
||||
'';
|
||||
};
|
||||
devShells.nightly = with pkgs; mkShell {
|
||||
buildInputs = [
|
||||
(rust-bin.selectLatestNightlyWith (toolchain: toolchain.complete))
|
||||
];
|
||||
packages = with pkgs; [
|
||||
gdb
|
||||
bacon
|
||||
python313
|
||||
python313Packages.pygments # for personal gdb-dashboard use
|
||||
python313Packages.ruff
|
||||
cargo-expand
|
||||
];
|
||||
shellHook = ''
|
||||
export SHELL=${pkgs.lib.getExe pkgs.bashInteractive}
|
||||
'';
|
||||
};
|
||||
}
|
||||
);
|
||||
};
|
||||
}
|
||||
|
@ -4,6 +4,9 @@ use syn::parse_macro_input;
|
||||
|
||||
mod utils;
|
||||
|
||||
/// This macro kinda goes super crazy mode
|
||||
/// Here's how to use the macro:
|
||||
///
|
||||
/// `run_instruction!(function_name, output_stack, push state, any amount of
|
||||
/// comma separated stacks by name ; (the semicolon instructs use whether the instruction
|
||||
/// has multiple outputs. If ; passed, assumes multiple, without assumes just one output))`
|
||||
@ -27,7 +30,7 @@ mod utils;
|
||||
/// Some(vec![x + y, x - y])
|
||||
/// }
|
||||
///
|
||||
/// // rush_macro::run_instruction!(aux_iadd, int, _state, int, int;);
|
||||
/// run_instruction!(aux_iadd, int, state, int, int;);
|
||||
/// ```
|
||||
/// would have the ; placed at the end of the instruction. Check rush's `tests/instruction_test.rs`
|
||||
/// file for an example using this code.
|
||||
|
@ -1,2 +0,0 @@
|
||||
[toolchain]
|
||||
channel = "nightly"
|
@ -1,85 +0,0 @@
|
||||
import subprocess
|
||||
import sys
|
||||
import re
|
||||
from pathlib import Path
|
||||
|
||||
def run_cargo_expand(binary_name, path_to_module):
|
||||
"""Run cargo expand and return its output."""
|
||||
try:
|
||||
result = subprocess.run(
|
||||
["cargo", "expand", "--bin", binary_name, path_to_module],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
check=True
|
||||
)
|
||||
return result.stdout
|
||||
except subprocess.CalledProcessError as e:
|
||||
print(f"Error running cargo expand: {e}", file=sys.stderr)
|
||||
print(f"stderr: {e.stderr}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
except FileNotFoundError:
|
||||
print("Error: cargo expand command not found. Make sure cargo-expand is installed.", file=sys.stderr)
|
||||
print("You can install it with: cargo install cargo-expand", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
def extract_functions_with_push_state(code):
|
||||
"""Extract function names that have &mut PushState as their only parameter."""
|
||||
# Look for function definitions with pattern: pub fn name(state: &mut PushState)
|
||||
pattern = r'pub fn ([a-zA-Z0-9_]+)\s*\(\s*_?state\s*:\s*&mut\s+PushState\s*\)'
|
||||
matches = re.findall(pattern, code)
|
||||
return matches
|
||||
|
||||
def organize_functions(func_list) -> dict[str, list]:
|
||||
categorized: dict[str, list] = {}
|
||||
|
||||
for func in func_list:
|
||||
parts: list[str] = func.split("_")
|
||||
|
||||
if parts[0] == "vector":
|
||||
categorized[f"vector_{parts[1]}"] = []
|
||||
else:
|
||||
categorized[parts[0]] = []
|
||||
|
||||
for func in func_list:
|
||||
for key in categorized.keys():
|
||||
if func.startswith(key):
|
||||
categorized[key].append(func)
|
||||
|
||||
return categorized
|
||||
|
||||
if __name__ == "__main__":
|
||||
expanded_code: list = []
|
||||
|
||||
for rs_file in Path("src/instructions/").iterdir():
|
||||
if rs_file.name not in ["mod.rs", "utils.rs", "list.rs"]:
|
||||
expanded_code.append(run_cargo_expand("rush", f"instructions::{rs_file.stem}"))
|
||||
|
||||
function_names: list = []
|
||||
for code in expanded_code:
|
||||
function_names.extend(extract_functions_with_push_state(code))
|
||||
|
||||
categorized_funcs: dict[str, list] = organize_functions(function_names)
|
||||
|
||||
with open("src/instructions/list.rs", "w") as f:
|
||||
for rs_file in Path("src/instructions/").iterdir():
|
||||
if rs_file.name not in ["mod.rs", "utils.rs", "list.rs"]:
|
||||
f.write(f"use crate::instructions::{rs_file.stem}::*;\n")
|
||||
f.write("use crate::push::state::PushState;\n")
|
||||
|
||||
f.write("\n")
|
||||
|
||||
for list_name in categorized_funcs.keys():
|
||||
f.write("pub fn " + list_name + "_instructions() -> Vec<fn(&mut PushState)> {\n")
|
||||
f.write(" vec![\n")
|
||||
for func in categorized_funcs[list_name]:
|
||||
f.write(f" {func},\n")
|
||||
f.write(" ]\n")
|
||||
f.write("}\n")
|
||||
f.write("\n")
|
||||
|
||||
f.write("pub fn all_instructions() -> Vec<fn(&mut PushState)> {\n")
|
||||
f.write(" let mut all_vec = vec![];\n")
|
||||
for list_name in categorized_funcs.keys():
|
||||
f.write(f" all_vec.extend({list_name}_instructions().iter());\n")
|
||||
f.write(" all_vec\n")
|
||||
f.write("}")
|
@ -1,79 +0,0 @@
|
||||
use crate::gp::selection::Selection;
|
||||
use crate::gp::variation::Variation;
|
||||
use crate::push::state::Gene;
|
||||
use polars::prelude::*;
|
||||
use rust_decimal::prelude::*;
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum ClosingType {
|
||||
Specified,
|
||||
Balanced,
|
||||
None,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub struct PushArgs {
|
||||
pub alignment_deviation: Decimal, // For alternation, std dev of deviation of index when alternating
|
||||
pub alternation_rate: usize, // For alternation, prob of switching parents at each location. A number 0-100
|
||||
pub closes: ClosingType, // How push should automatically place Gene::Close into a plushy
|
||||
pub dont_end: bool, // If true, keep running until limit regardless of success
|
||||
// pub downsample: bool, // Whether or not to downsample. TODO later with all the related args
|
||||
pub elitism: bool, // Whether to always add the best individual to next generation
|
||||
pub error_function: Option<fn(&PushArgs, &DataFrame, Vec<Gene>) -> Vec<Decimal>>, // The error function
|
||||
pub instructions: Option<Vec<Gene>>, // Instructions to use in a run
|
||||
pub max_generations: usize, // Max amount of generations
|
||||
pub max_init_plushy_size: usize, // max initial plushy size
|
||||
pub max_stack_size: usize, // max size a stack is allowed to reach during execution
|
||||
pub parent_selection: Selection, // Selection to use, TODO change this later.
|
||||
pub pop_size: usize, // Population size
|
||||
pub replacement_rate: f64, // For uniform replacement, rate items replaced
|
||||
pub use_simplification: bool, // Whether to use simplification at end of run
|
||||
pub simplification_k: usize, // Max amt of genes to attempt removal during one round of simplification process
|
||||
pub simplification_steps: usize, // How many attempts to find simplified genomes
|
||||
pub simplification_verbose: bool, // Whether to send extra messages about simplification or not
|
||||
pub solution_error_threshold: Decimal, // Max total error for solutions
|
||||
pub use_single_thread: bool, // if true, only single threaded
|
||||
pub step_limit: usize, // Amount of steps a push interpreter can run for
|
||||
pub testing_data: Option<DataFrame>, // The testing data, must be formatted the same as training data
|
||||
pub tournament_size: usize, // Tournament size for tournament selection
|
||||
pub training_data: Option<DataFrame>, // The training data, must be formatted the same as testing data
|
||||
pub umad_rate: f64, // addition rate (deletion rate derived) for UMAD
|
||||
pub variation: HashMap<Variation, f64>, // genetic operators and probability for use. should sum to 1,
|
||||
}
|
||||
|
||||
impl PushArgs {
|
||||
/// Holds the default arguments
|
||||
pub fn new() -> Self {
|
||||
let mut map = HashMap::new();
|
||||
map.insert(Variation::UMAD, 1.0);
|
||||
|
||||
Self {
|
||||
alignment_deviation: dec!(2.0),
|
||||
alternation_rate: 10,
|
||||
closes: ClosingType::Specified,
|
||||
dont_end: false,
|
||||
elitism: false,
|
||||
error_function: None,
|
||||
instructions: None,
|
||||
max_generations: 1000,
|
||||
max_init_plushy_size: 100,
|
||||
max_stack_size: 100,
|
||||
parent_selection: Selection::Lexicase,
|
||||
pop_size: 1000,
|
||||
replacement_rate: 0.1,
|
||||
use_simplification: true,
|
||||
simplification_k: 4,
|
||||
simplification_steps: 1000,
|
||||
simplification_verbose: true,
|
||||
use_single_thread: false,
|
||||
solution_error_threshold: dec!(0.0),
|
||||
step_limit: 1000,
|
||||
testing_data: None,
|
||||
tournament_size: 5,
|
||||
training_data: None,
|
||||
umad_rate: 0.1,
|
||||
variation: map,
|
||||
}
|
||||
}
|
||||
}
|
194
src/gp/genome.rs
194
src/gp/genome.rs
@ -1,194 +0,0 @@
|
||||
use crate::instructions::code::{
|
||||
exec_do_count, exec_do_range, exec_do_times, exec_do_while, exec_if, exec_when, exec_while,
|
||||
};
|
||||
use crate::instructions::common::{
|
||||
exec_dup, exec_dup_times, exec_pop, exec_rotate, exec_shove, exec_swap,
|
||||
};
|
||||
use crate::instructions::vector::{
|
||||
string_iterate, vector_boolean_iterate, vector_char_iterate, vector_float_iterate,
|
||||
vector_int_iterate, vector_string_iterate,
|
||||
};
|
||||
use crate::push::state::Gene;
|
||||
use crate::push::state::Gene::StateFunc;
|
||||
use rand::prelude::*;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::LazyLock;
|
||||
|
||||
/// Generates a random plushy.
|
||||
pub fn make_random_plushy(
|
||||
genes: Vec<Gene>,
|
||||
max_init_plushy_size: usize,
|
||||
mut rng: impl Rng,
|
||||
) -> Vec<Gene> {
|
||||
let plushy_size = rng.random_range(0..=max_init_plushy_size);
|
||||
let mut plushy = Vec::with_capacity(plushy_size);
|
||||
for _ in 0..plushy_size {
|
||||
plushy.push(genes[rng.random_range(0..genes.len())].clone());
|
||||
}
|
||||
plushy
|
||||
}
|
||||
|
||||
/// A map of genes to their number of blocks they open.
|
||||
pub static OPEN_MAP: LazyLock<HashMap<Gene, u8>> = LazyLock::new(|| {
|
||||
let mut temp_map = HashMap::default();
|
||||
temp_map.insert(StateFunc(exec_dup), 1u8);
|
||||
temp_map.insert(StateFunc(exec_dup_times), 1u8);
|
||||
temp_map.insert(StateFunc(exec_pop), 1u8);
|
||||
temp_map.insert(StateFunc(exec_rotate), 3u8);
|
||||
temp_map.insert(StateFunc(exec_shove), 1u8);
|
||||
temp_map.insert(StateFunc(exec_swap), 2u8);
|
||||
temp_map.insert(StateFunc(exec_if), 2u8);
|
||||
temp_map.insert(StateFunc(exec_when), 1u8);
|
||||
temp_map.insert(StateFunc(exec_while), 1u8);
|
||||
temp_map.insert(StateFunc(exec_do_while), 1u8);
|
||||
temp_map.insert(StateFunc(exec_do_range), 1u8);
|
||||
temp_map.insert(StateFunc(exec_do_count), 1u8);
|
||||
temp_map.insert(StateFunc(exec_do_times), 1u8);
|
||||
//exec_k, 2
|
||||
//exec_s 3
|
||||
//exec_y 1
|
||||
temp_map.insert(StateFunc(string_iterate), 1u8);
|
||||
temp_map.insert(StateFunc(vector_int_iterate), 1u8);
|
||||
temp_map.insert(StateFunc(vector_float_iterate), 1u8);
|
||||
temp_map.insert(StateFunc(vector_string_iterate), 1u8);
|
||||
temp_map.insert(StateFunc(vector_boolean_iterate), 1u8);
|
||||
temp_map.insert(StateFunc(vector_char_iterate), 1u8);
|
||||
temp_map
|
||||
});
|
||||
|
||||
fn has_openers(genes: &[Gene]) -> bool {
|
||||
for gene in genes {
|
||||
if is_opener(gene) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
fn is_opener(gene: &Gene) -> bool {
|
||||
match gene {
|
||||
Gene::Open(_) => return true,
|
||||
_ => (),
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
fn get_opener_count(gene: &Gene) -> &u8 {
|
||||
match gene {
|
||||
Gene::Open(val) => val,
|
||||
_ => &0u8,
|
||||
}
|
||||
}
|
||||
|
||||
fn dec_opener(gene: Gene) -> Gene {
|
||||
match gene {
|
||||
Gene::Open(val) => Gene::Open(val - 1),
|
||||
_ => gene,
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts a plushy to a push program.
|
||||
pub fn plushy_to_push(genes: Vec<Gene>) -> Vec<Gene> {
|
||||
let mut plushy_buffer: Vec<Gene> = Vec::with_capacity(genes.len() * 2);
|
||||
for gene in genes.into_iter() {
|
||||
let open = OPEN_MAP.get(&gene);
|
||||
plushy_buffer.push(gene);
|
||||
if let Some(amt) = open {
|
||||
plushy_buffer.push(Gene::Open(*amt))
|
||||
}
|
||||
}
|
||||
let mut push_buffer = Vec::with_capacity(plushy_buffer.len());
|
||||
loop {
|
||||
// recur with one more close if there are openers
|
||||
if plushy_buffer.is_empty() && has_openers(&push_buffer) {
|
||||
plushy_buffer.push(Gene::Close);
|
||||
} else if plushy_buffer.is_empty() {
|
||||
return push_buffer;
|
||||
} else {
|
||||
let first_gene = plushy_buffer.remove(0);
|
||||
match &first_gene {
|
||||
Gene::Close => {
|
||||
if has_openers(&push_buffer) {
|
||||
let mut index: Option<usize> = None;
|
||||
let mut opener: Option<Gene> = None;
|
||||
// not the most optimal iterating through the entire genome.
|
||||
// Will do for now.
|
||||
for (ndx, el) in push_buffer.clone().into_iter().enumerate() {
|
||||
if is_opener(&el) {
|
||||
index = Some(ndx);
|
||||
opener = Some(el);
|
||||
}
|
||||
}
|
||||
let post_open: Vec<_> = push_buffer.drain((index.unwrap() + 1)..).collect();
|
||||
push_buffer.pop(); // Pop the close here
|
||||
push_buffer.push(Gene::Block(post_open));
|
||||
if get_opener_count(&opener.clone().unwrap()) > &1u8 {
|
||||
let opener_new = dec_opener(opener.unwrap().clone());
|
||||
push_buffer.push(opener_new);
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => push_buffer.push(first_gene),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
// use crate::instructions::vector::{string_iterate, vector_float_maximum};
|
||||
use crate::instructions::common::*;
|
||||
use crate::instructions::numeric::*;
|
||||
use crate::push::state::*;
|
||||
// use crate::push::utils::most_genes;
|
||||
// use rand::SeedableRng;
|
||||
|
||||
#[test]
|
||||
fn make_random_plushy_test() {
|
||||
// let rng = StdRng::seed_from_u64(42);
|
||||
// let rand_plushy = make_random_plushy(most_genes(), 15, rng);
|
||||
// let fin_result = vec![StateFunc(string_iterate), StateFunc(vector_float_maximum)];
|
||||
// Make this consistent later
|
||||
// assert_eq!(fin_result, rand_plushy);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn plushy_to_push_test() {
|
||||
let plushy = vec![
|
||||
Gene::StateFunc(exec_swap),
|
||||
Gene::StateFunc(float_tan),
|
||||
Gene::StateFunc(int_pop),
|
||||
Gene::Close,
|
||||
Gene::StateFunc(exec_flush),
|
||||
Gene::Close,
|
||||
Gene::StateFunc(boolean_pop),
|
||||
];
|
||||
let res_push = plushy_to_push(plushy);
|
||||
assert_eq!(
|
||||
res_push,
|
||||
vec![
|
||||
StateFunc(exec_swap),
|
||||
Gene::Block(vec![Gene::StateFunc(float_tan), Gene::StateFunc(int_pop)]),
|
||||
Gene::Block(vec![Gene::StateFunc(exec_flush)]),
|
||||
Gene::StateFunc(boolean_pop),
|
||||
]
|
||||
);
|
||||
|
||||
let plushy = vec![
|
||||
Gene::StateFunc(exec_swap),
|
||||
Gene::StateFunc(float_tan),
|
||||
Gene::StateFunc(int_pop),
|
||||
Gene::Close,
|
||||
];
|
||||
let res_push = plushy_to_push(plushy);
|
||||
assert_eq!(
|
||||
res_push,
|
||||
vec![
|
||||
StateFunc(exec_swap),
|
||||
Gene::Block(vec![Gene::StateFunc(float_tan), Gene::StateFunc(int_pop)]),
|
||||
Gene::Block(vec![]),
|
||||
]
|
||||
)
|
||||
}
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
use crate::push::state::Gene;
|
||||
use rust_decimal::Decimal;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Individual {
|
||||
pub plushy: Vec<Gene>,
|
||||
pub total_fitness: Option<Decimal>,
|
||||
pub fitness_cases: Option<Vec<Decimal>>,
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
use args::PushArgs;
|
||||
|
||||
pub mod args;
|
||||
pub mod genome;
|
||||
pub mod individual;
|
||||
pub mod selection;
|
||||
pub mod simplification;
|
||||
pub mod utils;
|
||||
pub mod variation;
|
||||
|
||||
pub fn gp_loop(push_args: PushArgs) -> bool {
|
||||
let _pop_size = push_args.pop_size;
|
||||
let _max_gens = push_args.max_generations;
|
||||
let _error_func = push_args.error_function;
|
||||
let _solution_error_threshold = push_args.solution_error_threshold;
|
||||
let _dont_end = push_args.dont_end;
|
||||
let _elitism = push_args.elitism;
|
||||
let _training_data = push_args.training_data;
|
||||
let _testing_data = push_args.testing_data;
|
||||
let _simplification = push_args.use_simplification;
|
||||
|
||||
true
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
use crate::gp::args::PushArgs;
|
||||
use crate::gp::individual::Individual;
|
||||
use rand::Rng;
|
||||
|
||||
pub enum Selection {
|
||||
Lexicase,
|
||||
Tournament,
|
||||
}
|
||||
|
||||
pub fn select_parent(
|
||||
_pop: Vec<Individual>,
|
||||
_push_args: &PushArgs,
|
||||
_rng: &mut impl Rng,
|
||||
) -> Individual {
|
||||
todo!()
|
||||
}
|
@ -1,89 +0,0 @@
|
||||
use super::args::PushArgs;
|
||||
use crate::push::state::Gene;
|
||||
use polars::prelude::*;
|
||||
use rand::Rng;
|
||||
use rand::prelude::SliceRandom;
|
||||
use rand::rng;
|
||||
use rust_decimal::Decimal;
|
||||
use std::collections::HashSet;
|
||||
|
||||
/// Takes k random indices from the given range
|
||||
fn choose_random_k(k: usize, indices_count: usize, rng: &mut impl Rng) -> Vec<usize> {
|
||||
let mut indices: Vec<usize> = (0..indices_count).collect();
|
||||
indices.shuffle(rng);
|
||||
indices.truncate(k);
|
||||
indices
|
||||
}
|
||||
|
||||
/// Deletes the values at the given set of indices
|
||||
fn delete_at_indices<T: Clone>(indices: &[usize], plushy: &[T]) -> Vec<T> {
|
||||
let indices_set: HashSet<usize> = indices.iter().cloned().collect();
|
||||
plushy
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter_map(|(i, item)| {
|
||||
if !indices_set.contains(&i) {
|
||||
Some(item.clone())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Deletes k random instructions from the plushy
|
||||
fn delete_k_random<T: Clone>(k: usize, plushy: &[T], rng: &mut impl Rng) -> Vec<T> {
|
||||
let actual_k = std::cmp::min(k, plushy.len());
|
||||
if actual_k == 0 {
|
||||
return plushy.to_vec();
|
||||
}
|
||||
let indices = choose_random_k(actual_k, plushy.len(), rng);
|
||||
delete_at_indices(&indices, plushy)
|
||||
}
|
||||
|
||||
pub fn auto_simplify_plushy<F>(plushy: Vec<Gene>, error_func: F, push_args: PushArgs) -> Vec<Gene>
|
||||
where
|
||||
F: Fn(&PushArgs, &DataFrame, Vec<Gene>) -> Vec<Decimal>,
|
||||
{
|
||||
if push_args.simplification_verbose {
|
||||
println!(
|
||||
"{{ start_plushy_length: {}, k: {} }}",
|
||||
plushy.len(),
|
||||
push_args.simplification_k
|
||||
);
|
||||
}
|
||||
|
||||
let training_data = (&push_args)
|
||||
.training_data
|
||||
.clone()
|
||||
.expect("Must provide training_data");
|
||||
|
||||
let mut curr_errors = error_func(&push_args, &training_data, plushy.clone());
|
||||
let mut step = 0;
|
||||
let mut curr_plushy = plushy;
|
||||
|
||||
while step < push_args.simplification_steps {
|
||||
let mut rng = rng();
|
||||
let random_k = rng.random_range(1..=push_args.simplification_k);
|
||||
|
||||
let new_plushy = delete_k_random(random_k, &curr_plushy, &mut rng);
|
||||
let new_plushy_errors = error_func(&push_args, &training_data, new_plushy.clone());
|
||||
|
||||
if new_plushy_errors.iter().sum::<Decimal>() <= curr_errors.iter().sum() {
|
||||
curr_plushy = new_plushy;
|
||||
curr_errors = new_plushy_errors;
|
||||
}
|
||||
|
||||
step += 1;
|
||||
}
|
||||
|
||||
if push_args.simplification_verbose {
|
||||
println!(
|
||||
"{{ end_plushy_length: {}, k: {} }}",
|
||||
curr_plushy.len(),
|
||||
push_args.simplification_k
|
||||
);
|
||||
}
|
||||
|
||||
curr_plushy
|
||||
}
|
268
src/gp/utils.rs
268
src/gp/utils.rs
@ -1,268 +0,0 @@
|
||||
use crate::gp::args::ClosingType;
|
||||
use crate::gp::genome::OPEN_MAP;
|
||||
use crate::push::state::Gene;
|
||||
use polars::prelude::*;
|
||||
use rand::Rng;
|
||||
use rand::seq::IndexedRandom;
|
||||
use rust_decimal::prelude::*;
|
||||
|
||||
pub fn polars_to_gene(polars_value: &AnyValue) -> Gene {
|
||||
match polars_value {
|
||||
AnyValue::Int8(val) => Gene::GeneInt(*val as i128),
|
||||
AnyValue::Int16(val) => Gene::GeneInt(*val as i128),
|
||||
AnyValue::Int32(val) => Gene::GeneInt(*val as i128),
|
||||
AnyValue::Int64(val) => Gene::GeneInt(*val as i128),
|
||||
AnyValue::Int128(val) => Gene::GeneInt(*val as i128),
|
||||
AnyValue::UInt8(val) => Gene::GeneInt(*val as i128),
|
||||
AnyValue::UInt16(val) => Gene::GeneInt(*val as i128),
|
||||
AnyValue::UInt32(val) => Gene::GeneInt(*val as i128),
|
||||
AnyValue::UInt64(val) => Gene::GeneInt(*val as i128),
|
||||
AnyValue::Float32(val) => Gene::GeneFloat(Decimal::from_f32(*val).unwrap()),
|
||||
AnyValue::Float64(val) => Gene::GeneFloat(Decimal::from_f64(*val).unwrap()),
|
||||
AnyValue::Boolean(val) => Gene::GeneBoolean(*val),
|
||||
AnyValue::String(val) => Gene::GeneString(val.chars().collect()),
|
||||
AnyValue::List(series) => match series.dtype() {
|
||||
DataType::Int8 => {
|
||||
let vec = series
|
||||
.i8()
|
||||
.unwrap()
|
||||
.into_iter()
|
||||
.map(|opt| opt.map(|v| v as i128))
|
||||
.collect::<Option<Vec<_>>>()
|
||||
.unwrap();
|
||||
Gene::GeneVectorInt(vec)
|
||||
}
|
||||
DataType::Int16 => {
|
||||
let vec = series
|
||||
.i16()
|
||||
.unwrap()
|
||||
.into_iter()
|
||||
.map(|opt| opt.map(|v| v as i128))
|
||||
.collect::<Option<Vec<_>>>()
|
||||
.unwrap();
|
||||
Gene::GeneVectorInt(vec)
|
||||
}
|
||||
DataType::Int32 => {
|
||||
let vec = series
|
||||
.i32()
|
||||
.unwrap()
|
||||
.into_iter()
|
||||
.map(|opt| opt.map(|v| v as i128))
|
||||
.collect::<Option<Vec<_>>>()
|
||||
.unwrap();
|
||||
Gene::GeneVectorInt(vec)
|
||||
}
|
||||
DataType::Int64 => {
|
||||
let vec = series
|
||||
.i64()
|
||||
.unwrap()
|
||||
.into_iter()
|
||||
.map(|opt| opt.map(|v| v as i128))
|
||||
.collect::<Option<Vec<_>>>()
|
||||
.unwrap();
|
||||
Gene::GeneVectorInt(vec)
|
||||
}
|
||||
DataType::Int128 => {
|
||||
let vec = series
|
||||
.i64() // i64 will have to do
|
||||
.unwrap()
|
||||
.into_iter()
|
||||
.map(|opt| opt.map(|v| v as i128))
|
||||
.collect::<Option<Vec<_>>>()
|
||||
.unwrap();
|
||||
Gene::GeneVectorInt(vec)
|
||||
}
|
||||
DataType::UInt8 => {
|
||||
let vec = series
|
||||
.u8()
|
||||
.unwrap()
|
||||
.into_iter()
|
||||
.map(|opt| opt.map(|v| v as i128))
|
||||
.collect::<Option<Vec<_>>>()
|
||||
.unwrap();
|
||||
Gene::GeneVectorInt(vec)
|
||||
}
|
||||
DataType::UInt16 => {
|
||||
let vec = series
|
||||
.u16()
|
||||
.unwrap()
|
||||
.into_iter()
|
||||
.map(|opt| opt.map(|v| v as i128))
|
||||
.collect::<Option<Vec<_>>>()
|
||||
.unwrap();
|
||||
Gene::GeneVectorInt(vec)
|
||||
}
|
||||
DataType::UInt32 => {
|
||||
let vec = series
|
||||
.u32()
|
||||
.unwrap()
|
||||
.into_iter()
|
||||
.map(|opt| opt.map(|v| v as i128))
|
||||
.collect::<Option<Vec<_>>>()
|
||||
.unwrap();
|
||||
Gene::GeneVectorInt(vec)
|
||||
}
|
||||
DataType::UInt64 => {
|
||||
let vec = series
|
||||
.u64()
|
||||
.unwrap()
|
||||
.into_iter()
|
||||
.map(|opt| opt.map(|v| v as i128))
|
||||
.collect::<Option<Vec<_>>>()
|
||||
.unwrap();
|
||||
Gene::GeneVectorInt(vec)
|
||||
}
|
||||
DataType::Float32 => {
|
||||
let vec = series
|
||||
.f32()
|
||||
.unwrap()
|
||||
.into_iter()
|
||||
.map(|opt| opt.map(|v| Decimal::from_f32(v).unwrap()))
|
||||
.collect::<Option<Vec<_>>>()
|
||||
.unwrap();
|
||||
Gene::GeneVectorFloat(vec)
|
||||
}
|
||||
DataType::Float64 => {
|
||||
let vec = series
|
||||
.f64()
|
||||
.unwrap()
|
||||
.into_iter()
|
||||
.map(|opt| opt.map(|v| Decimal::from_f64(v).unwrap()))
|
||||
.collect::<Option<Vec<_>>>()
|
||||
.unwrap();
|
||||
Gene::GeneVectorFloat(vec)
|
||||
}
|
||||
DataType::Boolean => {
|
||||
let vec = series
|
||||
.bool()
|
||||
.unwrap()
|
||||
.into_iter()
|
||||
.map(|opt| opt.map(|v| v as bool))
|
||||
.collect::<Option<Vec<_>>>()
|
||||
.unwrap();
|
||||
Gene::GeneVectorBoolean(vec)
|
||||
}
|
||||
DataType::String => {
|
||||
let vec = series
|
||||
.str()
|
||||
.unwrap()
|
||||
.into_iter()
|
||||
.map(|opt| opt.map(|v| v.chars().collect()))
|
||||
.collect::<Option<Vec<_>>>()
|
||||
.unwrap();
|
||||
Gene::GeneVectorString(vec)
|
||||
}
|
||||
_ => unimplemented!("Type {:?} not handled inside a vector", polars_value),
|
||||
},
|
||||
_ => unimplemented!("Type {:?} not handled", polars_value),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn random_instruction(
|
||||
instructions: Vec<Gene>,
|
||||
closing_type: ClosingType,
|
||||
rng: &mut impl Rng,
|
||||
) -> Gene {
|
||||
match closing_type {
|
||||
ClosingType::Specified => return instructions.choose(rng).unwrap().clone(),
|
||||
ClosingType::Balanced => {
|
||||
let source: Vec<Gene> = instructions
|
||||
.iter()
|
||||
.filter(|instr| !matches!(instr, Gene::Close))
|
||||
.cloned()
|
||||
.collect();
|
||||
let total_opens: usize = source
|
||||
.iter()
|
||||
.filter_map(|instr| {
|
||||
if let Gene::StateFunc(_) = instr {
|
||||
OPEN_MAP.get(instr).copied().map(|val| val as usize)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.sum();
|
||||
let p = if source.is_empty() {
|
||||
0.0
|
||||
} else {
|
||||
total_opens as f64 / source.len() as f64
|
||||
};
|
||||
// Return Close or a random instruction based on probability
|
||||
if rng.random::<f64>() < p {
|
||||
Gene::Close
|
||||
} else {
|
||||
source.choose(rng).unwrap().clone()
|
||||
}
|
||||
}
|
||||
ClosingType::None => {
|
||||
// Find multi-block instructions (those with opens > 1)
|
||||
let multi_block_instructions: Vec<Gene> = instructions
|
||||
.iter()
|
||||
.filter(|instr| {
|
||||
if let Gene::StateFunc(_) = instr {
|
||||
OPEN_MAP.get(instr).map_or(false, |&opens| opens > 1)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
})
|
||||
.cloned()
|
||||
.collect();
|
||||
|
||||
// Remove Close and multi-block instructions
|
||||
let source: Vec<Gene> = instructions
|
||||
.into_iter() // Take ownership of instructions
|
||||
.filter(|instr| {
|
||||
!matches!(instr, Gene::Close) && !multi_block_instructions.contains(instr)
|
||||
})
|
||||
.collect();
|
||||
|
||||
source.choose(rng).unwrap().clone()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn gaussian_noise_factor(rng: &mut impl Rng) -> Decimal {
|
||||
let u0f64: f64 = rng.random();
|
||||
let u1f64: f64 = rng.random();
|
||||
|
||||
let u0: Decimal = FromPrimitive::from_f64(u0f64).unwrap();
|
||||
let u1: Decimal = FromPrimitive::from_f64(u1f64).unwrap();
|
||||
|
||||
let u0 = if u0 == dec!(0.0) {
|
||||
FromPrimitive::from_f64(f64::EPSILON).unwrap()
|
||||
} else {
|
||||
u0
|
||||
};
|
||||
|
||||
(dec!(-2.0) * u0.ln()).sqrt().unwrap() * (dec!(2.0) * rust_decimal::Decimal::PI * u1).cos()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::instructions::code::*;
|
||||
use crate::instructions::common::boolean_rotate;
|
||||
use crate::instructions::vector::*;
|
||||
use crate::push::utils::most_genes;
|
||||
use rand::SeedableRng;
|
||||
use rand::rngs::StdRng;
|
||||
|
||||
#[test]
|
||||
fn random_instruction_test() {
|
||||
let mut rng = StdRng::seed_from_u64(42);
|
||||
let genes = most_genes();
|
||||
|
||||
let rand_instruction = random_instruction(genes.clone(), ClosingType::Specified, &mut rng);
|
||||
assert_eq!(
|
||||
Gene::StateFunc(vector_float_from_last_prim),
|
||||
rand_instruction
|
||||
);
|
||||
|
||||
let mut rng = StdRng::seed_from_u64(32038);
|
||||
let rand_instruction = random_instruction(genes.clone(), ClosingType::Balanced, &mut rng);
|
||||
assert_eq!(Gene::StateFunc(boolean_rotate), rand_instruction);
|
||||
|
||||
let mut rng = StdRng::seed_from_u64(3203890821);
|
||||
let rand_instruction = random_instruction(genes, ClosingType::None, &mut rng);
|
||||
assert_eq!(Gene::StateFunc(code_insert), rand_instruction);
|
||||
}
|
||||
}
|
@ -1,509 +0,0 @@
|
||||
use crate::gp::args::PushArgs;
|
||||
use crate::gp::individual::Individual;
|
||||
use crate::gp::selection::select_parent;
|
||||
use crate::gp::utils::gaussian_noise_factor;
|
||||
use crate::push::state::Gene;
|
||||
use rand::Rng;
|
||||
use rust_decimal::Decimal;
|
||||
use rust_decimal::prelude::ToPrimitive;
|
||||
use std::collections::HashMap;
|
||||
use std::iter::zip;
|
||||
|
||||
use super::args::ClosingType;
|
||||
use super::utils::random_instruction;
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Hash)]
|
||||
pub enum Variation {
|
||||
Crossover,
|
||||
Alternation,
|
||||
TailAlignedCrossover,
|
||||
UniformAddition,
|
||||
UniformReplacement,
|
||||
UniformDeletion,
|
||||
Reproduction,
|
||||
UMAD,
|
||||
}
|
||||
|
||||
fn crossover(plushy0: Vec<Gene>, plushy1: Vec<Gene>, mut rng: impl Rng) -> Vec<Gene> {
|
||||
let mut shorter: Vec<Gene>;
|
||||
let longer: Vec<Gene>;
|
||||
let mut new_plushy: Vec<Gene> = vec![];
|
||||
|
||||
if plushy0.len() >= plushy1.len() {
|
||||
shorter = plushy1;
|
||||
longer = plushy0;
|
||||
} else {
|
||||
shorter = plushy0;
|
||||
longer = plushy1;
|
||||
}
|
||||
|
||||
for _ in 0..(longer.len() - shorter.len()) {
|
||||
shorter.push(Gene::CrossoverPadding)
|
||||
}
|
||||
|
||||
// Add genes here
|
||||
for (sgene, lgene) in zip(shorter, longer) {
|
||||
if rng.random_range(0..=99) < 50 {
|
||||
new_plushy.push(sgene)
|
||||
} else {
|
||||
new_plushy.push(lgene)
|
||||
}
|
||||
}
|
||||
|
||||
new_plushy
|
||||
.into_iter()
|
||||
.filter(|gene| !matches!(gene, Gene::CrossoverPadding))
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn tail_aligned_crossover(plushy0: Vec<Gene>, plushy1: Vec<Gene>, mut rng: impl Rng) -> Vec<Gene> {
|
||||
let mut shorter: Vec<Gene>;
|
||||
let longer: Vec<Gene>;
|
||||
let mut new_plushy: Vec<Gene> = vec![];
|
||||
|
||||
if plushy0.len() >= plushy1.len() {
|
||||
shorter = plushy1;
|
||||
longer = plushy0;
|
||||
} else {
|
||||
shorter = plushy0;
|
||||
longer = plushy1;
|
||||
}
|
||||
|
||||
for _ in 0..(longer.len() - shorter.len()) {
|
||||
shorter.insert(0, Gene::CrossoverPadding)
|
||||
}
|
||||
|
||||
// Add genes here
|
||||
for (sgene, lgene) in zip(shorter, longer) {
|
||||
if rng.random_range(0..=99) < 50 {
|
||||
new_plushy.push(sgene)
|
||||
} else {
|
||||
new_plushy.push(lgene)
|
||||
}
|
||||
}
|
||||
|
||||
new_plushy
|
||||
.into_iter()
|
||||
.filter(|gene| !matches!(gene, Gene::CrossoverPadding))
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn alternation(
|
||||
plushy0: Vec<Gene>,
|
||||
plushy1: Vec<Gene>,
|
||||
alternation_rate: usize,
|
||||
alignment_deviation: Decimal,
|
||||
mut rng: impl Rng,
|
||||
) -> Vec<Gene> {
|
||||
let mut use_plushy0: bool = true;
|
||||
let mut result_plushy: Vec<Gene> = vec![];
|
||||
let mut iteration_budget = plushy0.len() + plushy1.len();
|
||||
let mut n: i128 = 0;
|
||||
loop {
|
||||
if use_plushy0 {
|
||||
if n >= plushy0.len() as i128 {
|
||||
return result_plushy;
|
||||
}
|
||||
} else {
|
||||
if n >= plushy1.len() as i128 {
|
||||
return result_plushy;
|
||||
}
|
||||
}
|
||||
if iteration_budget <= 0 {
|
||||
return result_plushy;
|
||||
}
|
||||
if rng.random_range(0..=99) < alternation_rate {
|
||||
let pre_usize = alignment_deviation * gaussian_noise_factor(&mut rng);
|
||||
n = 0i128.max(n + ToPrimitive::to_i128(&(pre_usize).round()).unwrap());
|
||||
use_plushy0 = !use_plushy0;
|
||||
} else {
|
||||
result_plushy.push(if use_plushy0 {
|
||||
plushy0[n as usize].clone()
|
||||
} else {
|
||||
plushy1[n as usize].clone()
|
||||
});
|
||||
n += 1;
|
||||
}
|
||||
iteration_budget -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
fn uniform_addition(
|
||||
plushy: Vec<Gene>,
|
||||
instructions: Vec<Gene>,
|
||||
umad_rate: f64,
|
||||
closing_type: ClosingType,
|
||||
rng: &mut impl Rng,
|
||||
) -> Vec<Gene> {
|
||||
let mut new_plushy: Vec<Gene> = vec![];
|
||||
|
||||
for gene in plushy {
|
||||
if rng.random::<f64>() < umad_rate {
|
||||
let new_instruction = random_instruction(instructions.clone(), closing_type, rng);
|
||||
|
||||
// Randomly decide order (original first or new first)
|
||||
if rng.random::<bool>() {
|
||||
new_plushy.push(gene);
|
||||
new_plushy.push(new_instruction);
|
||||
} else {
|
||||
new_plushy.push(new_instruction);
|
||||
new_plushy.push(gene);
|
||||
}
|
||||
} else {
|
||||
new_plushy.push(gene);
|
||||
}
|
||||
}
|
||||
|
||||
new_plushy
|
||||
}
|
||||
|
||||
fn uniform_replacement(
|
||||
plushy: Vec<Gene>,
|
||||
instructions: Vec<Gene>,
|
||||
replacement_rate: f64,
|
||||
closing_type: ClosingType,
|
||||
rng: &mut impl Rng,
|
||||
) -> Vec<Gene> {
|
||||
plushy
|
||||
.into_iter()
|
||||
.map(|gene| {
|
||||
if rng.random::<f64>() < replacement_rate {
|
||||
// Replace with random instruction
|
||||
random_instruction(instructions.to_vec(), closing_type, rng)
|
||||
} else {
|
||||
// Keep original gene
|
||||
gene
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn uniform_deletion(plushy: Vec<Gene>, umad_rate: f64, rng: &mut impl Rng) -> Vec<Gene> {
|
||||
// If umad_rate is zero, return the original vector
|
||||
if umad_rate == 0.0 {
|
||||
return plushy;
|
||||
}
|
||||
|
||||
// Calculate the adjusted deletion rate
|
||||
let adjusted_rate = 1.0 / (1.0 + (1.0 / umad_rate));
|
||||
|
||||
// Filter the vector, keeping items that are either Gene::Skip or pass the random test
|
||||
plushy
|
||||
.into_iter()
|
||||
.filter(|_| rng.random::<f64>() >= adjusted_rate)
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Selects a variation operator based on the probabilities
|
||||
fn select_variation_op(variation_ops: &HashMap<Variation, f64>, r: f64) -> Variation {
|
||||
let mut accum = 0.0;
|
||||
|
||||
for (op, prob) in variation_ops {
|
||||
accum += prob;
|
||||
if accum >= r {
|
||||
return op.clone();
|
||||
}
|
||||
}
|
||||
|
||||
// Default to reproduction if no match (or probabilities don't sum to 1.0)
|
||||
Variation::Reproduction
|
||||
}
|
||||
|
||||
/// Creates a new individual based on an argmap variation
|
||||
pub fn new_individual(pop: Vec<Individual>, argmap: &PushArgs, rng: &mut impl Rng) -> Individual {
|
||||
// Select variation operator based on probabilities
|
||||
let r = rng.random::<f64>();
|
||||
let op = select_variation_op(&argmap.variation, r);
|
||||
|
||||
let plushy = match op {
|
||||
Variation::Crossover => {
|
||||
let parent1 = select_parent(pop.clone(), argmap, rng);
|
||||
let parent2 = select_parent(pop, argmap, rng);
|
||||
crossover(parent1.plushy, parent2.plushy, rng)
|
||||
}
|
||||
|
||||
Variation::TailAlignedCrossover => {
|
||||
let parent1 = select_parent(pop.clone(), argmap, rng);
|
||||
let parent2 = select_parent(pop, argmap, rng);
|
||||
tail_aligned_crossover(parent1.plushy, parent2.plushy, rng)
|
||||
}
|
||||
|
||||
Variation::UniformAddition => {
|
||||
let parent = select_parent(pop, argmap, rng);
|
||||
uniform_addition(
|
||||
parent.plushy.clone(),
|
||||
argmap
|
||||
.instructions
|
||||
.clone()
|
||||
.expect("Must provide instructions"),
|
||||
argmap.umad_rate,
|
||||
argmap.closes,
|
||||
rng,
|
||||
)
|
||||
}
|
||||
|
||||
Variation::UniformReplacement => {
|
||||
let parent = select_parent(pop, argmap, rng);
|
||||
uniform_replacement(
|
||||
parent.plushy.clone(),
|
||||
argmap
|
||||
.instructions
|
||||
.clone()
|
||||
.expect("Must provide instructions!"),
|
||||
argmap.replacement_rate,
|
||||
argmap.closes,
|
||||
rng,
|
||||
)
|
||||
}
|
||||
|
||||
Variation::UniformDeletion => {
|
||||
let parent = select_parent(pop, argmap, rng);
|
||||
uniform_deletion(parent.plushy.clone(), argmap.umad_rate, rng)
|
||||
}
|
||||
|
||||
Variation::Alternation => {
|
||||
let parent1 = select_parent(pop.clone(), argmap, rng);
|
||||
let parent2 = select_parent(pop, argmap, rng);
|
||||
alternation(
|
||||
parent1.plushy,
|
||||
parent2.plushy,
|
||||
argmap.alternation_rate,
|
||||
argmap.alignment_deviation,
|
||||
rng,
|
||||
)
|
||||
}
|
||||
|
||||
Variation::UMAD => {
|
||||
let parent = select_parent(pop, argmap, rng);
|
||||
let parent_plushy = parent.plushy.clone();
|
||||
|
||||
// Apply uniform addition followed by uniform deletion
|
||||
let after_addition = uniform_addition(
|
||||
parent_plushy,
|
||||
argmap
|
||||
.instructions
|
||||
.clone()
|
||||
.expect("Must provide instructions"),
|
||||
argmap.umad_rate,
|
||||
argmap.closes,
|
||||
rng,
|
||||
);
|
||||
|
||||
uniform_deletion(after_addition, argmap.umad_rate, rng)
|
||||
}
|
||||
|
||||
Variation::Reproduction => {
|
||||
let parent = select_parent(pop, argmap, rng);
|
||||
parent.plushy.clone()
|
||||
}
|
||||
};
|
||||
|
||||
Individual {
|
||||
plushy,
|
||||
total_fitness: None,
|
||||
fitness_cases: None,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::instructions::common::*;
|
||||
use crate::instructions::numeric::*;
|
||||
use crate::instructions::vector::*;
|
||||
use crate::push::state::Gene;
|
||||
use crate::push::utils::most_genes;
|
||||
use rand::SeedableRng;
|
||||
use rand::rngs::StdRng;
|
||||
use rust_decimal::dec;
|
||||
|
||||
#[test]
|
||||
fn crossover_test() {
|
||||
let rng = StdRng::seed_from_u64(42);
|
||||
let plushy0 = vec![
|
||||
Gene::StateFunc(exec_swap),
|
||||
Gene::StateFunc(float_tan),
|
||||
Gene::StateFunc(int_pop),
|
||||
Gene::Close,
|
||||
Gene::StateFunc(exec_flush),
|
||||
Gene::Close,
|
||||
Gene::StateFunc(boolean_pop),
|
||||
Gene::StateFunc(vector_int_swap),
|
||||
Gene::StateFunc(vector_char_pop),
|
||||
];
|
||||
let plushy1 = vec![
|
||||
Gene::StateFunc(string_swap),
|
||||
Gene::StateFunc(float_arctan),
|
||||
Gene::StateFunc(char_pop),
|
||||
Gene::GeneChar('a'),
|
||||
Gene::StateFunc(code_flush),
|
||||
Gene::GeneInt(1),
|
||||
Gene::StateFunc(float_pop),
|
||||
];
|
||||
let res_plushy = crossover(plushy0, plushy1, rng);
|
||||
assert_eq!(
|
||||
vec![
|
||||
Gene::StateFunc(string_swap),
|
||||
Gene::StateFunc(float_tan),
|
||||
Gene::StateFunc(char_pop),
|
||||
Gene::Close,
|
||||
Gene::StateFunc(exec_flush),
|
||||
Gene::Close,
|
||||
Gene::StateFunc(boolean_pop),
|
||||
Gene::StateFunc(vector_char_pop),
|
||||
],
|
||||
res_plushy
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tail_aligned_crossover_test() {
|
||||
let rng = StdRng::seed_from_u64(42);
|
||||
let plushy0 = vec![
|
||||
Gene::StateFunc(exec_swap),
|
||||
Gene::StateFunc(float_tan),
|
||||
Gene::StateFunc(int_pop),
|
||||
Gene::Close,
|
||||
Gene::StateFunc(exec_flush),
|
||||
Gene::Close,
|
||||
Gene::StateFunc(boolean_pop),
|
||||
Gene::StateFunc(vector_int_swap),
|
||||
Gene::StateFunc(vector_char_pop),
|
||||
];
|
||||
let plushy1 = vec![
|
||||
Gene::StateFunc(string_swap),
|
||||
Gene::StateFunc(float_arctan),
|
||||
Gene::StateFunc(char_pop),
|
||||
Gene::GeneChar('a'),
|
||||
Gene::StateFunc(code_flush),
|
||||
Gene::GeneInt(1),
|
||||
Gene::StateFunc(float_pop),
|
||||
];
|
||||
let res_plushy = tail_aligned_crossover(plushy0, plushy1, rng);
|
||||
assert_eq!(
|
||||
vec![
|
||||
Gene::StateFunc(float_tan),
|
||||
Gene::StateFunc(string_swap),
|
||||
Gene::Close,
|
||||
Gene::StateFunc(exec_flush),
|
||||
Gene::Close,
|
||||
Gene::StateFunc(boolean_pop),
|
||||
Gene::GeneInt(1),
|
||||
Gene::StateFunc(vector_char_pop),
|
||||
],
|
||||
res_plushy
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn alternation_test() {
|
||||
let rng = StdRng::seed_from_u64(42);
|
||||
let plushy0 = vec![
|
||||
Gene::StateFunc(exec_swap),
|
||||
Gene::StateFunc(float_tan),
|
||||
Gene::StateFunc(int_pop),
|
||||
Gene::Close,
|
||||
Gene::StateFunc(exec_flush),
|
||||
Gene::Close,
|
||||
Gene::StateFunc(boolean_pop),
|
||||
Gene::StateFunc(vector_int_swap),
|
||||
Gene::StateFunc(vector_char_pop),
|
||||
];
|
||||
let plushy1 = vec![
|
||||
Gene::StateFunc(string_swap),
|
||||
Gene::StateFunc(float_arctan),
|
||||
Gene::StateFunc(char_pop),
|
||||
Gene::GeneChar('a'),
|
||||
Gene::StateFunc(code_flush),
|
||||
Gene::GeneInt(1),
|
||||
Gene::StateFunc(float_pop),
|
||||
];
|
||||
let res_plushy = alternation(plushy0, plushy1, 50, dec!(2.0), rng);
|
||||
assert_eq!(
|
||||
vec![
|
||||
Gene::StateFunc(char_pop),
|
||||
Gene::GeneChar('a'),
|
||||
Gene::StateFunc(boolean_pop),
|
||||
Gene::StateFunc(vector_int_swap),
|
||||
Gene::StateFunc(vector_char_pop),
|
||||
],
|
||||
res_plushy
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn uniform_addition_test() {
|
||||
let mut rng = StdRng::seed_from_u64(42);
|
||||
let plushy0 = vec![
|
||||
Gene::StateFunc(exec_swap),
|
||||
Gene::StateFunc(float_tan),
|
||||
Gene::StateFunc(int_pop),
|
||||
Gene::Close,
|
||||
];
|
||||
let res_plushy =
|
||||
uniform_addition(plushy0, most_genes(), 0.75, ClosingType::Balanced, &mut rng);
|
||||
assert_eq!(
|
||||
vec![
|
||||
Gene::StateFunc(exec_swap),
|
||||
Gene::StateFunc(float_min),
|
||||
Gene::StateFunc(float_tan),
|
||||
Gene::Close,
|
||||
Gene::StateFunc(int_pop),
|
||||
Gene::StateFunc(int_yank_dup),
|
||||
Gene::Close,
|
||||
Gene::StateFunc(float_is_empty),
|
||||
],
|
||||
res_plushy
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn uniform_replacement_test() {
|
||||
let mut rng = StdRng::seed_from_u64(42);
|
||||
let plushy0 = vec![
|
||||
Gene::StateFunc(exec_swap),
|
||||
Gene::StateFunc(float_tan),
|
||||
Gene::StateFunc(int_pop),
|
||||
Gene::Close,
|
||||
Gene::Close,
|
||||
Gene::GeneInt(1),
|
||||
];
|
||||
let res_plushy =
|
||||
uniform_replacement(plushy0, most_genes(), 0.5, ClosingType::Balanced, &mut rng);
|
||||
assert_eq!(
|
||||
vec![
|
||||
Gene::StateFunc(exec_swap),
|
||||
Gene::StateFunc(float_tan),
|
||||
Gene::StateFunc(int_pop),
|
||||
Gene::Close,
|
||||
Gene::StateFunc(vector_float_sort_reverse),
|
||||
Gene::GeneInt(1),
|
||||
],
|
||||
res_plushy
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn uniform_deletion_test() {
|
||||
let mut rng = StdRng::seed_from_u64(42);
|
||||
let plushy0 = vec![
|
||||
Gene::StateFunc(exec_swap),
|
||||
Gene::StateFunc(float_tan),
|
||||
Gene::StateFunc(int_pop),
|
||||
Gene::Close,
|
||||
Gene::Close,
|
||||
Gene::GeneInt(1),
|
||||
];
|
||||
let res_plushy = uniform_deletion(plushy0, 0.5, &mut rng);
|
||||
assert_eq!(
|
||||
vec![
|
||||
Gene::StateFunc(exec_swap),
|
||||
Gene::StateFunc(float_tan),
|
||||
Gene::StateFunc(int_pop),
|
||||
Gene::Close,
|
||||
Gene::GeneInt(1),
|
||||
],
|
||||
res_plushy
|
||||
);
|
||||
}
|
||||
}
|
@ -1,10 +1,15 @@
|
||||
use super::common::{code_from_exec, code_pop, int_pop};
|
||||
use crate::push::state::{Gene, PushState};
|
||||
use std::ops::Not;
|
||||
|
||||
use crate::push::state::{Gene, PushState};
|
||||
|
||||
use super::common::{code_from_exec, code_pop, int_pop};
|
||||
|
||||
/// Checks to see if a single gene is a block.
|
||||
fn _is_block(a: Gene) -> Option<bool> {
|
||||
Some(matches!(a, Gene::Block(_)))
|
||||
Some(match a {
|
||||
Gene::Block(_) => true,
|
||||
_ => false,
|
||||
})
|
||||
}
|
||||
|
||||
/// Checks to see if a single gene is not a block.
|
||||
@ -316,7 +321,7 @@ pub fn code_map(state: &mut PushState) {
|
||||
|
||||
/// If top bool is true, execute top element of code/exec stack and skip the second.
|
||||
/// If false, execute second element and skip the top.
|
||||
fn _if(a: Gene, b: Gene, cond: bool) -> Option<Gene> {
|
||||
pub fn _if(a: Gene, b: Gene, cond: bool) -> Option<Gene> {
|
||||
Some(if cond { a } else { b })
|
||||
}
|
||||
|
||||
@ -344,7 +349,7 @@ pub fn exec_when(state: &mut PushState) {
|
||||
|
||||
/// Pushes true if the second code item is found within the first item.
|
||||
/// If the first item isn't a block, coerced into one.
|
||||
fn _member(a: Gene, b: Gene) -> Option<bool> {
|
||||
pub fn _member(a: Gene, b: Gene) -> Option<bool> {
|
||||
let block = match b {
|
||||
Gene::Block(val) => val,
|
||||
val => vec![val],
|
||||
@ -355,7 +360,7 @@ fn _member(a: Gene, b: Gene) -> Option<bool> {
|
||||
|
||||
/// Pushes the nth item of the top element of the code stack.
|
||||
/// If top code item isn't a block, wrap one around it.
|
||||
fn _nth(a: Gene, idx: i128) -> Option<Gene> {
|
||||
pub fn _nth(a: Gene, idx: i128) -> Option<Gene> {
|
||||
let gene_vec = match a {
|
||||
Gene::Block(val) => val,
|
||||
val => vec![val],
|
||||
@ -369,21 +374,27 @@ fn _nth(a: Gene, idx: i128) -> Option<Gene> {
|
||||
}
|
||||
|
||||
/// Pushes an empty block to the top of a stack.
|
||||
fn _make_empty_block<T>() -> Option<Gene> {
|
||||
pub fn _make_empty_block<T>() -> Option<Gene> {
|
||||
Some(Gene::Block(vec![]))
|
||||
}
|
||||
|
||||
/// Checks to see if the top item on the code/exec stack is an empty block.
|
||||
/// True if is, False if not.
|
||||
fn _is_empty_block(a: Gene) -> Option<bool> {
|
||||
pub fn _is_empty_block(a: Gene) -> Option<bool> {
|
||||
Some(match a {
|
||||
Gene::Block(val) => val.is_empty(),
|
||||
Gene::Block(val) => {
|
||||
if val.is_empty() {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
_ => false,
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns the size of the top item on the code/exec stack.
|
||||
fn _size(a: Gene) -> Option<i128> {
|
||||
pub fn _size(a: Gene) -> Option<i128> {
|
||||
Some(match a.clone() {
|
||||
Gene::Block(val) => val.len() as i128,
|
||||
_ => 1,
|
||||
@ -391,7 +402,7 @@ fn _size(a: Gene) -> Option<i128> {
|
||||
}
|
||||
|
||||
/// Returns a nested element inside a block based on an int.
|
||||
fn _extract(a: Gene, idx: i128) -> Option<Gene> {
|
||||
pub fn _extract(a: Gene, idx: i128) -> Option<Gene> {
|
||||
match &a {
|
||||
block @ Gene::Block(_) => {
|
||||
let block_len = block.rec_len();
|
||||
@ -409,7 +420,7 @@ fn _extract(a: Gene, idx: i128) -> Option<Gene> {
|
||||
/// Inserts a gene at a given position in into the top block based off an
|
||||
/// int from the top of the int stack. The top code item is coerced into a block
|
||||
/// if needed.
|
||||
fn _insert(a: Gene, b: Gene, idx: i128) -> Option<Gene> {
|
||||
pub fn _insert(a: Gene, b: Gene, idx: i128) -> Option<Gene> {
|
||||
let mut block = match a.clone() {
|
||||
iblock @ Gene::Block(_) => iblock,
|
||||
val => Gene::Block(vec![val]),
|
||||
@ -425,7 +436,7 @@ fn _insert(a: Gene, b: Gene, idx: i128) -> Option<Gene> {
|
||||
/// Pushes the first position of the 2nd code item within the top code item.
|
||||
/// If not found, pushes -1. If top code item isn't a block, returns 0 if top
|
||||
/// two code items equal, -1 otherwise.
|
||||
fn _first_position(a: Gene, b: Gene) -> Option<i128> {
|
||||
pub fn _first_position(a: Gene, b: Gene) -> Option<i128> {
|
||||
let bad_cond: bool = match &a {
|
||||
Gene::Block(val) => val.len() == 0,
|
||||
_ => true,
|
||||
@ -450,7 +461,7 @@ fn _first_position(a: Gene, b: Gene) -> Option<i128> {
|
||||
}
|
||||
|
||||
/// Reverses the top block. Does nothing if not a block.
|
||||
fn _reverse(a: Gene) -> Option<Gene> {
|
||||
pub fn _reverse(a: Gene) -> Option<Gene> {
|
||||
Some(match a {
|
||||
Gene::Block(mut val) => {
|
||||
val.reverse();
|
||||
@ -464,7 +475,7 @@ fn _reverse(a: Gene) -> Option<Gene> {
|
||||
macro_rules! noop {
|
||||
($stack:ident, $name:ident) => {
|
||||
paste::item! {
|
||||
pub fn [< $stack $name >] (_state: &mut PushState) {
|
||||
pub fn [< $stack $name >] (_: &mut PushState) {
|
||||
()
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
use crate::push::state::{Gene, PushState};
|
||||
use std::cmp::{max, min};
|
||||
|
||||
use crate::push::state::{Gene, PushState};
|
||||
|
||||
fn min_max_bounds(ndx: i128, length: usize) -> usize {
|
||||
max(0, min(ndx.unsigned_abs() as usize, length - 1))
|
||||
}
|
||||
@ -70,31 +71,31 @@ macro_rules! make_code {
|
||||
}
|
||||
|
||||
/// Duplicates an item
|
||||
fn _dup<T: Clone>(val: T) -> Option<Vec<T>> {
|
||||
pub fn _dup<T: Clone>(val: T) -> Option<Vec<T>> {
|
||||
Some(vec![val.clone(), val])
|
||||
}
|
||||
|
||||
fn _dup_times<T: Clone>(amt: i128, val: T) -> Option<Vec<T>> {
|
||||
pub fn _dup_times<T: Clone>(amt: i128, val: T) -> Option<Vec<T>> {
|
||||
Some(vec![val; amt as usize])
|
||||
}
|
||||
|
||||
/// Swaps two values
|
||||
fn _swap<T>(a: T, b: T) -> Option<Vec<T>> {
|
||||
pub fn _swap<T: Clone>(a: T, b: T) -> Option<Vec<T>> {
|
||||
Some(vec![a, b])
|
||||
}
|
||||
|
||||
/// Rotates three values
|
||||
fn _rotate<T>(a: T, b: T, c: T) -> Option<Vec<T>> {
|
||||
pub fn _rotate<T>(a: T, b: T, c: T) -> Option<Vec<T>> {
|
||||
Some(vec![c, a, b])
|
||||
}
|
||||
|
||||
/// Checks if two values are equal
|
||||
fn _equal<T: Eq>(a: T, b: T) -> Option<bool> {
|
||||
pub fn _equal<T: Eq>(a: T, b: T) -> Option<bool> {
|
||||
Some(b == a)
|
||||
}
|
||||
|
||||
/// Checks if two values are not equal
|
||||
fn _not_equal<T: Eq>(a: T, b: T) -> Option<bool> {
|
||||
pub fn _not_equal<T: Clone + Eq>(a: T, b: T) -> Option<bool> {
|
||||
Some(b != a)
|
||||
}
|
||||
|
||||
|
@ -1,609 +0,0 @@
|
||||
use crate::instructions::vector::*;
|
||||
use crate::instructions::code::*;
|
||||
use crate::instructions::numeric::*;
|
||||
use crate::instructions::logical::*;
|
||||
use crate::instructions::common::*;
|
||||
use crate::push::state::PushState;
|
||||
|
||||
pub fn vector_int_instructions() -> Vec<fn(&mut PushState)> {
|
||||
vec![
|
||||
vector_int_iterate,
|
||||
vector_int_concat,
|
||||
vector_int_conj,
|
||||
vector_int_conj_end,
|
||||
vector_int_take_n,
|
||||
vector_int_take_last_n,
|
||||
vector_int_sub,
|
||||
vector_int_first,
|
||||
vector_int_from_first_prim,
|
||||
vector_int_from_prim,
|
||||
vector_int_last,
|
||||
vector_int_from_last_prim,
|
||||
vector_int_nth,
|
||||
vector_int_from_nth_prim,
|
||||
vector_int_rest,
|
||||
vector_int_but_last,
|
||||
vector_int_drop,
|
||||
vector_int_drop_last,
|
||||
vector_int_length,
|
||||
vector_int_reverse,
|
||||
vector_int_push_all,
|
||||
vector_int_is_vector_empty,
|
||||
vector_int_contains,
|
||||
vector_int_contains_vector_non_contiguous,
|
||||
vector_int_contains_vector_contiguous,
|
||||
vector_int_index_of,
|
||||
vector_int_index_of_vector,
|
||||
vector_int_occurrences_of,
|
||||
vector_int_occurrences_of_vector,
|
||||
vector_int_parse_to_prim,
|
||||
vector_int_set_nth,
|
||||
vector_int_split_on,
|
||||
vector_int_replace,
|
||||
vector_int_remove,
|
||||
vector_int_insert,
|
||||
vector_int_insert_vector,
|
||||
vector_int_make_empty,
|
||||
vector_int_sort,
|
||||
vector_int_sort_reverse,
|
||||
vector_int_mean,
|
||||
vector_int_maximum,
|
||||
vector_int_minimum,
|
||||
vector_int_sum,
|
||||
vector_int_mode,
|
||||
vector_int_two_norm,
|
||||
vector_int_cumulative_sum,
|
||||
vector_int_pop,
|
||||
vector_int_dup,
|
||||
vector_int_dup_times,
|
||||
vector_int_swap,
|
||||
vector_int_rotate,
|
||||
vector_int_equal,
|
||||
vector_int_flush,
|
||||
vector_int_depth,
|
||||
vector_int_yank,
|
||||
vector_int_yank_dup,
|
||||
vector_int_shove,
|
||||
vector_int_shove_dup,
|
||||
vector_int_is_empty,
|
||||
]
|
||||
}
|
||||
|
||||
pub fn vector_float_instructions() -> Vec<fn(&mut PushState)> {
|
||||
vec![
|
||||
vector_float_iterate,
|
||||
vector_float_concat,
|
||||
vector_float_conj,
|
||||
vector_float_conj_end,
|
||||
vector_float_take_n,
|
||||
vector_float_take_last_n,
|
||||
vector_float_sub,
|
||||
vector_float_first,
|
||||
vector_float_from_first_prim,
|
||||
vector_float_from_prim,
|
||||
vector_float_last,
|
||||
vector_float_from_last_prim,
|
||||
vector_float_nth,
|
||||
vector_float_from_nth_prim,
|
||||
vector_float_rest,
|
||||
vector_float_but_last,
|
||||
vector_float_drop,
|
||||
vector_float_drop_last,
|
||||
vector_float_length,
|
||||
vector_float_reverse,
|
||||
vector_float_push_all,
|
||||
vector_float_is_vector_empty,
|
||||
vector_float_contains,
|
||||
vector_float_contains_vector_non_contiguous,
|
||||
vector_float_contains_vector_contiguous,
|
||||
vector_float_index_of,
|
||||
vector_float_index_of_vector,
|
||||
vector_float_occurrences_of,
|
||||
vector_float_occurrences_of_vector,
|
||||
vector_float_parse_to_prim,
|
||||
vector_float_set_nth,
|
||||
vector_float_split_on,
|
||||
vector_float_replace,
|
||||
vector_float_remove,
|
||||
vector_float_insert,
|
||||
vector_float_insert_vector,
|
||||
vector_float_make_empty,
|
||||
vector_float_sort,
|
||||
vector_float_sort_reverse,
|
||||
vector_float_mean,
|
||||
vector_float_maximum,
|
||||
vector_float_minimum,
|
||||
vector_float_sum,
|
||||
vector_float_mode,
|
||||
vector_float_two_norm,
|
||||
vector_float_cumulative_sum,
|
||||
vector_float_pop,
|
||||
vector_float_dup,
|
||||
vector_float_dup_times,
|
||||
vector_float_swap,
|
||||
vector_float_rotate,
|
||||
vector_float_equal,
|
||||
vector_float_flush,
|
||||
vector_float_depth,
|
||||
vector_float_yank,
|
||||
vector_float_yank_dup,
|
||||
vector_float_shove,
|
||||
vector_float_shove_dup,
|
||||
vector_float_is_empty,
|
||||
]
|
||||
}
|
||||
|
||||
pub fn vector_string_instructions() -> Vec<fn(&mut PushState)> {
|
||||
vec![
|
||||
vector_string_iterate,
|
||||
vector_string_concat,
|
||||
vector_string_conj,
|
||||
vector_string_conj_end,
|
||||
vector_string_take_n,
|
||||
vector_string_take_last_n,
|
||||
vector_string_sub,
|
||||
vector_string_first,
|
||||
vector_string_from_first_prim,
|
||||
vector_string_from_prim,
|
||||
vector_string_last,
|
||||
vector_string_from_last_prim,
|
||||
vector_string_nth,
|
||||
vector_string_from_nth_prim,
|
||||
vector_string_rest,
|
||||
vector_string_but_last,
|
||||
vector_string_drop,
|
||||
vector_string_drop_last,
|
||||
vector_string_length,
|
||||
vector_string_reverse,
|
||||
vector_string_push_all,
|
||||
vector_string_is_vector_empty,
|
||||
vector_string_contains,
|
||||
vector_string_contains_vector_non_contiguous,
|
||||
vector_string_contains_vector_contiguous,
|
||||
vector_string_index_of,
|
||||
vector_string_index_of_vector,
|
||||
vector_string_occurrences_of,
|
||||
vector_string_occurrences_of_vector,
|
||||
vector_string_parse_to_prim,
|
||||
vector_string_set_nth,
|
||||
vector_string_split_on,
|
||||
vector_string_replace,
|
||||
vector_string_remove,
|
||||
vector_string_insert,
|
||||
vector_string_insert_vector,
|
||||
vector_string_make_empty,
|
||||
vector_string_pop,
|
||||
vector_string_dup,
|
||||
vector_string_dup_times,
|
||||
vector_string_swap,
|
||||
vector_string_rotate,
|
||||
vector_string_equal,
|
||||
vector_string_flush,
|
||||
vector_string_depth,
|
||||
vector_string_yank,
|
||||
vector_string_yank_dup,
|
||||
vector_string_shove,
|
||||
vector_string_shove_dup,
|
||||
vector_string_is_empty,
|
||||
]
|
||||
}
|
||||
|
||||
pub fn vector_boolean_instructions() -> Vec<fn(&mut PushState)> {
|
||||
vec![
|
||||
vector_boolean_iterate,
|
||||
vector_boolean_concat,
|
||||
vector_boolean_conj,
|
||||
vector_boolean_conj_end,
|
||||
vector_boolean_take_n,
|
||||
vector_boolean_take_last_n,
|
||||
vector_boolean_sub,
|
||||
vector_boolean_first,
|
||||
vector_boolean_from_first_prim,
|
||||
vector_boolean_from_prim,
|
||||
vector_boolean_last,
|
||||
vector_boolean_from_last_prim,
|
||||
vector_boolean_nth,
|
||||
vector_boolean_from_nth_prim,
|
||||
vector_boolean_rest,
|
||||
vector_boolean_but_last,
|
||||
vector_boolean_drop,
|
||||
vector_boolean_drop_last,
|
||||
vector_boolean_length,
|
||||
vector_boolean_reverse,
|
||||
vector_boolean_push_all,
|
||||
vector_boolean_is_vector_empty,
|
||||
vector_boolean_contains,
|
||||
vector_boolean_contains_vector_non_contiguous,
|
||||
vector_boolean_contains_vector_contiguous,
|
||||
vector_boolean_index_of,
|
||||
vector_boolean_index_of_vector,
|
||||
vector_boolean_occurrences_of,
|
||||
vector_boolean_occurrences_of_vector,
|
||||
vector_boolean_parse_to_prim,
|
||||
vector_boolean_set_nth,
|
||||
vector_boolean_split_on,
|
||||
vector_boolean_replace,
|
||||
vector_boolean_remove,
|
||||
vector_boolean_insert,
|
||||
vector_boolean_insert_vector,
|
||||
vector_boolean_make_empty,
|
||||
vector_boolean_pop,
|
||||
vector_boolean_dup,
|
||||
vector_boolean_dup_times,
|
||||
vector_boolean_swap,
|
||||
vector_boolean_rotate,
|
||||
vector_boolean_equal,
|
||||
vector_boolean_flush,
|
||||
vector_boolean_depth,
|
||||
vector_boolean_yank,
|
||||
vector_boolean_yank_dup,
|
||||
vector_boolean_shove,
|
||||
vector_boolean_shove_dup,
|
||||
vector_boolean_is_empty,
|
||||
]
|
||||
}
|
||||
|
||||
pub fn vector_char_instructions() -> Vec<fn(&mut PushState)> {
|
||||
vec![
|
||||
vector_char_iterate,
|
||||
vector_char_concat,
|
||||
vector_char_conj,
|
||||
vector_char_conj_end,
|
||||
vector_char_take_n,
|
||||
vector_char_take_last_n,
|
||||
vector_char_sub,
|
||||
vector_char_first,
|
||||
vector_char_from_first_prim,
|
||||
vector_char_from_prim,
|
||||
vector_char_last,
|
||||
vector_char_from_last_prim,
|
||||
vector_char_nth,
|
||||
vector_char_from_nth_prim,
|
||||
vector_char_rest,
|
||||
vector_char_but_last,
|
||||
vector_char_drop,
|
||||
vector_char_drop_last,
|
||||
vector_char_length,
|
||||
vector_char_reverse,
|
||||
vector_char_push_all,
|
||||
vector_char_is_vector_empty,
|
||||
vector_char_contains,
|
||||
vector_char_contains_vector_non_contiguous,
|
||||
vector_char_contains_vector_contiguous,
|
||||
vector_char_index_of,
|
||||
vector_char_index_of_vector,
|
||||
vector_char_occurrences_of,
|
||||
vector_char_occurrences_of_vector,
|
||||
vector_char_parse_to_prim,
|
||||
vector_char_set_nth,
|
||||
vector_char_split_on,
|
||||
vector_char_replace,
|
||||
vector_char_remove,
|
||||
vector_char_insert,
|
||||
vector_char_insert_vector,
|
||||
vector_char_make_empty,
|
||||
vector_char_pop,
|
||||
vector_char_dup,
|
||||
vector_char_dup_times,
|
||||
vector_char_swap,
|
||||
vector_char_rotate,
|
||||
vector_char_equal,
|
||||
vector_char_flush,
|
||||
vector_char_depth,
|
||||
vector_char_yank,
|
||||
vector_char_yank_dup,
|
||||
vector_char_shove,
|
||||
vector_char_shove_dup,
|
||||
vector_char_is_empty,
|
||||
]
|
||||
}
|
||||
|
||||
pub fn string_instructions() -> Vec<fn(&mut PushState)> {
|
||||
vec![
|
||||
string_iterate,
|
||||
string_concat,
|
||||
string_conj,
|
||||
string_conj_end,
|
||||
string_take_n,
|
||||
string_take_last_n,
|
||||
string_sub,
|
||||
string_first,
|
||||
string_from_first_prim,
|
||||
string_from_prim,
|
||||
string_last,
|
||||
string_from_last_prim,
|
||||
string_nth,
|
||||
string_from_nth_prim,
|
||||
string_rest,
|
||||
string_but_last,
|
||||
string_drop,
|
||||
string_drop_last,
|
||||
string_length,
|
||||
string_reverse,
|
||||
string_push_all,
|
||||
string_is_vector_empty,
|
||||
string_contains,
|
||||
string_contains_vector_non_contiguous,
|
||||
string_contains_vector_contiguous,
|
||||
string_index_of,
|
||||
string_index_of_vector,
|
||||
string_occurrences_of,
|
||||
string_occurrences_of_vector,
|
||||
string_parse_to_prim,
|
||||
string_set_nth,
|
||||
string_split_on,
|
||||
string_replace,
|
||||
string_remove,
|
||||
string_insert,
|
||||
string_insert_vector,
|
||||
string_make_empty,
|
||||
string_pop,
|
||||
string_dup,
|
||||
string_dup_times,
|
||||
string_swap,
|
||||
string_rotate,
|
||||
string_equal,
|
||||
string_flush,
|
||||
string_depth,
|
||||
string_yank,
|
||||
string_yank_dup,
|
||||
string_shove,
|
||||
string_shove_dup,
|
||||
string_is_empty,
|
||||
]
|
||||
}
|
||||
|
||||
pub fn code_instructions() -> Vec<fn(&mut PushState)> {
|
||||
vec![
|
||||
code_do_then_pop,
|
||||
code_do_range,
|
||||
code_do_count,
|
||||
code_do_times,
|
||||
code_map,
|
||||
code_when,
|
||||
code_is_block,
|
||||
code_is_singular,
|
||||
code_length,
|
||||
code_first,
|
||||
code_last,
|
||||
code_rest,
|
||||
code_but_last,
|
||||
code_wrap_block,
|
||||
code_combine,
|
||||
code_if,
|
||||
code_member,
|
||||
code_nth,
|
||||
code_make_empty_block,
|
||||
code_is_empty_block,
|
||||
code_size,
|
||||
code_extract,
|
||||
code_insert,
|
||||
code_first_position,
|
||||
code_reverse,
|
||||
code_noop,
|
||||
code_noop_block,
|
||||
code_from_int,
|
||||
code_from_float,
|
||||
code_from_string,
|
||||
code_from_boolean,
|
||||
code_from_char,
|
||||
code_from_vector_int,
|
||||
code_from_vector_float,
|
||||
code_from_vector_string,
|
||||
code_from_vector_boolean,
|
||||
code_from_vector_char,
|
||||
code_pop,
|
||||
code_from_code,
|
||||
code_dup,
|
||||
code_dup_times,
|
||||
code_swap,
|
||||
code_rotate,
|
||||
code_equal,
|
||||
code_flush,
|
||||
code_depth,
|
||||
code_yank,
|
||||
code_yank_dup,
|
||||
code_shove,
|
||||
code_shove_dup,
|
||||
code_is_empty,
|
||||
code_from_exec,
|
||||
]
|
||||
}
|
||||
|
||||
pub fn exec_instructions() -> Vec<fn(&mut PushState)> {
|
||||
vec![
|
||||
exec_do_range,
|
||||
exec_do_count,
|
||||
exec_do_times,
|
||||
exec_while,
|
||||
exec_do_while,
|
||||
exec_when,
|
||||
exec_is_block,
|
||||
exec_is_singular,
|
||||
exec_length,
|
||||
exec_first,
|
||||
exec_last,
|
||||
exec_rest,
|
||||
exec_but_last,
|
||||
exec_wrap_block,
|
||||
exec_combine,
|
||||
exec_if,
|
||||
exec_member,
|
||||
exec_nth,
|
||||
exec_make_empty_block,
|
||||
exec_is_empty_block,
|
||||
exec_size,
|
||||
exec_extract,
|
||||
exec_insert,
|
||||
exec_first_position,
|
||||
exec_reverse,
|
||||
exec_noop,
|
||||
exec_noop_block,
|
||||
exec_pop,
|
||||
exec_dup,
|
||||
exec_dup_times,
|
||||
exec_swap,
|
||||
exec_rotate,
|
||||
exec_equal,
|
||||
exec_flush,
|
||||
exec_depth,
|
||||
exec_yank,
|
||||
exec_yank_dup,
|
||||
exec_shove,
|
||||
exec_shove_dup,
|
||||
exec_is_empty,
|
||||
]
|
||||
}
|
||||
|
||||
pub fn int_instructions() -> Vec<fn(&mut PushState)> {
|
||||
vec![
|
||||
int_add,
|
||||
int_sub,
|
||||
int_mult,
|
||||
int_div,
|
||||
int_rem,
|
||||
int_max,
|
||||
int_min,
|
||||
int_inc,
|
||||
int_dec,
|
||||
int_lt,
|
||||
int_gt,
|
||||
int_lte,
|
||||
int_gte,
|
||||
int_sin,
|
||||
int_arcsin,
|
||||
int_cos,
|
||||
int_arccos,
|
||||
int_tan,
|
||||
int_arctan,
|
||||
int_from_boolean,
|
||||
int_log,
|
||||
int_exp,
|
||||
int_sqrt,
|
||||
int_inv,
|
||||
int_abs,
|
||||
int_sign_reverse,
|
||||
int_square,
|
||||
int_from_float,
|
||||
int_pop,
|
||||
int_dup,
|
||||
int_dup_times,
|
||||
int_swap,
|
||||
int_rotate,
|
||||
int_equal,
|
||||
int_flush,
|
||||
int_depth,
|
||||
int_yank,
|
||||
int_yank_dup,
|
||||
int_shove,
|
||||
int_shove_dup,
|
||||
int_is_empty,
|
||||
]
|
||||
}
|
||||
|
||||
pub fn float_instructions() -> Vec<fn(&mut PushState)> {
|
||||
vec![
|
||||
float_add,
|
||||
float_sub,
|
||||
float_mult,
|
||||
float_div,
|
||||
float_rem,
|
||||
float_max,
|
||||
float_min,
|
||||
float_inc,
|
||||
float_dec,
|
||||
float_lt,
|
||||
float_gt,
|
||||
float_lte,
|
||||
float_gte,
|
||||
float_sin,
|
||||
float_arcsin,
|
||||
float_cos,
|
||||
float_arccos,
|
||||
float_tan,
|
||||
float_arctan,
|
||||
float_from_boolean,
|
||||
float_log,
|
||||
float_exp,
|
||||
float_sqrt,
|
||||
float_inv,
|
||||
float_abs,
|
||||
float_sign_reverse,
|
||||
float_square,
|
||||
float_from_int,
|
||||
float_pop,
|
||||
float_dup,
|
||||
float_dup_times,
|
||||
float_swap,
|
||||
float_rotate,
|
||||
float_equal,
|
||||
float_flush,
|
||||
float_depth,
|
||||
float_yank,
|
||||
float_yank_dup,
|
||||
float_shove,
|
||||
float_shove_dup,
|
||||
float_is_empty,
|
||||
]
|
||||
}
|
||||
|
||||
pub fn boolean_instructions() -> Vec<fn(&mut PushState)> {
|
||||
vec![
|
||||
boolean_and,
|
||||
boolean_or,
|
||||
boolean_not,
|
||||
boolean_xor,
|
||||
boolean_invert_first_then_and,
|
||||
boolean_invert_second_then_and,
|
||||
boolean_from_int,
|
||||
boolean_from_float,
|
||||
boolean_pop,
|
||||
boolean_dup,
|
||||
boolean_dup_times,
|
||||
boolean_swap,
|
||||
boolean_rotate,
|
||||
boolean_equal,
|
||||
boolean_flush,
|
||||
boolean_depth,
|
||||
boolean_yank,
|
||||
boolean_yank_dup,
|
||||
boolean_shove,
|
||||
boolean_shove_dup,
|
||||
boolean_is_empty,
|
||||
]
|
||||
}
|
||||
|
||||
pub fn char_instructions() -> Vec<fn(&mut PushState)> {
|
||||
vec![
|
||||
char_pop,
|
||||
char_dup,
|
||||
char_dup_times,
|
||||
char_swap,
|
||||
char_rotate,
|
||||
char_equal,
|
||||
char_flush,
|
||||
char_depth,
|
||||
char_yank,
|
||||
char_yank_dup,
|
||||
char_shove,
|
||||
char_shove_dup,
|
||||
char_is_empty,
|
||||
]
|
||||
}
|
||||
|
||||
pub fn all_instructions() -> Vec<fn(&mut PushState)> {
|
||||
let mut all_vec = vec![];
|
||||
all_vec.extend(vector_int_instructions().iter());
|
||||
all_vec.extend(vector_float_instructions().iter());
|
||||
all_vec.extend(vector_string_instructions().iter());
|
||||
all_vec.extend(vector_boolean_instructions().iter());
|
||||
all_vec.extend(vector_char_instructions().iter());
|
||||
all_vec.extend(string_instructions().iter());
|
||||
all_vec.extend(code_instructions().iter());
|
||||
all_vec.extend(exec_instructions().iter());
|
||||
all_vec.extend(int_instructions().iter());
|
||||
all_vec.extend(float_instructions().iter());
|
||||
all_vec.extend(boolean_instructions().iter());
|
||||
all_vec.extend(char_instructions().iter());
|
||||
all_vec
|
||||
}
|
@ -40,7 +40,6 @@ pub mod macros {
|
||||
|
||||
pub mod code;
|
||||
pub mod common;
|
||||
pub mod list;
|
||||
pub mod logical;
|
||||
pub mod numeric;
|
||||
pub mod utils;
|
||||
|
@ -219,7 +219,7 @@ fn _make_empty<T>() -> Option<Vec<T>> {
|
||||
}
|
||||
|
||||
/// Checks if a vector is empty. Pushes true if is, false otherwise
|
||||
fn _is_vector_empty<T>(vals: Vec<T>) -> Option<bool> {
|
||||
fn _is_empty<T>(vals: Vec<T>) -> Option<bool> {
|
||||
Some(vals.is_empty())
|
||||
}
|
||||
|
||||
@ -593,7 +593,7 @@ macro_rules! make_vector_instructions {
|
||||
make_instruction_new!(_reverse, $stack, $stack, $stack);
|
||||
make_instruction_new_aux!(_push_all, $stack, $prim_stack, $stack);
|
||||
// _make_empty would go here
|
||||
make_instruction_new!(_is_vector_empty, $stack, boolean, $stack);
|
||||
make_instruction_new!(_is_empty, $stack, boolean, $stack);
|
||||
make_instruction_new!(_contains, $stack, boolean, $stack, $prim_stack);
|
||||
make_instruction_new!(
|
||||
_contains_vector_non_contiguous,
|
||||
@ -1059,12 +1059,12 @@ mod tests {
|
||||
let empty_vec: Vec<i128> = vec![];
|
||||
|
||||
test_state.vector_int = vec![empty_vec.clone()];
|
||||
vector_int_is_vector_empty(&mut test_state);
|
||||
vector_int_is_empty(&mut test_state);
|
||||
assert_eq!(vec![true], test_state.boolean);
|
||||
test_state.boolean.clear();
|
||||
|
||||
test_state.vector_int = vec![vec![1, 2]];
|
||||
vector_int_is_vector_empty(&mut test_state);
|
||||
vector_int_is_empty(&mut test_state);
|
||||
assert_eq!(vec![false], test_state.boolean);
|
||||
}
|
||||
|
||||
|
@ -1,3 +1,2 @@
|
||||
pub mod gp;
|
||||
pub mod instructions;
|
||||
pub mod push;
|
||||
|
26
src/main.rs
26
src/main.rs
@ -1,32 +1,18 @@
|
||||
use crate::instructions::list::*;
|
||||
use crate::instructions::*;
|
||||
use crate::push::interpreter::interpret_program;
|
||||
use crate::push::state::EMPTY_STATE;
|
||||
use push::utils::most_genes;
|
||||
|
||||
mod instructions;
|
||||
mod push;
|
||||
|
||||
fn main() {
|
||||
let tvec = vec![1, 2, 3, 4, 5];
|
||||
println!("{:?}", tvec);
|
||||
|
||||
// These need to stay so linter doesn't go crazy.
|
||||
let mut empty_state = EMPTY_STATE;
|
||||
empty_state.int = vec![1, 2, 3];
|
||||
interpret_program(&mut empty_state, 1000, 1000);
|
||||
|
||||
int_instructions();
|
||||
float_instructions();
|
||||
string_instructions();
|
||||
boolean_instructions();
|
||||
char_instructions();
|
||||
vector_int_instructions();
|
||||
vector_float_instructions();
|
||||
vector_string_instructions();
|
||||
vector_boolean_instructions();
|
||||
vector_char_instructions();
|
||||
code_instructions();
|
||||
exec_instructions();
|
||||
all_instructions();
|
||||
most_genes();
|
||||
let mut counts: Vec<(&str, usize)> = vec![];
|
||||
counts.push(("int", 2));
|
||||
counts.push(("float", 1));
|
||||
|
||||
// counts.iter().map()
|
||||
}
|
||||
|
@ -19,16 +19,10 @@ pub fn gene_to_stack(state: &mut PushState, gene: Gene) {
|
||||
Gene::Block(x) => state.exec.extend(x.into_iter().rev()),
|
||||
Gene::Close => panic!("Close found in the exec stack, this should not happen!"),
|
||||
Gene::Open(_) => panic!("Open found in the exec stack, this should not happen!"),
|
||||
Gene::Skip => {
|
||||
state.exec.pop(); // Skip the next item by removing it.
|
||||
}
|
||||
Gene::Skip => panic!("Skip found in the exec stack, this should not happen!"),
|
||||
Gene::CrossoverPadding => {
|
||||
panic!("CrossoverPadding found in the exec stack, this should not happen!")
|
||||
}
|
||||
Gene::Place(idx) => {
|
||||
let var = state.input[idx].clone();
|
||||
state.exec.push(var)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,3 +1,2 @@
|
||||
pub mod interpreter;
|
||||
pub mod state;
|
||||
pub mod utils;
|
||||
|
@ -18,7 +18,6 @@ pub struct PushState {
|
||||
pub vector_char: Vec<Vec<char>>,
|
||||
pub exec: Vec<Gene>,
|
||||
pub code: Vec<Gene>,
|
||||
pub input: Vec<Gene>,
|
||||
}
|
||||
|
||||
pub const EMPTY_STATE: PushState = PushState {
|
||||
@ -34,10 +33,9 @@ pub const EMPTY_STATE: PushState = PushState {
|
||||
vector_char: vec![],
|
||||
exec: vec![],
|
||||
code: vec![],
|
||||
input: vec![],
|
||||
};
|
||||
|
||||
#[derive(PartialEq, Eq, Debug, Clone, Hash)]
|
||||
#[derive(PartialEq, Eq, Debug, Clone)]
|
||||
#[allow(dead_code)] // remove this later. Is here bc Close, Skip, CrossoverPadding
|
||||
pub enum Gene {
|
||||
GeneInt(i128),
|
||||
@ -56,7 +54,6 @@ pub enum Gene {
|
||||
Skip,
|
||||
Block(Vec<Gene>),
|
||||
CrossoverPadding,
|
||||
Place(usize),
|
||||
}
|
||||
|
||||
impl Gene {
|
||||
@ -132,13 +129,16 @@ impl Gene {
|
||||
val.insert(n, gene.clone());
|
||||
return true;
|
||||
}
|
||||
if let iblock @ Gene::Block(_) = el {
|
||||
// This line has side effects on iblock if inserts properly.
|
||||
let success = iblock.attempt_code_insert(gene.clone(), idx - 1);
|
||||
if success {
|
||||
return true;
|
||||
match el {
|
||||
iblock @ Gene::Block(_) => {
|
||||
// This line has side effects on iblock if inserts properly.
|
||||
let success = iblock.attempt_code_insert(gene.clone(), idx - 1);
|
||||
if success {
|
||||
return true;
|
||||
}
|
||||
idx -= iblock.rec_len() + 1
|
||||
}
|
||||
idx -= iblock.rec_len() + 1
|
||||
_ => (),
|
||||
}
|
||||
idx -= 1;
|
||||
}
|
||||
|
@ -1,12 +0,0 @@
|
||||
use crate::instructions::list::all_instructions;
|
||||
use crate::push::state::Gene;
|
||||
|
||||
pub fn most_genes() -> Vec<Gene> {
|
||||
let mut instructions: Vec<Gene> = all_instructions()
|
||||
.into_iter()
|
||||
.map(|x| Gene::StateFunc(x))
|
||||
.collect();
|
||||
instructions.push(Gene::Close);
|
||||
instructions.push(Gene::Skip);
|
||||
instructions
|
||||
}
|
@ -1,95 +0,0 @@
|
||||
use polars::prelude::*;
|
||||
use rush::gp::simplification::auto_simplify_plushy;
|
||||
use rush::gp::utils::polars_to_gene;
|
||||
use rush::instructions::numeric::*;
|
||||
use rush::push::interpreter::interpret_program;
|
||||
use rush::push::state::Gene;
|
||||
use rush::push::utils::most_genes;
|
||||
use rush::{gp::args::PushArgs, push::state::EMPTY_STATE};
|
||||
use rust_decimal::prelude::FromPrimitive;
|
||||
use rust_decimal::{Decimal, dec};
|
||||
|
||||
/// This is a prototype for an error function. I'm hoping to have some of this
|
||||
/// refined later.
|
||||
fn test_error_function(
|
||||
push_args: &PushArgs,
|
||||
data: &DataFrame,
|
||||
push_program: Vec<Gene>,
|
||||
) -> Vec<Decimal> {
|
||||
let mut error_vec: Vec<Decimal> = vec![];
|
||||
|
||||
let y = data
|
||||
.column("y")
|
||||
.unwrap()
|
||||
.i32()
|
||||
.unwrap()
|
||||
.into_iter()
|
||||
.map(|opt| opt.map(|v| v as i128))
|
||||
.collect::<Option<Vec<_>>>()
|
||||
.unwrap(); // How to convert a series to a vector everybody
|
||||
let x = data.drop("y").unwrap();
|
||||
|
||||
// println!("x: {x:#?}");
|
||||
// println!("y: {y:#?}");
|
||||
|
||||
for n in 0..x.height() {
|
||||
let mut state = EMPTY_STATE;
|
||||
let mut inputs: Vec<Gene> = Vec::with_capacity(x.width());
|
||||
let row = x.get_row(n).unwrap();
|
||||
for datum in row.0.iter() {
|
||||
inputs.push(polars_to_gene(datum))
|
||||
}
|
||||
state.exec.extend(push_program.clone().into_iter()); // load the program
|
||||
state.input.extend(inputs.clone().into_iter()); // Make inputs available to the state
|
||||
interpret_program(&mut state, push_args.step_limit, push_args.max_stack_size);
|
||||
if let Some(top_int) = state.int.pop() {
|
||||
error_vec.push(Decimal::from_i128((y[n] - top_int).abs()).unwrap());
|
||||
} else {
|
||||
error_vec.push(dec!(999999.0)) // super large error if no stack item.
|
||||
}
|
||||
}
|
||||
|
||||
// println!("{:?}", error_vec);
|
||||
error_vec
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn simplification_function_test() {
|
||||
let train_df: DataFrame = df!(
|
||||
"x0" => [4, 5, 6],
|
||||
"x1" => [7, 8, 9],
|
||||
"y" => [11, 13, 15],
|
||||
)
|
||||
.unwrap();
|
||||
println!("{}", train_df);
|
||||
// println!("{:#?}", train_df["x0"]);
|
||||
|
||||
// push program declaration
|
||||
let push_program: Vec<Gene> = vec![
|
||||
Gene::StateFunc(int_inc), // Should get simplified out
|
||||
Gene::StateFunc(float_tan), // along with all these float instructions
|
||||
Gene::StateFunc(float_sub),
|
||||
Gene::StateFunc(int_add), // stays
|
||||
Gene::StateFunc(float_tan),
|
||||
Gene::StateFunc(float_sub),
|
||||
Gene::StateFunc(float_rem),
|
||||
Gene::StateFunc(float_inc),
|
||||
Gene::Place(0), // stays
|
||||
Gene::Place(1), // stays
|
||||
];
|
||||
|
||||
let mut args = PushArgs::new();
|
||||
args.training_data = Some(train_df.clone());
|
||||
args.instructions = Some(most_genes());
|
||||
args.simplification_steps = 100;
|
||||
args.error_function = Some(test_error_function);
|
||||
|
||||
// test_error_function(&args, &train_df, push_program);
|
||||
|
||||
// test the auto simplification here
|
||||
let simplified_genome = auto_simplify_plushy(push_program, args.error_function.unwrap(), args);
|
||||
assert_eq!(
|
||||
vec![Gene::StateFunc(int_add), Gene::Place(0), Gene::Place(1)],
|
||||
simplified_genome
|
||||
)
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user