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.
- gsdesign-0.0.1/.github/workflows/ci-tests.yml +56 -0
- gsdesign-0.0.1/.github/workflows/mypy.yml +34 -0
- gsdesign-0.0.1/.gitignore +13 -0
- gsdesign-0.0.1/.python-version +1 -0
- gsdesign-0.0.1/CHANGELOG.md +14 -0
- gsdesign-0.0.1/LICENSE +20 -0
- gsdesign-0.0.1/PKG-INFO +49 -0
- gsdesign-0.0.1/README.md +25 -0
- gsdesign-0.0.1/pyproject.toml +51 -0
- gsdesign-0.0.1/src/gsdesign/__init__.py +5 -0
- gsdesign-0.0.1/src/gsdesign/integration.py +184 -0
- gsdesign-0.0.1/tests/__init__.py +0 -0
- gsdesign-0.0.1/tests/fixtures/README.md +16 -0
- gsdesign-0.0.1/tests/fixtures/generate_reference_data.R +45 -0
- gsdesign-0.0.1/tests/fixtures/gridpts_r5_mu0.5_a-2_b2.txt +29 -0
- gsdesign-0.0.1/tests/fixtures/h1_r5_theta0.5_info2_a-2_b2.txt +31 -0
- gsdesign-0.0.1/tests/fixtures/hupdate_r5_theta0.5_info2.5_thetaprev0.3_infoprev1.5_a-2_b2.txt +31 -0
- gsdesign-0.0.1/tests/test_integration.py +176 -0
- gsdesign-0.0.1/uv.lock +525 -0
|
@@ -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 @@
|
|
|
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.
|
gsdesign-0.0.1/PKG-INFO
ADDED
|
@@ -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
|
+
[](https://pypi.org/project/gsdesign/)
|
|
28
|
+

|
|
29
|
+
[](https://mypy-lang.org/)
|
|
30
|
+
[](https://github.com/nanxstats/gsdesign-python/actions/workflows/ci-tests.yml)
|
|
31
|
+

|
|
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
|
+
```
|
gsdesign-0.0.1/README.md
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# gsdesign-python
|
|
2
|
+
|
|
3
|
+
[](https://pypi.org/project/gsdesign/)
|
|
4
|
+

|
|
5
|
+
[](https://mypy-lang.org/)
|
|
6
|
+
[](https://github.com/nanxstats/gsdesign-python/actions/workflows/ci-tests.yml)
|
|
7
|
+

|
|
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,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
|