update FSRS to v0.2.0 (#2977)

* update FSRS to v0.2.0

* update comments

* ./ninja fix:minilints

* 1000 -> 400 in translation (dae)
This commit is contained in:
Jarrett Ye 2024-01-30 14:27:12 +08:00 committed by GitHub
parent ec3698502b
commit 2fffe4b7ba
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 23 additions and 20 deletions

5
Cargo.lock generated
View File

@ -1794,8 +1794,9 @@ dependencies = [
[[package]] [[package]]
name = "fsrs" name = "fsrs"
version = "0.1.0" version = "0.2.0"
source = "git+https://github.com/open-spaced-repetition/fsrs-rs.git?rev=58ca25ed2bc4bb1dc376208bbcaed7f5a501b941#58ca25ed2bc4bb1dc376208bbcaed7f5a501b941" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4938928321ed55a54cd8b90f0aa9dad79ee223aed6462cc37e83eb80b8bddb5a"
dependencies = [ dependencies = [
"burn", "burn",
"itertools 0.12.0", "itertools 0.12.0",

View File

@ -35,8 +35,9 @@ git = "https://github.com/ankitects/linkcheck.git"
rev = "184b2ca50ed39ca43da13f0b830a463861adb9ca" rev = "184b2ca50ed39ca43da13f0b830a463861adb9ca"
[workspace.dependencies.fsrs] [workspace.dependencies.fsrs]
git = "https://github.com/open-spaced-repetition/fsrs-rs.git" version = "0.2.0"
rev = "58ca25ed2bc4bb1dc376208bbcaed7f5a501b941" # git = "https://github.com/open-spaced-repetition/fsrs-rs.git"
# rev = "58ca25ed2bc4bb1dc376208bbcaed7f5a501b941"
# path = "../../../fsrs-rs" # path = "../../../fsrs-rs"
[workspace.dependencies] [workspace.dependencies]

View File

@ -1216,12 +1216,12 @@
}, },
{ {
"name": "fsrs", "name": "fsrs",
"version": "0.1.0", "version": "0.2.0",
"authors": null, "authors": "Open Spaced Repetition",
"repository": null, "repository": "https://github.com/open-spaced-repetition/fsrs-rs",
"license": "BSD-3-Clause", "license": "BSD-3-Clause",
"license_file": null, "license_file": null,
"description": null "description": "FSRS for Rust, including Optimizer and Scheduler"
}, },
{ {
"name": "futf", "name": "futf",

View File

@ -335,11 +335,11 @@ deck-config-invalid-weights = Parameters must be either left blank to use the de
deck-config-not-enough-history = Insufficient review history to perform this operation. deck-config-not-enough-history = Insufficient review history to perform this operation.
deck-config-unable-to-determine-desired-retention = deck-config-unable-to-determine-desired-retention =
Unable to determine an optimal retention. Unable to determine an optimal retention.
deck-config-must-have-1000-reviews = deck-config-must-have-400-reviews =
{ $count -> { $count ->
[one] Only { $count } review was found. [one] Only { $count } review was found.
*[other] Only { $count } reviews were found. *[other] Only { $count } reviews were found.
} You must have at least 1000 reviews for this operation. } You must have at least 400 reviews for this operation.
# Numbers that control how aggressively the FSRS algorithm schedules cards # Numbers that control how aggressively the FSRS algorithm schedules cards
deck-config-weights = FSRS parameters deck-config-weights = FSRS parameters
deck-config-compute-optimal-weights = Optimize FSRS parameters deck-config-compute-optimal-weights = Optimize FSRS parameters

View File

@ -114,9 +114,9 @@ pub enum AnkiError {
InvalidMethodIndex, InvalidMethodIndex,
InvalidServiceIndex, InvalidServiceIndex,
FsrsWeightsInvalid, FsrsWeightsInvalid,
/// Returned by fsrs-rs; may happen even if 1000+ reviews /// Returned by fsrs-rs; may happen even if 400+ reviews
FsrsInsufficientData, FsrsInsufficientData,
/// Generated by our backend if count < 1000 /// Generated by our backend if count < 400
FsrsInsufficientReviews { FsrsInsufficientReviews {
count: usize, count: usize,
}, },
@ -175,7 +175,7 @@ impl AnkiError {
AnkiError::NotFound { source } => source.message(tr), AnkiError::NotFound { source } => source.message(tr),
AnkiError::FsrsInsufficientData => tr.deck_config_not_enough_history().into(), AnkiError::FsrsInsufficientData => tr.deck_config_not_enough_history().into(),
AnkiError::FsrsInsufficientReviews { count } => { AnkiError::FsrsInsufficientReviews { count } => {
tr.deck_config_must_have_1000_reviews(*count).into() tr.deck_config_must_have_400_reviews(*count).into()
} }
AnkiError::FsrsWeightsInvalid => tr.deck_config_invalid_weights().into(), AnkiError::FsrsWeightsInvalid => tr.deck_config_invalid_weights().into(),
AnkiError::SchedulerUpgradeRequired => { AnkiError::SchedulerUpgradeRequired => {

View File

@ -27,7 +27,7 @@ use crate::search::SortMode;
pub(crate) type Weights = Vec<f32>; pub(crate) type Weights = Vec<f32>;
impl Collection { impl Collection {
/// Note this does not return an error if there are less than 1000 items - /// Note this does not return an error if there are less than 400 items -
/// the caller should instead check the fsrs_items count in the return /// the caller should instead check the fsrs_items count in the return
/// value. /// value.
pub fn compute_weights( pub fn compute_weights(
@ -39,12 +39,12 @@ impl Collection {
let mut anki_progress = self.new_progress_handler::<ComputeWeightsProgress>(); let mut anki_progress = self.new_progress_handler::<ComputeWeightsProgress>();
let timing = self.timing_today()?; let timing = self.timing_today()?;
let revlogs = self.revlog_for_srs(search)?; let revlogs = self.revlog_for_srs(search)?;
if revlogs.len() < 1000 { if revlogs.len() < 400 {
return Err(AnkiError::FsrsInsufficientReviews { return Err(AnkiError::FsrsInsufficientReviews {
count: revlogs.len(), count: revlogs.len(),
}); });
} }
let items = fsrs_items_for_training(revlogs, timing.next_day_at); let items = fsrs_items_for_training(revlogs.clone(), timing.next_day_at);
let fsrs_items = items.len() as u32; let fsrs_items = items.len() as u32;
anki_progress.update(false, |p| { anki_progress.update(false, |p| {
p.fsrs_items = fsrs_items; p.fsrs_items = fsrs_items;
@ -70,7 +70,7 @@ impl Collection {
} }
}); });
let fsrs = FSRS::new(None)?; let fsrs = FSRS::new(None)?;
let weights = fsrs.compute_weights(items, Some(progress2))?; let weights = fsrs.compute_weights(items, revlogs.len() < 1000, Some(progress2))?;
Ok(ComputeFsrsWeightsResponse { Ok(ComputeFsrsWeightsResponse {
weights, weights,
fsrs_items, fsrs_items,
@ -123,7 +123,7 @@ impl Collection {
.col .col
.storage .storage
.get_revlog_entries_for_searched_cards_in_card_order()?; .get_revlog_entries_for_searched_cards_in_card_order()?;
if revlogs.len() < 1000 { if revlogs.len() < 400 {
return Err(AnkiError::FsrsInsufficientReviews { return Err(AnkiError::FsrsInsufficientReviews {
count: revlogs.len(), count: revlogs.len(),
}); });

View File

@ -307,6 +307,7 @@ impl crate::services::BackendSchedulerService for Backend {
let fsrs_items = req.items.len() as u32; let fsrs_items = req.items.len() as u32;
let weights = fsrs.compute_weights( let weights = fsrs.compute_weights(
req.items.into_iter().map(fsrs_item_proto_to_fsrs).collect(), req.items.into_iter().map(fsrs_item_proto_to_fsrs).collect(),
false,
None, None,
)?; )?;
Ok(ComputeFsrsWeightsResponse { Ok(ComputeFsrsWeightsResponse {

View File

@ -108,9 +108,9 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
if (computeWeightsProgress) { if (computeWeightsProgress) {
computeWeightsProgress.current = computeWeightsProgress.total; computeWeightsProgress.current = computeWeightsProgress.total;
} }
if (resp.fsrsItems < 1000) { if (resp.fsrsItems < 400) {
alert( alert(
tr.deckConfigMustHave1000Reviews({ count: resp.fsrsItems }), tr.deckConfigMustHave400Reviews({ count: resp.fsrsItems }),
); );
} else { } else {
$config.fsrsWeights = resp.weights; $config.fsrsWeights = resp.weights;