mirror of
https://github.com/ankitects/anki.git
synced 2025-11-06 04:37:22 -05:00
Fix/Ensure fuzz doesn't go backward during rescheduling (#4364)
* Fix/Ensure fuzz doesn't go backward during rescheduling Fixes https://github.com/ankitects/anki/issues/2694 * Fix * Get previous_interval from LastRevlogInfo * Fix * Format * Format * Exclude lapses * Force reconfigure in CI The cached build.ninja may reference files that don't exist in the PR. On a local build this tends to auto-fix itself as the build scripts detect a quick failure and re-run the configure, but CI tends to be too slow. https://github.com/ankitects/anki/pull/4364#issuecomment-3338026129 * Rename min/max to make it clear they restrict interval, not fuzz * Wording tweaks/comments for clarity --------- Co-authored-by: Damien Elmes <gpg@ankiweb.net>
This commit is contained in:
parent
d8aa244a5a
commit
b0665a8ef1
3 changed files with 37 additions and 6 deletions
|
|
@ -16,6 +16,7 @@ if [ "$CLEAR_RUST" = "1" ]; then
|
||||||
rm -rf $BUILD_ROOT/rust
|
rm -rf $BUILD_ROOT/rust
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
rm -f out/build.ninja
|
||||||
./ninja pylib qt check
|
./ninja pylib qt check
|
||||||
|
|
||||||
echo "--- Ensure libs importable"
|
echo "--- Ensure libs importable"
|
||||||
|
|
|
||||||
|
|
@ -136,6 +136,19 @@ impl Collection {
|
||||||
let deckconfig_id = deck.config_id().unwrap();
|
let deckconfig_id = deck.config_id().unwrap();
|
||||||
// reschedule it
|
// reschedule it
|
||||||
let original_interval = card.interval;
|
let original_interval = card.interval;
|
||||||
|
let min_interval = |interval: u32| {
|
||||||
|
let previous_interval =
|
||||||
|
last_info.previous_interval.unwrap_or(0);
|
||||||
|
if interval > previous_interval {
|
||||||
|
// interval grew; don't allow fuzzed interval to
|
||||||
|
// be less than previous+1
|
||||||
|
previous_interval + 1
|
||||||
|
} else {
|
||||||
|
// interval shrunk; don't restrict negative fuzz
|
||||||
|
0
|
||||||
|
}
|
||||||
|
.max(1)
|
||||||
|
};
|
||||||
let interval = fsrs.next_interval(
|
let interval = fsrs.next_interval(
|
||||||
Some(state.stability),
|
Some(state.stability),
|
||||||
desired_retention,
|
desired_retention,
|
||||||
|
|
@ -146,7 +159,7 @@ impl Collection {
|
||||||
.and_then(|r| {
|
.and_then(|r| {
|
||||||
r.find_interval(
|
r.find_interval(
|
||||||
interval,
|
interval,
|
||||||
1,
|
min_interval(interval as u32),
|
||||||
req.max_interval,
|
req.max_interval,
|
||||||
days_elapsed as u32,
|
days_elapsed as u32,
|
||||||
deckconfig_id,
|
deckconfig_id,
|
||||||
|
|
@ -157,7 +170,7 @@ impl Collection {
|
||||||
with_review_fuzz(
|
with_review_fuzz(
|
||||||
card.get_fuzz_factor(true),
|
card.get_fuzz_factor(true),
|
||||||
interval,
|
interval,
|
||||||
1,
|
min_interval(interval as u32),
|
||||||
req.max_interval,
|
req.max_interval,
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
|
@ -310,6 +323,9 @@ pub(crate) struct LastRevlogInfo {
|
||||||
/// reviewed the card and now, so that we can determine an accurate period
|
/// reviewed the card and now, so that we can determine an accurate period
|
||||||
/// when the card has subsequently been rescheduled to a different day.
|
/// when the card has subsequently been rescheduled to a different day.
|
||||||
pub(crate) last_reviewed_at: Option<TimestampSecs>,
|
pub(crate) last_reviewed_at: Option<TimestampSecs>,
|
||||||
|
/// The interval before the latest review. Used to prevent fuzz from going
|
||||||
|
/// backwards when rescheduling the card
|
||||||
|
pub(crate) previous_interval: Option<u32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return a map of cards to info about last review.
|
/// Return a map of cards to info about last review.
|
||||||
|
|
@ -321,14 +337,27 @@ pub(crate) fn get_last_revlog_info(revlogs: &[RevlogEntry]) -> HashMap<CardId, L
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.for_each(|(card_id, group)| {
|
.for_each(|(card_id, group)| {
|
||||||
let mut last_reviewed_at = None;
|
let mut last_reviewed_at = None;
|
||||||
|
let mut previous_interval = None;
|
||||||
for e in group.into_iter() {
|
for e in group.into_iter() {
|
||||||
if e.has_rating_and_affects_scheduling() {
|
if e.has_rating_and_affects_scheduling() {
|
||||||
last_reviewed_at = Some(e.id.as_secs());
|
last_reviewed_at = Some(e.id.as_secs());
|
||||||
|
previous_interval = if e.last_interval >= 0 && e.button_chosen > 1 {
|
||||||
|
Some(e.last_interval as u32)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
} else if e.is_reset() {
|
} else if e.is_reset() {
|
||||||
last_reviewed_at = None;
|
last_reviewed_at = None;
|
||||||
|
previous_interval = None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
out.insert(card_id, LastRevlogInfo { last_reviewed_at });
|
out.insert(
|
||||||
|
card_id,
|
||||||
|
LastRevlogInfo {
|
||||||
|
last_reviewed_at,
|
||||||
|
previous_interval,
|
||||||
|
},
|
||||||
|
);
|
||||||
});
|
});
|
||||||
out
|
out
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -115,13 +115,14 @@ impl Rescheduler {
|
||||||
pub fn find_interval(
|
pub fn find_interval(
|
||||||
&self,
|
&self,
|
||||||
interval: f32,
|
interval: f32,
|
||||||
minimum: u32,
|
minimum_interval: u32,
|
||||||
maximum: u32,
|
maximum_interval: u32,
|
||||||
days_elapsed: u32,
|
days_elapsed: u32,
|
||||||
deckconfig_id: DeckConfigId,
|
deckconfig_id: DeckConfigId,
|
||||||
fuzz_seed: Option<u64>,
|
fuzz_seed: Option<u64>,
|
||||||
) -> Option<u32> {
|
) -> Option<u32> {
|
||||||
let (before_days, after_days) = constrained_fuzz_bounds(interval, minimum, maximum);
|
let (before_days, after_days) =
|
||||||
|
constrained_fuzz_bounds(interval, minimum_interval, maximum_interval);
|
||||||
|
|
||||||
// Don't reschedule the card when it's overdue
|
// Don't reschedule the card when it's overdue
|
||||||
if after_days < days_elapsed {
|
if after_days < days_elapsed {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue