diff --git a/Cargo.lock b/Cargo.lock index 5481a97..7f9d23f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1077,7 +1077,7 @@ dependencies = [ [[package]] name = "fsrs" -version = "1.4.7" +version = "1.4.8" dependencies = [ "burn", "chrono", diff --git a/Cargo.toml b/Cargo.toml index 52ce055..0d7b174 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "fsrs" -version = "1.4.7" +version = "1.4.8" authors = ["Open Spaced Repetition"] categories = ["algorithms", "science"] edition = "2021" diff --git a/src/optimal_retention.rs b/src/optimal_retention.rs index 20cb6ec..4550066 100644 --- a/src/optimal_retention.rs +++ b/src/optimal_retention.rs @@ -216,9 +216,9 @@ pub fn simulate( let mut card_priorities = PriorityQueue::new(); - fn card_priority(card: &Card, learn: bool) -> (usize, bool, usize) { - // High difficulty priority as example - (-card.due as usize, !learn, -card.difficulty as usize) + fn card_priority(card: &Card, learn: bool) -> (i32, bool, i32) { + // high priority for early due, review, low difficulty card + (-card.due as i32, !learn, -(card.difficulty * 100.0) as i32) } for (i, card) in cards.iter().enumerate() { @@ -333,9 +333,7 @@ pub fn simulate( card.last_date = card.due; card.due += ivl; - if (card.due as usize) <= learn_span { - card_priorities.change_priority(&card_index, card_priority(card, false)); - } + card_priorities.change_priority(&card_index, card_priority(card, false)); } /*dbg!(( @@ -915,11 +913,43 @@ mod tests { simulate(&config, &DEFAULT_PARAMETERS, 0.9, None, None)?; assert_eq!( memorized_cnt_per_day[memorized_cnt_per_day.len() - 1], - 7004.319 + 6781.4946 ); Ok(()) } + #[test] + fn changing_learn_span_should_get_same_review_cnt_per_day() -> Result<()> { + const LOWER: usize = 365; + const DECK_SIZE: usize = 1000; + const LEARN_LIMIT: usize = 10; + let config = SimulatorConfig { + learn_span: LOWER, + learn_limit: LEARN_LIMIT, + deck_size: DECK_SIZE, + ..Default::default() + }; + let (_, review_cnt_per_day_lower, _, _) = + simulate(&config, &DEFAULT_PARAMETERS, 0.9, None, None)?; + let config = SimulatorConfig { + learn_span: LOWER + 10, + learn_limit: LEARN_LIMIT, + deck_size: DECK_SIZE, + ..Default::default() + }; + let (_, review_cnt_per_day_higher, _, _) = + simulate(&config, &DEFAULT_PARAMETERS, 0.9, None, None)?; + // Compare first LOWER items of review_cnt_per_day arrays + for i in 0..LOWER { + assert_eq!( + review_cnt_per_day_lower[i], review_cnt_per_day_higher[i], + "at index {}", + i + ); + } + Ok(()) + } + #[test] fn simulate_with_existing_cards() -> Result<()> { let config = SimulatorConfig { @@ -1032,8 +1062,8 @@ mod tests { assert_eq!( results.1.to_vec(), vec![ - 0, 16, 25, 34, 60, 65, 76, 85, 91, 92, 100, 103, 119, 107, 103, 113, 122, 143, 149, - 151, 148, 172, 154, 175, 156, 169, 155, 191, 185, 170 + 0, 15, 18, 38, 64, 64, 80, 89, 95, 95, 100, 96, 107, 118, 120, 114, 126, 123, 139, + 167, 158, 156, 167, 161, 154, 178, 163, 151, 160, 151 ] ); assert_eq!( @@ -1050,7 +1080,7 @@ mod tests { ..Default::default() }; let results = simulate(&config, &DEFAULT_PARAMETERS, 0.9, None, None)?; - assert_eq!(results.0[results.0.len() - 1], 6619.07); + assert_eq!(results.0[results.0.len() - 1], 6484.7144); Ok(()) } @@ -1103,7 +1133,7 @@ mod tests { ..Default::default() }; let optimal_retention = fsrs.optimal_retention(&config, &[], |_v| true).unwrap(); - assert_eq!(optimal_retention, 0.8372485); + assert_eq!(optimal_retention, 0.85450846); assert!(fsrs.optimal_retention(&config, &[1.], |_v| true).is_err()); Ok(()) } @@ -1123,7 +1153,7 @@ mod tests { let mut param = DEFAULT_PARAMETERS[..17].to_vec(); param.extend_from_slice(&[0.0, 0.0]); let optimal_retention = fsrs.optimal_retention(&config, ¶m, |_v| true).unwrap(); - assert_eq!(optimal_retention, 0.85450846); + assert_eq!(optimal_retention, 0.83750373); Ok(()) }