Luc Mcgrady 2025-07-23 14:51:53 +01:00
parent 8fb3d0bc86
commit 72efcf230c
No known key found for this signature in database
GPG key ID: 4F3D7A0B17CC3D9C
3 changed files with 12 additions and 45 deletions

5
Cargo.lock generated
View file

@ -2213,9 +2213,8 @@ dependencies = [
[[package]]
name = "fsrs"
version = "4.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1f3a8c3df2c324ebab71461178fe8c1fe2d7373cf603f312b652befd026f06d"
version = "5.0.0"
source = "git+https://github.com/open-spaced-repetition/fsrs-rs.git?branch=Refactor/expected_workload_via_dp#808bd715b302ccdda26a2d29c7566270e7be3bb3"
dependencies = [
"burn",
"itertools 0.14.0",

View file

@ -33,8 +33,9 @@ git = "https://github.com/ankitects/linkcheck.git"
rev = "184b2ca50ed39ca43da13f0b830a463861adb9ca"
[workspace.dependencies.fsrs]
version = "4.1.1"
# git = "https://github.com/open-spaced-repetition/fsrs-rs.git"
# version = "4.1.1"
git = "https://github.com/open-spaced-repetition/fsrs-rs.git"
branch = "Refactor/expected_workload_via_dp"
# rev = "a7f7efc10f0a26b14ee348cc7402155685f2a24f"
# path = "../open-spaced-repetition/fsrs-rs"

View file

@ -103,43 +103,15 @@ impl crate::services::DeckConfigService for Collection {
&mut self,
input: anki_proto::deck_config::GetRetentionWorkloadRequest,
) -> Result<anki_proto::deck_config::GetRetentionWorkloadResponse> {
const LEARN_SPAN: usize = 365;
const TERMINATION_PROB: f32 = 1e-5;
// the default values are from https://github.com/open-spaced-repetition/Anki-button-usage/blob/881009015c2a85ac911021d76d0aacb124849937/analysis.ipynb
const DEFAULT_LEARN_COST: f32 = 19.4698;
const DEFAULT_PASS_COST: f32 = 7.8454;
const DEFAULT_FAIL_COST: f32 = 23.185;
const DEFAULT_INITIAL_PASS_RATE: f32 = 0.7645;
let guard =
self.search_cards_into_table(&input.search, crate::search::SortMode::NoOrder)?;
let costs = guard.col.storage.get_costs_for_retention()?;
fn smoothing(obs: f32, default: f32, count: u32) -> f32 {
let alpha = count as f32 / (50.0 + count as f32);
obs * alpha + default * (1.0 - alpha)
}
let revlogs = guard
.col
.storage
.get_revlog_entries_for_searched_cards_in_card_order()?;
let cost_success = smoothing(
costs.average_pass_time_ms / 1000.0,
DEFAULT_PASS_COST,
costs.pass_count,
);
let cost_failure = smoothing(
costs.average_fail_time_ms / 1000.0,
DEFAULT_FAIL_COST,
costs.fail_count,
);
let cost_learn = smoothing(
costs.average_learn_time_ms / 1000.0,
DEFAULT_LEARN_COST,
costs.learn_count,
);
let initial_pass_rate = smoothing(
costs.initial_pass_rate,
DEFAULT_INITIAL_PASS_RATE,
costs.pass_count,
);
let config = guard.col.get_optimal_retention_parameters(revlogs)?;
let costs = (70u32..=99u32)
.map(|dr| {
@ -148,12 +120,7 @@ impl crate::services::DeckConfigService for Collection {
fsrs::expected_workload(
&input.w,
dr as f32 / 100.,
LEARN_SPAN,
cost_success,
cost_failure,
cost_learn,
initial_pass_rate,
TERMINATION_PROB,
&config
)?,
))
})