From 35d186cf0548c24ad7c4ac71c4e04c2d606c0e70 Mon Sep 17 00:00:00 2001 From: Rendo Date: Sun, 9 Nov 2025 15:43:03 +0500 Subject: [PATCH 1/3] Random mutations --- src/formula.rs | 4 +++- src/learner.rs | 20 +++++++++++++++++++- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/formula.rs b/src/formula.rs index c9e4833..eacd71a 100644 --- a/src/formula.rs +++ b/src/formula.rs @@ -22,11 +22,13 @@ impl Formula { } outputs } - pub fn mutate(&mut self) {} pub fn modify_tree(&mut self) -> NodeModifier { self.tree.modify_tree() } + pub fn modify_random_node(&mut self) -> NodeModifier { + self.tree.modify_node() + } pub fn display_tree(&self) { self.display_recursion(0, vec![&self.tree]); } diff --git a/src/learner.rs b/src/learner.rs index fb14647..d7d8dcc 100644 --- a/src/learner.rs +++ b/src/learner.rs @@ -1,4 +1,10 @@ use crate::formula::Formula; +use rand::random_range; + +const ACTION_ADD: u8 = 0; +const ACTION_REMOVE: u8 = 1; +const ACTION_INSERT: u8 = 2; +const ACTION_MUTATE: u8 = 3; pub struct Learner { best_algorithm: Formula, @@ -49,7 +55,19 @@ impl Learner { .0 .clone() } - fn mutate_formula_randomly(formula: &mut Formula) {} + fn mutate_formula_randomly(formula: &mut Formula) { + let mut editor = formula.modify_random_node(); + let decided_action = random_range(0..3); + if decided_action == ACTION_ADD { + editor.add_node(editor.get_random_node()); + } else if decided_action == ACTION_REMOVE { + editor.remove_node(None); + } else if decided_action == ACTION_INSERT { + editor.insert_node(editor.get_random_node(), None); + } else if decided_action == ACTION_MUTATE { + editor.mutate_node(); + } + } fn get_similarity(expected_output: &Vec, real_output: &Vec) -> Result { if expected_output.len() != real_output.len() { return Err(()); From a2f9c95c98e72d0460c0bb5dc773ff9f4741bab8 Mon Sep 17 00:00:00 2001 From: Rendo Date: Sun, 9 Nov 2025 15:53:23 +0500 Subject: [PATCH 2/3] I ain't happy --- src/learner.rs | 10 ++++++++-- src/main.rs | 12 ++++++++++-- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/learner.rs b/src/learner.rs index d7d8dcc..1a9f002 100644 --- a/src/learner.rs +++ b/src/learner.rs @@ -29,7 +29,13 @@ impl Learner { iterations: iterations.unwrap_or(200), } } - pub fn iterate(&self) -> Formula { + pub fn calculate_formula(&mut self) -> Formula { + for _ in 0..self.iterations { + self.best_algorithm = self.iterate() + } + self.best_algorithm.clone() + } + fn iterate(&self) -> Formula { let mut formulas: Vec<(Formula, f64)> = vec![]; for _ in 0..self.formulas_per_iteration { let mut formula = self.best_algorithm.clone(); @@ -68,7 +74,7 @@ impl Learner { editor.mutate_node(); } } - fn get_similarity(expected_output: &Vec, real_output: &Vec) -> Result { + pub fn get_similarity(expected_output: &Vec, real_output: &Vec) -> Result { if expected_output.len() != real_output.len() { return Err(()); } diff --git a/src/main.rs b/src/main.rs index 3aac0ff..797f633 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,8 +1,16 @@ -use crate::{formula::Formula, node::Node}; +use fapprox::learner::Learner; mod formula; mod node; #[cfg(test)] mod tests; -fn main() {} +fn main() { + let mut learner = Learner::new( + vec![0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10.], + vec![1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11.], + None, + None, + ); + println!("{:?}", learner.calculate_formula().as_text()); +} From b521356cc94a2dd759df8fb2f88b4b40e5f7d2a4 Mon Sep 17 00:00:00 2001 From: Rendo Date: Sun, 9 Nov 2025 16:23:24 +0500 Subject: [PATCH 3/3] it just works --- src/node/handler.rs | 10 +++++++++- src/node/mod.rs | 4 ++++ src/node/node_modifier/mod.rs | 13 +++++++++++++ 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/src/node/handler.rs b/src/node/handler.rs index 1c86bc4..fbb8802 100644 --- a/src/node/handler.rs +++ b/src/node/handler.rs @@ -7,6 +7,7 @@ pub enum NodeHandler { name: String, function: fn(Vec) -> f64, max_args: Option, + min_args: usize, }, Variable, Empty, @@ -20,7 +21,14 @@ impl NodeHandler { function, name, max_args, - } => function(inputs), + min_args, + } => { + if &inputs.len() >= min_args { + function(inputs) + } else { + 0. + } + } Self::Variable => passed_x, Self::Empty => inputs[0], } diff --git a/src/node/mod.rs b/src/node/mod.rs index c3bbfef..046369b 100644 --- a/src/node/mod.rs +++ b/src/node/mod.rs @@ -43,6 +43,7 @@ impl Node { func_name: String, func: fn(Vec) -> f64, max_children_count: Option, + min_arguments: usize, ) -> Self { Self { children: vec![], @@ -50,6 +51,7 @@ impl Node { name: func_name, function: func, max_args: max_children_count, + min_args: min_arguments, }, max_children_count, } @@ -93,6 +95,7 @@ impl Node { name, function, max_args, + min_args, } => name.clone() + "(" + children_text.as_str() + ")", NodeHandler::Empty => children_text, _ => self.to_string(), @@ -111,6 +114,7 @@ impl fmt::Display for Node { function, name, max_args, + min_args, } => name.clone(), NodeHandler::Variable => "X".to_string(), NodeHandler::Empty => "".to_string(), diff --git a/src/node/node_modifier/mod.rs b/src/node/node_modifier/mod.rs index f63442e..9a0007a 100644 --- a/src/node/node_modifier/mod.rs +++ b/src/node/node_modifier/mod.rs @@ -22,36 +22,43 @@ impl<'a> NodeModifier<'a> { name: "sin".to_string(), function: |inputs| inputs[0].sin(), max_args: Some(1), + min_args: 1, }, NodeHandler::Function { name: "cos".to_string(), function: |inputs| inputs[0].cos(), max_args: Some(1), + min_args: 1, }, NodeHandler::Function { name: "sum".to_string(), function: |inputs| inputs.iter().sum(), max_args: None, + min_args: 0, }, NodeHandler::Function { name: "-".to_string(), function: |inputs| -inputs[0], max_args: Some(1), + min_args: 1, }, NodeHandler::Function { name: "product".to_string(), function: |inputs| inputs.iter().product(), max_args: None, + min_args: 0, }, NodeHandler::Function { name: "exp".to_string(), function: |inputs| inputs[0].powf(inputs[1]), max_args: Some(2), + min_args: 2, }, NodeHandler::Function { name: "1/".to_string(), function: |inputs| 1f64 / inputs[0], max_args: Some(1), + min_args: 1, }, ]; let standard_number_mutation: Vec f64> = vec![ @@ -142,6 +149,9 @@ impl<'a> NodeModifier<'a> { } } let children_count = self.picked_node.children.len(); + if children_count <= 0 { + return Err(NodeManipulationError::NotEnoughChildren); + } let operated_index = between.unwrap_or(random_range(0..children_count)); let moved = self.picked_node.children.remove(operated_index); node.children.push(moved); @@ -167,6 +177,7 @@ impl<'a> NodeModifier<'a> { function, name, max_args, + min_args, } => { let selected_mutation = &self.function_mutation_pool [random_range(0..self.function_mutation_pool.len())]; @@ -174,6 +185,7 @@ impl<'a> NodeModifier<'a> { name, function, max_args, + min_args, } = &selected_mutation { self.picked_node.max_children_count = max_args.clone(); @@ -211,6 +223,7 @@ impl<'a> NodeModifier<'a> { name, function, max_args, + min_args, } => max_args, NodeHandler::Variable => Some(0), NodeHandler::Empty => Some(1),