gsdesign 0.0.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,56 @@
1
+ on:
2
+ push:
3
+ branches:
4
+ - main
5
+ pull_request:
6
+ branches:
7
+ - main
8
+
9
+ name: CI Tests
10
+
11
+ jobs:
12
+ build:
13
+ runs-on: ubuntu-latest
14
+ strategy:
15
+ matrix:
16
+ python-version: ["3.10", "3.11", "3.12", "3.13"]
17
+ fail-fast: false
18
+
19
+ steps:
20
+ - uses: actions/checkout@v4
21
+ - name: Set up Python ${{ matrix.python-version }}
22
+ uses: actions/setup-python@v5
23
+ with:
24
+ python-version: ${{ matrix.python-version }}
25
+ - name: Install dependencies
26
+ run: |
27
+ # we are using the -e flag, so that code cov finds the source.
28
+ # this is not ideal, since installing an editable can technically
29
+ # differ from a normal install in surprising ways.
30
+ pip install -e '.[all]'
31
+ - name: Test with pytest
32
+ run: |
33
+ pip install pytest pytest-cov
34
+ pytest --cov=gsdesign --cov-report=xml
35
+
36
+ # - name: Upload coverage reports to Codecov
37
+ # uses: codecov/codecov-action@v4
38
+ # with:
39
+ # name: "py${{ matrix.python-version }}"
40
+ # token: ${{ secrets.CODECOV_TOKEN }}
41
+
42
+ test-windows:
43
+ runs-on: windows-latest
44
+ steps:
45
+ - uses: actions/checkout@v4
46
+ - name: Set up Python
47
+ uses: actions/setup-python@v5
48
+ with:
49
+ python-version: "3.13"
50
+ - name: Install dependencies
51
+ run: |
52
+ pip install -e '.[all]'
53
+ - name: Test with pytest
54
+ run: |
55
+ pip install pytest pytest-cov
56
+ pytest --cov=gsdesign --cov-report=xml
@@ -0,0 +1,34 @@
1
+ name: Mypy check
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - main
7
+ pull_request:
8
+ branches:
9
+ - '**'
10
+
11
+ jobs:
12
+ mypy:
13
+ runs-on: ubuntu-latest
14
+
15
+ steps:
16
+ - name: Checkout repository
17
+ uses: actions/checkout@v4
18
+
19
+ - name: Set up Python
20
+ uses: actions/setup-python@v5
21
+ with:
22
+ python-version: 3.13.7
23
+
24
+ - name: Install uv
25
+ run: |
26
+ pip install uv
27
+
28
+ - name: Install dependencies
29
+ run: |
30
+ uv sync --dev
31
+
32
+ - name: Run Type Checks
33
+ run: |
34
+ uv run mypy .
@@ -0,0 +1,13 @@
1
+ # Python-generated files
2
+ __pycache__/
3
+ *.py[oc]
4
+ build/
5
+ dist/
6
+ wheels/
7
+ *.egg-info
8
+
9
+ # Virtual environments
10
+ .venv
11
+
12
+ # Jupyter notebooks
13
+ .ipynb_checkpoints/
@@ -0,0 +1 @@
1
+ 3.13.7
@@ -0,0 +1,14 @@
1
+ # Changelog
2
+
3
+ ## gsdesign-python 0.0.1
4
+
5
+ ### New features
6
+
7
+ - Ported the canonical `gridpts`, `h1`, and `hupdate` numerical integration
8
+ routines from gsDesign, complete with typed public exports (#1).
9
+
10
+ ### Testing
11
+
12
+ - Added unit tests with high-precision reference fixtures and regeneration
13
+ tooling to keep the Python implementation aligned with the R package
14
+ gsDesign2 (#1).
gsdesign-0.0.1/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2025, gsdesign-python authors
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,49 @@
1
+ Metadata-Version: 2.4
2
+ Name: gsdesign
3
+ Version: 0.0.1
4
+ Summary: Group sequential design
5
+ Project-URL: Repository, https://github.com/nanxstats/gsdesign-python
6
+ Project-URL: Issues, https://github.com/nanxstats/gsdesign-python/issues
7
+ Project-URL: Changelog, https://github.com/nanxstats/gsdesign-python/blob/main/CHANGELOG.md
8
+ Author-email: Nan Xiao <me@nanx.me>
9
+ License-File: LICENSE
10
+ Classifier: Development Status :: 3 - Alpha
11
+ Classifier: Intended Audience :: Science/Research
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Operating System :: OS Independent
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Topic :: Scientific/Engineering :: Mathematics
20
+ Classifier: Typing :: Typed
21
+ Requires-Python: >=3.10
22
+ Requires-Dist: numpy>=2.0.0
23
+ Description-Content-Type: text/markdown
24
+
25
+ # gsdesign-python
26
+
27
+ [![PyPI version](https://img.shields.io/pypi/v/gsdesign)](https://pypi.org/project/gsdesign/)
28
+ ![Python versions](https://img.shields.io/pypi/pyversions/gsdesign)
29
+ [![Checked with mypy](https://www.mypy-lang.org/static/mypy_badge.svg)](https://mypy-lang.org/)
30
+ [![CI Tests](https://github.com/nanxstats/gsdesign-python/actions/workflows/ci-tests.yml/badge.svg)](https://github.com/nanxstats/gsdesign-python/actions/workflows/ci-tests.yml)
31
+ ![License](https://img.shields.io/pypi/l/gsdesign)
32
+
33
+ gsdesign-python is an experimental Python package for group sequential design.
34
+
35
+ ## Installation
36
+
37
+ You can install gsdesign-python from PyPI:
38
+
39
+ ```bash
40
+ pip install gsdesign
41
+ ```
42
+
43
+ Or install the development version from GitHub:
44
+
45
+ ```bash
46
+ git clone https://github.com/nanxstats/gsdesign-python.git
47
+ cd gsdesign-python
48
+ python3 -m pip install -e .
49
+ ```
@@ -0,0 +1,25 @@
1
+ # gsdesign-python
2
+
3
+ [![PyPI version](https://img.shields.io/pypi/v/gsdesign)](https://pypi.org/project/gsdesign/)
4
+ ![Python versions](https://img.shields.io/pypi/pyversions/gsdesign)
5
+ [![Checked with mypy](https://www.mypy-lang.org/static/mypy_badge.svg)](https://mypy-lang.org/)
6
+ [![CI Tests](https://github.com/nanxstats/gsdesign-python/actions/workflows/ci-tests.yml/badge.svg)](https://github.com/nanxstats/gsdesign-python/actions/workflows/ci-tests.yml)
7
+ ![License](https://img.shields.io/pypi/l/gsdesign)
8
+
9
+ gsdesign-python is an experimental Python package for group sequential design.
10
+
11
+ ## Installation
12
+
13
+ You can install gsdesign-python from PyPI:
14
+
15
+ ```bash
16
+ pip install gsdesign
17
+ ```
18
+
19
+ Or install the development version from GitHub:
20
+
21
+ ```bash
22
+ git clone https://github.com/nanxstats/gsdesign-python.git
23
+ cd gsdesign-python
24
+ python3 -m pip install -e .
25
+ ```
@@ -0,0 +1,51 @@
1
+ [project]
2
+ name = "gsdesign"
3
+ version = "0.0.1"
4
+ description = "Group sequential design"
5
+ authors = [
6
+ { name = "Nan Xiao", email = "me@nanx.me" }
7
+ ]
8
+ dependencies = [
9
+ "numpy>=2.0.0",
10
+ ]
11
+ readme = "README.md"
12
+
13
+ classifiers = [
14
+ "Development Status :: 3 - Alpha",
15
+
16
+ "Intended Audience :: Science/Research",
17
+
18
+ "License :: OSI Approved :: MIT License",
19
+
20
+ "Operating System :: OS Independent",
21
+
22
+ "Programming Language :: Python :: 3",
23
+ "Programming Language :: Python :: 3.10",
24
+ "Programming Language :: Python :: 3.11",
25
+ "Programming Language :: Python :: 3.12",
26
+ "Programming Language :: Python :: 3.13",
27
+
28
+ "Topic :: Scientific/Engineering :: Mathematics",
29
+
30
+ "Typing :: Typed",
31
+ ]
32
+
33
+ requires-python = ">=3.10"
34
+
35
+ [project.urls]
36
+ Repository = "https://github.com/nanxstats/gsdesign-python"
37
+ Issues = "https://github.com/nanxstats/gsdesign-python/issues"
38
+ Changelog = "https://github.com/nanxstats/gsdesign-python/blob/main/CHANGELOG.md"
39
+
40
+ [build-system]
41
+ requires = ["hatchling"]
42
+ build-backend = "hatchling.build"
43
+
44
+ [dependency-groups]
45
+ dev = [
46
+ "isort>=6.1.0",
47
+ "mypy>=1.18.2",
48
+ "pytest>=8.4.2",
49
+ "pytest-cov>=7.0.0",
50
+ "ruff>=0.13.3",
51
+ ]
@@ -0,0 +1,5 @@
1
+ """Core numerical integration routines for gsdesign."""
2
+
3
+ from .integration import gridpts, h1, hupdate
4
+
5
+ __all__ = ["gridpts", "h1", "hupdate"]
@@ -0,0 +1,184 @@
1
+ """Numerical integration utilities for group sequential design.
2
+
3
+ These routines port the canonical grid generation and update algorithms
4
+ from the original C and C++ implementations in gsDesign.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from typing import Iterable
10
+
11
+ import numpy as np
12
+ from numpy.typing import NDArray
13
+
14
+ SQRT_2PI: float = float(np.sqrt(2.0 * np.pi))
15
+ FloatArray = NDArray[np.float64]
16
+
17
+
18
+ def _normal_pdf(x: FloatArray) -> FloatArray:
19
+ """Evaluate the standard normal density at the supplied points."""
20
+ squared = np.square(x, dtype=np.float64)
21
+ return np.exp(-0.5 * squared) / SQRT_2PI
22
+
23
+
24
+ def _as_float64(array: Iterable[float]) -> FloatArray:
25
+ """Convert an iterable of floats to a contiguous float64 NumPy array."""
26
+ return np.asarray(array, dtype=np.float64)
27
+
28
+
29
+ def gridpts(
30
+ r: int = 18,
31
+ mu: float = 0.0,
32
+ a: float = -np.inf,
33
+ b: float = np.inf,
34
+ ) -> tuple[FloatArray, FloatArray]:
35
+ """
36
+ Construct Simpson's rule grid points for canonical normal integration.
37
+
38
+ Args:
39
+ r: Number of odd grid points defining the Simpson stencil (at least 2).
40
+ mu: Mean shift applied to the canonical grid before truncation.
41
+ a: Lower integration limit; use ``-numpy.inf`` for no truncation.
42
+ b: Upper integration limit; use ``numpy.inf`` for no truncation.
43
+
44
+ Returns:
45
+ A tuple containing grid locations ``z`` and Simpson weights ``w``.
46
+ """
47
+
48
+ if r < 2:
49
+ raise ValueError("r must be at least 2 for Simpson integration.")
50
+ if not a < b:
51
+ raise ValueError("Lower limit 'a' must be strictly less than upper limit 'b'.")
52
+
53
+ base_count = 6 * r - 1
54
+ x = np.empty(base_count, dtype=np.float64)
55
+ odd_indices = np.arange(r - 1, dtype=np.int64)
56
+ right_indices = 6 * r - 2 - odd_indices
57
+ tmp = 3.0 + 4.0 * np.log(r / (odd_indices.astype(np.float64) + 1.0))
58
+ x[odd_indices] = mu - tmp
59
+ x[right_indices] = mu + tmp
60
+
61
+ mid_indices = np.arange(r - 1, 5 * r, dtype=np.int64)
62
+ x[mid_indices] = mu - 3.0 + 3.0 * (mid_indices - (r - 1)) / (2.0 * r)
63
+
64
+ if np.nanmin(x) < a:
65
+ x = x[x > a]
66
+ x = np.insert(x, 0, a)
67
+ if np.nanmax(x) > b:
68
+ x = x[x < b]
69
+ x = np.append(x, b)
70
+
71
+ m = x.size
72
+ if m == 1:
73
+ return x.astype(np.float64), np.ones(1, dtype=np.float64)
74
+
75
+ z = np.empty(2 * m - 1, dtype=np.float64)
76
+ w = np.empty(2 * m - 1, dtype=np.float64)
77
+
78
+ odd_positions = np.arange(0, 2 * m - 1, 2)
79
+ even_positions = np.arange(1, 2 * m - 1, 2)
80
+
81
+ z[odd_positions] = x
82
+ z[even_positions] = 0.5 * (x[:-1] + x[1:])
83
+
84
+ w[odd_positions[0]] = x[1] - x[0]
85
+ if m > 2:
86
+ w[odd_positions[1:-1]] = x[2:] - x[:-2]
87
+ w[odd_positions[-1]] = x[-1] - x[-2]
88
+ w[even_positions] = 4.0 * (x[1:] - x[:-1])
89
+ w /= 6.0
90
+
91
+ return z, w
92
+
93
+
94
+ def h1(
95
+ r: int = 18,
96
+ theta: float = 0.0,
97
+ info: float = 1.0,
98
+ a: float = -np.inf,
99
+ b: float = np.inf,
100
+ ) -> tuple[FloatArray, FloatArray, FloatArray]:
101
+ """
102
+ Initialize the density grid for the first group sequential analysis.
103
+
104
+ Args:
105
+ r: Number of odd grid points defining the Simpson stencil (at least 2).
106
+ theta: Canonical drift parameter for the analysis.
107
+ info: Fisher information at the analysis; must be positive.
108
+ a: Lower integration limit; use ``-numpy.inf`` for no truncation.
109
+ b: Upper integration limit; use ``numpy.inf`` for no truncation.
110
+
111
+ Returns:
112
+ A tuple of arrays ``(z, w, h)`` ready for recursive integration.
113
+ """
114
+
115
+ if info <= 0:
116
+ raise ValueError("Information 'info' must be positive.")
117
+
118
+ mu = float(theta) * np.sqrt(info)
119
+ z, w = gridpts(r=r, mu=mu, a=a, b=b)
120
+ deviation = z - mu
121
+ h = w * _normal_pdf(deviation)
122
+ return z, w, h
123
+
124
+
125
+ def hupdate(
126
+ r: int,
127
+ theta: float,
128
+ info: float,
129
+ a: float,
130
+ b: float,
131
+ theta_prev: float,
132
+ info_prev: float,
133
+ gm1: tuple[Iterable[float], Iterable[float], Iterable[float]],
134
+ ) -> tuple[FloatArray, FloatArray, FloatArray]:
135
+ """
136
+ Update the density grid for a subsequent group sequential analysis.
137
+
138
+ Args:
139
+ r: Number of odd grid points defining the Simpson stencil (at least 2).
140
+ theta: Canonical drift parameter for the current analysis.
141
+ info: Fisher information at the current analysis; must exceed ``info_prev``.
142
+ a: Lower integration limit; use ``-numpy.inf`` for no truncation.
143
+ b: Upper integration limit; use ``numpy.inf`` for no truncation.
144
+ theta_prev: Canonical drift parameter at the previous analysis.
145
+ info_prev: Fisher information at the previous analysis; must be positive.
146
+ gm1: tuple ``(z_prev, w_prev, h_prev)`` from ``h1`` or ``hupdate``.
147
+
148
+ Returns:
149
+ A tuple of arrays ``(z, w, h)`` updated for the current analysis.
150
+ """
151
+
152
+ if info <= info_prev:
153
+ raise ValueError("Current information must exceed previous information.")
154
+ if info_prev <= 0:
155
+ raise ValueError("Previous information must be positive.")
156
+
157
+ try:
158
+ z_prev_raw, _, h_prev_raw = gm1
159
+ except (TypeError, ValueError) as exc:
160
+ raise ValueError("gm1 must unpack into (z_prev, w_prev, h_prev).") from exc
161
+
162
+ z_prev = _as_float64(z_prev_raw)
163
+ h_prev = _as_float64(h_prev_raw)
164
+ if z_prev.shape != h_prev.shape:
165
+ raise ValueError("Previous grid points and weights must share the same shape.")
166
+
167
+ rt_info = np.sqrt(info)
168
+ rt_info_prev = np.sqrt(info_prev)
169
+ delta = info - info_prev
170
+ rt_delta = np.sqrt(delta)
171
+
172
+ z, w = gridpts(r=r, mu=float(theta) * rt_info, a=a, b=b)
173
+
174
+ mu = theta * info - theta_prev * info_prev
175
+ scale = rt_info / rt_delta
176
+ t = (z_prev * rt_info_prev + mu) / rt_delta
177
+
178
+ kernel = _normal_pdf(z[:, np.newaxis] * scale - t[np.newaxis, :])
179
+ h = kernel @ h_prev
180
+ h *= w * scale
181
+ return z, w, h
182
+
183
+
184
+ __all__ = ["gridpts", "h1", "hupdate"]
File without changes
@@ -0,0 +1,16 @@
1
+ # Reference data fixtures
2
+
3
+ The `.txt` files in this directory contain reference outputs from the original
4
+ gsDesign2 R implementation. They are used to validate the Python port of the
5
+ `gridpts`, `h1`, and `hupdate` routines.
6
+
7
+ To regenerate the fixtures, run the helper script below (requires the
8
+ gsDesign2 R package to be installed):
9
+
10
+ ```sh
11
+ Rscript tests/fixtures/generate_reference_data.R
12
+ ```
13
+
14
+ The script recomputes each dataset via the package's internal functions and
15
+ writes the results in plain text so the pytest suite can consume them with
16
+ `numpy.loadtxt`.
@@ -0,0 +1,45 @@
1
+ options(digits = 16, scipen = 999)
2
+
3
+ suppressPackageStartupMessages(library(gsDesign2))
4
+
5
+ output_dir <- "tests/fixtures"
6
+ dir.create(output_dir, showWarnings = FALSE, recursive = TRUE)
7
+
8
+ write_matrix <- function(mat, filename) {
9
+ path <- file.path(output_dir, filename)
10
+ write.table(
11
+ mat,
12
+ file = path,
13
+ row.names = FALSE,
14
+ col.names = FALSE,
15
+ quote = FALSE
16
+ )
17
+ }
18
+
19
+ g <- gsDesign2:::gridpts(r = 5, mu = 0.5, a = -2, b = 2)
20
+ write_matrix(
21
+ cbind(g$z, g$w),
22
+ "gridpts_r5_mu0.5_a-2_b2.txt"
23
+ )
24
+
25
+ h1_ref <- gsDesign2:::h1(r = 5, theta = 0.5, info = 2, a = -2, b = 2)
26
+ write_matrix(
27
+ cbind(h1_ref$z, h1_ref$w, h1_ref$h),
28
+ "h1_r5_theta0.5_info2_a-2_b2.txt"
29
+ )
30
+
31
+ gm1 <- gsDesign2:::h1(r = 5, theta = 0.3, info = 1.5, a = -2, b = 2)
32
+ hupdate_ref <- gsDesign2:::hupdate(
33
+ r = 5,
34
+ theta = 0.5,
35
+ info = 2.5,
36
+ a = -2,
37
+ b = 2,
38
+ thetam1 = 0.3,
39
+ im1 = 1.5,
40
+ gm1 = gm1
41
+ )
42
+ write_matrix(
43
+ cbind(hupdate_ref$z, hupdate_ref$w, hupdate_ref$h),
44
+ "hupdate_r5_theta0.5_info2.5_thetaprev0.3_infoprev1.5_a-2_b2.txt"
45
+ )
@@ -0,0 +1,29 @@
1
+ -2 0.0166666666666667
2
+ -1.95 0.0666666666666667
3
+ -1.9 0.0666666666666667
4
+ -1.75 0.2
5
+ -1.6 0.1
6
+ -1.45 0.2
7
+ -1.3 0.1
8
+ -1.15 0.2
9
+ -1 0.1
10
+ -0.85 0.2
11
+ -0.7 0.1
12
+ -0.55 0.2
13
+ -0.4 0.1
14
+ -0.25 0.2
15
+ -0.1 0.1
16
+ 0.05 0.2
17
+ 0.2 0.1
18
+ 0.35 0.2
19
+ 0.5 0.0999999999999999
20
+ 0.65 0.2
21
+ 0.8 0.1
22
+ 0.95 0.2
23
+ 1.1 0.1
24
+ 1.25 0.2
25
+ 1.4 0.1
26
+ 1.55 0.2
27
+ 1.7 0.1
28
+ 1.85 0.2
29
+ 2 0.05
@@ -0,0 +1,31 @@
1
+ -2 0.00118446353109125 0.0000121083238684652
2
+ -1.99644660940673 0.004737854124365 0.000048901134406299
3
+ -1.99289321881345 0.0511844635310913 0.000533389957968692
4
+ -1.84289321881345 0.2 0.00308986942687904
5
+ -1.69289321881345 0.1 0.00223945302948429
6
+ -1.54289321881345 0.2 0.00634793036713348
7
+ -1.39289321881345 0.1 0.00439835959804272
8
+ -1.24289321881345 0.2 0.0119189412137632
9
+ -1.09289321881345 0.1 0.00789501583008941
10
+ -0.942893218813453 0.2 0.0204529849127956
11
+ -0.792893218813453 0.1 0.0129517595665892
12
+ -0.642893218813453 0.2 0.0320766654683839
13
+ -0.492893218813452 0.1 0.0194186054983213
14
+ -0.342893218813452 0.2 0.0459764281368466
15
+ -0.192893218813452 0.1 0.0266085249898755
16
+ -0.0428932188134525 0.2 0.0602274864309608
17
+ 0.107106781186547 0.1 0.03332246028918
18
+ 0.257106781186548 0.2 0.0721053924923297
19
+ 0.407106781186548 0.1 0.0381387815460524
20
+ 0.557106781186548 0.2 0.0788958661815777
21
+ 0.707106781186547 0.0999999999999999 0.0398942280401432
22
+ 0.857106781186547 0.2 0.0788958661815777
23
+ 1.00710678118655 0.1 0.0381387815460524
24
+ 1.15710678118655 0.2 0.0721053924923297
25
+ 1.30710678118655 0.1 0.03332246028918
26
+ 1.45710678118655 0.2 0.0602274864309608
27
+ 1.60710678118655 0.1 0.0266085249898755
28
+ 1.75710678118655 0.2 0.0459764281368467
29
+ 1.90710678118655 0.0654822031355754 0.0127157306985068
30
+ 1.95355339059327 0.0619288125423016 0.0113615225581578
31
+ 2 0.0154822031355754 0.0026777213989986
@@ -0,0 +1,31 @@
1
+ -2 0.0150949025070158 0.0000769903094874132
2
+ -1.95471529247895 0.0603796100280634 0.000360648259573358
3
+ -1.9094305849579 0.0650949025070158 0.000453637555511597
4
+ -1.7594305849579 0.2 0.00226308249491002
5
+ -1.6094305849579 0.1 0.00176751849809336
6
+ -1.4594305849579 0.2 0.00532161106376017
7
+ -1.30943058495791 0.1 0.00386730566696142
8
+ -1.15943058495791 0.2 0.0108735635349179
9
+ -1.0094305849579 0.1 0.00740601835535395
10
+ -0.859430584957905 0.2 0.0195837513130162
11
+ -0.709430584957905 0.1 0.0125849259586546
12
+ -0.559430584957905 0.2 0.0314887051813321
13
+ -0.409430584957905 0.1 0.0191948082376024
14
+ -0.259430584957905 0.2 0.0456519180921292
15
+ -0.109430584957905 0.1 0.0264953977337527
16
+ 0.040569415042095 0.2 0.060070766179351
17
+ 0.190569415042095 0.1 0.0332633993810258
18
+ 0.340569415042095 0.2 0.0719917642881179
19
+ 0.490569415042095 0.1 0.0380637898902835
20
+ 0.640569415042095 0.2 0.0786564457361483
21
+ 0.790569415042095 0.0999999999999999 0.0396941599902116
22
+ 0.940569415042095 0.2 0.0782412744009736
23
+ 1.09056941504209 0.1 0.0376262137261268
24
+ 1.2405694150421 0.2 0.0705783338474663
25
+ 1.3905694150421 0.1 0.0322423441110482
26
+ 1.5405694150421 0.2 0.057325866269257
27
+ 1.6905694150421 0.1 0.0247577062768794
28
+ 1.8405694150421 0.2 0.041489467946484
29
+ 1.9905694150421 0.0515717641596508 0.0086812044484898
30
+ 1.99528470752105 0.00628705663860322 0.00105082035484165
31
+ 2 0.00157176415965081 0.00026083569600901