Feat/Per card parameters for simulator#377
Feat/Per card parameters for simulator#377L-M-Sherlock merged 7 commits intoopen-spaced-repetition:mainfrom
Conversation
Summary of ChangesHello @Luc-Mcgrady, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request introduces a fundamental change to the simulator's parameter handling by enabling each individual card to carry its own set of parameters. This enhancement moves away from a monolithic global parameter approach, paving the way for more nuanced and flexible simulations where different cards can adhere to distinct learning models or weightings. The modifications involve structural changes to the Highlights
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
There was a problem hiding this comment.
Code Review
This pull request introduces the ability to specify FSRS parameters on a per-card basis, which is a valuable enhancement for simulations. The implementation is mostly on the right track, with updates to data structures and function signatures to accommodate this change. However, I've identified a critical bug in expected_workload_with_existing_cards where the WorkloadEstimator is not correctly used when cards have different parameter sets, leading to incorrect calculations. I've also provided a suggestion to improve the Card API to make it more robust and prevent potential misuse. Addressing these points will significantly improve the correctness and maintainability of the new feature.
| let w = check_and_fill_parameters(parameters)?; | ||
| let mut estimator = WorkloadEstimator::new(config); | ||
| estimator.precompute_cost_matrix(desired_retention, w); | ||
| estimator.precompute_cost_matrix(desired_retention, &w); |
There was a problem hiding this comment.
There is a critical issue here. The WorkloadEstimator is initialized and its cost matrix is precomputed using a single set of parameters w. However, the function then processes cards that may have their own parameters, which can differ from w.
The evaluate_in_flight_card_cost and evaluate_new_card_cost methods rely on the precomputed cost_matrix. This will lead to incorrect workload calculations for any card whose parameters do not match w.
To fix this, you need to run the estimation for each unique set of parameters. You can do this by identifying all unique parameter sets, and for each set, filtering the cards that use it and calculating their combined workload.
Here's a possible implementation to replace lines 570-605:
let mut estimator = WorkloadEstimator::new(config);
let mut cards = existing_cards.to_vec();
let w_global = Arc::new(check_and_fill_parameters(parameters)?);
if config.learn_limit > 0 {
let init_ratings = (0..(config.deck_size - cards.len())).map(|i| Card {
id: -(i as i64),
difficulty: f32::NEG_INFINITY,
stability: f32::NEG_INFINITY,
last_date: f32::NEG_INFINITY,
due: (i / config.learn_limit) as f32,
interval: f32::NEG_INFINITY,
lapses: 0,
desired_retention,
parameters: w_global.clone(),
});
cards.extend(init_ratings);
}
let mut unique_params: Vec<Arc<Vec<f32>>> = vec![];
for card in &cards {
if !unique_params.iter().any(|p| Arc::ptr_eq(p, &card.parameters)) {
unique_params.push(card.parameters.clone());
}
}
let mut total_workload = 0.0;
for params in unique_params {
estimator.precompute_cost_matrix(desired_retention, ¶ms);
let group_workload: f32 = cards.iter().filter(|c| Arc::ptr_eq(&c.parameters, ¶ms)).map(|card| {
if card.stability > 1e-9 {
estimator.evaluate_in_flight_card_cost(card, &card.parameters)
} else {
estimator.evaluate_new_card_cost(
&card.parameters,
&config.first_rating_prob,
card.due as usize,
)
}
}).sum();
total_workload += group_workload;
}
return Ok(total_workload);This is a critical bug that affects the correctness of the workload estimation. Also, consider adding a test case for expected_workload_with_existing_cards with cards that have different parameters to cover this scenario.
There was a problem hiding this comment.
I will give up on the workload version.
|
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request introduces a significant feature: per-card parameters for the simulator. The changes are mostly well-implemented, updating the Card struct and the simulate function to correctly use these new parameters. However, I've identified a critical issue in expected_workload_with_existing_cards where it fails to use the per-card parameters, instead using global ones. Additionally, I've provided a suggestion to improve the Card struct's API to prevent potential misuse regarding parameter validation.
… clarifying that per-card parameters are ignored in favor of global parameters.
Which structure of function did you mean? |
| pub desired_retention: f32, | ||
| // check_and_fill_parameters needs to be called manually on the parameters provided to the card. | ||
| pub parameters: Arc<Vec<f32>>, |
There was a problem hiding this comment.
Wrap these in an Option and use the defaults in the function if it's None.
There was a problem hiding this comment.
It depends on how we call this API in Anki's side. How do you think?
There was a problem hiding this comment.
Will it be implemented in Anki before you release it? Then we can change it to an Option if it is easier.
There was a problem hiding this comment.
I haven't figured out how to design an UI for the simulator which can include multiple presets. Do you have any idea? Btw, I it's not very urgent for me to make a new release. Burn recently released 0.20, I would take a look when I'm available.
There was a problem hiding this comment.
I think maybe we could just have a search-box in the simulator modal and the cards that it matches regardless of preset?
Also I'm not sure how to use the per deck DR with the simulators DR setting.
There was a problem hiding this comment.
how to use the per deck DR with the simulators DR setting.
Can we just store the DR in Card structure?
There was a problem hiding this comment.
OMG... I haven't thought about it.
Co-authored-by: Luc Mcgrady <lucmcgrady@gmail.com>
|
Let's merge it and leave the remaining issues to the next PR. |
I'm not sure if the parameters and desired retention would be better in an option? That way they can be opted out of for the values passed to the function maybe?