Feat/support new cards ignore review limit in simulator (#3707)

* Feat/support new cards ignore review limit in simulator

* ./ninja fix:minilints & ./ninja format

* use published crate

* make newCardsIgnoreReviewLimit reactive

* format

---------

Co-authored-by: Damien Elmes <gpg@ankiweb.net>
This commit is contained in:
Jarrett Ye 2025-01-09 19:49:13 +08:00 committed by GitHub
parent f0e67c4cd3
commit c4ad27a2db
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 29 additions and 16 deletions

4
Cargo.lock generated
View file

@ -1860,9 +1860,9 @@ dependencies = [
[[package]] [[package]]
name = "fsrs" name = "fsrs"
version = "1.5.0" version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "738a17a9825de16c23063c5931738e96aacce208a9b0ab54260c6ea2aa6a6feb" checksum = "b444b46751c2196ed329f3e577e8a693b948d9d0f07c237473c15dead8d7000e"
dependencies = [ dependencies = [
"burn", "burn",
"itertools 0.12.1", "itertools 0.12.1",

View file

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

View file

@ -1225,7 +1225,7 @@
}, },
{ {
"name": "fsrs", "name": "fsrs",
"version": "1.5.0", "version": "2.0.0",
"authors": "Open Spaced Repetition", "authors": "Open Spaced Repetition",
"repository": "https://github.com/open-spaced-repetition/fsrs-rs", "repository": "https://github.com/open-spaced-repetition/fsrs-rs",
"license": "BSD-3-Clause", "license": "BSD-3-Clause",

View file

@ -388,6 +388,7 @@ message SimulateFsrsReviewRequest {
uint32 review_limit = 6; uint32 review_limit = 6;
uint32 max_interval = 7; uint32 max_interval = 7;
string search = 8; string search = 8;
bool new_cards_ignore_review_limit = 9;
} }
message SimulateFsrsReviewResponse { message SimulateFsrsReviewResponse {

View file

@ -97,7 +97,8 @@ impl Collection {
} }
} }
}); });
let mut params = FSRS::new(None)?.compute_parameters(items.clone(), Some(progress2))?; let mut params =
FSRS::new(None)?.compute_parameters(items.clone(), Some(progress2), true)?;
progress_thread.join().ok(); progress_thread.join().ok();
if let Ok(fsrs) = FSRS::new(Some(current_params)) { if let Ok(fsrs) = FSRS::new(Some(current_params)) {
let current_rmse = fsrs.evaluate(items.clone(), |_| true)?.rmse_bins; let current_rmse = fsrs.evaluate(items.clone(), |_| true)?.rmse_bins;

View file

@ -53,6 +53,7 @@ impl Collection {
loss_aversion: req.loss_aversion as f32, loss_aversion: req.loss_aversion as f32,
learn_limit, learn_limit,
review_limit: usize::MAX, review_limit: usize::MAX,
new_cards_ignore_review_limit: true,
}, },
&req.params, &req.params,
|ip| { |ip| {

View file

@ -46,13 +46,9 @@ impl Collection {
loss_aversion: 1.0, loss_aversion: 1.0,
learn_limit: req.new_limit as usize, learn_limit: req.new_limit as usize,
review_limit: req.review_limit as usize, review_limit: req.review_limit as usize,
new_cards_ignore_review_limit: req.new_cards_ignore_review_limit,
}; };
let ( let result = simulate(
accumulated_knowledge_acquisition,
daily_review_count,
daily_new_count,
daily_time_cost,
) = simulate(
&config, &config,
&req.params, &req.params,
req.desired_retention, req.desired_retention,
@ -60,10 +56,18 @@ impl Collection {
Some(converted_cards), Some(converted_cards),
)?; )?;
Ok(SimulateFsrsReviewResponse { Ok(SimulateFsrsReviewResponse {
accumulated_knowledge_acquisition: accumulated_knowledge_acquisition.to_vec(), accumulated_knowledge_acquisition: result.memorized_cnt_per_day.to_vec(),
daily_review_count: daily_review_count.iter().map(|x| *x as u32).collect_vec(), daily_review_count: result
daily_new_count: daily_new_count.iter().map(|x| *x as u32).collect_vec(), .review_cnt_per_day
daily_time_cost: daily_time_cost.to_vec(), .iter()
.map(|x| *x as u32)
.collect_vec(),
daily_new_count: result
.learn_cnt_per_day
.iter()
.map(|x| *x as u32)
.collect_vec(),
daily_time_cost: result.cost_per_day.to_vec(),
}) })
} }
} }

View file

@ -348,6 +348,7 @@ impl crate::services::BackendSchedulerService for Backend {
let params = fsrs.compute_parameters( let params = fsrs.compute_parameters(
req.items.into_iter().map(fsrs_item_proto_to_fsrs).collect(), req.items.into_iter().map(fsrs_item_proto_to_fsrs).collect(),
None, None,
true,
)?; )?;
Ok(ComputeFsrsParamsResponse { params, fsrs_items }) Ok(ComputeFsrsParamsResponse { params, fsrs_items })
} }
@ -362,7 +363,7 @@ impl crate::services::BackendSchedulerService for Backend {
.into_iter() .into_iter()
.map(fsrs_item_proto_to_fsrs) .map(fsrs_item_proto_to_fsrs)
.collect(); .collect();
let params = fsrs.benchmark(train_set); let params = fsrs.benchmark(train_set, true);
Ok(FsrsBenchmarkResponse { params }) Ok(FsrsBenchmarkResponse { params })
} }

View file

@ -90,6 +90,8 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
optimalRetentionRequest.daysToSimulate = 3650; optimalRetentionRequest.daysToSimulate = 3650;
} }
$: newCardsIgnoreReviewLimit = state.newCardsIgnoreReviewLimit;
const simulateFsrsRequest = new SimulateFsrsReviewRequest({ const simulateFsrsRequest = new SimulateFsrsReviewRequest({
params: fsrsParams($config), params: fsrsParams($config),
desiredRetention: $config.desiredRetention, desiredRetention: $config.desiredRetention,
@ -99,6 +101,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
reviewLimit: $config.reviewsPerDay, reviewLimit: $config.reviewsPerDay,
maxInterval: $config.maximumReviewInterval, maxInterval: $config.maximumReviewInterval,
search: `preset:"${state.getCurrentNameForSearch()}" -is:suspended`, search: `preset:"${state.getCurrentNameForSearch()}" -is:suspended`,
newCardsIgnoreReviewLimit: $newCardsIgnoreReviewLimit,
}); });
function getRetentionWarning(retention: number): string { function getRetentionWarning(retention: number): string {
@ -318,6 +321,8 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
simulateFsrsRequest.params = fsrsParams($config); simulateFsrsRequest.params = fsrsParams($config);
simulateFsrsRequest.desiredRetention = $config.desiredRetention; simulateFsrsRequest.desiredRetention = $config.desiredRetention;
simulateFsrsRequest.search = `preset:"${state.getCurrentNameForSearch()}" -is:suspended`; simulateFsrsRequest.search = `preset:"${state.getCurrentNameForSearch()}" -is:suspended`;
simulateFsrsRequest.newCardsIgnoreReviewLimit =
$newCardsIgnoreReviewLimit;
simulating = true; simulating = true;
resp = await simulateFsrsReview(simulateFsrsRequest); resp = await simulateFsrsReview(simulateFsrsRequest);
}, },