diff --git a/docs/.configotron-whiteboard.autosave.xopp b/docs/.configotron-whiteboard.autosave.xopp deleted file mode 100644 index b521613..0000000 Binary files a/docs/.configotron-whiteboard.autosave.xopp and /dev/null differ diff --git a/docs/configotron-whiteboard.xopp b/docs/configotron-whiteboard.xopp index 45d33e2..ca8c0cb 100644 Binary files a/docs/configotron-whiteboard.xopp and b/docs/configotron-whiteboard.xopp differ diff --git a/src/configotron/fsm/builder/numbers.rs b/src/configotron/fsm/builder/numbers.rs index 075eac6..d5a7738 100644 --- a/src/configotron/fsm/builder/numbers.rs +++ b/src/configotron/fsm/builder/numbers.rs @@ -1,6 +1,6 @@ use std::{rc::Rc}; -use crate::configotron::fsm::{builder::elimate_unused_states, masking::{MaskPresets, TransitionMask}, new_state_ref, transition::FSMTranistion, FSMState, FSMStateAction, FSMStateRef}; +use crate::{configotron::fsm::{builder::elimate_unused_states, masking::{MaskPresets, TransitionMask}, new_state_ref, transition::FSMTranistion, FSMState, FSMStateAction, FSMStateRef}, main}; use super::super::FSM; @@ -27,8 +27,8 @@ fn nth_decimal_digit(num: u32, n: u32) -> u32 { (num / divisor) % 10 } -fn create_fsm_number_upperbound(max: u32) -> FSM { - let length_of_number = number_of_digits(max as i32); +fn create_fsm_number_scafold(n: u32) -> (Vec, Vec, FSMStateRef, FSMStateRef) { + let length_of_number = number_of_digits(n as i32); // Creating All states let error_state = new_state_ref(FSMState::new("e".to_string(), FSMStateAction::Error)); @@ -39,15 +39,22 @@ fn create_fsm_number_upperbound(max: u32) -> FSM { // Create and Link Main to side for i in 0..length_of_number { - let digit = nth_decimal_digit(max, i); + let digit = nth_decimal_digit(n, i); let new_main_state = new_state_ref(FSMState::new( - format!("m{}", i), FSMStateAction::Terminal)); + format!("m{}", i), FSMStateAction::None)); let new_side_state = new_state_ref(FSMState::new( - format!("s{}", i), FSMStateAction::Terminal)); - + format!("s{}", i), FSMStateAction::None)); + + // Main -> Error let mut main_state_transition = FSMTranistion::new(Rc::downgrade(&error_state)); + // Side -> Error + new_side_state.borrow_mut().set_transitions( + FSMTranistion::new(Rc::downgrade(&error_state)) + ); + + // Main -> Side (-) Transition [0..n-1] if digit > 0 { main_state_transition.apply(TransitionMask::from(MaskPresets::NumberRange(0..=(digit as u8 - 1))), Rc::downgrade(&new_side_state)); } @@ -56,14 +63,11 @@ fn create_fsm_number_upperbound(max: u32) -> FSM { main_state_transition ); - new_side_state.borrow_mut().set_transitions( - FSMTranistion::new(Rc::downgrade(&error_state)) - ); - main_line.push(new_main_state.clone()); - side_line.push(new_side_state.clone()); + side_line.push(new_side_state.clone()); }; + // Link Main to main, side to side for (i, ( @@ -74,19 +78,20 @@ fn create_fsm_number_upperbound(max: u32) -> FSM { main_line.iter().zip(main_line.iter().skip(1)) .zip(side_line.iter().zip(side_line.iter().skip(1))) .enumerate() { - let digit = nth_decimal_digit(max, i as u32); + let digit = nth_decimal_digit(n, i as u32); match &mut prev_main.borrow_mut().transition { None => {}, Some(t) => { + // prev_main -> next_side (+) Transition if digit < 9 { t.apply( TransitionMask::from(MaskPresets::NumberRange((digit as u8 + 1)..=9)), Rc::downgrade(next_side) ); } - + // prev_main -> next_main (=) Transition t.apply( TransitionMask::from(MaskPresets::Char(std::char::from_digit(digit, 10).unwrap())), Rc::downgrade(next_main) @@ -94,6 +99,7 @@ fn create_fsm_number_upperbound(max: u32) -> FSM { } } + // prev_side -> next_side match &mut prev_side.borrow_mut().transition { None => {}, Some(t) => { @@ -105,16 +111,30 @@ fn create_fsm_number_upperbound(max: u32) -> FSM { } } - // Link last main to side, goal + (main_line, side_line, goal_state, error_state) +} + +fn create_fsm_number_upper_bound(max: u32) -> FSM { + let ( + mut main_line, + mut side_line, + goal_state, + error_state + ) = create_fsm_number_scafold(max); + + // Setting main/side line as Terminal states + for (side, main) in side_line.iter_mut().zip(&mut main_line) { + side.borrow_mut().action = FSMStateAction::Terminal; + main.borrow_mut().action = FSMStateAction::Terminal; + }; + + // Link last main to goal match &mut main_line.last() { Some(main_last) => { let last_digit = max % 10; match &mut main_last.borrow_mut().transition { Some(t) => { - t.apply(TransitionMask::from(MaskPresets::Char( - std::char::from_digit(last_digit, 10).unwrap() - )), Rc::downgrade(&goal_state)); - + // Main -> Goal (=) or (+) t.apply(TransitionMask::from(MaskPresets::NumberRange(0..=(last_digit as u8))), Rc::downgrade(&goal_state) ); @@ -153,21 +173,84 @@ fn create_fsm_number_upperbound(max: u32) -> FSM { fsm } +fn create_fsm_number_lower_bound(min: u32) -> FSM { + let ( + mut main_line, + mut side_line, + goal_state, + error_state + ) = create_fsm_number_scafold(min); + + // Setting main/side line as Error states + for (side, main) in side_line.iter_mut().zip(&mut main_line) { + side.borrow_mut().action = FSMStateAction::Error; + main.borrow_mut().action = FSMStateAction::Error; + }; + + // Link last main to goal,error,side + match &mut main_line.last() { + Some(main_last) => { + let last_digit = min % 10; + match &mut main_last.borrow_mut().transition { + Some(t) => { + // Main -> Goal (=) + t.apply(TransitionMask::from(MaskPresets::NumberRange(0..=(last_digit as u8))), + Rc::downgrade(&goal_state) + ); + + // Main -> Error (+) + t.apply(TransitionMask::from(MaskPresets::NumberRange(0..=(last_digit as u8))), + Rc::downgrade(&goal_state) + ); + + }, + _ => {} + } + }, + _ => {} + } + + // Link goal to error + goal_state.borrow_mut().set_transitions(FSMTranistion::new(Rc::downgrade(&error_state))); + + // Linking error to error + error_state.borrow_mut().set_transitions(FSMTranistion::new(Rc::downgrade(&error_state))); + + // Combinding in one array + let mut states: Vec>> = vec![error_state, goal_state]; + let first_state: Option = match main_line.first() { + None => None, + Some(first) => { + Some(first.clone()) + } + }; + states.append(&mut main_line); + states.append(&mut side_line); + + let mut fsm = FSM { + name: format!("FSM_LowerBound_{}", min), + states: states, + start: first_state + }; + + elimate_unused_states(&mut fsm); + + fsm +} #[cfg(test)] mod test { use graphviz_rust::cmd::Format; - use crate::configotron::fsm::{builder::numbers::{create_fsm_number_upperbound, number_of_digits}, run::run_fsm, test::debug_file_dump, FSMStateAction}; + use crate::configotron::fsm::{builder::numbers::{create_fsm_number_upper_bound, number_of_digits}, run::run_fsm, test::debug_file_dump, FSMStateAction}; #[test] fn build_upper_bound() { - for max in vec![4026, 124, 9999, 1000, 0, 42398] { - let fsm = create_fsm_number_upperbound(max); + let fsm = create_fsm_number_upper_bound(max); let data = fsm.render_graph(Format::Svg).unwrap(); - println!("Testing Lower Bound FSM {}", max); + println!("Testing upper Bound FSM {}", max); for i in 0..=(if max == 0 {10} else {max * 10} ) { @@ -175,7 +258,7 @@ mod test { FSMStateAction::Terminal } else { FSMStateAction::Error - }); + }, "{} yield the wrong final state", i); } // Testing against refernce machine @@ -185,6 +268,29 @@ mod test { } } + #[test] + fn build_lower_bound() { + for max in vec![4026, 124, 9999, 1000, 0, 42398] { + let fsm = create_fsm_number_upper_bound(max); + let data = fsm.render_graph(Format::Svg).unwrap(); + println!("Testing Lower Bound FSM {}", max); + + for i in 0..=(if max == 0 {10} else {max * 10} ) { + + assert_eq!(run_fsm(&i.to_string(), &fsm), if i >= max { + FSMStateAction::Terminal + } else { + FSMStateAction::Error + }, "{} yield the wrong final state", i); + } + + // Testing against refernce machine + let file_name = format!("build_number_lower_bound_{}.svg", max); + debug_file_dump(data.clone(), format!("/tmp/{}", file_name).to_string()); + + } + } + #[test] fn number_of_digits_test() { assert_eq!(number_of_digits(0), 1);