haskell-fsrs (empty) → 7.0.0
raw patch · 22 files changed
+6301/−0 lines, 22 filesdep +QuickCheckdep +arraydep +basesetup-changed
Dependencies added: QuickCheck, array, base, haskell-fsrs, tasty, tasty-hunit, tasty-quickcheck, time
Files
- CHANGELOG.md +33/−0
- LICENSE +21/−0
- README.md +164/−0
- Setup.hs +2/−0
- app/Main.hs +53/−0
- haskell-fsrs.cabal +107/−0
- reference/check_golden.py +92/−0
- reference/fsrs7_reference.py +243/−0
- reference/gen_golden.py +338/−0
- reference/test_reference.py +181/−0
- src/FSRS.hs +46/−0
- src/FSRS/Algorithm.hs +335/−0
- src/FSRS/Parameters.hs +361/−0
- src/FSRS/Scheduler.hs +317/−0
- src/FSRS/Types.hs +66/−0
- test/Spec.hs +20/−0
- test/Test/FSRS/Gen.hs +139/−0
- test/Test/FSRS/Golden.hs +133/−0
- test/Test/FSRS/GoldenData.hs +2723/−0
- test/Test/FSRS/Properties.hs +358/−0
- test/Test/FSRS/SchedulerSpec.hs +296/−0
- test/Test/FSRS/Unit.hs +273/−0
+ CHANGELOG.md view
@@ -0,0 +1,33 @@+# Changelog for `haskell-fsrs`++All notable changes to this project will be documented in this file.++The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).+The major version tracks the FSRS algorithm version, as `py-fsrs` and `fsrs-rs`+do: `7.x.y` implements FSRS-7.++## Unreleased++## 7.0.0 - 2026-08-20++Initial release: FSRS-7.++### Added++- `FSRS.Types` — `Rating`, `MemoryState` and the `Stability` / `Difficulty` /+ `Retrievability` / `Days` synonyms.+- `FSRS.Parameters` — the 35 FSRS-7 weights, the default set, bounds taken from+ the upstream optimiser's clipper, validation with per-weight errors, clamping,+ and typed views onto the weight blocks (`StabilityWeights`, `CurveWeights`).+- `FSRS.Algorithm` — the model: the two-component `retrievability` curve and its+ derivative, `nextIntervalDays` (a safeguarded Newton root-find, since the+ FSRS-7 curve has no closed-form inverse), `initialDifficulty`,+ `nextDifficulty`, `initialStability`, `stabilityAfterReview`,+ `transitionCoefficient`, `nextStability`, `nextMemoryState` and+ `replayReviews`.+- `FSRS.Scheduler` — cards, due dates, learning and relearning steps, review+ logs, interval preview and explicit (pure) interval fuzzing.+- `FSRS` — an umbrella module re-exporting all of the above.+- A test suite of golden vectors generated from a pure-Python transcription of+ the upstream reference implementation, plus property tests for the model's+ invariants.
+ LICENSE view
@@ -0,0 +1,21 @@+The MIT License (MIT)++Copyright ©️ 2026 Flavio Corpa Ríos++Permission is hereby granted, free of charge, to any person obtaining a copy+of this software and associated documentation files (the "Software"), to deal+in the Software without restriction, including without limitation the rights+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+copies of the Software, and to permit persons to whom the Software is+furnished to do so, subject to the following conditions:++The above copyright notice and this permission notice shall be included in all+copies or substantial portions of the Software.++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+SOFTWARE.
+ README.md view
@@ -0,0 +1,164 @@+# haskell-fsrs++[](https://github.com/kutyel/haskell-fsrs/actions/workflows/ci.yml)++A Haskell implementation of **FSRS-7**, the seventh version of the [Free Spaced+Repetition Scheduler](https://github.com/open-spaced-repetition) — the memory+model behind Anki's scheduler.++FSRS predicts when you are about to forget a flashcard so it can be shown to+you just before that happens. It tracks two numbers per card:++- **stability** — the memory's half-life, in days;+- **difficulty** — how hard this particular card is for you, on a 1–10 scale;++and derives **retrievability**, the probability that you can recall the card+right now.++The package version tracks the algorithm version, the way `py-fsrs` and+`fsrs-rs` do: `7.x.y` implements FSRS-7.++## What is new in FSRS-7++FSRS-7 has **35 parameters**, up from FSRS-6's 21. Three things changed:++- **The forgetting curve is a mixture of two power laws** rather than one, with+ the mixing weights themselves depending on stability. That is where six of+ the new parameters go, and it means the curve has no closed-form inverse — so+ computing an interval is a root-find, not a formula.+- **The stability update runs twice**, once with a long-term weight block and+ once with a short-term one, and the two are blended by a smooth transition+ function of the elapsed time. FSRS-6 instead switched between two separate+ formulas on a same-day / not-same-day flag.+- **Intervals are genuinely continuous.** Every earlier version was designed+ around whole-day intervals; FSRS-7 is the first that gives realistic+ predictions for same-day reviews. Ten minutes is `10 / 1440` days and the+ model means it.++## Getting started++```console+$ stack build+$ stack test+$ stack run # a small demo: one card, graded Good ten times+```++## Using it++```haskell+import FSRS++-- Grade a brand-new card Good, then grade it again a week later.+firstReview, secondReview :: MemoryState+firstReview = nextMemoryState defaultParameters Nothing 0 Good+secondReview = nextMemoryState defaultParameters (Just firstReview) 7 Good++-- When should it come back, if we want a 90% chance of recall?+whenDue :: Days+whenDue = nextIntervalDays defaultParameters 0.9 (memoryStability secondReview)++-- How likely are we to recall it three days from now?+odds :: Retrievability+odds = retrievability defaultParameters 3 (memoryStability secondReview)+```++Whole-card scheduling — learning steps, due dates, lapses, fuzz — lives in+`FSRS.Scheduler`:++```haskell+import FSRS++session :: UTCTime -> (Card, ReviewLog)+session now = reviewCard defaultScheduler (newCard now) Good now+```++`reviewCard` is deterministic. If you want Anki-style interval fuzzing, use+`reviewCardFuzzed` and hand it the random sample yourself, so scheduling stays+a pure function of its inputs.++Optimising the 35 weights against a user's own review history is *not* part of+this package. Use the upstream optimiser and feed the result to `mkParameters`.++### Modules++| Module | What is in it |+| --- | --- |+| `FSRS` | Re-exports everything below. |+| `FSRS.Types` | `Rating`, `MemoryState`, the type synonyms. |+| `FSRS.Parameters` | The 35 weights, their bounds, validation, typed views onto the blocks. |+| `FSRS.Algorithm` | The model: forgetting curve, difficulty, stability, interval inversion. |+| `FSRS.Scheduler` | Cards, due dates, learning steps, fuzz. |++## Provenance++`FSRS.Algorithm` is a transcription of the reference implementation the+upstream authors benchmark against:+[`srs-benchmark`](https://github.com/open-spaced-repetition/srs-benchmark),+`models/fsrs_v7.py` and `models/fsrs_v7_interval_penalty.py` (revision+`8c11619`).++Two things are worth knowing about the default weights:++- The published defaults use **1.3** for `w15` and `w24`, the easy bonus of the+ two stability blocks. The `Default Parameters` section of the `srs-benchmark`+ README still lists `1.15`; that block has not been touched since 2026-03-18,+ while the model itself was changed to `1.3` three days later (commit+ `e274ac3`). This package follows the model.+- The parameter bounds in `parameterBounds` come from the clipper the upstream+ optimiser applies after every gradient step, so any weights a real optimiser+ produces will satisfy them.++The scheduling policy in `FSRS.Scheduler` is *not* specified upstream — only+the memory model is. It follows the reference scheduler from+[`py-fsrs`](https://github.com/open-spaced-repetition/py-fsrs), adapted to+FSRS-7's continuous intervals.++## Tests++Two complementary suites, 113 test cases in all:++- **Golden vectors** — 2,589 of them, covering every function of the model+ across three parameter sets, generated by `reference/fsrs7_reference.py`, a+ pure-Python transcription of the same upstream source. Both implementations+ perform the same floating-point operations in the same order, so they are+ checked to a relative tolerance of `1e-12`.+- **Properties** — invariants that should hold for *every* parameter vector+ inside the valid box: retrievability is a probability and decreases with+ time, a better rating never means less stability, difficulty stays in range+ however long the history, the interval solver really does land on the desired+ retention, and so on.++A few properties hold only for well-behaved weights and say so. Because+FSRS-7 re-weights its two power laws by stability, adversarial-but-in-bounds+weights can make retrievability *fall* as stability grows; the properties about+how the model responds to stability are therefore stated for+`defaultParameters`.++To regenerate the golden vectors after touching the reference:++```console+$ python3 reference/gen_golden.py+```++The reference gets two checks of its own, both standard-library only:++```console+$ python3 reference/test_reference.py # the model's invariants, in Python+$ python3 reference/check_golden.py # the committed vectors still match it+```++`check_golden.py` compares numerically rather than by `git diff`. `exp` and+`pow` are not required by IEEE-754 to be correctly rounded, so the last bit of+a literal can legitimately differ between the machine that generated the file+and the one checking it; a textual diff would go red for reasons that have+nothing to do with the model.++## Continuous integration++[`.github/workflows/ci.yml`](.github/workflows/ci.yml) builds and tests with+Stack under `--pedantic` (`-Wall -Werror`), smoke-tests the demo, and runs both+reference checks.++## Licence++MIT. See [LICENSE](LICENSE).
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ app/Main.hs view
@@ -0,0 +1,53 @@+{-# LANGUAGE NumericUnderscores #-}++-- | A tiny demonstration of the FSRS-7 scheduler: grade one card 'Good' every+-- time it comes due, and print what the model makes of it.+module Main (main) where++import Data.Time.Calendar (fromGregorian)+import Data.Time.Clock (NominalDiffTime, UTCTime (..))+import Numeric (showFFloat)+import Text.Printf (printf)++import FSRS++main :: IO ()+main = do+ printf "FSRS-7 — %d parameters\n\n" parameterCount+ putStrLn (unwords [showFFloat Nothing w "" | w <- parametersToList defaultParameters])+ putStrLn ""+ putStrLn " # elapsed | state | stability | difficulty | next | R at due"+ putStrLn "----------------------------------------------------------------------------"+ go 1 epoch (newCard epoch)+ where+ reviews = 10 :: Int++ go :: Int -> UTCTime -> Card -> IO ()+ go n now card+ | n > reviews = pure ()+ | otherwise = do+ let (card', entry) = reviewCard defaultScheduler card Good now+ memory = logMemoryAfter entry+ due = cardDue card'+ printf+ "%2d %10s | %-10s | %10.4f | %10.4f | %-9s | %.4f\n"+ n+ (humanDuration (realToFrac (logElapsedDays entry * 86400) :: NominalDiffTime))+ (show (cardState card'))+ (memoryStability memory)+ (memoryDifficulty memory)+ (humanDuration (logInterval entry))+ (maybe 1 id (cardRetrievability defaultScheduler card' due))+ go (n + 1) due card'++epoch :: UTCTime+epoch = UTCTime (fromGregorian 2026 1 1) 0++humanDuration :: NominalDiffTime -> String+humanDuration dt+ | seconds < 60 = printf "%.0fs" seconds+ | seconds < 3_600 = printf "%.0fm" (seconds / 60)+ | seconds < 86_400 = printf "%.1fh" (seconds / 3_600)+ | otherwise = printf "%.2fd" (seconds / 86_400)+ where+ seconds = realToFrac dt :: Double
+ haskell-fsrs.cabal view
@@ -0,0 +1,107 @@+cabal-version: 2.2++name: haskell-fsrs+-- The major version tracks the algorithm version, as py-fsrs and fsrs-rs do:+-- 7.x.y implements FSRS-7.+version: 7.0.0+synopsis: FSRS-7, the Free Spaced Repetition Scheduler+description:+ A Haskell implementation of FSRS-7, the seventh version of the Free Spaced+ Repetition Scheduler: a memory model that predicts when you are about to+ forget a flashcard, so it can be shown to you just before that happens.+ .+ The model itself lives in "FSRS.Algorithm" and is a direct transcription of+ the reference implementation used by the upstream benchmark. A card+ scheduler built on top of it — learning steps, due dates, lapses, fuzz —+ lives in "FSRS.Scheduler". Import "FSRS" for everything at once.++homepage: https://github.com/kutyel/haskell-fsrs#readme+bug-reports: https://github.com/kutyel/haskell-fsrs/issues+license: MIT+license-file: LICENSE+author: Flavio Corpa+maintainer: https://github.com/kutyel/haskell-fsrs/issues+copyright: 2026 © Flavio Corpa Ríos+category: Education+build-type: Simple+tested-with:+ GHC ==8.10.7 || ==9.0.2 || ==9.2.7 || ==9.4.8 || ==9.6.7 || ==9.8.4 || ==9.10.3+extra-doc-files:+ CHANGELOG.md+ README.md++extra-source-files:+ reference/check_golden.py+ reference/fsrs7_reference.py+ reference/gen_golden.py+ reference/test_reference.py++source-repository head+ type: git+ location: https://github.com/kutyel/haskell-fsrs++common warnings+ ghc-options:+ -Wall+ -Wcompat+ -Widentities+ -Wincomplete-record-updates+ -Wincomplete-uni-patterns+ -Wmissing-export-lists+ -Wmissing-home-modules+ -Wpartial-fields+ -Wredundant-constraints++library+ import: warnings+ hs-source-dirs: src+ exposed-modules:+ FSRS+ FSRS.Algorithm+ FSRS.Parameters+ FSRS.Scheduler+ FSRS.Types++ build-depends:+ , array >=0.5 && <0.6+ , base >=4.14 && <5+ , time >=1.9 && <2++ default-language: Haskell2010++executable haskell-fsrs+ import: warnings+ hs-source-dirs: app+ main-is: Main.hs+ build-depends:+ , base+ , haskell-fsrs+ , time++ ghc-options: -threaded -rtsopts -with-rtsopts=-N+ default-language: Haskell2010++test-suite haskell-fsrs-test+ import: warnings+ type: exitcode-stdio-1.0+ hs-source-dirs: test+ main-is: Spec.hs+ other-modules:+ Test.FSRS.Gen+ Test.FSRS.Golden+ Test.FSRS.GoldenData+ Test.FSRS.Properties+ Test.FSRS.SchedulerSpec+ Test.FSRS.Unit++ build-depends:+ , base+ , haskell-fsrs+ , QuickCheck >=2.14 && <3+ , tasty >=1.4 && <1.6+ , tasty-hunit >=0.10 && <0.11+ , tasty-quickcheck >=0.10 && <0.12+ , time++ ghc-options: -threaded -rtsopts -with-rtsopts=-N+ default-language: Haskell2010
+ reference/check_golden.py view
@@ -0,0 +1,92 @@+"""Check that the committed golden vectors still match the Python reference.++Regenerates the vectors in memory and compares them, token by token, against+``test/Test/FSRS/GoldenData.hs``.++Numbers are compared with a tolerance rather than textually. ``exp`` and+``pow`` are not required by IEEE-754 to be correctly rounded, so the last bit+of a literal can legitimately differ between the machine that generated the+file and the machine checking it — a plain ``git diff`` would go red for+reasons that have nothing to do with the model. Everything else — structure,+identifiers, how many vectors there are — must match exactly.++Run from the repository root:++ python3 reference/check_golden.py+"""++import os+import re+import sys++sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))++import gen_golden # noqa: E402++# Relative tolerance. Several orders of magnitude looser than the last-bit+# noise we are trying to ignore, and several orders tighter than any change+# a real edit to the model would produce.+RTOL = 1e-9+ATOL = 1e-12++MAX_REPORTED = 5++_SPLIT = re.compile(r"([,()\[\]])|\s+")+++def tokens(text):+ return [tok for tok in _SPLIT.split(text) if tok and tok.strip()]+++def as_float(token):+ try:+ return float(token)+ except ValueError:+ return None+++def close(a, b):+ return abs(a - b) <= ATOL + RTOL * max(abs(a), abs(b))+++def main():+ expected = tokens(gen_golden.render())+ with open(gen_golden.OUT) as fh:+ actual = tokens(fh.read())++ if len(expected) != len(actual):+ print(+ f"{gen_golden.OUT} has {len(actual)} tokens, the reference "+ f"produces {len(expected)}: the two have diverged structurally."+ )+ return 1++ drifted = []+ nudged = 0+ for index, (want, got) in enumerate(zip(expected, actual)):+ if want == got:+ continue+ want_f, got_f = as_float(want), as_float(got)+ if want_f is not None and got_f is not None and close(want_f, got_f):+ nudged += 1+ continue+ drifted.append((index, want, got))++ if drifted:+ print(f"{len(drifted)} of {len(expected)} tokens have drifted:")+ for index, want, got in drifted[:MAX_REPORTED]:+ print(f" token {index}: committed {got!r}, reference says {want!r}")+ if len(drifted) > MAX_REPORTED:+ print(f" ... and {len(drifted) - MAX_REPORTED} more")+ print("Run 'python3 reference/gen_golden.py' and commit the result.")+ return 1++ print(+ f"{len(expected)} tokens checked, all in agreement"+ + (f" ({nudged} within tolerance but not bit-identical)" if nudged else "")+ )+ return 0+++if __name__ == "__main__":+ sys.exit(main())
+ reference/fsrs7_reference.py view
@@ -0,0 +1,243 @@+"""Pure-Python transcription of the FSRS-7 memory model.++Transcribed line-by-line from the reference implementation used by the official+benchmark:++ https://github.com/open-spaced-repetition/srs-benchmark+ models/fsrs_v7.py (rev 8c11619, 2026-08-04)+ models/fsrs_v7_interval_penalty.py (same rev)++The benchmark implementation is written in PyTorch; this file reproduces the+exact same scalar arithmetic with the standard library only, so that it can be+used to generate golden vectors for the Haskell port without pulling in torch.+"""++import math++# w[15] / w[24] (the "easy bonus" of the long-/short-term blocks) are 1.3 here.+# The srs-benchmark README still lists 1.15 for those two weights, but that+# block of the README has not been touched since 2026-03-18 while the code was+# updated to 1.3 on 2026-03-21 (commit e274ac3, "Update FSRS-7"). The code wins.+DEFAULT_PARAMETERS = [+ # Initial stability, indexed by rating - 1+ 0.041, 2.4175, 4.1283, 11.9709,+ # Difficulty+ 5.6385, 0.4468, 3.262,+ # Stability, long-term block+ 2.3054, 0.1688, 1.3325, 0.3524, 0.0049, 0.7503, 0.0896, 0.6625, 1.3,+ # Stability, short-term block+ 0.882, 0.3072, 3.5875, 0.303, 0.0107, 0.2279, 2.6413, 0.5594, 1.3,+ # Long/short-term transition function+ 2.5, 1.0,+ # Forgetting curve+ 0.0723, 0.1634, 0.5, 0.9555, 0.2245, 0.6232, 0.1362, 0.3862,+]++LOWER_BOUNDS = [+ 0.0001, 0.0001, 0.0001, 0.0001,+ 1.0, 0.001, 0.1,+ 0.0, 0.0, 0.3, 0.01, 0.001, 0.1, 0.0, 0.0, 1.0,+ 0.0, 0.0, 0.5, 0.001, 0.001, 0.001, 0.0, 0.0, 1.0,+ 2.5, 0.0,+ 0.01, 0.01, 0.5, 0.5, 0.01, 0.1, 0.0, 0.1,+]++UPPER_BOUNDS = [+ 50.0, 100.0, 100.0, 100.0,+ 10.0, 4.0, 4.0,+ 4.0, 1.2, 3.0, 1.5, 0.9, 1.0, 3.5, 1.0, 7.0,+ 4.0, 2.0, 6.0, 1.5, 2.0, 1.0, 5.0, 1.0, 7.0,+ 15.0, 1.0,+ 0.25, 0.95, 0.85, 0.99, 1.0, 1.0, 0.9, 1.1,+]++STABILITY_MIN = 0.0001 # config.s_min for FSRS-7 (always run with --secs)+STABILITY_MAX = 36500.0 # config.s_max+MIN_DIFFICULTY = 1.0+MAX_DIFFICULTY = 10.0+MIN_INTERVAL = 1.0 / 86400.0 # one second, in days+MAX_INTERVAL = 36500.0 # one hundred years, in days++LONG_TERM_BASE = 7+SHORT_TERM_BASE = 16+++def clamp(x, lo, hi):+ return min(max(x, lo), hi)+++# --------------------------------------------------------------------------+# Forgetting curve: a stability-weighted mixture of two power laws.+# --------------------------------------------------------------------------+++def forgetting_curve(w, t, s):+ """Probability of recall after `t` days with stability `s` days."""+ decay1 = -w[-8]+ decay2 = -w[-7]+ base1, base2 = w[-6], w[-5]+ base_weight1, base_weight2 = w[-4], w[-3]+ swp1, swp2 = w[-2], w[-1]++ t_over_s = t / s++ def power_law_retention(base, decay):+ factor = base ** (1.0 / decay) - 1.0+ return (1.0 + factor * t_over_s) ** decay++ r1 = power_law_retention(base1, decay1)+ r2 = power_law_retention(base2, decay2)++ weight1 = base_weight1 * s ** -swp1+ weight2 = base_weight2 * s ** swp2++ return (weight1 * r1 + weight2 * r2) / (weight1 + weight2)+++def forgetting_curve_derivative(w, t, s):+ """dR/dt of `forgetting_curve`; always <= 0 for in-bounds parameters."""+ decay1 = -w[-8]+ decay2 = -w[-7]+ base1, base2 = w[-6], w[-5]+ base_weight1, base_weight2 = w[-4], w[-3]+ swp1, swp2 = w[-2], w[-1]++ c1 = base1 ** (1.0 / decay1) - 1.0+ c2 = base2 ** (1.0 / decay2) - 1.0+ t_over_s = t / s+ i1 = 1.0 + c1 * t_over_s+ i2 = 1.0 + c2 * t_over_s++ weight1 = base_weight1 * s ** -swp1+ weight2 = base_weight2 * s ** swp2++ d1 = decay1 * i1 ** (decay1 - 1.0) * (c1 / s)+ d2 = decay2 * i2 ** (decay2 - 1.0) * (c2 / s)+ return (weight1 * d1 + weight2 * d2) / (weight1 + weight2)+++def next_interval(w, desired_retention, s):+ """Invert the forgetting curve: the t with R(t, s) = desired_retention.++ The mixture has no closed-form inverse. R is strictly decreasing in t, so a+ bisection on [MIN_INTERVAL, MAX_INTERVAL] converges to full double+ precision; this is the value the Haskell root-finder is checked against.+ """+ lo, hi = MIN_INTERVAL, MAX_INTERVAL+ if forgetting_curve(w, lo, s) <= desired_retention:+ return lo+ if forgetting_curve(w, hi, s) >= desired_retention:+ return hi+ for _ in range(200):+ mid = math.sqrt(lo * hi) # bisect in log space+ if mid <= lo or mid >= hi:+ break+ if forgetting_curve(w, mid, s) > desired_retention:+ lo = mid+ else:+ hi = mid+ return math.sqrt(lo * hi)+++# --------------------------------------------------------------------------+# Difficulty+# --------------------------------------------------------------------------+++def initial_difficulty(w, rating):+ """Unclamped; `step` clamps the result to [1, 10]."""+ return w[4] - math.exp(w[5] * (rating - 1)) + 1.0+++def linear_damping(delta_difficulty, difficulty):+ return delta_difficulty * (10.0 - difficulty) / 9.0+++def mean_reversion(init, current):+ return 0.01 * init + 0.99 * current+++def next_difficulty(w, difficulty, rating):+ delta_d = -w[6] * (rating - 3)+ new_d = difficulty + linear_damping(delta_d, difficulty)+ return mean_reversion(initial_difficulty(w, 4), new_d)+++# --------------------------------------------------------------------------+# Stability+# --------------------------------------------------------------------------+++def stability_after_review(w, s, d, r, rating, base):+ """One half of the stability update; `base` is 7 (long) or 16 (short)."""+ w_sinc_base = w[base]+ w_sinc_s_exp = w[base + 1]+ w_sinc_r_mult = w[base + 2]+ w_fail_mult = w[base + 3]+ w_fail_d_exp = w[base + 4]+ w_fail_s_exp = w[base + 5]+ w_fail_r_mult = w[base + 6]+ w_hard = w[base + 7]+ w_easy = w[base + 8]++ hard_penalty = w_hard if rating == 2 else 1.0+ easy_bonus = w_easy if rating == 4 else 1.0++ new_s_fail = (+ w_fail_mult+ * d ** -w_fail_d_exp+ * ((s + 1.0) ** w_fail_s_exp - 1.0)+ * math.exp((1.0 - r) * w_fail_r_mult)+ )+ pls = min(s, new_s_fail)++ s_inc = 1.0 + (+ math.exp(w_sinc_base - 1.5)+ * (11.0 - d)+ * s ** -w_sinc_s_exp+ * (math.exp((1.0 - r) * w_sinc_r_mult) - 1.0)+ * hard_penalty+ * easy_bonus+ )+ new_s_success = max(pls, s * s_inc)++ return new_s_success if rating > 1 else pls+++def transition_function(w, delta_t):+ """1 for a fully long-term review, 0 for a same-instant (short-term) one."""+ return 1.0 - w[26] * math.exp(-w[25] * delta_t)+++def next_stability(w, s, d, delta_t, rating):+ r = forgetting_curve(w, delta_t, s)+ s_long = stability_after_review(w, s, d, r, rating, LONG_TERM_BASE)+ s_short = stability_after_review(w, s, d, r, rating, SHORT_TERM_BASE)+ coefficient = transition_function(w, delta_t)+ return coefficient * s_long + (1.0 - coefficient) * s_short+++# --------------------------------------------------------------------------+# The state transition+# --------------------------------------------------------------------------+++def step(w, state, delta_t, rating, s_min=STABILITY_MIN):+ """`state` is None for the very first review, else an (S, D) pair."""+ if state is None:+ new_s = w[rating - 1]+ new_d = clamp(initial_difficulty(w, rating), MIN_DIFFICULTY, MAX_DIFFICULTY)+ else:+ s, d = state+ new_s = next_stability(w, s, d, delta_t, rating)+ new_d = clamp(next_difficulty(w, d, rating), MIN_DIFFICULTY, MAX_DIFFICULTY)+ new_s = clamp(new_s, s_min, STABILITY_MAX)+ return (new_s, new_d)+++def replay(w, reviews, s_min=STABILITY_MIN):+ """Fold `step` over a list of (delta_t, rating) pairs."""+ state = None+ for delta_t, rating in reviews:+ state = step(w, state, delta_t, rating, s_min)+ return state
+ reference/gen_golden.py view
@@ -0,0 +1,338 @@+"""Generate test/Test/FSRS/GoldenData.hs from the Python FSRS-7 reference.++Run from the repository root:++ python3 reference/gen_golden.py+"""++import os+import sys++sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))++from fsrs7_reference import ( # noqa: E402+ DEFAULT_PARAMETERS,+ LOWER_BOUNDS,+ UPPER_BOUNDS,+ LONG_TERM_BASE,+ SHORT_TERM_BASE,+ clamp,+ forgetting_curve,+ initial_difficulty,+ next_difficulty,+ next_interval,+ stability_after_review,+ step,+ transition_function,+)++OUT = os.path.join(+ os.path.dirname(os.path.dirname(os.path.abspath(__file__))),+ "test",+ "Test",+ "FSRS",+ "GoldenData.hs",+)+++def hs(x):+ """Render a Python float as a Haskell `Double` literal."""+ x = float(x)+ s = repr(x)+ if "e" in s or "E" in s:+ mantissa, exponent = s.replace("E", "e").split("e")+ if "." not in mantissa:+ mantissa += ".0"+ return f"{mantissa}e{int(exponent)}"+ if "." not in s:+ s += ".0"+ return s+++def hs_list(xs):+ return "[" + ", ".join(xs) + "]"+++# --------------------------------------------------------------------------+# Alternative parameter sets: a deterministic LCG walk over the valid box.+# --------------------------------------------------------------------------+++def make_parameter_set(seed):+ state = seed+ w = []+ for lo, hi in zip(LOWER_BOUNDS, UPPER_BOUNDS):+ state = (state * 6364136223846793005 + 1442695040888963407) % (2**64)+ u = (state >> 11) / float(2**53)+ w.append(lo + u * (hi - lo))+ # Restore the ordering constraints the clipper enforces.+ for i in (1, 2, 3):+ w[i] = max(w[i], w[i - 1])+ w[28] = max(w[28], w[27])+ w[30] = max(w[30], w[29])+ return [round(v, 6) for v in w]+++PARAMETER_SETS = [+ DEFAULT_PARAMETERS,+ make_parameter_set(1),+ make_parameter_set(2026),+]++TIMES = [0.0, 1.0 / 86400.0, 1.0 / 1440.0, 10.0 / 1440.0, 0.25, 1.0, 3.0, 7.5, 30.0, 365.0, 3650.0]+STABILITIES = [0.0001, 0.01, 0.5, 1.0, 4.1283, 15.0, 100.0, 1000.0, 36500.0]+DIFFICULTIES = [1.0, 2.5, 4.194588083372719, 7.0, 10.0]+HALF_DIFFICULTIES = [1.0, 4.194588083372719, 10.0]+HALF_STABILITIES = [0.01, 1.0, 4.1283, 1000.0]+HALF_RETRIEVABILITIES = [0.05, 0.5, 1.0]+STEP_STABILITIES = [0.0001, 1.0, 4.1283, 1000.0, 36500.0]+STEP_DIFFICULTIES = [1.0, 4.194588083372719, 10.0]+STEP_DELTAS = [0.0, 10.0 / 1440.0, 0.5, 1.0, 45.0, 400.0]+DELTAS = [0.0, 1.0 / 1440.0, 10.0 / 1440.0, 0.5, 1.0, 6.0, 45.0, 400.0]+RETENTIONS = [0.7, 0.8, 0.85, 0.9, 0.95, 0.97, 0.99]+RATINGS = [1, 2, 3, 4]++REVIEW_SEQUENCES = [+ [(0.0, 3)],+ [(0.0, 1)],+ [(0.0, 4)],+ [(0.0, 3), (10.0 / 1440.0, 3)],+ [(0.0, 1), (1.0 / 1440.0, 3), (10.0 / 1440.0, 3), (1.0, 3)],+ [(0.0, 3), (1.0, 3), (3.0, 3), (8.0, 3), (21.0, 3)],+ [(0.0, 2), (1.0, 2), (2.0, 2), (3.0, 2)],+ [(0.0, 4), (15.0, 4), (90.0, 4), (365.0, 4)],+ [(0.0, 3), (5.0, 1), (10.0 / 1440.0, 3), (1.0, 3), (4.0, 4)],+ [(0.0, 1), (0.0, 1), (0.0, 1), (0.0, 3)],+ [(0.0, 3), (100.0, 1), (0.5, 2), (2.0, 3), (6.0, 4), (30.0, 1)],+ [(0.0, 2), (0.25, 3), (0.75, 4), (2.5, 1), (0.01, 3), (7.0, 3)],+ [(0.0, 3)] + [(2.0 ** k, 3) for k in range(10)],+ [(0.0, 4)] + [(1.0, r) for r in (4, 3, 2, 1, 3, 4, 2, 1)],+]+++def render():+ """Build the contents of GoldenData.hs and return it as a string."""+ lines = []+ add = lines.append++ add("{-# LANGUAGE DerivingStrategies #-}")+ add("")+ add("-- This module is nothing but a few thousand literals; optimising it")+ add("-- costs compile time and buys nothing.")+ add("{-# OPTIONS_GHC -O0 #-}")+ add("")+ add("-- | Golden vectors for the FSRS-7 implementation.")+ add("--")+ add("-- Generated by @reference\\/gen_golden.py@ from the pure-Python")+ add("-- transcription of the official benchmark model. Do not edit by hand;")+ add("-- regenerate with @python3 reference\\/gen_golden.py@.")+ add("module Test.FSRS.GoldenData")+ add(" ( goldenParameterSets")+ add(" , CurveVector (..)")+ add(" , goldenCurveVectors")+ add(" , DifficultyVector (..)")+ add(" , goldenDifficultyVectors")+ add(" , HalfStabilityVector (..)")+ add(" , goldenHalfStabilityVectors")+ add(" , TransitionVector (..)")+ add(" , goldenTransitionVectors")+ add(" , StepVector (..)")+ add(" , goldenStepVectors")+ add(" , IntervalVector (..)")+ add(" , goldenIntervalVectors")+ add(" , ReplayVector (..)")+ add(" , goldenReplayVectors")+ add(" ) where")+ add("")+ add("-- | The parameter sets the vectors below refer to by index.")+ add("-- Index 0 is the FSRS-7 default parameter set.")+ add("goldenParameterSets :: [[Double]]")+ add("goldenParameterSets =")+ for i, w in enumerate(PARAMETER_SETS):+ prefix = " [ " if i == 0 else " , "+ add(prefix + hs_list([hs(v) for v in w]))+ add(" ]")+ add("")++ # ---------------------------------------------------------------- curve+ add("-- | @R(t, s)@, the probability of recall.")+ add("data CurveVector = CurveVector")+ add(" { cvParams :: !Int")+ add(" , cvElapsedDays :: !Double")+ add(" , cvStability :: !Double")+ add(" , cvRetrievability :: !Double")+ add(" }")+ add(" deriving stock (Eq, Show)")+ add("")+ rows = []+ for pi, w in enumerate(PARAMETER_SETS):+ for t in TIMES:+ for s in STABILITIES:+ rows.append(+ f"CurveVector {pi} {hs(t)} {hs(s)} {hs(forgetting_curve(w, t, s))}"+ )+ emit_list(add, "goldenCurveVectors", rows)++ # ----------------------------------------------------------- difficulty+ add("-- | Initial and subsequent difficulty.")+ add("data DifficultyVector = DifficultyVector")+ add(" { dvParams :: !Int")+ add(" , dvDifficulty :: !(Maybe Double)")+ add(" -- ^ 'Nothing' for the initial difficulty of a brand-new card.")+ add(" , dvRating :: !Int")+ add(" , dvNextDifficulty :: !Double")+ add(" }")+ add(" deriving stock (Eq, Show)")+ add("")+ rows = []+ for pi, w in enumerate(PARAMETER_SETS):+ for g in RATINGS:+ v = clamp(initial_difficulty(w, g), 1.0, 10.0)+ rows.append(f"DifficultyVector {pi} Nothing {g} {hs(v)}")+ for d in DIFFICULTIES:+ for g in RATINGS:+ v = clamp(next_difficulty(w, d, g), 1.0, 10.0)+ rows.append(+ f"DifficultyVector {pi} (Just {hs(d)}) {g} {hs(v)}"+ )+ emit_list(add, "goldenDifficultyVectors", rows)++ # ------------------------------------------------------- half stability+ add("-- | One half of the stability update, before the two are blended.")+ add("data HalfStabilityVector = HalfStabilityVector")+ add(" { hsParams :: !Int")+ add(" , hsLongTerm :: !Bool")+ add(" -- ^ 'True' for the long-term block, 'False' for the short-term one.")+ add(" , hsStability :: !Double")+ add(" , hsDifficulty :: !Double")+ add(" , hsRetrievability :: !Double")+ add(" , hsRating :: !Int")+ add(" , hsNextStability :: !Double")+ add(" }")+ add(" deriving stock (Eq, Show)")+ add("")+ rows = []+ for pi, w in enumerate(PARAMETER_SETS):+ for s in HALF_STABILITIES:+ for d in HALF_DIFFICULTIES:+ for r in HALF_RETRIEVABILITIES:+ for g in RATINGS:+ for long, base in ((True, LONG_TERM_BASE), (False, SHORT_TERM_BASE)):+ v = stability_after_review(w, s, d, r, g, base)+ rows.append(+ f"HalfStabilityVector {pi} {long} {hs(s)} {hs(d)} "+ f"{hs(r)} {g} {hs(v)}"+ )+ emit_list(add, "goldenHalfStabilityVectors", rows)++ # --------------------------------------------------------- transition+ add("-- | The long-\\/short-term blending coefficient.")+ add("data TransitionVector = TransitionVector")+ add(" { tvParams :: !Int")+ add(" , tvElapsedDays :: !Double")+ add(" , tvCoefficient :: !Double")+ add(" }")+ add(" deriving stock (Eq, Show)")+ add("")+ rows = []+ for pi, w in enumerate(PARAMETER_SETS):+ for t in TIMES:+ rows.append(+ f"TransitionVector {pi} {hs(t)} {hs(transition_function(w, t))}"+ )+ emit_list(add, "goldenTransitionVectors", rows)++ # --------------------------------------------------------------- step+ add("-- | A full memory-state transition.")+ add("data StepVector = StepVector")+ add(" { svParams :: !Int")+ add(" , svState :: !(Maybe (Double, Double))")+ add(" -- ^ @(stability, difficulty)@; 'Nothing' for the first review.")+ add(" , svElapsedDays :: !Double")+ add(" , svRating :: !Int")+ add(" , svNextState :: !(Double, Double)")+ add(" }")+ add(" deriving stock (Eq, Show)")+ add("")+ rows = []+ for pi, w in enumerate(PARAMETER_SETS):+ for g in RATINGS:+ s1, d1 = step(w, None, 0.0, g)+ rows.append(f"StepVector {pi} Nothing 0.0 {g} ({hs(s1)}, {hs(d1)})")+ for s in STEP_STABILITIES:+ for d in STEP_DIFFICULTIES:+ for dt in STEP_DELTAS:+ for g in RATINGS:+ s1, d1 = step(w, (s, d), dt, g)+ rows.append(+ f"StepVector {pi} (Just ({hs(s)}, {hs(d)})) {hs(dt)} {g} "+ f"({hs(s1)}, {hs(d1)})"+ )+ emit_list(add, "goldenStepVectors", rows)++ # ----------------------------------------------------------- intervals+ add("-- | The interval that lands exactly on the desired retention.")+ add("data IntervalVector = IntervalVector")+ add(" { ivParams :: !Int")+ add(" , ivDesiredRetention :: !Double")+ add(" , ivStability :: !Double")+ add(" , ivInterval :: !Double")+ add(" }")+ add(" deriving stock (Eq, Show)")+ add("")+ rows = []+ for pi, w in enumerate(PARAMETER_SETS):+ for dr in RETENTIONS:+ for s in STABILITIES:+ rows.append(+ f"IntervalVector {pi} {hs(dr)} {hs(s)} {hs(next_interval(w, dr, s))}"+ )+ emit_list(add, "goldenIntervalVectors", rows)++ # -------------------------------------------------------------- replay+ add("-- | A whole review history folded into a final memory state.")+ add("data ReplayVector = ReplayVector")+ add(" { rvParams :: !Int")+ add(" , rvReviews :: ![(Double, Int)]")+ add(" -- ^ @(days since the previous review, rating)@.")+ add(" , rvFinalState :: !(Double, Double)")+ add(" }")+ add(" deriving stock (Eq, Show)")+ add("")+ rows = []+ for pi, w in enumerate(PARAMETER_SETS):+ for seq_ in REVIEW_SEQUENCES:+ state = None+ for dt, g in seq_:+ state = step(w, state, dt, g)+ reviews = hs_list([f"({hs(dt)}, {g})" for dt, g in seq_])+ assert state is not None+ rows.append(+ f"ReplayVector {pi} {reviews} ({hs(state[0])}, {hs(state[1])})"+ )+ emit_list(add, "goldenReplayVectors", rows)++ return "\n".join(lines).rstrip() + "\n"+++def main(out=OUT):+ text = render()+ with open(out, "w") as fh:+ fh.write(text)+ print(f"wrote {out} ({len(text.splitlines())} lines)")+++def emit_list(add, name, rows):+ ty = name[len("golden"):]+ ty = ty[0].upper() + ty[1:]+ ty = ty[: -len("Vectors")] + "Vector"+ add(f"{name} :: [{ty}]")+ add(f"{name} =")+ for i, row in enumerate(rows):+ add((" [ " if i == 0 else " , ") + row)+ add(" ]")+ add("")+++if __name__ == "__main__":+ main()
+ reference/test_reference.py view
@@ -0,0 +1,181 @@+"""Self-checks for the pure-Python FSRS-7 reference.++The reference is the source of truth for the golden vectors that the Haskell+test suite is measured against, so it gets a few checks of its own. These are+the model's structural invariants, not a second copy of the Haskell suite:+enough to catch a transcription typo before it is baked into GoldenData.hs.++No test framework needed. Run from the repository root:++ python3 reference/test_reference.py+"""++import math+import os+import random+import sys++sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))++from fsrs7_reference import ( # noqa: E402+ DEFAULT_PARAMETERS,+ LOWER_BOUNDS,+ MAX_DIFFICULTY,+ MIN_DIFFICULTY,+ STABILITY_MAX,+ STABILITY_MIN,+ UPPER_BOUNDS,+ forgetting_curve,+ initial_difficulty,+ next_difficulty,+ next_interval,+ step,+ transition_function,+)++ORDERING_CONSTRAINTS = [(0, 1), (1, 2), (2, 3), (27, 28), (29, 30)]+RATINGS = [1, 2, 3, 4]+++def parameter_sets(count, seed):+ """The defaults plus `count` random vectors from inside the valid box."""+ rng = random.Random(seed)+ yield DEFAULT_PARAMETERS+ for _ in range(count):+ w = [rng.uniform(lo, hi) for lo, hi in zip(LOWER_BOUNDS, UPPER_BOUNDS)]+ for i, j in ORDERING_CONSTRAINTS:+ w[j] = max(w[j], w[i])+ yield w+++def sample_states(seed):+ rng = random.Random(seed)+ for _ in range(40):+ s = math.exp(rng.uniform(math.log(STABILITY_MIN), math.log(STABILITY_MAX)))+ d = rng.uniform(MIN_DIFFICULTY, MAX_DIFFICULTY)+ dt = 0.0 if rng.random() < 0.2 else math.exp(rng.uniform(math.log(1 / 86400), math.log(3650)))+ yield s, d, dt+++# ---------------------------------------------------------------------------+++def test_parameter_vector_is_well_formed():+ assert len(DEFAULT_PARAMETERS) == 35, len(DEFAULT_PARAMETERS)+ assert len(LOWER_BOUNDS) == 35 and len(UPPER_BOUNDS) == 35+ for i, (lo, hi) in enumerate(zip(LOWER_BOUNDS, UPPER_BOUNDS)):+ assert lo <= hi, f"bound {i} is inverted: {lo} > {hi}"+ for i, w in enumerate(DEFAULT_PARAMETERS):+ assert LOWER_BOUNDS[i] <= w <= UPPER_BOUNDS[i], f"default w{i} = {w} is out of bounds"+ for i, j in ORDERING_CONSTRAINTS:+ assert DEFAULT_PARAMETERS[i] <= DEFAULT_PARAMETERS[j], f"w{i} > w{j}"+++def test_nothing_is_forgotten_immediately():+ for w in parameter_sets(20, seed=1):+ for s in (STABILITY_MIN, 1.0, 37.0, STABILITY_MAX):+ assert forgetting_curve(w, 0.0, s) == 1.0+++def test_retrievability_is_a_decreasing_probability():+ for w in parameter_sets(40, seed=2):+ for s, _, dt in sample_states(seed=3):+ r = forgetting_curve(w, dt, s)+ assert 0.0 < r <= 1.0, r+ assert forgetting_curve(w, dt + 1e-3, s) <= r+++def test_base_weights_are_the_recall_probability_at_t_equals_s():+ # Give both power laws the same base and the mixture collapses to it.+ for base in (0.5, 0.85):+ w = list(DEFAULT_PARAMETERS)+ w[29] = w[30] = base+ for s in (0.5, 1.0, 37.0, 1000.0):+ assert abs(forgetting_curve(w, s, s) - base) < 1e-12+++def test_intervals_land_on_the_desired_retention():+ for w in parameter_sets(20, seed=4):+ for dr in (0.7, 0.8, 0.9, 0.95, 0.99):+ for s in (0.01, 1.0, 37.0, 1000.0):+ t = next_interval(w, dr, s)+ if t <= 1 / 86400 or t >= 36500:+ continue # saturated, cannot hit the target+ assert abs(forgetting_curve(w, t, s) - dr) < 1e-9+++def test_a_better_rating_is_never_worse_for_the_card():+ for w in parameter_sets(40, seed=5):+ for s, d, dt in sample_states(seed=6):+ outcomes = [step(w, (s, d), dt, g) for g in RATINGS]+ stabilities = [new_s for new_s, _ in outcomes]+ difficulties = [new_d for _, new_d in outcomes]+ assert stabilities == sorted(stabilities), stabilities+ assert difficulties == sorted(difficulties, reverse=True), difficulties+++def test_remembering_helps_and_forgetting_does_not():+ for w in parameter_sets(40, seed=7):+ for s, d, dt in sample_states(seed=8):+ for g in (2, 3, 4):+ assert step(w, (s, d), dt, g)[0] >= s * (1 - 1e-12)+ assert step(w, (s, d), dt, 1)[0] <= s * (1 + 1e-12)+++def test_the_state_stays_in_range():+ for w in parameter_sets(40, seed=9):+ for s, d, dt in sample_states(seed=10):+ for g in RATINGS:+ new_s, new_d = step(w, (s, d), dt, g)+ assert STABILITY_MIN <= new_s <= STABILITY_MAX, new_s+ assert MIN_DIFFICULTY <= new_d <= MAX_DIFFICULTY, new_d+ first_s, first_d = step(w, None, 0.0, g)+ assert first_s == min(max(w[g - 1], STABILITY_MIN), STABILITY_MAX)+ assert MIN_DIFFICULTY <= first_d <= MAX_DIFFICULTY+++def test_difficulty_reverts_towards_an_easy_first_review():+ # A Good review leaves the rating delta at zero, so all that is left is the+ # 1% pull towards init_d(4). Iterating it therefore converges on exactly+ # that anchor, which pins down which rating the anchor is taken from.+ for w in parameter_sets(10, seed=12):+ anchor = min(max(initial_difficulty(w, 4), MIN_DIFFICULTY), MAX_DIFFICULTY)+ for start in (MIN_DIFFICULTY, 5.0, MAX_DIFFICULTY):+ d = start+ for _ in range(3000):+ d = min(max(next_difficulty(w, d, 3), MIN_DIFFICULTY), MAX_DIFFICULTY)+ assert abs(d - anchor) < 1e-9, (d, anchor)+++def test_the_transition_function_is_a_weight():+ for w in parameter_sets(40, seed=11):+ assert transition_function(w, 0.0) == 1 - w[26]+ assert transition_function(w, 3650.0) == 1.0+ previous = -1.0+ for dt in (0.0, 1 / 86400, 0.01, 0.5, 1.0, 10.0, 3650.0):+ c = transition_function(w, dt)+ assert 0.0 <= c <= 1.0, c+ assert c >= previous+ previous = c+++# ---------------------------------------------------------------------------+++def main():+ checks = [(name, fn) for name, fn in sorted(globals().items()) if name.startswith("test_")]+ failed = 0+ for name, check in checks:+ try:+ check()+ except AssertionError as error:+ failed += 1+ print(f"FAIL {name}: {error}")+ else:+ print(f"ok {name}")+ print(f"\n{len(checks) - failed} of {len(checks)} checks passed")+ return 1 if failed else 0+++if __name__ == "__main__":+ sys.exit(main())
+ src/FSRS.hs view
@@ -0,0 +1,46 @@+-- | FSRS-7 — the Free Spaced Repetition Scheduler, version 7.+--+-- FSRS predicts when you are about to forget something and schedules the+-- review for just before that happens. It models a card with two numbers:+--+-- * /stability/, the memory's half-life in days, and+-- * /difficulty/, how hard this particular card is for you, on a 1–10 scale,+--+-- from which it derives /retrievability/, the probability that you can recall+-- the card right now.+--+-- A quick tour:+--+-- @+-- import "FSRS"+--+-- -- Grade a brand-new card 'Good', then grade it again a week later.+-- let p = 'defaultParameters'+-- first = 'nextMemoryState' p Nothing 0 'Good'+-- second = 'nextMemoryState' p ('Just' first) 7 'Good'+--+-- -- When should it come back, if we want a 90% chance of recall?+-- 'nextIntervalDays' p 0.9 ('memoryStability' second)+-- @+--+-- For whole-card scheduling — learning steps, due dates, lapses — use+-- "FSRS.Scheduler":+--+-- @+-- let (card', logEntry) = 'reviewCard' 'defaultScheduler' ('newCard' now) 'Good' now+-- @+--+-- The modules underneath are "FSRS.Types" (ratings and memory states),+-- "FSRS.Parameters" (the 35 weights), "FSRS.Algorithm" (the model itself) and+-- "FSRS.Scheduler".+module FSRS+ ( module FSRS.Types+ , module FSRS.Parameters+ , module FSRS.Algorithm+ , module FSRS.Scheduler+ ) where++import FSRS.Algorithm+import FSRS.Parameters+import FSRS.Scheduler+import FSRS.Types
+ src/FSRS/Algorithm.hs view
@@ -0,0 +1,335 @@+{-# LANGUAGE BangPatterns #-}++-- | The FSRS-7 memory model.+--+-- This module is a direct transcription of the reference implementation in+-- <https://github.com/open-spaced-repetition/srs-benchmark srs-benchmark>+-- (@models\/fsrs_v7.py@ and @models\/fsrs_v7_interval_penalty.py@). Every+-- function here is pure and total.+--+-- What changed in FSRS-7 relative to FSRS-6:+--+-- * The forgetting curve is a stability-weighted mixture of /two/ power laws+-- instead of one, which is why it has eight weights and no closed-form+-- inverse (see 'nextIntervalDays').+-- * The stability update is computed twice — once with a long-term weight+-- block and once with a short-term one — and the two are blended by+-- 'transitionCoefficient', a smooth function of the elapsed time. FSRS-6+-- switched between two separate formulas on a same-day\/not-same-day flag.+-- * Intervals are genuinely continuous. Ten minutes is @10 \/ 1440@ days and+-- the model is meant to be evaluated at such values, not at whole days.+module FSRS.Algorithm+ ( -- * Forgetting curve+ retrievability+ , retrievabilityDerivative+ , nextIntervalDays++ -- * Difficulty+ , initialDifficulty+ , nextDifficulty++ -- * Stability+ , initialStability+ , stabilityAfterReview+ , transitionCoefficient+ , nextStability++ -- * State transition+ , nextMemoryState+ , replayReviews++ -- * Bounds+ , stabilityMin+ , stabilityMax+ , difficultyMin+ , difficultyMax+ , minimumIntervalDays+ , maximumIntervalDays+ ) where++import FSRS.Parameters+ ( CurveWeights (..)+ , Parameters+ , StabilityWeights (..)+ , curveWeights+ , difficultyDelta+ , initialDifficultyBase+ , initialDifficultyRate+ , initialStabilityWeight+ , longTermWeights+ , shortTermWeights+ , transitionAmplitude+ , transitionRate+ )+import FSRS.Types+ ( Days+ , Difficulty+ , MemoryState (..)+ , Rating (..)+ , Retrievability+ , Stability+ , ratingToInt+ )++-- | The smallest stability the model will report, @1e-4@ days (about nine+-- seconds). This is the @s_min@ the upstream configuration uses for FSRS-7,+-- which is always run with second-precision intervals.+stabilityMin :: Stability+stabilityMin = 1.0e-4++-- | The largest stability the model will report: @36500@ days, a century.+stabilityMax :: Stability+stabilityMax = 36500.0++-- | @1@.+difficultyMin :: Difficulty+difficultyMin = 1.0++-- | @10@.+difficultyMax :: Difficulty+difficultyMax = 10.0++-- | One second, expressed in days — the shortest interval 'nextIntervalDays'+-- will return.+minimumIntervalDays :: Days+minimumIntervalDays = 1.0 / 86400.0++-- | A century in days — the longest interval 'nextIntervalDays' will return.+maximumIntervalDays :: Days+maximumIntervalDays = 36500.0++clampTo :: Double -> Double -> Double -> Double+clampTo lo hi x = min hi (max lo x)++-- ---------------------------------------------------------------------------+-- Forgetting curve+-- ---------------------------------------------------------------------------++-- | The probability of recalling a card @t@ days after the last review, given+-- its stability.+--+-- FSRS-7 mixes two power laws whose relative weight depends on the stability+-- itself, so — unlike every earlier version — the retrievability at @t == s@+-- is not a fixed @0.9@ but drifts with @s@.+--+-- @t@ must be non-negative and @s@ strictly positive.+retrievability :: Parameters -> Days -> Stability -> Retrievability+retrievability params t s = (weight1 * r1 + weight2 * r2) / (weight1 + weight2)+ where+ cw = curveWeights params+ tOverS = t / s+ powerLaw base decay = (1 + factor * tOverS) ** decay+ where+ factor = base ** (1 / decay) - 1+ r1 = powerLaw (cwBase1 cw) (cwDecay1 cw)+ r2 = powerLaw (cwBase2 cw) (cwDecay2 cw)+ weight1 = cwWeight1 cw * s ** negate (cwStabilityPower1 cw)+ weight2 = cwWeight2 cw * s ** cwStabilityPower2 cw++-- | @d\/dt@ of 'retrievability'. Never positive for in-bounds parameters.+retrievabilityDerivative :: Parameters -> Days -> Stability -> Double+retrievabilityDerivative params t s =+ (weight1 * d1 + weight2 * d2) / (weight1 + weight2)+ where+ cw = curveWeights params+ tOverS = t / s+ slope base decay = decay * inner ** (decay - 1) * (factor / s)+ where+ factor = base ** (1 / decay) - 1+ inner = 1 + factor * tOverS+ d1 = slope (cwBase1 cw) (cwDecay1 cw)+ d2 = slope (cwBase2 cw) (cwDecay2 cw)+ weight1 = cwWeight1 cw * s ** negate (cwStabilityPower1 cw)+ weight2 = cwWeight2 cw * s ** cwStabilityPower2 cw++-- | The interval, in days, after which a card of the given stability will have+-- decayed to exactly the desired retention.+--+-- The FSRS-7 forgetting curve has no closed-form inverse, so this is a+-- root-find: Newton's method in @log t@ (which is what makes the problem+-- well-conditioned — see the upstream @fsrs_v7_interval_penalty@ module),+-- safeguarded by a bracketing bisection so that it cannot diverge.+--+-- The result is always within @['minimumIntervalDays', 'maximumIntervalDays']@;+-- a desired retention that is unreachable within that window saturates at the+-- nearer end.+nextIntervalDays :: Parameters -> Retrievability -> Stability -> Days+nextIntervalDays params target s+ | not (target > 0) = maximumIntervalDays -- also catches NaN+ | target >= 1 = minimumIntervalDays+ | retrievability params lo s <= target = lo+ | retrievability params hi s >= target = hi+ | otherwise = exp (search (0 :: Int) (log lo) (log hi) u0)+ where+ lo = minimumIntervalDays+ hi = maximumIntervalDays+ -- R(s, s) is near the interesting range, so start there.+ u0 = clampTo (log lo) (log hi) (log s)++ maxIterations = 200 :: Int+ -- Full double precision in log space.+ tolerance = 1.0e-15++ search !n !a !b !u+ | n >= maxIterations = u+ | fu == 0 = u+ | converged = next+ | otherwise = search (n + 1) a' b' next+ where+ t = exp u+ fu = retrievability params t s - target+ -- R is strictly decreasing in t, so the sign of `fu` says which side+ -- of the root `u` is on.+ (a', b') = if fu > 0 then (u, b) else (a, u)+ slope = retrievabilityDerivative params t s * t+ newton = u - fu / slope+ next+ | isNaN newton || isInfinite newton || newton <= a' || newton >= b' =+ 0.5 * (a' + b')+ | otherwise = newton+ converged = abs (next - u) <= tolerance * max 1 (abs u)++-- ---------------------------------------------------------------------------+-- Difficulty+-- ---------------------------------------------------------------------------++-- | Difficulty before clamping. The mean reversion in 'nextDifficulty' pulls+-- towards the /unclamped/ value for 'Easy', which is why this is kept+-- separate.+rawInitialDifficulty :: Parameters -> Rating -> Double+rawInitialDifficulty params rating =+ initialDifficultyBase params+ - exp (initialDifficultyRate params * fromIntegral (ratingToInt rating - 1))+ + 1++-- | The difficulty a card is born with, given the rating of its first review.+initialDifficulty :: Parameters -> Rating -> Difficulty+initialDifficulty params =+ clampTo difficultyMin difficultyMax . rawInitialDifficulty params++-- | Difficulty after a review: a rating-driven step, damped so that it slows+-- down as difficulty approaches its maximum, then reverted 1% of the way+-- towards the difficulty an 'Easy' first review would have produced.+nextDifficulty :: Parameters -> Difficulty -> Rating -> Difficulty+nextDifficulty params d rating =+ clampTo difficultyMin difficultyMax (meanReversion damped)+ where+ delta = negate (difficultyDelta params) * fromIntegral (ratingToInt rating - 3)+ damped = d + delta * (10 - d) / 9+ meanReversion current = 0.01 * rawInitialDifficulty params Easy + 0.99 * current++-- ---------------------------------------------------------------------------+-- Stability+-- ---------------------------------------------------------------------------++-- | The stability a card is born with, given the rating of its first review.+initialStability :: Parameters -> Rating -> Stability+initialStability = initialStabilityWeight++-- | One half of the stability update.+--+-- Called twice per review — once with 'FSRS.Parameters.longTermWeights' and+-- once with 'FSRS.Parameters.shortTermWeights' — and the two results are+-- blended by 'nextStability'.+--+-- On a lapse the new stability is the post-lapse stability, which can never+-- exceed the old one. On a success it is the old stability scaled by a factor+-- that grows with how overdue the card was, shrinks as the card gets easier+-- and more stable, and is scaled again by the hard penalty or the easy bonus.+stabilityAfterReview+ :: StabilityWeights+ -> MemoryState+ -> Retrievability+ -- ^ The retrievability at review time, from 'retrievability'.+ -> Rating+ -> Stability+stabilityAfterReview w (MemoryState s d) r rating+ | rating == Again = postLapse+ | otherwise = max postLapse (s * increase)+ where+ postLapse = min s failureStability+ failureStability =+ swFailureFactor w+ * d ** negate (swFailureDifficultyExponent w)+ * ((s + 1) ** swFailureStabilityExponent w - 1)+ * exp ((1 - r) * swFailureRetrievabilityFactor w)+ hardPenalty = if rating == Hard then swHardPenalty w else 1+ easyBonus = if rating == Easy then swEasyBonus w else 1+ increase =+ 1+ + exp (swIncreaseBase w - 1.5)+ * (11 - d)+ * s ** negate (swIncreaseStabilityExponent w)+ * (exp ((1 - r) * swIncreaseRetrievabilityFactor w) - 1)+ * hardPenalty+ * easyBonus++-- | How much of a long-term review this is: @0@ for a review that happens at+-- the same instant as the previous one, tending to @1@ as the gap grows.+--+-- This is the piece that replaces FSRS-6's hard same-day\/not-same-day split.+-- The elapsed time is expected to be non-negative.+transitionCoefficient :: Parameters -> Days -> Double+transitionCoefficient params deltaT =+ 1 - transitionAmplitude params * exp (negate (transitionRate params) * deltaT)++-- | Stability after a review, blending the long- and short-term updates.+nextStability+ :: Parameters+ -> MemoryState+ -> Days+ -- ^ Days since the previous review.+ -> Rating+ -> Stability+nextStability params state deltaT rating =+ coefficient * longTerm + (1 - coefficient) * shortTerm+ where+ r = retrievability params deltaT (memoryStability state)+ longTerm = stabilityAfterReview (longTermWeights params) state r rating+ shortTerm = stabilityAfterReview (shortTermWeights params) state r rating+ coefficient = transitionCoefficient params deltaT++-- ---------------------------------------------------------------------------+-- State transition+-- ---------------------------------------------------------------------------++-- | Advance a card's memory state by one review.+--+-- Pass 'Nothing' for a card that has never been reviewed; the elapsed time is+-- then ignored and the state is read straight off the initial-stability and+-- initial-difficulty weights.+nextMemoryState+ :: Parameters+ -> Maybe MemoryState+ -- ^ The state before the review, or 'Nothing' for a brand-new card.+ -> Days+ -- ^ Days since the previous review.+ -> Rating+ -> MemoryState+nextMemoryState params before deltaT rating =+ MemoryState+ { memoryStability = clampTo stabilityMin stabilityMax s+ , memoryDifficulty = clampTo difficultyMin difficultyMax d+ }+ where+ (s, d) = case before of+ Nothing ->+ ( initialStability params rating+ , initialDifficulty params rating+ )+ Just state ->+ ( nextStability params state deltaT rating+ , nextDifficulty params (memoryDifficulty state) rating+ )++-- | Fold a whole review history into a memory state.+--+-- Each element is @(days since the previous review, rating)@; the elapsed time+-- of the first review is ignored. 'Nothing' for an empty history.+replayReviews :: Parameters -> [(Days, Rating)] -> Maybe MemoryState+replayReviews params = go Nothing+ where+ go before [] = before+ go before ((deltaT, rating) : rest) =+ let next = nextMemoryState params before deltaT rating+ in next `seq` go (Just next) rest
+ src/FSRS/Parameters.hs view
@@ -0,0 +1,361 @@+{-# LANGUAGE DerivingStrategies #-}++-- | The 35 weights of FSRS-7, and typed views onto the blocks they form.+--+-- FSRS-7 groups its weights like this:+--+-- +-----------+------------------------------------------------------------++-- | @w0..w3@ | initial stability, indexed by rating |+-- +-----------+------------------------------------------------------------++-- | @w4..w6@ | difficulty |+-- +-----------+------------------------------------------------------------++-- | @w7..w15@ | stability update, long-term block |+-- +-----------+------------------------------------------------------------++-- | @w16..w24@| stability update, short-term (same-day) block |+-- +-----------+------------------------------------------------------------++-- | @w25,w26@ | the long-\/short-term transition function |+-- +-----------+------------------------------------------------------------++-- | @w27..w34@| the two-component forgetting curve |+-- +-----------+------------------------------------------------------------++--+-- The two stability blocks have identical shapes, which is why+-- 'longTermWeights' and 'shortTermWeights' both produce a t'StabilityWeights'.+module FSRS.Parameters+ ( -- * Parameters+ Parameters+ , parameterCount+ , defaultParameters+ , mkParameters+ , clampParameters+ , parametersToList+ , parameterAt++ -- * Validation+ , ParameterError (..)+ , parameterBounds+ , validateParameters++ -- * Weight blocks+ , initialStabilityWeight+ , initialDifficultyBase+ , initialDifficultyRate+ , difficultyDelta+ , transitionRate+ , transitionAmplitude+ , StabilityWeights (..)+ , longTermWeights+ , shortTermWeights+ , CurveWeights (..)+ , curveWeights+ ) where++import Data.Array.Unboxed (UArray, bounds, elems, listArray, (!))+import Data.Maybe (mapMaybe)++import FSRS.Types (Rating, ratingToInt)++-- | An FSRS-7 parameter vector: exactly 'parameterCount' weights.+--+-- Build one with 'mkParameters' or 'clampParameters'; the constructor is+-- hidden so that the length invariant cannot be broken.+newtype Parameters = Parameters (UArray Int Double)+ deriving stock (Eq, Ord)++instance Show Parameters where+ showsPrec d p =+ showParen (d > 10) $+ showString "mkParameters " . showsPrec 11 (parametersToList p)++-- | @35@. FSRS-6 had 21 weights; FSRS-7 adds a second stability block, the+-- transition function and the six extra forgetting-curve weights.+parameterCount :: Int+parameterCount = 35++-- | The 0-based weight at the given index. Indices outside+-- @[0, 'parameterCount')@ are a programmer error and raise an exception.+parameterAt :: Parameters -> Int -> Double+parameterAt (Parameters a) i+ | i >= lo && i <= hi = a ! i+ | otherwise =+ error $+ "FSRS.Parameters.parameterAt: index " <> show i <> " out of range " <> show (lo, hi)+ where+ (lo, hi) = bounds a++-- | The weights as a plain list, in index order.+parametersToList :: Parameters -> [Double]+parametersToList (Parameters a) = elems a++-- | The default FSRS-7 parameters, obtained by the upstream authors through+-- multi-user optimisation.+--+-- These match @models\/fsrs_v7.py@ in+-- <https://github.com/open-spaced-repetition/srs-benchmark srs-benchmark>.+-- Note that the @Default Parameters@ section of that repository's README still+-- lists @1.15@ for @w15@ and @w24@; that block of the README has not been+-- updated since 2026-03-18, while the model was changed to @1.3@ three days+-- later. The values below follow the model.+defaultParameters :: Parameters+defaultParameters = Parameters (listArray (0, parameterCount - 1) ws)+ where+ ws =+ [ -- Initial stability, indexed by rating - 1+ 0.041+ , 2.4175+ , 4.1283+ , 11.9709+ , -- Difficulty+ 5.6385+ , 0.4468+ , 3.262+ , -- Stability, long-term block+ 2.3054+ , 0.1688+ , 1.3325+ , 0.3524+ , 0.0049+ , 0.7503+ , 0.0896+ , 0.6625+ , 1.3+ , -- Stability, short-term block+ 0.882+ , 0.3072+ , 3.5875+ , 0.303+ , 0.0107+ , 0.2279+ , 2.6413+ , 0.5594+ , 1.3+ , -- Long-/short-term transition function+ 2.5+ , 1.0+ , -- Forgetting curve+ 0.0723+ , 0.1634+ , 0.5+ , 0.9555+ , 0.2245+ , 0.6232+ , 0.1362+ , 0.3862+ ]++-- | Why a list of weights is not a valid parameter vector.+data ParameterError+ = -- | Got this many weights instead of 'parameterCount'.+ WrongParameterCount !Int+ | -- | @index@, @value@, @lower bound@, @upper bound@.+ ParameterOutOfBounds !Int !Double !Double !Double+ | -- | @w[i] <= w[j]@ is required but was violated: @i@, @j@, @w[i]@, @w[j]@.+ ParameterOutOfOrder !Int !Int !Double !Double+ | -- | @index@, the offending @NaN@ or infinity.+ ParameterNotFinite !Int !Double+ deriving stock (Eq, Show)++-- | The inclusive @(lower, upper)@ bound of every weight, in index order.+--+-- Taken from the parameter clipper the upstream optimiser applies after each+-- gradient step, so any parameter set produced by a real optimiser satisfies+-- them.+parameterBounds :: [(Double, Double)]+parameterBounds =+ [ -- Initial stability+ (1.0e-4, 50.0)+ , (1.0e-4, 100.0)+ , (1.0e-4, 100.0)+ , (1.0e-4, 100.0)+ , -- Difficulty+ (1.0, 10.0)+ , (0.001, 4.0)+ , (0.1, 4.0)+ , -- Stability, long-term block+ (0.0, 4.0)+ , (0.0, 1.2)+ , (0.3, 3.0)+ , (0.01, 1.5)+ , (0.001, 0.9)+ , (0.1, 1.0)+ , (0.0, 3.5)+ , (0.0, 1.0)+ , (1.0, 7.0)+ , -- Stability, short-term block+ (0.0, 4.0)+ , (0.0, 2.0)+ , (0.5, 6.0)+ , (0.001, 1.5)+ , (0.001, 2.0)+ , (0.001, 1.0)+ , (0.0, 5.0)+ , (0.0, 1.0)+ , (1.0, 7.0)+ , -- Transition function+ (2.5, 15.0)+ , (0.0, 1.0)+ , -- Forgetting curve+ (0.01, 0.25)+ , (0.01, 0.95)+ , (0.5, 0.85)+ , (0.5, 0.99)+ , (0.01, 1.0)+ , (0.1, 1.0)+ , (0.0, 0.9)+ , (0.1, 1.1)+ ]++-- | Pairs @(i, j)@ for which @w[i] <= w[j]@ must hold.+orderingConstraints :: [(Int, Int)]+orderingConstraints = [(0, 1), (1, 2), (2, 3), (27, 28), (29, 30)]++-- | Every problem with a candidate weight list, or @[]@ if there is none.+validateParameters :: [Double] -> [ParameterError]+validateParameters ws+ | n /= parameterCount = [WrongParameterCount n]+ | otherwise = boundErrors <> orderErrors+ where+ n = length ws+ boundErrors = concat (zipWith3 check [0 ..] ws parameterBounds)+ check i w (lo, hi)+ | isNaN w || isInfinite w = [ParameterNotFinite i w]+ | w < lo || w > hi = [ParameterOutOfBounds i w lo hi]+ | otherwise = []+ orderErrors = mapMaybe checkOrder orderingConstraints+ checkOrder (i, j)+ | wi <= wj = Nothing+ | otherwise = Just (ParameterOutOfOrder i j wi wj)+ where+ wi = ws !! i+ wj = ws !! j++-- | Build a parameter vector, rejecting anything out of bounds.+mkParameters :: [Double] -> Either [ParameterError] Parameters+mkParameters ws = case validateParameters ws of+ [] -> Right (Parameters (listArray (0, parameterCount - 1) ws))+ errs -> Left errs++-- | Build a parameter vector by pulling every weight into its valid range,+-- exactly as the upstream optimiser's clipper does: bounds first, in index+-- order, so that the ordering constraints are resolved against already-clamped+-- neighbours. Only a wrong number of weights can still fail.+clampParameters :: [Double] -> Either [ParameterError] Parameters+clampParameters ws+ | length ws /= parameterCount = Left [WrongParameterCount (length ws)]+ | otherwise = Right (Parameters (listArray (0, parameterCount - 1) clamped))+ where+ clamped = foldl step [] (zip3 [0 :: Int ..] ws parameterBounds)+ -- `acc` is the already-clamped prefix, in order.+ step acc (i, w, (lo, hi)) = acc <> [clamp lo' hi' w]+ where+ lo' = maximum (lo : [acc !! j | (j, k) <- orderingConstraints, k == i])+ hi' = max lo' hi+ clamp lo hi x+ | isNaN x = lo+ | otherwise = min hi (max lo x)++-- | @w[rating - 1]@: the stability a card is born with after its first review.+initialStabilityWeight :: Parameters -> Rating -> Double+initialStabilityWeight p r = parameterAt p (ratingToInt r - 1)++-- | @w4@.+initialDifficultyBase :: Parameters -> Double+initialDifficultyBase p = parameterAt p 4++-- | @w5@.+initialDifficultyRate :: Parameters -> Double+initialDifficultyRate p = parameterAt p 5++-- | @w6@.+difficultyDelta :: Parameters -> Double+difficultyDelta p = parameterAt p 6++-- | @w25@: how fast a review stops counting as same-day.+transitionRate :: Parameters -> Double+transitionRate p = parameterAt p 25++-- | @w26@: how much of the short-term behaviour applies at zero elapsed time.+transitionAmplitude :: Parameters -> Double+transitionAmplitude p = parameterAt p 26++-- | One of the two nine-weight blocks that drive the stability update.+data StabilityWeights = StabilityWeights+ { swIncreaseBase :: !Double+ -- ^ @w7@ \/ @w16@, used as @exp (base - 1.5)@.+ , swIncreaseStabilityExponent :: !Double+ -- ^ @w8@ \/ @w17@.+ , swIncreaseRetrievabilityFactor :: !Double+ -- ^ @w9@ \/ @w18@.+ , swFailureFactor :: !Double+ -- ^ @w10@ \/ @w19@.+ , swFailureDifficultyExponent :: !Double+ -- ^ @w11@ \/ @w20@.+ , swFailureStabilityExponent :: !Double+ -- ^ @w12@ \/ @w21@.+ , swFailureRetrievabilityFactor :: !Double+ -- ^ @w13@ \/ @w22@.+ , swHardPenalty :: !Double+ -- ^ @w14@ \/ @w23@.+ , swEasyBonus :: !Double+ -- ^ @w15@ \/ @w24@.+ }+ deriving stock (Eq, Show)++stabilityWeightsAt :: Int -> Parameters -> StabilityWeights+stabilityWeightsAt base p =+ StabilityWeights+ { swIncreaseBase = at 0+ , swIncreaseStabilityExponent = at 1+ , swIncreaseRetrievabilityFactor = at 2+ , swFailureFactor = at 3+ , swFailureDifficultyExponent = at 4+ , swFailureStabilityExponent = at 5+ , swFailureRetrievabilityFactor = at 6+ , swHardPenalty = at 7+ , swEasyBonus = at 8+ }+ where+ at k = parameterAt p (base + k)++-- | @w7..w15@: the block used for reviews separated by a real interval.+longTermWeights :: Parameters -> StabilityWeights+longTermWeights = stabilityWeightsAt 7++-- | @w16..w24@: the block used for same-day reviews.+shortTermWeights :: Parameters -> StabilityWeights+shortTermWeights = stabilityWeightsAt 16++-- | @w27..w34@: the mixture of two power laws that makes up the FSRS-7+-- forgetting curve.+data CurveWeights = CurveWeights+ { cwDecay1 :: !Double+ -- ^ @negate w27@ — already carries the minus sign the formula wants.+ , cwDecay2 :: !Double+ -- ^ @negate w28@.+ , cwBase1 :: !Double+ -- ^ @w29@: the recall probability of the first component at @t == s@.+ , cwBase2 :: !Double+ -- ^ @w30@: likewise for the second component.+ , cwWeight1 :: !Double+ -- ^ @w31@.+ , cwWeight2 :: !Double+ -- ^ @w32@.+ , cwStabilityPower1 :: !Double+ -- ^ @w33@; applied as @s ** negate cwStabilityPower1@.+ , cwStabilityPower2 :: !Double+ -- ^ @w34@; applied as @s ** cwStabilityPower2@.+ }+ deriving stock (Eq, Show)++-- | Read the forgetting-curve block out of a parameter vector.+curveWeights :: Parameters -> CurveWeights+curveWeights p =+ CurveWeights+ { cwDecay1 = negate (parameterAt p 27)+ , cwDecay2 = negate (parameterAt p 28)+ , cwBase1 = parameterAt p 29+ , cwBase2 = parameterAt p 30+ , cwWeight1 = parameterAt p 31+ , cwWeight2 = parameterAt p 32+ , cwStabilityPower1 = parameterAt p 33+ , cwStabilityPower2 = parameterAt p 34+ }
+ src/FSRS/Scheduler.hs view
@@ -0,0 +1,317 @@+{-# LANGUAGE DerivingStrategies #-}++-- | A card scheduler built on top of the FSRS-7 memory model.+--+-- The memory model in "FSRS.Algorithm" is fully specified by upstream; the+-- scheduling policy around it is not, so this module follows the widely used+-- reference scheduler from+-- <https://github.com/open-spaced-repetition/py-fsrs py-fsrs>: a card walks+-- through a list of learning steps, graduates into the review queue, and drops+-- into relearning steps when it lapses.+--+-- Two things differ from py-fsrs, both because FSRS-7 is built for continuous+-- intervals where FSRS-6 was built for whole days:+--+-- * Elapsed time is measured in fractional days rather than truncated to whole+-- days, and it is fed to the model directly. There is no same-day special+-- case, because 'FSRS.Algorithm.transitionCoefficient' already is one.+-- * Scheduled intervals are not rounded to whole days. Set+-- 'schedulerMinimumInterval' to @1@ (the default) to keep review-queue+-- intervals at a day or more anyway, or lower it to let FSRS-7 schedule+-- sub-day reviews.+--+-- Fuzzing is explicit rather than ambient: 'reviewCard' is deterministic, and+-- 'reviewCardFuzzed' takes the random sample as an argument, so scheduling+-- stays a pure function of its inputs.+module FSRS.Scheduler+ ( -- * Cards+ CardState (..)+ , Card (..)+ , newCard+ , cardRetrievability++ -- * Scheduler+ , Scheduler (..)+ , defaultScheduler+ , nextReviewInterval++ -- * Reviewing+ , ReviewLog (..)+ , reviewCard+ , reviewCardFuzzed+ , previewIntervals++ -- * Fuzz+ , fuzzRanges+ , fuzzBounds+ , fuzzInterval+ ) where++import Data.Maybe (fromMaybe)+import Data.Time.Clock (NominalDiffTime, UTCTime, addUTCTime, diffUTCTime)++import FSRS.Algorithm+ ( nextIntervalDays+ , nextMemoryState+ , retrievability+ )+import FSRS.Parameters (Parameters, defaultParameters)+import FSRS.Types+ ( Days+ , MemoryState (..)+ , Rating (..)+ , Retrievability+ , Stability+ , allRatings+ )++-- | Where a card sits in the learn \/ review \/ relearn cycle.+data CardState+ = -- | Working through 'schedulerLearningSteps'.+ Learning+ | -- | Graduated; intervals come from the memory model.+ Review+ | -- | Lapsed, working through 'schedulerRelearningSteps'.+ Relearning+ deriving stock (Eq, Ord, Show, Read, Enum, Bounded)++-- | A card's scheduling state.+data Card = Card+ { cardState :: !CardState+ , cardStep :: !(Maybe Int)+ -- ^ Index into the current step list; 'Nothing' in the 'Review' state.+ , cardMemory :: !(Maybe MemoryState)+ -- ^ 'Nothing' until the card has been reviewed once.+ , cardDue :: !UTCTime+ , cardLastReview :: !(Maybe UTCTime)+ }+ deriving stock (Eq, Show)++-- | A card that has never been reviewed, due at the given time.+newCard :: UTCTime -> Card+newCard due =+ Card+ { cardState = Learning+ , cardStep = Just 0+ , cardMemory = Nothing+ , cardDue = due+ , cardLastReview = Nothing+ }++-- | Scheduling policy.+--+-- 'schedulerMinimumInterval' must not exceed 'schedulerMaximumInterval'.+data Scheduler = Scheduler+ { schedulerParameters :: !Parameters+ , schedulerDesiredRetention :: !Retrievability+ -- ^ The recall probability a scheduled review aims for.+ , schedulerLearningSteps :: ![NominalDiffTime]+ , schedulerRelearningSteps :: ![NominalDiffTime]+ , schedulerMinimumInterval :: !Days+ -- ^ Floor for review-queue intervals.+ , schedulerMaximumInterval :: !Days+ -- ^ Ceiling for review-queue intervals.+ }+ deriving stock (Eq, Show)++-- | The FSRS-7 defaults: 90% desired retention, one-minute and ten-minute+-- learning steps, a ten-minute relearning step, and intervals between one day+-- and a century.+defaultScheduler :: Scheduler+defaultScheduler =+ Scheduler+ { schedulerParameters = defaultParameters+ , schedulerDesiredRetention = 0.9+ , schedulerLearningSteps = [minutes 1, minutes 10]+ , schedulerRelearningSteps = [minutes 10]+ , schedulerMinimumInterval = 1+ , schedulerMaximumInterval = 36500+ }+ where+ minutes :: Integer -> NominalDiffTime+ minutes n = fromInteger (n * 60)++-- | The interval a graduated card of the given stability earns, clamped to the+-- scheduler's interval bounds.+nextReviewInterval :: Scheduler -> Stability -> Days+nextReviewInterval sched stability =+ clampTo (schedulerMinimumInterval sched) (schedulerMaximumInterval sched) $+ nextIntervalDays+ (schedulerParameters sched)+ (schedulerDesiredRetention sched)+ stability++-- | What happened in a single review.+data ReviewLog = ReviewLog+ { logRating :: !Rating+ , logReviewTime :: !UTCTime+ , logElapsedDays :: !Days+ -- ^ Days since the previous review; @0@ for a card's first review.+ , logStateBefore :: !CardState+ , logMemoryBefore :: !(Maybe MemoryState)+ , logMemoryAfter :: !MemoryState+ , logInterval :: !NominalDiffTime+ -- ^ The interval that was scheduled, after any fuzz.+ }+ deriving stock (Eq, Show)++-- | Review a card. Deterministic: no fuzz is applied.+reviewCard :: Scheduler -> Card -> Rating -> UTCTime -> (Card, ReviewLog)+reviewCard = reviewCardWith Nothing++-- | Review a card, fuzzing the scheduled interval.+--+-- The first argument is a uniform sample from @[0, 1]@, which the caller draws+-- however it likes; values outside that range are clamped. Fuzz only ever+-- applies to a card that ends up in the 'Review' state with an interval of at+-- least 2.5 days — see 'fuzzInterval'.+reviewCardFuzzed :: Double -> Scheduler -> Card -> Rating -> UTCTime -> (Card, ReviewLog)+reviewCardFuzzed = reviewCardWith . Just++reviewCardWith+ :: Maybe Double -> Scheduler -> Card -> Rating -> UTCTime -> (Card, ReviewLog)+reviewCardWith sample sched card rating now = (card', logEntry)+ where+ elapsed = case cardLastReview card of+ Nothing -> 0+ Just previous -> max 0 (realToFrac (diffUTCTime now previous) / 86400)++ memoryAfter = nextMemoryState (schedulerParameters sched) (cardMemory card) elapsed rating+ (state', step', interval) = schedule sample sched card rating memoryAfter++ card' =+ card+ { cardState = state'+ , cardStep = step'+ , cardMemory = Just memoryAfter+ , cardDue = addUTCTime interval now+ , cardLastReview = Just now+ }++ logEntry =+ ReviewLog+ { logRating = rating+ , logReviewTime = now+ , logElapsedDays = elapsed+ , logStateBefore = cardState card+ , logMemoryBefore = cardMemory card+ , logMemoryAfter = memoryAfter+ , logInterval = interval+ }++-- | The state machine: which state the card moves to, where it lands in the+-- step list, and how long until it is due again.+schedule+ :: Maybe Double+ -> Scheduler+ -> Card+ -> Rating+ -> MemoryState+ -> (CardState, Maybe Int, NominalDiffTime)+schedule sample sched card rating memory = case cardState card of+ Learning -> stepped Learning (schedulerLearningSteps sched)+ Relearning -> stepped Relearning (schedulerRelearningSteps sched)+ Review -> case rating of+ Again -> case schedulerRelearningSteps sched of+ [] -> graduate+ (firstStep : _) -> (Relearning, Just 0, firstStep)+ _ -> graduate+ where+ graduate = (Review, Nothing, daysToDiffTime fuzzed)+ where+ plain = nextReviewInterval sched (memoryStability memory)+ fuzzed = maybe plain (\u -> fuzzInterval sched u plain) sample++ current = max 0 (fromMaybe 0 (cardStep card))++ stepped _ [] = graduate+ stepped state steps@(firstStep : rest)+ -- The card was scheduled by a scheduler with more steps than this one.+ | current >= length steps && rating /= Again = graduate+ | otherwise = case rating of+ Again -> (state, Just 0, firstStep)+ Hard -> (state, Just current, hardInterval)+ Good -> case stepAt (current + 1) of+ Nothing -> graduate+ Just interval -> (state, Just (current + 1), interval)+ Easy -> graduate+ where+ stepAt i = case drop i steps of+ (interval : _) -> Just interval+ [] -> Nothing++ -- Hard repeats the current step. On the very first step there is+ -- nothing to repeat yet, so py-fsrs splits the difference with the+ -- next step, or stretches the only step by half.+ hardInterval = case (current, rest) of+ (0, []) -> firstStep * 1.5+ (0, second : _) -> (firstStep + second) / 2+ -- `current` is in range here: the guard above sent the rest to+ -- `graduate`, so the fallback is unreachable.+ _ -> fromMaybe firstStep (stepAt current)++-- | A card's retrievability at the given time, or 'Nothing' if it has never+-- been reviewed.+cardRetrievability :: Scheduler -> Card -> UTCTime -> Maybe Retrievability+cardRetrievability sched card now = do+ memory <- cardMemory card+ previous <- cardLastReview card+ let elapsed = max 0 (realToFrac (diffUTCTime now previous) / 86400)+ pure (retrievability (schedulerParameters sched) elapsed (memoryStability memory))++-- | The interval each of the four ratings would earn, without reviewing.+-- Handy for showing the four buttons' answers in a UI.+previewIntervals :: Scheduler -> Card -> UTCTime -> [(Rating, NominalDiffTime)]+previewIntervals sched card now =+ [ (rating, logInterval (snd (reviewCard sched card rating now)))+ | rating <- allRatings+ ]++-- ---------------------------------------------------------------------------+-- Fuzz+-- ---------------------------------------------------------------------------++-- | @(start, end, factor)@ triples describing how much an interval may be+-- nudged: every day of the interval that falls inside a range contributes+-- @factor@ days of slack. Taken from py-fsrs.+fuzzRanges :: [(Days, Days, Double)]+fuzzRanges =+ [ (2.5, 7.0, 0.15)+ , (7.0, 20.0, 0.1)+ , (20.0, 1 / 0, 0.05)+ ]++-- | The window an interval may be fuzzed into, or 'Nothing' for intervals+-- shorter than 2.5 days, which are left alone.+fuzzBounds :: Scheduler -> Days -> Maybe (Days, Days)+fuzzBounds sched interval+ | not (interval >= 2.5) = Nothing+ | otherwise = Just (min low high, high)+ where+ delta =+ 1+ + sum+ [ factor * max 0 (min interval end - start)+ | (start, end, factor) <- fuzzRanges+ ]+ low = max 2 (interval - delta)+ high = min (schedulerMaximumInterval sched) (interval + delta)++-- | Nudge an interval by a random amount within 'fuzzBounds'.+--+-- The first argument is a uniform sample from @[0, 1]@; it is clamped, so any+-- finite value is safe. Intervals below 2.5 days are returned unchanged.+fuzzInterval :: Scheduler -> Double -> Days -> Days+fuzzInterval sched sample interval = case fuzzBounds sched interval of+ Nothing -> interval+ Just (low, high) -> low + clampTo 0 1 sample * (high - low)++-- ---------------------------------------------------------------------------+-- Helpers+-- ---------------------------------------------------------------------------++clampTo :: Double -> Double -> Double -> Double+clampTo lo hi x = min hi (max lo x)++daysToDiffTime :: Days -> NominalDiffTime+daysToDiffTime d = realToFrac (d * 86400)
+ src/FSRS/Types.hs view
@@ -0,0 +1,66 @@+{-# LANGUAGE DerivingStrategies #-}++-- | The vocabulary shared by the whole package: the four grades a reviewer can+-- give a card, and the two-variable memory state FSRS tracks for it.+module FSRS.Types+ ( -- * Ratings+ Rating (..)+ , allRatings+ , ratingToInt+ , ratingFromInt++ -- * Memory state+ , MemoryState (..)++ -- * Type synonyms+ , Stability+ , Difficulty+ , Retrievability+ , Days+ ) where++-- | How well the card was recalled. The 'Enum' instance counts from @0@; the+-- FSRS papers and reference implementations number the ratings from @1@, which+-- is what 'ratingToInt' gives you.+data Rating+ = Again+ | Hard+ | Good+ | Easy+ deriving stock (Eq, Ord, Show, Read, Enum, Bounded)++-- | Every rating, from 'Again' to 'Easy'.+allRatings :: [Rating]+allRatings = [minBound .. maxBound]++-- | The rating as FSRS numbers it: @1@ for 'Again' through @4@ for 'Easy'.+ratingToInt :: Rating -> Int+ratingToInt r = fromEnum r + 1++-- | Inverse of 'ratingToInt'. 'Nothing' outside @1..4@.+ratingFromInt :: Int -> Maybe Rating+ratingFromInt n+ | n >= 1 && n <= 4 = Just (toEnum (n - 1))+ | otherwise = Nothing++-- | Memory half-life in days: the larger it is, the slower the card is+-- forgotten. In FSRS-7 stability is a genuine continuous quantity — sub-day+-- values are meaningful and are what the model uses for same-day reviews.+type Stability = Double++-- | How hard the card is for this reviewer, on a @[1, 10]@ scale.+type Difficulty = Double++-- | Probability of recall, in @(0, 1]@.+type Retrievability = Double++-- | A duration in days. Fractional values are meaningful throughout FSRS-7:+-- ten minutes is @10 / 1440@.+type Days = Double++-- | Everything FSRS remembers about a card.+data MemoryState = MemoryState+ { memoryStability :: !Stability+ , memoryDifficulty :: !Difficulty+ }+ deriving stock (Eq, Ord, Show, Read)
+ test/Spec.hs view
@@ -0,0 +1,20 @@+-- | The test suite entry point.+module Main (main) where++import Test.Tasty (defaultMain, testGroup)++import qualified Test.FSRS.Golden as Golden+import qualified Test.FSRS.Properties as Properties+import qualified Test.FSRS.SchedulerSpec as SchedulerSpec+import qualified Test.FSRS.Unit as Unit++main :: IO ()+main =+ defaultMain $+ testGroup+ "haskell-fsrs"+ [ Unit.tests+ , Golden.tests+ , Properties.tests+ , SchedulerSpec.tests+ ]
+ test/Test/FSRS/Gen.hs view
@@ -0,0 +1,139 @@+-- | Generators and comparison helpers shared by the test modules.+--+-- Everything here produces /valid/ inputs: parameter vectors inside the box+-- the upstream optimiser clips to, stabilities inside+-- @['stabilityMin', 'stabilityMax']@, difficulties inside @[1, 10]@ and+-- non-negative elapsed times. Properties that should hold for nonsense inputs+-- too say so explicitly.+module Test.FSRS.Gen+ ( -- * Generators+ genParameters+ , genRating+ , genStability+ , genDifficulty+ , genMemoryState+ , genElapsedDays+ , genDesiredRetention+ , genReviewHistory+ , genUTCTime+ , genScheduler++ -- * Approximate comparison+ , approxEqual+ , relativeError+ ) where++import Data.Time.Calendar (addDays, fromGregorian)+import Data.Time.Clock (UTCTime (..), secondsToDiffTime)+import Test.QuickCheck++import FSRS++-- | A parameter vector inside the valid box, biased towards the defaults.+genParameters :: Gen Parameters+genParameters =+ frequency+ [ (1, pure defaultParameters)+ , (3, genRandomParameters)+ ]++genRandomParameters :: Gen Parameters+genRandomParameters = do+ ws <- traverse choose parameterBounds+ -- `clampParameters` only re-establishes the three ordering constraints; the+ -- weights are already inside their individual bounds.+ case clampParameters ws of+ Right p -> pure p+ Left errs -> error ("genRandomParameters: " <> show errs)++genRating :: Gen Rating+genRating = elements allRatings++-- | Log-uniform across the whole legal range, with the endpoints thrown in.+genStability :: Gen Stability+genStability =+ frequency+ [ (1, pure stabilityMin)+ , (1, pure stabilityMax)+ , (1, pure 1)+ , (9, exp <$> choose (log stabilityMin, log stabilityMax))+ ]++genDifficulty :: Gen Difficulty+genDifficulty =+ frequency+ [ (1, pure difficultyMin)+ , (1, pure difficultyMax)+ , (8, choose (difficultyMin, difficultyMax))+ ]++genMemoryState :: Gen MemoryState+genMemoryState = MemoryState <$> genStability <*> genDifficulty++-- | Anything from "the same instant" to ten years, log-uniform in between.+genElapsedDays :: Gen Days+genElapsedDays =+ frequency+ [ (2, pure 0)+ , (8, exp <$> choose (log (1 / 86400), log 3650))+ ]++genDesiredRetention :: Gen Retrievability+genDesiredRetention =+ frequency+ [ (1, choose (0.5, 0.7))+ , (8, choose (0.7, 0.98))+ , (1, choose (0.98, 0.999))+ ]++genReviewHistory :: Gen [(Days, Rating)]+genReviewHistory = sized $ \n -> do+ k <- choose (0, min n 30)+ vectorOf k ((,) <$> genElapsedDays <*> genRating)++genUTCTime :: Gen UTCTime+genUTCTime = do+ day <- choose (0, 3650)+ seconds <- choose (0, 86399)+ pure (UTCTime (addDays day (fromGregorian 2026 1 1)) (secondsToDiffTime seconds))++genScheduler :: Gen Scheduler+genScheduler = do+ params <- genParameters+ retention <- genDesiredRetention+ learning <- genSteps+ relearning <- genSteps+ maxIvl <- choose (1, 36500)+ minIvl <- choose (1 / 86400, maxIvl)+ pure+ Scheduler+ { schedulerParameters = params+ , schedulerDesiredRetention = retention+ , schedulerLearningSteps = learning+ , schedulerRelearningSteps = relearning+ , schedulerMinimumInterval = minIvl+ , schedulerMaximumInterval = maxIvl+ }+ where+ genSteps = do+ k <- choose (0 :: Int, 4)+ vectorOf k (fromInteger <$> choose (60, 86400))++-- | @abs (a - b) <= atol + rtol * abs b@.+approxEqual+ :: Double+ -- ^ Absolute tolerance.+ -> Double+ -- ^ Relative tolerance.+ -> Double+ -- ^ Actual.+ -> Double+ -- ^ Expected.+ -> Bool+approxEqual atol rtol actual expected =+ abs (actual - expected) <= atol + rtol * abs expected++relativeError :: Double -> Double -> Double+relativeError actual expected+ | expected == 0 = abs actual+ | otherwise = abs (actual - expected) / abs expected
+ test/Test/FSRS/Golden.hs view
@@ -0,0 +1,133 @@+-- | Every function of the model, checked against vectors produced by the+-- pure-Python transcription of the upstream reference implementation.+--+-- The two implementations perform the same floating-point operations in the+-- same order on the same libm, so agreement is expected to the last few bits;+-- the tolerances below are deliberately much tighter than "close enough".+module Test.FSRS.Golden (tests) where++import Control.Monad (unless)+import Test.Tasty (TestTree, testGroup)+import Test.Tasty.HUnit (Assertion, assertFailure, testCase, (@?=))++import FSRS+import Test.FSRS.Gen (approxEqual, relativeError)+import Test.FSRS.GoldenData++-- | Tolerance for everything but the root-finder: bit-for-bit agreement with a+-- little slack for the last ulp.+tol :: Double+tol = 1.0e-12++-- | The interval solver converges by a different route than the Python+-- bisection used to produce the vectors, so it only agrees to about a+-- nanosecond in relative terms.+intervalTol :: Double+intervalTol = 1.0e-9++tests :: TestTree+tests =+ testGroup+ "golden vectors"+ [ testCase "the golden parameter sets are all valid" $+ mapM_+ (\ws -> validateParameters ws @?= [])+ goldenParameterSets+ , testCase "the first golden parameter set is the default one" $+ take 1 goldenParameterSets @?= [parametersToList defaultParameters]+ , labelled "forgetting curve" goldenCurveVectors checkCurve+ , labelled "difficulty" goldenDifficultyVectors checkDifficulty+ , labelled "stability blocks" goldenHalfStabilityVectors checkHalfStability+ , labelled "transition function" goldenTransitionVectors checkTransition+ , labelled "memory-state transition" goldenStepVectors checkStep+ , labelled "interval inversion" goldenIntervalVectors checkInterval+ , labelled "replayed review histories" goldenReplayVectors checkReplay+ ]++labelled :: String -> [a] -> (a -> Assertion) -> TestTree+labelled name vectors check =+ testCase (name <> " (" <> show (length vectors) <> " vectors)") $+ mapM_ check vectors++paramsAt :: Int -> Parameters+paramsAt i = case mkParameters (goldenParameterSets !! i) of+ Right p -> p+ Left errs -> error ("golden parameter set " <> show i <> " is invalid: " <> show errs)++ratingAt :: Int -> Rating+ratingAt n = case ratingFromInt n of+ Just r -> r+ Nothing -> error ("golden vector has a bad rating: " <> show n)++close :: Double -> String -> Double -> Double -> Assertion+close t label expected actual =+ unless (approxEqual t t actual expected) $+ assertFailure $+ label+ <> "\n expected: "+ <> show expected+ <> "\n actual: "+ <> show actual+ <> "\n relative error: "+ <> show (relativeError actual expected)++checkCurve :: CurveVector -> Assertion+checkCurve v =+ close tol (show v) (cvRetrievability v) $+ retrievability (paramsAt (cvParams v)) (cvElapsedDays v) (cvStability v)++checkDifficulty :: DifficultyVector -> Assertion+checkDifficulty v =+ close tol (show v) (dvNextDifficulty v) $+ case dvDifficulty v of+ Nothing -> initialDifficulty params rating+ Just d -> nextDifficulty params d rating+ where+ params = paramsAt (dvParams v)+ rating = ratingAt (dvRating v)++checkHalfStability :: HalfStabilityVector -> Assertion+checkHalfStability v =+ close tol (show v) (hsNextStability v) $+ stabilityAfterReview+ block+ (MemoryState (hsStability v) (hsDifficulty v))+ (hsRetrievability v)+ (ratingAt (hsRating v))+ where+ params = paramsAt (hsParams v)+ block = (if hsLongTerm v then longTermWeights else shortTermWeights) params++checkTransition :: TransitionVector -> Assertion+checkTransition v =+ close tol (show v) (tvCoefficient v) $+ transitionCoefficient (paramsAt (tvParams v)) (tvElapsedDays v)++checkStep :: StepVector -> Assertion+checkStep v = do+ close tol (show v <> " [stability]") expectedS (memoryStability actual)+ close tol (show v <> " [difficulty]") expectedD (memoryDifficulty actual)+ where+ (expectedS, expectedD) = svNextState v+ actual =+ nextMemoryState+ (paramsAt (svParams v))+ (uncurry MemoryState <$> svState v)+ (svElapsedDays v)+ (ratingAt (svRating v))++checkInterval :: IntervalVector -> Assertion+checkInterval v =+ close intervalTol (show v) (ivInterval v) $+ nextIntervalDays (paramsAt (ivParams v)) (ivDesiredRetention v) (ivStability v)++checkReplay :: ReplayVector -> Assertion+checkReplay v = case replayReviews params reviews of+ Nothing -> assertFailure (show v <> ": replayReviews returned Nothing")+ Just actual -> do+ close tol (show v <> " [stability]") expectedS (memoryStability actual)+ close tol (show v <> " [difficulty]") expectedD (memoryDifficulty actual)+ where+ params = paramsAt (rvParams v)+ reviews = [(dt, ratingAt g) | (dt, g) <- rvReviews v]+ (expectedS, expectedD) = rvFinalState v
+ test/Test/FSRS/GoldenData.hs view
@@ -0,0 +1,2723 @@+{-# LANGUAGE DerivingStrategies #-}++-- This module is nothing but a few thousand literals; optimising it+-- costs compile time and buys nothing.+{-# OPTIONS_GHC -O0 #-}++-- | Golden vectors for the FSRS-7 implementation.+--+-- Generated by @reference\/gen_golden.py@ from the pure-Python+-- transcription of the official benchmark model. Do not edit by hand;+-- regenerate with @python3 reference\/gen_golden.py@.+module Test.FSRS.GoldenData+ ( goldenParameterSets+ , CurveVector (..)+ , goldenCurveVectors+ , DifficultyVector (..)+ , goldenDifficultyVectors+ , HalfStabilityVector (..)+ , goldenHalfStabilityVectors+ , TransitionVector (..)+ , goldenTransitionVectors+ , StepVector (..)+ , goldenStepVectors+ , IntervalVector (..)+ , goldenIntervalVectors+ , ReplayVector (..)+ , goldenReplayVectors+ ) where++-- | The parameter sets the vectors below refer to by index.+-- Index 0 is the FSRS-7 default parameter set.+goldenParameterSets :: [[Double]]+goldenParameterSets =+ [ [0.041, 2.4175, 4.1283, 11.9709, 5.6385, 0.4468, 3.262, 2.3054, 0.1688, 1.3325, 0.3524, 0.0049, 0.7503, 0.0896, 0.6625, 1.3, 0.882, 0.3072, 3.5875, 0.303, 0.0107, 0.2279, 2.6413, 0.5594, 1.3, 2.5, 1.0, 0.0723, 0.1634, 0.5, 0.9555, 0.2245, 0.6232, 0.1362, 0.3862]+ , [21.160516, 50.940793, 64.835975, 64.835975, 8.15903, 2.002545, 2.260348, 0.261677, 1.007671, 0.835788, 1.121191, 0.482646, 0.805315, 1.109673, 0.243581, 5.499531, 1.698145, 1.144289, 3.924479, 0.305639, 1.731898, 0.979642, 2.748763, 0.621608, 3.323164, 12.353494, 0.589693, 0.023181, 0.916871, 0.810769, 0.810769, 0.643876, 0.388689, 0.492485, 0.639409]+ , [2.462798, 11.949056, 79.640406, 79.640406, 7.614116, 1.181111, 0.390871, 2.724834, 0.753779, 2.243577, 0.730412, 0.835923, 0.322241, 1.039029, 0.595056, 6.951994, 3.326003, 0.777298, 2.338648, 0.894925, 0.32714, 0.712525, 3.444161, 0.965072, 6.509826, 5.536095, 0.438431, 0.018217, 0.26739, 0.581093, 0.581093, 0.397612, 0.469117, 0.180743, 0.357585]+ ]++-- | @R(t, s)@, the probability of recall.+data CurveVector = CurveVector+ { cvParams :: !Int+ , cvElapsedDays :: !Double+ , cvStability :: !Double+ , cvRetrievability :: !Double+ }+ deriving stock (Eq, Show)++goldenCurveVectors :: [CurveVector]+goldenCurveVectors =+ [ CurveVector 0 0.0 0.0001 1.0+ , CurveVector 0 0.0 0.01 1.0+ , CurveVector 0 0.0 0.5 1.0+ , CurveVector 0 0.0 1.0 1.0+ , CurveVector 0 0.0 4.1283 1.0+ , CurveVector 0 0.0 15.0 1.0+ , CurveVector 0 0.0 100.0 1.0+ , CurveVector 0 0.0 1000.0 1.0+ , CurveVector 0 0.0 36500.0 1.0+ , CurveVector 0 1.1574074074074073e-5 0.0001 0.5933860064644932+ , CurveVector 0 1.1574074074074073e-5 0.01 0.8495113580744659+ , CurveVector 0 1.1574074074074073e-5 0.5 0.9929070497623003+ , CurveVector 0 1.1574074074074073e-5 1.0 0.9970315864605649+ , CurveVector 0 1.1574074074074073e-5 4.1283 0.9995760691373587+ , CurveVector 0 1.1574074074074073e-5 15.0 0.9999349085685156+ , CurveVector 0 1.1574074074074073e-5 100.0 0.9999961594473195+ , CurveVector 0 1.1574074074074073e-5 1000.0 0.9999998815426243+ , CurveVector 0 1.1574074074074073e-5 36500.0 0.9999999994861863+ , CurveVector 0 0.0006944444444444445 0.0001 0.4432668218647261+ , CurveVector 0 0.0006944444444444445 0.01 0.6844202927268608+ , CurveVector 0 0.0006944444444444445 0.5 0.9323536480673809+ , CurveVector 0 0.0006944444444444445 1.0 0.9576427479174111+ , CurveVector 0 0.0006944444444444445 4.1283 0.9874342644794948+ , CurveVector 0 0.0006944444444444445 15.0 0.9970520789455777+ , CurveVector 0 0.0006944444444444445 100.0 0.999781044413337+ , CurveVector 0 0.0006944444444444445 1000.0 0.9999929300276222+ , CurveVector 0 0.0006944444444444445 36500.0 0.9999999691755385+ , CurveVector 0 0.006944444444444444 0.0001 0.3730533620906363+ , CurveVector 0 0.006944444444444444 0.01 0.6043230466193572+ , CurveVector 0 0.006944444444444444 0.5 0.8907215861983732+ , CurveVector 0 0.006944444444444444 1.0 0.9244321330914924+ , CurveVector 0 0.006944444444444444 4.1283 0.9693189917294772+ , CurveVector 0 0.006944444444444444 15.0 0.9889027240570584+ , CurveVector 0 0.006944444444444444 100.0 0.9984451422665508+ , CurveVector 0 0.006944444444444444 1000.0 0.9999325077444561+ , CurveVector 0 0.006944444444444444 36500.0 0.9999996921537052+ , CurveVector 0 0.25 0.0001 0.2851191592785943+ , CurveVector 0 0.25 0.01 0.456616482214346+ , CurveVector 0 0.25 0.5 0.8224198592478944+ , CurveVector 0 0.25 1.0 0.8723190093653708+ , CurveVector 0 0.25 4.1283 0.9404929608601553+ , CurveVector 0 0.25 15.0 0.9728008245439088+ , CurveVector 0 0.25 100.0 0.9926213962042669+ , CurveVector 0 0.25 1000.0 0.9989715171159107+ , CurveVector 0 0.25 36500.0 0.9999894395613305+ , CurveVector 0 1.0 0.0001 0.25713379769027217+ , CurveVector 0 1.0 0.01 0.39965839215670973+ , CurveVector 0 1.0 0.5 0.7698463681144272+ , CurveVector 0 1.0 1.0 0.8348679957532145+ , CurveVector 0 1.0 4.1283 0.9242342483541028+ , CurveVector 0 1.0 15.0 0.965276266166443+ , CurveVector 0 1.0 100.0 0.9899633108373221+ , CurveVector 0 1.0 1000.0 0.9982079823122783+ , CurveVector 0 1.0 36500.0 0.9999628548326086+ , CurveVector 0 3.0 0.0001 0.2369807334603691+ , CurveVector 0 3.0 0.01 0.3595136620236083+ , CurveVector 0 3.0 0.5 0.7027042985360686+ , CurveVector 0 3.0 1.0 0.7807132698581536+ , CurveVector 0 3.0 4.1283 0.8996583671005782+ , CurveVector 0 3.0 15.0 0.9554107397126494+ , CurveVector 0 3.0 100.0 0.9872853400435361+ , CurveVector 0 3.0 1000.0 0.9975222007805449+ , CurveVector 0 3.0 36500.0 0.9999133375629187+ , CurveVector 0 7.5 0.0001 0.22142030501492593+ , CurveVector 0 7.5 0.01 0.3294480191014634+ , CurveVector 0 7.5 0.5 0.6343961597998443+ , CurveVector 0 7.5 1.0 0.7161183991831989+ , CurveVector 0 7.5 4.1283 0.8618548545083785+ , CurveVector 0 7.5 15.0 0.9397110393641435+ , CurveVector 0 7.5 100.0 0.9837439115086568+ , CurveVector 0 7.5 1000.0 0.9968247800782952+ , CurveVector 0 7.5 36500.0 0.9998474481935904+ , CurveVector 0 30.0 0.0001 0.19984766152161007+ , CurveVector 0 30.0 0.01 0.28929613460097364+ , CurveVector 0 30.0 0.5 0.5298364300580066+ , CurveVector 0 30.0 1.0 0.6031223500178141+ , CurveVector 0 30.0 4.1283 0.7644685415426927+ , CurveVector 0 30.0 15.0 0.886172361687806+ , CurveVector 0 30.0 100.0 0.971243149616753+ , CurveVector 0 30.0 1000.0 0.9950103052406525+ , CurveVector 0 30.0 36500.0 0.9997052031663322+ , CurveVector 0 365.0 0.0001 0.16624187657470219+ , CurveVector 0 365.0 0.01 0.2304175269361819+ , CurveVector 0 365.0 0.5 0.37581378678844907+ , CurveVector 0 365.0 1.0 0.42347782141604523+ , CurveVector 0 365.0 4.1283 0.5441682159716109+ , CurveVector 0 365.0 15.0 0.6762521980608913+ , CurveVector 0 365.0 100.0 0.867529117768457+ , CurveVector 0 365.0 1000.0 0.9777522230298146+ , CurveVector 0 365.0 36500.0 0.9990262613080615+ , CurveVector 0 3650.0 0.0001 0.1403867606436746+ , CurveVector 0 3650.0 0.01 0.18814188666158319+ , CurveVector 0 3650.0 0.5 0.2750460193341646+ , CurveVector 0 3650.0 1.0 0.3048269100949967+ , CurveVector 0 3650.0 4.1283 0.3837451992278071+ , CurveVector 0 3650.0 15.0 0.47717234376306134+ , CurveVector 0 3650.0 100.0 0.6512878215764997+ , CurveVector 0 3650.0 1000.0 0.8768098115543785+ , CurveVector 0 3650.0 36500.0 0.9942449441927469+ , CurveVector 1 0.0 0.0001 1.0+ , CurveVector 1 0.0 0.01 1.0+ , CurveVector 1 0.0 0.5 1.0+ , CurveVector 1 0.0 1.0 1.0+ , CurveVector 1 0.0 4.1283 1.0+ , CurveVector 1 0.0 15.0 1.0+ , CurveVector 1 0.0 100.0 1.0+ , CurveVector 1 0.0 1000.0 1.0+ , CurveVector 1 0.0 36500.0 1.0+ , CurveVector 1 1.1574074074074073e-5 0.0001 0.8523118660514808+ , CurveVector 1 1.1574074074074073e-5 0.01 0.9464045240335968+ , CurveVector 1 1.1574074074074073e-5 0.5 0.9967370567403695+ , CurveVector 1 1.1574074074074073e-5 1.0 0.9986422759813346+ , CurveVector 1 1.1574074074074073e-5 4.1283 0.9998630293353797+ , CurveVector 1 1.1574074074074073e-5 15.0 0.9999889480490822+ , CurveVector 1 1.1574074074074073e-5 100.0 0.9999997688242355+ , CurveVector 1 1.1574074074074073e-5 1000.0 0.9999999957537147+ , CurveVector 1 1.1574074074074073e-5 36500.0 0.9999999999245476+ , CurveVector 1 0.0006944444444444445 0.0001 0.7751473949811729+ , CurveVector 1 0.0006944444444444445 0.01 0.8628468758887021+ , CurveVector 1 0.0006944444444444445 0.5 0.9549077686473312+ , CurveVector 1 0.0006944444444444445 1.0 0.9726123591278394+ , CurveVector 1 0.0006944444444444445 4.1283 0.994878960710534+ , CurveVector 1 0.0006944444444444445 15.0 0.9994396296146354+ , CurveVector 1 0.0006944444444444445 100.0 0.9999864797130398+ , CurveVector 1 0.0006944444444444445 1000.0 0.9999997454930079+ , CurveVector 1 0.0006944444444444445 36500.0 0.9999999954728627+ , CurveVector 1 0.006944444444444444 0.0001 0.7348526048890944+ , CurveVector 1 0.006944444444444444 0.01 0.8177897420073064+ , CurveVector 1 0.006944444444444444 0.5 0.9170456452923051+ , CurveVector 1 0.006944444444444444 1.0 0.9428992518963294+ , CurveVector 1 0.006944444444444444 4.1283 0.9843947461781376+ , CurveVector 1 0.006944444444444444 15.0 0.997291246557506+ , CurveVector 1 0.006944444444444444 100.0 0.9998880108746181+ , CurveVector 1 0.006944444444444444 1000.0 0.9999974787127267+ , CurveVector 1 0.006944444444444444 36500.0 0.9999999547289472+ , CurveVector 1 0.25 0.0001 0.6762743567768189+ , CurveVector 1 0.25 0.01 0.7505308522242855+ , CurveVector 1 0.25 0.5 0.8392665173234493+ , CurveVector 1 0.25 1.0 0.8776118456992493+ , CurveVector 1 0.25 4.1283 0.9557830490326991+ , CurveVector 1 0.25 15.0 0.9885751564319429+ , CurveVector 1 0.25 100.0 0.9987955076727638+ , CurveVector 1 0.25 1000.0 0.9999237504867172+ , CurveVector 1 0.25 36500.0 0.9999983706724714+ , CurveVector 1 1.0 0.0001 0.6548872661921853+ , CurveVector 1 1.0 0.01 0.7264518681527963+ , CurveVector 1 1.0 0.5 0.7731740600264984+ , CurveVector 1 1.0 1.0 0.810769+ , CurveVector 1 1.0 4.1283 0.9190823327933287+ , CurveVector 1 1.0 15.0 0.975841522705037+ , CurveVector 1 1.0 100.0 0.9967920795404497+ , CurveVector 1 1.0 1000.0 0.999730641866046+ , CurveVector 1 1.0 36500.0 0.9999934873029269+ , CurveVector 1 3.0 0.0001 0.6384198660053784+ , CurveVector 1 3.0 0.01 0.708088035759968+ , CurveVector 1 3.0 0.5 0.701602618114653+ , CurveVector 1 3.0 1.0 0.715726404952451+ , CurveVector 1 3.0 4.1283 0.8452125848714827+ , CurveVector 1 3.0 15.0 0.9469306801277422+ , CurveVector 1 3.0 100.0 0.9919643351359503+ , CurveVector 1 3.0 1000.0 0.9992451543075624+ , CurveVector 1 3.0 36500.0 0.9999804885340793+ , CurveVector 1 7.5 0.0001 0.6250024841695064+ , CurveVector 1 7.5 0.01 0.6931736699730552+ , CurveVector 1 7.5 0.5 0.6477065571889125+ , CurveVector 1 7.5 1.0 0.6230688725366799+ , CurveVector 1 7.5 4.1283 0.7276607711422548+ , CurveVector 1 7.5 15.0 0.8899496169066309+ , CurveVector 1 7.5 100.0 0.9815538224427173+ , CurveVector 1 7.5 1000.0 0.9981752619340438+ , CurveVector 1 7.5 36500.0 0.9999513066062199+ , CurveVector 1 30.0 0.0001 0.6052368883847312+ , CurveVector 1 30.0 0.01 0.671234178061259+ , CurveVector 1 30.0 0.5 0.5947036849457923+ , CurveVector 1 30.0 1.0 0.5189670702148328+ , CurveVector 1 30.0 4.1283 0.47889902062470296+ , CurveVector 1 30.0 15.0 0.6917999200125268+ , CurveVector 1 30.0 100.0 0.9332515717445918+ , CurveVector 1 30.0 1000.0 0.9929049778715002+ , CurveVector 1 30.0 36500.0 0.9998057738948768+ , CurveVector 1 365.0 0.0001 0.5711760994954371+ , CurveVector 1 365.0 0.01 0.6334530598009184+ , CurveVector 1 365.0 0.5 0.5473455073533272+ , CurveVector 1 365.0 1.0 0.4467423870943384+ , CurveVector 1 365.0 4.1283 0.2236204733666933+ , CurveVector 1 365.0 15.0 0.20485637040312182+ , CurveVector 1 365.0 100.0 0.5472460692590585+ , CurveVector 1 365.0 1000.0 0.9209964297111749+ , CurveVector 1 365.0 36500.0 0.9976476169878027+ , CurveVector 1 3650.0 0.0001 0.5414882365587022+ , CurveVector 1 3650.0 0.01 0.600527626709789+ , CurveVector 1 3650.0 0.5 0.5174338916915161+ , CurveVector 1 3650.0 1.0 0.4187361900293764+ , CurveVector 1 3650.0 4.1283 0.17815726304772947+ , CurveVector 1 3650.0 15.0 0.07182364534647995+ , CurveVector 1 3650.0 100.0 0.12261437863592996+ , CurveVector 1 3650.0 1000.0 0.5452451752481946+ , CurveVector 1 3650.0 36500.0 0.9769943425928189+ , CurveVector 2 0.0 0.0001 1.0+ , CurveVector 2 0.0 0.01 1.0+ , CurveVector 2 0.0 0.5 1.0+ , CurveVector 2 0.0 1.0 1.0+ , CurveVector 2 0.0 4.1283 1.0+ , CurveVector 2 0.0 15.0 1.0+ , CurveVector 2 0.0 100.0 1.0+ , CurveVector 2 0.0 1000.0 1.0+ , CurveVector 2 0.0 36500.0 1.0+ , CurveVector 2 1.1574074074074073e-5 0.0001 0.606467529772504+ , CurveVector 2 1.1574074074074073e-5 0.01 0.6879249664472816+ , CurveVector 2 1.1574074074074073e-5 0.5 0.8376629751583106+ , CurveVector 2 1.1574074074074073e-5 1.0 0.8691455215882177+ , CurveVector 2 1.1574074074074073e-5 4.1283 0.9245200592994596+ , CurveVector 2 1.1574074074074073e-5 15.0 0.9589607675714509+ , CurveVector 2 1.1574074074074073e-5 100.0 0.9852302440781773+ , CurveVector 2 1.1574074074074073e-5 1000.0 0.9961835844156868+ , CurveVector 2 1.1574074074074073e-5 36500.0 0.9996023459553239+ , CurveVector 2 0.0006944444444444445 0.0001 0.5592622855394497+ , CurveVector 2 0.0006944444444444445 0.01 0.6364681643081666+ , CurveVector 2 0.0006944444444444445 0.5 0.8085965033237014+ , CurveVector 2 0.0006944444444444445 1.0 0.8449260419015837+ , CurveVector 2 0.0006944444444444445 4.1283 0.9093808945594827+ , CurveVector 2 0.0006944444444444445 15.0 0.9500009198888169+ , CurveVector 2 0.0006944444444444445 100.0 0.9815131069373282+ , CurveVector 2 0.0006944444444444445 1000.0 0.9950082011084547+ , CurveVector 2 0.0006944444444444445 36500.0 0.9994183653980044+ , CurveVector 2 0.006944444444444444 0.0001 0.5350670232767891+ , CurveVector 2 0.006944444444444444 0.01 0.589113601405182+ , CurveVector 2 0.006944444444444444 0.5 0.7844310926509394+ , CurveVector 2 0.006944444444444444 1.0 0.8266256162029996+ , CurveVector 2 0.006944444444444444 4.1283 0.8995564546163054+ , CurveVector 2 0.006944444444444444 15.0 0.9446694150577564+ , CurveVector 2 0.006944444444444444 100.0 0.9794440853923929+ , CurveVector 2 0.006944444444444444 1000.0 0.9943744941210607+ , CurveVector 2 0.006944444444444444 36500.0 0.9993204768981533+ , CurveVector 2 0.25 0.0001 0.5003708631019913+ , CurveVector 2 0.25 0.01 0.5216072380488823+ , CurveVector 2 0.25 0.5 0.6280324448150036+ , CurveVector 2 0.25 1.0 0.6903199684153861+ , CurveVector 2 0.25 4.1283 0.8282411098226722+ , CurveVector 2 0.25 15.0 0.915358354463665+ , CurveVector 2 0.25 100.0 0.9725726133113185+ , CurveVector 2 0.25 1000.0 0.9930348052824383+ , CurveVector 2 0.25 36500.0 0.9991647717317014+ , CurveVector 2 1.0 0.0001 0.4877182960236155+ , CurveVector 2 1.0 0.01 0.5020895922583641+ , CurveVector 2 1.0 0.5 0.5369692356076303+ , CurveVector 2 1.0 1.0 0.5810929999999999+ , CurveVector 2 1.0 4.1283 0.7239189779069897+ , CurveVector 2 1.0 15.0 0.8580842903071186+ , CurveVector 2 1.0 100.0 0.9597307808999423+ , CurveVector 2 1.0 1000.0 0.991401983249404+ , CurveVector 2 1.0 36500.0 0.9990753188455495+ , CurveVector 2 3.0 0.0001 0.47795520962718263+ , CurveVector 2 3.0 0.01 0.48842523115540376+ , CurveVector 2 3.0 0.5 0.4767232073536098+ , CurveVector 2 3.0 1.0 0.5015673153236732+ , CurveVector 2 3.0 4.1283 0.6133617183123362+ , CurveVector 2 3.0 15.0 0.7652883605652564+ , CurveVector 2 3.0 100.0 0.9306360628988384+ , CurveVector 2 3.0 1000.0 0.9877295789699271+ , CurveVector 2 3.0 36500.0 0.9989374948726737+ , CurveVector 2 7.5 0.0001 0.4699801195648465+ , CurveVector 2 7.5 0.01 0.47796923981833955+ , CurveVector 2 7.5 0.5 0.4359460557309245+ , CurveVector 2 7.5 1.0 0.44650478450469305+ , CurveVector 2 7.5 4.1283 0.5236779738387979+ , CurveVector 2 7.5 15.0 0.6621824742906998+ , CurveVector 2 7.5 100.0 0.8787205126459078+ , CurveVector 2 7.5 1000.0 0.9800441454347029+ , CurveVector 2 7.5 36500.0 0.9986865595421579+ , CurveVector 2 30.0 0.0001 0.4581895710614185+ , CurveVector 2 30.0 0.01 0.46341631653021614+ , CurveVector 2 30.0 0.5 0.3880162263777013+ , CurveVector 2 30.0 1.0 0.3819137459401326+ , CurveVector 2 30.0 4.1283 0.4118207123301889+ , CurveVector 2 30.0 15.0 0.5051701223166598+ , CurveVector 2 30.0 100.0 0.7363682560284641+ , CurveVector 2 30.0 1000.0 0.9460279362095325+ , CurveVector 2 30.0 36500.0 0.9975540277157354+ , CurveVector 2 365.0 0.0001 0.43772550284476164+ , CurveVector 2 365.0 0.01 0.43996830916988416+ , CurveVector 2 365.0 0.5 0.3307292574698105+ , CurveVector 2 365.0 1.0 0.3068347504530301+ , CurveVector 2 365.0 4.1283 0.2820726268682856+ , CurveVector 2 365.0 15.0 0.30463737786259887+ , CurveVector 2 365.0 100.0 0.43185104483801695+ , CurveVector 2 365.0 1000.0 0.7175121426626243+ , CurveVector 2 365.0 36500.0 0.9819794894033199+ , CurveVector 2 3650.0 0.0001 0.4197078090483988+ , CurveVector 2 3650.0 0.01 0.42052494087116143+ , CurveVector 2 3650.0 0.5 0.29772170181139634+ , CurveVector 2 3650.0 1.0 0.266007008010134+ , CurveVector 2 3650.0 4.1283 0.21591765051843548+ , CurveVector 2 3650.0 15.0 0.20257783586795206+ , CurveVector 2 3650.0 100.0 0.25116200187670906+ , CurveVector 2 3650.0 1000.0 0.4251397867408951+ , CurveVector 2 3650.0 36500.0 0.8722585713639893+ ]++-- | Initial and subsequent difficulty.+data DifficultyVector = DifficultyVector+ { dvParams :: !Int+ , dvDifficulty :: !(Maybe Double)+ -- ^ 'Nothing' for the initial difficulty of a brand-new card.+ , dvRating :: !Int+ , dvNextDifficulty :: !Double+ }+ deriving stock (Eq, Show)++goldenDifficultyVectors :: [DifficultyVector]+goldenDifficultyVectors =+ [ DifficultyVector 0 Nothing 1 5.6385+ , DifficultyVector 0 Nothing 2 5.075198392303237+ , DifficultyVector 0 Nothing 3 4.194588083372719+ , DifficultyVector 0 Nothing 4 2.817928571667297+ , DifficultyVector 0 (Just 1.0) 1 7.476939285716673+ , DifficultyVector 0 (Just 1.0) 2 4.247559285716673+ , DifficultyVector 0 (Just 1.0) 3 1.018179285716673+ , DifficultyVector 0 (Just 1.0) 4 1.0+ , DifficultyVector 0 (Just 2.5) 1 7.885479285716673+ , DifficultyVector 0 (Just 2.5) 2 5.194329285716673+ , DifficultyVector 0 (Just 2.5) 3 2.5031792857166733+ , DifficultyVector 0 (Just 2.5) 4 1.0+ , DifficultyVector 0 (Just 4.194588083372719) 1 8.347017296104067+ , DifficultyVector 0 (Just 4.194588083372719) 2 6.263919392179866+ , DifficultyVector 0 (Just 4.194588083372719) 3 4.180821488255665+ , DifficultyVector 0 (Just 4.194588083372719) 4 2.097723584331464+ , DifficultyVector 0 (Just 7.0) 1 9.111099285716673+ , DifficultyVector 0 (Just 7.0) 2 8.034639285716674+ , DifficultyVector 0 (Just 7.0) 3 6.958179285716673+ , DifficultyVector 0 (Just 7.0) 4 5.881719285716673+ , DifficultyVector 0 (Just 10.0) 1 9.928179285716674+ , DifficultyVector 0 (Just 10.0) 2 9.928179285716674+ , DifficultyVector 0 (Just 10.0) 3 9.928179285716674+ , DifficultyVector 0 (Just 10.0) 4 9.928179285716674+ , DifficultyVector 1 Nothing 1 8.15903+ , DifficultyVector 1 Nothing 2 1.7511448034338732+ , DifficultyVector 1 Nothing 3 1.0+ , DifficultyVector 1 Nothing 4 1.0+ , DifficultyVector 1 (Just 1.0) 1 1.4918717310343146+ , DifficultyVector 1 (Just 1.0) 2 1.0+ , DifficultyVector 1 (Just 1.0) 3 1.0+ , DifficultyVector 1 (Just 1.0) 4 1.0+ , DifficultyVector 1 (Just 2.5) 1 2.2309568910343147+ , DifficultyVector 1 (Just 2.5) 2 1.0+ , DifficultyVector 1 (Just 2.5) 3 1.0+ , DifficultyVector 1 (Just 2.5) 4 1.0+ , DifficultyVector 1 (Just 4.194588083372719) 1 3.065920160856728+ , DifficultyVector 1 (Just 4.194588083372719) 2 1.6224725272150176+ , DifficultyVector 1 (Just 4.194588083372719) 3 1.0+ , DifficultyVector 1 (Just 4.194588083372719) 4 1.0+ , DifficultyVector 1 (Just 7.0) 1 4.448212371034315+ , DifficultyVector 1 (Just 7.0) 2 3.702297531034315+ , DifficultyVector 1 (Just 7.0) 3 2.9563826910343147+ , DifficultyVector 1 (Just 7.0) 4 2.2104678510343154+ , DifficultyVector 1 (Just 10.0) 1 5.926382691034315+ , DifficultyVector 1 (Just 10.0) 2 5.926382691034315+ , DifficultyVector 1 (Just 10.0) 3 5.926382691034315+ , DifficultyVector 1 (Just 10.0) 4 5.926382691034315+ , DifficultyVector 2 Nothing 1 7.614116+ , DifficultyVector 2 Nothing 2 5.356124178155698+ , DifficultyVector 2 Nothing 3 1.0+ , DifficultyVector 2 Nothing 4 1.0+ , DifficultyVector 2 (Just 1.0) 1 1.5042458491001744+ , DifficultyVector 2 (Just 1.0) 2 1.1172835591001746+ , DifficultyVector 2 (Just 1.0) 3 1.0+ , DifficultyVector 2 (Just 1.0) 4 1.0+ , DifficultyVector 2 (Just 2.5) 1 2.8602584191001745+ , DifficultyVector 2 (Just 2.5) 2 2.5377898441001747+ , DifficultyVector 2 (Just 2.5) 3 2.215321269100175+ , DifficultyVector 2 (Just 2.5) 4 1.8928526941001744+ , DifficultyVector 2 (Just 4.194588083372719) 1 4.392180247117252+ , DifficultyVector 2 (Just 4.194588083372719) 2 4.142571859378209+ , DifficultyVector 2 (Just 4.194588083372719) 3 3.892963471639167+ , DifficultyVector 2 (Just 4.194588083372719) 4 3.643355083900124+ , DifficultyVector 2 (Just 7.0) 1 6.928296129100175+ , DifficultyVector 2 (Just 7.0) 2 6.799308699100174+ , DifficultyVector 2 (Just 7.0) 3 6.6703212691001745+ , DifficultyVector 2 (Just 7.0) 4 6.541333839100175+ , DifficultyVector 2 (Just 10.0) 1 9.640321269100175+ , DifficultyVector 2 (Just 10.0) 2 9.640321269100175+ , DifficultyVector 2 (Just 10.0) 3 9.640321269100175+ , DifficultyVector 2 (Just 10.0) 4 9.640321269100175+ ]++-- | One half of the stability update, before the two are blended.+data HalfStabilityVector = HalfStabilityVector+ { hsParams :: !Int+ , hsLongTerm :: !Bool+ -- ^ 'True' for the long-term block, 'False' for the short-term one.+ , hsStability :: !Double+ , hsDifficulty :: !Double+ , hsRetrievability :: !Double+ , hsRating :: !Int+ , hsNextStability :: !Double+ }+ deriving stock (Eq, Show)++goldenHalfStabilityVectors :: [HalfStabilityVector]+goldenHalfStabilityVectors =+ [ HalfStabilityVector 0 True 0.01 1.0 0.05 1 0.00287539614361996+ , HalfStabilityVector 0 False 0.01 1.0 0.05 1 0.008457926427604777+ , HalfStabilityVector 0 True 0.01 1.0 0.05 2 0.8312175079505889+ , HalfStabilityVector 0 False 0.01 1.0 0.05 2 3.634419609530054+ , HalfStabilityVector 0 True 0.01 1.0 0.05 3 1.2495735969065493+ , HalfStabilityVector 0 False 0.01 1.0 0.05 3 6.489119788219617+ , HalfStabilityVector 0 True 0.01 1.0 0.05 4 1.6214456759785143+ , HalfStabilityVector 0 False 0.01 1.0 0.05 4 8.432855724685503+ , HalfStabilityVector 0 True 0.01 1.0 0.5 1 0.0027617663415225664+ , HalfStabilityVector 0 False 0.01 1.0 0.5 1 0.00257672455606105+ , HalfStabilityVector 0 True 0.01 1.0 0.5 2 0.3154085317282906+ , HalfStabilityVector 0 False 0.01 1.0 0.5 2 0.6319216021560662+ , HalfStabilityVector 0 True 0.01 1.0 0.5 3 0.4709940101559103+ , HalfStabilityVector 0 False 0.01 1.0 0.5 3 1.121765466850315+ , HalfStabilityVector 0 True 0.01 1.0 0.5 4 0.6092922132026835+ , HalfStabilityVector 0 False 0.01 1.0 0.5 4 1.4552951069054094+ , HalfStabilityVector 0 True 0.01 1.0 1.0 1 0.0026407697690489216+ , HalfStabilityVector 0 False 0.01 1.0 1.0 1 0.0006878868205852286+ , HalfStabilityVector 0 True 0.01 1.0 1.0 2 0.01+ , HalfStabilityVector 0 False 0.01 1.0 1.0 2 0.01+ , HalfStabilityVector 0 True 0.01 1.0 1.0 3 0.01+ , HalfStabilityVector 0 False 0.01 1.0 1.0 3 0.01+ , HalfStabilityVector 0 True 0.01 1.0 1.0 4 0.01+ , HalfStabilityVector 0 False 0.01 1.0 1.0 4 0.01+ , HalfStabilityVector 0 True 0.01 4.194588083372719 0.05 1 0.0028552655688472766+ , HalfStabilityVector 0 False 0.01 4.194588083372719 0.05 1 0.008329158514656381+ , HalfStabilityVector 0 True 0.01 4.194588083372719 0.05 2 0.5688723414749896+ , HalfStabilityVector 0 False 0.01 4.194588083372719 0.05 2 2.4765668401553422+ , HalfStabilityVector 0 True 0.01 4.194588083372719 0.05 3 0.8535808927924372+ , HalfStabilityVector 0 False 0.01 4.194588083372719 0.05 3 4.419307901600541+ , HalfStabilityVector 0 True 0.01 4.194588083372719 0.05 4 1.1066551606301684+ , HalfStabilityVector 0 False 0.01 4.194588083372719 0.05 4 5.7421002720807035+ , HalfStabilityVector 0 True 0.01 4.194588083372719 0.5 1 0.0027424312860847063+ , HalfStabilityVector 0 False 0.01 4.194588083372719 0.5 1 0.0025374951484554284+ , HalfStabilityVector 0 True 0.01 4.194588083372719 0.5 2 0.21784308612633496+ , HalfStabilityVector 0 False 0.01 4.194588083372719 0.5 2 0.4332432682520823+ , HalfStabilityVector 0 True 0.01 4.194588083372719 0.5 3 0.3237254130208829+ , HalfStabilityVector 0 False 0.01 4.194588083372719 0.5 3 0.7666021956597825+ , HalfStabilityVector 0 True 0.01 4.194588083372719 0.5 4 0.41784303692714786+ , HalfStabilityVector 0 False 0.01 4.194588083372719 0.5 4 0.9935828543577173+ , HalfStabilityVector 0 True 0.01 4.194588083372719 1.0 1 0.0026222818075166522+ , HalfStabilityVector 0 False 0.01 4.194588083372719 1.0 1 0.0006774140704390025+ , HalfStabilityVector 0 True 0.01 4.194588083372719 1.0 2 0.01+ , HalfStabilityVector 0 False 0.01 4.194588083372719 1.0 2 0.01+ , HalfStabilityVector 0 True 0.01 4.194588083372719 1.0 3 0.01+ , HalfStabilityVector 0 False 0.01 4.194588083372719 1.0 3 0.01+ , HalfStabilityVector 0 True 0.01 4.194588083372719 1.0 4 0.01+ , HalfStabilityVector 0 False 0.01 4.194588083372719 1.0 4 0.01+ , HalfStabilityVector 0 True 0.01 10.0 0.05 1 0.0028431363371105457+ , HalfStabilityVector 0 False 0.01 10.0 0.05 1 0.008252088996248524+ , HalfStabilityVector 0 True 0.01 10.0 0.05 2 0.09212175079505888+ , HalfStabilityVector 0 False 0.01 10.0 0.05 2 0.37244196095300536+ , HalfStabilityVector 0 True 0.01 10.0 0.05 3 0.13395735969065492+ , HalfStabilityVector 0 False 0.01 10.0 0.05 3 0.6579119788219617+ , HalfStabilityVector 0 True 0.01 10.0 0.05 4 0.17114456759785143+ , HalfStabilityVector 0 False 0.01 10.0 0.05 4 0.8522855724685503+ , HalfStabilityVector 0 True 0.01 10.0 0.5 1 0.002730781376894504+ , HalfStabilityVector 0 False 0.01 10.0 0.5 1 0.0025140157623074026+ , HalfStabilityVector 0 True 0.01 10.0 0.5 2 0.040540853172829065+ , HalfStabilityVector 0 False 0.01 10.0 0.5 2 0.07219216021560662+ , HalfStabilityVector 0 True 0.01 10.0 0.5 3 0.056099401015591036+ , HalfStabilityVector 0 False 0.01 10.0 0.5 3 0.1211765466850315+ , HalfStabilityVector 0 True 0.01 10.0 0.5 4 0.06992922132026835+ , HalfStabilityVector 0 False 0.01 10.0 0.5 4 0.15452951069054094+ , HalfStabilityVector 0 True 0.01 10.0 1.0 1 0.0026111422959877043+ , HalfStabilityVector 0 False 0.01 10.0 1.0 1 0.000671145973118058+ , HalfStabilityVector 0 True 0.01 10.0 1.0 2 0.01+ , HalfStabilityVector 0 False 0.01 10.0 1.0 2 0.01+ , HalfStabilityVector 0 True 0.01 10.0 1.0 3 0.01+ , HalfStabilityVector 0 False 0.01 10.0 1.0 3 0.01+ , HalfStabilityVector 0 True 0.01 10.0 1.0 4 0.01+ , HalfStabilityVector 0 False 0.01 10.0 1.0 4 0.01+ , HalfStabilityVector 0 True 1.0 1.0 0.05 1 0.2617448884635849+ , HalfStabilityVector 0 False 1.0 1.0 0.05 1 0.6375484000895719+ , HalfStabilityVector 0 True 1.0 1.0 0.05 2 38.744893102401065+ , HalfStabilityVector 0 False 1.0 1.0 0.05 2 89.07212425705278+ , HalfStabilityVector 0 True 1.0 1.0 0.05 3 57.97342355079406+ , HalfStabilityVector 0 False 1.0 1.0 0.05 3 158.44033653388055+ , HalfStabilityVector 0 True 1.0 1.0 0.05 4 75.06545061603228+ , HalfStabilityVector 0 False 1.0 1.0 0.05 4 205.67243749404471+ , HalfStabilityVector 0 True 1.0 1.0 0.5 1 0.25140126331053797+ , HalfStabilityVector 0 False 1.0 1.0 0.5 1 0.19423042187108028+ , HalfStabilityVector 0 True 1.0 1.0 0.5 2 15.037221894371966+ , HalfStabilityVector 0 False 1.0 1.0 0.5 2 16.112476623625945+ , HalfStabilityVector 0 True 1.0 1.0 0.5 3 22.188259463202968+ , HalfStabilityVector 0 False 1.0 1.0 0.5 3 28.015510589249097+ , HalfStabilityVector 0 True 1.0 1.0 0.5 4 28.54473730216386+ , HalfStabilityVector 0 False 1.0 1.0 0.5 4 36.12016376602383+ , HalfStabilityVector 0 True 1.0 1.0 1.0 1 0.24038704725656526+ , HalfStabilityVector 0 False 1.0 1.0 1.0 1 0.05185208758442845+ , HalfStabilityVector 0 True 1.0 1.0 1.0 2 1.0+ , HalfStabilityVector 0 False 1.0 1.0 1.0 2 1.0+ , HalfStabilityVector 0 True 1.0 1.0 1.0 3 1.0+ , HalfStabilityVector 0 False 1.0 1.0 1.0 3 1.0+ , HalfStabilityVector 0 True 1.0 1.0 1.0 4 1.0+ , HalfStabilityVector 0 False 1.0 1.0 1.0 4 1.0+ , HalfStabilityVector 0 True 1.0 4.194588083372719 0.05 1 0.25991241920181896+ , HalfStabilityVector 0 False 1.0 4.194588083372719 0.05 1 0.6278420284882321+ , HalfStabilityVector 0 True 1.0 4.194588083372719 0.05 2 26.686954531090308+ , HalfStabilityVector 0 False 1.0 4.194588083372719 0.05 2 60.93670839416256+ , HalfStabilityVector 0 True 1.0 4.194588083372719 0.05 3 39.77276155636273+ , HalfStabilityVector 0 False 1.0 4.194588083372719 0.05 3 108.14463424054802+ , HalfStabilityVector 0 True 1.0 4.194588083372719 0.05 4 51.40459002327155+ , HalfStabilityVector 0 False 1.0 4.194588083372719 0.05 4 140.2880245127124+ , HalfStabilityVector 0 True 1.0 4.194588083372719 0.5 1 0.24964120950360458+ , HalfStabilityVector 0 False 1.0 4.194588083372719 0.5 1 0.19127335594369213+ , HalfStabilityVector 0 True 1.0 4.194588083372719 0.5 2 10.552907715630036+ , HalfStabilityVector 0 False 1.0 4.194588083372719 0.5 2 11.284662850417522+ , HalfStabilityVector 0 True 1.0 4.194588083372719 0.5 3 15.419483344347224+ , HalfStabilityVector 0 False 1.0 4.194588083372719 0.5 3 19.38516776978463+ , HalfStabilityVector 0 True 1.0 4.194588083372719 0.5 4 19.74532834765139+ , HalfStabilityVector 0 False 1.0 4.194588083372719 0.5 4 24.90071810072002+ , HalfStabilityVector 0 True 1.0 4.194588083372719 1.0 1 0.23870410369419032+ , HalfStabilityVector 0 False 1.0 4.194588083372719 1.0 1 0.05106266417699935+ , HalfStabilityVector 0 True 1.0 4.194588083372719 1.0 2 1.0+ , HalfStabilityVector 0 False 1.0 4.194588083372719 1.0 2 1.0+ , HalfStabilityVector 0 True 1.0 4.194588083372719 1.0 3 1.0+ , HalfStabilityVector 0 False 1.0 4.194588083372719 1.0 3 1.0+ , HalfStabilityVector 0 True 1.0 4.194588083372719 1.0 4 1.0+ , HalfStabilityVector 0 False 1.0 4.194588083372719 1.0 4 1.0+ , HalfStabilityVector 0 True 1.0 10.0 0.05 1 0.2588083054555709+ , HalfStabilityVector 0 False 1.0 10.0 0.05 1 0.6220326201684536+ , HalfStabilityVector 0 True 1.0 10.0 0.05 2 4.7744893102401065+ , HalfStabilityVector 0 False 1.0 10.0 0.05 2 9.807212425705277+ , HalfStabilityVector 0 True 1.0 10.0 0.05 3 6.697342355079406+ , HalfStabilityVector 0 False 1.0 10.0 0.05 3 16.744033653388055+ , HalfStabilityVector 0 True 1.0 10.0 0.05 4 8.406545061603229+ , HalfStabilityVector 0 False 1.0 10.0 0.05 4 21.46724374940447+ , HalfStabilityVector 0 True 1.0 10.0 0.5 1 0.24858072808494294+ , HalfStabilityVector 0 False 1.0 10.0 0.5 1 0.18950350783708025+ , HalfStabilityVector 0 True 1.0 10.0 0.5 2 2.4037221894371967+ , HalfStabilityVector 0 False 1.0 10.0 0.5 2 2.5112476623625946+ , HalfStabilityVector 0 True 1.0 10.0 0.5 3 3.118825946320297+ , HalfStabilityVector 0 False 1.0 10.0 0.5 3 3.7015510589249097+ , HalfStabilityVector 0 True 1.0 10.0 0.5 4 3.754473730216386+ , HalfStabilityVector 0 False 1.0 10.0 0.5 4 4.512016376602382+ , HalfStabilityVector 0 True 1.0 10.0 1.0 1 0.23769008334462816+ , HalfStabilityVector 0 False 1.0 10.0 1.0 1 0.05059018248154134+ , HalfStabilityVector 0 True 1.0 10.0 1.0 2 1.0+ , HalfStabilityVector 0 False 1.0 10.0 1.0 2 1.0+ , HalfStabilityVector 0 True 1.0 10.0 1.0 3 1.0+ , HalfStabilityVector 0 False 1.0 10.0 1.0 3 1.0+ , HalfStabilityVector 0 True 1.0 10.0 1.0 4 1.0+ , HalfStabilityVector 0 False 1.0 10.0 1.0 4 1.0+ , HalfStabilityVector 0 True 4.1283 1.0 0.05 1 0.9245562153616427+ , HalfStabilityVector 0 False 4.1283 1.0 0.05 1 1.6819069920331728+ , HalfStabilityVector 0 True 4.1283 1.0 0.05 2 126.78386642337001+ , HalfStabilityVector 0 False 4.1283 1.0 0.05 2 239.3323486572463+ , HalfStabilityVector 0 True 4.1283 1.0 0.05 3 189.26877762018117+ , HalfStabilityVector 0 False 4.1283 1.0 0.05 3 424.5860201595393+ , HalfStabilityVector 0 True 4.1283 1.0 0.05 4 244.8109209062355+ , HalfStabilityVector 0 False 4.1283 1.0 0.05 4 550.7233362074012+ , HalfStabilityVector 0 True 4.1283 1.0 0.5 1 0.8880196358671743+ , HalfStabilityVector 0 False 4.1283 1.0 0.5 1 0.5123963993394485+ , HalfStabilityVector 0 True 4.1283 1.0 0.5 2 49.74356768121113+ , HalfStabilityVector 0 False 4.1283 1.0 0.5 2 44.4874456104815+ , HalfStabilityVector 0 True 4.1283 1.0 0.5 3 72.98153423579039+ , HalfStabilityVector 0 False 4.1283 1.0 0.5 3 76.27550345098588+ , HalfStabilityVector 0 True 4.1283 1.0 0.5 4 93.63750450652752+ , HalfStabilityVector 0 False 4.1283 1.0 0.5 4 97.91966448628165+ , HalfStabilityVector 0 True 4.1283 1.0 1.0 1 0.849114341594529+ , HalfStabilityVector 0 False 4.1283 1.0 1.0 1 0.13679022431475651+ , HalfStabilityVector 0 True 4.1283 1.0 1.0 2 4.1283+ , HalfStabilityVector 0 False 4.1283 1.0 1.0 2 4.1283+ , HalfStabilityVector 0 True 4.1283 1.0 1.0 3 4.1283+ , HalfStabilityVector 0 False 4.1283 1.0 1.0 3 4.1283+ , HalfStabilityVector 0 True 4.1283 1.0 1.0 4 4.1283+ , HalfStabilityVector 0 False 4.1283 1.0 1.0 4 4.1283+ , HalfStabilityVector 0 True 4.1283 4.194588083372719 0.05 1 0.9180834209725344+ , HalfStabilityVector 0 False 4.1283 4.194588083372719 0.05 1 1.6563007568653456+ , HalfStabilityVector 0 True 4.1283 4.194588083372719 0.05 2 87.60046533782713+ , HalfStabilityVector 0 False 4.1283 4.194588083372719 0.05 2 164.19434355710067+ , HalfStabilityVector 0 True 4.1283 4.194588083372719 0.05 3 130.1240212646447+ , HalfStabilityVector 0 False 4.1283 4.194588083372719 0.05 3 290.26709792116674+ , HalfStabilityVector 0 True 4.1283 4.194588083372719 0.05 4 167.92273764403814+ , HalfStabilityVector 0 False 4.1283 4.194588083372719 0.05 4 376.10873729751677+ , HalfStabilityVector 0 True 4.1283 4.194588083372719 0.5 1 0.8818026331355332+ , HalfStabilityVector 0 False 4.1283 4.194588083372719 0.5 1 0.5045954075112541+ , HalfStabilityVector 0 True 4.1283 4.194588083372719 0.5 2 35.17136862578576+ , HalfStabilityVector 0 False 4.1283 4.194588083372719 0.5 2 31.594361048246647+ , HalfStabilityVector 0 True 4.1283 4.194588083372719 0.5 3 50.98576207665775+ , HalfStabilityVector 0 False 4.1283 4.194588083372719 0.5 3 53.22744381166723+ , HalfStabilityVector 0 True 4.1283 4.194588083372719 0.5 4 65.04300069965508+ , HalfStabilityVector 0 False 4.1283 4.194588083372719 0.5 4 67.9571869551674+ , HalfStabilityVector 0 True 4.1283 4.194588083372719 1.0 1 0.8431697138318628+ , HalfStabilityVector 0 False 4.1283 4.194588083372719 1.0 1 0.13470765811516586+ , HalfStabilityVector 0 True 4.1283 4.194588083372719 1.0 2 4.1283+ , HalfStabilityVector 0 False 4.1283 4.194588083372719 1.0 2 4.1283+ , HalfStabilityVector 0 True 4.1283 4.194588083372719 1.0 3 4.1283+ , HalfStabilityVector 0 False 4.1283 4.194588083372719 1.0 3 4.1283+ , HalfStabilityVector 0 True 4.1283 4.194588083372719 1.0 4 4.1283+ , HalfStabilityVector 0 False 4.1283 4.194588083372719 1.0 4 4.1283+ , HalfStabilityVector 0 True 4.1283 10.0 0.05 1 0.9141833821501835+ , HalfStabilityVector 0 False 4.1283 10.0 0.05 1 1.640975042815654+ , HalfStabilityVector 0 True 4.1283 10.0 0.05 2 16.393856642337+ , HalfStabilityVector 0 False 4.1283 10.0 0.05 2 27.648704865724625+ , HalfStabilityVector 0 True 4.1283 10.0 0.05 3 22.642347762018115+ , HalfStabilityVector 0 False 4.1283 10.0 0.05 3 46.174072015953925+ , HalfStabilityVector 0 True 4.1283 10.0 0.05 4 28.196562090623548+ , HalfStabilityVector 0 False 4.1283 10.0 0.05 4 58.78780362074011+ , HalfStabilityVector 0 True 4.1283 10.0 0.5 1 0.8780567159080586+ , HalfStabilityVector 0 False 4.1283 10.0 0.5 1 0.4999263974330719+ , HalfStabilityVector 0 True 4.1283 10.0 0.5 2 8.689826768121115+ , HalfStabilityVector 0 False 4.1283 10.0 0.5 2 8.16421456104815+ , HalfStabilityVector 0 True 4.1283 10.0 0.5 3 11.01362342357904+ , HalfStabilityVector 0 False 4.1283 10.0 0.5 3 11.343020345098587+ , HalfStabilityVector 0 True 4.1283 10.0 0.5 4 13.079220450652754+ , HalfStabilityVector 0 False 4.1283 10.0 0.5 4 13.507436448628166+ , HalfStabilityVector 0 True 4.1283 10.0 1.0 1 0.839587910106128+ , HalfStabilityVector 0 False 4.1283 10.0 1.0 1 0.13346121115194412+ , HalfStabilityVector 0 True 4.1283 10.0 1.0 2 4.1283+ , HalfStabilityVector 0 False 4.1283 10.0 1.0 2 4.1283+ , HalfStabilityVector 0 True 4.1283 10.0 1.0 3 4.1283+ , HalfStabilityVector 0 False 4.1283 10.0 1.0 3 4.1283+ , HalfStabilityVector 0 True 4.1283 10.0 1.0 4 4.1283+ , HalfStabilityVector 0 False 4.1283 10.0 1.0 4 4.1283+ , HalfStabilityVector 0 True 1000.0 1.0 0.05 1 68.04348456164972+ , HalfStabilityVector 0 False 1000.0 1.0 0.05 1 14.26268886210528+ , HalfStabilityVector 0 True 1000.0 1.0 0.05 2 12761.377775584082+ , HalfStabilityVector 0 False 1000.0 1.0 0.05 2 11549.660200515413+ , HalfStabilityVector 0 True 1000.0 1.0 0.05 3 18753.023057485407+ , HalfStabilityVector 0 False 1000.0 1.0 0.05 3 19858.884877574925+ , HalfStabilityVector 0 True 1000.0 1.0 0.05 4 24078.92997473103+ , HalfStabilityVector 0 False 1000.0 1.0 0.05 4 25516.550340847407+ , HalfStabilityVector 0 True 1000.0 1.0 0.5 1 65.35454456918542+ , HalfStabilityVector 0 False 1000.0 1.0 0.5 1 4.3451572842367145+ , HalfStabilityVector 0 True 1000.0 1.0 0.5 2 5374.024034761578+ , HalfStabilityVector 0 False 1000.0 1.0 0.5 2 2810.2378534910713+ , HalfStabilityVector 0 True 1000.0 1.0 0.5 3 7602.300429828797+ , HalfStabilityVector 0 False 1000.0 1.0 0.5 3 4236.034775636524+ , HalfStabilityVector 0 True 1000.0 1.0 0.5 4 9582.990558777437+ , HalfStabilityVector 0 False 1000.0 1.0 0.5 4 5206.8452083274815+ , HalfStabilityVector 0 True 1000.0 1.0 1.0 1 62.49127704015617+ , HalfStabilityVector 0 False 1000.0 1.0 1.0 1 1.159990664180841+ , HalfStabilityVector 0 True 1000.0 1.0 1.0 2 1000.0+ , HalfStabilityVector 0 False 1000.0 1.0 1.0 2 1000.0+ , HalfStabilityVector 0 True 1000.0 1.0 1.0 3 1000.0+ , HalfStabilityVector 0 False 1000.0 1.0 1.0 3 1000.0+ , HalfStabilityVector 0 True 1000.0 1.0 1.0 4 1000.0+ , HalfStabilityVector 0 False 1000.0 1.0 1.0 4 1000.0+ , HalfStabilityVector 0 True 1000.0 4.194588083372719 0.05 1 67.56711386858835+ , HalfStabilityVector 0 False 1000.0 4.194588083372719 0.05 1 14.045546197939808+ , HalfStabilityVector 0 True 1000.0 4.194588083372719 0.05 2 9004.102046991517+ , HalfStabilityVector 0 False 1000.0 4.194588083372719 0.05 2 8179.478324495616+ , HalfStabilityVector 0 True 1000.0 4.194588083372719 0.05 3 13081.663467157006+ , HalfStabilityVector 0 False 1000.0 4.194588083372719 0.05 3 13834.247988015042+ , HalfStabilityVector 0 True 1000.0 4.194588083372719 0.05 4 16706.16250730411+ , HalfStabilityVector 0 False 1000.0 4.194588083372719 0.05 4 17684.522384419553+ , HalfStabilityVector 0 True 1000.0 4.194588083372719 0.5 1 64.89699907615697+ , HalfStabilityVector 0 False 1000.0 4.194588083372719 0.5 1 4.27900432822405+ , HalfStabilityVector 0 True 1000.0 4.194588083372719 0.5 2 3976.703528978058+ , HalfStabilityVector 0 False 1000.0 4.194588083372719 0.5 2 2231.941426007793+ , HalfStabilityVector 0 True 1000.0 4.194588083372719 0.5 3 5493.137402231031+ , HalfStabilityVector 0 False 1000.0 4.194588083372719 0.5 3 3202.254962473709+ , HalfStabilityVector 0 True 1000.0 4.194588083372719 0.5 4 6841.07862290034+ , HalfStabilityVector 0 False 1000.0 4.194588083372719 0.5 4 3862.931451215822+ , HalfStabilityVector 0 True 1000.0 4.194588083372719 1.0 1 62.05377720978023+ , HalfStabilityVector 0 False 1000.0 4.194588083372719 1.0 1 1.1423303572315298+ , HalfStabilityVector 0 True 1000.0 4.194588083372719 1.0 2 1000.0+ , HalfStabilityVector 0 False 1000.0 4.194588083372719 1.0 2 1000.0+ , HalfStabilityVector 0 True 1000.0 4.194588083372719 1.0 3 1000.0+ , HalfStabilityVector 0 False 1000.0 4.194588083372719 1.0 3 1000.0+ , HalfStabilityVector 0 True 1000.0 4.194588083372719 1.0 4 1000.0+ , HalfStabilityVector 0 False 1000.0 4.194588083372719 1.0 4 1000.0+ , HalfStabilityVector 0 True 1000.0 10.0 0.05 1 67.28008726383543+ , HalfStabilityVector 0 False 1000.0 10.0 0.05 1 13.915583071491234+ , HalfStabilityVector 0 True 1000.0 10.0 0.05 2 2176.1377775584087+ , HalfStabilityVector 0 False 1000.0 10.0 0.05 2 2054.9660200515414+ , HalfStabilityVector 0 True 1000.0 10.0 0.05 3 2775.302305748541+ , HalfStabilityVector 0 False 1000.0 10.0 0.05 3 2885.888487757493+ , HalfStabilityVector 0 True 1000.0 10.0 0.05 4 3307.892997473103+ , HalfStabilityVector 0 False 1000.0 10.0 0.05 4 3451.6550340847402+ , HalfStabilityVector 0 True 1000.0 10.0 0.5 1 64.62131517851839+ , HalfStabilityVector 0 False 1000.0 10.0 0.5 1 4.239410796385142+ , HalfStabilityVector 0 True 1000.0 10.0 0.5 2 1437.4024034761578+ , HalfStabilityVector 0 False 1000.0 10.0 0.5 2 1181.0237853491071+ , HalfStabilityVector 0 True 1000.0 10.0 0.5 3 1660.2300429828797+ , HalfStabilityVector 0 False 1000.0 10.0 0.5 3 1323.6034775636524+ , HalfStabilityVector 0 True 1000.0 10.0 0.5 4 1858.2990558777435+ , HalfStabilityVector 0 False 1000.0 10.0 0.5 4 1420.6845208327481+ , HalfStabilityVector 0 True 1000.0 10.0 1.0 1 61.790171381962004+ , HalfStabilityVector 0 False 1000.0 10.0 1.0 1 1.1317603998535317+ , HalfStabilityVector 0 True 1000.0 10.0 1.0 2 1000.0+ , HalfStabilityVector 0 False 1000.0 10.0 1.0 2 1000.0+ , HalfStabilityVector 0 True 1000.0 10.0 1.0 3 1000.0+ , HalfStabilityVector 0 False 1000.0 10.0 1.0 3 1000.0+ , HalfStabilityVector 0 True 1000.0 10.0 1.0 4 1000.0+ , HalfStabilityVector 0 False 1000.0 10.0 1.0 4 1000.0+ , HalfStabilityVector 1 True 0.01 1.0 0.05 1 0.01+ , HalfStabilityVector 1 False 0.01 1.0 0.05 1 0.01+ , HalfStabilityVector 1 True 0.01 1.0 0.05 2 0.8966896600454457+ , HalfStabilityVector 1 False 0.01 1.0 0.05 2 598.0673472983267+ , HalfStabilityVector 1 True 0.01 1.0 0.05 3 3.6502250587913085+ , HalfStabilityVector 1 False 0.01 1.0 0.05 3 962.1233371808707+ , HalfStabilityVector 1 True 0.01 1.0 0.05 4 20.029530557799625+ , HalfStabilityVector 1 False 0.01 1.0 0.05 4 3197.270406039331+ , HalfStabilityVector 1 True 0.01 1.0 0.5 1 0.01+ , HalfStabilityVector 1 False 0.01 1.0 0.5 1 0.01+ , HalfStabilityVector 1 True 0.01 1.0 0.5 2 0.38945019019101057+ , HalfStabilityVector 1 False 0.01 1.0 0.5 2 90.07616126697779+ , HalfStabilityVector 1 True 0.01 1.0 0.5 3 1.5677988028253866+ , HalfStabilityVector 1 False 0.01 1.0 0.5 3 144.90221706763393+ , HalfStabilityVector 1 True 0.01 1.0 0.5 4 8.577162807901102+ , HalfStabilityVector 1 False 0.01 1.0 0.5 4 481.51059963934654+ , HalfStabilityVector 1 True 0.01 1.0 1.0 1 0.00902036494133907+ , HalfStabilityVector 1 False 0.01 1.0 1.0 1 0.0029938642674169837+ , HalfStabilityVector 1 True 0.01 1.0 1.0 2 0.01+ , HalfStabilityVector 1 False 0.01 1.0 1.0 2 0.01+ , HalfStabilityVector 1 True 0.01 1.0 1.0 3 0.01+ , HalfStabilityVector 1 False 0.01 1.0 1.0 3 0.01+ , HalfStabilityVector 1 True 0.01 1.0 1.0 4 0.01+ , HalfStabilityVector 1 False 0.01 1.0 1.0 4 0.01+ , HalfStabilityVector 1 True 0.01 4.194588083372719 0.05 1 0.01+ , HalfStabilityVector 1 False 0.01 4.194588083372719 0.05 1 0.003403154718652425+ , HalfStabilityVector 1 True 0.01 4.194588083372719 0.05 2 0.613428837882347+ , HalfStabilityVector 1 False 0.01 4.194588083372719 0.05 2 407.0126598130534+ , HalfStabilityVector 1 True 0.01 4.194588083372719 0.05 3 2.487323099430362+ , HalfStabilityVector 1 False 0.01 4.194588083372719 0.05 3 654.767756999674+ , HalfStabilityVector 1 True 0.01 4.194588083372719 0.05 4 13.634115182333359+ , HalfStabilityVector 1 False 0.01 4.194588083372719 0.05 4 2175.8774067820646+ , HalfStabilityVector 1 True 0.01 4.194588083372719 0.5 1 0.007864081935762476+ , HalfStabilityVector 1 False 0.01 4.194588083372719 0.5 1 0.0009878341199227173+ , HalfStabilityVector 1 True 0.01 4.194588083372719 0.5 2 0.2682314846092391+ , HalfStabilityVector 1 False 0.01 4.194588083372719 0.5 2 61.30373271711653+ , HalfStabilityVector 1 True 0.01 4.194588083372719 0.5 3 1.07014625364556+ , HalfStabilityVector 1 False 0.01 4.194588083372719 0.5 3 98.6151220658623+ , HalfStabilityVector 1 True 0.01 4.194588083372719 0.5 4 5.84030718645762+ , HalfStabilityVector 1 False 0.01 4.194588083372719 0.5 4 327.6909918648792+ , HalfStabilityVector 1 True 0.01 4.194588083372719 1.0 1 0.004515289488579959+ , HalfStabilityVector 1 False 0.01 4.194588083372719 1.0 1 0.0002499181061597935+ , HalfStabilityVector 1 True 0.01 4.194588083372719 1.0 2 0.01+ , HalfStabilityVector 1 False 0.01 4.194588083372719 1.0 2 0.01+ , HalfStabilityVector 1 True 0.01 4.194588083372719 1.0 3 0.01+ , HalfStabilityVector 1 False 0.01 4.194588083372719 1.0 3 0.01+ , HalfStabilityVector 1 True 0.01 4.194588083372719 1.0 4 0.01+ , HalfStabilityVector 1 False 0.01 4.194588083372719 1.0 4 0.01+ , HalfStabilityVector 1 True 0.01 10.0 0.05 1 0.00851935520311179+ , HalfStabilityVector 1 False 0.01 10.0 0.05 1 0.0007558194778112339+ , HalfStabilityVector 1 True 0.01 10.0 0.05 2 0.09866896600454458+ , HalfStabilityVector 1 False 0.01 10.0 0.05 2 59.81573472983268+ , HalfStabilityVector 1 True 0.01 10.0 0.05 3 0.3740225058791309+ , HalfStabilityVector 1 False 0.01 10.0 0.05 3 96.22133371808708+ , HalfStabilityVector 1 True 0.01 10.0 0.05 4 2.0119530557799625+ , HalfStabilityVector 1 False 0.01 10.0 0.05 4 319.73604060393313+ , HalfStabilityVector 1 True 0.01 10.0 0.5 1 0.005170595199856055+ , HalfStabilityVector 1 False 0.01 10.0 0.5 1 0.00021939180860391642+ , HalfStabilityVector 1 True 0.01 10.0 0.5 2 0.047945019019101046+ , HalfStabilityVector 1 False 0.01 10.0 0.5 2 9.01661612669778+ , HalfStabilityVector 1 True 0.01 10.0 0.5 3 0.16577988028253868+ , HalfStabilityVector 1 False 0.01 10.0 0.5 3 14.499221706763393+ , HalfStabilityVector 1 True 0.01 10.0 0.5 4 0.8667162807901102+ , HalfStabilityVector 1 False 0.01 10.0 0.5 4 48.16005996393466+ , HalfStabilityVector 1 True 0.01 10.0 1.0 1 0.0029687806340675436+ , HalfStabilityVector 1 False 0.01 10.0 1.0 1 5.550525559650873e-5+ , HalfStabilityVector 1 True 0.01 10.0 1.0 2 0.01+ , HalfStabilityVector 1 False 0.01 10.0 1.0 2 0.01+ , HalfStabilityVector 1 True 0.01 10.0 1.0 3 0.01+ , HalfStabilityVector 1 False 0.01 10.0 1.0 3 0.01+ , HalfStabilityVector 1 True 0.01 10.0 1.0 4 0.01+ , HalfStabilityVector 1 False 0.01 10.0 1.0 4 0.01+ , HalfStabilityVector 1 True 1.0 1.0 0.05 1 1.0+ , HalfStabilityVector 1 False 1.0 1.0 0.05 1 1.0+ , HalfStabilityVector 1 True 1.0 1.0 0.05 2 1.8559130421060241+ , HalfStabilityVector 1 False 1.0 1.0 0.05 2 308.72645242925637+ , HalfStabilityVector 1 True 1.0 1.0 0.05 3 4.513874407716629+ , HalfStabilityVector 1 False 1.0 1.0 0.05 3 496.04905411329383+ , HalfStabilityVector 1 True 1.0 1.0 0.05 4 20.32466123534424+ , HalfStabilityVector 1 False 1.0 1.0 0.05 4 1646.12919486335+ , HalfStabilityVector 1 True 1.0 1.0 0.5 1 1.0+ , HalfStabilityVector 1 False 1.0 1.0 0.5 1 1.0+ , HalfStabilityVector 1 True 1.0 1.0 0.5 2 1.3662796367755674+ , HalfStabilityVector 1 False 1.0 1.0 0.5 2 47.34294757151948+ , HalfStabilityVector 1 True 1.0 1.0 0.5 3 2.5037282742724902+ , HalfStabilityVector 1 False 1.0 1.0 0.5 3 75.55333195763163+ , HalfStabilityVector 1 True 1.0 1.0 0.5 4 9.269800259938062+ , HalfStabilityVector 1 False 1.0 1.0 0.5 4 248.75294884165092+ , HalfStabilityVector 1 True 1.0 1.0 1.0 1 0.8381208896180983+ , HalfStabilityVector 1 False 1.0 1.0 1.0 1 0.2970737753985787+ , HalfStabilityVector 1 True 1.0 1.0 1.0 2 1.0+ , HalfStabilityVector 1 False 1.0 1.0 1.0 2 1.0+ , HalfStabilityVector 1 True 1.0 1.0 1.0 3 1.0+ , HalfStabilityVector 1 False 1.0 1.0 1.0 3 1.0+ , HalfStabilityVector 1 True 1.0 1.0 1.0 4 1.0+ , HalfStabilityVector 1 False 1.0 1.0 1.0 4 1.0+ , HalfStabilityVector 1 True 1.0 4.194588083372719 0.05 1 1.0+ , HalfStabilityVector 1 False 1.0 4.194588083372719 0.05 1 0.33768665852303786+ , HalfStabilityVector 1 True 1.0 4.194588083372719 0.05 2 1.5824840816345045+ , HalfStabilityVector 1 False 1.0 4.194588083372719 0.05 2 210.42052664234998+ , HalfStabilityVector 1 True 1.0 4.194588083372719 0.05 3 3.3913362767806374+ , HalfStabilityVector 1 False 1.0 4.194588083372719 0.05 3 337.9012732177674+ , HalfStabilityVector 1 True 1.0 4.194588083372719 0.05 4 14.151227985579697+ , HalfStabilityVector 1 False 1.0 4.194588083372719 0.05 4 1120.5781827114488+ , HalfStabilityVector 1 True 1.0 4.194588083372719 0.5 1 0.7306856641492406+ , HalfStabilityVector 1 False 1.0 4.194588083372719 0.5 1 0.09802034603464575+ , HalfStabilityVector 1 True 1.0 4.194588083372719 0.5 2 1.2492683804930358+ , HalfStabilityVector 1 False 1.0 4.194588083372719 0.5 2 32.5382847654852+ , HalfStabilityVector 1 True 1.0 4.194588083372719 0.5 3 2.023349031710338+ , HalfStabilityVector 1 False 1.0 4.194588083372719 0.5 3 51.736613372873585+ , HalfStabilityVector 1 True 1.0 4.194588083372719 0.5 4 6.6279397237109885+ , HalfStabilityVector 1 False 1.0 4.194588083372719 0.5 4 169.60608704265206+ , HalfStabilityVector 1 True 1.0 4.194588083372719 1.0 1 0.4195349598006505+ , HalfStabilityVector 1 False 1.0 4.194588083372719 1.0 1 0.02479875796153185+ , HalfStabilityVector 1 True 1.0 4.194588083372719 1.0 2 1.0+ , HalfStabilityVector 1 False 1.0 4.194588083372719 1.0 2 1.0+ , HalfStabilityVector 1 True 1.0 4.194588083372719 1.0 3 1.0+ , HalfStabilityVector 1 False 1.0 4.194588083372719 1.0 3 1.0+ , HalfStabilityVector 1 True 1.0 4.194588083372719 1.0 4 1.0+ , HalfStabilityVector 1 False 1.0 4.194588083372719 1.0 4 1.0+ , HalfStabilityVector 1 True 1.0 10.0 0.05 1 0.7915699207558515+ , HalfStabilityVector 1 False 1.0 10.0 0.05 1 0.07499810470261795+ , HalfStabilityVector 1 True 1.0 10.0 0.05 2 1.0855913042106025+ , HalfStabilityVector 1 False 1.0 10.0 0.05 2 31.77264524292564+ , HalfStabilityVector 1 True 1.0 10.0 0.05 3 1.3513874407716628+ , HalfStabilityVector 1 False 1.0 10.0 0.05 3 50.50490541132939+ , HalfStabilityVector 1 True 1.0 10.0 0.05 4 2.9324661235344243+ , HalfStabilityVector 1 False 1.0 10.0 0.05 4 165.512919486335+ , HalfStabilityVector 1 True 1.0 10.0 0.5 1 0.480422230911991+ , HalfStabilityVector 1 False 1.0 10.0 0.5 1 0.021769708661414817+ , HalfStabilityVector 1 True 1.0 10.0 0.5 2 1.0366279636775568+ , HalfStabilityVector 1 False 1.0 10.0 0.5 2 5.634294757151948+ , HalfStabilityVector 1 True 1.0 10.0 0.5 3 1.1503728274272491+ , HalfStabilityVector 1 False 1.0 10.0 0.5 3 8.455333195763163+ , HalfStabilityVector 1 True 1.0 10.0 0.5 4 1.8269800259938063+ , HalfStabilityVector 1 False 1.0 10.0 0.5 4 25.775294884165092+ , HalfStabilityVector 1 True 1.0 10.0 1.0 1 0.2758421729372182+ , HalfStabilityVector 1 False 1.0 10.0 1.0 1 0.005507649766882815+ , HalfStabilityVector 1 True 1.0 10.0 1.0 2 1.0+ , HalfStabilityVector 1 False 1.0 10.0 1.0 2 1.0+ , HalfStabilityVector 1 True 1.0 10.0 1.0 3 1.0+ , HalfStabilityVector 1 False 1.0 10.0 1.0 3 1.0+ , HalfStabilityVector 1 True 1.0 10.0 1.0 4 1.0+ , HalfStabilityVector 1 False 1.0 10.0 1.0 4 1.0+ , HalfStabilityVector 1 True 4.1283 1.0 0.05 1 4.1283+ , HalfStabilityVector 1 False 4.1283 1.0 0.05 1 4.1283+ , HalfStabilityVector 1 True 4.1283 1.0 0.05 2 4.974954191572213+ , HalfStabilityVector 1 False 4.1283 1.0 0.05 2 254.92153203736223+ , HalfStabilityVector 1 True 4.1283 1.0 0.05 3 7.60416302532715+ , HalfStabilityVector 1 False 4.1283 1.0 0.05 3 407.58712298387763+ , HalfStabilityVector 1 True 4.1283 1.0 0.05 4 23.243916459540443+ , HalfStabilityVector 1 False 4.1283 1.0 0.05 4 1344.8881360223947+ , HalfStabilityVector 1 True 4.1283 1.0 0.5 1 4.1283+ , HalfStabilityVector 1 False 4.1283 1.0 0.5 1 4.1283+ , HalfStabilityVector 1 True 4.1283 1.0 0.5 2 4.490617402011462+ , HalfStabilityVector 1 False 4.1283 1.0 0.5 2 41.89722597906027+ , HalfStabilityVector 1 True 4.1283 1.0 0.5 3 5.615761673987142+ , HalfStabilityVector 1 False 4.1283 1.0 0.5 3 64.88833844715684+ , HalfStabilityVector 1 True 4.1283 1.0 0.5 4 12.308641587404178+ , HalfStabilityVector 1 False 4.1283 1.0 0.5 4 206.04387240620753+ , HalfStabilityVector 1 True 4.1283 1.0 1.0 1 3.061269519318899+ , HalfStabilityVector 1 False 4.1283 1.0 1.0 1 1.210463465991554+ , HalfStabilityVector 1 True 4.1283 1.0 1.0 2 4.1283+ , HalfStabilityVector 1 False 4.1283 1.0 1.0 2 4.1283+ , HalfStabilityVector 1 True 4.1283 1.0 1.0 3 4.1283+ , HalfStabilityVector 1 False 4.1283 1.0 1.0 3 4.1283+ , HalfStabilityVector 1 True 4.1283 1.0 1.0 4 4.1283+ , HalfStabilityVector 1 False 4.1283 1.0 1.0 4 4.1283+ , HalfStabilityVector 1 True 4.1283 4.194588083372719 0.05 1 4.1283+ , HalfStabilityVector 1 False 4.1283 4.194588083372719 0.05 1 1.3759456301603201+ , HalfStabilityVector 1 True 4.1283 4.194588083372719 0.05 2 4.704483052458797+ , HalfStabilityVector 1 False 4.1283 4.194588083372719 0.05 2 174.8034249916536+ , HalfStabilityVector 1 True 4.1283 4.194588083372719 0.05 3 6.493767965312554+ , HalfStabilityVector 1 False 4.1283 4.194588083372719 0.05 3 278.6986481802898+ , HalfStabilityVector 1 True 4.1283 4.194588083372719 0.05 4 17.137264404743316+ , HalfStabilityVector 1 False 4.1283 4.194588083372719 0.05 4 916.5705965402046+ , HalfStabilityVector 1 True 4.1283 4.194588083372719 0.5 1 2.668858132008376+ , HalfStabilityVector 1 False 4.1283 4.194588083372719 0.5 1 0.3993958996872009+ , HalfStabilityVector 1 True 4.1283 4.194588083372719 0.5 2 4.3748719165250245+ , HalfStabilityVector 1 False 4.1283 4.194588083372719 0.5 2 29.83160989361106+ , HalfStabilityVector 1 True 4.1283 4.194588083372719 0.5 3 5.140578940167846+ , HalfStabilityVector 1 False 4.1283 4.194588083372719 0.5 3 45.4780089703013+ , HalfStabilityVector 1 True 4.1283 4.194588083372719 0.5 4 9.695359412100212+ , HalfStabilityVector 1 False 4.1283 4.194588083372719 0.5 4 141.54016426058237+ , HalfStabilityVector 1 True 4.1283 4.194588083372719 1.0 1 1.5323679443327378+ , HalfStabilityVector 1 False 4.1283 4.194588083372719 1.0 1 0.10104557520813433+ , HalfStabilityVector 1 True 4.1283 4.194588083372719 1.0 2 4.1283+ , HalfStabilityVector 1 False 4.1283 4.194588083372719 1.0 2 4.1283+ , HalfStabilityVector 1 True 4.1283 4.194588083372719 1.0 3 4.1283+ , HalfStabilityVector 1 False 4.1283 4.194588083372719 1.0 3 4.1283+ , HalfStabilityVector 1 True 4.1283 4.194588083372719 1.0 4 4.1283+ , HalfStabilityVector 1 False 4.1283 4.194588083372719 1.0 4 4.1283+ , HalfStabilityVector 1 True 4.1283 10.0 0.05 1 2.891240274328127+ , HalfStabilityVector 1 False 4.1283 10.0 0.05 1 0.30558895896929017+ , HalfStabilityVector 1 True 4.1283 10.0 0.05 2 4.2129654191572214+ , HalfStabilityVector 1 False 4.1283 10.0 0.05 2 29.207623203736222+ , HalfStabilityVector 1 True 4.1283 10.0 0.05 3 4.475886302532715+ , HalfStabilityVector 1 False 4.1283 10.0 0.05 3 44.47418229838777+ , HalfStabilityVector 1 True 4.1283 10.0 0.05 4 6.039861645954045+ , HalfStabilityVector 1 False 4.1283 10.0 0.05 4 138.20428360223949+ , HalfStabilityVector 1 True 4.1283 10.0 0.5 1 1.7547610972495982+ , HalfStabilityVector 1 False 4.1283 10.0 0.5 1 0.0887033430149372+ , HalfStabilityVector 1 True 4.1283 10.0 0.5 2 4.164531740201147+ , HalfStabilityVector 1 False 4.1283 10.0 0.5 2 7.905192597906028+ , HalfStabilityVector 1 True 4.1283 10.0 0.5 3 4.277046167398715+ , HalfStabilityVector 1 False 4.1283 10.0 0.5 3 10.204303844715685+ , HalfStabilityVector 1 True 4.1283 10.0 0.5 4 4.9463341587404175+ , HalfStabilityVector 1 False 4.1283 10.0 0.5 4 24.319857240620756+ , HalfStabilityVector 1 True 4.1283 10.0 1.0 1 1.0075243877290467+ , HalfStabilityVector 1 False 4.1283 10.0 1.0 1 0.022441593228294237+ , HalfStabilityVector 1 True 4.1283 10.0 1.0 2 4.1283+ , HalfStabilityVector 1 False 4.1283 10.0 1.0 2 4.1283+ , HalfStabilityVector 1 True 4.1283 10.0 1.0 3 4.1283+ , HalfStabilityVector 1 False 4.1283 10.0 1.0 3 4.1283+ , HalfStabilityVector 1 True 4.1283 10.0 1.0 4 4.1283+ , HalfStabilityVector 1 False 4.1283 10.0 1.0 4 4.1283+ , HalfStabilityVector 1 True 1000.0 1.0 0.05 1 835.861456174516+ , HalfStabilityVector 1 False 1000.0 1.0 0.05 1 1000.0+ , HalfStabilityVector 1 True 1000.0 1.0 0.05 2 1000.8117394334613+ , HalfStabilityVector 1 False 1000.0 1.0 0.05 2 1113.5789449580627+ , HalfStabilityVector 1 True 1000.0 1.0 0.05 3 1003.3325236100566+ , HalfStabilityVector 1 False 1000.0 1.0 0.05 3 1182.7179588391118+ , HalfStabilityVector 1 True 1000.0 1.0 0.05 4 1018.3273169017377+ , HalfStabilityVector 1 False 1000.0 1.0 0.05 4 1607.2017429676182+ , HalfStabilityVector 1 True 1000.0 1.0 0.5 1 507.30379588610435+ , HalfStabilityVector 1 False 1000.0 1.0 0.5 1 1000.0+ , HalfStabilityVector 1 True 1000.0 1.0 0.5 2 1000.3473759718779+ , HalfStabilityVector 1 False 1000.0 1.0 0.5 2 1017.1047469265908+ , HalfStabilityVector 1 True 1000.0 1.0 0.5 3 1001.4261209695252+ , HalfStabilityVector 1 False 1000.0 1.0 0.5 3 1027.5169349921346+ , HalfStabilityVector 1 True 1000.0 1.0 0.5 4 1007.8429964816538+ , HalfStabilityVector 1 False 1000.0 1.0 0.5 4 1091.4432877562017+ , HalfStabilityVector 1 True 1000.0 1.0 1.0 1 291.2766570582722+ , HalfStabilityVector 1 False 1000.0 1.0 1.0 1 265.49744196083424+ , HalfStabilityVector 1 True 1000.0 1.0 1.0 2 1000.0+ , HalfStabilityVector 1 False 1000.0 1.0 1.0 2 1000.0+ , HalfStabilityVector 1 True 1000.0 1.0 1.0 3 1000.0+ , HalfStabilityVector 1 False 1000.0 1.0 1.0 3 1000.0+ , HalfStabilityVector 1 True 1000.0 1.0 1.0 4 1000.0+ , HalfStabilityVector 1 False 1000.0 1.0 1.0 4 1000.0+ , HalfStabilityVector 1 True 1000.0 4.194588083372719 0.05 1 418.4039638659739+ , HalfStabilityVector 1 False 1000.0 4.194588083372719 0.05 1 301.7935322694836+ , HalfStabilityVector 1 True 1000.0 4.194588083372719 0.05 2 1000.5524221213673+ , HalfStabilityVector 1 False 1000.0 4.194588083372719 0.05 2 1077.2951505495553+ , HalfStabilityVector 1 True 1000.0 4.194588083372719 0.05 3 1002.267919588832+ , HalfStabilityVector 1 False 1000.0 4.194588083372719 0.05 3 1124.3470974465506+ , HalfStabilityVector 1 True 1000.0 4.194588083372719 0.05 4 1012.4724940842891+ , HalfStabilityVector 1 False 1000.0 4.194588083372719 0.05 4 1413.2257977388686+ , HalfStabilityVector 1 True 1000.0 4.194588083372719 0.5 1 253.93911576499895+ , HalfStabilityVector 1 False 1000.0 4.194588083372719 0.5 1 87.60164406096801+ , HalfStabilityVector 1 True 1000.0 4.194588083372719 0.5 2 1000.2364036578568+ , HalfStabilityVector 1 False 1000.0 4.194588083372719 0.5 2 1011.6404848565115+ , HalfStabilityVector 1 True 1000.0 4.194588083372719 0.5 3 1000.9705340640558+ , HalfStabilityVector 1 False 1000.0 4.194588083372719 0.5 3 1018.7264077304529+ , HalfStabilityVector 1 True 1000.0 4.194588083372719 0.5 4 1005.3374821718313+ , HalfStabilityVector 1 False 1000.0 4.194588083372719 0.5 4 1062.2309240191632+ , HalfStabilityVector 1 True 1000.0 4.194588083372719 1.0 1 145.80323927433972+ , HalfStabilityVector 1 False 1000.0 4.194588083372719 1.0 1 22.162867771680386+ , HalfStabilityVector 1 True 1000.0 4.194588083372719 1.0 2 1000.0+ , HalfStabilityVector 1 False 1000.0 4.194588083372719 1.0 2 1000.0+ , HalfStabilityVector 1 True 1000.0 4.194588083372719 1.0 3 1000.0+ , HalfStabilityVector 1 False 1000.0 4.194588083372719 1.0 3 1000.0+ , HalfStabilityVector 1 True 1000.0 4.194588083372719 1.0 4 1000.0+ , HalfStabilityVector 1 False 1000.0 4.194588083372719 1.0 4 1000.0+ , HalfStabilityVector 1 True 1000.0 10.0 0.05 1 275.09854867202563+ , HalfStabilityVector 1 False 1000.0 10.0 0.05 1 67.02646480235609+ , HalfStabilityVector 1 True 1000.0 10.0 0.05 2 1000.0811739433461+ , HalfStabilityVector 1 False 1000.0 10.0 0.05 2 1011.3578944958061+ , HalfStabilityVector 1 True 1000.0 10.0 0.05 3 1000.3332523610055+ , HalfStabilityVector 1 False 1000.0 10.0 0.05 3 1018.2717958839112+ , HalfStabilityVector 1 True 1000.0 10.0 0.05 4 1001.8327316901739+ , HalfStabilityVector 1 False 1000.0 10.0 0.05 4 1060.7201742967618+ , HalfStabilityVector 1 True 1000.0 10.0 0.5 1 166.96371982839585+ , HalfStabilityVector 1 False 1000.0 10.0 0.5 1 19.45577981120545+ , HalfStabilityVector 1 True 1000.0 10.0 0.5 2 1000.0347375971878+ , HalfStabilityVector 1 False 1000.0 10.0 0.5 2 1001.7104746926591+ , HalfStabilityVector 1 True 1000.0 10.0 0.5 3 1000.1426120969526+ , HalfStabilityVector 1 False 1000.0 10.0 0.5 3 1002.7516934992136+ , HalfStabilityVector 1 True 1000.0 10.0 0.5 4 1000.7842996481653+ , HalfStabilityVector 1 False 1000.0 10.0 0.5 4 1009.1443287756201+ , HalfStabilityVector 1 True 1000.0 10.0 1.0 1 95.86491281162755+ , HalfStabilityVector 1 False 1000.0 10.0 1.0 1 4.922234964569572+ , HalfStabilityVector 1 True 1000.0 10.0 1.0 2 1000.0+ , HalfStabilityVector 1 False 1000.0 10.0 1.0 2 1000.0+ , HalfStabilityVector 1 True 1000.0 10.0 1.0 3 1000.0+ , HalfStabilityVector 1 False 1000.0 10.0 1.0 3 1000.0+ , HalfStabilityVector 1 True 1000.0 10.0 1.0 4 1000.0+ , HalfStabilityVector 1 False 1000.0 10.0 1.0 4 1000.0+ , HalfStabilityVector 2 True 0.01 1.0 0.05 1 0.006294554510381623+ , HalfStabilityVector 2 False 0.01 1.0 0.05 1 0.01+ , HalfStabilityVector 2 True 0.01 1.0 0.05 2 48.410168671017125+ , HalfStabilityVector 2 False 0.01 1.0 0.05 2 176.70182400119643+ , HalfStabilityVector 2 True 0.01 1.0 0.05 3 81.34716603314163+ , HalfStabilityVector 2 False 0.01 1.0 0.05 3 183.09667539955197+ , HalfStabilityVector 2 True 0.01 1.0 0.05 4 565.4654902394044+ , HalfStabilityVector 2 False 0.01 1.0 0.05 4 1191.872399769564+ , HalfStabilityVector 2 True 0.01 1.0 0.5 1 0.0039437097695426936+ , HalfStabilityVector 2 False 0.01 1.0 0.5 1 0.01+ , HalfStabilityVector 2 True 0.01 1.0 0.5 2 13.502619862518062+ , HalfStabilityVector 2 False 0.01 1.0 0.5 2 47.7074964323397+ , HalfStabilityVector 2 True 0.01 1.0 0.5 3 22.684537963684193+ , HalfStabilityVector 2 False 0.01 1.0 0.5 3 49.43376986622729+ , HalfStabilityVector 2 True 0.01 1.0 0.5 4 157.64325187630473+ , HalfStabilityVector 2 False 0.01 1.0 0.5 4 321.75014209318294+ , HalfStabilityVector 2 True 0.01 1.0 1.0 1 0.0023457550809011848+ , HalfStabilityVector 2 False 0.01 1.0 1.0 1 0.006367437953152754+ , HalfStabilityVector 2 True 0.01 1.0 1.0 2 0.01+ , HalfStabilityVector 2 False 0.01 1.0 1.0 2 0.01+ , HalfStabilityVector 2 True 0.01 1.0 1.0 3 0.01+ , HalfStabilityVector 2 False 0.01 1.0 1.0 3 0.01+ , HalfStabilityVector 2 True 0.01 1.0 1.0 4 0.01+ , HalfStabilityVector 2 False 0.01 1.0 1.0 4 0.01+ , HalfStabilityVector 2 True 0.01 4.194588083372719 0.05 1 0.0018986489589857918+ , HalfStabilityVector 2 False 0.01 4.194588083372719 0.05 1 0.01+ , HalfStabilityVector 2 True 0.01 4.194588083372719 0.05 2 32.94830846405103+ , HalfStabilityVector 2 False 0.01 4.194588083372719 0.05 2 120.25606446283523+ , HalfStabilityVector 2 True 0.01 4.194588083372719 0.05 3 55.36329189866338+ , HalfStabilityVector 2 False 0.01 4.194588083372719 0.05 3 124.60802425397817+ , HalfStabilityVector 2 True 0.01 4.194588083372719 0.05 4 384.82575315975635+ , HalfStabilityVector 2 False 0.01 4.194588083372719 0.05 4 811.1214578371778+ , HalfStabilityVector 2 True 0.01 4.194588083372719 0.5 1 0.0011895552633843772+ , HalfStabilityVector 2 False 0.01 4.194588083372719 0.5 1 0.01+ , HalfStabilityVector 2 True 0.01 4.194588083372719 0.5 2 9.192283599890237+ , HalfStabilityVector 2 False 0.01 4.194588083372719 0.5 2 32.47011106139318+ , HalfStabilityVector 2 True 0.01 4.194588083372719 0.5 3 15.440957086207408+ , HalfStabilityVector 2 False 0.01 4.194588083372719 0.5 3 33.644911241226744+ , HalfStabilityVector 2 True 0.01 4.194588083372719 0.5 4 107.28592107757139+ , HalfStabilityVector 2 False 0.01 4.194588083372719 0.5 4 218.96741970583014+ , HalfStabilityVector 2 True 0.01 4.194588083372719 1.0 1 0.0007075584832958489+ , HalfStabilityVector 2 False 0.01 4.194588083372719 1.0 1 0.003983438697046004+ , HalfStabilityVector 2 True 0.01 4.194588083372719 1.0 2 0.01+ , HalfStabilityVector 2 False 0.01 4.194588083372719 1.0 2 0.01+ , HalfStabilityVector 2 True 0.01 4.194588083372719 1.0 3 0.01+ , HalfStabilityVector 2 False 0.01 4.194588083372719 1.0 3 0.01+ , HalfStabilityVector 2 True 0.01 4.194588083372719 1.0 4 0.01+ , HalfStabilityVector 2 False 0.01 4.194588083372719 1.0 4 0.01+ , HalfStabilityVector 2 True 0.01 10.0 0.05 1 0.000918421408993407+ , HalfStabilityVector 2 False 0.01 10.0 0.05 1 0.01+ , HalfStabilityVector 2 True 0.01 10.0 0.05 2 4.850016867101713+ , HalfStabilityVector 2 False 0.01 10.0 0.05 2 17.679182400119643+ , HalfStabilityVector 2 True 0.01 10.0 0.05 3 8.143716603314163+ , HalfStabilityVector 2 False 0.01 10.0 0.05 3 18.318667539955197+ , HalfStabilityVector 2 True 0.01 10.0 0.05 4 56.55554902394044+ , HalfStabilityVector 2 False 0.01 10.0 0.05 4 119.19623997695636+ , HalfStabilityVector 2 True 0.01 10.0 0.5 1 0.0005754160166904127+ , HalfStabilityVector 2 False 0.01 10.0 0.5 1 0.01+ , HalfStabilityVector 2 True 0.01 10.0 0.5 2 1.359261986251806+ , HalfStabilityVector 2 False 0.01 10.0 0.5 2 4.77974964323397+ , HalfStabilityVector 2 True 0.01 10.0 0.5 3 2.277453796368419+ , HalfStabilityVector 2 False 0.01 10.0 0.5 3 4.9523769866227285+ , HalfStabilityVector 2 True 0.01 10.0 0.5 4 15.773325187630471+ , HalfStabilityVector 2 False 0.01 10.0 0.5 4 32.18401420931829+ , HalfStabilityVector 2 True 0.01 10.0 1.0 1 0.00034226277379939535+ , HalfStabilityVector 2 False 0.01 10.0 1.0 1 0.0029979523217426437+ , HalfStabilityVector 2 True 0.01 10.0 1.0 2 0.01+ , HalfStabilityVector 2 False 0.01 10.0 1.0 2 0.01+ , HalfStabilityVector 2 True 0.01 10.0 1.0 3 0.01+ , HalfStabilityVector 2 False 0.01 10.0 1.0 3 0.01+ , HalfStabilityVector 2 True 0.01 10.0 1.0 4 0.01+ , HalfStabilityVector 2 False 0.01 10.0 1.0 4 0.01+ , HalfStabilityVector 2 True 1.0 1.0 0.05 1 0.49052484188063894+ , HalfStabilityVector 2 False 1.0 1.0 0.05 1 1.0+ , HalfStabilityVector 2 True 1.0 1.0 0.05 2 151.41421279521114+ , HalfStabilityVector 2 False 1.0 1.0 0.05 2 493.74298943643595+ , HalfStabilityVector 2 True 1.0 1.0 0.05 3 253.77320587509604+ , HalfStabilityVector 2 False 1.0 1.0 0.05 3 511.5764020056907+ , HalfStabilityVector 2 True 1.0 1.0 0.05 4 1758.2778106044325+ , HalfStabilityVector 2 False 1.0 1.0 0.05 4 3324.7635367630974+ , HalfStabilityVector 2 True 1.0 1.0 0.5 1 0.307327167941354+ , HalfStabilityVector 2 False 1.0 1.0 0.5 1 1.0+ , HalfStabilityVector 2 True 1.0 1.0 0.5 2 42.9312959208957+ , HalfStabilityVector 2 False 1.0 1.0 0.5 2 134.01468312730566+ , HalfStabilityVector 2 True 1.0 1.0 0.5 3 71.46613414686298+ , HalfStabilityVector 2 False 1.0 1.0 0.5 3 138.8287662757863+ , HalfStabilityVector 2 True 1.0 1.0 0.5 4 490.8801417921866+ , HalfStabilityVector 2 False 1.0 1.0 0.5 4 898.2412862500369+ , HalfStabilityVector 2 True 1.0 1.0 1.0 1 0.18280104465724897+ , HalfStabilityVector 2 False 1.0 1.0 1.0 1 0.5715613943040697+ , HalfStabilityVector 2 True 1.0 1.0 1.0 2 1.0+ , HalfStabilityVector 2 False 1.0 1.0 1.0 2 1.0+ , HalfStabilityVector 2 True 1.0 1.0 1.0 3 1.0+ , HalfStabilityVector 2 False 1.0 1.0 1.0 3 1.0+ , HalfStabilityVector 2 True 1.0 1.0 1.0 4 1.0+ , HalfStabilityVector 2 False 1.0 1.0 1.0 4 1.0+ , HalfStabilityVector 2 True 1.0 4.194588083372719 0.05 1 0.1479587600452571+ , HalfStabilityVector 2 False 1.0 4.194588083372719 0.05 1 1.0+ , HalfStabilityVector 2 True 1.0 4.194588083372719 0.05 2 103.36306761866416+ , HalfStabilityVector 2 False 1.0 4.194588083372719 0.05 2 336.33190121452714+ , HalfStabilityVector 2 True 1.0 4.194588083372719 0.05 3 173.02257874664596+ , HalfStabilityVector 2 False 1.0 4.194588083372719 0.05 3 348.4682730558208+ , HalfStabilityVector 2 True 1.0 4.194588083372719 0.05 4 1196.8999353112104+ , HalfStabilityVector 2 False 1.0 4.194588083372719 0.05 4 2262.957998113882+ , HalfStabilityVector 2 True 1.0 4.194588083372719 0.5 1 0.09270019133483157+ , HalfStabilityVector 2 False 1.0 4.194588083372719 0.5 1 1.0+ , HalfStabilityVector 2 True 1.0 4.194588083372719 0.5 2 29.53597409396885+ , HalfStabilityVector 2 False 1.0 4.194588083372719 0.5 2 91.52197096409675+ , HalfStabilityVector 2 True 1.0 4.194588083372719 0.5 3 48.95510690417179+ , HalfStabilityVector 2 False 1.0 4.194588083372719 0.5 3 94.79815284672723+ , HalfStabilityVector 2 True 1.0 4.194588083372719 0.5 4 334.3836154671609+ , HalfStabilityVector 2 False 1.0 4.194588083372719 0.5 4 611.609654153599+ , HalfStabilityVector 2 True 1.0 4.194588083372719 1.0 1 0.05513893200345941+ , HalfStabilityVector 2 False 1.0 4.194588083372719 1.0 1 0.35756607171666005+ , HalfStabilityVector 2 True 1.0 4.194588083372719 1.0 2 1.0+ , HalfStabilityVector 2 False 1.0 4.194588083372719 1.0 2 1.0+ , HalfStabilityVector 2 True 1.0 4.194588083372719 1.0 3 1.0+ , HalfStabilityVector 2 False 1.0 4.194588083372719 1.0 3 1.0+ , HalfStabilityVector 2 True 1.0 4.194588083372719 1.0 4 1.0+ , HalfStabilityVector 2 False 1.0 4.194588083372719 1.0 4 1.0+ , HalfStabilityVector 2 True 1.0 10.0 0.05 1 0.07157115180800482+ , HalfStabilityVector 2 False 1.0 10.0 0.05 1 1.0+ , HalfStabilityVector 2 True 1.0 10.0 0.05 2 16.041421279521117+ , HalfStabilityVector 2 False 1.0 10.0 0.05 2 50.27429894364359+ , HalfStabilityVector 2 True 1.0 10.0 0.05 3 26.277320587509603+ , HalfStabilityVector 2 False 1.0 10.0 0.05 3 52.05764020056907+ , HalfStabilityVector 2 True 1.0 10.0 0.05 4 176.72778106044325+ , HalfStabilityVector 2 False 1.0 10.0 0.05 4 333.37635367630975+ , HalfStabilityVector 2 True 1.0 10.0 0.5 1 0.04484127512711607+ , HalfStabilityVector 2 False 1.0 10.0 0.5 1 1.0+ , HalfStabilityVector 2 True 1.0 10.0 0.5 2 5.19312959208957+ , HalfStabilityVector 2 False 1.0 10.0 0.5 2 14.301468312730565+ , HalfStabilityVector 2 True 1.0 10.0 0.5 3 8.046613414686298+ , HalfStabilityVector 2 False 1.0 10.0 0.5 3 14.78287662757863+ , HalfStabilityVector 2 True 1.0 10.0 0.5 4 49.98801417921866+ , HalfStabilityVector 2 False 1.0 10.0 0.5 4 90.72412862500369+ , HalfStabilityVector 2 True 1.0 10.0 1.0 1 0.026672005576038556+ , HalfStabilityVector 2 False 1.0 10.0 1.0 1 0.26910569395088085+ , HalfStabilityVector 2 True 1.0 10.0 1.0 2 1.0+ , HalfStabilityVector 2 False 1.0 10.0 1.0 2 1.0+ , HalfStabilityVector 2 True 1.0 10.0 1.0 3 1.0+ , HalfStabilityVector 2 False 1.0 10.0 1.0 3 1.0+ , HalfStabilityVector 2 True 1.0 10.0 1.0 4 1.0+ , HalfStabilityVector 2 False 1.0 10.0 1.0 4 1.0+ , HalfStabilityVector 2 True 4.1283 1.0 0.05 1 1.3592214337511979+ , HalfStabilityVector 2 False 4.1283 1.0 0.05 1 4.1283+ , HalfStabilityVector 2 True 4.1283 1.0 0.05 2 217.38598378253639+ , HalfStabilityVector 2 False 4.1283 1.0 0.05 2 679.8283372044299+ , HalfStabilityVector 2 True 4.1283 1.0 0.05 3 362.51084514287123+ , HalfStabilityVector 2 False 4.1283 1.0 0.05 3 704.283352891836+ , HalfStabilityVector 2 True 4.1283 1.0 0.05 4 2495.60160353797+ , HalfStabilityVector 2 False 4.1283 1.0 0.05 4 4562.015867346649+ , HalfStabilityVector 2 True 4.1283 1.0 0.5 1 0.8515892329497738+ , HalfStabilityVector 2 False 4.1283 1.0 0.5 1 4.1283+ , HalfStabilityVector 2 True 4.1283 1.0 0.5 2 63.57860645651215+ , HalfStabilityVector 2 False 4.1283 1.0 0.5 2 186.53176035293558+ , HalfStabilityVector 2 True 4.1283 1.0 0.5 3 104.03537842037076+ , HalfStabilityVector 2 False 4.1283 1.0 0.5 3 193.13332796986708+ , HalfStabilityVector 2 True 4.1283 1.0 0.5 4 698.681709735947+ , HalfStabilityVector 2 False 4.1283 1.0 0.5 4 1234.518145208968+ , HalfStabilityVector 2 True 4.1283 1.0 1.0 1 0.5065331595799241+ , HalfStabilityVector 2 False 4.1283 1.0 1.0 1 1.9736119841548887+ , HalfStabilityVector 2 True 4.1283 1.0 1.0 2 4.1283+ , HalfStabilityVector 2 False 4.1283 1.0 1.0 2 4.1283+ , HalfStabilityVector 2 True 4.1283 1.0 1.0 3 4.1283+ , HalfStabilityVector 2 False 4.1283 1.0 1.0 3 4.1283+ , HalfStabilityVector 2 True 4.1283 1.0 1.0 4 4.1283+ , HalfStabilityVector 2 False 4.1283 1.0 1.0 4 4.1283+ , HalfStabilityVector 2 True 4.1283 4.194588083372719 0.05 1 0.4099868157415364+ , HalfStabilityVector 2 False 4.1283 4.194588083372719 0.05 1 4.1283+ , HalfStabilityVector 2 True 4.1283 4.194588083372719 0.05 2 149.25893825260056+ , HalfStabilityVector 2 False 4.1283 4.194588083372719 0.05 2 463.9700085256525+ , HalfStabilityVector 2 True 4.1283 4.194588083372719 0.05 3 248.022384342651+ , HalfStabilityVector 2 False 4.1283 4.194588083372719 0.05 3 480.61265404369044+ , HalfStabilityVector 2 True 4.1283 4.194588083372719 0.05 4 1699.6785109856037+ , HalfStabilityVector 2 False 4.1283 4.194588083372719 0.05 4 3105.9585365468215+ , HalfStabilityVector 2 True 4.1283 4.194588083372719 0.5 1 0.25686790192330394+ , HalfStabilityVector 2 False 4.1283 4.194588083372719 0.5 1 4.1283+ , HalfStabilityVector 2 True 4.1283 4.194588083372719 0.5 2 44.58668240062915+ , HalfStabilityVector 2 False 4.1283 4.194588083372719 0.5 2 128.26136827199196+ , HalfStabilityVector 2 True 4.1283 4.194588083372719 0.5 3 72.11918220374075+ , HalfStabilityVector 2 False 4.1283 4.194588083372719 0.5 3 132.75400696486057+ , HalfStabilityVector 2 True 4.1283 4.194588083372719 0.5 4 476.8005051351125+ , HalfStabilityVector 2 False 4.1283 4.194588083372719 0.5 4 841.4592714682307+ , HalfStabilityVector 2 True 4.1283 4.194588083372719 1.0 1 0.15278740608918798+ , HalfStabilityVector 2 False 4.1283 4.194588083372719 1.0 1 1.234682207895513+ , HalfStabilityVector 2 True 4.1283 4.194588083372719 1.0 2 4.1283+ , HalfStabilityVector 2 False 4.1283 4.194588083372719 1.0 2 4.1283+ , HalfStabilityVector 2 True 4.1283 4.194588083372719 1.0 3 4.1283+ , HalfStabilityVector 2 False 4.1283 4.194588083372719 1.0 3 4.1283+ , HalfStabilityVector 2 True 4.1283 4.194588083372719 1.0 4 4.1283+ , HalfStabilityVector 2 False 4.1283 4.194588083372719 1.0 4 4.1283+ , HalfStabilityVector 2 True 4.1283 10.0 0.05 1 0.19832031993065227+ , HalfStabilityVector 2 False 4.1283 10.0 0.05 1 4.1283+ , HalfStabilityVector 2 True 4.1283 10.0 0.05 2 25.45406837825364+ , HalfStabilityVector 2 False 4.1283 10.0 0.05 2 71.698303720443+ , HalfStabilityVector 2 True 4.1283 10.0 0.05 3 39.966554514287125+ , HalfStabilityVector 2 False 4.1283 10.0 0.05 3 74.14380528918359+ , HalfStabilityVector 2 True 4.1283 10.0 0.05 4 253.275630353797+ , HalfStabilityVector 2 False 4.1283 10.0 0.05 4 459.9170567346648+ , HalfStabilityVector 2 True 4.1283 10.0 0.5 1 0.12425307969283564+ , HalfStabilityVector 2 False 4.1283 10.0 0.5 1 4.1283+ , HalfStabilityVector 2 True 4.1283 10.0 0.5 2 10.073330645651216+ , HalfStabilityVector 2 False 4.1283 10.0 0.5 2 22.368646035293555+ , HalfStabilityVector 2 True 4.1283 10.0 0.5 3 14.119007842037076+ , HalfStabilityVector 2 False 4.1283 10.0 0.5 3 23.028802796986707+ , HalfStabilityVector 2 True 4.1283 10.0 0.5 4 73.58364097359471+ , HalfStabilityVector 2 False 4.1283 10.0 0.5 4 127.16728452089679+ , HalfStabilityVector 2 True 4.1283 10.0 1.0 1 0.07390688210833708+ , HalfStabilityVector 2 False 4.1283 10.0 1.0 1 0.929226899994625+ , HalfStabilityVector 2 True 4.1283 10.0 1.0 2 4.1283+ , HalfStabilityVector 2 False 4.1283 10.0 1.0 2 4.1283+ , HalfStabilityVector 2 True 4.1283 10.0 1.0 3 4.1283+ , HalfStabilityVector 2 False 4.1283 10.0 1.0 3 4.1283+ , HalfStabilityVector 2 True 4.1283 10.0 1.0 4 4.1283+ , HalfStabilityVector 2 False 4.1283 10.0 1.0 4 4.1283+ , HalfStabilityVector 2 True 1000.0 1.0 0.05 1 16.1999120360543+ , HalfStabilityVector 2 False 1000.0 1.0 0.05 1 1000.0+ , HalfStabilityVector 2 True 1000.0 1.0 0.05 2 1824.0467960051703+ , HalfStabilityVector 2 False 1000.0 1.0 0.05 2 3294.70284462841+ , HalfStabilityVector 2 True 1000.0 1.0 0.05 3 2384.822262115112+ , HalfStabilityVector 2 False 1000.0 1.0 0.05 3 3377.7530014635277+ , HalfStabilityVector 2 True 1000.0 1.0 0.05 4 10627.276057290686+ , HalfStabilityVector 2 False 1000.0 1.0 0.05 4 16478.758310505313+ , HalfStabilityVector 2 True 1000.0 1.0 0.5 1 10.14968593201463+ , HalfStabilityVector 2 False 1000.0 1.0 0.5 1 682.9483757192087+ , HalfStabilityVector 2 True 1000.0 1.0 0.5 2 1229.7213103325757+ , HalfStabilityVector 2 False 1000.0 1.0 0.5 2 1619.449039952195+ , HalfStabilityVector 2 True 1000.0 1.0 0.5 3 1386.049901744669+ , HalfStabilityVector 2 False 1000.0 1.0 0.5 3 1641.8682128920898+ , HalfStabilityVector 2 True 1000.0 1.0 0.5 4 3683.816600629527+ , HalfStabilityVector 2 False 1000.0 1.0 0.5 4 5178.450380858463+ , HalfStabilityVector 2 True 1000.0 1.0 1.0 1 6.037127155869641+ , HalfStabilityVector 2 False 1000.0 1.0 1.0 1 122.03876889929109+ , HalfStabilityVector 2 True 1000.0 1.0 1.0 2 1000.0+ , HalfStabilityVector 2 False 1000.0 1.0 1.0 2 1000.0+ , HalfStabilityVector 2 True 1000.0 1.0 1.0 3 1000.0+ , HalfStabilityVector 2 False 1000.0 1.0 1.0 3 1000.0+ , HalfStabilityVector 2 True 1000.0 1.0 1.0 4 1000.0+ , HalfStabilityVector 2 False 1000.0 1.0 1.0 4 1000.0+ , HalfStabilityVector 2 True 1000.0 4.194588083372719 0.05 1 4.886437328040729+ , HalfStabilityVector 2 False 1000.0 4.194588083372719 0.05 1 1000.0+ , HalfStabilityVector 2 True 1000.0 4.194588083372719 0.05 2 1560.7977885392115+ , HalfStabilityVector 2 False 1000.0 4.194588083372719 0.05 2 2561.63980839527+ , HalfStabilityVector 2 True 1000.0 4.194588083372719 0.05 3 1942.428592500893+ , HalfStabilityVector 2 False 1000.0 4.194588083372719 0.05 3 2618.1588610956173+ , HalfStabilityVector 2 True 1000.0 4.194588083372719 0.05 4 7551.757920494653+ , HalfStabilityVector 2 False 1000.0 4.194588083372719 0.05 4 11533.932626090638+ , HalfStabilityVector 2 True 1000.0 4.194588083372719 0.5 1 3.061486018918276+ , HalfStabilityVector 2 False 1000.0 4.194588083372719 0.5 1 427.24923398391303+ , HalfStabilityVector 2 True 1000.0 4.194588083372719 0.5 2 1156.3348142840543+ , HalfStabilityVector 2 False 1000.0 4.194588083372719 0.5 2 1421.5605878233996+ , HalfStabilityVector 2 True 1000.0 4.194588083372719 0.5 3 1262.722860174596+ , HalfStabilityVector 2 False 1000.0 4.194588083372719 0.5 3 1436.8177584920086+ , HalfStabilityVector 2 True 1000.0 4.194588083372719 0.5 4 2826.44774759663+ , HalfStabilityVector 2 False 1000.0 4.194588083372719 0.5 4 3843.6076014929977+ , HalfStabilityVector 2 True 1000.0 4.194588083372719 1.0 1 1.821000226600915+ , HalfStabilityVector 2 False 1000.0 4.194588083372719 1.0 1 76.34686951799625+ , HalfStabilityVector 2 True 1000.0 4.194588083372719 1.0 2 1000.0+ , HalfStabilityVector 2 False 1000.0 4.194588083372719 1.0 2 1000.0+ , HalfStabilityVector 2 True 1000.0 4.194588083372719 1.0 3 1000.0+ , HalfStabilityVector 2 False 1000.0 4.194588083372719 1.0 3 1000.0+ , HalfStabilityVector 2 True 1000.0 4.194588083372719 1.0 4 1000.0+ , HalfStabilityVector 2 False 1000.0 4.194588083372719 1.0 4 1000.0+ , HalfStabilityVector 2 True 1000.0 10.0 0.05 1 2.363685311356562+ , HalfStabilityVector 2 False 1000.0 10.0 0.05 1 1000.0+ , HalfStabilityVector 2 True 1000.0 10.0 0.05 2 1082.404679600517+ , HalfStabilityVector 2 False 1000.0 10.0 0.05 2 1229.470284462841+ , HalfStabilityVector 2 True 1000.0 10.0 0.05 3 1138.482226211511+ , HalfStabilityVector 2 False 1000.0 10.0 0.05 3 1237.7753001463527+ , HalfStabilityVector 2 True 1000.0 10.0 0.05 4 1962.7276057290683+ , HalfStabilityVector 2 False 1000.0 10.0 0.05 4 2547.875831050531+ , HalfStabilityVector 2 True 1000.0 10.0 0.5 1 1.480913198725526+ , HalfStabilityVector 2 False 1000.0 10.0 0.5 1 321.5495280333281+ , HalfStabilityVector 2 True 1000.0 10.0 0.5 2 1022.9721310332576+ , HalfStabilityVector 2 False 1000.0 10.0 0.5 2 1061.9449039952196+ , HalfStabilityVector 2 True 1000.0 10.0 0.5 3 1038.604990174467+ , HalfStabilityVector 2 False 1000.0 10.0 0.5 3 1064.1868212892089+ , HalfStabilityVector 2 True 1000.0 10.0 0.5 4 1268.3816600629525+ , HalfStabilityVector 2 False 1000.0 10.0 0.5 4 1417.8450380858462+ , HalfStabilityVector 2 True 1000.0 10.0 1.0 1 0.8808608805629355+ , HalfStabilityVector 2 False 1000.0 10.0 1.0 1 57.458967524464+ , HalfStabilityVector 2 True 1000.0 10.0 1.0 2 1000.0+ , HalfStabilityVector 2 False 1000.0 10.0 1.0 2 1000.0+ , HalfStabilityVector 2 True 1000.0 10.0 1.0 3 1000.0+ , HalfStabilityVector 2 False 1000.0 10.0 1.0 3 1000.0+ , HalfStabilityVector 2 True 1000.0 10.0 1.0 4 1000.0+ , HalfStabilityVector 2 False 1000.0 10.0 1.0 4 1000.0+ ]++-- | The long-\/short-term blending coefficient.+data TransitionVector = TransitionVector+ { tvParams :: !Int+ , tvElapsedDays :: !Double+ , tvCoefficient :: !Double+ }+ deriving stock (Eq, Show)++goldenTransitionVectors :: [TransitionVector]+goldenTransitionVectors =+ [ TransitionVector 0 0.0 0.0+ , TransitionVector 0 1.1574074074074073e-5 2.8934766566734993e-5+ , TransitionVector 0 0.0006944444444444445 0.0017346049419677545+ , TransitionVector 0 0.006944444444444444 0.0172112753795709+ , TransitionVector 0 0.25 0.4647385714810097+ , TransitionVector 0 1.0 0.9179150013761012+ , TransitionVector 0 3.0 0.9994469156298522+ , TransitionVector 0 7.5 0.9999999928058669+ , TransitionVector 0 30.0 1.0+ , TransitionVector 0 365.0 1.0+ , TransitionVector 0 3650.0 1.0+ , TransitionVector 1 0.0 0.410307+ , TransitionVector 1 1.1574074074074073e-5 0.4103913084279295+ , TransitionVector 1 0.0006944444444444445 0.41534422969275386+ , TransitionVector 1 0.006944444444444444 0.45878646256833155+ , TransitionVector 1 0.25 0.9731241379424495+ , TransitionVector 1 1.0 0.9999974556802093+ , TransitionVector 1 3.0 1.0+ , TransitionVector 1 7.5 1.0+ , TransitionVector 1 30.0 1.0+ , TransitionVector 1 365.0 1.0+ , TransitionVector 1 3650.0 1.0+ , TransitionVector 2 0.0 0.561569+ , TransitionVector 2 1.1574074074074073e-5 0.5615970916424434+ , TransitionVector 2 0.0006944444444444445 0.5632513166324914+ , TransitionVector 2 0.006944444444444444 0.5781046317970904+ , TransitionVector 2 0.25 0.8901430906590875+ , TransitionVector 2 1.0 0.9982717532681704+ , TransitionVector 2 3.0 0.999999973145645+ , TransitionVector 2 7.5 1.0+ , TransitionVector 2 30.0 1.0+ , TransitionVector 2 365.0 1.0+ , TransitionVector 2 3650.0 1.0+ ]++-- | A full memory-state transition.+data StepVector = StepVector+ { svParams :: !Int+ , svState :: !(Maybe (Double, Double))+ -- ^ @(stability, difficulty)@; 'Nothing' for the first review.+ , svElapsedDays :: !Double+ , svRating :: !Int+ , svNextState :: !(Double, Double)+ }+ deriving stock (Eq, Show)++goldenStepVectors :: [StepVector]+goldenStepVectors =+ [ StepVector 0 Nothing 0.0 1 (0.041, 5.6385)+ , StepVector 0 Nothing 0.0 2 (2.4175, 5.075198392303237)+ , StepVector 0 Nothing 0.0 3 (4.1283, 4.194588083372719)+ , StepVector 0 Nothing 0.0 4 (11.9709, 2.817928571667297)+ , StepVector 0 (Just (0.0001, 1.0)) 0.0 1 (0.0001, 7.476939285716673)+ , StepVector 0 (Just (0.0001, 1.0)) 0.0 2 (0.0001, 4.247559285716673)+ , StepVector 0 (Just (0.0001, 1.0)) 0.0 3 (0.0001, 1.018179285716673)+ , StepVector 0 (Just (0.0001, 1.0)) 0.0 4 (0.0001, 1.0)+ , StepVector 0 (Just (0.0001, 1.0)) 0.006944444444444444 1 (0.0001, 7.476939285716673)+ , StepVector 0 (Just (0.0001, 1.0)) 0.006944444444444444 2 (0.042815393880189796, 4.247559285716673)+ , StepVector 0 (Just (0.0001, 1.0)) 0.006944444444444444 3 (0.0764154303138622, 1.018179285716673)+ , StepVector 0 (Just (0.0001, 1.0)) 0.006944444444444444 4 (0.09931005940802089, 1.0)+ , StepVector 0 (Just (0.0001, 1.0)) 0.5 1 (0.0001, 7.476939285716673)+ , StepVector 0 (Just (0.0001, 1.0)) 0.5 2 (0.02687991895595657, 4.247559285716673)+ , StepVector 0 (Just (0.0001, 1.0)) 0.5 3 (0.045684811910156525, 1.018179285716673)+ , StepVector 0 (Just (0.0001, 1.0)) 0.5 4 (0.05936025548320348, 1.0)+ , StepVector 0 (Just (0.0001, 1.0)) 1.0 1 (0.0001, 7.476939285716673)+ , StepVector 0 (Just (0.0001, 1.0)) 1.0 2 (0.01659503714401098, 4.247559285716673)+ , StepVector 0 (Just (0.0001, 1.0)) 1.0 3 (0.026557084707377977, 1.018179285716673)+ , StepVector 0 (Just (0.0001, 1.0)) 1.0 4 (0.03449421011959137, 1.0)+ , StepVector 0 (Just (0.0001, 1.0)) 45.0 1 (0.0001, 7.476939285716673)+ , StepVector 0 (Just (0.0001, 1.0)) 45.0 2 (0.013623815415699077, 4.247559285716673)+ , StepVector 0 (Just (0.0001, 1.0)) 45.0 3 (0.02051330628784766, 1.018179285716673)+ , StepVector 0 (Just (0.0001, 1.0)) 45.0 4 (0.02663729817420196, 1.0)+ , StepVector 0 (Just (0.0001, 1.0)) 400.0 1 (0.0001, 7.476939285716673)+ , StepVector 0 (Just (0.0001, 1.0)) 400.0 2 (0.014428231476499855, 4.247559285716673)+ , StepVector 0 (Just (0.0001, 1.0)) 400.0 3 (0.021727519209811103, 1.018179285716673)+ , StepVector 0 (Just (0.0001, 1.0)) 400.0 4 (0.028215774972754435, 1.0)+ , StepVector 0 (Just (0.0001, 4.194588083372719)) 0.0 1 (0.0001, 8.347017296104067)+ , StepVector 0 (Just (0.0001, 4.194588083372719)) 0.0 2 (0.0001, 6.263919392179866)+ , StepVector 0 (Just (0.0001, 4.194588083372719)) 0.0 3 (0.0001, 4.180821488255665)+ , StepVector 0 (Just (0.0001, 4.194588083372719)) 0.0 4 (0.0001, 2.097723584331464)+ , StepVector 0 (Just (0.0001, 4.194588083372719)) 0.006944444444444444 1 (0.0001, 8.347017296104067)+ , StepVector 0 (Just (0.0001, 4.194588083372719)) 0.006944444444444444 2 (0.029169585053567166, 6.263919392179866)+ , StepVector 0 (Just (0.0001, 4.194588083372719)) 0.006944444444444444 3 (0.05203579388804967, 4.180821488255665)+ , StepVector 0 (Just (0.0001, 4.194588083372719)) 0.006944444444444444 4 (0.06761653205446458, 2.097723584331464)+ , StepVector 0 (Just (0.0001, 4.194588083372719)) 0.5 1 (0.0001, 8.347017296104067)+ , StepVector 0 (Just (0.0001, 4.194588083372719)) 0.5 2 (0.018324837958917966, 6.263919392179866)+ , StepVector 0 (Just (0.0001, 4.194588083372719)) 0.5 3 (0.031122342219059244, 4.180821488255665)+ , StepVector 0 (Just (0.0001, 4.194588083372719)) 0.5 4 (0.04042904488477702, 2.097723584331464)+ , StepVector 0 (Just (0.0001, 4.194588083372719)) 1.0 1 (0.0001, 8.347017296104067)+ , StepVector 0 (Just (0.0001, 4.194588083372719)) 1.0 2 (0.011325552234506195, 6.263919392179866)+ , StepVector 0 (Just (0.0001, 4.194588083372719)) 1.0 3 (0.01810513595468075, 4.180821488255665)+ , StepVector 0 (Just (0.0001, 4.194588083372719)) 1.0 4 (0.023506676741084975, 2.097723584331464)+ , StepVector 0 (Just (0.0001, 4.194588083372719)) 45.0 1 (0.0001, 8.347017296104067)+ , StepVector 0 (Just (0.0001, 4.194588083372719)) 45.0 2 (0.009303513458826622, 6.263919392179866)+ , StepVector 0 (Just (0.0001, 4.194588083372719)) 45.0 3 (0.01399209578690811, 4.180821488255665)+ , StepVector 0 (Just (0.0001, 4.194588083372719)) 45.0 4 (0.018159724522980543, 2.097723584331464)+ , StepVector 0 (Just (0.0001, 4.194588083372719)) 400.0 1 (0.0001, 8.347017296104067)+ , StepVector 0 (Just (0.0001, 4.194588083372719)) 400.0 2 (0.009850951723436623, 6.263919392179866)+ , StepVector 0 (Just (0.0001, 4.194588083372719)) 400.0 3 (0.014818417695753395, 4.180821488255665)+ , StepVector 0 (Just (0.0001, 4.194588083372719)) 400.0 4 (0.019233943004479413, 2.097723584331464)+ , StepVector 0 (Just (0.0001, 10.0)) 0.0 1 (0.0001, 9.928179285716674)+ , StepVector 0 (Just (0.0001, 10.0)) 0.0 2 (0.0001, 9.928179285716674)+ , StepVector 0 (Just (0.0001, 10.0)) 0.0 3 (0.0001, 9.928179285716674)+ , StepVector 0 (Just (0.0001, 10.0)) 0.0 4 (0.0001, 9.928179285716674)+ , StepVector 0 (Just (0.0001, 10.0)) 0.006944444444444444 1 (0.0001, 9.928179285716674)+ , StepVector 0 (Just (0.0001, 10.0)) 0.006944444444444444 2 (0.004371539388018979, 9.928179285716674)+ , StepVector 0 (Just (0.0001, 10.0)) 0.006944444444444444 3 (0.007731543031386222, 9.928179285716674)+ , StepVector 0 (Just (0.0001, 10.0)) 0.006944444444444444 4 (0.010021005940802089, 9.928179285716674)+ , StepVector 0 (Just (0.0001, 10.0)) 0.5 1 (0.0001, 9.928179285716674)+ , StepVector 0 (Just (0.0001, 10.0)) 0.5 2 (0.002777991895595657, 9.928179285716674)+ , StepVector 0 (Just (0.0001, 10.0)) 0.5 3 (0.004658481191015653, 9.928179285716674)+ , StepVector 0 (Just (0.0001, 10.0)) 0.5 4 (0.006026025548320348, 9.928179285716674)+ , StepVector 0 (Just (0.0001, 10.0)) 1.0 1 (0.0001, 9.928179285716674)+ , StepVector 0 (Just (0.0001, 10.0)) 1.0 2 (0.001749503714401098, 9.928179285716674)+ , StepVector 0 (Just (0.0001, 10.0)) 1.0 3 (0.002745708470737798, 9.928179285716674)+ , StepVector 0 (Just (0.0001, 10.0)) 1.0 4 (0.0035394210119591377, 9.928179285716674)+ , StepVector 0 (Just (0.0001, 10.0)) 45.0 1 (0.0001, 9.928179285716674)+ , StepVector 0 (Just (0.0001, 10.0)) 45.0 2 (0.0014523815415699078, 9.928179285716674)+ , StepVector 0 (Just (0.0001, 10.0)) 45.0 3 (0.0021413306287847663, 9.928179285716674)+ , StepVector 0 (Just (0.0001, 10.0)) 45.0 4 (0.0027537298174201965, 9.928179285716674)+ , StepVector 0 (Just (0.0001, 10.0)) 400.0 1 (0.0001, 9.928179285716674)+ , StepVector 0 (Just (0.0001, 10.0)) 400.0 2 (0.0015328231476499858, 9.928179285716674)+ , StepVector 0 (Just (0.0001, 10.0)) 400.0 3 (0.0022627519209811107, 9.928179285716674)+ , StepVector 0 (Just (0.0001, 10.0)) 400.0 4 (0.0029115774972754437, 9.928179285716674)+ , StepVector 0 (Just (1.0, 1.0)) 0.0 1 (0.05185208758442845, 7.476939285716673)+ , StepVector 0 (Just (1.0, 1.0)) 0.0 2 (1.0, 4.247559285716673)+ , StepVector 0 (Just (1.0, 1.0)) 0.0 3 (1.0, 1.018179285716673)+ , StepVector 0 (Just (1.0, 1.0)) 0.0 4 (1.0, 1.0)+ , StepVector 0 (Just (1.0, 1.0)) 0.006944444444444444 1 (0.06638267651649077, 7.476939285716673)+ , StepVector 0 (Just (1.0, 1.0)) 0.006944444444444444 2 (1.9498457743368915, 4.247559285716673)+ , StepVector 0 (Just (1.0, 1.0)) 0.006944444444444444 3 (2.6904530220163196, 1.018179285716673)+ , StepVector 0 (Just (1.0, 1.0)) 0.006944444444444444 4 (3.197588928621215, 1.0)+ , StepVector 0 (Just (1.0, 1.0)) 0.5 1 (0.1954216491542706, 7.476939285716673)+ , StepVector 0 (Just (1.0, 1.0)) 0.5 2 (3.8057614435171345, 4.247559285716673)+ , StepVector 0 (Just (1.0, 1.0)) 0.5 3 (5.396628606628578, 1.018179285716673)+ , StepVector 0 (Just (1.0, 1.0)) 0.5 4 (6.715617188617151, 1.0)+ , StepVector 0 (Just (1.0, 1.0)) 1.0 1 (0.230527366662237, 7.476939285716673)+ , StepVector 0 (Just (1.0, 1.0)) 1.0 2 (4.549141883918697, 4.247559285716673)+ , StepVector 0 (Just (1.0, 1.0)) 1.0 3 (6.412854677935164, 1.018179285716673)+ , StepVector 0 (Just (1.0, 1.0)) 1.0 4 (8.036711081315712, 1.0)+ , StepVector 0 (Just (1.0, 1.0)) 45.0 1 (0.24981723569318473, 7.476939285716673)+ , StepVector 0 (Just (1.0, 1.0)) 45.0 2 (12.447877746852612, 4.247559285716673)+ , StepVector 0 (Just (1.0, 1.0)) 45.0 3 (18.27981546694734, 1.018179285716673)+ , StepVector 0 (Just (1.0, 1.0)) 45.0 4 (23.463760107031543, 1.0)+ , StepVector 0 (Just (1.0, 1.0)) 400.0 1 (0.25325646949892705, 7.476939285716673)+ , StepVector 0 (Just (1.0, 1.0)) 400.0 2 (18.37195723994685, 4.247559285716673)+ , StepVector 0 (Just (1.0, 1.0)) 400.0 3 (27.221822248976377, 1.018179285716673)+ , StepVector 0 (Just (1.0, 1.0)) 400.0 4 (35.08836892366929, 1.0)+ , StepVector 0 (Just (1.0, 4.194588083372719)) 0.0 1 (0.05106266417699935, 8.347017296104067)+ , StepVector 0 (Just (1.0, 4.194588083372719)) 0.0 2 (1.0, 6.263919392179866)+ , StepVector 0 (Just (1.0, 4.194588083372719)) 0.0 3 (1.0, 4.180821488255665)+ , StepVector 0 (Just (1.0, 4.194588083372719)) 0.0 4 (1.0, 2.097723584331464)+ , StepVector 0 (Just (1.0, 4.194588083372719)) 0.006944444444444444 1 (0.06540628679938068, 8.347017296104067)+ , StepVector 0 (Just (1.0, 4.194588083372719)) 0.006944444444444444 2 (1.6464091751630348, 6.263919392179866)+ , StepVector 0 (Just (1.0, 4.194588083372719)) 0.006944444444444444 3 (2.150422914052846, 4.180821488255665)+ , StepVector 0 (Just (1.0, 4.194588083372719)) 0.006944444444444444 4 (2.4955497882686997, 2.097723584331464)+ , StepVector 0 (Just (1.0, 4.194588083372719)) 0.5 1 (0.1938751351692444, 8.347017296104067)+ , StepVector 0 (Just (1.0, 4.194588083372719)) 0.5 2 (2.9094362362924873, 6.263919392179866)+ , StepVector 0 (Just (1.0, 4.194588083372719)) 0.5 3 (3.992086871253452, 4.180821488255665)+ , StepVector 0 (Just (1.0, 4.194588083372719)) 0.5 4 (4.889712932629488, 2.097723584331464)+ , StepVector 0 (Just (1.0, 4.194588083372719)) 1.0 1 (0.22885931116712982, 8.347017296104067)+ , StepVector 0 (Just (1.0, 4.194588083372719)) 1.0 2 (3.41533724706213, 6.263919392179866)+ , StepVector 0 (Just (1.0, 4.194588083372719)) 1.0 3 (4.683670572819169, 4.180821488255665)+ , StepVector 0 (Just (1.0, 4.194588083372719)) 1.0 4 (5.78877174466492, 2.097723584331464)+ , StepVector 0 (Just (1.0, 4.194588083372719)) 45.0 1 (0.24806827162303902, 8.347017296104067)+ , StepVector 0 (Just (1.0, 4.194588083372719)) 45.0 2 (8.790752363852306, 6.263919392179866)+ , StepVector 0 (Just (1.0, 4.194588083372719)) 45.0 3 (12.759626209588385, 4.180821488255665)+ , StepVector 0 (Just (1.0, 4.194588083372719)) 45.0 4 (16.2875140724649, 2.097723584331464)+ , StepVector 0 (Just (1.0, 4.194588083372719)) 400.0 1 (0.251483427440974, 8.347017296104067)+ , StepVector 0 (Just (1.0, 4.194588083372719)) 400.0 2 (12.822332481587384, 6.263919392179866)+ , StepVector 0 (Just (1.0, 4.194588083372719)) 400.0 3 (18.84503016088662, 4.180821488255665)+ , StepVector 0 (Just (1.0, 4.194588083372719)) 400.0 4 (24.198539209152607, 2.097723584331464)+ , StepVector 0 (Just (1.0, 10.0)) 0.0 1 (0.05059018248154134, 9.928179285716674)+ , StepVector 0 (Just (1.0, 10.0)) 0.0 2 (1.0, 9.928179285716674)+ , StepVector 0 (Just (1.0, 10.0)) 0.0 3 (1.0, 9.928179285716674)+ , StepVector 0 (Just (1.0, 10.0)) 0.0 4 (1.0, 9.928179285716674)+ , StepVector 0 (Just (1.0, 10.0)) 0.006944444444444444 1 (0.06482178595010671, 9.928179285716674)+ , StepVector 0 (Just (1.0, 10.0)) 0.006944444444444444 2 (1.0949845774336893, 9.928179285716674)+ , StepVector 0 (Just (1.0, 10.0)) 0.006944444444444444 3 (1.1690453022016318, 9.928179285716674)+ , StepVector 0 (Just (1.0, 10.0)) 0.006944444444444444 4 (1.2197588928621212, 9.928179285716674)+ , StepVector 0 (Just (1.0, 10.0)) 0.5 1 (0.19294464260502497, 9.928179285716674)+ , StepVector 0 (Just (1.0, 10.0)) 0.5 2 (1.2805761443517136, 9.928179285716674)+ , StepVector 0 (Just (1.0, 10.0)) 0.5 3 (1.4396628606628579, 9.928179285716674)+ , StepVector 0 (Just (1.0, 10.0)) 0.5 4 (1.571561718861715, 9.928179285716674)+ , StepVector 0 (Just (1.0, 10.0)) 1.0 1 (0.22785466350592223, 9.928179285716674)+ , StepVector 0 (Just (1.0, 10.0)) 1.0 2 (1.3549141883918698, 9.928179285716674)+ , StepVector 0 (Just (1.0, 10.0)) 1.0 3 (1.5412854677935166, 9.928179285716674)+ , StepVector 0 (Just (1.0, 10.0)) 1.0 4 (1.7036711081315714, 9.928179285716674)+ , StepVector 0 (Just (1.0, 10.0)) 45.0 1 (0.2470144720795308, 9.928179285716674)+ , StepVector 0 (Just (1.0, 10.0)) 45.0 2 (2.1447877746852617, 9.928179285716674)+ , StepVector 0 (Just (1.0, 10.0)) 45.0 3 (2.7279815466947346, 9.928179285716674)+ , StepVector 0 (Just (1.0, 10.0)) 45.0 4 (3.246376010703155, 9.928179285716674)+ , StepVector 0 (Just (1.0, 10.0)) 400.0 1 (0.25041512023947954, 9.928179285716674)+ , StepVector 0 (Just (1.0, 10.0)) 400.0 2 (2.737195723994685, 9.928179285716674)+ , StepVector 0 (Just (1.0, 10.0)) 400.0 3 (3.622182224897638, 9.928179285716674)+ , StepVector 0 (Just (1.0, 10.0)) 400.0 4 (4.40883689236693, 9.928179285716674)+ , StepVector 0 (Just (4.1283, 1.0)) 0.0 1 (0.13679022431475651, 7.476939285716673)+ , StepVector 0 (Just (4.1283, 1.0)) 0.0 2 (4.1283, 4.247559285716673)+ , StepVector 0 (Just (4.1283, 1.0)) 0.0 3 (4.1283, 1.018179285716673)+ , StepVector 0 (Just (4.1283, 1.0)) 0.0 4 (4.1283, 1.0)+ , StepVector 0 (Just (4.1283, 1.0)) 0.006944444444444444 1 (0.1604384406182761, 7.476939285716673)+ , StepVector 0 (Just (4.1283, 1.0)) 0.006944444444444444 2 (5.083722317803886, 4.247559285716673)+ , StepVector 0 (Just (4.1283, 1.0)) 0.006944444444444444 3 (5.826616153297511, 1.018179285716673)+ , StepVector 0 (Just (4.1283, 1.0)) 0.006944444444444444 4 (6.336110999286765, 1.0)+ , StepVector 0 (Just (4.1283, 1.0)) 0.5 1 (0.6561785769111506, 7.476939285716673)+ , StepVector 0 (Just (4.1283, 1.0)) 0.5 2 (7.935413208123225, 4.247559285716673)+ , StepVector 0 (Just (4.1283, 1.0)) 0.5 3 (10.047855927471742, 1.018179285716673)+ , StepVector 0 (Just (4.1283, 1.0)) 0.5 4 (11.823722705713264, 1.0)+ , StepVector 0 (Just (4.1283, 1.0)) 1.0 1 (0.7984400132524605, 7.476939285716673)+ , StepVector 0 (Just (4.1283, 1.0)) 1.0 2 (9.032023096735257, 4.247559285716673)+ , StepVector 0 (Just (4.1283, 1.0)) 1.0 3 (11.587580645763943, 1.018179285716673)+ , StepVector 0 (Just (4.1283, 1.0)) 1.0 4 (13.825364839493126, 1.0)+ , StepVector 0 (Just (4.1283, 1.0)) 45.0 1 (0.869977897241395, 7.476939285716673)+ , StepVector 0 (Just (4.1283, 1.0)) 45.0 2 (25.071343188360963, 4.247559285716673)+ , StepVector 0 (Just (4.1283, 1.0)) 45.0 3 (35.74044066167693, 1.018179285716673)+ , StepVector 0 (Just (4.1283, 1.0)) 45.0 4 (45.224082860180005, 1.0)+ , StepVector 0 (Just (4.1283, 1.0)) 400.0 1 (0.8850995782249731, 7.476939285716673)+ , StepVector 0 (Just (4.1283, 1.0)) 400.0 2 (45.26030223522177, 4.247559285716673)+ , StepVector 0 (Just (4.1283, 1.0)) 400.0 3 (66.2143411097687, 1.018179285716673)+ , StepVector 0 (Just (4.1283, 1.0)) 400.0 4 (84.84015344269932, 1.0)+ , StepVector 0 (Just (4.1283, 4.194588083372719)) 0.0 1 (0.13470765811516586, 8.347017296104067)+ , StepVector 0 (Just (4.1283, 4.194588083372719)) 0.0 2 (4.1283, 6.263919392179866)+ , StepVector 0 (Just (4.1283, 4.194588083372719)) 0.0 3 (4.1283, 4.180821488255665)+ , StepVector 0 (Just (4.1283, 4.194588083372719)) 0.0 4 (4.1283, 2.097723584331464)+ , StepVector 0 (Just (4.1283, 4.194588083372719)) 0.006944444444444444 1 (0.15811635416498357, 8.347017296104067)+ , StepVector 0 (Just (4.1283, 4.194588083372719)) 0.006944444444444444 2 (4.778504242699423, 6.263919392179866)+ , StepVector 0 (Just (4.1283, 4.194588083372719)) 0.006944444444444444 3 (5.284074098785149, 4.180821488255665)+ , StepVector 0 (Just (4.1283, 4.194588083372719)) 0.006944444444444444 4 (5.630806328420692, 2.097723584331464)+ , StepVector 0 (Just (4.1283, 4.194588083372719)) 0.5 1 (0.6512004982520425, 8.347017296104067)+ , StepVector 0 (Just (4.1283, 4.194588083372719)) 0.5 2 (6.719197359451092, 6.263919392179866)+ , StepVector 0 (Just (4.1283, 4.194588083372719)) 0.5 3 (8.156801644995785, 4.180821488255665)+ , StepVector 0 (Just (4.1283, 4.194588083372719)) 0.5 4 (9.365352138494519, 2.097723584331464)+ , StepVector 0 (Just (4.1283, 4.194588083372719)) 1.0 1 (0.7927373603135137, 8.347017296104067)+ , StepVector 0 (Just (4.1283, 4.194588083372719)) 1.0 2 (7.465485559836253, 6.263919392179866)+ , StepVector 0 (Just (4.1283, 4.194588083372719)) 1.0 3 (9.204647739614918, 4.180821488255665)+ , StepVector 0 (Just (4.1283, 4.194588083372719)) 1.0 4 (10.727552061499393, 2.097723584331464)+ , StepVector 0 (Just (4.1283, 4.194588083372719)) 45.0 1 (0.8638872042598874, 8.347017296104067)+ , StepVector 0 (Just (4.1283, 4.194588083372719)) 45.0 2 (18.380903568451153, 6.263919392179866)+ , StepVector 0 (Just (4.1283, 4.194588083372719)) 45.0 3 (25.641663876907398, 4.180821488255665)+ , StepVector 0 (Just (4.1283, 4.194588083372719)) 45.0 4 (32.095673039979616, 2.097723584331464)+ , StepVector 0 (Just (4.1283, 4.194588083372719)) 400.0 1 (0.8789030187421127, 8.347017296104067)+ , StepVector 0 (Just (4.1283, 4.194588083372719)) 400.0 2 (32.12032181663182, 6.263919392179866)+ , StepVector 0 (Just (4.1283, 4.194588083372719)) 400.0 3 (46.380408402463125, 4.180821488255665)+ , StepVector 0 (Just (4.1283, 4.194588083372719)) 400.0 4 (59.05604092320207, 2.097723584331464)+ , StepVector 0 (Just (4.1283, 10.0)) 0.0 1 (0.13346121115194412, 9.928179285716674)+ , StepVector 0 (Just (4.1283, 10.0)) 0.0 2 (4.1283, 9.928179285716674)+ , StepVector 0 (Just (4.1283, 10.0)) 0.0 3 (4.1283, 9.928179285716674)+ , StepVector 0 (Just (4.1283, 10.0)) 0.0 4 (4.1283, 9.928179285716674)+ , StepVector 0 (Just (4.1283, 10.0)) 0.006944444444444444 1 (0.15672613904424862, 9.928179285716674)+ , StepVector 0 (Just (4.1283, 10.0)) 0.006944444444444444 2 (4.223842231780389, 9.928179285716674)+ , StepVector 0 (Just (4.1283, 10.0)) 0.006944444444444444 3 (4.298131615329752, 9.928179285716674)+ , StepVector 0 (Just (4.1283, 10.0)) 0.006944444444444444 4 (4.349081099928677, 9.928179285716674)+ , StepVector 0 (Just (4.1283, 10.0)) 0.5 1 (0.6482039215002308, 9.928179285716674)+ , StepVector 0 (Just (4.1283, 10.0)) 0.5 2 (4.5090113208123235, 9.928179285716674)+ , StepVector 0 (Just (4.1283, 10.0)) 0.5 3 (4.720255592747175, 9.928179285716674)+ , StepVector 0 (Just (4.1283, 10.0)) 0.5 4 (4.897842270571327, 9.928179285716674)+ , StepVector 0 (Just (4.1283, 10.0)) 1.0 1 (0.7893021911345529, 9.928179285716674)+ , StepVector 0 (Just (4.1283, 10.0)) 1.0 2 (4.618672309673525, 9.928179285716674)+ , StepVector 0 (Just (4.1283, 10.0)) 1.0 3 (4.874228064576394, 9.928179285716674)+ , StepVector 0 (Just (4.1283, 10.0)) 1.0 4 (5.098006483949312, 9.928179285716674)+ , StepVector 0 (Just (4.1283, 10.0)) 45.0 1 (0.8602173921733379, 9.928179285716674)+ , StepVector 0 (Just (4.1283, 10.0)) 45.0 2 (6.222604318836096, 9.928179285716674)+ , StepVector 0 (Just (4.1283, 10.0)) 45.0 3 (7.289514066167692, 9.928179285716674)+ , StepVector 0 (Just (4.1283, 10.0)) 45.0 4 (8.237878286018, 9.928179285716674)+ , StepVector 0 (Just (4.1283, 10.0)) 400.0 1 (0.8751694191411695, 9.928179285716674)+ , StepVector 0 (Just (4.1283, 10.0)) 400.0 2 (8.241500223522177, 9.928179285716674)+ , StepVector 0 (Just (4.1283, 10.0)) 400.0 3 (10.336904110976871, 9.928179285716674)+ , StepVector 0 (Just (4.1283, 10.0)) 400.0 4 (12.199485344269933, 9.928179285716674)+ , StepVector 0 (Just (1000.0, 1.0)) 0.0 1 (1.159990664180841, 7.476939285716673)+ , StepVector 0 (Just (1000.0, 1.0)) 0.0 2 (1000.0, 4.247559285716673)+ , StepVector 0 (Just (1000.0, 1.0)) 0.0 3 (1000.0, 1.018179285716673)+ , StepVector 0 (Just (1000.0, 1.0)) 0.0 4 (1000.0, 1.0)+ , StepVector 0 (Just (1000.0, 1.0)) 0.006944444444444444 1 (2.2157900750295205, 7.476939285716673)+ , StepVector 0 (Just (1000.0, 1.0)) 0.006944444444444444 2 (1000.0931083879832, 4.247559285716673)+ , StepVector 0 (Just (1000.0, 1.0)) 0.006944444444444444 3 (1000.1644541460627, 1.018179285716673)+ , StepVector 0 (Just (1000.0, 1.0)) 0.006944444444444444 4 (1000.2137903898813, 1.0)+ , StepVector 0 (Just (1000.0, 1.0)) 0.5 1 (44.92637532074338, 7.476939285716673)+ , StepVector 0 (Just (1000.0, 1.0)) 0.5 2 (1006.6568772170801, 4.247559285716673)+ , StepVector 0 (Just (1000.0, 1.0)) 0.5 3 (1010.1926725341626, 1.018179285716673)+ , StepVector 0 (Just (1000.0, 1.0)) 0.5 4 (1013.2504742944116, 1.0)+ , StepVector 0 (Just (1000.0, 1.0)) 1.0 1 (57.46656124646133, 7.476939285716673)+ , StepVector 0 (Just (1000.0, 1.0)) 1.0 2 (1010.3279310369161, 4.247559285716673)+ , StepVector 0 (Just (1000.0, 1.0)) 1.0 3 (1015.6425252019736, 1.018179285716673)+ , StepVector 0 (Just (1000.0, 1.0)) 1.0 4 (1020.3352827625655, 1.0)+ , StepVector 0 (Just (1000.0, 1.0)) 45.0 1 (62.52453527105817, 7.476939285716673)+ , StepVector 0 (Just (1000.0, 1.0)) 45.0 2 (1036.6952134413232, 4.247559285716673)+ , StepVector 0 (Just (1000.0, 1.0)) 45.0 3 (1055.3890014208653, 1.018179285716673)+ , StepVector 0 (Just (1000.0, 1.0)) 45.0 4 (1072.005701847125, 1.0)+ , StepVector 0 (Just (1000.0, 1.0)) 400.0 1 (62.625085083607765, 7.476939285716673)+ , StepVector 0 (Just (1000.0, 1.0)) 400.0 2 (1149.2965612933137, 4.247559285716673)+ , StepVector 0 (Just (1000.0, 1.0)) 400.0 3 (1225.353300065379, 1.018179285716673)+ , StepVector 0 (Just (1000.0, 1.0)) 400.0 4 (1292.959290084993, 1.0)+ , StepVector 0 (Just (1000.0, 4.194588083372719)) 0.0 1 (1.1423303572315298, 8.347017296104067)+ , StepVector 0 (Just (1000.0, 4.194588083372719)) 0.0 2 (1000.0, 6.263919392179866)+ , StepVector 0 (Just (1000.0, 4.194588083372719)) 0.0 3 (1000.0, 4.180821488255665)+ , StepVector 0 (Just (1000.0, 4.194588083372719)) 0.0 4 (1000.0, 2.097723584331464)+ , StepVector 0 (Just (1000.0, 4.194588083372719)) 0.006944444444444444 1 (2.1909006545458993, 8.347017296104067)+ , StepVector 0 (Just (1000.0, 4.194588083372719)) 0.006944444444444444 2 (1000.0633640933117, 6.263919392179866)+ , StepVector 0 (Just (1000.0, 4.194588083372719)) 0.006944444444444444 3 (1000.1119178205353, 4.180821488255665)+ , StepVector 0 (Just (1000.0, 4.194588083372719)) 0.006944444444444444 4 (1000.1454931666959, 2.097723584331464)+ , StepVector 0 (Just (1000.0, 4.194588083372719)) 0.5 1 (44.609103781527075, 8.347017296104067)+ , StepVector 0 (Just (1000.0, 4.194588083372719)) 0.5 2 (1004.5302791540641, 6.263919392179866)+ , StepVector 0 (Just (1000.0, 4.194588083372719)) 0.5 3 (1006.9365335126271, 4.180821488255665)+ , StepVector 0 (Just (1000.0, 4.194588083372719)) 0.5 4 (1009.0174935664152, 2.097723584331464)+ , StepVector 0 (Just (1000.0, 4.194588083372719)) 1.0 1 (57.06345257896361, 8.347017296104067)+ , StepVector 0 (Just (1000.0, 4.194588083372719)) 1.0 2 (1007.0285824952732, 6.263919392179866)+ , StepVector 0 (Just (1000.0, 4.194588083372719)) 1.0 3 (1010.6453827415654, 4.180821488255665)+ , StepVector 0 (Just (1000.0, 4.194588083372719)) 1.0 4 (1013.8389975640349, 2.097723584331464)+ , StepVector 0 (Just (1000.0, 4.194588083372719)) 45.0 1 (62.08680260065931, 8.347017296104067)+ , StepVector 0 (Just (1000.0, 4.194588083372719)) 45.0 2 (1024.9726042836762, 6.263919392179866)+ , StepVector 0 (Just (1000.0, 4.194588083372719)) 45.0 3 (1037.6944970319641, 4.180821488255665)+ , StepVector 0 (Just (1000.0, 4.194588083372719)) 45.0 4 (1049.0028461415534, 2.097723584331464)+ , StepVector 0 (Just (1000.0, 4.194588083372719)) 400.0 1 (62.18664846654597, 8.347017296104067)+ , StepVector 0 (Just (1000.0, 4.194588083372719)) 400.0 2 (1101.6024597336993, 6.263919392179866)+ , StepVector 0 (Just (1000.0, 4.194588083372719)) 400.0 3 (1153.3622033716215, 4.180821488255665)+ , StepVector 0 (Just (1000.0, 4.194588083372719)) 400.0 4 (1199.3708643831078, 2.097723584331464)+ , StepVector 0 (Just (1000.0, 10.0)) 0.0 1 (1.1317603998535317, 9.928179285716674)+ , StepVector 0 (Just (1000.0, 10.0)) 0.0 2 (1000.0, 9.928179285716674)+ , StepVector 0 (Just (1000.0, 10.0)) 0.0 3 (1000.0, 9.928179285716674)+ , StepVector 0 (Just (1000.0, 10.0)) 0.0 4 (1000.0, 9.928179285716674)+ , StepVector 0 (Just (1000.0, 10.0)) 0.006944444444444444 1 (2.175973747672225, 9.928179285716674)+ , StepVector 0 (Just (1000.0, 10.0)) 0.006944444444444444 2 (1000.0093108387983, 9.928179285716674)+ , StepVector 0 (Just (1000.0, 10.0)) 0.006944444444444444 3 (1000.0164454146063, 9.928179285716674)+ , StepVector 0 (Just (1000.0, 10.0)) 0.006944444444444444 4 (1000.0213790389881, 9.928179285716674)+ , StepVector 0 (Just (1000.0, 10.0)) 0.5 1 (44.41795922568229, 9.928179285716674)+ , StepVector 0 (Just (1000.0, 10.0)) 0.5 2 (1000.6656877217079, 9.928179285716674)+ , StepVector 0 (Just (1000.0, 10.0)) 0.5 3 (1001.0192672534162, 9.928179285716674)+ , StepVector 0 (Just (1000.0, 10.0)) 0.5 4 (1001.3250474294412, 9.928179285716674)+ , StepVector 0 (Just (1000.0, 10.0)) 1.0 1 (56.82057422913128, 9.928179285716674)+ , StepVector 0 (Just (1000.0, 10.0)) 1.0 2 (1001.0327931036915, 9.928179285716674)+ , StepVector 0 (Just (1000.0, 10.0)) 1.0 3 (1001.5642525201973, 9.928179285716674)+ , StepVector 0 (Just (1000.0, 10.0)) 1.0 4 (1002.0335282762567, 9.928179285716674)+ , StepVector 0 (Just (1000.0, 10.0)) 45.0 1 (61.823056480245, 9.928179285716674)+ , StepVector 0 (Just (1000.0, 10.0)) 45.0 2 (1003.6695213441322, 9.928179285716674)+ , StepVector 0 (Just (1000.0, 10.0)) 45.0 3 (1005.5389001420865, 9.928179285716674)+ , StepVector 0 (Just (1000.0, 10.0)) 45.0 4 (1007.2005701847124, 9.928179285716674)+ , StepVector 0 (Just (1000.0, 10.0)) 400.0 1 (61.92247819866933, 9.928179285716674)+ , StepVector 0 (Just (1000.0, 10.0)) 400.0 2 (1014.9296561293313, 9.928179285716674)+ , StepVector 0 (Just (1000.0, 10.0)) 400.0 3 (1022.5353300065378, 9.928179285716674)+ , StepVector 0 (Just (1000.0, 10.0)) 400.0 4 (1029.2959290084993, 9.928179285716674)+ , StepVector 0 (Just (36500.0, 1.0)) 0.0 1 (3.017411305804305, 7.476939285716673)+ , StepVector 0 (Just (36500.0, 1.0)) 0.0 2 (36500.0, 4.247559285716673)+ , StepVector 0 (Just (36500.0, 1.0)) 0.0 3 (36500.0, 1.018179285716673)+ , StepVector 0 (Just (36500.0, 1.0)) 0.0 4 (36500.0, 1.0)+ , StepVector 0 (Just (36500.0, 1.0)) 0.006944444444444444 1 (19.026838013168028, 7.476939285716673)+ , StepVector 0 (Just (36500.0, 1.0)) 0.006944444444444444 2 (36500.0, 4.247559285716673)+ , StepVector 0 (Just (36500.0, 1.0)) 0.006944444444444444 3 (36500.0, 1.018179285716673)+ , StepVector 0 (Just (36500.0, 1.0)) 0.006944444444444444 4 (36500.0, 1.0)+ , StepVector 0 (Just (36500.0, 1.0)) 0.5 1 (666.6909844968715, 7.476939285716673)+ , StepVector 0 (Just (36500.0, 1.0)) 0.5 2 (36500.0, 4.247559285716673)+ , StepVector 0 (Just (36500.0, 1.0)) 0.5 3 (36500.0, 1.018179285716673)+ , StepVector 0 (Just (36500.0, 1.0)) 0.5 4 (36500.0, 1.0)+ , StepVector 0 (Just (36500.0, 1.0)) 1.0 1 (856.8379144357807, 7.476939285716673)+ , StepVector 0 (Just (36500.0, 1.0)) 1.0 2 (36500.0, 4.247559285716673)+ , StepVector 0 (Just (36500.0, 1.0)) 1.0 3 (36500.0, 1.018179285716673)+ , StepVector 0 (Just (36500.0, 1.0)) 1.0 4 (36500.0, 1.0)+ , StepVector 0 (Just (36500.0, 1.0)) 45.0 1 (933.2173460039444, 7.476939285716673)+ , StepVector 0 (Just (36500.0, 1.0)) 45.0 2 (36500.0, 4.247559285716673)+ , StepVector 0 (Just (36500.0, 1.0)) 45.0 3 (36500.0, 1.018179285716673)+ , StepVector 0 (Just (36500.0, 1.0)) 45.0 4 (36500.0, 1.0)+ , StepVector 0 (Just (36500.0, 1.0)) 400.0 1 (933.2742754379002, 7.476939285716673)+ , StepVector 0 (Just (36500.0, 1.0)) 400.0 2 (36500.0, 4.247559285716673)+ , StepVector 0 (Just (36500.0, 1.0)) 400.0 3 (36500.0, 1.018179285716673)+ , StepVector 0 (Just (36500.0, 1.0)) 400.0 4 (36500.0, 1.0)+ , StepVector 0 (Just (36500.0, 4.194588083372719)) 0.0 1 (2.971472651728621, 8.347017296104067)+ , StepVector 0 (Just (36500.0, 4.194588083372719)) 0.0 2 (36500.0, 6.263919392179866)+ , StepVector 0 (Just (36500.0, 4.194588083372719)) 0.0 3 (36500.0, 4.180821488255665)+ , StepVector 0 (Just (36500.0, 4.194588083372719)) 0.0 4 (36500.0, 2.097723584331464)+ , StepVector 0 (Just (36500.0, 4.194588083372719)) 0.006944444444444444 1 (18.869244830573844, 8.347017296104067)+ , StepVector 0 (Just (36500.0, 4.194588083372719)) 0.006944444444444444 2 (36500.0, 6.263919392179866)+ , StepVector 0 (Just (36500.0, 4.194588083372719)) 0.006944444444444444 3 (36500.0, 4.180821488255665)+ , StepVector 0 (Just (36500.0, 4.194588083372719)) 0.006944444444444444 4 (36500.0, 2.097723584331464)+ , StepVector 0 (Just (36500.0, 4.194588083372719)) 0.5 1 (662.0163883245173, 8.347017296104067)+ , StepVector 0 (Just (36500.0, 4.194588083372719)) 0.5 2 (36500.0, 6.263919392179866)+ , StepVector 0 (Just (36500.0, 4.194588083372719)) 0.5 3 (36500.0, 4.180821488255665)+ , StepVector 0 (Just (36500.0, 4.194588083372719)) 0.5 4 (36500.0, 2.097723584331464)+ , StepVector 0 (Just (36500.0, 4.194588083372719)) 1.0 1 (850.8371770939843, 8.347017296104067)+ , StepVector 0 (Just (36500.0, 4.194588083372719)) 1.0 2 (36500.0, 6.263919392179866)+ , StepVector 0 (Just (36500.0, 4.194588083372719)) 1.0 3 (36500.0, 4.180821488255665)+ , StepVector 0 (Just (36500.0, 4.194588083372719)) 1.0 4 (36500.0, 2.097723584331464)+ , StepVector 0 (Just (36500.0, 4.194588083372719)) 45.0 1 (926.6839152609904, 8.347017296104067)+ , StepVector 0 (Just (36500.0, 4.194588083372719)) 45.0 2 (36500.0, 6.263919392179866)+ , StepVector 0 (Just (36500.0, 4.194588083372719)) 45.0 3 (36500.0, 4.180821488255665)+ , StepVector 0 (Just (36500.0, 4.194588083372719)) 45.0 4 (36500.0, 2.097723584331464)+ , StepVector 0 (Just (36500.0, 4.194588083372719)) 400.0 1 (926.7404461334369, 8.347017296104067)+ , StepVector 0 (Just (36500.0, 4.194588083372719)) 400.0 2 (36500.0, 6.263919392179866)+ , StepVector 0 (Just (36500.0, 4.194588083372719)) 400.0 3 (36500.0, 4.180821488255665)+ , StepVector 0 (Just (36500.0, 4.194588083372719)) 400.0 4 (36500.0, 2.097723584331464)+ , StepVector 0 (Just (36500.0, 10.0)) 0.0 1 (2.943977681399042, 9.928179285716674)+ , StepVector 0 (Just (36500.0, 10.0)) 0.0 2 (36500.0, 9.928179285716674)+ , StepVector 0 (Just (36500.0, 10.0)) 0.0 3 (36500.0, 9.928179285716674)+ , StepVector 0 (Just (36500.0, 10.0)) 0.0 4 (36500.0, 9.928179285716674)+ , StepVector 0 (Just (36500.0, 10.0)) 0.006944444444444444 1 (18.774471725632857, 9.928179285716674)+ , StepVector 0 (Just (36500.0, 10.0)) 0.006944444444444444 2 (36500.0, 9.928179285716674)+ , StepVector 0 (Just (36500.0, 10.0)) 0.006944444444444444 3 (36500.0, 9.928179285716674)+ , StepVector 0 (Just (36500.0, 10.0)) 0.006944444444444444 4 (36500.0, 9.928179285716674)+ , StepVector 0 (Just (36500.0, 10.0)) 0.5 1 (659.1998668089976, 9.928179285716674)+ , StepVector 0 (Just (36500.0, 10.0)) 0.5 2 (36500.0, 9.928179285716674)+ , StepVector 0 (Just (36500.0, 10.0)) 0.5 3 (36500.0, 9.928179285716674)+ , StepVector 0 (Just (36500.0, 10.0)) 0.5 4 (36500.0, 9.928179285716674)+ , StepVector 0 (Just (36500.0, 10.0)) 1.0 1 (847.2215809183945, 9.928179285716674)+ , StepVector 0 (Just (36500.0, 10.0)) 1.0 2 (36500.0, 9.928179285716674)+ , StepVector 0 (Just (36500.0, 10.0)) 1.0 3 (36500.0, 9.928179285716674)+ , StepVector 0 (Just (36500.0, 10.0)) 1.0 4 (36500.0, 9.928179285716674)+ , StepVector 0 (Just (36500.0, 10.0)) 45.0 1 (922.7473413473284, 9.928179285716674)+ , StepVector 0 (Just (36500.0, 10.0)) 45.0 2 (36500.0, 9.928179285716674)+ , StepVector 0 (Just (36500.0, 10.0)) 45.0 3 (36500.0, 9.928179285716674)+ , StepVector 0 (Just (36500.0, 10.0)) 45.0 4 (36500.0, 9.928179285716674)+ , StepVector 0 (Just (36500.0, 10.0)) 400.0 1 (922.8036320753696, 9.928179285716674)+ , StepVector 0 (Just (36500.0, 10.0)) 400.0 2 (36500.0, 9.928179285716674)+ , StepVector 0 (Just (36500.0, 10.0)) 400.0 3 (36500.0, 9.928179285716674)+ , StepVector 0 (Just (36500.0, 10.0)) 400.0 4 (36500.0, 9.928179285716674)+ , StepVector 1 Nothing 0.0 1 (21.160516, 8.15903)+ , StepVector 1 Nothing 0.0 2 (50.940793, 1.7511448034338732)+ , StepVector 1 Nothing 0.0 3 (64.835975, 1.0)+ , StepVector 1 Nothing 0.0 4 (64.835975, 1.0)+ , StepVector 1 (Just (0.0001, 1.0)) 0.0 1 (0.0001, 1.4918717310343146)+ , StepVector 1 (Just (0.0001, 1.0)) 0.0 2 (0.0001, 1.0)+ , StepVector 1 (Just (0.0001, 1.0)) 0.0 3 (0.0001, 1.0)+ , StepVector 1 (Just (0.0001, 1.0)) 0.0 4 (0.0001, 1.0)+ , StepVector 1 (Just (0.0001, 1.0)) 0.006944444444444444 1 (0.0001, 1.4918717310343146)+ , StepVector 1 (Just (0.0001, 1.0)) 0.006944444444444444 2 (28.448516471119373, 1.0)+ , StepVector 1 (Just (0.0001, 1.0)) 0.006944444444444444 3 (45.9812730814133, 1.0)+ , StepVector 1 (Just (0.0001, 1.0)) 0.006944444444444444 4 (153.57366846777214, 1.0)+ , StepVector 1 (Just (0.0001, 1.0)) 0.5 1 (0.0001, 1.4918717310343146)+ , StepVector 1 (Just (0.0001, 1.0)) 0.5 2 (0.339469306240738, 1.0)+ , StepVector 1 (Just (0.0001, 1.0)) 0.5 3 (1.1555661678427094, 1.0)+ , StepVector 1 (Just (0.0001, 1.0)) 0.5 4 (6.021168242345363, 1.0)+ , StepVector 1 (Just (0.0001, 1.0)) 1.0 1 (0.0001, 1.4918717310343146)+ , StepVector 1 (Just (0.0001, 1.0)) 1.0 2 (0.2536618617280553, 1.0)+ , StepVector 1 (Just (0.0001, 1.0)) 1.0 3 (1.0405528909992465, 1.0)+ , StepVector 1 (Just (0.0001, 1.0)) 1.0 4 (5.721370004876744, 1.0)+ , StepVector 1 (Just (0.0001, 1.0)) 45.0 1 (0.0001, 1.4918717310343146)+ , StepVector 1 (Just (0.0001, 1.0)) 45.0 2 (0.3012935756884682, 1.0)+ , StepVector 1 (Just (0.0001, 1.0)) 45.0 3 (1.2366232743459802, 1.0)+ , StepVector 1 (Just (0.0001, 1.0)) 45.0 4 (6.800398079487223, 1.0)+ , StepVector 1 (Just (0.0001, 1.0)) 400.0 1 (0.0001, 1.4918717310343146)+ , StepVector 1 (Just (0.0001, 1.0)) 400.0 2 (0.3278270236691793, 1.0)+ , StepVector 1 (Just (0.0001, 1.0)) 400.0 3 (1.3455539708317943, 1.0)+ , StepVector 1 (Just (0.0001, 1.0)) 400.0 4 (7.39946582166255, 1.0)+ , StepVector 1 (Just (0.0001, 4.194588083372719)) 0.0 1 (0.0001, 3.065920160856728)+ , StepVector 1 (Just (0.0001, 4.194588083372719)) 0.0 2 (0.0001, 1.6224725272150176)+ , StepVector 1 (Just (0.0001, 4.194588083372719)) 0.0 3 (0.0001, 1.0)+ , StepVector 1 (Just (0.0001, 4.194588083372719)) 0.0 4 (0.0001, 1.0)+ , StepVector 1 (Just (0.0001, 4.194588083372719)) 0.006944444444444444 1 (0.0001, 3.065920160856728)+ , StepVector 1 (Just (0.0001, 4.194588083372719)) 0.006944444444444444 2 (19.360419246173162, 1.6224725272150176)+ , StepVector 1 (Just (0.0001, 4.194588083372719)) 0.006944444444444444 3 (31.292182322875167, 1.0)+ , StepVector 1 (Just (0.0001, 4.194588083372719)) 0.006944444444444444 4 (104.51323929295523, 1.0)+ , StepVector 1 (Just (0.0001, 4.194588083372719)) 0.5 1 (0.0001, 3.065920160856728)+ , StepVector 1 (Just (0.0001, 4.194588083372719)) 0.5 2 (0.23105479208282514, 1.6224725272150176)+ , StepVector 1 (Just (0.0001, 4.194588083372719)) 0.5 3 (0.7864423227896431, 1.0)+ , StepVector 1 (Just (0.0001, 4.194588083372719)) 0.5 4 (4.097684956728321, 1.0)+ , StepVector 1 (Just (0.0001, 4.194588083372719)) 1.0 1 (0.0001, 3.065920160856728)+ , StepVector 1 (Just (0.0001, 4.194588083372719)) 1.0 2 (0.1726592915406306, 1.6224725272150176)+ , StepVector 1 (Just (0.0001, 4.194588083372719)) 1.0 3 (0.7081710503095576, 1.0)+ , StepVector 1 (Just (0.0001, 4.194588083372719)) 1.0 4 (3.8936599069430406, 1.0)+ , StepVector 1 (Just (0.0001, 4.194588083372719)) 45.0 1 (0.0001, 3.065920160856728)+ , StepVector 1 (Just (0.0001, 4.194588083372719)) 45.0 2 (0.2050746349201882, 1.6224725272150176)+ , StepVector 1 (Just (0.0001, 4.194588083372719)) 45.0 3 (0.8416050226421118, 1.0)+ , StepVector 1 (Just (0.0001, 4.194588083372719)) 45.0 4 (4.627982958675996, 1.0)+ , StepVector 1 (Just (0.0001, 4.194588083372719)) 400.0 1 (0.0001, 3.065920160856728)+ , StepVector 1 (Just (0.0001, 4.194588083372719)) 400.0 2 (0.2231317392279024, 1.6224725272150176)+ , StepVector 1 (Just (0.0001, 4.194588083372719)) 400.0 3 (0.9157368486372188, 1.0)+ , StepVector 1 (Just (0.0001, 4.194588083372719)) 400.0 4 (5.035673233822694, 1.0)+ , StepVector 1 (Just (0.0001, 10.0)) 0.0 1 (0.0001, 5.926382691034315)+ , StepVector 1 (Just (0.0001, 10.0)) 0.0 2 (0.0001, 5.926382691034315)+ , StepVector 1 (Just (0.0001, 10.0)) 0.0 3 (0.0001, 5.926382691034315)+ , StepVector 1 (Just (0.0001, 10.0)) 0.0 4 (0.0001, 5.926382691034315)+ , StepVector 1 (Just (0.0001, 10.0)) 0.006944444444444444 1 (0.0001, 5.926382691034315)+ , StepVector 1 (Just (0.0001, 10.0)) 0.006944444444444444 2 (2.844941647111938, 5.926382691034315)+ , StepVector 1 (Just (0.0001, 10.0)) 0.006944444444444444 3 (4.598217308141331, 5.926382691034315)+ , StepVector 1 (Just (0.0001, 10.0)) 0.006944444444444444 4 (15.35745684677722, 5.926382691034315)+ , StepVector 1 (Just (0.0001, 10.0)) 0.5 1 (0.0001, 5.926382691034315)+ , StepVector 1 (Just (0.0001, 10.0)) 0.5 2 (0.0340369306240738, 5.926382691034315)+ , StepVector 1 (Just (0.0001, 10.0)) 0.5 3 (0.11564661678427092, 5.926382691034315)+ , StepVector 1 (Just (0.0001, 10.0)) 0.5 4 (0.6022068242345362, 5.926382691034315)+ , StepVector 1 (Just (0.0001, 10.0)) 1.0 1 (0.0001, 5.926382691034315)+ , StepVector 1 (Just (0.0001, 10.0)) 1.0 2 (0.025456186172805522, 5.926382691034315)+ , StepVector 1 (Just (0.0001, 10.0)) 1.0 3 (0.10414528909992463, 5.926382691034315)+ , StepVector 1 (Just (0.0001, 10.0)) 1.0 4 (0.5722270004876744, 5.926382691034315)+ , StepVector 1 (Just (0.0001, 10.0)) 45.0 1 (0.0001, 5.926382691034315)+ , StepVector 1 (Just (0.0001, 10.0)) 45.0 2 (0.030219357568846812, 5.926382691034315)+ , StepVector 1 (Just (0.0001, 10.0)) 45.0 3 (0.12375232743459799, 5.926382691034315)+ , StepVector 1 (Just (0.0001, 10.0)) 45.0 4 (0.6801298079487221, 5.926382691034315)+ , StepVector 1 (Just (0.0001, 10.0)) 400.0 1 (0.0001, 5.926382691034315)+ , StepVector 1 (Just (0.0001, 10.0)) 400.0 2 (0.03287270236691793, 5.926382691034315)+ , StepVector 1 (Just (0.0001, 10.0)) 400.0 3 (0.13464539708317944, 5.926382691034315)+ , StepVector 1 (Just (0.0001, 10.0)) 400.0 4 (0.7400365821662549, 5.926382691034315)+ , StepVector 1 (Just (1.0, 1.0)) 0.0 1 (0.5190691936926471, 1.4918717310343146)+ , StepVector 1 (Just (1.0, 1.0)) 0.0 2 (1.0, 1.0)+ , StepVector 1 (Just (1.0, 1.0)) 0.0 3 (1.0, 1.0)+ , StepVector 1 (Just (1.0, 1.0)) 0.0 4 (1.0, 1.0)+ , StepVector 1 (Just (1.0, 1.0)) 0.006944444444444444 1 (0.5977753964961243, 1.4918717310343146)+ , StepVector 1 (Just (1.0, 1.0)) 0.006944444444444444 2 (2.046057528926491, 1.0)+ , StepVector 1 (Just (1.0, 1.0)) 0.006944444444444444 3 (2.722358302580804, 1.0)+ , StepVector 1 (Just (1.0, 1.0)) 0.006944444444444444 4 (6.865156869556282, 1.0)+ , StepVector 1 (Just (1.0, 1.0)) 0.5 1 (0.9884954134248733, 1.4918717310343146)+ , StepVector 1 (Just (1.0, 1.0)) 0.5 2 (1.1011303465568445, 1.0)+ , StepVector 1 (Just (1.0, 1.0)) 0.5 3 (1.3967160307851858, 1.0)+ , StepVector 1 (Just (1.0, 1.0)) 0.5 4 (3.1558571548181913, 1.0)+ , StepVector 1 (Just (1.0, 1.0)) 1.0 1 (0.9999987272341702, 1.4918717310343146)+ , StepVector 1 (Just (1.0, 1.0)) 1.0 2 (1.1210057486537282, 1.0)+ , StepVector 1 (Just (1.0, 1.0)) 1.0 3 (1.4967252494147611, 1.0)+ , StepVector 1 (Just (1.0, 1.0)) 1.0 4 (3.73168154985234, 1.0)+ , StepVector 1 (Just (1.0, 1.0)) 45.0 1 (1.0, 1.4918717310343146)+ , StepVector 1 (Just (1.0, 1.0)) 45.0 2 (1.3664273324928338, 1.0)+ , StepVector 1 (Just (1.0, 1.0)) 45.0 3 (2.504334625823992, 1.0)+ , StepVector 1 (Just (1.0, 1.0)) 45.0 4 (9.273134909092443, 1.0)+ , StepVector 1 (Just (1.0, 1.0)) 400.0 1 (1.0, 1.4918717310343146)+ , StepVector 1 (Just (1.0, 1.0)) 400.0 2 (1.4164002736284353, 1.0)+ , StepVector 1 (Just (1.0, 1.0)) 400.0 3 (2.709494064103667, 1.0)+ , StepVector 1 (Just (1.0, 1.0)) 400.0 4 (10.401415599854104, 1.0)+ , StepVector 1 (Just (1.0, 4.194588083372719)) 0.0 1 (0.18676178472953509, 3.065920160856728)+ , StepVector 1 (Just (1.0, 4.194588083372719)) 0.0 2 (1.0, 1.6224725272150176)+ , StepVector 1 (Just (1.0, 4.194588083372719)) 0.0 3 (1.0, 1.0)+ , StepVector 1 (Just (1.0, 4.194588083372719)) 0.0 4 (1.0, 1.0)+ , StepVector 1 (Just (1.0, 4.194588083372719)) 0.006944444444444444 1 (0.22076990936539628, 3.065920160856728)+ , StepVector 1 (Just (1.0, 4.194588083372719)) 0.006944444444444444 2 (1.7118852372834032, 1.6224725272150176)+ , StepVector 1 (Just (1.0, 4.194588083372719)) 0.006944444444444444 3 (2.172135771708534, 1.0)+ , StepVector 1 (Just (1.0, 4.194588083372719)) 0.006944444444444444 4 (4.991480845296668, 1.0)+ , StepVector 1 (Just (1.0, 4.194588083372719)) 0.5 1 (0.49457856595636623, 3.065920160856728)+ , StepVector 1 (Just (1.0, 4.194588083372719)) 0.5 2 (1.0688233665590596, 1.6224725272150176)+ , StepVector 1 (Just (1.0, 4.194588083372719)) 0.5 3 (1.269981600342258, 1.0)+ , StepVector 1 (Just (1.0, 4.194588083372719)) 0.5 4 (2.4671495971945903, 1.0)+ , StepVector 1 (Just (1.0, 4.194588083372719)) 1.0 1 (0.5175618585847412, 3.065920160856728)+ , StepVector 1 (Just (1.0, 4.194588083372719)) 1.0 2 (1.0823493963868487, 1.6224725272150176)+ , StepVector 1 (Just (1.0, 4.194588083372719)) 1.0 3 (1.3380419931656875, 1.0)+ , StepVector 1 (Just (1.0, 4.194588083372719)) 1.0 4 (2.8590218171795994, 1.0)+ , StepVector 1 (Just (1.0, 4.194588083372719)) 45.0 1 (0.7308192841763158, 3.065920160856728)+ , StepVector 1 (Just (1.0, 4.194588083372719)) 45.0 2 (1.2493688935124678, 1.6224725272150176)+ , StepVector 1 (Just (1.0, 4.194588083372719)) 45.0 3 (2.0237616789177633, 1.0)+ , StepVector 1 (Just (1.0, 4.194588083372719)) 45.0 4 (6.630209089820287, 1.0)+ , StepVector 1 (Just (1.0, 4.194588083372719)) 400.0 1 (0.7763723584667507, 3.065920160856728)+ , StepVector 1 (Just (1.0, 4.194588083372719)) 400.0 2 (1.2833775384237813, 1.6224725272150176)+ , StepVector 1 (Just (1.0, 4.194588083372719)) 400.0 3 (2.1633811275254695, 1.0)+ , StepVector 1 (Just (1.0, 4.194588083372719)) 400.0 4 (7.398050575641275, 1.0)+ , StepVector 1 (Just (1.0, 10.0)) 0.0 1 (0.1164277969653336, 5.926382691034315)+ , StepVector 1 (Just (1.0, 10.0)) 0.0 2 (1.0, 5.926382691034315)+ , StepVector 1 (Just (1.0, 10.0)) 0.0 3 (1.0, 5.926382691034315)+ , StepVector 1 (Just (1.0, 10.0)) 0.0 4 (1.0, 5.926382691034315)+ , StepVector 1 (Just (1.0, 10.0)) 0.006944444444444444 1 (0.13831831803780184, 5.926382691034315)+ , StepVector 1 (Just (1.0, 10.0)) 0.006944444444444444 2 (1.1046057528926492, 5.926382691034315)+ , StepVector 1 (Just (1.0, 10.0)) 0.006944444444444444 3 (1.1722358302580804, 5.926382691034315)+ , StepVector 1 (Just (1.0, 10.0)) 0.006944444444444444 4 (1.5865156869556283, 5.926382691034315)+ , StepVector 1 (Just (1.0, 10.0)) 0.5 1 (0.3251630375627063, 5.926382691034315)+ , StepVector 1 (Just (1.0, 10.0)) 0.5 2 (1.0101130346556846, 5.926382691034315)+ , StepVector 1 (Just (1.0, 10.0)) 0.5 3 (1.0396716030785185, 5.926382691034315)+ , StepVector 1 (Just (1.0, 10.0)) 0.5 4 (1.215585715481819, 5.926382691034315)+ , StepVector 1 (Just (1.0, 10.0)) 1.0 1 (0.340294330608703, 5.926382691034315)+ , StepVector 1 (Just (1.0, 10.0)) 1.0 2 (1.0121005748653729, 5.926382691034315)+ , StepVector 1 (Just (1.0, 10.0)) 1.0 3 (1.049672524941476, 5.926382691034315)+ , StepVector 1 (Just (1.0, 10.0)) 1.0 4 (1.273168154985234, 5.926382691034315)+ , StepVector 1 (Just (1.0, 10.0)) 45.0 1 (0.48051008542269463, 5.926382691034315)+ , StepVector 1 (Just (1.0, 10.0)) 45.0 2 (1.0366427332492834, 5.926382691034315)+ , StepVector 1 (Just (1.0, 10.0)) 45.0 3 (1.150433462582399, 5.926382691034315)+ , StepVector 1 (Just (1.0, 10.0)) 45.0 4 (1.8273134909092443, 5.926382691034315)+ , StepVector 1 (Just (1.0, 10.0)) 400.0 1 (0.5104610077539702, 5.926382691034315)+ , StepVector 1 (Just (1.0, 10.0)) 400.0 2 (1.0416400273628434, 5.926382691034315)+ , StepVector 1 (Just (1.0, 10.0)) 400.0 3 (1.1709494064103667, 5.926382691034315)+ , StepVector 1 (Just (1.0, 10.0)) 400.0 4 (1.9401415599854106, 5.926382691034315)+ , StepVector 1 (Just (4.1283, 1.0)) 0.0 1 (1.9698621453141367, 1.4918717310343146)+ , StepVector 1 (Just (4.1283, 1.0)) 0.0 2 (4.1283, 1.0)+ , StepVector 1 (Just (4.1283, 1.0)) 0.0 3 (4.1283, 1.0)+ , StepVector 1 (Just (4.1283, 1.0)) 0.0 4 (4.1283, 1.0)+ , StepVector 1 (Just (4.1283, 1.0)) 0.006944444444444444 1 (2.112833688081948, 1.4918717310343146)+ , StepVector 1 (Just (4.1283, 1.0)) 0.006944444444444444 2 (4.343616671264395, 1.0)+ , StepVector 1 (Just (4.1283, 1.0)) 0.006944444444444444 3 (4.485189226730096, 1.0)+ , StepVector 1 (Just (4.1283, 1.0)) 0.006944444444444444 4 (5.35188729349908, 1.0)+ , StepVector 1 (Just (4.1283, 1.0)) 0.5 1 (3.2621611345234798, 1.4918717310343146)+ , StepVector 1 (Just (4.1283, 1.0)) 0.5 2 (4.164818822298755, 1.0)+ , StepVector 1 (Just (4.1283, 1.0)) 0.5 3 (4.273405953665746, 1.0)+ , StepVector 1 (Just (4.1283, 1.0)) 0.5 4 (4.919557098776611, 1.0)+ , StepVector 1 (Just (4.1283, 1.0)) 1.0 1 (3.348861577485005, 1.4918717310343146)+ , StepVector 1 (Just (4.1283, 1.0)) 1.0 2 (4.177174462163136, 1.0)+ , StepVector 1 (Just (4.1283, 1.0)) 1.0 3 (4.328935066852582, 1.0)+ , StepVector 1 (Just (4.1283, 1.0)) 1.0 4 (5.231678205541075, 1.0)+ , StepVector 1 (Just (4.1283, 1.0)) 45.0 1 (4.1283, 1.4918717310343146)+ , StepVector 1 (Just (4.1283, 1.0)) 45.0 2 (4.571526948274232, 1.0)+ , StepVector 1 (Just (4.1283, 1.0)) 45.0 3 (5.947928576425219, 1.0)+ , StepVector 1 (Just (4.1283, 1.0)) 45.0 4 (14.135403764536361, 1.0)+ , StepVector 1 (Just (4.1283, 1.0)) 400.0 1 (4.1283, 1.4918717310343146)+ , StepVector 1 (Just (4.1283, 1.0)) 400.0 2 (4.770250458631877, 1.0)+ , StepVector 1 (Just (4.1283, 1.0)) 400.0 3 (6.763770166523156, 1.0)+ , StepVector 1 (Just (4.1283, 1.0)) 400.0 4 (18.62214988036926, 1.0)+ , StepVector 1 (Just (4.1283, 4.194588083372719)) 0.0 1 (0.688327162516543, 3.065920160856728)+ , StepVector 1 (Just (4.1283, 4.194588083372719)) 0.0 2 (4.1283, 1.6224725272150176)+ , StepVector 1 (Just (4.1283, 4.194588083372719)) 0.0 3 (4.1283, 1.0)+ , StepVector 1 (Just (4.1283, 4.194588083372719)) 0.0 4 (4.1283, 1.0)+ , StepVector 1 (Just (4.1283, 4.194588083372719)) 0.006944444444444444 1 (0.7723939513781536, 3.065920160856728)+ , StepVector 1 (Just (4.1283, 4.194588083372719)) 0.006944444444444444 2 (4.2748318640471235, 1.6224725272150176)+ , StepVector 1 (Just (4.1283, 4.194588083372719)) 0.006944444444444444 3 (4.371177819650489, 1.0)+ , StepVector 1 (Just (4.1283, 4.194588083372719)) 0.006944444444444444 4 (4.961001554821236, 1.0)+ , StepVector 1 (Just (4.1283, 4.194588083372719)) 0.5 1 (1.6322023829383279, 3.065920160856728)+ , StepVector 1 (Just (4.1283, 4.194588083372719)) 0.5 2 (4.153152562845314, 1.6224725272150176)+ , StepVector 1 (Just (4.1283, 4.194588083372719)) 0.5 3 (4.227050578625043, 1.0)+ , StepVector 1 (Just (4.1283, 4.194588083372719)) 0.5 4 (4.666783048913028, 1.0)+ , StepVector 1 (Just (4.1283, 4.194588083372719)) 1.0 1 (1.6763251935314982, 3.065920160856728)+ , StepVector 1 (Just (4.1283, 4.194588083372719)) 1.0 2 (4.1615610847223765, 1.6224725272150176)+ , StepVector 1 (Just (4.1283, 4.194588083372719)) 1.0 3 (4.264840427485187, 1.0)+ , StepVector 1 (Just (4.1283, 4.194588083372719)) 1.0 4 (4.879194318853606, 1.0)+ , StepVector 1 (Just (4.1283, 4.194588083372719)) 45.0 1 (2.942458898819786, 3.065920160856728)+ , StepVector 1 (Just (4.1283, 4.194588083372719)) 45.0 2 (4.42993419555558, 1.6224725272150176)+ , StepVector 1 (Just (4.1283, 4.194588083372719)) 45.0 3 (5.3666321997839725, 1.0)+ , StepVector 1 (Just (4.1283, 4.194588083372719)) 45.0 4 (10.938546321010149, 1.0)+ , StepVector 1 (Just (4.1283, 4.194588083372719)) 400.0 1 (3.6411691112365006, 3.065920160856728)+ , StepVector 1 (Just (4.1283, 4.194588083372719)) 400.0 2 (4.565173730105773, 1.6224725272150176)+ , StepVector 1 (Just (4.1283, 4.194588083372719)) 400.0 3 (5.921846007717237, 1.0)+ , StepVector 1 (Just (4.1283, 4.194588083372719)) 400.0 4 (13.991961869367186, 1.0)+ , StepVector 1 (Just (4.1283, 10.0)) 0.0 1 (0.4266279593915145, 5.926382691034315)+ , StepVector 1 (Just (4.1283, 10.0)) 0.0 2 (4.1283, 5.926382691034315)+ , StepVector 1 (Just (4.1283, 10.0)) 0.0 3 (4.1283, 5.926382691034315)+ , StepVector 1 (Just (4.1283, 10.0)) 0.0 4 (4.1283, 5.926382691034315)+ , StepVector 1 (Just (4.1283, 10.0)) 0.006944444444444444 1 (0.48299073758377764, 5.926382691034315)+ , StepVector 1 (Just (4.1283, 10.0)) 0.006944444444444444 2 (4.14983166712644, 5.926382691034315)+ , StepVector 1 (Just (4.1283, 10.0)) 0.006944444444444444 3 (4.16398892267301, 5.926382691034315)+ , StepVector 1 (Just (4.1283, 10.0)) 0.006944444444444444 4 (4.250658729349908, 5.926382691034315)+ , StepVector 1 (Just (4.1283, 10.0)) 0.5 1 (1.0731018530915, 5.926382691034315)+ , StepVector 1 (Just (4.1283, 10.0)) 0.5 2 (4.131951882229876, 5.926382691034315)+ , StepVector 1 (Just (4.1283, 10.0)) 0.5 3 (4.142810595366575, 5.926382691034315)+ , StepVector 1 (Just (4.1283, 10.0)) 0.5 4 (4.207425709877661, 5.926382691034315)+ , StepVector 1 (Just (4.1283, 10.0)) 1.0 1 (1.1021754313217746, 5.926382691034315)+ , StepVector 1 (Just (4.1283, 10.0)) 1.0 2 (4.133187446216315, 5.926382691034315)+ , StepVector 1 (Just (4.1283, 10.0)) 1.0 3 (4.148363506685257, 5.926382691034315)+ , StepVector 1 (Just (4.1283, 10.0)) 1.0 4 (4.238637820554107, 5.926382691034315)+ , StepVector 1 (Just (4.1283, 10.0)) 45.0 1 (1.934652255951628, 5.926382691034315)+ , StepVector 1 (Just (4.1283, 10.0)) 45.0 2 (4.172622694827424, 5.926382691034315)+ , StepVector 1 (Just (4.1283, 10.0)) 45.0 3 (4.310262857642522, 5.926382691034315)+ , StepVector 1 (Just (4.1283, 10.0)) 45.0 4 (5.1290103764536354, 5.926382691034315)+ , StepVector 1 (Just (4.1283, 10.0)) 400.0 1 (2.394050784593991, 5.926382691034315)+ , StepVector 1 (Just (4.1283, 10.0)) 400.0 2 (4.192495045863188, 5.926382691034315)+ , StepVector 1 (Just (4.1283, 10.0)) 400.0 3 (4.391847016652316, 5.926382691034315)+ , StepVector 1 (Just (4.1283, 10.0)) 400.0 4 (5.577684988036926, 5.926382691034315)+ , StepVector 1 (Just (1000.0, 1.0)) 0.0 1 (276.07483436981875, 1.4918717310343146)+ , StepVector 1 (Just (1000.0, 1.0)) 0.0 2 (1000.0, 1.0)+ , StepVector 1 (Just (1000.0, 1.0)) 0.0 3 (1000.0, 1.0)+ , StepVector 1 (Just (1000.0, 1.0)) 0.0 4 (1000.0, 1.0)+ , StepVector 1 (Just (1000.0, 1.0)) 0.006944444444444444 1 (277.32596658617865, 1.4918717310343146)+ , StepVector 1 (Just (1000.0, 1.0)) 0.006944444444444444 2 (1000.00001562622, 1.0)+ , StepVector 1 (Just (1000.0, 1.0)) 0.006944444444444444 3 (1000.0000267546975, 1.0)+ , StepVector 1 (Just (1000.0, 1.0)) 0.006944444444444444 4 (1000.0000946945609, 1.0)+ , StepVector 1 (Just (1000.0, 1.0)) 0.5 1 (291.2913365605847, 1.4918717310343146)+ , StepVector 1 (Just (1000.0, 1.0)) 0.5 2 (1000.0000817929213, 1.0)+ , StepVector 1 (Just (1000.0, 1.0)) 0.5 3 (1000.0003309957921, 1.0)+ , StepVector 1 (Just (1000.0, 1.0)) 0.5 4 (1000.0018135935829, 1.0)+ , StepVector 1 (Just (1000.0, 1.0)) 1.0 1 (291.36366719142313, 1.4918717310343146)+ , StepVector 1 (Just (1000.0, 1.0)) 1.0 2 (1000.0001507749704, 1.0)+ , StepVector 1 (Just (1000.0, 1.0)) 1.0 3 (1000.0006189743576, 1.0)+ , StepVector 1 (Just (1000.0, 1.0)) 1.0 4 (1000.0034040423155, 1.0)+ , StepVector 1 (Just (1000.0, 1.0)) 45.0 1 (294.7130255473377, 1.4918717310343146)+ , StepVector 1 (Just (1000.0, 1.0)) 45.0 2 (1000.00594154031, 1.0)+ , StepVector 1 (Just (1000.0, 1.0)) 45.0 3 (1000.0243924620967, 1.0)+ , StepVector 1 (Just (1000.0, 1.0)) 45.0 4 (1000.1341471014666, 1.0)+ , StepVector 1 (Just (1000.0, 1.0)) 400.0 1 (320.4051046030849, 1.4918717310343146)+ , StepVector 1 (Just (1000.0, 1.0)) 400.0 2 (1000.0498387210777, 1.0)+ , StepVector 1 (Just (1000.0, 1.0)) 400.0 3 (1000.204608409842, 1.0)+ , StepVector 1 (Just (1000.0, 1.0)) 400.0 4 (1001.1252502927861, 1.0)+ , StepVector 1 (Just (1000.0, 4.194588083372719)) 0.0 1 (72.89337768182203, 3.065920160856728)+ , StepVector 1 (Just (1000.0, 4.194588083372719)) 0.0 2 (1000.0, 1.6224725272150176)+ , StepVector 1 (Just (1000.0, 4.194588083372719)) 0.0 3 (1000.0, 1.0)+ , StepVector 1 (Just (1000.0, 4.194588083372719)) 0.0 4 (1000.0, 1.0)+ , StepVector 1 (Just (1000.0, 4.194588083372719)) 0.006944444444444444 1 (78.88766672616913, 3.065920160856728)+ , StepVector 1 (Just (1000.0, 4.194588083372719)) 0.006944444444444444 2 (1000.0000106342864, 1.6224725272150176)+ , StepVector 1 (Just (1000.0, 4.194588083372719)) 0.006944444444444444 3 (1000.0000182076737, 1.0)+ , StepVector 1 (Just (1000.0, 4.194588083372719)) 0.006944444444444444 4 (1000.0000644435494, 1.0)+ , StepVector 1 (Just (1000.0, 4.194588083372719)) 0.5 1 (145.67489388411784, 3.065920160856728)+ , StepVector 1 (Just (1000.0, 4.194588083372719)) 0.5 2 (1000.0000556634521, 1.6224725272150176)+ , StepVector 1 (Just (1000.0, 4.194588083372719)) 0.5 3 (1000.0002252562708, 1.0)+ , StepVector 1 (Just (1000.0, 4.194588083372719)) 0.5 4 (1000.001234225138, 1.0)+ , StepVector 1 (Just (1000.0, 4.194588083372719)) 1.0 1 (145.84651164612652, 3.065920160856728)+ , StepVector 1 (Just (1000.0, 4.194588083372719)) 1.0 2 (1000.0001026085781, 1.6224725272150176)+ , StepVector 1 (Just (1000.0, 4.194588083372719)) 1.0 3 (1000.0004212375471, 1.0)+ , StepVector 1 (Just (1000.0, 4.194588083372719)) 1.0 4 (1000.0023165910139, 1.0)+ , StepVector 1 (Just (1000.0, 4.194588083372719)) 45.0 1 (147.52336907157843, 3.065920160856728)+ , StepVector 1 (Just (1000.0, 4.194588083372719)) 45.0 2 (1000.0040434629229, 1.6224725272150176)+ , StepVector 1 (Just (1000.0, 4.194588083372719)) 45.0 3 (1000.0166000752229, 1.0)+ , StepVector 1 (Just (1000.0, 4.194588083372719)) 45.0 4 (1000.0912926282904, 1.0)+ , StepVector 1 (Just (1000.0, 4.194588083372719)) 400.0 1 (160.38395456391657, 3.065920160856728)+ , StepVector 1 (Just (1000.0, 4.194588083372719)) 400.0 2 (1000.0339173026331, 1.6224725272150176)+ , StepVector 1 (Just (1000.0, 4.194588083372719)) 400.0 3 (1000.139244451058, 1.0)+ , StepVector 1 (Just (1000.0, 4.194588083372719)) 400.0 4 (1000.7657791751716, 1.0)+ , StepVector 1 (Just (1000.0, 10.0)) 0.0 1 (42.23665228396239, 5.926382691034315)+ , StepVector 1 (Just (1000.0, 10.0)) 0.0 2 (1000.0, 5.926382691034315)+ , StepVector 1 (Just (1000.0, 10.0)) 0.0 3 (1000.0, 5.926382691034315)+ , StepVector 1 (Just (1000.0, 10.0)) 0.0 4 (1000.0, 5.926382691034315)+ , StepVector 1 (Just (1000.0, 10.0)) 0.006944444444444444 1 (46.64564594495611, 5.926382691034315)+ , StepVector 1 (Just (1000.0, 10.0)) 0.006944444444444444 2 (1000.000001562622, 5.926382691034315)+ , StepVector 1 (Just (1000.0, 10.0)) 0.006944444444444444 3 (1000.0000026754698, 5.926382691034315)+ , StepVector 1 (Just (1000.0, 10.0)) 0.006944444444444444 4 (1000.0000094694561, 5.926382691034315)+ , StepVector 1 (Just (1000.0, 10.0)) 0.5 1 (95.76870178616187, 5.926382691034315)+ , StepVector 1 (Just (1000.0, 10.0)) 0.5 2 (1000.0000081792921, 5.926382691034315)+ , StepVector 1 (Just (1000.0, 10.0)) 0.5 3 (1000.0000330995792, 5.926382691034315)+ , StepVector 1 (Just (1000.0, 10.0)) 0.5 4 (1000.0001813593583, 5.926382691034315)+ , StepVector 1 (Just (1000.0, 10.0)) 1.0 1 (95.89333961306478, 5.926382691034315)+ , StepVector 1 (Just (1000.0, 10.0)) 1.0 2 (1000.000015077497, 5.926382691034315)+ , StepVector 1 (Just (1000.0, 10.0)) 1.0 3 (1000.0000618974359, 5.926382691034315)+ , StepVector 1 (Just (1000.0, 10.0)) 1.0 4 (1000.0003404042317, 5.926382691034315)+ , StepVector 1 (Just (1000.0, 10.0)) 45.0 1 (96.99588969429269, 5.926382691034315)+ , StepVector 1 (Just (1000.0, 10.0)) 45.0 2 (1000.0005941540311, 5.926382691034315)+ , StepVector 1 (Just (1000.0, 10.0)) 45.0 3 (1000.0024392462096, 5.926382691034315)+ , StepVector 1 (Just (1000.0, 10.0)) 45.0 4 (1000.0134147101467, 5.926382691034315)+ , StepVector 1 (Just (1000.0, 10.0)) 400.0 1 (105.45166141147467, 5.926382691034315)+ , StepVector 1 (Just (1000.0, 10.0)) 400.0 2 (1000.0049838721077, 5.926382691034315)+ , StepVector 1 (Just (1000.0, 10.0)) 400.0 3 (1000.0204608409841, 5.926382691034315)+ , StepVector 1 (Just (1000.0, 10.0)) 400.0 4 (1000.1125250292786, 5.926382691034315)+ , StepVector 1 (Just (36500.0, 1.0)) 0.0 1 (7483.4905391444845, 1.4918717310343146)+ , StepVector 1 (Just (36500.0, 1.0)) 0.0 2 (36500.0, 1.0)+ , StepVector 1 (Just (36500.0, 1.0)) 0.0 3 (36500.0, 1.0)+ , StepVector 1 (Just (36500.0, 1.0)) 0.0 4 (36500.0, 1.0)+ , StepVector 1 (Just (36500.0, 1.0)) 0.006944444444444444 1 (7303.386202408987, 1.4918717310343146)+ , StepVector 1 (Just (36500.0, 1.0)) 0.006944444444444444 2 (36500.0, 1.0)+ , StepVector 1 (Just (36500.0, 1.0)) 0.006944444444444444 3 (36500.0, 1.0)+ , StepVector 1 (Just (36500.0, 1.0)) 0.006944444444444444 4 (36500.0, 1.0)+ , StepVector 1 (Just (36500.0, 1.0)) 0.5 1 (5297.303859927724, 1.4918717310343146)+ , StepVector 1 (Just (36500.0, 1.0)) 0.5 2 (36500.0, 1.0)+ , StepVector 1 (Just (36500.0, 1.0)) 0.5 3 (36500.0, 1.0)+ , StepVector 1 (Just (36500.0, 1.0)) 0.5 4 (36500.0, 1.0)+ , StepVector 1 (Just (36500.0, 1.0)) 1.0 1 (5292.781771598717, 1.4918717310343146)+ , StepVector 1 (Just (36500.0, 1.0)) 1.0 2 (36500.0, 1.0)+ , StepVector 1 (Just (36500.0, 1.0)) 1.0 3 (36500.0, 1.0)+ , StepVector 1 (Just (36500.0, 1.0)) 1.0 4 (36500.0, 1.0)+ , StepVector 1 (Just (36500.0, 1.0)) 45.0 1 (5294.4442297978385, 1.4918717310343146)+ , StepVector 1 (Just (36500.0, 1.0)) 45.0 2 (36500.0, 1.0)+ , StepVector 1 (Just (36500.0, 1.0)) 45.0 3 (36500.0, 1.0)+ , StepVector 1 (Just (36500.0, 1.0)) 45.0 4 (36500.0, 1.0)+ , StepVector 1 (Just (36500.0, 1.0)) 400.0 1 (5307.892516795593, 1.4918717310343146)+ , StepVector 1 (Just (36500.0, 1.0)) 400.0 2 (36500.0, 1.0)+ , StepVector 1 (Just (36500.0, 1.0)) 400.0 3 (36500.0, 1.0)+ , StepVector 1 (Just (36500.0, 1.0)) 400.0 4 (36500.0, 1.0)+ , StepVector 1 (Just (36500.0, 4.194588083372719)) 0.0 1 (1530.4680451928025, 3.065920160856728)+ , StepVector 1 (Just (36500.0, 4.194588083372719)) 0.0 2 (36500.0, 1.6224725272150176)+ , StepVector 1 (Just (36500.0, 4.194588083372719)) 0.0 3 (36500.0, 1.0)+ , StepVector 1 (Just (36500.0, 4.194588083372719)) 0.0 4 (36500.0, 1.0)+ , StepVector 1 (Just (36500.0, 4.194588083372719)) 0.006944444444444444 1 (1622.454080095556, 3.065920160856728)+ , StepVector 1 (Just (36500.0, 4.194588083372719)) 0.006944444444444444 2 (36500.0, 1.6224725272150176)+ , StepVector 1 (Just (36500.0, 4.194588083372719)) 0.006944444444444444 3 (36500.0, 1.0)+ , StepVector 1 (Just (36500.0, 4.194588083372719)) 0.006944444444444444 4 (36500.0, 1.0)+ , StepVector 1 (Just (36500.0, 4.194588083372719)) 0.5 1 (2647.049030400001, 3.065920160856728)+ , StepVector 1 (Just (36500.0, 4.194588083372719)) 0.5 2 (36500.0, 1.6224725272150176)+ , StepVector 1 (Just (36500.0, 4.194588083372719)) 0.5 3 (36500.0, 1.0)+ , StepVector 1 (Just (36500.0, 4.194588083372719)) 0.5 4 (36500.0, 1.0)+ , StepVector 1 (Just (36500.0, 4.194588083372719)) 1.0 1 (2649.3779160050353, 3.065920160856728)+ , StepVector 1 (Just (36500.0, 4.194588083372719)) 1.0 2 (36500.0, 1.6224725272150176)+ , StepVector 1 (Just (36500.0, 4.194588083372719)) 1.0 3 (36500.0, 1.0)+ , StepVector 1 (Just (36500.0, 4.194588083372719)) 1.0 4 (36500.0, 1.0)+ , StepVector 1 (Just (36500.0, 4.194588083372719)) 45.0 1 (2650.2196456732454, 3.065920160856728)+ , StepVector 1 (Just (36500.0, 4.194588083372719)) 45.0 2 (36500.0, 1.6224725272150176)+ , StepVector 1 (Just (36500.0, 4.194588083372719)) 45.0 3 (36500.0, 1.0)+ , StepVector 1 (Just (36500.0, 4.194588083372719)) 45.0 4 (36500.0, 1.0)+ , StepVector 1 (Just (36500.0, 4.194588083372719)) 400.0 1 (2656.9514031259937, 3.065920160856728)+ , StepVector 1 (Just (36500.0, 4.194588083372719)) 400.0 2 (36500.0, 1.6224725272150176)+ , StepVector 1 (Just (36500.0, 4.194588083372719)) 400.0 3 (36500.0, 1.0)+ , StepVector 1 (Just (36500.0, 4.194588083372719)) 400.0 4 (36500.0, 1.0)+ , StepVector 1 (Just (36500.0, 10.0)) 0.0 1 (813.211474455443, 5.926382691034315)+ , StepVector 1 (Just (36500.0, 10.0)) 0.0 2 (36500.0, 5.926382691034315)+ , StepVector 1 (Just (36500.0, 10.0)) 0.0 3 (36500.0, 5.926382691034315)+ , StepVector 1 (Just (36500.0, 10.0)) 0.0 4 (36500.0, 5.926382691034315)+ , StepVector 1 (Just (36500.0, 10.0)) 0.006944444444444444 1 (889.5638502332042, 5.926382691034315)+ , StepVector 1 (Just (36500.0, 10.0)) 0.006944444444444444 2 (36500.0, 5.926382691034315)+ , StepVector 1 (Just (36500.0, 10.0)) 0.006944444444444444 3 (36500.0, 5.926382691034315)+ , StepVector 1 (Just (36500.0, 10.0)) 0.006944444444444444 4 (36500.0, 5.926382691034315)+ , StepVector 1 (Just (36500.0, 10.0)) 0.5 1 (1740.020689636713, 5.926382691034315)+ , StepVector 1 (Just (36500.0, 10.0)) 0.5 2 (36500.0, 5.926382691034315)+ , StepVector 1 (Just (36500.0, 10.0)) 0.5 3 (36500.0, 5.926382691034315)+ , StepVector 1 (Just (36500.0, 10.0)) 0.5 4 (36500.0, 5.926382691034315)+ , StepVector 1 (Just (36500.0, 10.0)) 1.0 1 (1741.9521180068818, 5.926382691034315)+ , StepVector 1 (Just (36500.0, 10.0)) 1.0 2 (36500.0, 5.926382691034315)+ , StepVector 1 (Just (36500.0, 10.0)) 1.0 3 (36500.0, 5.926382691034315)+ , StepVector 1 (Just (36500.0, 10.0)) 1.0 4 (36500.0, 5.926382691034315)+ , StepVector 1 (Just (36500.0, 10.0)) 45.0 1 (1742.5063841420515, 5.926382691034315)+ , StepVector 1 (Just (36500.0, 10.0)) 45.0 2 (36500.0, 5.926382691034315)+ , StepVector 1 (Just (36500.0, 10.0)) 45.0 3 (36500.0, 5.926382691034315)+ , StepVector 1 (Just (36500.0, 10.0)) 45.0 4 (36500.0, 5.926382691034315)+ , StepVector 1 (Just (36500.0, 10.0)) 400.0 1 (1746.9324815627165, 5.926382691034315)+ , StepVector 1 (Just (36500.0, 10.0)) 400.0 2 (36500.0, 5.926382691034315)+ , StepVector 1 (Just (36500.0, 10.0)) 400.0 3 (36500.0, 5.926382691034315)+ , StepVector 1 (Just (36500.0, 10.0)) 400.0 4 (36500.0, 5.926382691034315)+ , StepVector 2 Nothing 0.0 1 (2.462798, 7.614116)+ , StepVector 2 Nothing 0.0 2 (11.949056, 5.356124178155698)+ , StepVector 2 Nothing 0.0 3 (79.640406, 1.0)+ , StepVector 2 Nothing 0.0 4 (79.640406, 1.0)+ , StepVector 2 (Just (0.0001, 1.0)) 0.0 1 (0.0001, 1.5042458491001744)+ , StepVector 2 (Just (0.0001, 1.0)) 0.0 2 (0.0001, 1.1172835591001746)+ , StepVector 2 (Just (0.0001, 1.0)) 0.0 3 (0.0001, 1.0)+ , StepVector 2 (Just (0.0001, 1.0)) 0.0 4 (0.0001, 1.0)+ , StepVector 2 (Just (0.0001, 1.0)) 0.006944444444444444 1 (0.0001, 1.5042458491001744)+ , StepVector 2 (Just (0.0001, 1.0)) 0.006944444444444444 2 (8.62028065329838, 1.1172835591001746)+ , StepVector 2 (Just (0.0001, 1.0)) 0.006944444444444444 3 (10.368005059871361, 1.0)+ , StepVector 2 (Just (0.0001, 1.0)) 0.006944444444444444 4 (69.1491388215093, 1.0)+ , StepVector 2 (Just (0.0001, 1.0)) 0.5 1 (0.0001, 1.5042458491001744)+ , StepVector 2 (Just (0.0001, 1.0)) 0.5 2 (4.7876074677538565, 1.1172835591001746)+ , StepVector 2 (Just (0.0001, 1.0)) 0.5 3 (7.735999636785466, 1.0)+ , StepVector 2 (Just (0.0001, 1.0)) 0.5 4 (53.55989271881453, 1.0)+ , StepVector 2 (Just (0.0001, 1.0)) 1.0 1 (0.0001, 1.5042458491001744)+ , StepVector 2 (Just (0.0001, 1.0)) 1.0 2 (4.544624683421755, 1.1172835591001746)+ , StepVector 2 (Just (0.0001, 1.0)) 1.0 3 (7.617386986108458, 1.0)+ , StepVector 2 (Just (0.0001, 1.0)) 1.0 4 (52.94131769091274, 1.0)+ , StepVector 2 (Just (0.0001, 1.0)) 45.0 1 (0.0001, 1.5042458491001744)+ , StepVector 2 (Just (0.0001, 1.0)) 45.0 2 (5.028925054459579, 1.1172835591001746)+ , StepVector 2 (Just (0.0001, 1.0)) 45.0 3 (8.4511114249072, 1.0)+ , StepVector 2 (Just (0.0001, 1.0)) 45.0 4 (58.7514807198863, 1.0)+ , StepVector 2 (Just (0.0001, 1.0)) 400.0 1 (0.0001, 1.5042458491001744)+ , StepVector 2 (Just (0.0001, 1.0)) 400.0 2 (5.319385386674042, 1.1172835591001746)+ , StepVector 2 (Just (0.0001, 1.0)) 400.0 3 (8.939234109519173, 1.0)+ , StepVector 2 (Just (0.0001, 1.0)) 400.0 4 (62.14490669457264, 1.0)+ , StepVector 2 (Just (0.0001, 4.194588083372719)) 0.0 1 (0.0001, 4.392180247117252)+ , StepVector 2 (Just (0.0001, 4.194588083372719)) 0.0 2 (0.0001, 4.142571859378209)+ , StepVector 2 (Just (0.0001, 4.194588083372719)) 0.0 3 (0.0001, 3.892963471639167)+ , StepVector 2 (Just (0.0001, 4.194588083372719)) 0.0 4 (0.0001, 3.643355083900124)+ , StepVector 2 (Just (0.0001, 4.194588083372719)) 0.006944444444444444 1 (0.0001, 4.392180247117252)+ , StepVector 2 (Just (0.0001, 4.194588083372719)) 0.006944444444444444 2 (5.866488014143673, 4.142571859378209)+ , StepVector 2 (Just (0.0001, 4.194588083372719)) 0.006944444444444444 3 (7.055886464490884, 3.892963471639167)+ , StepVector 2 (Just (0.0001, 4.194588083372719)) 0.006944444444444444 4 (47.05886928192219, 3.643355083900124)+ , StepVector 2 (Just (0.0001, 4.194588083372719)) 0.5 1 (0.0001, 4.392180247117252)+ , StepVector 2 (Just (0.0001, 4.194588083372719)) 0.5 2 (3.2581960371994203, 4.142571859378209)+ , StepVector 2 (Just (0.0001, 4.194588083372719)) 0.5 3 (5.264698357401247, 3.892963471639167)+ , StepVector 2 (Just (0.0001, 4.194588083372719)) 0.5 4 (36.44974516207075, 3.643355083900124)+ , StepVector 2 (Just (0.0001, 4.194588083372719)) 1.0 1 (0.0001, 4.392180247117252)+ , StepVector 2 (Just (0.0001, 4.194588083372719)) 1.0 2 (3.092836243596524, 4.142571859378209)+ , StepVector 2 (Just (0.0001, 4.194588083372719)) 1.0 3 (5.183977562763242, 3.892963471639167)+ , StepVector 2 (Just (0.0001, 4.194588083372719)) 1.0 4 (36.028779375449666, 3.643355083900124)+ , StepVector 2 (Just (0.0001, 4.194588083372719)) 45.0 1 (0.0001, 4.392180247117252)+ , StepVector 2 (Just (0.0001, 4.194588083372719)) 45.0 2 (3.422422595225306, 4.142571859378209)+ , StepVector 2 (Just (0.0001, 4.194588083372719)) 45.0 3 (5.751361385861677, 3.892963471639167)+ , StepVector 2 (Just (0.0001, 4.194588083372719)) 45.0 4 (39.98283464694206, 3.643355083900124)+ , StepVector 2 (Just (0.0001, 4.194588083372719)) 400.0 1 (0.0001, 4.392180247117252)+ , StepVector 2 (Just (0.0001, 4.194588083372719)) 400.0 2 (3.6200928158412884, 4.142571859378209)+ , StepVector 2 (Just (0.0001, 4.194588083372719)) 400.0 3 (6.083548979325119, 3.892963471639167)+ , StepVector 2 (Just (0.0001, 4.194588083372719)) 400.0 4 (42.29220080357435, 3.643355083900124)+ , StepVector 2 (Just (0.0001, 10.0)) 0.0 1 (0.0001, 9.640321269100175)+ , StepVector 2 (Just (0.0001, 10.0)) 0.0 2 (0.0001, 9.640321269100175)+ , StepVector 2 (Just (0.0001, 10.0)) 0.0 3 (0.0001, 9.640321269100175)+ , StepVector 2 (Just (0.0001, 10.0)) 0.0 4 (0.0001, 9.640321269100175)+ , StepVector 2 (Just (0.0001, 10.0)) 0.006944444444444444 1 (0.0001, 9.640321269100175)+ , StepVector 2 (Just (0.0001, 10.0)) 0.006944444444444444 2 (0.8621180653298379, 9.640321269100175)+ , StepVector 2 (Just (0.0001, 10.0)) 0.006944444444444444 3 (1.036890505987136, 9.640321269100175)+ , StepVector 2 (Just (0.0001, 10.0)) 0.006944444444444444 4 (6.9150038821509305, 9.640321269100175)+ , StepVector 2 (Just (0.0001, 10.0)) 0.5 1 (0.0001, 9.640321269100175)+ , StepVector 2 (Just (0.0001, 10.0)) 0.5 2 (0.4788507467753858, 9.640321269100175)+ , StepVector 2 (Just (0.0001, 10.0)) 0.5 3 (0.7736899636785466, 9.640321269100175)+ , StepVector 2 (Just (0.0001, 10.0)) 0.5 4 (5.356079271881453, 9.640321269100175)+ , StepVector 2 (Just (0.0001, 10.0)) 1.0 1 (0.0001, 9.640321269100175)+ , StepVector 2 (Just (0.0001, 10.0)) 1.0 2 (0.45455246834217555, 9.640321269100175)+ , StepVector 2 (Just (0.0001, 10.0)) 1.0 3 (0.7618286986108458, 9.640321269100175)+ , StepVector 2 (Just (0.0001, 10.0)) 1.0 4 (5.2942217690912745, 9.640321269100175)+ , StepVector 2 (Just (0.0001, 10.0)) 45.0 1 (0.0001, 9.640321269100175)+ , StepVector 2 (Just (0.0001, 10.0)) 45.0 2 (0.5029825054459579, 9.640321269100175)+ , StepVector 2 (Just (0.0001, 10.0)) 45.0 3 (0.84520114249072, 9.640321269100175)+ , StepVector 2 (Just (0.0001, 10.0)) 45.0 4 (5.875238071988631, 9.640321269100175)+ , StepVector 2 (Just (0.0001, 10.0)) 400.0 1 (0.0001, 9.640321269100175)+ , StepVector 2 (Just (0.0001, 10.0)) 400.0 2 (0.5320285386674042, 9.640321269100175)+ , StepVector 2 (Just (0.0001, 10.0)) 400.0 3 (0.8940134109519173, 9.640321269100175)+ , StepVector 2 (Just (0.0001, 10.0)) 400.0 4 (6.214580669457264, 9.640321269100175)+ , StepVector 2 (Just (1.0, 1.0)) 0.0 1 (0.3532456335132542, 1.5042458491001744)+ , StepVector 2 (Just (1.0, 1.0)) 0.0 2 (1.0, 1.1172835591001746)+ , StepVector 2 (Just (1.0, 1.0)) 0.0 3 (1.0, 1.0)+ , StepVector 2 (Just (1.0, 1.0)) 0.0 4 (1.0, 1.0)+ , StepVector 2 (Just (1.0, 1.0)) 0.006944444444444444 1 (0.5484329032074956, 1.5042458491001744)+ , StepVector 2 (Just (1.0, 1.0)) 0.006944444444444444 2 (19.207272573619168, 1.1172835591001746)+ , StepVector 2 (Just (1.0, 1.0)) 0.006944444444444444 3 (23.45323720105931, 1.0)+ , StepVector 2 (Just (1.0, 1.0)) 0.006944444444444444 4 (151.30340979774786, 1.0)+ , StepVector 2 (Just (1.0, 1.0)) 0.5 1 (0.2869453338741392, 1.5042458491001744)+ , StepVector 2 (Just (1.0, 1.0)) 0.5 2 (28.06295395341064, 1.1172835591001746)+ , StepVector 2 (Just (1.0, 1.0)) 0.5 3 (45.054180261872915, 1.0)+ , StepVector 2 (Just (1.0, 1.0)) 0.5 4 (306.2507410751382, 1.0)+ , StepVector 2 (Just (1.0, 1.0)) 1.0 1 (0.28373334597262656, 1.5042458491001744)+ , StepVector 2 (Just (1.0, 1.0)) 1.0 2 (32.70474103933747, 1.1172835591001746)+ , StepVector 2 (Just (1.0, 1.0)) 1.0 3 (54.16926046249099, 1.0)+ , StepVector 2 (Just (1.0, 1.0)) 1.0 4 (370.5534458848565, 1.0)+ , StepVector 2 (Just (1.0, 1.0)) 45.0 1 (0.3530084060356767, 1.5042458491001744)+ , StepVector 2 (Just (1.0, 1.0)) 45.0 2 (64.62284942111141, 1.1172835591001746)+ , StepVector 2 (Just (1.0, 1.0)) 45.0 3 (107.91909571722898, 1.0)+ , StepVector 2 (Just (1.0, 1.0)) 45.0 4 (744.3009119116016, 1.0)+ , StepVector 2 (Just (1.0, 1.0)) 400.0 1 (0.37642751849615735, 1.5042458491001744)+ , StepVector 2 (Just (1.0, 1.0)) 400.0 2 (77.10188063654348, 1.1172835591001746)+ , StepVector 2 (Just (1.0, 1.0)) 400.0 3 (128.89028366497183, 1.0)+ , StepVector 2 (Just (1.0, 1.0)) 400.0 4 (890.0924846971822, 1.0)+ , StepVector 2 (Just (1.0, 4.194588083372719)) 0.0 1 (0.18773236529505768, 4.392180247117252)+ , StepVector 2 (Just (1.0, 4.194588083372719)) 0.0 2 (1.0, 4.142571859378209)+ , StepVector 2 (Just (1.0, 4.194588083372719)) 0.0 3 (1.0, 3.892963471639167)+ , StepVector 2 (Just (1.0, 4.194588083372719)) 0.0 4 (1.0, 3.643355083900124)+ , StepVector 2 (Just (1.0, 4.194588083372719)) 0.006944444444444444 1 (0.31225659659012783, 4.392180247117252)+ , StepVector 2 (Just (1.0, 4.194588083372719)) 0.006944444444444444 2 (13.390798974178896, 4.142571859378209)+ , StepVector 2 (Just (1.0, 4.194588083372719)) 0.006944444444444444 3 (16.2803528014948, 3.892963471639167)+ , StepVector 2 (Just (1.0, 4.194588083372719)) 0.006944444444444444 4 (103.28766161473068, 3.643355083900124)+ , StepVector 2 (Just (1.0, 4.194588083372719)) 0.5 1 (0.10577604029541765, 4.392180247117252)+ , StepVector 2 (Just (1.0, 4.194588083372719)) 0.5 2 (19.417454933367615, 4.142571859378209)+ , StepVector 2 (Just (1.0, 4.194588083372719)) 0.5 3 (30.980684333139628, 3.892963471639167)+ , StepVector 2 (Just (1.0, 4.194588083372719)) 0.5 4 (208.7357030872054, 3.643355083900124)+ , StepVector 2 (Just (1.0, 4.194588083372719)) 1.0 1 (0.0867904520426487, 4.392180247117252)+ , StepVector 2 (Just (1.0, 4.194588083372719)) 1.0 2 (22.576382248268914, 4.142571859378209)+ , StepVector 2 (Just (1.0, 4.194588083372719)) 1.0 3 (37.18387187496958, 3.892963471639167)+ , StepVector 2 (Just (1.0, 4.194588083372719)) 1.0 4 (252.4963424455477, 3.643355083900124)+ , StepVector 2 (Just (1.0, 4.194588083372719)) 45.0 1 (0.10647918633915149, 4.392180247117252)+ , StepVector 2 (Just (1.0, 4.194588083372719)) 45.0 2 (44.297969762021474, 4.142571859378209)+ , StepVector 2 (Just (1.0, 4.194588083372719)) 45.0 3 (73.7628488109043, 3.892963471639167)+ , StepVector 2 (Just (1.0, 4.194588083372719)) 45.0 4 (506.84688835631385, 3.643355083900124)+ , StepVector 2 (Just (1.0, 4.194588083372719)) 400.0 1 (0.11354317687575374, 4.392180247117252)+ , StepVector 2 (Just (1.0, 4.194588083372719)) 400.0 2 (52.790464536167995, 4.142571859378209)+ , StepVector 2 (Just (1.0, 4.194588083372719)) 400.0 3 (88.03460604744426, 3.892963471639167)+ , StepVector 2 (Just (1.0, 4.194588083372719)) 400.0 4 (606.0640590341961, 3.643355083900124)+ , StepVector 2 (Just (1.0, 10.0)) 0.0 1 (0.13296245000390905, 9.640321269100175)+ , StepVector 2 (Just (1.0, 10.0)) 0.0 2 (1.0, 9.640321269100175)+ , StepVector 2 (Just (1.0, 10.0)) 0.0 3 (1.0, 9.640321269100175)+ , StepVector 2 (Just (1.0, 10.0)) 0.0 4 (1.0, 9.640321269100175)+ , StepVector 2 (Just (1.0, 10.0)) 0.006944444444444444 1 (0.22474297616036126, 9.640321269100175)+ , StepVector 2 (Just (1.0, 10.0)) 0.006944444444444444 2 (2.820727257361917, 9.640321269100175)+ , StepVector 2 (Just (1.0, 10.0)) 0.006944444444444444 3 (3.2453237201059313, 9.640321269100175)+ , StepVector 2 (Just (1.0, 10.0)) 0.006944444444444444 4 (16.030340979774785, 9.640321269100175)+ , StepVector 2 (Just (1.0, 10.0)) 0.5 1 (0.06377984076442395, 9.640321269100175)+ , StepVector 2 (Just (1.0, 10.0)) 0.5 2 (3.7062953953410642, 9.640321269100175)+ , StepVector 2 (Just (1.0, 10.0)) 0.5 3 (5.4054180261872915, 9.640321269100175)+ , StepVector 2 (Just (1.0, 10.0)) 0.5 4 (31.525074107513813, 9.640321269100175)+ , StepVector 2 (Just (1.0, 10.0)) 1.0 1 (0.04287484736272249, 9.640321269100175)+ , StepVector 2 (Just (1.0, 10.0)) 1.0 2 (4.170474103933746, 9.640321269100175)+ , StepVector 2 (Just (1.0, 10.0)) 1.0 3 (6.316926046249098, 9.640321269100175)+ , StepVector 2 (Just (1.0, 10.0)) 1.0 4 (37.95534458848565, 9.640321269100175)+ , StepVector 2 (Just (1.0, 10.0)) 45.0 1 (0.05150650091647976, 9.640321269100175)+ , StepVector 2 (Just (1.0, 10.0)) 45.0 2 (7.362284942111141, 9.640321269100175)+ , StepVector 2 (Just (1.0, 10.0)) 45.0 3 (11.691909571722897, 9.640321269100175)+ , StepVector 2 (Just (1.0, 10.0)) 45.0 4 (75.33009119116015, 9.640321269100175)+ , StepVector 2 (Just (1.0, 10.0)) 400.0 1 (0.054923520219093705, 9.640321269100175)+ , StepVector 2 (Just (1.0, 10.0)) 400.0 2 (8.610188063654348, 9.640321269100175)+ , StepVector 2 (Just (1.0, 10.0)) 400.0 3 (13.789028366497183, 9.640321269100175)+ , StepVector 2 (Just (1.0, 10.0)) 400.0 4 (89.90924846971822, 9.640321269100175)+ , StepVector 2 (Just (4.1283, 1.0)) 0.0 1 (1.1497459957171503, 1.5042458491001744)+ , StepVector 2 (Just (4.1283, 1.0)) 0.0 2 (4.1283, 1.1172835591001746)+ , StepVector 2 (Just (4.1283, 1.0)) 0.0 3 (4.1283, 1.0)+ , StepVector 2 (Just (4.1283, 1.0)) 0.0 4 (4.1283, 1.0)+ , StepVector 2 (Just (4.1283, 1.0)) 0.006944444444444444 1 (1.5018560311903157, 1.5042458491001744)+ , StepVector 2 (Just (4.1283, 1.0)) 0.006944444444444444 2 (17.503695467765404, 1.1172835591001746)+ , StepVector 2 (Just (4.1283, 1.0)) 0.006944444444444444 3 (20.691351937544823, 1.0)+ , StepVector 2 (Just (4.1283, 1.0)) 0.006944444444444444 4 (115.06880316386457, 1.0)+ , StepVector 2 (Just (4.1283, 1.0)) 0.5 1 (0.7305170439992782, 1.5042458491001744)+ , StepVector 2 (Just (4.1283, 1.0)) 0.5 2 (23.087390493764737, 1.1172835591001746)+ , StepVector 2 (Just (4.1283, 1.0)) 0.5 3 (35.02841075098335, 1.0)+ , StepVector 2 (Just (4.1283, 1.0)) 0.5 4 (218.26239221301392, 1.0)+ , StepVector 2 (Just (4.1283, 1.0)) 1.0 1 (0.6807884583025208, 1.5042458491001744)+ , StepVector 2 (Just (4.1283, 1.0)) 1.0 2 (28.84734624265902, 1.1172835591001746)+ , StepVector 2 (Just (4.1283, 1.0)) 1.0 3 (45.58599277477573, 1.0)+ , StepVector 2 (Just (4.1283, 1.0)) 1.0 4 (292.2829016676129, 1.0)+ , StepVector 2 (Just (4.1283, 1.0)) 45.0 1 (0.9596111442461993, 1.5042458491001744)+ , StepVector 2 (Just (4.1283, 1.0)) 45.0 2 (89.51455435971307, 1.1172835591001746)+ , StepVector 2 (Just (4.1283, 1.0)) 45.0 3 (147.62110464311436, 1.0)+ , StepVector 2 (Just (4.1283, 1.0)) 45.0 4 (1001.6894169221032, 1.0)+ , StepVector 2 (Just (4.1283, 1.0)) 400.0 1 (1.0717754376017037, 1.5042458491001744)+ , StepVector 2 (Just (4.1283, 1.0)) 400.0 2 (120.27563227006279, 1.1172835591001746)+ , StepVector 2 (Just (4.1283, 1.0)) 400.0 3 (199.31552989107374, 1.0)+ , StepVector 2 (Just (4.1283, 1.0)) 400.0 4 (1361.068751079365, 1.0)+ , StepVector 2 (Just (4.1283, 4.194588083372719)) 0.0 1 (0.627123625939937, 4.392180247117252)+ , StepVector 2 (Just (4.1283, 4.194588083372719)) 0.0 2 (4.1283, 4.142571859378209)+ , StepVector 2 (Just (4.1283, 4.194588083372719)) 0.0 3 (4.1283, 3.892963471639167)+ , StepVector 2 (Just (4.1283, 4.194588083372719)) 0.0 4 (4.1283, 3.643355083900124)+ , StepVector 2 (Just (4.1283, 4.194588083372719)) 0.006944444444444444 1 (0.8342529357140094, 4.392180247117252)+ , StepVector 2 (Just (4.1283, 4.194588083372719)) 0.006944444444444444 2 (13.23080757059332, 4.142571859378209)+ , StepVector 2 (Just (4.1283, 4.194588083372719)) 0.006944444444444444 3 (15.400139103148412, 3.892963471639167)+ , StepVector 2 (Just (4.1283, 4.194588083372719)) 0.006944444444444444 4 (79.62788222679904, 3.643355083900124)+ , StepVector 2 (Just (4.1283, 4.194588083372719)) 0.5 1 (0.2577204164133434, 4.392180247117252)+ , StepVector 2 (Just (4.1283, 4.194588083372719)) 0.5 2 (17.03074203746815, 4.142571859378209)+ , StepVector 2 (Just (4.1283, 4.194588083372719)) 0.5 3 (25.157098192984485, 3.892963471639167)+ , StepVector 2 (Just (4.1283, 4.194588083372719)) 0.5 4 (149.85537029026096, 3.643355083900124)+ , StepVector 2 (Just (4.1283, 4.194588083372719)) 1.0 1 (0.20871885032025972, 4.392180247117252)+ , StepVector 2 (Just (4.1283, 4.194588083372719)) 1.0 2 (20.950629186745253, 4.142571859378209)+ , StepVector 2 (Just (4.1283, 4.194588083372719)) 1.0 3 (32.34196764453314, 3.892963471639167)+ , StepVector 2 (Just (4.1283, 4.194588083372719)) 1.0 4 (200.22937600197605, 3.643355083900124)+ , StepVector 2 (Just (4.1283, 4.194588083372719)) 45.0 1 (0.2894509368453701, 4.392180247117252)+ , StepVector 2 (Just (4.1283, 4.194588083372719)) 45.0 2 (62.23716329357594, 4.142571859378209)+ , StepVector 2 (Just (4.1283, 4.194588083372719)) 45.0 3 (101.78106426685208, 3.892963471639167)+ , StepVector 2 (Just (4.1283, 4.194588083372719)) 45.0 4 (683.0097312665702, 3.643355083900124)+ , StepVector 2 (Just (4.1283, 4.194588083372719)) 400.0 1 (0.3232834532631037, 4.392180247117252)+ , StepVector 2 (Just (4.1283, 4.194588083372719)) 400.0 2 (83.17134391151534, 4.142571859378209)+ , StepVector 2 (Just (4.1283, 4.194588083372719)) 400.0 3 (136.96125002741815, 3.892963471639167)+ , StepVector 2 (Just (4.1283, 4.194588083372719)) 400.0 4 (927.5821715929109, 3.643355083900124)+ , StepVector 2 (Just (4.1283, 10.0)) 0.0 1 (0.4489056928702402, 9.640321269100175)+ , StepVector 2 (Just (4.1283, 10.0)) 0.0 2 (4.1283, 9.640321269100175)+ , StepVector 2 (Just (4.1283, 10.0)) 0.0 3 (4.1283, 9.640321269100175)+ , StepVector 2 (Just (4.1283, 10.0)) 0.0 4 (4.1283, 9.640321269100175)+ , StepVector 2 (Just (4.1283, 10.0)) 0.006944444444444444 1 (0.6015002164431043, 9.640321269100175)+ , StepVector 2 (Just (4.1283, 10.0)) 0.006944444444444444 2 (5.46583954677654, 9.640321269100175)+ , StepVector 2 (Just (4.1283, 10.0)) 0.006944444444444444 3 (5.784605193754482, 9.640321269100175)+ , StepVector 2 (Just (4.1283, 10.0)) 0.006944444444444444 4 (15.222350316386454, 9.640321269100175)+ , StepVector 2 (Just (4.1283, 10.0)) 0.5 1 (0.14393049807698233, 9.640321269100175)+ , StepVector 2 (Just (4.1283, 10.0)) 0.5 2 (6.0242090493764735, 9.640321269100175)+ , StepVector 2 (Just (4.1283, 10.0)) 0.5 3 (7.2183110750983355, 9.640321269100175)+ , StepVector 2 (Just (4.1283, 10.0)) 0.5 4 (25.54170922130139, 9.640321269100175)+ , StepVector 2 (Just (4.1283, 10.0)) 1.0 1 (0.10244707437917078, 9.640321269100175)+ , StepVector 2 (Just (4.1283, 10.0)) 1.0 2 (6.600204624265903, 9.640321269100175)+ , StepVector 2 (Just (4.1283, 10.0)) 1.0 3 (8.274069277477574, 9.640321269100175)+ , StepVector 2 (Just (4.1283, 10.0)) 1.0 4 (32.943760166761294, 9.640321269100175)+ , StepVector 2 (Just (4.1283, 10.0)) 45.0 1 (0.14001426435036735, 9.640321269100175)+ , StepVector 2 (Just (4.1283, 10.0)) 45.0 2 (12.666925435971306, 9.640321269100175)+ , StepVector 2 (Just (4.1283, 10.0)) 45.0 3 (18.477580464311437, 9.640321269100175)+ , StepVector 2 (Just (4.1283, 10.0)) 45.0 4 (103.8844116922103, 9.640321269100175)+ , StepVector 2 (Just (4.1283, 10.0)) 400.0 1 (0.1563798527605417, 9.640321269100175)+ , StepVector 2 (Just (4.1283, 10.0)) 400.0 2 (15.743033227006277, 9.640321269100175)+ , StepVector 2 (Just (4.1283, 10.0)) 400.0 3 (23.647022989107374, 9.640321269100175)+ , StepVector 2 (Just (4.1283, 10.0)) 400.0 4 (139.82234510793654, 9.640321269100175)+ , StepVector 2 (Just (1000.0, 1.0)) 0.0 1 (56.89584294707965, 1.5042458491001744)+ , StepVector 2 (Just (1000.0, 1.0)) 0.0 2 (1000.0, 1.1172835591001746)+ , StepVector 2 (Just (1000.0, 1.0)) 0.0 3 (1000.0, 1.0)+ , StepVector 2 (Just (1000.0, 1.0)) 0.0 4 (1000.0, 1.0)+ , StepVector 2 (Just (1000.0, 1.0)) 0.006944444444444444 1 (56.005448597396025, 1.5042458491001744)+ , StepVector 2 (Just (1000.0, 1.0)) 0.006944444444444444 2 (1002.3738481011515, 1.1172835591001746)+ , StepVector 2 (Just (1000.0, 1.0)) 0.006944444444444444 3 (1002.9847091391927, 1.0)+ , StepVector 2 (Just (1000.0, 1.0)) 0.006944444444444444 4 (1020.0353359083821, 1.0)+ , StepVector 2 (Just (1000.0, 1.0)) 0.5 1 (9.365326366825816, 1.5042458491001744)+ , StepVector 2 (Just (1000.0, 1.0)) 0.5 2 (1001.9849631831362, 1.1172835591001746)+ , StepVector 2 (Just (1000.0, 1.0)) 0.5 3 (1003.2473807949993, 1.0)+ , StepVector 2 (Just (1000.0, 1.0)) 0.5 4 (1022.5129272023743, 1.0)+ , StepVector 2 (Just (1000.0, 1.0)) 1.0 1 (6.298026982765722, 1.5042458491001744)+ , StepVector 2 (Just (1000.0, 1.0)) 1.0 2 (1002.167257364372, 1.1172835591001746)+ , StepVector 2 (Just (1000.0, 1.0)) 1.0 3 (1003.6357950413839, 1.0)+ , StepVector 2 (Just (1000.0, 1.0)) 1.0 4 (1025.2715372505786, 1.0)+ , StepVector 2 (Just (1000.0, 1.0)) 45.0 1 (6.51766509568746, 1.5042458491001744)+ , StepVector 2 (Just (1000.0, 1.0)) 45.0 2 (1019.9544144747115, 1.1172835591001746)+ , StepVector 2 (Just (1000.0, 1.0)) 45.0 3 (1033.5336749393527, 1.0)+ , StepVector 2 (Just (1000.0, 1.0)) 45.0 4 (1233.1259069763294, 1.0)+ , StepVector 2 (Just (1000.0, 1.0)) 400.0 1 (8.200629394345464, 1.5042458491001744)+ , StepVector 2 (Just (1000.0, 1.0)) 400.0 2 (1104.014330705398, 1.1172835591001746)+ , StepVector 2 (Just (1000.0, 1.0)) 400.0 3 (1174.797549651458, 1.0)+ , StepVector 2 (Just (1000.0, 1.0)) 400.0 4 (2215.191516391638, 1.0)+ , StepVector 2 (Just (1000.0, 4.194588083372719)) 0.0 1 (34.49545162589666, 4.392180247117252)+ , StepVector 2 (Just (1000.0, 4.194588083372719)) 0.0 2 (1000.0, 4.142571859378209)+ , StepVector 2 (Just (1000.0, 4.194588083372719)) 0.0 3 (1000.0, 3.892963471639167)+ , StepVector 2 (Just (1000.0, 4.194588083372719)) 0.0 4 (1000.0, 3.643355083900124)+ , StepVector 2 (Just (1000.0, 4.194588083372719)) 0.006944444444444444 1 (33.89945672815858, 4.392180247117252)+ , StepVector 2 (Just (1000.0, 4.194588083372719)) 0.006944444444444444 2 (1001.6155014155838, 4.142571859378209)+ , StepVector 2 (Just (1000.0, 4.194588083372719)) 0.006944444444444444 3 (1002.0312175143529, 3.892963471639167)+ , StepVector 2 (Just (1000.0, 4.194588083372719)) 0.006944444444444444 4 (1013.6348713744535, 3.643355083900124)+ , StepVector 2 (Just (1000.0, 4.194588083372719)) 0.5 1 (3.9419273987129158, 4.392180247117252)+ , StepVector 2 (Just (1000.0, 4.194588083372719)) 0.5 2 (1001.3508492100582, 4.142571859378209)+ , StepVector 2 (Just (1000.0, 4.194588083372719)) 0.5 3 (1002.2099763960116, 3.892963471639167)+ , StepVector 2 (Just (1000.0, 4.194588083372719)) 0.5 4 (1015.32097430612, 3.643355083900124)+ , StepVector 2 (Just (1000.0, 4.194588083372719)) 1.0 1 (1.9700777720638714, 4.392180247117252)+ , StepVector 2 (Just (1000.0, 4.194588083372719)) 1.0 2 (1001.4749079093896, 4.142571859378209)+ , StepVector 2 (Just (1000.0, 4.194588083372719)) 1.0 3 (1002.4743082901048, 3.892963471639167)+ , StepVector 2 (Just (1000.0, 4.194588083372719)) 1.0 4 (1017.1983220756576, 3.643355083900124)+ , StepVector 2 (Just (1000.0, 4.194588083372719)) 45.0 1 (1.9659466017071279, 4.392180247117252)+ , StepVector 2 (Just (1000.0, 4.194588083372719)) 45.0 2 (1013.5798010055521, 4.142571859378209)+ , StepVector 2 (Just (1000.0, 4.194588083372719)) 45.0 3 (1022.8210471040575, 3.892963471639167)+ , StepVector 2 (Just (1000.0, 4.194588083372719)) 45.0 4 (1158.6517825411256, 3.643355083900124)+ , StepVector 2 (Just (1000.0, 4.194588083372719)) 400.0 1 (2.4735851340905017, 4.392180247117252)+ , StepVector 2 (Just (1000.0, 4.194588083372719)) 400.0 2 (1070.7860365682527, 4.142571859378209)+ , StepVector 2 (Just (1000.0, 4.194588083372719)) 400.0 3 (1118.9569327395282, 3.892963471639167)+ , StepVector 2 (Just (1000.0, 4.194588083372719)) 400.0 4 (1826.9878826636022, 3.643355083900124)+ , StepVector 2 (Just (1000.0, 10.0)) 0.0 1 (25.686456754555124, 9.640321269100175)+ , StepVector 2 (Just (1000.0, 10.0)) 0.0 2 (1000.0, 9.640321269100175)+ , StepVector 2 (Just (1000.0, 10.0)) 0.0 3 (1000.0, 9.640321269100175)+ , StepVector 2 (Just (1000.0, 10.0)) 0.0 4 (1000.0, 9.640321269100175)+ , StepVector 2 (Just (1000.0, 10.0)) 0.006944444444444444 1 (25.228152845249443, 9.640321269100175)+ , StepVector 2 (Just (1000.0, 10.0)) 0.006944444444444444 2 (1000.2373848101151, 9.640321269100175)+ , StepVector 2 (Just (1000.0, 10.0)) 0.006944444444444444 3 (1000.2984709139192, 9.640321269100175)+ , StepVector 2 (Just (1000.0, 10.0)) 0.006944444444444444 4 (1002.0035335908382, 9.640321269100175)+ , StepVector 2 (Just (1000.0, 10.0)) 0.5 1 (2.4867983369157667, 9.640321269100175)+ , StepVector 2 (Just (1000.0, 10.0)) 0.5 2 (1000.1984963183138, 9.640321269100175)+ , StepVector 2 (Just (1000.0, 10.0)) 0.5 3 (1000.3247380795, 9.640321269100175)+ , StepVector 2 (Just (1000.0, 10.0)) 0.5 4 (1002.2512927202373, 9.640321269100175)+ , StepVector 2 (Just (1000.0, 10.0)) 1.0 1 (0.9895172887055139, 9.640321269100175)+ , StepVector 2 (Just (1000.0, 10.0)) 1.0 2 (1000.2167257364373, 9.640321269100175)+ , StepVector 2 (Just (1000.0, 10.0)) 1.0 3 (1000.3635795041383, 9.640321269100175)+ , StepVector 2 (Just (1000.0, 10.0)) 1.0 4 (1002.5271537250578, 9.640321269100175)+ , StepVector 2 (Just (1000.0, 10.0)) 45.0 1 (0.9509748705259065, 9.640321269100175)+ , StepVector 2 (Just (1000.0, 10.0)) 45.0 2 (1001.9954414474712, 9.640321269100175)+ , StepVector 2 (Just (1000.0, 10.0)) 45.0 3 (1003.3533674939353, 9.640321269100175)+ , StepVector 2 (Just (1000.0, 10.0)) 45.0 4 (1023.312590697633, 9.640321269100175)+ , StepVector 2 (Just (1000.0, 10.0)) 400.0 1 (1.1965316354899411, 9.640321269100175)+ , StepVector 2 (Just (1000.0, 10.0)) 400.0 2 (1010.4014330705397, 9.640321269100175)+ , StepVector 2 (Just (1000.0, 10.0)) 400.0 3 (1017.4797549651457, 9.640321269100175)+ , StepVector 2 (Just (1000.0, 10.0)) 400.0 4 (1121.5191516391635, 9.640321269100175)+ , StepVector 2 (Just (36500.0, 1.0)) 0.0 1 (710.2538998690314, 1.5042458491001744)+ , StepVector 2 (Just (36500.0, 1.0)) 0.0 2 (36500.0, 1.1172835591001746)+ , StepVector 2 (Just (36500.0, 1.0)) 0.0 3 (36500.0, 1.0)+ , StepVector 2 (Just (36500.0, 1.0)) 0.0 4 (36500.0, 1.0)+ , StepVector 2 (Just (36500.0, 1.0)) 0.006944444444444444 1 (685.8356643703515, 1.5042458491001744)+ , StepVector 2 (Just (36500.0, 1.0)) 0.006944444444444444 2 (36500.0, 1.1172835591001746)+ , StepVector 2 (Just (36500.0, 1.0)) 0.006944444444444444 3 (36500.0, 1.0)+ , StepVector 2 (Just (36500.0, 1.0)) 0.006944444444444444 4 (36500.0, 1.0)+ , StepVector 2 (Just (36500.0, 1.0)) 0.5 1 (64.26913123751073, 1.5042458491001744)+ , StepVector 2 (Just (36500.0, 1.0)) 0.5 2 (36500.0, 1.1172835591001746)+ , StepVector 2 (Just (36500.0, 1.0)) 0.5 3 (36500.0, 1.0)+ , StepVector 2 (Just (36500.0, 1.0)) 0.5 4 (36500.0, 1.0)+ , StepVector 2 (Just (36500.0, 1.0)) 1.0 1 (23.579993025244807, 1.5042458491001744)+ , StepVector 2 (Just (36500.0, 1.0)) 1.0 2 (36500.0, 1.1172835591001746)+ , StepVector 2 (Just (36500.0, 1.0)) 1.0 3 (36500.0, 1.0)+ , StepVector 2 (Just (36500.0, 1.0)) 1.0 4 (36500.0, 1.0)+ , StepVector 2 (Just (36500.0, 1.0)) 45.0 1 (20.902526842337465, 1.5042458491001744)+ , StepVector 2 (Just (36500.0, 1.0)) 45.0 2 (36500.0, 1.1172835591001746)+ , StepVector 2 (Just (36500.0, 1.0)) 45.0 3 (36500.0, 1.0)+ , StepVector 2 (Just (36500.0, 1.0)) 45.0 4 (36500.0, 1.0)+ , StepVector 2 (Just (36500.0, 1.0)) 400.0 1 (21.261717622500864, 1.5042458491001744)+ , StepVector 2 (Just (36500.0, 1.0)) 400.0 2 (36500.0, 1.1172835591001746)+ , StepVector 2 (Just (36500.0, 1.0)) 400.0 3 (36500.0, 1.0)+ , StepVector 2 (Just (36500.0, 1.0)) 400.0 4 (36500.0, 1.0)+ , StepVector 2 (Just (36500.0, 4.194588083372719)) 0.0 1 (440.5412488204074, 4.392180247117252)+ , StepVector 2 (Just (36500.0, 4.194588083372719)) 0.0 2 (36500.0, 4.142571859378209)+ , StepVector 2 (Just (36500.0, 4.194588083372719)) 0.0 3 (36500.0, 3.892963471639167)+ , StepVector 2 (Just (36500.0, 4.194588083372719)) 0.0 4 (36500.0, 3.643355083900124)+ , StepVector 2 (Just (36500.0, 4.194588083372719)) 0.006944444444444444 1 (425.1509580675626, 4.392180247117252)+ , StepVector 2 (Just (36500.0, 4.194588083372719)) 0.006944444444444444 2 (36500.0, 4.142571859378209)+ , StepVector 2 (Just (36500.0, 4.194588083372719)) 0.006944444444444444 3 (36500.0, 3.892963471639167)+ , StepVector 2 (Just (36500.0, 4.194588083372719)) 0.006944444444444444 4 (36500.0, 3.643355083900124)+ , StepVector 2 (Just (36500.0, 4.194588083372719)) 0.5 1 (33.63699546233535, 4.392180247117252)+ , StepVector 2 (Just (36500.0, 4.194588083372719)) 0.5 2 (36500.0, 4.142571859378209)+ , StepVector 2 (Just (36500.0, 4.194588083372719)) 0.5 3 (36500.0, 3.892963471639167)+ , StepVector 2 (Just (36500.0, 4.194588083372719)) 0.5 4 (36500.0, 3.643355083900124)+ , StepVector 2 (Just (36500.0, 4.194588083372719)) 1.0 1 (8.007431778493624, 4.392180247117252)+ , StepVector 2 (Just (36500.0, 4.194588083372719)) 1.0 2 (36500.0, 4.142571859378209)+ , StepVector 2 (Just (36500.0, 4.194588083372719)) 1.0 3 (36500.0, 3.892963471639167)+ , StepVector 2 (Just (36500.0, 4.194588083372719)) 1.0 4 (36500.0, 3.643355083900124)+ , StepVector 2 (Just (36500.0, 4.194588083372719)) 45.0 1 (6.304903828209203, 4.392180247117252)+ , StepVector 2 (Just (36500.0, 4.194588083372719)) 45.0 2 (36500.0, 4.142571859378209)+ , StepVector 2 (Just (36500.0, 4.194588083372719)) 45.0 3 (36500.0, 3.892963471639167)+ , StepVector 2 (Just (36500.0, 4.194588083372719)) 45.0 4 (36500.0, 3.643355083900124)+ , StepVector 2 (Just (36500.0, 4.194588083372719)) 400.0 1 (6.413247826137848, 4.392180247117252)+ , StepVector 2 (Just (36500.0, 4.194588083372719)) 400.0 2 (36500.0, 4.142571859378209)+ , StepVector 2 (Just (36500.0, 4.194588083372719)) 400.0 3 (36500.0, 3.892963471639167)+ , StepVector 2 (Just (36500.0, 4.194588083372719)) 400.0 4 (36500.0, 3.643355083900124)+ , StepVector 2 (Just (36500.0, 10.0)) 0.0 1 (330.60428380490436, 9.640321269100175)+ , StepVector 2 (Just (36500.0, 10.0)) 0.0 2 (36500.0, 9.640321269100175)+ , StepVector 2 (Just (36500.0, 10.0)) 0.0 3 (36500.0, 9.640321269100175)+ , StepVector 2 (Just (36500.0, 10.0)) 0.0 4 (36500.0, 9.640321269100175)+ , StepVector 2 (Just (36500.0, 10.0)) 0.006944444444444444 1 (318.9928580228448, 9.640321269100175)+ , StepVector 2 (Just (36500.0, 10.0)) 0.006944444444444444 2 (36500.0, 9.640321269100175)+ , StepVector 2 (Just (36500.0, 10.0)) 0.006944444444444444 3 (36500.0, 9.640321269100175)+ , StepVector 2 (Just (36500.0, 10.0)) 0.006944444444444444 4 (36500.0, 9.640321269100175)+ , StepVector 2 (Just (36500.0, 10.0)) 0.5 1 (23.670683890481016, 9.640321269100175)+ , StepVector 2 (Just (36500.0, 10.0)) 0.5 2 (36500.0, 9.640321269100175)+ , StepVector 2 (Just (36500.0, 10.0)) 0.5 3 (36500.0, 9.640321269100175)+ , StepVector 2 (Just (36500.0, 10.0)) 0.5 4 (36500.0, 9.640321269100175)+ , StepVector 2 (Just (36500.0, 10.0)) 1.0 1 (4.338049711119281, 9.640321269100175)+ , StepVector 2 (Just (36500.0, 10.0)) 1.0 2 (36500.0, 9.640321269100175)+ , StepVector 2 (Just (36500.0, 10.0)) 1.0 3 (36500.0, 9.640321269100175)+ , StepVector 2 (Just (36500.0, 10.0)) 1.0 4 (36500.0, 9.640321269100175)+ , StepVector 2 (Just (36500.0, 10.0)) 45.0 1 (3.0498311075708195, 9.640321269100175)+ , StepVector 2 (Just (36500.0, 10.0)) 45.0 2 (36500.0, 9.640321269100175)+ , StepVector 2 (Just (36500.0, 10.0)) 45.0 3 (36500.0, 9.640321269100175)+ , StepVector 2 (Just (36500.0, 10.0)) 45.0 4 (36500.0, 9.640321269100175)+ , StepVector 2 (Just (36500.0, 10.0)) 400.0 1 (3.102239661960336, 9.640321269100175)+ , StepVector 2 (Just (36500.0, 10.0)) 400.0 2 (36500.0, 9.640321269100175)+ , StepVector 2 (Just (36500.0, 10.0)) 400.0 3 (36500.0, 9.640321269100175)+ , StepVector 2 (Just (36500.0, 10.0)) 400.0 4 (36500.0, 9.640321269100175)+ ]++-- | The interval that lands exactly on the desired retention.+data IntervalVector = IntervalVector+ { ivParams :: !Int+ , ivDesiredRetention :: !Double+ , ivStability :: !Double+ , ivInterval :: !Double+ }+ deriving stock (Eq, Show)++goldenIntervalVectors :: [IntervalVector]+goldenIntervalVectors =+ [ IntervalVector 0 0.7 0.0001 1.1574074074074073e-5+ , IntervalVector 0 0.7 0.01 0.00045127975239051384+ , IntervalVector 0 0.7 0.5 3.117203331616744+ , IntervalVector 0 0.7 1.0 9.20105680045469+ , IntervalVector 0 0.7 4.1283 62.10906194594796+ , IntervalVector 0 0.7 15.0 284.948503494052+ , IntervalVector 0 0.7 100.0 2225.756072433354+ , IntervalVector 0 0.7 1000.0 23800.027080355834+ , IntervalVector 0 0.7 36500.0 36500.0+ , IntervalVector 0 0.8 0.0001 1.1574074074074073e-5+ , IntervalVector 0 0.8 0.01 3.601728249454452e-5+ , IntervalVector 0 0.8 0.5 0.5024089885355536+ , IntervalVector 0 0.8 1.0 2.150047765631358+ , IntervalVector 0 0.8 4.1283 19.35445042913598+ , IntervalVector 0 0.8 15.0 97.42745289971072+ , IntervalVector 0 0.8 100.0 801.9939743014621+ , IntervalVector 0 0.8 1000.0 8749.841127265681+ , IntervalVector 0 0.8 36500.0 36500.0+ , IntervalVector 0 0.85 0.0001 1.1574074074074073e-5+ , IntervalVector 0 0.85 0.01 1.1574074074074073e-5+ , IntervalVector 0 0.85 0.5 0.07311627017082284+ , IntervalVector 0 0.85 1.0 0.6357738009780464+ , IntervalVector 0 0.85 4.1283 9.281518670005237+ , IntervalVector 0 0.85 15.0 52.320939407195404+ , IntervalVector 0 0.85 100.0 455.33708673914697+ , IntervalVector 0 0.85 1000.0 5067.354602800332+ , IntervalVector 0 0.85 36500.0 36500.0+ , IntervalVector 0 0.9 0.0001 1.1574074074074073e-5+ , IntervalVector 0 0.9 0.01 1.1574074074074073e-5+ , IntervalVector 0 0.9 0.5 0.004070952126970879+ , IntervalVector 0 0.9 1.0 0.04220140211604471+ , IntervalVector 0 0.9 4.1283 2.9669271623721456+ , IntervalVector 0 0.9 15.0 23.130676977447674+ , IntervalVector 0 0.9 100.0 228.64254264799698+ , IntervalVector 0 0.9 1000.0 2650.9394532829792+ , IntervalVector 0 0.9 36500.0 36500.0+ , IntervalVector 0 0.95 0.0001 1.1574074074074073e-5+ , IntervalVector 0 0.95 0.01 1.1574074074074073e-5+ , IntervalVector 0 0.95 0.5 0.0002729212997928062+ , IntervalVector 0 0.95 1.0 0.0011673402673624+ , IntervalVector 0 0.95 4.1283 0.08000910354847687+ , IntervalVector 0 0.95 15.0 4.414772788071169+ , IntervalVector 0 0.95 100.0 77.51137131161089+ , IntervalVector 0 0.95 1000.0 1029.0563316579403+ , IntervalVector 0 0.95 36500.0 36500.0+ , IntervalVector 0 0.97 0.0001 1.1574074074074073e-5+ , IntervalVector 0 0.97 0.01 1.1574074074074073e-5+ , IntervalVector 0 0.97 0.5 8.828059519681088e-5+ , IntervalVector 0 0.97 1.0 0.00029303360834978737+ , IntervalVector 0 0.97 4.1283 0.006386991233059331+ , IntervalVector 0 0.97 15.0 0.4429904100443122+ , IntervalVector 0 0.97 100.0 32.514164306905954+ , IntervalVector 0 0.97 1000.0 536.2719260144573+ , IntervalVector 0 0.97 36500.0 22700.633467170508+ , IntervalVector 0 0.99 0.0001 1.1574074074074073e-5+ , IntervalVector 0 0.99 0.01 1.1574074074074073e-5+ , IntervalVector 0 0.99 0.5 1.7471896134792815e-5+ , IntervalVector 0 0.99 1.0 4.822136328432182e-5+ , IntervalVector 0 0.99 4.1283 0.0004690664752905264+ , IntervalVector 0 0.99 15.0 0.005395816582669202+ , IntervalVector 0 0.99 100.0 0.9825033805227932+ , IntervalVector 0 0.99 1000.0 117.48067393690135+ , IntervalVector 0 0.99 36500.0 6735.646375251022+ , IntervalVector 1 0.7 0.0001 0.056485270434622384+ , IntervalVector 1 0.7 0.01 4.917962841074945+ , IntervalVector 1 0.7 0.5 3.0747826128579723+ , IntervalVector 1 0.7 1.0 3.5035241205529903+ , IntervalVector 1 0.7 4.1283 8.881571776199577+ , IntervalVector 1 0.7 15.0 28.779595370154098+ , IntervalVector 1 0.7 100.0 185.77323261468953+ , IntervalVector 1 0.7 1000.0 1850.306402242769+ , IntervalVector 1 0.7 36500.0 36500.0+ , IntervalVector 1 0.8 0.0001 0.00017803154636673922+ , IntervalVector 1 0.8 0.01 0.017526088717440668+ , IntervalVector 1 0.8 0.5 0.6209748700795628+ , IntervalVector 1 0.8 1.0 1.1624258186863363+ , IntervalVector 1 0.8 4.1283 4.509858675287754+ , IntervalVector 1 0.8 15.0 16.151138483343377+ , IntervalVector 1 0.8 100.0 107.24123174296729+ , IntervalVector 1 0.8 1000.0 1071.8776526967645+ , IntervalVector 1 0.8 36500.0 36500.0+ , IntervalVector 1 0.85 0.0001 1.3014325708657666e-5+ , IntervalVector 1 0.85 0.01 0.0013275784398440527+ , IntervalVector 1 0.85 0.5 0.18019830183924998+ , IntervalVector 1 0.85 1.0 0.5072819008173706+ , IntervalVector 1 0.85 4.1283 2.853572670471599+ , IntervalVector 1 0.85 15.0 11.084784580817049+ , IntervalVector 1 0.85 100.0 75.25530086567957+ , IntervalVector 1 0.85 1000.0 754.2392102615415+ , IntervalVector 1 0.85 36500.0 27534.560520025057+ , IntervalVector 1 0.9 0.0001 1.1574074074074073e-5+ , IntervalVector 1 0.9 0.01 0.00011117565267932369+ , IntervalVector 1 0.9 0.5 0.018717648016651153+ , IntervalVector 1 0.9 1.0 0.10511511284303723+ , IntervalVector 1 0.9 4.1283 1.4637131423968208+ , IntervalVector 1 0.9 15.0 6.655916282644194+ , IntervalVector 1 0.9 100.0 47.011718979983804+ , IntervalVector 1 0.9 1000.0 473.4253654955935+ , IntervalVector 1 0.9 36500.0 17289.509963417844+ , IntervalVector 1 0.95 0.0001 1.1574074074074073e-5+ , IntervalVector 1 0.95 0.01 1.1574074074074073e-5+ , IntervalVector 1 0.95 0.5 0.0009437701786925955+ , IntervalVector 1 0.95 1.0 0.004090102355002918+ , IntervalVector 1 0.95 4.1283 0.3495061226120306+ , IntervalVector 1 0.95 15.0 2.7772828623271026+ , IntervalVector 1 0.95 100.0 21.91235884204184+ , IntervalVector 1 0.95 1000.0 223.46725792535577+ , IntervalVector 1 0.95 36500.0 8169.033979115177+ , IntervalVector 1 0.97 0.0001 1.1574074074074073e-5+ , IntervalVector 1 0.97 0.01 1.1574074074074073e-5+ , IntervalVector 1 0.97 0.5 0.0002569412683931921+ , IntervalVector 1 0.97 1.0 0.0008627094776825766+ , IntervalVector 1 0.97 4.1283 0.06823050658616155+ , IntervalVector 1 0.97 15.0 1.3832728374582621+ , IntervalVector 1 0.97 100.0 12.652613385391312+ , IntervalVector 1 0.97 1000.0 131.0325051789605+ , IntervalVector 1 0.97 36500.0 4795.665879636751+ , IntervalVector 1 0.99 0.0001 1.1574074074074073e-5+ , IntervalVector 1 0.99 0.01 1.1574074074074073e-5+ , IntervalVector 1 0.99 0.5 4.343160931319135e-5+ , IntervalVector 1 0.99 1.0 0.00011831556774026941+ , IntervalVector 1 0.99 4.1283 0.0022932718844632704+ , IntervalVector 1 0.99 15.0 0.1832552247602712+ , IntervalVector 1 0.99 100.0 3.835732740677949+ , IntervalVector 1 0.99 1000.0 42.53363987052+ , IntervalVector 1 0.99 36500.0 1564.6644364198594+ , IntervalVector 2 0.7 0.0001 1.1574074074074073e-5+ , IntervalVector 2 0.7 0.01 1.1574074074074073e-5+ , IntervalVector 2 0.7 0.5 0.08150032655928467+ , IntervalVector 2 0.7 1.0 0.2191302172372853+ , IntervalVector 2 0.7 4.1283 1.280641542930248+ , IntervalVector 2 0.7 15.0 5.426265610662961+ , IntervalVector 2 0.7 100.0 39.94832161945218+ , IntervalVector 2 0.7 1000.0 415.7814582906561+ , IntervalVector 2 0.7 36500.0 15389.855536955905+ , IntervalVector 2 0.8 0.0001 1.1574074074074073e-5+ , IntervalVector 2 0.8 0.01 1.1574074074074073e-5+ , IntervalVector 2 0.8 0.5 0.0019323117414683263+ , IntervalVector 2 0.8 1.0 0.02982261032771186+ , IntervalVector 2 0.8 4.1283 0.397688827723519+ , IntervalVector 2 0.8 15.0 2.104189792791598+ , IntervalVector 2 0.8 100.0 17.48703508290727+ , IntervalVector 2 0.8 1000.0 190.42477333335583+ , IntervalVector 2 0.8 36500.0 7157.847169026045+ , IntervalVector 2 0.85 0.0001 1.1574074074074073e-5+ , IntervalVector 2 0.85 0.01 1.1574074074074073e-5+ , IntervalVector 2 0.85 0.5 1.1574074074074073e-5+ , IntervalVector 2 0.85 1.0 0.00029955593419729983+ , IntervalVector 2 0.85 4.1283 0.15588323083723007+ , IntervalVector 2 0.85 15.0 1.1299878116819286+ , IntervalVector 2 0.85 100.0 10.619072803191733+ , IntervalVector 2 0.85 1000.0 120.33639320854094+ , IntervalVector 2 0.85 36500.0 4582.215684387548+ , IntervalVector 2 0.9 0.0001 1.1574074074074073e-5+ , IntervalVector 2 0.9 0.01 1.1574074074074073e-5+ , IntervalVector 2 0.9 0.5 1.1574074074074073e-5+ , IntervalVector 2 0.9 1.0 1.1574074074074073e-5+ , IntervalVector 2 0.9 4.1283 0.006395903619397388+ , IntervalVector 2 0.9 15.0 0.42381904955941113+ , IntervalVector 2 0.9 100.0 5.496698918051801+ , IntervalVector 2 0.9 1000.0 67.54103651918959+ , IntervalVector 2 0.9 36500.0 2635.459438849799+ , IntervalVector 2 0.95 0.0001 1.1574074074074073e-5+ , IntervalVector 2 0.95 0.01 1.1574074074074073e-5+ , IntervalVector 2 0.95 0.5 1.1574074074074073e-5+ , IntervalVector 2 0.95 1.0 1.1574074074074073e-5+ , IntervalVector 2 0.95 4.1283 1.1574074074074073e-5+ , IntervalVector 2 0.95 15.0 0.0006947402110169297+ , IntervalVector 2 0.95 100.0 1.6297887361214212+ , IntervalVector 2 0.95 1000.0 27.162156921554093+ , IntervalVector 2 0.95 36500.0 1140.9809607840618+ , IntervalVector 2 0.97 0.0001 1.1574074074074073e-5+ , IntervalVector 2 0.97 0.01 1.1574074074074073e-5+ , IntervalVector 2 0.97 0.5 1.1574074074074073e-5+ , IntervalVector 2 0.97 1.0 1.1574074074074073e-5+ , IntervalVector 2 0.97 4.1283 1.1574074074074073e-5+ , IntervalVector 2 0.97 15.0 1.1574074074074073e-5+ , IntervalVector 2 0.97 100.0 0.38856423686691866+ , IntervalVector 2 0.97 1000.0 13.726252993269208+ , IntervalVector 2 0.97 36500.0 641.4142966751779+ , IntervalVector 2 0.99 0.0001 1.1574074074074073e-5+ , IntervalVector 2 0.99 0.01 1.1574074074074073e-5+ , IntervalVector 2 0.99 0.5 1.1574074074074073e-5+ , IntervalVector 2 0.99 1.0 1.1574074074074073e-5+ , IntervalVector 2 0.99 4.1283 1.1574074074074073e-5+ , IntervalVector 2 0.99 15.0 1.1574074074074073e-5+ , IntervalVector 2 0.99 100.0 1.1574074074074073e-5+ , IntervalVector 2 0.99 1000.0 1.7403480423800615+ , IntervalVector 2 0.99 36500.0 188.8949885261801+ ]++-- | A whole review history folded into a final memory state.+data ReplayVector = ReplayVector+ { rvParams :: !Int+ , rvReviews :: ![(Double, Int)]+ -- ^ @(days since the previous review, rating)@.+ , rvFinalState :: !(Double, Double)+ }+ deriving stock (Eq, Show)++goldenReplayVectors :: [ReplayVector]+goldenReplayVectors =+ [ ReplayVector 0 [(0.0, 3)] (4.1283, 4.194588083372719)+ , ReplayVector 0 [(0.0, 1)] (0.041, 5.6385)+ , ReplayVector 0 [(0.0, 4)] (11.9709, 2.817928571667297)+ , ReplayVector 0 [(0.0, 3), (0.006944444444444444, 3)] (5.284074098785149, 4.180821488255665)+ , ReplayVector 0 [(0.0, 1), (0.0006944444444444445, 3), (0.006944444444444444, 3), (1.0, 3)] (4.363823678078679, 5.554726208007091)+ , ReplayVector 0 [(0.0, 3), (1.0, 3), (3.0, 3), (8.0, 3), (21.0, 3)] (51.13598657235655, 4.140342205740074)+ , ReplayVector 0 [(0.0, 2), (1.0, 2), (2.0, 2), (3.0, 2)] (10.005657593467827, 8.615870652454893)+ , ReplayVector 0 [(0.0, 4), (15.0, 4), (90.0, 4), (365.0, 4)] (399.54723405853474, 1.0)+ , ReplayVector 0 [(0.0, 3), (5.0, 1), (0.006944444444444444, 3), (1.0, 3), (4.0, 4)] (6.709654019064798, 7.550194020527194)+ , ReplayVector 0 [(0.0, 1), (0.0, 1), (0.0, 1), (0.0, 3)] (0.0001844264325618162, 9.517410721695096)+ , ReplayVector 0 [(0.0, 3), (100.0, 1), (0.5, 2), (2.0, 3), (6.0, 4), (30.0, 1)] (1.2988830554348012, 9.476663700091226)+ , ReplayVector 0 [(0.0, 2), (0.25, 3), (0.75, 4), (2.5, 1), (0.01, 3), (7.0, 3)] (6.155878820322062, 7.9861912704492415)+ , ReplayVector 0 [(0.0, 3), (1.0, 3), (2.0, 3), (4.0, 3), (8.0, 3), (16.0, 3), (32.0, 3), (64.0, 3), (128.0, 3), (256.0, 3), (512.0, 3)] (504.34338372214967, 4.062954757444055)+ , ReplayVector 0 [(0.0, 4), (1.0, 4), (1.0, 3), (1.0, 2), (1.0, 1), (1.0, 3), (1.0, 4), (1.0, 2), (1.0, 1)] (1.8700202120083298, 9.504197999898857)+ , ReplayVector 1 [(0.0, 3)] (64.835975, 1.0)+ , ReplayVector 1 [(0.0, 1)] (21.160516, 8.15903)+ , ReplayVector 1 [(0.0, 4)] (64.835975, 1.0)+ , ReplayVector 1 [(0.0, 3), (0.006944444444444444, 3)] (64.83966034515682, 1.0)+ , ReplayVector 1 [(0.0, 1), (0.0006944444444444445, 3), (0.006944444444444444, 3), (1.0, 3)] (21.22186424830409, 1.0)+ , ReplayVector 1 [(0.0, 3), (1.0, 3), (3.0, 3), (8.0, 3), (21.0, 3)] (65.12283435473542, 1.0)+ , ReplayVector 1 [(0.0, 2), (1.0, 2), (2.0, 2), (3.0, 2)] (50.96007847033368, 1.0)+ , ReplayVector 1 [(0.0, 4), (15.0, 4), (90.0, 4), (365.0, 4)] (77.80278794798323, 1.0)+ , ReplayVector 1 [(0.0, 3), (5.0, 1), (0.006944444444444444, 3), (1.0, 3), (4.0, 4)] (32.70121989196062, 1.0)+ , ReplayVector 1 [(0.0, 1), (0.0, 1), (0.0, 1), (0.0, 3)] (0.3145624222371321, 1.0)+ , ReplayVector 1 [(0.0, 3), (100.0, 1), (0.5, 2), (2.0, 3), (6.0, 4), (30.0, 1)] (26.19569389489973, 1.4918717310343146)+ , ReplayVector 1 [(0.0, 2), (0.25, 3), (0.75, 4), (2.5, 1), (0.01, 3), (7.0, 3)] (26.472074461000048, 1.0)+ , ReplayVector 1 [(0.0, 3), (1.0, 3), (2.0, 3), (4.0, 3), (8.0, 3), (16.0, 3), (32.0, 3), (64.0, 3), (128.0, 3), (256.0, 3), (512.0, 3)] (69.9098324237063, 1.0)+ , ReplayVector 1 [(0.0, 4), (1.0, 4), (1.0, 3), (1.0, 2), (1.0, 1), (1.0, 3), (1.0, 4), (1.0, 2), (1.0, 1)] (17.7943323192371, 1.4918717310343146)+ , ReplayVector 2 [(0.0, 3)] (79.640406, 1.0)+ , ReplayVector 2 [(0.0, 1)] (2.462798, 7.614116)+ , ReplayVector 2 [(0.0, 4)] (79.640406, 1.0)+ , ReplayVector 2 [(0.0, 3), (0.006944444444444444, 3)] (86.62079519809366, 1.0)+ , ReplayVector 2 [(0.0, 1), (0.0006944444444444445, 3), (0.006944444444444444, 3), (1.0, 3)] (23.961229647935912, 6.61669734203843)+ , ReplayVector 2 [(0.0, 3), (1.0, 3), (3.0, 3), (8.0, 3), (21.0, 3)] (199.62738805973905, 1.0)+ , ReplayVector 2 [(0.0, 2), (1.0, 2), (2.0, 2), (3.0, 2)] (43.299666393753476, 5.033143534988341)+ , ReplayVector 2 [(0.0, 4), (15.0, 4), (90.0, 4), (365.0, 4)] (2203.3303431594163, 1.0)+ , ReplayVector 2 [(0.0, 3), (5.0, 1), (0.006944444444444444, 3), (1.0, 3), (4.0, 4)] (280.96023230120966, 1.0)+ , ReplayVector 2 [(0.0, 1), (0.0, 1), (0.0, 1), (0.0, 3)] (0.05224193167244188, 7.032017724078441)+ , ReplayVector 2 [(0.0, 3), (100.0, 1), (0.5, 2), (2.0, 3), (6.0, 4), (30.0, 1)] (4.551999327806947, 1.5042458491001744)+ , ReplayVector 2 [(0.0, 2), (0.25, 3), (0.75, 4), (2.5, 1), (0.01, 3), (7.0, 3)] (63.18078959050319, 4.076018495507828)+ , ReplayVector 2 [(0.0, 3), (1.0, 3), (2.0, 3), (4.0, 3), (8.0, 3), (16.0, 3), (32.0, 3), (64.0, 3), (128.0, 3), (256.0, 3), (512.0, 3)] (890.1169420823825, 1.0)+ , ReplayVector 2 [(0.0, 4), (1.0, 4), (1.0, 3), (1.0, 2), (1.0, 1), (1.0, 3), (1.0, 4), (1.0, 2), (1.0, 1)] (2.817832383828903, 1.6102711693629577)+ ]
+ test/Test/FSRS/Properties.hs view
@@ -0,0 +1,358 @@+-- | Properties of the FSRS-7 model.+--+-- Most of these hold for every parameter vector inside the valid box, and are+-- generated that way. A few — the ones about how retrievability and intervals+-- respond to /stability/ — only hold for well-behaved parameters: the two+-- power laws of the FSRS-7 forgetting curve are re-weighted by stability, and+-- for adversarial weights the second component can pull retrievability+-- /down/ as stability grows. Those properties are therefore stated for+-- 'defaultParameters', and say so.+module Test.FSRS.Properties (tests) where++import Test.Tasty (TestTree, testGroup)+import Test.Tasty.QuickCheck+ ( counterexample+ , forAll+ , testProperty+ , vectorOf+ , (===)+ , (==>)+ )+import qualified Test.Tasty.QuickCheck as QC++import FSRS+import Test.FSRS.Gen++tests :: TestTree+tests =+ testGroup+ "properties"+ [ parameterProperties+ , curveProperties+ , intervalProperties+ , difficultyProperties+ , stabilityProperties+ , transitionProperties+ , stateProperties+ ]++-- ---------------------------------------------------------------------------++parameterProperties :: TestTree+parameterProperties =+ testGroup+ "parameters"+ [ testProperty "the defaults are valid" $+ validateParameters (parametersToList defaultParameters) === []+ , testProperty "there are exactly parameterCount defaults" $+ length (parametersToList defaultParameters) === parameterCount+ , testProperty "mkParameters . parametersToList is the identity" $+ forAll genParameters $ \p ->+ mkParameters (parametersToList p) === Right p+ , testProperty "parameterAt agrees with parametersToList" $+ forAll genParameters $ \p ->+ map (parameterAt p) [0 .. parameterCount - 1] === parametersToList p+ , testProperty "a wrong number of weights is rejected" $+ forAll (QC.choose (0, 60)) $ \n ->+ n /= parameterCount ==>+ mkParameters (replicate n 0.5) === Left [WrongParameterCount n]+ , testProperty "clampParameters always produces something valid" $+ forAll (vectorOf parameterCount (QC.choose (-1000, 1000))) $ \ws ->+ case clampParameters ws of+ Left errs -> counterexample (show errs) False+ Right p -> counterexample (show p) (validateParameters (parametersToList p) == [])+ , testProperty "clampParameters is idempotent" $+ forAll (vectorOf parameterCount (QC.choose (-1000, 1000))) $ \ws ->+ let once = clampParameters ws+ twice = once >>= clampParameters . parametersToList+ in once === twice+ , testProperty "clampParameters keeps valid weights untouched" $+ forAll genParameters $ \p ->+ clampParameters (parametersToList p) === Right p+ ]++-- ---------------------------------------------------------------------------++curveProperties :: TestTree+curveProperties =+ testGroup+ "forgetting curve"+ [ testProperty "a card just reviewed is certain to be recalled" $+ forAll genParameters $ \p ->+ forAll genStability $ \s ->+ retrievability p 0 s === 1+ , testProperty "retrievability is a probability" $+ forAll genParameters $ \p ->+ forAll genElapsedDays $ \t ->+ forAll genStability $ \s ->+ let r = retrievability p t s+ in counterexample (show r) (r > 0 && r <= 1)+ , testProperty "retrievability decreases as time passes" $+ forAll genParameters $ \p ->+ forAll genElapsedDays $ \t1 ->+ forAll (QC.choose (1.0e-6, 5)) $ \gap ->+ forAll genStability $ \s ->+ let t2 = t1 + gap+ r1 = retrievability p t1 s+ r2 = retrievability p t2 s+ in counterexample (show (t1, t2, r1, r2)) (r2 <= r1 + 1.0e-15)+ , testProperty "the derivative is never positive" $+ forAll genParameters $ \p ->+ forAll genElapsedDays $ \t ->+ forAll genStability $ \s ->+ let d = retrievabilityDerivative p t s+ in counterexample (show d) (d <= 0)+ , testProperty "the derivative matches a finite difference" $+ forAll genParameters $ \p ->+ forAll (QC.choose (0.5, 50)) $ \t ->+ forAll (QC.choose (1, 500)) $ \s ->+ let h = 1.0e-6 * t+ numeric = (retrievability p (t + h) s - retrievability p (t - h) s) / (2 * h)+ exact = retrievabilityDerivative p t s+ in counterexample (show (numeric, exact)) $+ approxEqual 1.0e-7 1.0e-5 numeric exact+ , testProperty "with the default weights, more stability means more recall" $+ forAll genElapsedDays $ \t ->+ forAll genStability $ \s1 ->+ forAll (QC.choose (1.0e-6, 5)) $ \growth ->+ let s2 = min stabilityMax (s1 * exp growth)+ r1 = retrievability defaultParameters t s1+ r2 = retrievability defaultParameters t s2+ in counterexample (show (s1, s2, r1, r2)) (r2 >= r1)+ ]++-- ---------------------------------------------------------------------------++intervalProperties :: TestTree+intervalProperties =+ testGroup+ "interval inversion"+ [ testProperty "the answer is always a legal interval" $+ forAll genParameters $ \p ->+ forAll genDesiredRetention $ \dr ->+ forAll genStability $ \s ->+ let t = nextIntervalDays p dr s+ in counterexample (show t) (t >= minimumIntervalDays && t <= maximumIntervalDays)+ , testProperty "waiting that long really does land on the desired retention" $+ forAll genParameters $ \p ->+ forAll genDesiredRetention $ \dr ->+ forAll genStability $ \s ->+ let t = nextIntervalDays p dr s+ r = retrievability p t s+ in -- Saturated answers cannot hit the target and do not claim to.+ t > minimumIntervalDays && t < maximumIntervalDays ==>+ counterexample (show (t, r, dr)) (approxEqual 1.0e-9 1.0e-9 r dr)+ , testProperty "asking for more retention never buys a longer interval" $+ forAll genParameters $ \p ->+ forAll genStability $ \s ->+ forAll genDesiredRetention $ \dr1 ->+ forAll (QC.choose (1.0e-6, 0.2)) $ \bump ->+ let dr2 = min 0.999 (dr1 + bump)+ t1 = nextIntervalDays p dr1 s+ t2 = nextIntervalDays p dr2 s+ in counterexample (show (dr1, dr2, t1, t2)) (t2 <= t1 * (1 + 1.0e-9))+ , testProperty "with the default weights, more stability means a longer interval" $+ forAll genDesiredRetention $ \dr ->+ forAll genStability $ \s1 ->+ forAll (QC.choose (1.0e-6, 5)) $ \growth ->+ let s2 = min stabilityMax (s1 * exp growth)+ t1 = nextIntervalDays defaultParameters dr s1+ t2 = nextIntervalDays defaultParameters dr s2+ in counterexample (show (s1, s2, t1, t2)) (t2 >= t1 * (1 - 1.0e-9))+ , testProperty "an impossible retention saturates instead of diverging" $+ forAll genParameters $ \p ->+ forAll genStability $ \s ->+ counterexample "retention 1" (nextIntervalDays p 1 s == minimumIntervalDays)+ QC..&&. counterexample "retention 0" (nextIntervalDays p 0 s == maximumIntervalDays)+ ]++-- ---------------------------------------------------------------------------++difficultyProperties :: TestTree+difficultyProperties =+ testGroup+ "difficulty"+ [ testProperty "initial difficulty is in range" $+ forAll genParameters $ \p ->+ forAll genRating $ \rating ->+ let d = initialDifficulty p rating+ in counterexample (show d) (d >= difficultyMin && d <= difficultyMax)+ , testProperty "difficulty stays in range" $+ forAll genParameters $ \p ->+ forAll genDifficulty $ \d ->+ forAll genRating $ \rating ->+ let d' = nextDifficulty p d rating+ in counterexample (show d') (d' >= difficultyMin && d' <= difficultyMax)+ , testProperty "a better rating never makes a card harder" $+ forAll genParameters $ \p ->+ forAll genDifficulty $ \d ->+ let ds = map (nextDifficulty p d) allRatings+ in counterexample (show ds) (nonIncreasing ds)+ , testProperty "an easier first answer means an easier card" $+ forAll genParameters $ \p ->+ counterexample+ (show (map (initialDifficulty p) allRatings))+ (nonIncreasing (map (initialDifficulty p) allRatings))+ , testProperty "difficulty stays in range over a long history" $+ forAll genParameters $ \p ->+ forAll (vectorOf 200 genRating) $ \ratings ->+ let ds = scanl (nextDifficulty p) 5 ratings+ in counterexample (show (minimum ds, maximum ds)) $+ all (\d -> d >= difficultyMin && d <= difficultyMax) ds+ ]++-- ---------------------------------------------------------------------------++stabilityProperties :: TestTree+stabilityProperties =+ testGroup+ "stability"+ [ testProperty "stability stays in range" $+ forAll genParameters $ \p ->+ forAll genMemoryState $ \st ->+ forAll genElapsedDays $ \t ->+ forAll genRating $ \rating ->+ let s = memoryStability (nextMemoryState p (Just st) t rating)+ in counterexample (show s) (s >= stabilityMin && s <= stabilityMax)+ , testProperty "a better rating never means less stability" $+ forAll genParameters $ \p ->+ forAll genMemoryState $ \st ->+ forAll genElapsedDays $ \t ->+ let ss = [memoryStability (nextMemoryState p (Just st) t r) | r <- allRatings]+ in counterexample (show ss) (nonDecreasing ss)+ , testProperty "remembering a card cannot weaken it" $+ forAll genParameters $ \p ->+ forAll genMemoryState $ \st ->+ forAll genElapsedDays $ \t ->+ forAll (QC.elements [Hard, Good, Easy]) $ \rating ->+ let before = memoryStability st+ after = memoryStability (nextMemoryState p (Just st) t rating)+ in counterexample (show (before, after)) (after >= before * (1 - 1.0e-12))+ , testProperty "forgetting a card cannot strengthen it" $+ forAll genParameters $ \p ->+ forAll genMemoryState $ \st ->+ forAll genElapsedDays $ \t ->+ let before = memoryStability st+ after = memoryStability (nextMemoryState p (Just st) t Again)+ in counterexample (show (before, after)) (after <= before * (1 + 1.0e-12))+ , testProperty "the two blocks bracket the blended result" $+ forAll genParameters $ \p ->+ forAll genMemoryState $ \st ->+ forAll genElapsedDays $ \t ->+ forAll genRating $ \rating ->+ let r = retrievability p t (memoryStability st)+ long = stabilityAfterReview (longTermWeights p) st r rating+ short = stabilityAfterReview (shortTermWeights p) st r rating+ blended = nextStability p st t rating+ in counterexample (show (short, blended, long)) $+ blended >= min short long - 1.0e-9+ && blended <= max short long + 1.0e-9+ , testProperty "at zero elapsed time the blend is the short-term block" $+ -- Only when the transition amplitude is exactly 1 — which is the+ -- default, and the upper bound of w26.+ forAll (withFullAmplitude <$> genParameters) $ \p ->+ forAll genMemoryState $ \st ->+ forAll genRating $ \rating ->+ let r = retrievability p 0 (memoryStability st)+ short = stabilityAfterReview (shortTermWeights p) st r rating+ in counterexample (show (short, nextStability p st 0 rating)) $+ approxEqual 1.0e-12 1.0e-12 (nextStability p st 0 rating) short+ , testProperty "the initial stability is the matching weight" $+ forAll genParameters $ \p ->+ forAll genRating $ \rating ->+ initialStability p rating === parameterAt p (ratingToInt rating - 1)+ ]++-- ---------------------------------------------------------------------------++transitionProperties :: TestTree+transitionProperties =+ testGroup+ "long-/short-term transition"+ [ testProperty "the coefficient is a weight in [0, 1]" $+ forAll genParameters $ \p ->+ forAll genElapsedDays $ \t ->+ let c = transitionCoefficient p t+ in counterexample (show c) (c >= 0 && c <= 1)+ , testProperty "the coefficient grows with the gap" $+ forAll genParameters $ \p ->+ forAll genElapsedDays $ \t1 ->+ forAll (QC.choose (1.0e-6, 10)) $ \gap ->+ let c1 = transitionCoefficient p t1+ c2 = transitionCoefficient p (t1 + gap)+ in counterexample (show (c1, c2)) (c2 >= c1 - 1.0e-15)+ , testProperty "a same-instant review is purely short-term" $+ forAll genParameters $ \p ->+ transitionCoefficient p 0 === 1 - transitionAmplitude p+ , testProperty "a distant review is purely long-term" $+ forAll genParameters $ \p ->+ counterexample (show (transitionCoefficient p 3650)) $+ approxEqual 1.0e-9 0 (transitionCoefficient p 3650) 1+ ]++-- ---------------------------------------------------------------------------++stateProperties :: TestTree+stateProperties =+ testGroup+ "state transitions"+ [ testProperty "a first review reads the state off the weights" $+ forAll genParameters $ \p ->+ forAll genElapsedDays $ \t ->+ forAll genRating $ \rating ->+ nextMemoryState p Nothing t rating+ === MemoryState (initialStability p rating) (initialDifficulty p rating)+ , testProperty "the elapsed time of a first review is ignored" $+ forAll genParameters $ \p ->+ forAll genElapsedDays $ \t1 ->+ forAll genElapsedDays $ \t2 ->+ forAll genRating $ \rating ->+ nextMemoryState p Nothing t1 rating === nextMemoryState p Nothing t2 rating+ , testProperty "an empty history has no memory state" $+ forAll genParameters $ \p ->+ replayReviews p [] === Nothing+ , testProperty "replaying is a left fold" $+ forAll genParameters $ \p ->+ forAll genReviewHistory $ \xs ->+ forAll genReviewHistory $ \ys ->+ let viaConcat = replayReviews p (xs <> ys)+ viaFold = foldl (\st (t, r) -> Just (nextMemoryState p st t r)) (replayReviews p xs) ys+ in viaConcat === viaFold+ , testProperty "any history leaves the card in a legal state" $+ forAll genParameters $ \p ->+ forAll genReviewHistory $ \history ->+ case replayReviews p history of+ Nothing -> QC.property (null history)+ Just (MemoryState s d) ->+ counterexample (show (s, d)) $+ s >= stabilityMin+ && s <= stabilityMax+ && d >= difficultyMin+ && d <= difficultyMax+ , testProperty "the state is finite, however long the history" $+ forAll genParameters $ \p ->+ forAll (vectorOf 100 ((,) <$> genElapsedDays <*> genRating)) $ \history ->+ case replayReviews p history of+ Nothing -> counterexample "unexpected Nothing" False+ Just (MemoryState s d) ->+ counterexample (show (s, d)) $+ not (isNaN s) && not (isInfinite s) && not (isNaN d) && not (isInfinite d)+ ]++-- ---------------------------------------------------------------------------++-- | Pin @w26@ to its upper bound, so a same-instant review is purely+-- short-term.+withFullAmplitude :: Parameters -> Parameters+withFullAmplitude p =+ case clampParameters (setAt 26 1 (parametersToList p)) of+ Right p' -> p'+ Left errs -> error (show errs)+ where+ setAt i x xs = take i xs <> [x] <> drop (i + 1) xs++nonDecreasing :: [Double] -> Bool+nonDecreasing xs = and (zipWith (<=) xs (drop 1 xs))++nonIncreasing :: [Double] -> Bool+nonIncreasing xs = and (zipWith (>=) xs (drop 1 xs))
+ test/Test/FSRS/SchedulerSpec.hs view
@@ -0,0 +1,296 @@+-- | Tests for the scheduling layer: the state machine, due dates and fuzz.+module Test.FSRS.SchedulerSpec (tests) where++import Data.Time.Calendar (fromGregorian)+import Data.Time.Clock (NominalDiffTime, UTCTime (..), addUTCTime, diffUTCTime)+import Test.Tasty (TestTree, testGroup)+import Test.Tasty.HUnit (assertBool, testCase, (@?=))+import Test.Tasty.QuickCheck (counterexample, forAll, testProperty, (===))+import qualified Test.Tasty.QuickCheck as QC++import FSRS+import Test.FSRS.Gen++tests :: TestTree+tests = testGroup "scheduler" [unitTests, properties]++t0 :: UTCTime+t0 = UTCTime (fromGregorian 2026 1 1) 0++minutes :: Double -> NominalDiffTime+minutes m = realToFrac (m * 60)++days :: Double -> NominalDiffTime+days d = realToFrac (d * 86400)++-- ---------------------------------------------------------------------------++unitTests :: TestTree+unitTests =+ testGroup+ "the learn/review/relearn cycle"+ [ testCase "a new card starts in Learning on step 0 with no memory" $ do+ let card = newCard t0+ cardState card @?= Learning+ cardStep card @?= Just 0+ cardMemory card @?= Nothing+ cardLastReview card @?= Nothing+ , testCase "Good on a new card takes the first learning step" $ do+ let (card, entry) = reviewCard defaultScheduler (newCard t0) Good t0+ cardState card @?= Learning+ cardStep card @?= Just 1+ logInterval entry @?= minutes 10+ cardDue card @?= addUTCTime (minutes 10) t0+ cardMemory card+ @?= Just (nextMemoryState defaultParameters Nothing 0 Good)+ , testCase "Again on a new card repeats the first learning step" $ do+ let (card, entry) = reviewCard defaultScheduler (newCard t0) Again t0+ cardState card @?= Learning+ cardStep card @?= Just 0+ logInterval entry @?= minutes 1+ , testCase "Hard on the first of two learning steps splits the difference" $ do+ let (_, entry) = reviewCard defaultScheduler (newCard t0) Hard t0+ logInterval entry @?= minutes 5.5+ , testCase "Hard on a single learning step stretches it by half" $ do+ let sched = defaultScheduler {schedulerLearningSteps = [minutes 10]}+ (_, entry) = reviewCard sched (newCard t0) Hard t0+ logInterval entry @?= minutes 15+ , testCase "Easy graduates a new card immediately" $ do+ let (card, entry) = reviewCard defaultScheduler (newCard t0) Easy t0+ cardState card @?= Review+ cardStep card @?= Nothing+ assertBool "at least a day" (logInterval entry >= days 1)+ , testCase "Good on the last learning step graduates" $ do+ let (card1, _) = reviewCard defaultScheduler (newCard t0) Good t0+ t1 = cardDue card1+ (card2, _) = reviewCard defaultScheduler card1 Good t1+ cardState card2 @?= Review+ cardStep card2 @?= Nothing+ , testCase "a scheduler with no learning steps graduates at once" $ do+ let sched = defaultScheduler {schedulerLearningSteps = []}+ (card, _) = reviewCard sched (newCard t0) Good t0+ cardState card @?= Review+ , testCase "Again on a review card drops it into relearning" $ do+ let (graduated, _) = reviewCard defaultScheduler (newCard t0) Easy t0+ t1 = cardDue graduated+ (card, entry) = reviewCard defaultScheduler graduated Again t1+ cardState card @?= Relearning+ cardStep card @?= Just 0+ logInterval entry @?= minutes 10+ , testCase "Again on a review card stays in review when relearning is off" $ do+ let sched = defaultScheduler {schedulerRelearningSteps = []}+ (graduated, _) = reviewCard sched (newCard t0) Easy t0+ (card, _) = reviewCard sched graduated Again (cardDue graduated)+ cardState card @?= Review+ cardStep card @?= Nothing+ , testCase "Good on the only relearning step graduates again" $ do+ let (graduated, _) = reviewCard defaultScheduler (newCard t0) Easy t0+ (lapsed, _) = reviewCard defaultScheduler graduated Again (cardDue graduated)+ (card, _) = reviewCard defaultScheduler lapsed Good (cardDue lapsed)+ cardState card @?= Review+ cardStep card @?= Nothing+ , testCase "a card scheduled by a longer-stepped scheduler still graduates" $ do+ let stale = (newCard t0) {cardStep = Just 5, cardMemory = Just (MemoryState 10 5)}+ (card, _) = reviewCard defaultScheduler stale Good t0+ cardState card @?= Review+ , testCase "retrievability is unknown until the first review" $+ cardRetrievability defaultScheduler (newCard t0) t0 @?= Nothing+ , testCase "a graduated card is at the desired retention when it comes due" $ do+ let (card, _) = reviewCard defaultScheduler (newCard t0) Easy t0+ due = cardDue card+ case cardRetrievability defaultScheduler card due of+ Nothing -> assertBool "expected a retrievability" False+ Just r ->+ assertBool+ ("expected ~0.9, got " <> show r)+ (approxEqual 1.0e-6 1.0e-6 r (schedulerDesiredRetention defaultScheduler))+ , testCase "previewIntervals agrees with actually reviewing" $ do+ let card = newCard t0+ preview = previewIntervals defaultScheduler card t0+ actual =+ [ (r, logInterval (snd (reviewCard defaultScheduler card r t0)))+ | r <- allRatings+ ]+ preview @?= actual+ , testCase "fuzz leaves short intervals alone" $ do+ fuzzInterval defaultScheduler 0.0 2.4 @?= 2.4+ fuzzBounds defaultScheduler 2.4 @?= Nothing+ , testCase "the fuzz window for a 10-day interval matches py-fsrs" $+ -- delta = 1 + 0.15 * (7 - 2.5) + 0.1 * (10 - 7) = 1.975+ case fuzzBounds defaultScheduler 10 of+ Nothing -> assertBool "expected a fuzz window" False+ Just (low, high) -> do+ assertBool (show low) (approxEqual 1.0e-12 1.0e-12 low 8.025)+ assertBool (show high) (approxEqual 1.0e-12 1.0e-12 high 11.975)+ , testCase "fuzz is centred on the unfuzzed interval" $+ assertBool "midpoint" $+ approxEqual 1.0e-12 1.0e-12 (fuzzInterval defaultScheduler 0.5 10) 10+ ]++-- ---------------------------------------------------------------------------++properties :: TestTree+properties =+ testGroup+ "scheduling properties"+ [ testProperty "a reviewed card is always due in the future" $+ forAll genScheduler $ \sched ->+ forAll genCardAndTime $ \(card, now) ->+ forAll genRating $ \rating ->+ let (card', _) = reviewCard sched card rating now+ in counterexample (show (cardDue card', now)) (cardDue card' > now)+ , testProperty "a reviewed card always has a memory state" $+ forAll genScheduler $ \sched ->+ forAll genCardAndTime $ \(card, now) ->+ forAll genRating $ \rating ->+ let (card', _) = reviewCard sched card rating now+ in counterexample (show card') (cardMemory card' /= Nothing)+ , testProperty "the log agrees with the card" $+ forAll genScheduler $ \sched ->+ forAll genCardAndTime $ \(card, now) ->+ forAll genRating $ \rating ->+ let (card', entry) = reviewCard sched card rating now+ in counterexample (show (card', entry)) $+ logRating entry == rating+ && logReviewTime entry == now+ && logStateBefore entry == cardState card+ && logMemoryBefore entry == cardMemory card+ && Just (logMemoryAfter entry) == cardMemory card'+ && addUTCTime (logInterval entry) now == cardDue card'+ , testProperty "reviewing is deterministic" $+ forAll genScheduler $ \sched ->+ forAll genCardAndTime $ \(card, now) ->+ forAll genRating $ \rating ->+ reviewCard sched card rating now === reviewCard sched card rating now+ , testProperty "a card in Review has no step, one in Learning has one" $+ forAll genScheduler $ \sched ->+ forAll genCardAndTime $ \(card, now) ->+ forAll genRating $ \rating ->+ let (card', _) = reviewCard sched card rating now+ in counterexample (show card') $+ case cardState card' of+ Review -> cardStep card' == Nothing+ _ -> cardStep card' /= Nothing+ , testProperty "a graduated interval respects the scheduler's bounds" $+ forAll genScheduler $ \sched ->+ forAll genStability $ \s ->+ let ivl = nextReviewInterval sched s+ in counterexample (show ivl) $+ ivl >= schedulerMinimumInterval sched+ && ivl <= schedulerMaximumInterval sched+ , testProperty "fuzz stays inside its window" $+ forAll genScheduler $ \sched ->+ forAll (QC.choose (0, 1)) $ \sample ->+ forAll (QC.choose (0, 36500)) $ \ivl ->+ let fuzzed = fuzzInterval sched sample ivl+ in case fuzzBounds sched ivl of+ Nothing -> counterexample (show fuzzed) (fuzzed === ivl)+ Just (low, high) ->+ counterexample (show (low, fuzzed, high)) $+ QC.property (fuzzed >= low && fuzzed <= high)+ , testProperty "fuzz never exceeds the maximum interval" $+ forAll genScheduler $ \sched ->+ forAll (QC.choose (-5, 5)) $ \sample ->+ forAll (QC.choose (0, 36500)) $ \ivl ->+ let fuzzed = fuzzInterval sched sample ivl+ in counterexample (show fuzzed) $+ fuzzed <= max ivl (schedulerMaximumInterval sched)+ , testProperty "an out-of-range fuzz sample is clamped, not extrapolated" $+ forAll genScheduler $ \sched ->+ forAll (QC.choose (2.5, 36500)) $ \ivl ->+ fuzzInterval sched (-100) ivl === fuzzInterval sched 0 ivl+ QC..&&. fuzzInterval sched 100 ivl === fuzzInterval sched 1 ivl+ , testProperty "a better rating never shortens a review card's interval" $+ -- With the default weights: for adversarial weights a longer interval+ -- does not always follow from more stability, see Test.FSRS.Properties.+ forAll (withDefaultParameters <$> genScheduler) $ \sched ->+ forAll genUTCTime $ \now ->+ forAll genMemoryState $ \memory ->+ let card =+ (newCard now)+ { cardState = Review+ , cardStep = Nothing+ , cardMemory = Just memory+ , cardLastReview = Just now+ }+ ivls =+ [ logInterval (snd (reviewCard sched card r now))+ | r <- [Hard, Good, Easy]+ ]+ in counterexample (show ivls) (and (zipWith (<=) ivls (drop 1 ivls)))+ , testProperty "elapsed time is measured in fractional days" $+ forAll genScheduler $ \sched ->+ forAll genUTCTime $ \now ->+ forAll (QC.choose (0, 10 * 86400)) $ \seconds ->+ forAll genMemoryState $ \memory ->+ let card =+ (newCard now)+ { cardState = Review+ , cardStep = Nothing+ , cardMemory = Just memory+ , cardLastReview = Just now+ }+ later = addUTCTime (realToFrac (seconds :: Double)) now+ (_, entry) = reviewCard sched card Good later+ in counterexample (show (seconds, logElapsedDays entry)) $+ approxEqual 1.0e-9 1.0e-9 (logElapsedDays entry) (seconds / 86400)+ , testProperty "a session of reviews always moves forward in time" $+ forAll genScheduler $ \sched ->+ forAll genUTCTime $ \start ->+ forAll (QC.resize 20 (QC.listOf genRating)) $ \ratings ->+ let session = scanl next (newCard start, start) ratings+ next (card, now) rating =+ let (card', _) = reviewCard sched card rating now+ in (card', cardDue card')+ times = map snd session+ gaps = zipWith diffUTCTime (drop 1 times) times+ in counterexample (show gaps) (all (> 0) gaps)+ , testProperty "a session never leaves the memory state out of range" $+ forAll genScheduler $ \sched ->+ forAll genUTCTime $ \start ->+ forAll (QC.resize 20 (QC.listOf genRating)) $ \ratings ->+ let step (card, now) rating =+ let (card', _) = reviewCard sched card rating now+ in (card', cardDue card')+ states =+ [ memory+ | (card, _) <- scanl step (newCard start, start) ratings+ , Just memory <- [cardMemory card]+ ]+ in counterexample (show states) $+ all+ ( \(MemoryState s d) ->+ s >= stabilityMin+ && s <= stabilityMax+ && d >= difficultyMin+ && d <= difficultyMax+ )+ states+ ]++-- | Keep a generated scheduler's policy but pin it to the default weights.+withDefaultParameters :: Scheduler -> Scheduler+withDefaultParameters sched = sched {schedulerParameters = defaultParameters}++genCardAndTime :: QC.Gen (Card, UTCTime)+genCardAndTime = do+ now <- genUTCTime+ state <- QC.elements [Learning, Review, Relearning]+ memory <- QC.frequency [(1, pure Nothing), (4, Just <$> genMemoryState)]+ step <- case state of+ Review -> pure Nothing+ _ -> Just <$> QC.choose (0, 4)+ elapsed <- QC.choose (0, 400 * 86400)+ let lastReview = case memory of+ Nothing -> Nothing+ Just _ -> Just (addUTCTime (negate (realToFrac (elapsed :: Double))) now)+ pure+ ( Card+ { cardState = state+ , cardStep = step+ , cardMemory = memory+ , cardDue = now+ , cardLastReview = lastReview+ }+ , now+ )
+ test/Test/FSRS/Unit.hs view
@@ -0,0 +1,273 @@+-- | Hand-written checks of specific values and edge cases.+--+-- The numbers here were derived independently of the Haskell implementation:+-- the default weights come from the upstream model file, and the worked+-- examples were computed from the published formulas.+module Test.FSRS.Unit (tests) where++import Test.Tasty (TestTree, testGroup)+import Test.Tasty.HUnit (Assertion, assertBool, assertFailure, testCase, (@?=))++import FSRS+import Test.FSRS.Gen (approxEqual, relativeError)++tests :: TestTree+tests =+ testGroup+ "units"+ [ parameterTests+ , curveTests+ , stateTests+ , intervalTests+ ]++close :: String -> Double -> Double -> Assertion+close label expected actual =+ assertBool+ ( label+ <> ": expected "+ <> show expected+ <> ", got "+ <> show actual+ <> " (relative error "+ <> show (relativeError actual expected)+ <> ")"+ )+ (approxEqual 1.0e-12 1.0e-12 actual expected)++-- ---------------------------------------------------------------------------++parameterTests :: TestTree+parameterTests =+ testGroup+ "parameters"+ [ testCase "FSRS-7 has 35 weights" $+ parameterCount @?= 35+ , testCase "the default weights are the published ones" $+ parametersToList defaultParameters+ @?= [ 0.041+ , 2.4175+ , 4.1283+ , 11.9709+ , 5.6385+ , 0.4468+ , 3.262+ , 2.3054+ , 0.1688+ , 1.3325+ , 0.3524+ , 0.0049+ , 0.7503+ , 0.0896+ , 0.6625+ , 1.3+ , 0.882+ , 0.3072+ , 3.5875+ , 0.303+ , 0.0107+ , 0.2279+ , 2.6413+ , 0.5594+ , 1.3+ , 2.5+ , 1.0+ , 0.0723+ , 0.1634+ , 0.5+ , 0.9555+ , 0.2245+ , 0.6232+ , 0.1362+ , 0.3862+ ]+ , testCase "there is a bound for every weight" $+ length parameterBounds @?= parameterCount+ , testCase "too few weights are rejected" $+ mkParameters [1, 2, 3] @?= Left [WrongParameterCount 3]+ , testCase "an out-of-bounds weight is reported with its index" $+ case mkParameters (setAt 5 99 (parametersToList defaultParameters)) of+ Left errs -> errs @?= [ParameterOutOfBounds 5 99 0.001 4.0]+ Right _ -> assertFailure "expected a rejection"+ , testCase "several bad weights are all reported" $+ case mkParameters (setAt 4 0 (setAt 26 7 (parametersToList defaultParameters))) of+ Left errs -> length errs @?= 2+ Right _ -> assertFailure "expected a rejection"+ , testCase "the initial-stability weights must be ordered" $+ case mkParameters (setAt 0 5 (parametersToList defaultParameters)) of+ Left errs -> errs @?= [ParameterOutOfOrder 0 1 5 2.4175]+ Right _ -> assertFailure "expected a rejection"+ , testCase "a NaN weight is rejected" $+ case mkParameters (setAt 6 (0 / 0) (parametersToList defaultParameters)) of+ Left [ParameterNotFinite 6 _] -> pure ()+ other -> assertFailure ("unexpected: " <> show other)+ , testCase "clamping repairs junk" $+ case clampParameters (replicate parameterCount 1000) of+ Right p -> validateParameters (parametersToList p) @?= []+ Left errs -> assertFailure (show errs)+ , testCase "clamping fixes the ordering constraints too" $+ case clampParameters (setAt 1 0.0001 (parametersToList defaultParameters)) of+ Right p -> do+ parameterAt p 0 @?= 0.041+ -- w1 is pulled up to w0, not left below it.+ parameterAt p 1 @?= 0.041+ validateParameters (parametersToList p) @?= []+ Left errs -> assertFailure (show errs)+ , testCase "the weight blocks read the right indices" $ do+ let p = defaultParameters+ swIncreaseBase (longTermWeights p) @?= parameterAt p 7+ swEasyBonus (longTermWeights p) @?= parameterAt p 15+ swIncreaseBase (shortTermWeights p) @?= parameterAt p 16+ swEasyBonus (shortTermWeights p) @?= parameterAt p 24+ cwDecay1 (curveWeights p) @?= negate (parameterAt p 27)+ cwDecay2 (curveWeights p) @?= negate (parameterAt p 28)+ cwStabilityPower2 (curveWeights p) @?= parameterAt p 34+ , testCase "ratings number from one" $+ map ratingToInt allRatings @?= [1, 2, 3, 4]+ , testCase "rating numbers round-trip" $ do+ map ratingFromInt [1, 2, 3, 4] @?= map Just allRatings+ ratingFromInt 0 @?= Nothing+ ratingFromInt 5 @?= Nothing+ ]++setAt :: Int -> a -> [a] -> [a]+setAt i x xs = take i xs <> [x] <> drop (i + 1) xs++-- ---------------------------------------------------------------------------++curveTests :: TestTree+curveTests =+ testGroup+ "forgetting curve"+ [ testCase "no time has passed, nothing is forgotten" $+ retrievability defaultParameters 0 10 @?= 1+ , testCase "w29 and w30 are the recall probability at t == s" $ do+ -- Both components carry the same base, so their mixture is that base+ -- at t == s whatever the stability-dependent weighting does.+ mapM_+ ( \(base, s) ->+ close+ ("R(s, s) with both bases at " <> show base)+ base+ (retrievability (tweak [(29, base), (30, base)]) s s)+ )+ [(b, s) | b <- [0.5, 0.85], s <- [0.5, 1, 37, 1000]]+ , testCase "a worked value of the default curve" $+ -- R(1, 1) with the default weights, computed from the published+ -- formulas: weights 0.2245 and 0.6232, components 0.5 and 0.9555.+ close+ "R(1, 1)"+ ((0.2245 * 0.5 + 0.6232 * 0.9555) / (0.2245 + 0.6232))+ (retrievability defaultParameters 1 1)+ , testCase "retrievability at a century is still positive" $+ assertBool "positive" (retrievability defaultParameters 36500 0.5 > 0)+ ]+ where+ tweak overrides =+ case mkParameters (foldr apply (parametersToList defaultParameters) overrides) of+ Right p -> p+ Left errs -> error (show errs)+ where+ apply (i, v) ws = setAt i v ws++-- ---------------------------------------------------------------------------++stateTests :: TestTree+stateTests =+ testGroup+ "state transitions"+ [ testCase "a first review reads stability straight off the weights" $+ map (memoryStability . firstReview) allRatings+ @?= [0.041, 2.4175, 4.1283, 11.9709]+ , testCase "a first review's difficulty follows the published formula" $+ mapM_+ ( \rating ->+ close+ ("initial difficulty for " <> show rating)+ ( min 10 . max 1 $+ 5.6385 - exp (0.4468 * fromIntegral (ratingToInt rating - 1)) + 1+ )+ (memoryDifficulty (firstReview rating))+ )+ allRatings+ , testCase "Again on a brand-new card gives the smallest stability" $+ memoryStability (firstReview Again) @?= 0.041+ , testCase "a same-instant review is handled by the short-term block" $ do+ -- w26 is 1 by default, so the transition coefficient is 0 at dt == 0.+ let before = MemoryState 10 5+ r = retrievability defaultParameters 0 10+ expected = stabilityAfterReview (shortTermWeights defaultParameters) before r Good+ close+ "same-instant stability"+ expected+ (memoryStability (nextMemoryState defaultParameters (Just before) 0 Good))+ , testCase "a review after ten years is handled by the long-term block" $ do+ let before = MemoryState 10 5+ r = retrievability defaultParameters 3650 10+ expected = stabilityAfterReview (longTermWeights defaultParameters) before r Good+ close+ "long-term stability"+ expected+ (memoryStability (nextMemoryState defaultParameters (Just before) 3650 Good))+ , testCase "stability is clamped at the century mark" $+ memoryStability (nextMemoryState defaultParameters (Just (MemoryState 36500 1)) 36500 Easy)+ @?= stabilityMax+ , testCase "repeated Good reviews converge on the Easy anchor" $+ -- A Good review zeroes the rating delta, leaving only the 1% pull+ -- towards the difficulty an Easy first review would have produced.+ -- Iterating it therefore pins down which rating that anchor comes from.+ mapM_+ ( \start ->+ close+ ("limit from " <> show start)+ (initialDifficulty defaultParameters Easy)+ (iterate (\d -> nextDifficulty defaultParameters d Good) start !! 3000)+ )+ [difficultyMin, 5, difficultyMax]+ , testCase "an empty history has no state" $+ replayReviews defaultParameters [] @?= Nothing+ , testCase "a one-review history is a first review" $+ replayReviews defaultParameters [(99, Good)]+ @?= Just (nextMemoryState defaultParameters Nothing 0 Good)+ ]+ where+ firstReview = nextMemoryState defaultParameters Nothing 0++-- ---------------------------------------------------------------------------++intervalTests :: TestTree+intervalTests =+ testGroup+ "interval inversion"+ [ testCase "the interval really does land on the target" $+ mapM_+ ( \(dr, s) ->+ close+ ("R after the scheduled interval for " <> show (dr, s))+ dr+ (retrievability defaultParameters (nextIntervalDays defaultParameters dr s) s)+ )+ [(0.9, 10), (0.8, 1), (0.95, 100), (0.7, 0.5), (0.99, 1000)]+ , testCase "an unreachable target saturates at the shortest interval" $+ nextIntervalDays defaultParameters 1 10 @?= minimumIntervalDays+ , testCase "a target of zero saturates at the longest interval" $+ nextIntervalDays defaultParameters 0 10 @?= maximumIntervalDays+ , testCase "a nonsensical target does not diverge" $ do+ nextIntervalDays defaultParameters (0 / 0) 10 @?= maximumIntervalDays+ nextIntervalDays defaultParameters (-1) 10 @?= maximumIntervalDays+ nextIntervalDays defaultParameters 2 10 @?= minimumIntervalDays+ , testCase "a fresh Good card comes back in about three days" $+ close+ "interval after one Good"+ 2.9669271623721456+ ( nextIntervalDays defaultParameters 0.9 $+ memoryStability (nextMemoryState defaultParameters Nothing 0 Good)+ )+ , testCase "a fresh Easy card comes back in about seventeen days" $+ close+ "interval after one Easy"+ 16.9366155257869+ ( nextIntervalDays defaultParameters 0.9 $+ memoryStability (nextMemoryState defaultParameters Nothing 0 Easy)+ )+ ]