progress on error function
Some checks failed
/ Test-Suite (push) Failing after 1m11s

This commit is contained in:
Rowan Torbitzky-Lane 2025-04-29 23:11:51 -05:00
parent 35ad71ffc3
commit f424a7bd3a
7 changed files with 177 additions and 24 deletions

View File

@ -1,3 +1,4 @@
use crate::gp::selection::Selection;
use crate::gp::variation::Variation;
use crate::push::state::Gene;
use polars::prelude::*;
@ -19,23 +20,58 @@ pub struct PushArgs {
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: fn(&PushArgs, &DataFrame, Vec<Gene>) -> Vec<Decimal>, // The error function
pub instructions: Vec<Gene>, // Instructions to use in a run
pub max_init_plushy_size: usize, // max initial plushy size
pub max_generations: usize, // Max amount of generations
pub parent_selection: usize, // 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 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_init_plushy_size: usize, // max initial plushy size
pub max_generations: usize, // Max amount of generations
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: DataFrame, // The testing data, must be formatted the same as training data
pub tournament_size: usize, // Tournament size for tournament selection
pub training_data: DataFrame, // The training data, must be formatted the same as testing data
pub umad_rate: f64, // addition rate (deletion rate derived) for UMAD
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_init_plushy_size: 100,
max_generations: 1000,
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,
}
}
}

View File

@ -2,6 +2,11 @@ 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,

View File

@ -53,7 +53,12 @@ where
);
}
let initial_errors = error_func(&push_args, &push_args.training_data, plushy.clone());
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;
@ -62,15 +67,23 @@ where
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, &push_args.training_data, new_plushy.clone());
let new_plushy_errors = error_func(&push_args, &training_data, new_plushy.clone());
if new_plushy_errors.iter().sum::<Decimal>() <= initial_errors.iter().sum() {
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
}

View File

@ -12,7 +12,7 @@ use std::iter::zip;
use super::args::ClosingType;
use super::utils::random_instruction;
#[derive(Clone)]
#[derive(Clone, PartialEq, Eq, Hash)]
pub enum Variation {
Crossover,
Alternation,
@ -21,6 +21,7 @@ pub enum Variation {
UniformReplacement,
UniformDeletion,
Reproduction,
UMAD,
}
fn crossover(plushy0: Vec<Gene>, plushy1: Vec<Gene>, mut rng: impl Rng) -> Vec<Gene> {
@ -132,13 +133,13 @@ fn uniform_addition(
instructions: Vec<Gene>,
umad_rate: f64,
closing_type: ClosingType,
mut rng: impl Rng,
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, &mut rng);
let new_instruction = random_instruction(instructions.clone(), closing_type, rng);
// Randomly decide order (original first or new first)
if rng.random::<bool>() {
@ -231,7 +232,10 @@ pub fn new_individual(pop: Vec<Individual>, argmap: &PushArgs, rng: &mut impl Rn
let parent = select_parent(pop, argmap, rng);
uniform_addition(
parent.plushy.clone(),
argmap.instructions.clone(),
argmap
.instructions
.clone()
.expect("Must provide instructions"),
argmap.umad_rate,
argmap.closes,
rng,
@ -242,7 +246,10 @@ pub fn new_individual(pop: Vec<Individual>, argmap: &PushArgs, rng: &mut impl Rn
let parent = select_parent(pop, argmap, rng);
uniform_replacement(
parent.plushy.clone(),
argmap.instructions.clone(),
argmap
.instructions
.clone()
.expect("Must provide instructions!"),
argmap.replacement_rate,
argmap.closes,
rng,
@ -266,6 +273,25 @@ pub fn new_individual(pop: Vec<Individual>, argmap: &PushArgs, rng: &mut impl Rn
)
}
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()
@ -407,14 +433,15 @@ mod tests {
#[test]
fn uniform_addition_test() {
let rng = StdRng::seed_from_u64(42);
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, rng);
let res_plushy =
uniform_addition(plushy0, most_genes(), 0.75, ClosingType::Balanced, &mut rng);
assert_eq!(
vec![
Gene::StateFunc(exec_swap),

View File

@ -19,7 +19,9 @@ 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 => panic!("Skip found in the exec stack, this should not happen!"),
Gene::Skip => {
state.exec.pop(); // Skip the next item by removing it.
}
Gene::CrossoverPadding => {
panic!("CrossoverPadding found in the exec stack, this should not happen!")
}

View File

@ -18,6 +18,7 @@ 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 {
@ -33,6 +34,7 @@ pub const EMPTY_STATE: PushState = PushState {
vector_char: vec![],
exec: vec![],
code: vec![],
input: vec![],
};
#[derive(PartialEq, Eq, Debug, Clone, Hash)]

View File

@ -0,0 +1,68 @@
use polars::prelude::*;
use rush::gp::args::PushArgs;
use rush::gp::simplification::auto_simplify_plushy;
use rush::instructions::numeric::*;
use rush::push::state::Gene;
use rush::push::utils::most_genes;
use rust_decimal::{Decimal, dec};
fn test_error_function(
_push_args: &PushArgs,
data: &DataFrame,
_push_program: Vec<Gene>,
) -> Vec<Decimal> {
let err_vec: Vec<Decimal> = vec![];
let y = data.column("y").unwrap();
let x = data.drop("y").unwrap();
// println!("x: {x:#?}");
// println!("y: {y:#?}");
for n in 0..x.height() {
let mut inputs: Vec<Gene> = Vec::with_capacity(x.width());
let row = x.get_row(n).unwrap();
for datum in row.0.iter() {
// println!("{:?}", val);
inputs.push(match datum {
&AnyValue::Int32(val) => Gene::GeneInt(val as i128),
_ => Gene::Close,
});
}
println!("{:?}", inputs);
inputs.clear();
}
vec![dec!(0.0)]
}
#[test]
fn simplification_function_test() {
let train_df: DataFrame = df!(
"x0" => [1, 2, 3],
"x1" => [7, 8, 9],
"y" => [8, 10, 12],
)
.unwrap();
println!("{}", train_df);
// println!("{:#?}", train_df["x0"]);
// push program declaration
let push_program: Vec<Gene> = vec![
Gene::StateFunc(float_tan),
Gene::StateFunc(float_sub),
Gene::StateFunc(int_add),
Gene::StateFunc(float_tan),
Gene::StateFunc(float_sub),
Gene::StateFunc(float_rem),
Gene::StateFunc(float_inc),
];
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);
}