mirror of
https://github.com/ankitects/anki.git
synced 2025-09-18 14:02:21 -04:00
Rename remaining 'weights' references to 'params'
This commit is contained in:
parent
c45fa518d2
commit
6adbd922f7
27 changed files with 194 additions and 200 deletions
|
@ -127,21 +127,21 @@ message Progress {
|
|||
DatabaseCheck database_check = 6;
|
||||
string importing = 7;
|
||||
string exporting = 8;
|
||||
ComputeWeightsProgress compute_weights = 9;
|
||||
ComputeParamsProgress compute_params = 9;
|
||||
ComputeRetentionProgress compute_retention = 10;
|
||||
ComputeMemoryProgress compute_memory = 11;
|
||||
}
|
||||
}
|
||||
|
||||
message ComputeWeightsProgress {
|
||||
message ComputeParamsProgress {
|
||||
// Current iteration
|
||||
uint32 current = 1;
|
||||
// Total iterations
|
||||
uint32 total = 2;
|
||||
uint32 reviews = 3;
|
||||
// Only used in 'compute all weights' case
|
||||
// Only used in 'compute all params' case
|
||||
uint32 current_preset = 4;
|
||||
// Only used in 'compute all weights' case
|
||||
// Only used in 'compute all params' case
|
||||
uint32 total_presets = 5;
|
||||
}
|
||||
|
||||
|
|
|
@ -165,7 +165,7 @@ message DeckConfig {
|
|||
// used for fsrs_reschedule in the past
|
||||
reserved 39;
|
||||
float historical_retention = 40;
|
||||
string weight_search = 45;
|
||||
string param_search = 45;
|
||||
|
||||
bytes other = 255;
|
||||
}
|
||||
|
@ -215,7 +215,7 @@ message DeckConfigsForUpdate {
|
|||
enum UpdateDeckConfigsMode {
|
||||
UPDATE_DECK_CONFIGS_MODE_NORMAL = 0;
|
||||
UPDATE_DECK_CONFIGS_MODE_APPLY_TO_CHILDREN = 1;
|
||||
UPDATE_DECK_CONFIGS_MODE_COMPUTE_ALL_WEIGHTS = 2;
|
||||
UPDATE_DECK_CONFIGS_MODE_COMPUTE_ALL_PARAMS = 2;
|
||||
}
|
||||
|
||||
message UpdateDeckConfigsRequest {
|
||||
|
|
|
@ -45,15 +45,15 @@ service SchedulerService {
|
|||
rpc CustomStudyDefaults(CustomStudyDefaultsRequest)
|
||||
returns (CustomStudyDefaultsResponse);
|
||||
rpc RepositionDefaults(generic.Empty) returns (RepositionDefaultsResponse);
|
||||
rpc ComputeFsrsWeights(ComputeFsrsWeightsRequest)
|
||||
returns (ComputeFsrsWeightsResponse);
|
||||
rpc ComputeFsrsParams(ComputeFsrsParamsRequest)
|
||||
returns (ComputeFsrsParamsResponse);
|
||||
rpc GetOptimalRetentionParameters(GetOptimalRetentionParametersRequest)
|
||||
returns (GetOptimalRetentionParametersResponse);
|
||||
rpc ComputeOptimalRetention(ComputeOptimalRetentionRequest)
|
||||
returns (ComputeOptimalRetentionResponse);
|
||||
rpc SimulateFsrsReview(SimulateFsrsReviewRequest)
|
||||
returns (SimulateFsrsReviewResponse);
|
||||
rpc EvaluateWeights(EvaluateWeightsRequest) returns (EvaluateWeightsResponse);
|
||||
rpc EvaluateParams(EvaluateParamsRequest) returns (EvaluateParamsResponse);
|
||||
rpc ComputeMemoryState(cards.CardId) returns (ComputeMemoryStateResponse);
|
||||
// The number of days the calculated interval was fuzzed by on the previous
|
||||
// review (if any). Utilized by the FSRS add-on.
|
||||
|
@ -63,8 +63,8 @@ service SchedulerService {
|
|||
// Implicitly includes any of the above methods that are not listed in the
|
||||
// backend service.
|
||||
service BackendSchedulerService {
|
||||
rpc ComputeFsrsWeightsFromItems(ComputeFsrsWeightsFromItemsRequest)
|
||||
returns (ComputeFsrsWeightsResponse);
|
||||
rpc ComputeFsrsParamsFromItems(ComputeFsrsParamsFromItemsRequest)
|
||||
returns (ComputeFsrsParamsResponse);
|
||||
// Generates parameters used for FSRS's scheduler benchmarks.
|
||||
rpc FsrsBenchmark(FsrsBenchmarkRequest) returns (FsrsBenchmarkResponse);
|
||||
// Used for exporting revlogs for algorithm research.
|
||||
|
@ -341,19 +341,19 @@ message RepositionDefaultsResponse {
|
|||
bool shift = 2;
|
||||
}
|
||||
|
||||
message ComputeFsrsWeightsRequest {
|
||||
message ComputeFsrsParamsRequest {
|
||||
/// The search used to gather cards for training
|
||||
string search = 1;
|
||||
repeated float current_weights = 2;
|
||||
repeated float current_params = 2;
|
||||
int64 ignore_revlogs_before_ms = 3;
|
||||
}
|
||||
|
||||
message ComputeFsrsWeightsResponse {
|
||||
repeated float weights = 1;
|
||||
message ComputeFsrsParamsResponse {
|
||||
repeated float params = 1;
|
||||
uint32 fsrs_items = 2;
|
||||
}
|
||||
|
||||
message ComputeFsrsWeightsFromItemsRequest {
|
||||
message ComputeFsrsParamsFromItemsRequest {
|
||||
repeated FsrsItem items = 1;
|
||||
}
|
||||
|
||||
|
@ -362,7 +362,7 @@ message FsrsBenchmarkRequest {
|
|||
}
|
||||
|
||||
message FsrsBenchmarkResponse {
|
||||
repeated float weights = 1;
|
||||
repeated float params = 1;
|
||||
}
|
||||
|
||||
message ExportDatasetRequest {
|
||||
|
@ -380,7 +380,7 @@ message FsrsReview {
|
|||
}
|
||||
|
||||
message SimulateFsrsReviewRequest {
|
||||
repeated float weights = 1;
|
||||
repeated float params = 1;
|
||||
float desired_retention = 2;
|
||||
uint32 deck_size = 3;
|
||||
uint32 days_to_simulate = 4;
|
||||
|
@ -398,7 +398,7 @@ message SimulateFsrsReviewResponse {
|
|||
}
|
||||
|
||||
message ComputeOptimalRetentionRequest {
|
||||
repeated float weights = 1;
|
||||
repeated float params = 1;
|
||||
uint32 days_to_simulate = 2;
|
||||
uint32 max_interval = 3;
|
||||
string search = 4;
|
||||
|
@ -431,13 +431,13 @@ message GetOptimalRetentionParametersResponse {
|
|||
uint32 review_limit = 15;
|
||||
}
|
||||
|
||||
message EvaluateWeightsRequest {
|
||||
repeated float weights = 1;
|
||||
message EvaluateParamsRequest {
|
||||
repeated float params = 1;
|
||||
string search = 2;
|
||||
int64 ignore_revlogs_before_ms = 3;
|
||||
}
|
||||
|
||||
message EvaluateWeightsResponse {
|
||||
message EvaluateParamsResponse {
|
||||
float log_loss = 1;
|
||||
float rmse_bins = 2;
|
||||
}
|
||||
|
|
|
@ -149,8 +149,8 @@ class RustBackend(RustBackendGenerated):
|
|||
)
|
||||
return self.format_timespan(seconds=seconds, context=context)
|
||||
|
||||
def compute_weights_from_items(self, items: Iterable[FsrsItem]) -> Sequence[float]:
|
||||
return self.compute_fsrs_weights_from_items(items).weights
|
||||
def compute_params_from_items(self, items: Iterable[FsrsItem]) -> Sequence[float]:
|
||||
return self.compute_fsrs_params_from_items(items).params
|
||||
|
||||
def benchmark(self, train_set: Iterable[FsrsItem]) -> Sequence[float]:
|
||||
return self.fsrs_benchmark(train_set=train_set)
|
||||
|
|
|
@ -457,8 +457,8 @@ def update_deck_configs() -> bytes:
|
|||
update.max = val.total_cards
|
||||
update.value = val.current_cards
|
||||
update.label = val.label
|
||||
elif progress.HasField("compute_weights"):
|
||||
val2 = progress.compute_weights
|
||||
elif progress.HasField("compute_params"):
|
||||
val2 = progress.compute_params
|
||||
# prevent an indeterminate progress bar from appearing at the start of each preset
|
||||
update.max = max(val2.total, 1)
|
||||
update.value = val2.current
|
||||
|
@ -621,10 +621,10 @@ exposed_backend_list = [
|
|||
"update_image_occlusion_note",
|
||||
"get_image_occlusion_fields",
|
||||
# SchedulerService
|
||||
"compute_fsrs_weights",
|
||||
"compute_fsrs_params",
|
||||
"compute_optimal_retention",
|
||||
"set_wants_abort",
|
||||
"evaluate_weights",
|
||||
"evaluate_params",
|
||||
"get_optimal_retention_parameters",
|
||||
"simulate_fsrs_review",
|
||||
]
|
||||
|
|
|
@ -42,7 +42,7 @@ impl AnkiError {
|
|||
AnkiError::InvalidId => Kind::InvalidInput,
|
||||
AnkiError::InvalidMethodIndex
|
||||
| AnkiError::InvalidServiceIndex
|
||||
| AnkiError::FsrsWeightsInvalid
|
||||
| AnkiError::FsrsParamsInvalid
|
||||
| AnkiError::FsrsUnableToDetermineDesiredRetention
|
||||
| AnkiError::FsrsInsufficientData => Kind::InvalidInput,
|
||||
#[cfg(windows)]
|
||||
|
|
|
@ -79,7 +79,7 @@ const DEFAULT_DECK_CONFIG_INNER: DeckConfigInner = DeckConfigInner {
|
|||
desired_retention: 0.9,
|
||||
other: Vec::new(),
|
||||
historical_retention: 0.9,
|
||||
weight_search: String::new(),
|
||||
param_search: String::new(),
|
||||
ignore_revlogs_before_date: String::new(),
|
||||
easy_days_percentages: Vec::new(),
|
||||
};
|
||||
|
|
|
@ -94,8 +94,8 @@ pub struct DeckConfSchema11 {
|
|||
#[serde(default)]
|
||||
/// historical retention
|
||||
sm2_retention: f32,
|
||||
#[serde(default)]
|
||||
weight_search: String,
|
||||
#[serde(default, rename = "weightSearch")]
|
||||
param_search: String,
|
||||
|
||||
#[serde(flatten)]
|
||||
other: HashMap<String, Value>,
|
||||
|
@ -312,7 +312,7 @@ impl Default for DeckConfSchema11 {
|
|||
fsrs_params_5: vec![],
|
||||
desired_retention: 0.9,
|
||||
sm2_retention: 0.9,
|
||||
weight_search: "".to_string(),
|
||||
param_search: "".to_string(),
|
||||
ignore_revlogs_before_date: "".to_string(),
|
||||
easy_days_percentages: vec![1.0; 7],
|
||||
}
|
||||
|
@ -395,7 +395,7 @@ impl From<DeckConfSchema11> for DeckConfig {
|
|||
easy_days_percentages: c.easy_days_percentages,
|
||||
desired_retention: c.desired_retention,
|
||||
historical_retention: c.sm2_retention,
|
||||
weight_search: c.weight_search,
|
||||
param_search: c.param_search,
|
||||
other: other_bytes,
|
||||
},
|
||||
}
|
||||
|
@ -506,7 +506,7 @@ impl From<DeckConfig> for DeckConfSchema11 {
|
|||
fsrs_params_5: i.fsrs_params_5,
|
||||
desired_retention: i.desired_retention,
|
||||
sm2_retention: i.historical_retention,
|
||||
weight_search: i.weight_search,
|
||||
param_search: i.param_search,
|
||||
ignore_revlogs_before_date: i.ignore_revlogs_before_date,
|
||||
easy_days_percentages: i.easy_days_percentages,
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ use crate::decks::NormalDeck;
|
|||
use crate::prelude::*;
|
||||
use crate::scheduler::fsrs::memory_state::UpdateMemoryStateEntry;
|
||||
use crate::scheduler::fsrs::memory_state::UpdateMemoryStateRequest;
|
||||
use crate::scheduler::fsrs::weights::ignore_revlogs_before_ms_from_config;
|
||||
use crate::scheduler::fsrs::params::ignore_revlogs_before_ms_from_config;
|
||||
use crate::search::JoinSearches;
|
||||
use crate::search::Negated;
|
||||
use crate::search::SearchNode;
|
||||
|
@ -159,8 +159,8 @@ impl Collection {
|
|||
configs_after_update.remove(dcid);
|
||||
}
|
||||
|
||||
if req.mode == UpdateDeckConfigsMode::ComputeAllWeights {
|
||||
self.compute_all_weights(&mut req)?;
|
||||
if req.mode == UpdateDeckConfigsMode::ComputeAllParams {
|
||||
self.compute_all_params(&mut req)?;
|
||||
}
|
||||
|
||||
// add/update provided configs
|
||||
|
@ -207,13 +207,13 @@ impl Collection {
|
|||
if let Ok(normal) = deck.normal() {
|
||||
let deck_id = deck.id;
|
||||
|
||||
// previous order & weights
|
||||
// previous order & params
|
||||
let previous_config_id = DeckConfigId(normal.config_id);
|
||||
let previous_config = configs_before_update.get(&previous_config_id);
|
||||
let previous_order = previous_config
|
||||
.map(|c| c.inner.new_card_insert_order())
|
||||
.unwrap_or_default();
|
||||
let previous_weights = previous_config.map(|c| c.fsrs_params());
|
||||
let previous_params = previous_config.map(|c| c.fsrs_params());
|
||||
let previous_retention = previous_config.map(|c| c.inner.desired_retention);
|
||||
|
||||
// if a selected (sub)deck, or its old config was removed, update deck to point
|
||||
|
@ -239,11 +239,11 @@ impl Collection {
|
|||
self.sort_deck(deck_id, current_order, usn)?;
|
||||
}
|
||||
|
||||
// if weights differ, memory state needs to be recomputed
|
||||
let current_weights = current_config.map(|c| c.fsrs_params());
|
||||
// if params differ, memory state needs to be recomputed
|
||||
let current_params = current_config.map(|c| c.fsrs_params());
|
||||
let current_retention = current_config.map(|c| c.inner.desired_retention);
|
||||
if fsrs_toggled
|
||||
|| previous_weights != current_weights
|
||||
|| previous_params != current_params
|
||||
|| previous_retention != current_retention
|
||||
{
|
||||
decks_needing_memory_recompute
|
||||
|
@ -261,10 +261,10 @@ impl Collection {
|
|||
.into_iter()
|
||||
.map(|(conf_id, search)| {
|
||||
let config = configs_after_update.get(&conf_id);
|
||||
let weights = config.and_then(|c| {
|
||||
let params = config.and_then(|c| {
|
||||
if req.fsrs {
|
||||
Some(UpdateMemoryStateRequest {
|
||||
weights: c.fsrs_params().clone(),
|
||||
params: c.fsrs_params().clone(),
|
||||
desired_retention: c.inner.desired_retention,
|
||||
max_interval: c.inner.maximum_review_interval,
|
||||
reschedule: req.fsrs_reschedule,
|
||||
|
@ -275,7 +275,7 @@ impl Collection {
|
|||
}
|
||||
});
|
||||
Ok(UpdateMemoryStateEntry {
|
||||
req: weights,
|
||||
req: params,
|
||||
search: SearchNode::DeckIdsWithoutChildren(comma_separated_ids(&search)),
|
||||
ignore_before: config
|
||||
.map(ignore_revlogs_before_ms_from_config)
|
||||
|
@ -329,7 +329,7 @@ impl Collection {
|
|||
}
|
||||
Ok(())
|
||||
}
|
||||
fn compute_all_weights(&mut self, req: &mut UpdateDeckConfigsRequest) -> Result<()> {
|
||||
fn compute_all_params(&mut self, req: &mut UpdateDeckConfigsRequest) -> Result<()> {
|
||||
require!(req.fsrs, "FSRS must be enabled");
|
||||
|
||||
// frontend didn't include any unmodified deck configs, so we need to fill them
|
||||
|
@ -344,28 +344,28 @@ impl Collection {
|
|||
// other parts of the code expect the currently-selected preset to come last
|
||||
req.configs.push(previous_last);
|
||||
|
||||
// calculate and apply weights to each preset
|
||||
// calculate and apply params to each preset
|
||||
let config_len = req.configs.len() as u32;
|
||||
for (idx, config) in req.configs.iter_mut().enumerate() {
|
||||
let search = if config.inner.weight_search.trim().is_empty() {
|
||||
let search = if config.inner.param_search.trim().is_empty() {
|
||||
SearchNode::Preset(config.name.clone())
|
||||
.and(SearchNode::State(StateKind::Suspended).negated())
|
||||
.try_into_search()?
|
||||
.to_string()
|
||||
} else {
|
||||
config.inner.weight_search.clone()
|
||||
config.inner.param_search.clone()
|
||||
};
|
||||
let ignore_revlogs_before_ms = ignore_revlogs_before_ms_from_config(config)?;
|
||||
match self.compute_weights(
|
||||
match self.compute_params(
|
||||
&search,
|
||||
ignore_revlogs_before_ms,
|
||||
idx as u32 + 1,
|
||||
config_len,
|
||||
config.fsrs_params(),
|
||||
) {
|
||||
Ok(weights) => {
|
||||
println!("{}: {:?}", config.name, weights.weights);
|
||||
config.inner.fsrs_params_5 = weights.weights;
|
||||
Ok(params) => {
|
||||
println!("{}: {:?}", config.name, params.params);
|
||||
config.inner.fsrs_params_5 = params.params;
|
||||
}
|
||||
Err(AnkiError::Interrupted) => return Err(AnkiError::Interrupted),
|
||||
Err(err) => {
|
||||
|
|
|
@ -113,7 +113,7 @@ pub enum AnkiError {
|
|||
},
|
||||
InvalidMethodIndex,
|
||||
InvalidServiceIndex,
|
||||
FsrsWeightsInvalid,
|
||||
FsrsParamsInvalid,
|
||||
/// Returned by fsrs-rs; may happen even if 400+ reviews
|
||||
FsrsInsufficientData,
|
||||
/// Generated by our backend if count < 400
|
||||
|
@ -181,7 +181,7 @@ impl AnkiError {
|
|||
AnkiError::FsrsInsufficientReviews { count } => {
|
||||
tr.deck_config_must_have_400_reviews(*count).into()
|
||||
}
|
||||
AnkiError::FsrsWeightsInvalid => tr.deck_config_invalid_parameters().into(),
|
||||
AnkiError::FsrsParamsInvalid => tr.deck_config_invalid_parameters().into(),
|
||||
AnkiError::SchedulerUpgradeRequired => {
|
||||
tr.scheduling_update_required().replace("V2", "v3")
|
||||
}
|
||||
|
|
|
@ -15,8 +15,8 @@ use crate::import_export::ExportProgress;
|
|||
use crate::import_export::ImportProgress;
|
||||
use crate::prelude::Collection;
|
||||
use crate::scheduler::fsrs::memory_state::ComputeMemoryProgress;
|
||||
use crate::scheduler::fsrs::params::ComputeParamsProgress;
|
||||
use crate::scheduler::fsrs::retention::ComputeRetentionProgress;
|
||||
use crate::scheduler::fsrs::weights::ComputeWeightsProgress;
|
||||
use crate::sync::collection::normal::NormalSyncProgress;
|
||||
use crate::sync::collection::progress::FullSyncProgress;
|
||||
use crate::sync::collection::progress::SyncStage;
|
||||
|
@ -131,7 +131,7 @@ pub enum Progress {
|
|||
DatabaseCheck(DatabaseCheckProgress),
|
||||
Import(ImportProgress),
|
||||
Export(ExportProgress),
|
||||
ComputeWeights(ComputeWeightsProgress),
|
||||
ComputeParams(ComputeParamsProgress),
|
||||
ComputeRetention(ComputeRetentionProgress),
|
||||
ComputeMemory(ComputeMemoryProgress),
|
||||
}
|
||||
|
@ -209,8 +209,8 @@ pub(crate) fn progress_to_proto(
|
|||
}
|
||||
.into(),
|
||||
),
|
||||
Progress::ComputeWeights(progress) => {
|
||||
Value::ComputeWeights(anki_proto::collection::ComputeWeightsProgress {
|
||||
Progress::ComputeParams(progress) => {
|
||||
Value::ComputeParams(anki_proto::collection::ComputeParamsProgress {
|
||||
current: progress.current_iteration,
|
||||
total: progress.total_iterations,
|
||||
reviews: progress.reviews,
|
||||
|
@ -296,9 +296,9 @@ impl From<ExportProgress> for Progress {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<ComputeWeightsProgress> for Progress {
|
||||
fn from(p: ComputeWeightsProgress) -> Self {
|
||||
Progress::ComputeWeights(p)
|
||||
impl From<ComputeParamsProgress> for Progress {
|
||||
fn from(p: ComputeParamsProgress) -> Self {
|
||||
Progress::ComputeParams(p)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ use rand::prelude::*;
|
|||
use rand::rngs::StdRng;
|
||||
use revlog::RevlogEntryPartial;
|
||||
|
||||
use super::fsrs::weights::ignore_revlogs_before_ms_from_config;
|
||||
use super::fsrs::params::ignore_revlogs_before_ms_from_config;
|
||||
use super::queue::BuryMode;
|
||||
use super::states::load_balancer::LoadBalancerContext;
|
||||
use super::states::steps::LearningSteps;
|
||||
|
@ -433,7 +433,7 @@ impl Collection {
|
|||
let fsrs_next_states = if fsrs_enabled {
|
||||
let fsrs = FSRS::new(Some(config.fsrs_params()))?;
|
||||
if card.memory_state.is_none() && card.ctype != CardType::New {
|
||||
// Card has been moved or imported into an FSRS deck after weights were set,
|
||||
// Card has been moved or imported into an FSRS deck after params were set,
|
||||
// and will need its initial memory state to be calculated based on review
|
||||
// history.
|
||||
let revlog = self.revlog_for_srs(SearchNode::CardIds(card.id.to_string()))?;
|
||||
|
|
|
@ -12,10 +12,10 @@ impl From<FSRSError> for AnkiError {
|
|||
FSRSError::NotEnoughData => AnkiError::FsrsInsufficientData,
|
||||
FSRSError::OptimalNotFound => AnkiError::FsrsUnableToDetermineDesiredRetention,
|
||||
FSRSError::Interrupted => AnkiError::Interrupted,
|
||||
FSRSError::InvalidParameters => AnkiError::FsrsWeightsInvalid,
|
||||
FSRSError::InvalidParameters => AnkiError::FsrsParamsInvalid,
|
||||
FSRSError::InvalidInput => AnkiError::InvalidInput {
|
||||
source: InvalidInputError {
|
||||
message: "invalid weights provided".to_string(),
|
||||
message: "invalid params provided".to_string(),
|
||||
source: None,
|
||||
backtrace: None,
|
||||
},
|
||||
|
|
|
@ -9,13 +9,13 @@ use fsrs::MemoryState;
|
|||
use fsrs::FSRS;
|
||||
use itertools::Itertools;
|
||||
|
||||
use super::weights::ignore_revlogs_before_ms_from_config;
|
||||
use super::params::ignore_revlogs_before_ms_from_config;
|
||||
use crate::card::CardType;
|
||||
use crate::prelude::*;
|
||||
use crate::revlog::RevlogEntry;
|
||||
use crate::revlog::RevlogReviewKind;
|
||||
use crate::scheduler::fsrs::weights::single_card_revlog_to_items;
|
||||
use crate::scheduler::fsrs::weights::Weights;
|
||||
use crate::scheduler::fsrs::params::single_card_revlog_to_items;
|
||||
use crate::scheduler::fsrs::params::Params;
|
||||
use crate::scheduler::states::fuzz::with_review_fuzz;
|
||||
use crate::search::Negated;
|
||||
use crate::search::SearchNode;
|
||||
|
@ -29,7 +29,7 @@ pub struct ComputeMemoryProgress {
|
|||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct UpdateMemoryStateRequest {
|
||||
pub weights: Weights,
|
||||
pub params: Params,
|
||||
pub desired_retention: f32,
|
||||
pub historical_retention: f32,
|
||||
pub max_interval: u32,
|
||||
|
@ -43,10 +43,10 @@ pub(crate) struct UpdateMemoryStateEntry {
|
|||
}
|
||||
|
||||
impl Collection {
|
||||
/// For each provided set of weights, locate cards with the provided search,
|
||||
/// For each provided set of params, locate cards with the provided search,
|
||||
/// and update their memory state.
|
||||
/// Should be called inside a transaction.
|
||||
/// If Weights are None, it means the user disabled FSRS, and the existing
|
||||
/// If Params are None, it means the user disabled FSRS, and the existing
|
||||
/// memory state should be removed.
|
||||
pub(crate) fn update_memory_state(
|
||||
&mut self,
|
||||
|
@ -69,7 +69,7 @@ impl Collection {
|
|||
} else {
|
||||
None
|
||||
};
|
||||
let fsrs = FSRS::new(req.as_ref().map(|w| &w.weights[..]).or(Some([].as_slice())))?;
|
||||
let fsrs = FSRS::new(req.as_ref().map(|w| &w.params[..]).or(Some([].as_slice())))?;
|
||||
let historical_retention = req.as_ref().map(|w| w.historical_retention);
|
||||
let items = fsrs_items_for_memory_state(
|
||||
&fsrs,
|
||||
|
@ -337,8 +337,8 @@ mod tests {
|
|||
use super::*;
|
||||
use crate::card::FsrsMemoryState;
|
||||
use crate::revlog::RevlogReviewKind;
|
||||
use crate::scheduler::fsrs::weights::tests::convert;
|
||||
use crate::scheduler::fsrs::weights::tests::revlog;
|
||||
use crate::scheduler::fsrs::params::tests::convert;
|
||||
use crate::scheduler::fsrs::params::tests::revlog;
|
||||
|
||||
/// Floating point precision can vary between platforms, and each FSRS
|
||||
/// update tends to result in small changes to these numbers, so we
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
mod error;
|
||||
pub mod memory_state;
|
||||
pub mod params;
|
||||
pub mod retention;
|
||||
pub mod simulator;
|
||||
pub mod try_collect;
|
||||
pub mod weights;
|
||||
|
|
|
@ -7,7 +7,7 @@ use std::thread;
|
|||
use std::time::Duration;
|
||||
|
||||
use anki_io::write_file;
|
||||
use anki_proto::scheduler::ComputeFsrsWeightsResponse;
|
||||
use anki_proto::scheduler::ComputeFsrsParamsResponse;
|
||||
use anki_proto::stats::revlog_entry;
|
||||
use anki_proto::stats::Dataset;
|
||||
use anki_proto::stats::DeckEntry;
|
||||
|
@ -29,7 +29,7 @@ use crate::search::Node;
|
|||
use crate::search::SearchNode;
|
||||
use crate::search::SortMode;
|
||||
|
||||
pub(crate) type Weights = Vec<f32>;
|
||||
pub(crate) type Params = Vec<f32>;
|
||||
|
||||
fn ignore_revlogs_before_date_to_ms(
|
||||
ignore_revlogs_before_date: &String,
|
||||
|
@ -53,15 +53,15 @@ impl Collection {
|
|||
/// 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
|
||||
/// value.
|
||||
pub fn compute_weights(
|
||||
pub fn compute_params(
|
||||
&mut self,
|
||||
search: &str,
|
||||
ignore_revlogs_before: TimestampMillis,
|
||||
current_preset: u32,
|
||||
total_presets: u32,
|
||||
current_weights: &Weights,
|
||||
) -> Result<ComputeFsrsWeightsResponse> {
|
||||
let mut anki_progress = self.new_progress_handler::<ComputeWeightsProgress>();
|
||||
current_params: &Params,
|
||||
) -> Result<ComputeFsrsParamsResponse> {
|
||||
let mut anki_progress = self.new_progress_handler::<ComputeParamsProgress>();
|
||||
let timing = self.timing_today()?;
|
||||
let revlogs = self.revlog_for_srs(search)?;
|
||||
let (items, review_count) =
|
||||
|
@ -69,8 +69,8 @@ impl Collection {
|
|||
|
||||
let fsrs_items = items.len() as u32;
|
||||
if fsrs_items == 0 {
|
||||
return Ok(ComputeFsrsWeightsResponse {
|
||||
weights: current_weights.to_vec(),
|
||||
return Ok(ComputeFsrsParamsResponse {
|
||||
params: current_params.to_vec(),
|
||||
fsrs_items,
|
||||
});
|
||||
}
|
||||
|
@ -97,20 +97,17 @@ impl Collection {
|
|||
}
|
||||
}
|
||||
});
|
||||
let mut weights = FSRS::new(None)?.compute_parameters(items.clone(), Some(progress2))?;
|
||||
if let Ok(fsrs) = FSRS::new(Some(current_weights)) {
|
||||
let mut params = FSRS::new(None)?.compute_parameters(items.clone(), Some(progress2))?;
|
||||
if let Ok(fsrs) = FSRS::new(Some(current_params)) {
|
||||
let current_rmse = fsrs.evaluate(items.clone(), |_| true)?.rmse_bins;
|
||||
let optimized_fsrs = FSRS::new(Some(&weights))?;
|
||||
let optimized_fsrs = FSRS::new(Some(¶ms))?;
|
||||
let optimized_rmse = optimized_fsrs.evaluate(items.clone(), |_| true)?.rmse_bins;
|
||||
if current_rmse <= optimized_rmse {
|
||||
weights = current_weights.to_vec();
|
||||
params = current_params.to_vec();
|
||||
}
|
||||
}
|
||||
|
||||
Ok(ComputeFsrsWeightsResponse {
|
||||
weights,
|
||||
fsrs_items,
|
||||
})
|
||||
Ok(ComputeFsrsParamsResponse { params, fsrs_items })
|
||||
}
|
||||
|
||||
pub(crate) fn revlog_for_srs(
|
||||
|
@ -180,14 +177,14 @@ impl Collection {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn evaluate_weights(
|
||||
pub fn evaluate_params(
|
||||
&mut self,
|
||||
weights: &Weights,
|
||||
params: &Params,
|
||||
search: &str,
|
||||
ignore_revlogs_before: TimestampMillis,
|
||||
) -> Result<ModelEvaluation> {
|
||||
let timing = self.timing_today()?;
|
||||
let mut anki_progress = self.new_progress_handler::<ComputeWeightsProgress>();
|
||||
let mut anki_progress = self.new_progress_handler::<ComputeParamsProgress>();
|
||||
let guard = self.search_cards_into_table(search, SortMode::NoOrder)?;
|
||||
let revlogs: Vec<RevlogEntry> = guard
|
||||
.col
|
||||
|
@ -196,7 +193,7 @@ impl Collection {
|
|||
let (items, review_count) =
|
||||
fsrs_items_for_training(revlogs, timing.next_day_at, ignore_revlogs_before);
|
||||
anki_progress.state.reviews = review_count as u32;
|
||||
let fsrs = FSRS::new(Some(weights))?;
|
||||
let fsrs = FSRS::new(Some(params))?;
|
||||
Ok(fsrs.evaluate(items, |ip| {
|
||||
anki_progress
|
||||
.update(false, |p| {
|
||||
|
@ -209,13 +206,13 @@ impl Collection {
|
|||
}
|
||||
|
||||
#[derive(Default, Clone, Copy, Debug)]
|
||||
pub struct ComputeWeightsProgress {
|
||||
pub struct ComputeParamsProgress {
|
||||
pub current_iteration: u32,
|
||||
pub total_iterations: u32,
|
||||
pub reviews: u32,
|
||||
/// Only used in 'compute all weights' case
|
||||
/// Only used in 'compute all params' case
|
||||
pub current_preset: u32,
|
||||
/// Only used in 'compute all weights' case
|
||||
/// Only used in 'compute all params' case
|
||||
pub total_presets: u32,
|
||||
}
|
||||
|
|
@ -54,7 +54,7 @@ impl Collection {
|
|||
learn_limit,
|
||||
review_limit: usize::MAX,
|
||||
},
|
||||
&req.weights,
|
||||
&req.params,
|
||||
|ip| {
|
||||
anki_progress
|
||||
.update(false, |p| {
|
||||
|
|
|
@ -54,7 +54,7 @@ impl Collection {
|
|||
daily_time_cost,
|
||||
) = simulate(
|
||||
&config,
|
||||
&req.weights,
|
||||
&req.params,
|
||||
req.desired_retention,
|
||||
None,
|
||||
Some(converted_cards),
|
||||
|
|
|
@ -7,7 +7,7 @@ mod states;
|
|||
use anki_proto::cards;
|
||||
use anki_proto::generic;
|
||||
use anki_proto::scheduler;
|
||||
use anki_proto::scheduler::ComputeFsrsWeightsResponse;
|
||||
use anki_proto::scheduler::ComputeFsrsParamsResponse;
|
||||
use anki_proto::scheduler::ComputeMemoryStateResponse;
|
||||
use anki_proto::scheduler::ComputeOptimalRetentionRequest;
|
||||
use anki_proto::scheduler::ComputeOptimalRetentionResponse;
|
||||
|
@ -254,16 +254,16 @@ impl crate::services::SchedulerService for Collection {
|
|||
self.custom_study_defaults(input.deck_id.into())
|
||||
}
|
||||
|
||||
fn compute_fsrs_weights(
|
||||
fn compute_fsrs_params(
|
||||
&mut self,
|
||||
input: scheduler::ComputeFsrsWeightsRequest,
|
||||
) -> Result<scheduler::ComputeFsrsWeightsResponse> {
|
||||
self.compute_weights(
|
||||
input: scheduler::ComputeFsrsParamsRequest,
|
||||
) -> Result<scheduler::ComputeFsrsParamsResponse> {
|
||||
self.compute_params(
|
||||
&input.search,
|
||||
input.ignore_revlogs_before_ms.into(),
|
||||
1,
|
||||
1,
|
||||
&input.current_weights,
|
||||
&input.current_params,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -283,16 +283,16 @@ impl crate::services::SchedulerService for Collection {
|
|||
})
|
||||
}
|
||||
|
||||
fn evaluate_weights(
|
||||
fn evaluate_params(
|
||||
&mut self,
|
||||
input: scheduler::EvaluateWeightsRequest,
|
||||
) -> Result<scheduler::EvaluateWeightsResponse> {
|
||||
let ret = self.evaluate_weights(
|
||||
&input.weights,
|
||||
input: scheduler::EvaluateParamsRequest,
|
||||
) -> Result<scheduler::EvaluateParamsResponse> {
|
||||
let ret = self.evaluate_params(
|
||||
&input.params,
|
||||
&input.search,
|
||||
input.ignore_revlogs_before_ms.into(),
|
||||
)?;
|
||||
Ok(scheduler::EvaluateWeightsResponse {
|
||||
Ok(scheduler::EvaluateParamsResponse {
|
||||
log_loss: ret.log_loss,
|
||||
rmse_bins: ret.rmse_bins,
|
||||
})
|
||||
|
@ -339,20 +339,17 @@ impl crate::services::SchedulerService for Collection {
|
|||
}
|
||||
|
||||
impl crate::services::BackendSchedulerService for Backend {
|
||||
fn compute_fsrs_weights_from_items(
|
||||
fn compute_fsrs_params_from_items(
|
||||
&self,
|
||||
req: scheduler::ComputeFsrsWeightsFromItemsRequest,
|
||||
) -> Result<scheduler::ComputeFsrsWeightsResponse> {
|
||||
req: scheduler::ComputeFsrsParamsFromItemsRequest,
|
||||
) -> Result<scheduler::ComputeFsrsParamsResponse> {
|
||||
let fsrs = FSRS::new(None)?;
|
||||
let fsrs_items = req.items.len() as u32;
|
||||
let weights = fsrs.compute_parameters(
|
||||
let params = fsrs.compute_parameters(
|
||||
req.items.into_iter().map(fsrs_item_proto_to_fsrs).collect(),
|
||||
None,
|
||||
)?;
|
||||
Ok(ComputeFsrsWeightsResponse {
|
||||
weights,
|
||||
fsrs_items,
|
||||
})
|
||||
Ok(ComputeFsrsParamsResponse { params, fsrs_items })
|
||||
}
|
||||
|
||||
fn fsrs_benchmark(
|
||||
|
@ -365,8 +362,8 @@ impl crate::services::BackendSchedulerService for Backend {
|
|||
.into_iter()
|
||||
.map(fsrs_item_proto_to_fsrs)
|
||||
.collect();
|
||||
let weights = fsrs.benchmark(train_set);
|
||||
Ok(FsrsBenchmarkResponse { weights })
|
||||
let params = fsrs.benchmark(train_set);
|
||||
Ok(FsrsBenchmarkResponse { params })
|
||||
}
|
||||
|
||||
fn export_dataset(&self, req: scheduler::ExportDatasetRequest) -> Result<()> {
|
||||
|
|
|
@ -226,8 +226,8 @@ impl LoadBalancer {
|
|||
.collect::<Vec<_>>();
|
||||
let expected_distribution = check_review_distribution(&review_counts, &percentages);
|
||||
|
||||
// calculate weights for each day
|
||||
let intervals_and_weights = interval_days
|
||||
// calculate params for each day
|
||||
let intervals_and_params = interval_days
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(interval_index, interval_day)| {
|
||||
|
@ -262,10 +262,10 @@ impl LoadBalancer {
|
|||
let mut rng = StdRng::seed_from_u64(fuzz_seed?);
|
||||
|
||||
let weighted_intervals =
|
||||
WeightedIndex::new(intervals_and_weights.iter().map(|k| k.1)).ok()?;
|
||||
WeightedIndex::new(intervals_and_params.iter().map(|k| k.1)).ok()?;
|
||||
|
||||
let selected_interval_index = weighted_intervals.sample(&mut rng);
|
||||
Some(intervals_and_weights[selected_interval_index].0)
|
||||
Some(intervals_and_params[selected_interval_index].0)
|
||||
}
|
||||
|
||||
pub fn add_card(&mut self, cid: CardId, nid: NoteId, dcid: DeckConfigId, interval: u32) {
|
||||
|
|
|
@ -7,7 +7,7 @@ use crate::card::CardType;
|
|||
use crate::prelude::*;
|
||||
use crate::revlog::RevlogEntry;
|
||||
use crate::scheduler::fsrs::memory_state::single_card_revlog_to_item;
|
||||
use crate::scheduler::fsrs::weights::ignore_revlogs_before_ms_from_config;
|
||||
use crate::scheduler::fsrs::params::ignore_revlogs_before_ms_from_config;
|
||||
use crate::scheduler::timing::is_unix_epoch_timestamp;
|
||||
|
||||
impl Collection {
|
||||
|
|
|
@ -5,7 +5,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||
<script lang="ts">
|
||||
import {
|
||||
ComputeRetentionProgress,
|
||||
type ComputeWeightsProgress,
|
||||
type ComputeParamsProgress,
|
||||
} from "@generated/anki/collection_pb";
|
||||
import {
|
||||
ComputeOptimalRetentionRequest,
|
||||
|
@ -13,10 +13,10 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||
type SimulateFsrsReviewResponse,
|
||||
} from "@generated/anki/scheduler_pb";
|
||||
import {
|
||||
computeFsrsWeights,
|
||||
computeFsrsParams,
|
||||
computeOptimalRetention,
|
||||
simulateFsrsReview,
|
||||
evaluateWeights,
|
||||
evaluateParams,
|
||||
setWantsAbort,
|
||||
} from "@generated/backend";
|
||||
import * as tr from "@generated/ftl";
|
||||
|
@ -30,8 +30,8 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||
import SpinBoxFloatRow from "./SpinBoxFloatRow.svelte";
|
||||
import SpinBoxRow from "./SpinBoxRow.svelte";
|
||||
import Warning from "./Warning.svelte";
|
||||
import WeightsInputRow from "./WeightsInputRow.svelte";
|
||||
import WeightsSearchRow from "./WeightsSearchRow.svelte";
|
||||
import ParamsInputRow from "./ParamsInputRow.svelte";
|
||||
import ParamsSearchRow from "./ParamsSearchRow.svelte";
|
||||
import { renderSimulationChart, type Point } from "../graphs/simulator";
|
||||
import Graph from "../graphs/Graph.svelte";
|
||||
import HoverColumns from "../graphs/HoverColumns.svelte";
|
||||
|
@ -54,22 +54,22 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||
$: lastOptimizationWarning =
|
||||
$daysSinceLastOptimization > 30 ? tr.deckConfigOptimizeAllTip() : "";
|
||||
|
||||
let computeWeightsProgress: ComputeWeightsProgress | undefined;
|
||||
let computingWeights = false;
|
||||
let checkingWeights = false;
|
||||
let computeParamsProgress: ComputeParamsProgress | undefined;
|
||||
let computingParams = false;
|
||||
let checkingParams = false;
|
||||
let computingRetention = false;
|
||||
let optimalRetention = 0;
|
||||
$: if ($presetName) {
|
||||
optimalRetention = 0;
|
||||
}
|
||||
$: computing = computingWeights || checkingWeights || computingRetention;
|
||||
$: defaultWeightSearch = `preset:"${state.getCurrentName()}" -is:suspended`;
|
||||
$: computing = computingParams || checkingParams || computingRetention;
|
||||
$: defaultparamSearch = `preset:"${state.getCurrentName()}" -is:suspended`;
|
||||
$: roundedRetention = Number($config.desiredRetention.toFixed(2));
|
||||
$: desiredRetentionWarning = getRetentionWarning(roundedRetention);
|
||||
$: retentionWarningClass = getRetentionWarningClass(roundedRetention);
|
||||
|
||||
let computeRetentionProgress:
|
||||
| ComputeWeightsProgress
|
||||
| ComputeParamsProgress
|
||||
| ComputeRetentionProgress
|
||||
| undefined;
|
||||
|
||||
|
@ -82,7 +82,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||
}
|
||||
|
||||
const simulateFsrsRequest = new SimulateFsrsReviewRequest({
|
||||
weights: fsrsParams($config),
|
||||
params: fsrsParams($config),
|
||||
desiredRetention: $config.desiredRetention,
|
||||
deckSize: 0,
|
||||
daysToSimulate: 365,
|
||||
|
@ -123,8 +123,8 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||
);
|
||||
}
|
||||
|
||||
async function computeWeights(): Promise<void> {
|
||||
if (computingWeights) {
|
||||
async function computeParams(): Promise<void> {
|
||||
if (computingParams) {
|
||||
await setWantsAbort({});
|
||||
return;
|
||||
}
|
||||
|
@ -132,47 +132,47 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||
alert(tr.deckConfigPleaseSaveYourChangesFirst());
|
||||
return;
|
||||
}
|
||||
computingWeights = true;
|
||||
computeWeightsProgress = undefined;
|
||||
computingParams = true;
|
||||
computeParamsProgress = undefined;
|
||||
try {
|
||||
await runWithBackendProgress(
|
||||
async () => {
|
||||
const params = fsrsParams($config);
|
||||
const resp = await computeFsrsWeights({
|
||||
search: $config.weightSearch
|
||||
? $config.weightSearch
|
||||
: defaultWeightSearch,
|
||||
const resp = await computeFsrsParams({
|
||||
search: $config.paramSearch
|
||||
? $config.paramSearch
|
||||
: defaultparamSearch,
|
||||
ignoreRevlogsBeforeMs: getIgnoreRevlogsBeforeMs(),
|
||||
currentWeights: params,
|
||||
currentParams: params,
|
||||
});
|
||||
if (
|
||||
(params.length &&
|
||||
params.every(
|
||||
(n, i) => n.toFixed(4) === resp.weights[i].toFixed(4),
|
||||
(n, i) => n.toFixed(4) === resp.params[i].toFixed(4),
|
||||
)) ||
|
||||
resp.weights.length === 0
|
||||
resp.params.length === 0
|
||||
) {
|
||||
setTimeout(() => alert(tr.deckConfigFsrsParamsOptimal()), 100);
|
||||
} else {
|
||||
$config.fsrsParams5 = resp.weights;
|
||||
$config.fsrsParams5 = resp.params;
|
||||
}
|
||||
if (computeWeightsProgress) {
|
||||
computeWeightsProgress.current = computeWeightsProgress.total;
|
||||
if (computeParamsProgress) {
|
||||
computeParamsProgress.current = computeParamsProgress.total;
|
||||
}
|
||||
},
|
||||
(progress) => {
|
||||
if (progress.value.case === "computeWeights") {
|
||||
computeWeightsProgress = progress.value.value;
|
||||
if (progress.value.case === "computeParams") {
|
||||
computeParamsProgress = progress.value.value;
|
||||
}
|
||||
},
|
||||
);
|
||||
} finally {
|
||||
computingWeights = false;
|
||||
computingParams = false;
|
||||
}
|
||||
}
|
||||
|
||||
async function checkWeights(): Promise<void> {
|
||||
if (checkingWeights) {
|
||||
async function checkParams(): Promise<void> {
|
||||
if (checkingParams) {
|
||||
await setWantsAbort({});
|
||||
return;
|
||||
}
|
||||
|
@ -180,21 +180,21 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||
alert(tr.deckConfigPleaseSaveYourChangesFirst());
|
||||
return;
|
||||
}
|
||||
checkingWeights = true;
|
||||
computeWeightsProgress = undefined;
|
||||
checkingParams = true;
|
||||
computeParamsProgress = undefined;
|
||||
try {
|
||||
await runWithBackendProgress(
|
||||
async () => {
|
||||
const search = $config.weightSearch
|
||||
? $config.weightSearch
|
||||
: defaultWeightSearch;
|
||||
const resp = await evaluateWeights({
|
||||
weights: fsrsParams($config),
|
||||
const search = $config.paramSearch
|
||||
? $config.paramSearch
|
||||
: defaultparamSearch;
|
||||
const resp = await evaluateParams({
|
||||
params: fsrsParams($config),
|
||||
search,
|
||||
ignoreRevlogsBeforeMs: getIgnoreRevlogsBeforeMs(),
|
||||
});
|
||||
if (computeWeightsProgress) {
|
||||
computeWeightsProgress.current = computeWeightsProgress.total;
|
||||
if (computeParamsProgress) {
|
||||
computeParamsProgress.current = computeParamsProgress.total;
|
||||
}
|
||||
setTimeout(
|
||||
() =>
|
||||
|
@ -207,13 +207,13 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||
);
|
||||
},
|
||||
(progress) => {
|
||||
if (progress.value.case === "computeWeights") {
|
||||
computeWeightsProgress = progress.value.value;
|
||||
if (progress.value.case === "computeParams") {
|
||||
computeParamsProgress = progress.value.value;
|
||||
}
|
||||
},
|
||||
);
|
||||
} finally {
|
||||
checkingWeights = false;
|
||||
checkingParams = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -232,7 +232,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||
await runWithBackendProgress(
|
||||
async () => {
|
||||
optimalRetentionRequest.maxInterval = $config.maximumReviewInterval;
|
||||
optimalRetentionRequest.weights = fsrsParams($config);
|
||||
optimalRetentionRequest.params = fsrsParams($config);
|
||||
optimalRetentionRequest.search = `preset:"${state.getCurrentName()}" -is:suspended`;
|
||||
const resp = await computeOptimalRetention(optimalRetentionRequest);
|
||||
optimalRetention = resp.optimalRetention;
|
||||
|
@ -249,13 +249,13 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||
}
|
||||
}
|
||||
|
||||
$: computeWeightsProgressString = renderWeightProgress(computeWeightsProgress);
|
||||
$: computeParamsProgressString = renderWeightProgress(computeParamsProgress);
|
||||
$: computeRetentionProgressString = renderRetentionProgress(
|
||||
computeRetentionProgress,
|
||||
);
|
||||
$: totalReviews = computeWeightsProgress?.reviews ?? undefined;
|
||||
$: totalReviews = computeParamsProgress?.reviews ?? undefined;
|
||||
|
||||
function renderWeightProgress(val: ComputeWeightsProgress | undefined): String {
|
||||
function renderWeightProgress(val: ComputeParamsProgress | undefined): String {
|
||||
if (!val || !val.total) {
|
||||
return "";
|
||||
}
|
||||
|
@ -313,7 +313,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||
try {
|
||||
await runWithBackendProgress(
|
||||
async () => {
|
||||
simulateFsrsRequest.weights = fsrsParams($config);
|
||||
simulateFsrsRequest.params = fsrsParams($config);
|
||||
simulateFsrsRequest.desiredRetention = $config.desiredRetention;
|
||||
simulateFsrsRequest.search = `preset:"${state.getCurrentName()}" -is:suspended`;
|
||||
simulateProgressString = "processing...";
|
||||
|
@ -361,46 +361,46 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||
<Warning warning={desiredRetentionWarning} className={retentionWarningClass} />
|
||||
|
||||
<div class="ms-1 me-1">
|
||||
<WeightsInputRow
|
||||
<ParamsInputRow
|
||||
bind:value={$config.fsrsParams5}
|
||||
defaultValue={[]}
|
||||
defaults={defaults.fsrsParams5}
|
||||
>
|
||||
<SettingTitle on:click={() => openHelpModal("modelWeights")}>
|
||||
<SettingTitle on:click={() => openHelpModal("modelParams")}>
|
||||
{tr.deckConfigWeights()}
|
||||
</SettingTitle>
|
||||
</WeightsInputRow>
|
||||
</ParamsInputRow>
|
||||
|
||||
<WeightsSearchRow
|
||||
bind:value={$config.weightSearch}
|
||||
placeholder={defaultWeightSearch}
|
||||
<ParamsSearchRow
|
||||
bind:value={$config.paramSearch}
|
||||
placeholder={defaultparamSearch}
|
||||
/>
|
||||
|
||||
<button
|
||||
class="btn {computingWeights ? 'btn-warning' : 'btn-primary'}"
|
||||
disabled={!computingWeights && computing}
|
||||
on:click={() => computeWeights()}
|
||||
class="btn {computingParams ? 'btn-warning' : 'btn-primary'}"
|
||||
disabled={!computingParams && computing}
|
||||
on:click={() => computeParams()}
|
||||
>
|
||||
{#if computingWeights}
|
||||
{#if computingParams}
|
||||
{tr.actionsCancel()}
|
||||
{:else}
|
||||
{tr.deckConfigOptimizeButton()}
|
||||
{/if}
|
||||
</button>
|
||||
<button
|
||||
class="btn {checkingWeights ? 'btn-warning' : 'btn-primary'}"
|
||||
disabled={!checkingWeights && computing}
|
||||
on:click={() => checkWeights()}
|
||||
class="btn {checkingParams ? 'btn-warning' : 'btn-primary'}"
|
||||
disabled={!checkingParams && computing}
|
||||
on:click={() => checkParams()}
|
||||
>
|
||||
{#if checkingWeights}
|
||||
{#if checkingParams}
|
||||
{tr.actionsCancel()}
|
||||
{:else}
|
||||
{tr.deckConfigEvaluateButton()}
|
||||
{/if}
|
||||
</button>
|
||||
<div>
|
||||
{#if computingWeights || checkingWeights}
|
||||
{computeWeightsProgressString}
|
||||
{#if computingParams || checkingParams}
|
||||
{computeParamsProgressString}
|
||||
{:else if totalReviews !== undefined}
|
||||
{tr.statisticsReviews({ reviews: totalReviews })}
|
||||
{/if}
|
||||
|
|
|
@ -37,7 +37,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||
help: tr.deckConfigDesiredRetentionTooltip(),
|
||||
sched: HelpItemScheduler.FSRS,
|
||||
},
|
||||
modelWeights: {
|
||||
modelParams: {
|
||||
title: tr.deckConfigWeights(),
|
||||
help:
|
||||
tr.deckConfigWeightsTooltip2() +
|
||||
|
|
|
@ -9,8 +9,8 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||
let stringValue: string;
|
||||
$: stringValue = render(value);
|
||||
|
||||
function render(weights: number[]): string {
|
||||
return weights.map((v) => v.toFixed(4)).join(", ");
|
||||
function render(params: number[]): string {
|
||||
return params.map((v) => v.toFixed(4)).join(", ");
|
||||
}
|
||||
|
||||
function update(this: HTMLInputElement): void {
|
|
@ -6,7 +6,7 @@
|
|||
import ConfigInput from "$lib/components/ConfigInput.svelte";
|
||||
import RevertButton from "$lib/components/RevertButton.svelte";
|
||||
|
||||
import WeightsInput from "./WeightsInput.svelte";
|
||||
import ParamsInput from "./ParamsInput.svelte";
|
||||
|
||||
export let value: number[];
|
||||
export let defaultValue: number[];
|
||||
|
@ -15,6 +15,6 @@
|
|||
|
||||
<slot />
|
||||
<ConfigInput>
|
||||
<WeightsInput bind:value {defaults} />
|
||||
<ParamsInput bind:value {defaults} />
|
||||
<RevertButton slot="revert" bind:value {defaultValue} />
|
||||
</ConfigInput>
|
|
@ -56,7 +56,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||
|
||||
async function save(mode: UpdateDeckConfigsMode): Promise<void> {
|
||||
await commitEditing();
|
||||
if (mode === UpdateDeckConfigsMode.COMPUTE_ALL_WEIGHTS && !get(state.fsrs)) {
|
||||
if (mode === UpdateDeckConfigsMode.COMPUTE_ALL_PARAMS && !get(state.fsrs)) {
|
||||
alert(tr.deckConfigFsrsMustBeEnabled());
|
||||
return;
|
||||
}
|
||||
|
@ -119,7 +119,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||
{tr.deckConfigSaveToAllSubdecks()}
|
||||
</DropdownItem>
|
||||
<DropdownItem
|
||||
on:click={() => save(UpdateDeckConfigsMode.COMPUTE_ALL_WEIGHTS)}
|
||||
on:click={() => save(UpdateDeckConfigsMode.COMPUTE_ALL_PARAMS)}
|
||||
>
|
||||
{tr.deckConfigSaveAndOptimize()}
|
||||
</DropdownItem>
|
||||
|
|
Loading…
Reference in a new issue