Update FSRS

- up to 10x performance increase in optimal retention
- expose loss aversion
- use SpinBoxes
This commit is contained in:
Damien Elmes 2023-09-30 16:10:22 +10:00
parent 074f452762
commit 50c8a1ba9f
7 changed files with 64 additions and 198 deletions

108
Cargo.lock generated
View file

@ -573,7 +573,7 @@ checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec"
[[package]]
name = "burn"
version = "0.10.0"
source = "git+https://github.com/burn-rs/burn.git?rev=d7e9e750992229ed6a47101341f4630705fd564c#d7e9e750992229ed6a47101341f4630705fd564c"
source = "git+https://github.com/burn-rs/burn.git?rev=d06cc2f239c53e7f88dad7e0b2bbe6757a17d66c#d06cc2f239c53e7f88dad7e0b2bbe6757a17d66c"
dependencies = [
"burn-core",
"burn-train",
@ -582,7 +582,7 @@ dependencies = [
[[package]]
name = "burn-autodiff"
version = "0.10.0"
source = "git+https://github.com/burn-rs/burn.git?rev=d7e9e750992229ed6a47101341f4630705fd564c#d7e9e750992229ed6a47101341f4630705fd564c"
source = "git+https://github.com/burn-rs/burn.git?rev=d06cc2f239c53e7f88dad7e0b2bbe6757a17d66c#d06cc2f239c53e7f88dad7e0b2bbe6757a17d66c"
dependencies = [
"burn-common",
"burn-tensor",
@ -594,7 +594,7 @@ dependencies = [
[[package]]
name = "burn-common"
version = "0.10.0"
source = "git+https://github.com/burn-rs/burn.git?rev=d7e9e750992229ed6a47101341f4630705fd564c#d7e9e750992229ed6a47101341f4630705fd564c"
source = "git+https://github.com/burn-rs/burn.git?rev=d06cc2f239c53e7f88dad7e0b2bbe6757a17d66c#d06cc2f239c53e7f88dad7e0b2bbe6757a17d66c"
dependencies = [
"const-random",
"rand 0.8.5",
@ -605,7 +605,7 @@ dependencies = [
[[package]]
name = "burn-core"
version = "0.10.0"
source = "git+https://github.com/burn-rs/burn.git?rev=d7e9e750992229ed6a47101341f4630705fd564c#d7e9e750992229ed6a47101341f4630705fd564c"
source = "git+https://github.com/burn-rs/burn.git?rev=d06cc2f239c53e7f88dad7e0b2bbe6757a17d66c#d06cc2f239c53e7f88dad7e0b2bbe6757a17d66c"
dependencies = [
"bincode",
"burn-autodiff",
@ -630,12 +630,11 @@ dependencies = [
[[package]]
name = "burn-dataset"
version = "0.10.0"
source = "git+https://github.com/burn-rs/burn.git?rev=d7e9e750992229ed6a47101341f4630705fd564c#d7e9e750992229ed6a47101341f4630705fd564c"
source = "git+https://github.com/burn-rs/burn.git?rev=d06cc2f239c53e7f88dad7e0b2bbe6757a17d66c#d06cc2f239c53e7f88dad7e0b2bbe6757a17d66c"
dependencies = [
"csv 1.2.2",
"derive-new",
"dirs",
"gix-tempfile",
"rand 0.8.5",
"rmp-serde",
"sanitize-filename",
@ -650,7 +649,7 @@ dependencies = [
[[package]]
name = "burn-derive"
version = "0.10.0"
source = "git+https://github.com/burn-rs/burn.git?rev=d7e9e750992229ed6a47101341f4630705fd564c#d7e9e750992229ed6a47101341f4630705fd564c"
source = "git+https://github.com/burn-rs/burn.git?rev=d06cc2f239c53e7f88dad7e0b2bbe6757a17d66c#d06cc2f239c53e7f88dad7e0b2bbe6757a17d66c"
dependencies = [
"derive-new",
"proc-macro2",
@ -661,7 +660,7 @@ dependencies = [
[[package]]
name = "burn-ndarray"
version = "0.10.0"
source = "git+https://github.com/burn-rs/burn.git?rev=d7e9e750992229ed6a47101341f4630705fd564c#d7e9e750992229ed6a47101341f4630705fd564c"
source = "git+https://github.com/burn-rs/burn.git?rev=d06cc2f239c53e7f88dad7e0b2bbe6757a17d66c#d06cc2f239c53e7f88dad7e0b2bbe6757a17d66c"
dependencies = [
"burn-autodiff",
"burn-common",
@ -679,7 +678,7 @@ dependencies = [
[[package]]
name = "burn-tensor"
version = "0.10.0"
source = "git+https://github.com/burn-rs/burn.git?rev=d7e9e750992229ed6a47101341f4630705fd564c#d7e9e750992229ed6a47101341f4630705fd564c"
source = "git+https://github.com/burn-rs/burn.git?rev=d06cc2f239c53e7f88dad7e0b2bbe6757a17d66c#d06cc2f239c53e7f88dad7e0b2bbe6757a17d66c"
dependencies = [
"burn-tensor-testgen",
"derive-new",
@ -695,7 +694,7 @@ dependencies = [
[[package]]
name = "burn-tensor-testgen"
version = "0.10.0"
source = "git+https://github.com/burn-rs/burn.git?rev=d7e9e750992229ed6a47101341f4630705fd564c#d7e9e750992229ed6a47101341f4630705fd564c"
source = "git+https://github.com/burn-rs/burn.git?rev=d06cc2f239c53e7f88dad7e0b2bbe6757a17d66c#d06cc2f239c53e7f88dad7e0b2bbe6757a17d66c"
dependencies = [
"proc-macro2",
"quote",
@ -705,7 +704,7 @@ dependencies = [
[[package]]
name = "burn-train"
version = "0.10.0"
source = "git+https://github.com/burn-rs/burn.git?rev=d7e9e750992229ed6a47101341f4630705fd564c#d7e9e750992229ed6a47101341f4630705fd564c"
source = "git+https://github.com/burn-rs/burn.git?rev=d06cc2f239c53e7f88dad7e0b2bbe6757a17d66c#d06cc2f239c53e7f88dad7e0b2bbe6757a17d66c"
dependencies = [
"burn-core",
"derive-new",
@ -1128,19 +1127,6 @@ dependencies = [
"memchr",
]
[[package]]
name = "dashmap"
version = "5.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856"
dependencies = [
"cfg-if",
"hashbrown 0.14.0",
"lock_api",
"once_cell",
"parking_lot_core",
]
[[package]]
name = "data-encoding"
version = "2.4.0"
@ -1359,15 +1345,6 @@ version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a"
[[package]]
name = "faster-hex"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "239f7bfb930f820ab16a9cd95afc26f88264cf6905c960b340a615384aa3338a"
dependencies = [
"serde",
]
[[package]]
name = "fastrand"
version = "1.9.0"
@ -1528,7 +1505,7 @@ dependencies = [
[[package]]
name = "fsrs"
version = "0.1.0"
source = "git+https://github.com/open-spaced-repetition/fsrs-rs.git?rev=9e20a8b32ebae50230cc39e2331e9593660d56ed#9e20a8b32ebae50230cc39e2331e9593660d56ed"
source = "git+https://github.com/open-spaced-repetition/fsrs-rs.git?rev=5d67e1c0c82e56b49e3c9b3403da4ce703823b5f#5d67e1c0c82e56b49e3c9b3403da4ce703823b5f"
dependencies = [
"burn",
"itertools 0.11.0",
@ -1536,6 +1513,7 @@ dependencies = [
"ndarray",
"ndarray-rand",
"rand 0.8.5",
"rayon",
"serde",
"snafu",
"strum 0.25.0",
@ -1726,58 +1704,6 @@ version = "0.28.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0"
[[package]]
name = "gix-features"
version = "0.33.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f77decb545f63a52852578ef5f66ecd71017ffc1983d551d5fa2328d6d9817f"
dependencies = [
"gix-hash",
"gix-trace",
"libc",
]
[[package]]
name = "gix-fs"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53d5089f3338647776733a75a800a664ab046f56f21c515fa4722e395f877ef8"
dependencies = [
"gix-features",
]
[[package]]
name = "gix-hash"
version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d4796bac3aaf0c2f8bea152ca924ae3bdc5f135caefe6431116bcd67e98eab9"
dependencies = [
"faster-hex",
"thiserror",
]
[[package]]
name = "gix-tempfile"
version = "8.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cea558d3daf3b1d0001052b12218c66c8f84788852791333b633d7eeb6999db1"
dependencies = [
"dashmap",
"gix-fs",
"libc",
"once_cell",
"parking_lot",
"signal-hook",
"signal-hook-registry",
"tempfile",
]
[[package]]
name = "gix-trace"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96b6d623a1152c3facb79067d6e2ecdae48130030cf27d6eb21109f13bd7b836"
[[package]]
name = "glob"
version = "0.3.1"
@ -4121,16 +4047,6 @@ version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7cee0529a6d40f580e7a5e6c495c8fbfe21b7b52795ed4bb5e62cdf92bc6380"
[[package]]
name = "signal-hook"
version = "0.3.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801"
dependencies = [
"libc",
"signal-hook-registry",
]
[[package]]
name = "signal-hook-registry"
version = "1.4.1"

View file

@ -40,7 +40,7 @@ rev = "184b2ca50ed39ca43da13f0b830a463861adb9ca"
[workspace.dependencies.fsrs]
git = "https://github.com/open-spaced-repetition/fsrs-rs.git"
rev = "9e20a8b32ebae50230cc39e2331e9593660d56ed"
rev = "5d67e1c0c82e56b49e3c9b3403da4ce703823b5f"
# path = "../../../fsrs-rs"
[workspace.dependencies]

View file

@ -656,15 +656,6 @@
"license_file": null,
"description": "Bare bones CSV parsing with no_std support."
},
{
"name": "dashmap",
"version": "5.5.3",
"authors": "Acrimon <joel.wejdenstal@gmail.com>",
"repository": "https://github.com/xacrimon/dashmap",
"license": "MIT",
"license_file": null,
"description": "Blazing fast concurrent HashMap for Rust."
},
{
"name": "data-encoding",
"version": "2.4.0",
@ -845,15 +836,6 @@
"license_file": null,
"description": "Fallible streaming iteration"
},
{
"name": "faster-hex",
"version": "0.8.1",
"authors": "zhangsoledad <787953403@qq.com>",
"repository": "https://github.com/NervosFoundation/faster-hex",
"license": "MIT",
"license_file": null,
"description": "Fast hex encoding."
},
{
"name": "fastrand",
"version": "1.9.0",
@ -1133,51 +1115,6 @@
"license_file": null,
"description": "A library for reading and writing the DWARF debugging format."
},
{
"name": "gix-features",
"version": "0.33.0",
"authors": "Sebastian Thiel <sebastian.thiel@icloud.com>",
"repository": "https://github.com/Byron/gitoxide",
"license": "Apache-2.0 OR MIT",
"license_file": null,
"description": "A crate to integrate various capabilities using compile-time feature flags"
},
{
"name": "gix-fs",
"version": "0.5.0",
"authors": "Sebastian Thiel <sebastian.thiel@icloud.com>",
"repository": "https://github.com/Byron/gitoxide",
"license": "Apache-2.0 OR MIT",
"license_file": null,
"description": "A crate providing file system specific utilities to `gitoxide`"
},
{
"name": "gix-hash",
"version": "0.12.0",
"authors": "Sebastian Thiel <sebastian.thiel@icloud.com>",
"repository": "https://github.com/Byron/gitoxide",
"license": "Apache-2.0 OR MIT",
"license_file": null,
"description": "Borrowed and owned git hash digests used to identify git objects"
},
{
"name": "gix-tempfile",
"version": "8.0.0",
"authors": "Sebastian Thiel <sebastian.thiel@icloud.com>",
"repository": "https://github.com/Byron/gitoxide",
"license": "Apache-2.0 OR MIT",
"license_file": null,
"description": "A tempfile implementation with a global registry to assure cleanup"
},
{
"name": "gix-trace",
"version": "0.1.3",
"authors": "Sebastian Thiel <sebastian.thiel@icloud.com>",
"repository": "https://github.com/Byron/gitoxide",
"license": "Apache-2.0 OR MIT",
"license_file": null,
"description": "A crate to provide minimal `tracing` support that can be turned off to zero cost"
},
{
"name": "h2",
"version": "0.3.21",
@ -2708,15 +2645,6 @@
"license_file": null,
"description": "A lock-free concurrent slab."
},
{
"name": "signal-hook",
"version": "0.3.17",
"authors": "Michal 'vorner' Vaner <vorner@vorner.cz>|Thomas Himmelstoss <thimm@posteo.de>",
"repository": "https://github.com/vorner/signal-hook",
"license": "Apache-2.0 OR MIT",
"license_file": null,
"description": "Unix signal handling"
},
{
"name": "signal-hook-registry",
"version": "1.4.1",

View file

@ -362,6 +362,7 @@ message ComputeOptimalRetentionRequest {
uint32 max_minutes_of_study_per_day = 4;
uint32 max_interval = 5;
string search = 6;
double loss_aversion = 7;
}
message ComputeOptimalRetentionResponse {
@ -369,18 +370,18 @@ message ComputeOptimalRetentionResponse {
}
message OptimalRetentionParameters {
double recall_secs_hard = 6;
double recall_secs_good = 7;
double recall_secs_easy = 8;
double forget_secs = 9;
double learn_secs = 10;
double first_rating_probability_again = 11;
double first_rating_probability_hard = 12;
double first_rating_probability_good = 13;
double first_rating_probability_easy = 14;
double review_rating_probability_hard = 15;
double review_rating_probability_good = 16;
double review_rating_probability_easy = 17;
double recall_secs_hard = 1;
double recall_secs_good = 2;
double recall_secs_easy = 3;
double forget_secs = 4;
double learn_secs = 5;
double first_rating_probability_again = 6;
double first_rating_probability_hard = 7;
double first_rating_probability_good = 8;
double first_rating_probability_easy = 9;
double review_rating_probability_hard = 10;
double review_rating_probability_good = 11;
double review_rating_probability_easy = 12;
}
message GetOptimalRetentionParametersRequest {

View file

@ -67,9 +67,9 @@ pub enum RevlogReviewKind {
Learning = 0,
Review = 1,
Relearning = 2,
/// Old Anki versions called this "Cram" or "Early", and assigned it when
/// reviewing cards ahead. It is now only used for filtered decks with
/// rescheduling disabled.
/// Old Anki versions called this "Cram" or "Early". It's assigned when
/// reviewing cards before they're due, or when rescheduling is
/// disabled.
Filtered = 3,
Manual = 4,
}

View file

@ -49,6 +49,7 @@ impl Collection {
p.review_rating_probability_good,
p.review_rating_probability_easy,
],
loss_aversion: req.loss_aversion,
},
&req.weights,
|ip| {

View file

@ -20,6 +20,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
import SettingTitle from "../components/SettingTitle.svelte";
import type { DeckOptionsState } from "./lib";
import SpinBoxFloatRow from "./SpinBoxFloatRow.svelte";
import SpinBoxRow from "./SpinBoxRow.svelte";
import WeightsInputRow from "./WeightsInputRow.svelte";
export let state: DeckOptionsState;
@ -49,6 +50,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
deckSize: 10000,
daysToSimulate: 365,
maxMinutesOfStudyPerDay: 30,
lossAversion: 2.5,
});
$: if (optimalRetentionRequest.daysToSimulate > 3650) {
optimalRetentionRequest.daysToSimulate = 3650;
@ -253,23 +255,41 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
<details>
<summary>{tr.deckConfigComputeOptimalRetention()} (experimental)</summary>
Deck size:
<br />
<input type="number" bind:value={optimalRetentionRequest.deckSize} />
<br />
<SpinBoxRow
bind:value={optimalRetentionRequest.deckSize}
defaultValue={10000}
min={100}
max={999999}
>
<SettingTitle>Deck size</SettingTitle>
</SpinBoxRow>
Days to simulate
<br />
<input type="number" bind:value={optimalRetentionRequest.daysToSimulate} />
<br />
<SpinBoxRow
bind:value={optimalRetentionRequest.daysToSimulate}
defaultValue={365}
min={1}
max={3650}
>
<SettingTitle>Days to simulate</SettingTitle>
</SpinBoxRow>
Target minutes of study per day:
<br />
<input
type="number"
<SpinBoxRow
bind:value={optimalRetentionRequest.maxMinutesOfStudyPerDay}
/>
<br />
defaultValue={30}
min={1}
max={1800}
>
<SettingTitle>Minutes study/day</SettingTitle>
</SpinBoxRow>
<SpinBoxFloatRow
bind:value={optimalRetentionRequest.lossAversion}
defaultValue={2.5}
min={1.0}
max={3.0}
>
<SettingTitle>Loss aversion</SettingTitle>
</SpinBoxFloatRow>
<button
class="btn {computingRetention ? 'btn-warning' : 'btn-primary'}"