Added: start_memorized

This commit is contained in:
Luc Mcgrady 2025-09-01 16:47:02 +01:00
parent c2fdf474dd
commit c0a67c3eaa
No known key found for this signature in database
GPG key ID: 4F3D7A0B17CC3D9C
5 changed files with 17 additions and 9 deletions

View file

@ -522,8 +522,7 @@ deck-config-save-options-to-preset-confirm = Overwrite the options in your curre
# specific date. # specific date.
deck-config-fsrs-simulator-radio-memorized = Memorized deck-config-fsrs-simulator-radio-memorized = Memorized
deck-config-fsrs-simulator-radio-ratio = Time / Memorized Ratio deck-config-fsrs-simulator-radio-ratio = Time / Memorized Ratio
# $time here is pre-formatted e.g. "10 Seconds" deck-config-fsrs-simulator-ratio-tooltip = { $time } memorized cards per hour
deck-config-fsrs-simulator-ratio-tooltip = { $time } per memorized card
## Messages related to the FSRS schedulers health check. The health check determines whether the correlation between FSRS predictions and your memory is good or bad. It can be optionally triggered as part of the "Optimize" function. ## Messages related to the FSRS schedulers health check. The health check determines whether the correlation between FSRS predictions and your memory is good or bad. It can be optionally triggered as part of the "Optimize" function.

View file

@ -420,8 +420,9 @@ message SimulateFsrsReviewResponse {
message SimulateFsrsWorkloadResponse { message SimulateFsrsWorkloadResponse {
map<uint32, float> cost = 1; map<uint32, float> cost = 1;
map<uint32, float> memorized = 2; float start_memorized = 2;
map<uint32, uint32> review_count = 3; map<uint32, float> memorized = 3;
map<uint32, uint32> review_count = 4;
} }
message ComputeOptimalRetentionResponse { message ComputeOptimalRetentionResponse {

View file

@ -292,8 +292,7 @@ impl Collection {
Ok(( Ok((
dr, dr,
( (
*result.memorized_cnt_per_day.last().unwrap_or(&0.) *result.memorized_cnt_per_day.last().unwrap_or(&0.),
- *result.memorized_cnt_per_day.first().unwrap_or(&0.),
result.cost_per_day.iter().sum::<f32>(), result.cost_per_day.iter().sum::<f32>(),
result.review_cnt_per_day.iter().sum::<usize>() as u32 result.review_cnt_per_day.iter().sum::<usize>() as u32
+ result.learn_cnt_per_day.iter().sum::<usize>() as u32, + result.learn_cnt_per_day.iter().sum::<usize>() as u32,
@ -301,7 +300,11 @@ impl Collection {
)) ))
}) })
.collect::<Result<HashMap<_, _>>>()?; .collect::<Result<HashMap<_, _>>>()?;
let start_memorized = cards
.iter()
.fold(0., |p, c| p + c.retention_on(&req.params, 0.));
Ok(SimulateFsrsWorkloadResponse { Ok(SimulateFsrsWorkloadResponse {
start_memorized,
memorized: dr_workload.iter().map(|(k, v)| (*k, v.0)).collect(), memorized: dr_workload.iter().map(|(k, v)| (*k, v.0)).collect(),
cost: dr_workload.iter().map(|(k, v)| (*k, v.1)).collect(), cost: dr_workload.iter().map(|(k, v)| (*k, v.1)).collect(),
review_count: dr_workload.iter().map(|(k, v)| (*k, v.2)).collect(), review_count: dr_workload.iter().map(|(k, v)| (*k, v.2)).collect(),

View file

@ -212,6 +212,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
x: parseInt(dr), x: parseInt(dr),
timeCost: resp!.cost[dr], timeCost: resp!.cost[dr],
memorized: v, memorized: v,
start_memorized: resp!.startMemorized,
count: resp!.reviewCount[dr], count: resp!.reviewCount[dr],
label: simulationNumber, label: simulationNumber,
learnSpan: simulateFsrsRequest.daysToSimulate, learnSpan: simulateFsrsRequest.daysToSimulate,

View file

@ -34,6 +34,7 @@ export interface Point {
export type WorkloadPoint = Point & { export type WorkloadPoint = Point & {
learnSpan: number; learnSpan: number;
start_memorized: number;
}; };
export enum SimulateSubgraph { export enum SimulateSubgraph {
@ -63,14 +64,17 @@ export function renderWorkloadChart(
.range([bounds.marginLeft, bounds.width - bounds.marginRight]); .range([bounds.marginLeft, bounds.width - bounds.marginRight]);
const subgraph_data = ({ const subgraph_data = ({
[SimulateWorkloadSubgraph.ratio]: data.map(d => ({ ...d, y: d.memorized / d.timeCost })), [SimulateWorkloadSubgraph.ratio]: data.map(d => ({
...d,
y: (60 * 60 * (d.memorized - d.start_memorized)) / d.timeCost,
})),
[SimulateWorkloadSubgraph.time]: data.map(d => ({ ...d, y: d.timeCost / d.learnSpan })), [SimulateWorkloadSubgraph.time]: data.map(d => ({ ...d, y: d.timeCost / d.learnSpan })),
[SimulateWorkloadSubgraph.count]: data.map(d => ({ ...d, y: d.count / d.learnSpan })), [SimulateWorkloadSubgraph.count]: data.map(d => ({ ...d, y: d.count / d.learnSpan })),
[SimulateWorkloadSubgraph.memorized]: data.map(d => ({ ...d, y: d.memorized })), [SimulateWorkloadSubgraph.memorized]: data.map(d => ({ ...d, y: d.memorized })),
})[subgraph]; })[subgraph];
const yTickFormat = (n: number): string => { const yTickFormat = (n: number): string => {
return subgraph == SimulateWorkloadSubgraph.time || subgraph == SimulateWorkloadSubgraph.ratio return subgraph == SimulateWorkloadSubgraph.time
? timeSpan(n, true) ? timeSpan(n, true)
: n.toString(); : n.toString();
}; };
@ -84,7 +88,7 @@ export function renderWorkloadChart(
const formatY: (value: number) => string = ({ const formatY: (value: number) => string = ({
[SimulateWorkloadSubgraph.ratio]: (value: number) => [SimulateWorkloadSubgraph.ratio]: (value: number) =>
tr.deckConfigFsrsSimulatorRatioTooltip({ time: timeSpan(value) }), tr.deckConfigFsrsSimulatorRatioTooltip({ time: value.toFixed(2) }),
[SimulateWorkloadSubgraph.time]: (value: number) => [SimulateWorkloadSubgraph.time]: (value: number) =>
tr.statisticsMinutesPerDay({ count: parseFloat((value / 60).toPrecision(2)) }), tr.statisticsMinutesPerDay({ count: parseFloat((value / 60).toPrecision(2)) }),
[SimulateWorkloadSubgraph.count]: (value: number) => tr.statisticsReviewsPerDay({ count: Math.round(value) }), [SimulateWorkloadSubgraph.count]: (value: number) => tr.statisticsReviewsPerDay({ count: Math.round(value) }),