packages feed

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 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++[![CI](https://github.com/kutyel/haskell-fsrs/actions/workflows/ci.yml/badge.svg)](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)+          )+    ]