simtrial 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.
- simtrial-0.0.1/.github/workflows/ci-tests.yml +56 -0
- simtrial-0.0.1/.github/workflows/mypy.yml +34 -0
- simtrial-0.0.1/.gitignore +13 -0
- simtrial-0.0.1/.python-version +1 -0
- simtrial-0.0.1/CHANGELOG.md +15 -0
- simtrial-0.0.1/LICENSE +20 -0
- simtrial-0.0.1/PKG-INFO +50 -0
- simtrial-0.0.1/README.md +26 -0
- simtrial-0.0.1/pyproject.toml +51 -0
- simtrial-0.0.1/src/simtrial/__init__.py +7 -0
- simtrial-0.0.1/src/simtrial/piecewise_exponential.py +154 -0
- simtrial-0.0.1/tests/__init__.py +0 -0
- simtrial-0.0.1/tests/fixtures/README.md +18 -0
- simtrial-0.0.1/tests/fixtures/generate_piecewise_exponential.R +50 -0
- simtrial-0.0.1/tests/fixtures/pwexp_multi_seed_456_n30.txt +30 -0
- simtrial-0.0.1/tests/fixtures/pwexp_single_seed_123_n20.txt +20 -0
- simtrial-0.0.1/tests/test_piecewise_exponential.py +244 -0
- simtrial-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=simtrial --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=simtrial --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,15 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## simtrial-python 0.0.1
|
|
4
|
+
|
|
5
|
+
### New features
|
|
6
|
+
|
|
7
|
+
- Added a piecewise exponential sampler that mirrors the R implementation using
|
|
8
|
+
inverse-CDF sampling with reproducibility hooks and type hints (#1).
|
|
9
|
+
|
|
10
|
+
### Testing
|
|
11
|
+
|
|
12
|
+
- Added pytest tests with 100% code coverage for the sampler, including
|
|
13
|
+
validation, broadcasting, and RNG behaviors (#1).
|
|
14
|
+
- Added deterministic R-generated fixtures (`tests/fixtures/`) to
|
|
15
|
+
cross-check Python draws (#1).
|
simtrial-0.0.1/LICENSE
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
Copyright (c) 2025, simtrial-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.
|
simtrial-0.0.1/PKG-INFO
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: simtrial
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: Clinical trial simulation
|
|
5
|
+
Project-URL: Repository, https://github.com/nanxstats/simtrial-python
|
|
6
|
+
Project-URL: Issues, https://github.com/nanxstats/simtrial-python/issues
|
|
7
|
+
Project-URL: Changelog, https://github.com/nanxstats/simtrial-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
|
+
# simtrial-python
|
|
26
|
+
|
|
27
|
+
[](https://pypi.org/project/simtrial/)
|
|
28
|
+

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

|
|
32
|
+
|
|
33
|
+
simtrial-python is an experimental Python package for clinical trial
|
|
34
|
+
simulation with time-to-event endpoints.
|
|
35
|
+
|
|
36
|
+
## Installation
|
|
37
|
+
|
|
38
|
+
You can install simtrial-python from PyPI:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
pip install simtrial
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Or install the development version from GitHub:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
git clone https://github.com/nanxstats/simtrial-python.git
|
|
48
|
+
cd simtrial-python
|
|
49
|
+
python3 -m pip install -e .
|
|
50
|
+
```
|
simtrial-0.0.1/README.md
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# simtrial-python
|
|
2
|
+
|
|
3
|
+
[](https://pypi.org/project/simtrial/)
|
|
4
|
+

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

|
|
8
|
+
|
|
9
|
+
simtrial-python is an experimental Python package for clinical trial
|
|
10
|
+
simulation with time-to-event endpoints.
|
|
11
|
+
|
|
12
|
+
## Installation
|
|
13
|
+
|
|
14
|
+
You can install simtrial-python from PyPI:
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
pip install simtrial
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Or install the development version from GitHub:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
git clone https://github.com/nanxstats/simtrial-python.git
|
|
24
|
+
cd simtrial-python
|
|
25
|
+
python3 -m pip install -e .
|
|
26
|
+
```
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "simtrial"
|
|
3
|
+
version = "0.0.1"
|
|
4
|
+
description = "Clinical trial simulation"
|
|
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/simtrial-python"
|
|
37
|
+
Issues = "https://github.com/nanxstats/simtrial-python/issues"
|
|
38
|
+
Changelog = "https://github.com/nanxstats/simtrial-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,154 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Tools for working with the piecewise exponential distribution.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
import math
|
|
8
|
+
from dataclasses import dataclass
|
|
9
|
+
from typing import Sequence, cast
|
|
10
|
+
|
|
11
|
+
import numpy as np
|
|
12
|
+
from numpy.typing import NDArray
|
|
13
|
+
|
|
14
|
+
_RANDOM_STATE: np.random.Generator | None = None
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def _default_rng() -> np.random.Generator:
|
|
18
|
+
"""
|
|
19
|
+
Return a module-level random number generator.
|
|
20
|
+
|
|
21
|
+
Returns:
|
|
22
|
+
The reusable random number generator for piecewise exponential sampling.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
global _RANDOM_STATE
|
|
26
|
+
if _RANDOM_STATE is None:
|
|
27
|
+
_reset_rng()
|
|
28
|
+
return cast(np.random.Generator, _RANDOM_STATE)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _reset_rng(seed: int | None = None) -> None:
|
|
32
|
+
"""
|
|
33
|
+
Initialize the module-level random number generator.
|
|
34
|
+
|
|
35
|
+
Args:
|
|
36
|
+
seed: Seed used to reset the generator.
|
|
37
|
+
|
|
38
|
+
Returns:
|
|
39
|
+
Nothing.
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
global _RANDOM_STATE
|
|
43
|
+
_RANDOM_STATE = np.random.default_rng(seed)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def set_random_seed(seed: int) -> None:
|
|
47
|
+
"""
|
|
48
|
+
Set the seed for the module-level random number generator.
|
|
49
|
+
|
|
50
|
+
Args:
|
|
51
|
+
seed: Seed value that controls reproducibility.
|
|
52
|
+
|
|
53
|
+
Returns:
|
|
54
|
+
Nothing.
|
|
55
|
+
"""
|
|
56
|
+
|
|
57
|
+
_reset_rng(seed=seed)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
@dataclass
|
|
61
|
+
class PiecewiseExponential:
|
|
62
|
+
"""
|
|
63
|
+
Piecewise exponential sampler based on the inverse cumulative distribution.
|
|
64
|
+
|
|
65
|
+
Args:
|
|
66
|
+
durations: Interval durations for each hazard rate segment; all but the
|
|
67
|
+
final duration must be finite and strictly positive, while the last
|
|
68
|
+
entry may be set to ``math.inf`` to represent an open-ended tail.
|
|
69
|
+
rates: Hazard rates aligned with the provided durations.
|
|
70
|
+
rng: Optional random number generator.
|
|
71
|
+
|
|
72
|
+
Raises:
|
|
73
|
+
ValueError: Raised when inputs are invalid.
|
|
74
|
+
"""
|
|
75
|
+
|
|
76
|
+
durations: Sequence[float]
|
|
77
|
+
rates: Sequence[float]
|
|
78
|
+
rng: np.random.Generator | None = None
|
|
79
|
+
|
|
80
|
+
def __post_init__(self) -> None:
|
|
81
|
+
"""
|
|
82
|
+
Validate inputs and precompute cumulative quantities.
|
|
83
|
+
|
|
84
|
+
Returns:
|
|
85
|
+
Nothing.
|
|
86
|
+
"""
|
|
87
|
+
|
|
88
|
+
self._durations = np.asarray(self.durations, dtype=float)
|
|
89
|
+
self._rates = np.asarray(self.rates, dtype=float)
|
|
90
|
+
|
|
91
|
+
if self._durations.ndim != 1:
|
|
92
|
+
raise ValueError("durations must be one-dimensional")
|
|
93
|
+
if self._rates.ndim != 1:
|
|
94
|
+
raise ValueError("rates must be one-dimensional")
|
|
95
|
+
if self._durations.size == 0:
|
|
96
|
+
raise ValueError("durations must contain at least one interval")
|
|
97
|
+
if self._durations.size != self._rates.size:
|
|
98
|
+
raise ValueError("durations and rates must have the same length")
|
|
99
|
+
if not np.all(np.isfinite(self._durations[:-1])):
|
|
100
|
+
raise ValueError(
|
|
101
|
+
"durations must be finite except possibly the last interval, "
|
|
102
|
+
"which may extend to infinity"
|
|
103
|
+
)
|
|
104
|
+
if np.any(self._durations[:-1] <= 0):
|
|
105
|
+
raise ValueError("durations before the final interval must be positive")
|
|
106
|
+
last_duration = float(self._durations[-1])
|
|
107
|
+
if math.isnan(last_duration):
|
|
108
|
+
raise ValueError("final duration must be finite or math.inf")
|
|
109
|
+
if last_duration <= 0:
|
|
110
|
+
raise ValueError("final duration must be positive")
|
|
111
|
+
if np.any(~np.isfinite(self._rates)):
|
|
112
|
+
raise ValueError("rates must be finite")
|
|
113
|
+
if np.any(self._rates <= 0):
|
|
114
|
+
raise ValueError("rates must be strictly positive")
|
|
115
|
+
|
|
116
|
+
self._cum_time = np.concatenate(
|
|
117
|
+
(np.array([0.0]), np.cumsum(self._durations[:-1]))
|
|
118
|
+
)
|
|
119
|
+
self._cum_hazard = np.concatenate(
|
|
120
|
+
(np.array([0.0]), np.cumsum(self._durations[:-1] * self._rates[:-1]))
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
def sample(
|
|
124
|
+
self,
|
|
125
|
+
size: int | tuple[int, ...] | None = None,
|
|
126
|
+
rng: np.random.Generator | None = None,
|
|
127
|
+
) -> float | NDArray[np.float64]:
|
|
128
|
+
"""
|
|
129
|
+
Draw samples using the inverse cumulative distribution function.
|
|
130
|
+
|
|
131
|
+
Args:
|
|
132
|
+
size: Requested sample size or shape.
|
|
133
|
+
rng: Optional random number generator overriding the stored generator.
|
|
134
|
+
|
|
135
|
+
Returns:
|
|
136
|
+
A scalar when `size` is `None`, otherwise an array of samples.
|
|
137
|
+
"""
|
|
138
|
+
|
|
139
|
+
generator = rng or self.rng or _default_rng()
|
|
140
|
+
|
|
141
|
+
if size is None:
|
|
142
|
+
uniform = float(generator.uniform())
|
|
143
|
+
hazard = -math.log(uniform)
|
|
144
|
+
index = int(np.searchsorted(self._cum_hazard, hazard, side="right") - 1)
|
|
145
|
+
base_time = float(self._cum_time[index])
|
|
146
|
+
return base_time + (hazard - float(self._cum_hazard[index])) / float(
|
|
147
|
+
self._rates[index]
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
uniforms = generator.uniform(size=size)
|
|
151
|
+
hazards = -np.log(uniforms)
|
|
152
|
+
indices = np.searchsorted(self._cum_hazard, hazards, side="right") - 1
|
|
153
|
+
base_times = self._cum_time[indices]
|
|
154
|
+
return base_times + (hazards - self._cum_hazard[indices]) / self._rates[indices]
|
|
File without changes
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Reference data fixtures
|
|
2
|
+
|
|
3
|
+
The `.txt` files in this directory contain reference outputs from the original
|
|
4
|
+
simtrial R implementation. They are used to validate the Python port of the
|
|
5
|
+
piecewise exponential generator.
|
|
6
|
+
|
|
7
|
+
## Regenerating fixtures
|
|
8
|
+
|
|
9
|
+
The fixture generator script reproduces the draws using the R implementation
|
|
10
|
+
for specific seeds and parameter sets, and writes both the uniform random
|
|
11
|
+
numbers and the resulting event times to plain-text files without headers.
|
|
12
|
+
|
|
13
|
+
```sh
|
|
14
|
+
Rscript tests/fixtures/generate_piecewise_exponential.R
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
The pytest suite consumes these numbers with `numpy.loadtxt` to cross-check the
|
|
18
|
+
Python implementation against the reference algorithm.
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
options(digits = 16, scipen = 999)
|
|
2
|
+
|
|
3
|
+
suppressPackageStartupMessages(library(simtrial))
|
|
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
|
+
write_fixture <- function(filename, seed, n, durations, rates) {
|
|
20
|
+
fail_rate <- data.frame(duration = durations, rate = rates)
|
|
21
|
+
|
|
22
|
+
set.seed(seed)
|
|
23
|
+
uniforms <- runif(n)
|
|
24
|
+
|
|
25
|
+
set.seed(seed)
|
|
26
|
+
r_times <- simtrial::rpwexp(n = n, fail_rate = fail_rate)
|
|
27
|
+
|
|
28
|
+
if (!all.equal(length(r_times), n)) {
|
|
29
|
+
stop("Generated R sample length does not match request.")
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
data <- cbind(uniforms, r_times)
|
|
33
|
+
write_matrix(data, filename)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
write_fixture(
|
|
37
|
+
filename = "pwexp_single_seed_123_n20.txt",
|
|
38
|
+
seed = 123,
|
|
39
|
+
n = 20,
|
|
40
|
+
durations = c(1.0),
|
|
41
|
+
rates = c(2.0)
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
write_fixture(
|
|
45
|
+
filename = "pwexp_multi_seed_456_n30.txt",
|
|
46
|
+
seed = 456,
|
|
47
|
+
n = 30,
|
|
48
|
+
durations = c(0.5, 0.5, 1.0),
|
|
49
|
+
rates = c(1.0, 3.0, 10.0)
|
|
50
|
+
)
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
0.0895516003947705 1.04129402791134
|
|
2
|
+
0.21051231934689 0.852737034452974
|
|
3
|
+
0.73295526811853 0.3106706047168
|
|
4
|
+
0.852133540669456 0.16001202655997
|
|
5
|
+
0.788397894473746 0.237752374339119
|
|
6
|
+
0.331959968432784 0.700913631448442
|
|
7
|
+
0.0824327350128442 1.0495772651384
|
|
8
|
+
0.285526945022866 0.751139625325209
|
|
9
|
+
0.23750327154994 0.812524626885066
|
|
10
|
+
0.38523616688326 0.651299570761263
|
|
11
|
+
0.372945911018178 0.662107293509504
|
|
12
|
+
0.217908559599891 0.84122658518801
|
|
13
|
+
0.755105035379529 0.280898419701376
|
|
14
|
+
0.82168106874451 0.196402953443282
|
|
15
|
+
0.598918164148927 0.504210103662197
|
|
16
|
+
0.651033560046926 0.429194086570926
|
|
17
|
+
0.843117238022387 0.170649258262776
|
|
18
|
+
0.4532381426543 0.597112530135988
|
|
19
|
+
0.716757099609822 0.333018268987182
|
|
20
|
+
0.291222166502848 0.744556281441457
|
|
21
|
+
0.179883137578145 0.905149291537882
|
|
22
|
+
0.721743599977344 0.326085327846133
|
|
23
|
+
0.905087579507381 0.0997235670280772
|
|
24
|
+
0.445766670163721 0.602653208308821
|
|
25
|
+
0.838601463707164 0.17601969882944
|
|
26
|
+
0.70349283167161 0.351697592001127
|
|
27
|
+
0.950928996317089 0.0503158813512434
|
|
28
|
+
0.643152175005525 0.441373918661801
|
|
29
|
+
0.0748198556248099 1.05926719796977
|
|
30
|
+
0.253490373725072 0.790809810047676
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
0.287577520124614 0.623131409936862
|
|
2
|
+
0.788305135443807 0.118935018178498
|
|
3
|
+
0.4089769218117 0.4470482752098
|
|
4
|
+
0.883017404004931 0.0622051842437791
|
|
5
|
+
0.940467284293845 0.0306892081429518
|
|
6
|
+
0.0455564993899316 1.54440098925953
|
|
7
|
+
0.528105488047004 0.319229613631512
|
|
8
|
+
0.892419044394046 0.0569097380018624
|
|
9
|
+
0.551435014465824 0.297615640691194
|
|
10
|
+
0.456614735303447 0.391957636804057
|
|
11
|
+
0.956833345349878 0.0220630227419475
|
|
12
|
+
0.453334156190977 0.395562886897321
|
|
13
|
+
0.677570635452867 0.194620736345925
|
|
14
|
+
0.572633401956409 0.278754777090065
|
|
15
|
+
0.102924682665616 1.13687889724614
|
|
16
|
+
0.899824970401824 0.0527775059511509
|
|
17
|
+
0.24608773435466 0.701033581456949
|
|
18
|
+
0.0420595335308462 1.58433459966692
|
|
19
|
+
0.327920719282702 0.557491704659201
|
|
20
|
+
0.954503649147227 0.0232819063627237
|