mirror of
https://github.com/ankitects/anki.git
synced 2025-09-18 22:12:21 -04:00
Fix/FSRS simulator fallback to memory_state_from_sm2 when converting cards (#4189)
* Fix/FSRS simulator fallback to memory_state_from_sm2 for after setting “Ignore cards reviewed before” * add comment to fsrs_item_for_memory_state * Add historical retention field to FSRS review request and update related logic - Added `historical_retention` field to `SimulateFsrsReviewRequest` in `scheduler.proto`. - Updated `simulator.rs` to use `req.historical_retention` instead of the removed `desired_retention`. - Modified `FsrsOptions.svelte` to include `historicalRetention` in the options passed to the component. * Update rslib/src/scheduler/fsrs/memory_state.rs Co-authored-by: user1823 <92206575+user1823@users.noreply.github.com> * Update rslib/src/scheduler/fsrs/simulator.rs Co-authored-by: user1823 <92206575+user1823@users.noreply.github.com> * pass ci * Update rslib/src/scheduler/fsrs/simulator.rs Co-authored-by: user1823 <92206575+user1823@users.noreply.github.com> * format * Update rslib/src/scheduler/fsrs/simulator.rs Co-authored-by: Luc Mcgrady <lucmcgrady@gmail.com> * format * Fix condition in is_included_card function to check CardType instead of CardQueue --------- Co-authored-by: user1823 <92206575+user1823@users.noreply.github.com> Co-authored-by: Luc Mcgrady <lucmcgrady@gmail.com>
This commit is contained in:
parent
208729fa3e
commit
1f7f7bc8a3
4 changed files with 53 additions and 36 deletions
|
@ -404,6 +404,7 @@ message SimulateFsrsReviewRequest {
|
|||
repeated float easy_days_percentages = 10;
|
||||
deck_config.DeckConfig.Config.ReviewCardOrder review_order = 11;
|
||||
optional uint32 suspend_after_lapse_count = 12;
|
||||
float historical_retention = 13;
|
||||
}
|
||||
|
||||
message SimulateFsrsReviewResponse {
|
||||
|
|
|
@ -377,6 +377,7 @@ pub(crate) fn fsrs_item_for_memory_state(
|
|||
Ok(None)
|
||||
}
|
||||
} else {
|
||||
// no revlogs (new card or caused by ignore_revlogs_before or deleted revlogs)
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,11 +10,14 @@ use fsrs::simulate;
|
|||
use fsrs::PostSchedulingFn;
|
||||
use fsrs::ReviewPriorityFn;
|
||||
use fsrs::SimulatorConfig;
|
||||
use fsrs::FSRS;
|
||||
use itertools::Itertools;
|
||||
use rand::rngs::StdRng;
|
||||
use rand::Rng;
|
||||
|
||||
use crate::card::CardQueue;
|
||||
use crate::card::CardType;
|
||||
use crate::card::FsrsMemoryState;
|
||||
use crate::prelude::*;
|
||||
use crate::scheduler::states::fuzz::constrained_fuzz_bounds;
|
||||
use crate::scheduler::states::load_balancer::calculate_easy_days_modifiers;
|
||||
|
@ -129,7 +132,7 @@ impl Collection {
|
|||
fn is_included_card(c: &Card) -> bool {
|
||||
c.queue != CardQueue::Suspended
|
||||
&& c.queue != CardQueue::PreviewRepeat
|
||||
&& c.queue != CardQueue::New
|
||||
&& c.ctype != CardType::New
|
||||
}
|
||||
// calculate any missing memory state
|
||||
for c in &mut cards {
|
||||
|
@ -143,13 +146,29 @@ impl Collection {
|
|||
let days_elapsed = self.timing_today().unwrap().days_elapsed as i32;
|
||||
let new_cards = cards
|
||||
.iter()
|
||||
.filter(|c| c.memory_state.is_none() || c.queue == CardQueue::New)
|
||||
.filter(|c| c.ctype == CardType::New && c.queue != CardQueue::Suspended)
|
||||
.count()
|
||||
+ req.deck_size as usize;
|
||||
let fsrs = FSRS::new(Some(&req.params))?;
|
||||
let mut converted_cards = cards
|
||||
.into_iter()
|
||||
.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,
|
||||
// cards that lack memory states after compute_memory_state have no FSRS items,
|
||||
// implying a truncated or ignored revlog
|
||||
None => fsrs
|
||||
.memory_state_from_sm2(
|
||||
c.ease_factor(),
|
||||
c.interval as f32,
|
||||
req.historical_retention,
|
||||
)
|
||||
.ok()?
|
||||
.into(),
|
||||
};
|
||||
Card::convert(c, days_elapsed, memory_state)
|
||||
})
|
||||
.collect_vec();
|
||||
let introduced_today_count = self
|
||||
.search_cards(&format!("{} introduced:1", &req.search), SortMode::NoOrder)?
|
||||
|
@ -251,39 +270,34 @@ impl Collection {
|
|||
}
|
||||
|
||||
impl Card {
|
||||
fn convert(card: Card, days_elapsed: i32) -> Option<fsrs::Card> {
|
||||
match card.memory_state {
|
||||
Some(state) => match card.queue {
|
||||
CardQueue::DayLearn | CardQueue::Review => {
|
||||
let due = card.original_or_current_due();
|
||||
let relative_due = due - days_elapsed;
|
||||
let last_date = (relative_due - card.interval as i32).min(0) as f32;
|
||||
Some(fsrs::Card {
|
||||
id: card.id.0,
|
||||
difficulty: state.difficulty,
|
||||
stability: state.stability,
|
||||
last_date,
|
||||
due: relative_due as f32,
|
||||
interval: card.interval as f32,
|
||||
lapses: card.lapses,
|
||||
})
|
||||
}
|
||||
CardQueue::New => None,
|
||||
CardQueue::Learn | CardQueue::SchedBuried | CardQueue::UserBuried => {
|
||||
Some(fsrs::Card {
|
||||
id: card.id.0,
|
||||
difficulty: state.difficulty,
|
||||
stability: state.stability,
|
||||
last_date: 0.0,
|
||||
due: 0.0,
|
||||
interval: card.interval as f32,
|
||||
lapses: card.lapses,
|
||||
})
|
||||
}
|
||||
CardQueue::PreviewRepeat => None,
|
||||
CardQueue::Suspended => None,
|
||||
},
|
||||
None => None,
|
||||
fn convert(card: Card, days_elapsed: i32, memory_state: FsrsMemoryState) -> Option<fsrs::Card> {
|
||||
match card.queue {
|
||||
CardQueue::DayLearn | CardQueue::Review => {
|
||||
let due = card.original_or_current_due();
|
||||
let relative_due = due - days_elapsed;
|
||||
let last_date = (relative_due - card.interval as i32).min(0) as f32;
|
||||
Some(fsrs::Card {
|
||||
id: card.id.0,
|
||||
difficulty: memory_state.difficulty,
|
||||
stability: memory_state.stability,
|
||||
last_date,
|
||||
due: relative_due as f32,
|
||||
interval: card.interval as f32,
|
||||
lapses: card.lapses,
|
||||
})
|
||||
}
|
||||
CardQueue::New => None,
|
||||
CardQueue::Learn | CardQueue::SchedBuried | CardQueue::UserBuried => Some(fsrs::Card {
|
||||
id: card.id.0,
|
||||
difficulty: memory_state.difficulty,
|
||||
stability: memory_state.stability,
|
||||
last_date: 0.0,
|
||||
due: 0.0,
|
||||
interval: card.interval as f32,
|
||||
lapses: card.lapses,
|
||||
}),
|
||||
CardQueue::PreviewRepeat => None,
|
||||
CardQueue::Suspended => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -95,6 +95,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||
newCardsIgnoreReviewLimit: $newCardsIgnoreReviewLimit,
|
||||
easyDaysPercentages: $config.easyDaysPercentages,
|
||||
reviewOrder: $config.reviewOrder,
|
||||
historicalRetention: $config.historicalRetention,
|
||||
});
|
||||
|
||||
const DESIRED_RETENTION_LOW_THRESHOLD = 0.8;
|
||||
|
|
Loading…
Reference in a new issue