Allow cards with no learning history when not training

This commit is contained in:
Damien Elmes 2023-09-30 13:39:22 +10:00
parent 93499d4182
commit d16faacd0f
2 changed files with 64 additions and 6 deletions

View file

@ -125,3 +125,58 @@ pub(crate) fn single_card_revlog_to_item(
let items = single_card_revlog_to_items(entries, next_day_at, false);
items.and_then(|mut i| i.pop())
}
#[cfg(test)]
mod tests {
use fsrs::MemoryState;
use super::super::weights::tests::fsrs_items;
use super::*;
use crate::revlog::RevlogReviewKind;
use crate::scheduler::fsrs::weights::tests::convert;
use crate::scheduler::fsrs::weights::tests::review;
use crate::scheduler::fsrs::weights::tests::revlog;
#[test]
fn bypassed_learning_is_handled() {
// cards without any learning steps due to truncated history still have memory
// state calculated
assert_eq!(
convert(
&[
RevlogEntry {
ease_factor: 2500,
..revlog(RevlogReviewKind::Manual, 7)
},
revlog(RevlogReviewKind::Review, 6),
],
false,
),
fsrs_items!([review(0)])
);
}
#[test]
fn zero_history_is_handled() {
// when the history is empty, no items are produced
assert_eq!(convert(&[], false), None);
// but memory state should still be inferred, by using the card's current state
let mut card = Card {
ctype: CardType::Review,
interval: 100,
ease_factor: 1300,
..Default::default()
};
card.set_memory_state(&FSRS::new(Some(&[])).unwrap(), None);
assert_eq!(
card.memory_state,
Some(
MemoryState {
stability: 100.0,
difficulty: 9.692858
}
.into()
)
);
}
}

View file

@ -135,8 +135,8 @@ pub(crate) fn single_card_revlog_to_items(
if idx > 0 {
entries.drain(..idx);
}
} else {
// we ignore cards that don't have any learning steps
} else if training {
// when training, we ignore cards that don't have any learning steps
return None;
}
@ -210,12 +210,12 @@ impl RevlogEntry {
}
#[cfg(test)]
mod tests {
pub(crate) mod tests {
use super::*;
const NEXT_DAY_AT: TimestampSecs = TimestampSecs(86400 * 100);
fn revlog(review_kind: RevlogReviewKind, days_ago: i64) -> RevlogEntry {
pub(crate) fn revlog(review_kind: RevlogReviewKind, days_ago: i64) -> RevlogEntry {
RevlogEntry {
review_kind,
id: ((NEXT_DAY_AT.0 - days_ago * 86400) * 1000).into(),
@ -224,14 +224,15 @@ mod tests {
}
}
fn review(delta_t: u32) -> FSRSReview {
pub(crate) fn review(delta_t: u32) -> FSRSReview {
FSRSReview { rating: 3, delta_t }
}
fn convert(revlog: &[RevlogEntry], training: bool) -> Option<Vec<FSRSItem>> {
pub(crate) fn convert(revlog: &[RevlogEntry], training: bool) -> Option<Vec<FSRSItem>> {
single_card_revlog_to_items(revlog.to_vec(), NEXT_DAY_AT, training)
}
#[macro_export]
macro_rules! fsrs_items {
($($reviews:expr),*) => {
Some(vec![
@ -244,6 +245,8 @@ mod tests {
};
}
pub(crate) use fsrs_items;
#[test]
fn delta_t_is_correct() -> Result<()> {
assert_eq!(