From db93939ded947d74bb25bd8552a2b2356a096509 Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Tue, 12 Dec 2023 09:40:31 +1000 Subject: [PATCH] Don't use SM2 memory state when cards are manually introduced https://github.com/open-spaced-repetition/fsrs4anki/issues/540#issuecomment-1848833376 --- rslib/src/scheduler/fsrs/memory_state.rs | 5 ++--- rslib/src/scheduler/fsrs/weights.rs | 23 ++++++++++++++++++----- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/rslib/src/scheduler/fsrs/memory_state.rs b/rslib/src/scheduler/fsrs/memory_state.rs index 4bc541c6f49..c0a337b6c30 100644 --- a/rslib/src/scheduler/fsrs/memory_state.rs +++ b/rslib/src/scheduler/fsrs/memory_state.rs @@ -274,12 +274,11 @@ pub(crate) fn single_card_revlog_to_item( } as f32 / 1000.0, }); - if let Some((mut items, found_learning)) = + if let Some((mut items, revlogs_complete)) = single_card_revlog_to_items(entries, next_day_at, false) { let mut item = items.pop().unwrap(); - if found_learning { - // we assume the revlog is complete + if revlogs_complete { Ok(Some(FsrsItemWithStartingState { item, starting_state: None, diff --git a/rslib/src/scheduler/fsrs/weights.rs b/rslib/src/scheduler/fsrs/weights.rs index bc021315023..dfaa007b47a 100644 --- a/rslib/src/scheduler/fsrs/weights.rs +++ b/rslib/src/scheduler/fsrs/weights.rs @@ -162,26 +162,39 @@ fn fsrs_items_for_training(revlogs: Vec, next_day_at: TimestampSecs /// expects multiple items for a given card when training - for revlog /// `[1,2,3]`, we create FSRSItems corresponding to `[1,2]` and `[1,2,3]` /// in training, and `[1]`, [1,2]` and `[1,2,3]` when calculating memory -/// state. Returns (items, found_learn_entry), the latter of which is used -/// to determine whether the revlogs have been truncated when not training. +/// state. +/// +/// Returns (items, revlog_complete), the latter of which is assumed +/// when the revlogs have a learning step, or start with manual scheduling. When +/// revlogs are incomplete, the starting difficulty is later inferred from the +/// SM2 data, instead of using the standard FSRS initial difficulty. pub(crate) fn single_card_revlog_to_items( mut entries: Vec, next_day_at: TimestampSecs, training: bool, ) -> Option<(Vec, bool)> { let mut last_learn_entry = None; - let mut found_learn_entry = false; + let mut revlogs_complete = false; for (index, entry) in entries.iter().enumerate().rev() { if matches!( (entry.review_kind, entry.button_chosen), (RevlogReviewKind::Learning, 1..=4) ) { last_learn_entry = Some(index); - found_learn_entry = true; + revlogs_complete = true; } else if last_learn_entry.is_some() { break; } } + if !revlogs_complete { + revlogs_complete = matches!( + entries.first(), + Some(RevlogEntry { + review_kind: RevlogReviewKind::Manual, + .. + }) + ); + } let first_relearn = entries .iter() .enumerate() @@ -240,7 +253,7 @@ pub(crate) fn single_card_revlog_to_items( if items.is_empty() { None } else { - Some((items, found_learn_entry)) + Some((items, revlogs_complete)) } }