diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
--- /dev/null
+++ b/CHANGELOG.md
@@ -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.
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -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.
diff --git a/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -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).
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/app/Main.hs b/app/Main.hs
new file mode 100644
--- /dev/null
+++ b/app/Main.hs
@@ -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
diff --git a/haskell-fsrs.cabal b/haskell-fsrs.cabal
new file mode 100644
--- /dev/null
+++ b/haskell-fsrs.cabal
@@ -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
diff --git a/reference/check_golden.py b/reference/check_golden.py
new file mode 100644
--- /dev/null
+++ b/reference/check_golden.py
@@ -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())
diff --git a/reference/fsrs7_reference.py b/reference/fsrs7_reference.py
new file mode 100644
--- /dev/null
+++ b/reference/fsrs7_reference.py
@@ -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
diff --git a/reference/gen_golden.py b/reference/gen_golden.py
new file mode 100644
--- /dev/null
+++ b/reference/gen_golden.py
@@ -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()
diff --git a/reference/test_reference.py b/reference/test_reference.py
new file mode 100644
--- /dev/null
+++ b/reference/test_reference.py
@@ -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())
diff --git a/src/FSRS.hs b/src/FSRS.hs
new file mode 100644
--- /dev/null
+++ b/src/FSRS.hs
@@ -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
diff --git a/src/FSRS/Algorithm.hs b/src/FSRS/Algorithm.hs
new file mode 100644
--- /dev/null
+++ b/src/FSRS/Algorithm.hs
@@ -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
diff --git a/src/FSRS/Parameters.hs b/src/FSRS/Parameters.hs
new file mode 100644
--- /dev/null
+++ b/src/FSRS/Parameters.hs
@@ -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
+    }
diff --git a/src/FSRS/Scheduler.hs b/src/FSRS/Scheduler.hs
new file mode 100644
--- /dev/null
+++ b/src/FSRS/Scheduler.hs
@@ -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)
diff --git a/src/FSRS/Types.hs b/src/FSRS/Types.hs
new file mode 100644
--- /dev/null
+++ b/src/FSRS/Types.hs
@@ -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)
diff --git a/test/Spec.hs b/test/Spec.hs
new file mode 100644
--- /dev/null
+++ b/test/Spec.hs
@@ -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
+      ]
diff --git a/test/Test/FSRS/Gen.hs b/test/Test/FSRS/Gen.hs
new file mode 100644
--- /dev/null
+++ b/test/Test/FSRS/Gen.hs
@@ -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
diff --git a/test/Test/FSRS/Golden.hs b/test/Test/FSRS/Golden.hs
new file mode 100644
--- /dev/null
+++ b/test/Test/FSRS/Golden.hs
@@ -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
diff --git a/test/Test/FSRS/GoldenData.hs b/test/Test/FSRS/GoldenData.hs
new file mode 100644
--- /dev/null
+++ b/test/Test/FSRS/GoldenData.hs
@@ -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)
+  ]
diff --git a/test/Test/FSRS/Properties.hs b/test/Test/FSRS/Properties.hs
new file mode 100644
--- /dev/null
+++ b/test/Test/FSRS/Properties.hs
@@ -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))
diff --git a/test/Test/FSRS/SchedulerSpec.hs b/test/Test/FSRS/SchedulerSpec.hs
new file mode 100644
--- /dev/null
+++ b/test/Test/FSRS/SchedulerSpec.hs
@@ -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
+    )
diff --git a/test/Test/FSRS/Unit.hs b/test/Test/FSRS/Unit.hs
new file mode 100644
--- /dev/null
+++ b/test/Test/FSRS/Unit.hs
@@ -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)
+          )
+    ]
