mirror of
https://github.com/ankitects/anki.git
synced 2026-01-14 06:23:57 -05:00
* Feat/FSRS-6 * update comment * add decay to Card * ./ninja fix:minilints * pass check * fix NaN in evaluation * remove console * decay should fallback to 0.5 when it's None. * Update SimulatorModal.svelte * Update a few comments * Update FSRS decay defaults to use constants for better maintainability and clarity * Update rslib/src/storage/card/data.rs
61 lines
2.3 KiB
Rust
61 lines
2.3 KiB
Rust
// Copyright: Ankitects Pty Ltd and contributors
|
|
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|
|
|
use anki_proto::stats::graphs_response::Retrievability;
|
|
use fsrs::FSRS;
|
|
use fsrs::FSRS5_DEFAULT_DECAY;
|
|
|
|
use crate::prelude::TimestampSecs;
|
|
use crate::scheduler::timing::SchedTimingToday;
|
|
use crate::stats::graphs::eases::percent_to_bin;
|
|
use crate::stats::graphs::GraphsContext;
|
|
|
|
impl GraphsContext {
|
|
/// (SM-2, FSRS)
|
|
pub(super) fn retrievability(&self) -> Retrievability {
|
|
let mut retrievability = Retrievability::default();
|
|
let mut card_with_retrievability_count: usize = 0;
|
|
let timing = SchedTimingToday {
|
|
days_elapsed: self.days_elapsed,
|
|
now: TimestampSecs::now(),
|
|
next_day_at: self.next_day_start,
|
|
};
|
|
let fsrs = FSRS::new(None).unwrap();
|
|
// note id -> (sum, count)
|
|
let mut note_retrievability: std::collections::HashMap<i64, (f32, u32)> =
|
|
std::collections::HashMap::new();
|
|
for card in &self.cards {
|
|
let entry = note_retrievability
|
|
.entry(card.note_id.0)
|
|
.or_insert((0.0, 0));
|
|
entry.1 += 1;
|
|
if let Some(state) = card.memory_state {
|
|
let elapsed_days = card.days_since_last_review(&timing).unwrap_or_default();
|
|
let r = fsrs.current_retrievability(
|
|
state.into(),
|
|
elapsed_days,
|
|
card.decay.unwrap_or(FSRS5_DEFAULT_DECAY),
|
|
);
|
|
|
|
*retrievability
|
|
.retrievability
|
|
.entry(percent_to_bin(r * 100.0))
|
|
.or_insert_with(Default::default) += 1;
|
|
retrievability.sum_by_card += r;
|
|
card_with_retrievability_count += 1;
|
|
entry.0 += r;
|
|
} else {
|
|
entry.0 += 0.0;
|
|
}
|
|
}
|
|
if card_with_retrievability_count != 0 {
|
|
retrievability.average =
|
|
retrievability.sum_by_card * 100.0 / card_with_retrievability_count as f32;
|
|
}
|
|
retrievability.sum_by_note = note_retrievability
|
|
.values()
|
|
.map(|(sum, count)| sum / *count as f32)
|
|
.sum();
|
|
retrievability
|
|
}
|
|
}
|