Skip to content

Commit 4889ed3

Browse files
committed
use standard terminology
1 parent 94572fd commit 4889ed3

13 files changed

Lines changed: 98 additions & 109 deletions

File tree

activitysim/abm/models/util/bias_logsums.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,11 @@ def maybe_bias_logsums(state: workflow.State, choices_df: pd.DataFrame, model_se
4141
else:
4242
logger.warning(
4343
"Using Poisson sampling method for location choice logsum calculations. Currently the logsums results will"
44-
+ " differ from those obtained with monte_carlo or eet sampling by a constant shift of"
44+
+ " differ from those obtained with inverse_cdf or eet sampling by a constant shift of"
4545
+ f" log({model_settings.SAMPLE_SIZE}) if using the common correction factor"
4646
+ " `log(pick_count / prob)` in location choice specs. The results of the Poisson method are unbiased,"
4747
+ " i.e., they agree with the results obtained with a full destination sample, unlike those for"
48-
+ " monte_carlo or eet sampling."
48+
+ " inverse_cdf or eet sampling."
4949
)
5050

5151
return choices_df

activitysim/core/configuration/base.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -135,12 +135,12 @@ class ComputeSettings(PydanticBase):
135135
Sharrow settings for a component.
136136
"""
137137

138-
sample_method: None | Literal["monte_carlo", "eet", "poisson"] = None
138+
sample_method: None | Literal["inverse_cdf", "eet", "poisson"] = None
139139
"""
140140
Override the alternative sampling method used by `interaction_sample`.
141141
142142
When unset, `interaction_sample` preserves legacy behavior: it uses
143-
`monte_carlo` when explicit error terms are off and `poisson` when they
143+
`inverse_cdf` when explicit error terms are off and `poisson` when they
144144
are on.
145145
"""
146146

activitysim/core/configuration/top.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -786,17 +786,18 @@ def _check_store_skims_in_shm(self):
786786
Make choice from random utility model by drawing from distribution of unobserved
787787
part of utility and taking the maximum of total utility.
788788
789-
Defaults to standard Monte Carlo method, i.e., calculating probabilities and then
790-
drawing a single uniform random number to draw from cumulative probabily.
789+
Defaults to the standard inverse-CDF (probability-based) method, i.e., calculating
790+
probabilities and then drawing a single uniform random number against the
791+
cumulative probability.
791792
792793
.. versionadded:: 1.6
793794
"""
794795

795-
sample_method: None | Literal["monte_carlo", "eet", "poisson"] = None
796+
sample_method: None | Literal["inverse_cdf", "eet", "poisson"] = None
796797
"""
797798
Sampling method to use in `activitysim.core.interaction_sample`.
798799
799-
When unset, `monte_carlo` is used when `use_explicit_error_terms` is false and
800+
When unset, `inverse_cdf` is used when `use_explicit_error_terms` is false and
800801
`poisson` is used when it is true.
801802
802803
.. versionadded:: 1.6
@@ -806,7 +807,7 @@ def _check_store_skims_in_shm(self):
806807
"""
807808
Whether to apply a bias of `log(sample_size)` to the Poisson sampling results.
808809
This is a temporary workaround to align Poisson sampling results with the biased
809-
results of the monte_carlo and eet sampling methods, such that models that were
810+
results of the inverse_cdf and eet sampling methods, such that models that were
810811
estimated with historical biased sampling results can be run with Poisson sampling
811812
without needing to re-estimate the model.
812813

activitysim/core/interaction_sample.py

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131

3232
DUMP = False
3333

34-
InteractionSampleMethod = typing.Literal["monte_carlo", "eet", "poisson"]
34+
InteractionSampleMethod = typing.Literal["inverse_cdf", "eet", "poisson"]
3535

3636
# Threshold on P0, the probability that a chooser's Poisson draw comes up empty, below
3737
# which the fallback term is dropped from the reported inclusion probabilities. Choosers
@@ -82,7 +82,7 @@ def resolve_sample_method(
8282
sampling_method = state.settings.sample_method
8383
if sampling_method is None:
8484
sampling_method = (
85-
"poisson" if state.settings.use_explicit_error_terms else "monte_carlo"
85+
"poisson" if state.settings.use_explicit_error_terms else "inverse_cdf"
8686
)
8787
if sampling_method not in typing.get_args(InteractionSampleMethod):
8888
raise ValueError(
@@ -170,7 +170,7 @@ def make_sample_choices_eet(
170170
171171
Each chooser receives `sample_size` EV1 draw sets and the argmax-over-utility
172172
winner is recorded per draw, so duplicates are possible (same with-replacement
173-
semantics as the Monte Carlo sampling path).
173+
semantics as the inverse-CDF sampling path).
174174
175175
`utilities` drives the Gumbel argmax. `probs` (the MNL choice probabilities
176176
computed from the same utilities by the caller) supplies the `prob` column
@@ -229,7 +229,7 @@ def make_sample_choices_poisson(
229229
230230
where `p_i` is the chooser's MNL choice probability for alternative `i`. That is the
231231
probability the alternative would have been drawn at least once across `sample_size`
232-
Monte Carlo draws, which is what makes Poisson sampling interchangeable with the other
232+
inverse-CDF draws, which is what makes Poisson sampling interchangeable with the other
233233
sampling methods. `pick_count` is 1 by definition (the draw is a yes/no per
234234
alternative), so the standard sampling correction factor is recoverable in the usual
235235
way as `np.log(df.pick_count / df.prob)`.
@@ -781,10 +781,10 @@ def _interaction_sample(
781781

782782
sampling_method = resolve_sample_method(state, compute_settings)
783783

784-
# Estimation requires MC sampling and MC choice for now
785-
if estimation.manager.enabled and sampling_method != "monte_carlo":
784+
# Estimation requires inverse-CDF sampling and choice for now
785+
if estimation.manager.enabled and sampling_method != "inverse_cdf":
786786
raise ValueError(
787-
f"{trace_label}: estimation requires monte_carlo sampling and choice. Set sample_method='monte_carlo'"
787+
f"{trace_label}: estimation requires inverse_cdf sampling and choice. Set sample_method='inverse_cdf'"
788788
+ " (or leave it unset) and use_explicit_error_terms=False for estimation runs."
789789
)
790790

@@ -835,7 +835,7 @@ def _interaction_sample(
835835
column_labels=["alternative", "probability"],
836836
)
837837

838-
if sampling_method == "monte_carlo":
838+
if sampling_method == "inverse_cdf":
839839
del utilities
840840
chunk_sizer.log_df(trace_label, "utilities", None)
841841

@@ -890,8 +890,8 @@ def _interaction_sample(
890890
del probs
891891
chunk_sizer.log_df(trace_label, "probs", None)
892892
else:
893-
# eet and poisson: optionally trim choosers with all-zero probs. The MC
894-
# path handles this inside make_sample_choices
893+
# eet and poisson: optionally trim choosers with all-zero probs. The
894+
# inverse-CDF path handles this inside make_sample_choices
895895
if allow_zero_probs:
896896
non_zero = probs.sum(axis=1) != 0
897897
if not non_zero.any():
@@ -1093,10 +1093,11 @@ def interaction_sample(
10931093
sampling_method = resolve_sample_method(state, compute_settings)
10941094
logger.debug(f" interaction_sample sample method = {sampling_method}")
10951095

1096-
if sampling_method == "monte_carlo":
1097-
# The MC sampling path (make_sample_choices) does not consume stable_alt_positions
1098-
# or n_total_alts. Null them out so callers that conservatively pass values along
1099-
# don't accidentally rely on them under MC sampling.
1096+
if sampling_method == "inverse_cdf":
1097+
# The inverse-CDF sampling path (make_sample_choices) does not consume
1098+
# stable_alt_positions or n_total_alts. Null them out so callers that
1099+
# conservatively pass values along don't accidentally rely on them under
1100+
# inverse-CDF sampling.
11001101
stable_alt_positions = None
11011102
n_total_alts = None
11021103

activitysim/core/interaction_sample_simulate.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -91,8 +91,7 @@ def _interaction_sample_simulate(
9191
9292
choices : pandas.Series
9393
A series where index should match the index of the choosers DataFrame
94-
and values will match the index of the alternatives DataFrame -
95-
choices are simulated in the standard Monte Carlo fashion
94+
and values will match the index of the alternatives DataFrame
9695
9796
if want_logsums is True:
9897
@@ -546,8 +545,7 @@ def interaction_sample_simulate(
546545
547546
choices : pandas.Series
548547
A series where index should match the index of the choosers DataFrame
549-
and values will match the index of the alternatives DataFrame -
550-
choices are simulated in the standard Monte Carlo fashion
548+
and values will match the index of the alternatives DataFrame
551549
552550
if want_logsums is True:
553551

activitysim/core/interaction_simulate.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -704,8 +704,7 @@ def _interaction_simulate(
704704
-------
705705
ret : pandas.Series
706706
A series where index should match the index of the choosers DataFrame
707-
and values will match the index of the alternatives DataFrame -
708-
choices are simulated in the standard Monte Carlo fashion
707+
and values will match the index of the alternatives DataFrame
709708
"""
710709

711710
trace_label = tracing.extend_trace_label(trace_label, "interaction_simulate")
@@ -1031,8 +1030,7 @@ def interaction_simulate(
10311030
-------
10321031
choices : pandas.Series
10331032
A series where index should match the index of the choosers DataFrame
1034-
and values will match the index of the alternatives DataFrame -
1035-
choices are simulated in the standard Monte Carlo fashion
1033+
and values will match the index of the alternatives DataFrame
10361034
"""
10371035

10381036
trace_label = tracing.extend_trace_label(trace_label, "interaction_simulate")

activitysim/core/logit.py

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -690,15 +690,6 @@ def make_choices_utility_based(
690690
rands : pandas.Series
691691
A series of 0s for compatibility with make_choices. For EET, we do not have per-row random numbers.
692692
693-
Notes
694-
-----
695-
An argmax always returns a position, so a chooser with no available alternative gets a
696-
choice here rather than an error: with every utility at `UTIL_UNAVAILABLE` the alternatives
697-
are tied and the error terms decide, and with every utility at `-inf` the first column wins.
698-
The Monte Carlo path does not go quiet in that situation -- `make_choices` reports it unless
699-
`allow_bad_probs` is set -- so this function reports it too. Most callers reach here having
700-
already run `validate_utils`, which makes the same check; the duplication is deliberate and
701-
mirrors `make_choices` re-checking what `utils_to_probs` has already looked at.
702693
"""
703694
trace_label = tracing.extend_trace_label(trace_label, "make_choices_utility_based")
704695

activitysim/core/test/test_interaction_sample.py

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ def state() -> workflow.State:
2323
def test_interaction_sample_ignores_stable_positions_without_global_eet(
2424
state, monkeypatch
2525
):
26-
# Do not support stable alt positions or tracking total alts when running with MC sampling
26+
# Do not support stable alt positions or tracking total alts when running with inverse-CDF sampling
2727
# to not introduce any additional changes while adding eet simulation support to ensure no
2828
# regressions. We can add these features later if desired.
2929
captured = {}
@@ -139,7 +139,7 @@ def test_interaction_sample_parity(state):
139139
index=pd.Index(["chooser_attr * alt_attr"], name="Expression"),
140140
)
141141

142-
# Run Monte Carlo with replacement.
142+
# Run inverse-CDF sampling with replacement.
143143
state.settings.use_explicit_error_terms = False
144144
state.rng().set_base_seed(42)
145145
state.rng().add_channel("person_id", choosers)
@@ -198,14 +198,14 @@ def test_interaction_sample_parity(state):
198198
assert choices_eet["alt_id"].isin(alternatives.index).all()
199199

200200
shares = {
201-
"monte_carlo": _weighted_shares(choices_mnl),
201+
"inverse_cdf": _weighted_shares(choices_mnl),
202202
"poisson": _weighted_shares(choices_poisson),
203203
"eet": _weighted_shares(choices_eet),
204204
}
205205

206206
for left, right in [
207-
("monte_carlo", "poisson"),
208-
("monte_carlo", "eet"),
207+
("inverse_cdf", "poisson"),
208+
("inverse_cdf", "eet"),
209209
("poisson", "eet"),
210210
]:
211211
all_alts = set(shares[left].index) | set(shares[right].index)
@@ -428,7 +428,7 @@ def _shares_for_sample(
428428
return choices, _weighted_shares(choices)
429429

430430

431-
def test_interaction_sample_eet_sampling_under_mc_simulation(state):
431+
def test_interaction_sample_eet_sampling_under_inverse_cdf_simulation(state):
432432
# use_eet=False + sample_method="eet" was silently ignored before the
433433
# sampling/simulation decoupling. The dispatch now keys on sampling_method
434434
# only, so this combo must produce shares that match use_eet=True + eet.
@@ -483,9 +483,9 @@ def test_interaction_sample_eet_sampling_under_mc_simulation(state):
483483
)
484484

485485

486-
def test_interaction_sample_poisson_sampling_under_mc_simulation(state):
487-
# use_eet=False + sample_method="poisson" used to silently fall through to MC
488-
# sampling and then have pick_count forced to 1, corrupting results. After
486+
def test_interaction_sample_poisson_sampling_under_inverse_cdf_simulation(state):
487+
# use_eet=False + sample_method="poisson" used to silently fall through to
488+
# inverse-CDF sampling and then have pick_count forced to 1, corrupting results. After
489489
# decoupling, the combo must run the Poisson path and match use_eet=True + poisson.
490490
num_choosers = 100_000
491491
num_alts = 100
@@ -530,7 +530,7 @@ def test_interaction_sample_poisson_sampling_under_mc_simulation(state):
530530

531531
# Poisson contract: pick_count must be uniformly 1
532532
assert (choices_mc_sim["pick_count"] == 1).all(), (
533-
"Poisson sampling under MC simulation must produce pick_count=1; got "
533+
"Poisson sampling under inverse-CDF simulation must produce pick_count=1; got "
534534
f"{choices_mc_sim['pick_count'].value_counts().to_dict()}"
535535
)
536536

@@ -544,7 +544,7 @@ def test_interaction_sample_poisson_sampling_under_mc_simulation(state):
544544
)
545545

546546

547-
def test_interaction_sample_mc_sampling_under_eet_simulation(state):
547+
def test_interaction_sample_inverse_cdf_sampling_under_eet_simulation(state):
548548
num_choosers = 100_000
549549
num_alts = 100
550550
sample_size = 10
@@ -570,7 +570,7 @@ def test_interaction_sample_mc_sampling_under_eet_simulation(state):
570570
spec,
571571
sample_size,
572572
use_eet=False,
573-
sample_method="monte_carlo",
573+
sample_method="inverse_cdf",
574574
seed=42,
575575
step_name="test_mc_under_mc_sim",
576576
)
@@ -581,7 +581,7 @@ def test_interaction_sample_mc_sampling_under_eet_simulation(state):
581581
spec,
582582
sample_size,
583583
use_eet=True,
584-
sample_method="monte_carlo",
584+
sample_method="inverse_cdf",
585585
seed=42,
586586
step_name="test_mc_under_eet_sim",
587587
)
@@ -590,7 +590,7 @@ def test_interaction_sample_mc_sampling_under_eet_simulation(state):
590590
for alt in all_alts:
591591
diff = abs(shares_mc_sim.get(alt, 0.0) - shares_eet_sim.get(alt, 0.0))
592592
assert diff < 0.01, (
593-
f"MC sampling shares should not depend on simulation mode at alt {alt}: "
593+
f"Inverse-CDF sampling shares should not depend on simulation mode at alt {alt}: "
594594
f"mc_sim={shares_mc_sim.get(alt, 0.0):.4f}, "
595595
f"eet_sim={shares_eet_sim.get(alt, 0.0):.4f}, diff={diff:.4f}"
596596
)

activitysim/core/test/test_logit.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -683,7 +683,7 @@ def test_make_choices_vs_eet_same_distribution():
683683

684684
utils = pd.DataFrame([utils_values] * n_draws, columns=columns)
685685

686-
# Probability-based (Monte Carlo) path — independent RNG
686+
# Probability-based (inverse-CDF) path — independent RNG
687687
mc_rng = np.random.default_rng(42)
688688

689689
class MCDummyRNG:

0 commit comments

Comments
 (0)