sim-tools 1.0.3__tar.gz → 1.0.4__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.
- {sim_tools-1.0.3 → sim_tools-1.0.4}/PKG-INFO +1 -1
- {sim_tools-1.0.3 → sim_tools-1.0.4}/sim_tools/__init__.py +1 -1
- {sim_tools-1.0.3 → sim_tools-1.0.4}/sim_tools/time_dependent.py +49 -25
- {sim_tools-1.0.3 → sim_tools-1.0.4}/.gitignore +0 -0
- {sim_tools-1.0.3 → sim_tools-1.0.4}/LICENSE +0 -0
- {sim_tools-1.0.3 → sim_tools-1.0.4}/README.md +0 -0
- {sim_tools-1.0.3 → sim_tools-1.0.4}/pyproject.toml +0 -0
- {sim_tools-1.0.3 → sim_tools-1.0.4}/sim_tools/_validation.py +0 -0
- {sim_tools-1.0.3 → sim_tools-1.0.4}/sim_tools/data/nspp_example1.csv +0 -0
- {sim_tools-1.0.3 → sim_tools-1.0.4}/sim_tools/datasets.py +0 -0
- {sim_tools-1.0.3 → sim_tools-1.0.4}/sim_tools/distributions.py +0 -0
- {sim_tools-1.0.3 → sim_tools-1.0.4}/sim_tools/output_analysis.py +0 -0
- {sim_tools-1.0.3 → sim_tools-1.0.4}/sim_tools/ovs/__init__.py +0 -0
- {sim_tools-1.0.3 → sim_tools-1.0.4}/sim_tools/ovs/evaluation.py +0 -0
- {sim_tools-1.0.3 → sim_tools-1.0.4}/sim_tools/ovs/fixed_budget.py +0 -0
- {sim_tools-1.0.3 → sim_tools-1.0.4}/sim_tools/ovs/indifference_zone.py +0 -0
- {sim_tools-1.0.3 → sim_tools-1.0.4}/sim_tools/ovs/toy_models.py +0 -0
- {sim_tools-1.0.3 → sim_tools-1.0.4}/sim_tools/trace.py +0 -0
|
@@ -8,7 +8,7 @@ import numpy as np
|
|
|
8
8
|
from numpy.random import SeedSequence
|
|
9
9
|
import pandas as pd
|
|
10
10
|
import matplotlib.pyplot as plt
|
|
11
|
-
|
|
11
|
+
import itertools
|
|
12
12
|
|
|
13
13
|
# pylint: disable=too-few-public-methods
|
|
14
14
|
class NSPPThinning:
|
|
@@ -33,7 +33,7 @@ class NSPPThinning:
|
|
|
33
33
|
"""
|
|
34
34
|
Non Stationary Poisson Process via Thinning.
|
|
35
35
|
|
|
36
|
-
Time dependency is
|
|
36
|
+
Time dependency is handled for a single table
|
|
37
37
|
consisting of equally spaced intervals.
|
|
38
38
|
|
|
39
39
|
Parameters
|
|
@@ -54,12 +54,37 @@ class NSPPThinning:
|
|
|
54
54
|
Random seed for the uniform distribution used
|
|
55
55
|
for acceptance/rejection sampling.
|
|
56
56
|
"""
|
|
57
|
+
|
|
58
|
+
# -- Defensive parameter check added by TM as part of fix v1.0.4 --
|
|
59
|
+
|
|
60
|
+
# data must be a dataframe
|
|
61
|
+
if not isinstance(data, pd.DataFrame):
|
|
62
|
+
raise TypeError(f"Data should be a DataFrame, but got {type(data).__name__}")
|
|
63
|
+
|
|
64
|
+
# Check required columns t and mean_iat are provided.
|
|
65
|
+
required_cols = ["t", "mean_iat"]
|
|
66
|
+
missing_cols = [col for col in required_cols if col not in data.columns]
|
|
67
|
+
if missing_cols:
|
|
68
|
+
raise ValueError(f"Missing required columns: {missing_cols}")
|
|
69
|
+
|
|
70
|
+
# empty dataframe or only a single row.
|
|
71
|
+
if data.empty:
|
|
72
|
+
raise ValueError(f"Dataframe does not contain any rows. Add at least 2.")
|
|
73
|
+
elif len(data) == 1:
|
|
74
|
+
msg = "Dataframe contains a single time point. Add more of use Exponential class."
|
|
75
|
+
raise ValueError(msg)
|
|
76
|
+
|
|
77
|
+
# -- end of defensive code --
|
|
78
|
+
|
|
57
79
|
self.data = data
|
|
58
80
|
self.arr_rng = np.random.default_rng(random_seed1)
|
|
59
81
|
self.thinning_rng = np.random.default_rng(random_seed2)
|
|
60
82
|
|
|
61
|
-
#
|
|
62
|
-
self.
|
|
83
|
+
# drop to numpy for lookup speed
|
|
84
|
+
self.mean_iats = data["mean_iat"].to_numpy(dtype=float)
|
|
85
|
+
|
|
86
|
+
# Get the minimum mean IAT (corresponds to the maximum arrival rate)
|
|
87
|
+
self.min_iat = self.mean_iats.min()
|
|
63
88
|
|
|
64
89
|
if self.min_iat <= 0:
|
|
65
90
|
raise ValueError("Mean inter-arrival times must be positive")
|
|
@@ -75,6 +100,10 @@ class NSPPThinning:
|
|
|
75
100
|
"With only one data point, interval_width must be provided"
|
|
76
101
|
)
|
|
77
102
|
|
|
103
|
+
# Pre-compute the acceptance probabilities. Added by TM v1.0.4
|
|
104
|
+
self.accept_prob = self.min_iat / self.mean_iats
|
|
105
|
+
self.n_periods = self.mean_iats.size
|
|
106
|
+
|
|
78
107
|
self.rejects_last_sample = None
|
|
79
108
|
|
|
80
109
|
def __repr__(self):
|
|
@@ -90,6 +119,7 @@ class NSPPThinning:
|
|
|
90
119
|
f"{self.__class__.__name__}(data={data_str}, " +
|
|
91
120
|
f"interval={self.interval})"
|
|
92
121
|
)
|
|
122
|
+
|
|
93
123
|
|
|
94
124
|
def sample(self, simulation_time: float) -> float:
|
|
95
125
|
"""
|
|
@@ -99,36 +129,30 @@ class NSPPThinning:
|
|
|
99
129
|
Parameters
|
|
100
130
|
----------
|
|
101
131
|
simulation_time: float
|
|
102
|
-
The current simulation time.
|
|
103
|
-
the mean IAT for the time period.
|
|
132
|
+
The current simulation time.
|
|
104
133
|
|
|
105
134
|
Returns
|
|
106
135
|
-------
|
|
107
136
|
float
|
|
108
137
|
The inter-arrival time
|
|
109
138
|
"""
|
|
110
|
-
|
|
111
|
-
# this gives us the index of dataframe to use
|
|
112
|
-
t = int(simulation_time // self.interval) % len(self.data)
|
|
113
|
-
mean_iat_t = self.data["mean_iat"].iloc[t]
|
|
114
|
-
|
|
115
|
-
# set to a large number so that at least 1 sample taken!
|
|
116
|
-
u = np.inf
|
|
117
|
-
|
|
118
|
-
# included for audit and tracking purposes.
|
|
119
|
-
self.rejects_last_sample = 0
|
|
120
|
-
|
|
139
|
+
|
|
121
140
|
interarrival_time = 0.0
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
# since lambda = 1/mean_iat
|
|
126
|
-
while u >= (self.min_iat / mean_iat_t):
|
|
127
|
-
self.rejects_last_sample += 1
|
|
141
|
+
|
|
142
|
+
for self.rejects_last_sample in itertools.count(start=0):
|
|
143
|
+
# sample the next inter-arrival time and calculate clock time
|
|
128
144
|
interarrival_time += self.arr_rng.exponential(self.min_iat)
|
|
129
|
-
|
|
145
|
+
arrival_sim_clock_time = simulation_time + interarrival_time
|
|
146
|
+
|
|
147
|
+
# get the t index of the candidate arrival
|
|
148
|
+
# fix v1.0.4 to use 'candidate_arrival_time' Fix by Sammi Rosser
|
|
149
|
+
t_idx = int(arrival_sim_clock_time // self.interval) % self.n_periods
|
|
130
150
|
|
|
131
|
-
|
|
151
|
+
# accept or reject? TM modified v1.0.4 to use pre-computed probabilities
|
|
152
|
+
u = self.thinning_rng.uniform()
|
|
153
|
+
if u <= self.accept_prob[t_idx]:
|
|
154
|
+
# accepted so return inter-arrival time
|
|
155
|
+
return interarrival_time
|
|
132
156
|
|
|
133
157
|
|
|
134
158
|
def nspp_simulation(
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|