diff --git a/README.md b/README.md index 1c53748..6d1c230 100644 --- a/README.md +++ b/README.md @@ -81,6 +81,36 @@ print(f"Card due in {time_delta.seconds} seconds") ## Usage +### Custom scheduler + +You can initialize the FSRS scheduler with your own custom weights as well as desired retention rate and maximum interval. + +```python +f = FSRS( + w=( + 1.14, + 1.01, + 5.44, + 14.67, + 5.3024, + 1.5662, + 1.2503, + 0.0028, + 1.5489, + 0.1763, + 0.9953, + 2.7473, + 0.0179, + 0.3105, + 0.3976, + 0.0, + 2.0902, + ), + request_retention=0.85, + maximum_interval=3650, +) +``` + ### Advanced reviewing of cards Aside from using the convenience method `review_card`, there is also the `repeat` method: diff --git a/pyproject.toml b/pyproject.toml index ba99c3e..a8ff34c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "fsrs" -version = "2.4.0" +version = "2.5.0" description = "Free Spaced Repetition Scheduler" readme = "README.md" authors = [{ name = "Jarrett Ye", email = "jarrett.ye@outlook.com" }] diff --git a/src/fsrs/fsrs.py b/src/fsrs/fsrs.py index ca04cbb..6b4e34b 100644 --- a/src/fsrs/fsrs.py +++ b/src/fsrs/fsrs.py @@ -8,8 +8,13 @@ class FSRS: DECAY: float FACTOR: float - def __init__(self) -> None: - self.p = Parameters() + def __init__( + self, + w: Tuple[float, ...] = None, + request_retention: float = None, + maximum_interval: int = None, + ) -> None: + self.p = Parameters(w, request_retention, maximum_interval) self.DECAY = -0.5 self.FACTOR = 0.9 ** (1 / self.DECAY) - 1 diff --git a/src/fsrs/models.py b/src/fsrs/models.py index 5d5c39c..e3c8748 100644 --- a/src/fsrs/models.py +++ b/src/fsrs/models.py @@ -275,25 +275,38 @@ class Parameters: maximum_interval: int w: Tuple[float, ...] - def __init__(self) -> None: - self.request_retention = 0.9 - self.maximum_interval = 36500 + def __init__( + self, + w: Tuple[float, ...] = None, + request_retention: float = None, + maximum_interval: int = None, + ) -> None: self.w = ( - 0.4872, - 1.4003, - 3.7145, - 13.8206, - 5.1618, - 1.2298, - 0.8975, - 0.031, - 1.6474, - 0.1367, - 1.0461, - 2.1072, - 0.0793, - 0.3246, - 1.587, - 0.2272, - 2.8755, + w + if w is not None + else ( + 0.4872, + 1.4003, + 3.7145, + 13.8206, + 5.1618, + 1.2298, + 0.8975, + 0.031, + 1.6474, + 0.1367, + 1.0461, + 2.1072, + 0.0793, + 0.3246, + 1.587, + 0.2272, + 2.8755, + ) + ) + self.request_retention = ( + request_retention if request_retention is not None else 0.9 + ) + self.maximum_interval = ( + maximum_interval if maximum_interval is not None else 36500 ) diff --git a/tests/test_fsrs.py b/tests/test_fsrs.py index a8cbf39..7ea270b 100644 --- a/tests/test_fsrs.py +++ b/tests/test_fsrs.py @@ -258,3 +258,94 @@ def test_review_card(self): print(ivl_history) assert ivl_history == [0, 5, 16, 43, 106, 236, 0, 0, 12, 25, 47, 85, 147] + + def test_custom_scheduler_args(self): + + f = FSRS( + w=( + 1.14, + 1.01, + 5.44, + 14.67, + 5.3024, + 1.5662, + 1.2503, + 0.0028, + 1.5489, + 0.1763, + 0.9953, + 2.7473, + 0.0179, + 0.3105, + 0.3976, + 0.0, + 2.0902, + ), + request_retention=0.9, + maximum_interval=36500, + ) + card = Card() + now = datetime(2022, 11, 29, 12, 30, 0, 0, timezone.utc) + # scheduling_cards = f.repeat(card, now) + # print_scheduling_cards(scheduling_cards) + + ratings = ( + Rating.Good, + Rating.Good, + Rating.Good, + Rating.Good, + Rating.Good, + Rating.Good, + Rating.Again, + Rating.Again, + Rating.Good, + Rating.Good, + Rating.Good, + Rating.Good, + Rating.Good, + ) + ivl_history = [] + + for rating in ratings: + # card = scheduling_cards[rating].card + card, _ = f.review_card(card, rating, now) + ivl = card.scheduled_days + ivl_history.append(ivl) + now = card.due + # scheduling_cards = f.repeat(card, now) + # print_scheduling_cards(scheduling_cards) + + print(ivl_history) + assert ivl_history == [0, 5, 16, 43, 106, 236, 0, 0, 12, 25, 47, 85, 147] + + # initialize another scheduler and verify parameters are properly set + w2 = ( + 0.1456, + 0.4186, + 1.1104, + 4.1315, + 5.2417, + 1.3098, + 0.8975, + 0.0000, + 1.5674, + 0.0567, + 0.9661, + 2.0275, + 0.1592, + 0.2446, + 1.5071, + 0.2272, + 2.8755, + ) + request_retention2 = 0.85 + maximum_interval2 = 3650 + f2 = FSRS( + w=w2, + request_retention=request_retention2, + maximum_interval=maximum_interval2, + ) + + assert f2.p.w == w2 + assert f2.p.request_retention == request_retention2 + assert f2.p.maximum_interval == maximum_interval2