Skip to content

Commit

Permalink
Feat/minimal workload for optimal retention (#89)
Browse files Browse the repository at this point in the history
* Feat/minimal workload for optimal retention

* remove unnecessary arguments

* bump version
  • Loading branch information
L-M-Sherlock committed Mar 10, 2024
1 parent 1a3bb12 commit e411f68
Show file tree
Hide file tree
Showing 5 changed files with 46 additions and 23 deletions.
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"

[project]
name = "FSRS-Optimizer"
version = "4.26.0"
version = "4.26.1"
readme = "README.md"
dependencies = [
"matplotlib>=3.7.0",
Expand Down
14 changes: 5 additions & 9 deletions src/fsrs_optimizer/fsrs_optimizer.py
Original file line number Diff line number Diff line change
Expand Up @@ -1200,13 +1200,9 @@ def predict_memory_states(self):

def find_optimal_retention(
self,
deck_size=10000,
learn_span=365,
max_cost_perday=1800,
max_ivl=36500,
learn_limit_perday=math.inf,
review_limit_perday=math.inf,
loss_aversion=2.5,
loss_aversion=1,
verbose=True,
):
"""should not be called before predict_memory_states"""
Expand Down Expand Up @@ -1261,11 +1257,11 @@ def find_optimal_retention(

simulate_config = {
"w": self.w,
"deck_size": deck_size,
"deck_size": learn_span * 10,
"learn_span": learn_span,
"max_cost_perday": max_cost_perday,
"learn_limit_perday": learn_limit_perday,
"review_limit_perday": review_limit_perday,
"max_cost_perday": math.inf,
"learn_limit_perday": 10,
"review_limit_perday": math.inf,
"max_ivl": max_ivl,
"recall_costs": self.recall_costs,
"forget_cost": forget_cost,
Expand Down
26 changes: 13 additions & 13 deletions src/fsrs_optimizer/fsrs_simulator.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ def next_interval(s, r):
]
col = {key: i for i, key in enumerate(columns)}

SAMPLE_SIZE = 5
SAMPLE_SIZE = 4


def simulate(
Expand Down Expand Up @@ -208,7 +208,7 @@ def sample(
):
memorization = []
for i in range(SAMPLE_SIZE):
_, _, _, memorized_cnt_per_day, _ = simulate(
_, _, _, memorized_cnt_per_day, cost_per_day = simulate(
w,
request_retention=r,
deck_size=deck_size,
Expand All @@ -224,7 +224,7 @@ def sample(
review_rating_prob=review_rating_prob,
seed=42 + i,
)
memorization.append(memorized_cnt_per_day[-1])
memorization.append(cost_per_day.sum() / memorized_cnt_per_day[-1])
return np.mean(memorization)


Expand All @@ -236,15 +236,15 @@ def bracket(xa=0.75, xb=0.95, maxiter=20, **kwargs):
gold = 1.6180339
verysmall_num = 1e-21

fa = -sample(xa, **kwargs)
fb = -sample(xb, **kwargs)
fa = sample(xa, **kwargs)
fb = sample(xb, **kwargs)
funccalls = 2

if fa < fb: # Switch so fa > fb
xa, xb = xb, xa
fa, fb = fb, fa
xc = max(min(xb + gold * (xb - xa), u_lim), l_lim)
fc = -sample(xc, **kwargs)
fc = sample(xc, **kwargs)
funccalls += 1

iter = 0
Expand All @@ -265,7 +265,7 @@ def bracket(xa=0.75, xb=0.95, maxiter=20, **kwargs):

iter += 1
if (w - xc) * (xb - w) > 0.0:
fw = -sample(w, **kwargs)
fw = sample(w, **kwargs)
funccalls += 1
if fw < fc:
xa = max(min(xb, u_lim), l_lim)
Expand All @@ -278,26 +278,26 @@ def bracket(xa=0.75, xb=0.95, maxiter=20, **kwargs):
fc = fw
break
w = max(min(xc + gold * (xc - xb), u_lim), l_lim)
fw = -sample(w, **kwargs)
fw = sample(w, **kwargs)
funccalls += 1
elif (w - wlim) * (wlim - xc) >= 0.0:
w = wlim
fw = -sample(w, **kwargs)
fw = sample(w, **kwargs)
funccalls += 1
elif (w - wlim) * (xc - w) > 0.0:
fw = -sample(w, **kwargs)
fw = sample(w, **kwargs)
funccalls += 1
if fw < fc:
xb = max(min(xc, u_lim), l_lim)
xc = max(min(w, u_lim), l_lim)
w = max(min(xc + gold * (xc - xb), u_lim), l_lim)
fb = fc
fc = fw
fw = -sample(w, **kwargs)
fw = sample(w, **kwargs)
funccalls += 1
else:
w = max(min(xc + gold * (xc - xb), u_lim), l_lim)
fw = -sample(w, **kwargs)
fw = sample(w, **kwargs)
funccalls += 1
xa = max(min(xb, u_lim), l_lim)
xb = max(min(xc, u_lim), l_lim)
Expand Down Expand Up @@ -382,7 +382,7 @@ def brent(tol=0.01, maxiter=20, **kwargs):
u = x - tol1
else:
u = x + rat
fu = -sample(u, **kwargs) # calculate new output value
fu = sample(u, **kwargs) # calculate new output value
funccalls += 1

if fu > fx: # if it's bigger than current
Expand Down
Empty file added tests/__init__.py
Empty file.
27 changes: 27 additions & 0 deletions tests/simulator_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
from src.fsrs_optimizer import *


class Test_Simulator:
def test_simulate(self):
(_, _, _, memorized_cnt_per_day, _) = simulate(
w=DEFAULT_WEIGHT, forget_cost=125
)
assert memorized_cnt_per_day[-1] == 3145.3779679589484

def test_optimal_retention(self):
default_params = {
"w": DEFAULT_WEIGHT,
"deck_size": 10000,
"learn_span": 1000,
"max_cost_perday": math.inf,
"learn_limit_perday": 10,
"review_limit_perday": math.inf,
"max_ivl": 36500,
"recall_costs": np.array([14, 10, 6]),
"forget_cost": 50,
"learn_cost": 20,
"first_rating_prob": np.array([0.15, 0.2, 0.6, 0.05]),
"review_rating_prob": np.array([0.3, 0.6, 0.1]),
}
r = optimal_retention(**default_params)
assert r == 0.7791796050312

0 comments on commit e411f68

Please sign in to comment.