Fix/FSRS simulator fallback to memory_state_from_sm2 for after setting “Ignore cards reviewed before”

This commit is contained in:
Jarrett Ye 2025-07-08 16:41:05 +08:00
parent 1ad82ea8b5
commit 1081053807
No known key found for this signature in database
GPG key ID: EBFC55E0C1A352BB

View file

@ -10,11 +10,13 @@ use fsrs::simulate;
use fsrs::PostSchedulingFn; use fsrs::PostSchedulingFn;
use fsrs::ReviewPriorityFn; use fsrs::ReviewPriorityFn;
use fsrs::SimulatorConfig; use fsrs::SimulatorConfig;
use fsrs::FSRS;
use itertools::Itertools; use itertools::Itertools;
use rand::rngs::StdRng; use rand::rngs::StdRng;
use rand::Rng; use rand::Rng;
use crate::card::CardQueue; use crate::card::CardQueue;
use crate::card::FsrsMemoryState;
use crate::prelude::*; use crate::prelude::*;
use crate::scheduler::states::fuzz::constrained_fuzz_bounds; use crate::scheduler::states::fuzz::constrained_fuzz_bounds;
use crate::scheduler::states::load_balancer::calculate_easy_days_modifiers; use crate::scheduler::states::load_balancer::calculate_easy_days_modifiers;
@ -141,15 +143,27 @@ impl Collection {
} }
} }
let days_elapsed = self.timing_today().unwrap().days_elapsed as i32; let days_elapsed = self.timing_today().unwrap().days_elapsed as i32;
let new_cards = cards let new_cards =
.iter() cards.iter().filter(|c| c.queue == CardQueue::New).count() + req.deck_size as usize;
.filter(|c| c.memory_state.is_none() || c.queue == CardQueue::New) let fsrs = FSRS::new(Some(&req.params))?;
.count() let historical_retention = req.desired_retention;
+ req.deck_size as usize;
let mut converted_cards = cards let mut converted_cards = cards
.into_iter() .into_iter()
.filter(is_included_card) .filter(is_included_card)
.filter_map(|c| Card::convert(c, days_elapsed)) .filter_map(|c| {
let memory_state = match c.memory_state {
Some(state) => state,
None => fsrs
.memory_state_from_sm2(
c.ease_factor(),
c.interval as f32,
historical_retention,
)
.ok()?
.into(),
};
Card::convert(c, days_elapsed, memory_state)
})
.collect_vec(); .collect_vec();
let introduced_today_count = self let introduced_today_count = self
.search_cards(&format!("{} introduced:1", &req.search), SortMode::NoOrder)? .search_cards(&format!("{} introduced:1", &req.search), SortMode::NoOrder)?
@ -251,39 +265,34 @@ impl Collection {
} }
impl Card { impl Card {
fn convert(card: Card, days_elapsed: i32) -> Option<fsrs::Card> { fn convert(card: Card, days_elapsed: i32, memory_state: FsrsMemoryState) -> Option<fsrs::Card> {
match card.memory_state { match card.queue {
Some(state) => match card.queue { CardQueue::DayLearn | CardQueue::Review => {
CardQueue::DayLearn | CardQueue::Review => { let due = card.original_or_current_due();
let due = card.original_or_current_due(); let relative_due = due - days_elapsed;
let relative_due = due - days_elapsed; let last_date = (relative_due - card.interval as i32).min(0) as f32;
let last_date = (relative_due - card.interval as i32).min(0) as f32; Some(fsrs::Card {
Some(fsrs::Card { id: card.id.0,
id: card.id.0, difficulty: memory_state.difficulty,
difficulty: state.difficulty, stability: memory_state.stability,
stability: state.stability, last_date,
last_date, due: relative_due as f32,
due: relative_due as f32, interval: card.interval as f32,
interval: card.interval as f32, lapses: card.lapses,
lapses: card.lapses, })
}) }
} CardQueue::New => None,
CardQueue::New => None, CardQueue::Learn | CardQueue::SchedBuried | CardQueue::UserBuried => Some(fsrs::Card {
CardQueue::Learn | CardQueue::SchedBuried | CardQueue::UserBuried => { id: card.id.0,
Some(fsrs::Card { difficulty: memory_state.difficulty,
id: card.id.0, stability: memory_state.stability,
difficulty: state.difficulty, last_date: 0.0,
stability: state.stability, due: 0.0,
last_date: 0.0, interval: card.interval as f32,
due: 0.0, lapses: card.lapses,
interval: card.interval as f32, }),
lapses: card.lapses, CardQueue::PreviewRepeat => None,
}) CardQueue::Suspended => None,
}
CardQueue::PreviewRepeat => None,
CardQueue::Suspended => None,
},
None => None,
} }
} }
} }