Submodules

voiage.methods.adaptive module

Value of information helpers for adaptive trial designs.

The main entry point is adaptive_evsi, which estimates the value of sample information under user-supplied adaptive trial rules.

voiage.methods.adaptive.sophisticated_adaptive_trial_simulator(psa_samples: ParameterSet, base_design: TrialDesign, adaptive_rules: dict[str, object]) ValueArray[source]

Simulate an adaptive trial and return net-benefit samples.

Parameters:
  • psa_samples (ParameterSet) – PSA samples representing parameter uncertainty.

  • base_design (TrialDesign) – Trial design before adaptive modifications.

  • adaptive_rules (dict[str, object]) – Rules describing interim analyses and early stopping behavior.

Returns:

Net-benefit samples for the decision alternatives generated by the simulated adaptive trial.

Return type:

ValueArray

Notes

This helper is intentionally simplified and deterministic enough for testing and examples, not for production trial simulation.

voiage.methods.adaptive.bayesian_adaptive_trial_simulator(psa_samples: ParameterSet, base_design: TrialDesign, adaptive_rules: dict[str, object], true_parameters: dict[str, float] | None = None) ValueArray[source]

Simulate a Bayesian adaptive trial with belief updating.

Parameters:
  • psa_samples (ParameterSet) – PSA samples representing parameter uncertainty.

  • base_design (TrialDesign) – Trial design before adaptive modifications.

  • adaptive_rules (dict[str, object]) – Rules describing interim analyses and early stopping behavior.

  • true_parameters (dict[str, float], optional) – Optional true parameter values used to generate the simulated trial.

Returns:

Net-benefit samples after Bayesian updating.

Return type:

ValueArray

Notes

The implementation is a testing-oriented approximation of a Bayesian adaptive design rather than a fully general trial simulator.

voiage.methods.adaptive.adaptive_evsi(adaptive_trial_simulator: Callable[[ParameterSet, TrialDesign, dict[str, Any]], ValueArray], psa_prior: ParameterSet, base_trial_design: TrialDesign, adaptive_rules: dict[str, object], population: float | None = None, discount_rate: float | None = None, time_horizon: float | None = None, n_outer_loops: int = 10, n_inner_loops: int = 50, **kwargs: object) float[source]

Calculate expected value of sample information for an adaptive trial.

Parameters:
  • adaptive_trial_simulator (callable) – Simulator that produces net-benefit samples for an adaptive design.

  • psa_prior (ParameterSet) – Prior PSA sample representing current uncertainty.

  • base_trial_design (TrialDesign) – Initial trial design before adaptation.

  • adaptive_rules (dict[str, object]) – Adaptive rules such as interim timings and stopping criteria.

  • population (float, optional) – Population size for population scaling.

  • discount_rate (float, optional) – Annual discount rate used for population scaling.

  • time_horizon (float, optional) – Time horizon in years for population scaling.

  • n_outer_loops (int, default=10) – Number of outer Monte Carlo draws.

  • n_inner_loops (int, default=50) – Number of inner Monte Carlo draws.

  • **kwargs (object) – Additional simulator-specific arguments.

Returns:

Adaptive EVSI on a per-decision basis unless population scaling is requested.

Return type:

float

voiage.methods.basic module

Implementation of basic Value of Information methods.

  • EVPI (Expected Value of Perfect Information)

  • EVPPI (Expected Value of Partial Perfect Information)

voiage.methods.basic.check_parameter_samples(parameter_samples: object, n_samples: int) ndarray[source]

Validate and normalize parameter samples for EVPPI.

Parameters:
  • parameter_samples (object) – Parameter samples supplied as a NumPy array, a PSASample, or a mapping from parameter names to arrays.

  • n_samples (int) – Expected sample count from the associated net-benefit array.

Returns:

A 2D array with shape (n_samples, n_parameters).

Return type:

numpy.ndarray

Raises:

InputError – If the input type is unsupported or the sample counts do not match.

Notes

This helper is intentionally strict: EVPPI requires aligned PSA samples so the parameter matrix and net-benefit matrix can be paired sample by sample.

voiage.methods.basic.evpi(nb_array: ndarray | ValueArray, population: float | None = None, time_horizon: float | None = None, discount_rate: float | None = None) float[source]

Calculate expected value of perfect information.

Parameters:
  • nb_array (numpy.ndarray or ValueArray) – Net-benefit samples with shape (n_samples, n_strategies).

  • population (float, optional) – Population size for population-scaled EVPI.

  • time_horizon (float, optional) – Time horizon in years for population scaling.

  • discount_rate (float, optional) – Annual discount rate used for population scaling.

Returns:

EVPI on a per-decision basis unless population scaling is requested.

Return type:

float

Notes

EVPI is the gap between the expected value of the strategy that would be chosen with perfect information and the value of the strategy chosen under current information:

\[\mathrm{EVPI} = E\left[\max_i NB_i(\theta)\right] - \max_i E[NB_i(\theta)].\]

References

Briggs, A. H., Claxton, K., & Sculpher, M. J. (2006). Decision Modelling for Health Economic Evaluation. Oxford University Press. Claxton, K. (1999). The irrelevance of inference: A decision-making approach to the stochastic evaluation of health care technologies.

Examples

>>> import numpy as np
>>> from voiage.methods.basic import evpi
>>> nb = np.array([[10.0, 12.0], [11.0, 9.0], [13.0, 14.0]])
>>> round(evpi(nb), 6)
0.666667
voiage.methods.basic.evppi(nb_array: ndarray | ValueArray, parameter_samples: ndarray | ParameterSet | dict[str, ndarray], parameters_of_interest: list[str], population: float | None = None, time_horizon: float | None = None, discount_rate: float | None = None, n_regression_samples: int | None = None, chunk_size: int | None = None, regression_model: RegressionModelProtocol | type[RegressionModelProtocol] | None = None) float[source]

Calculate expected value of partial perfect information.

Parameters:
  • nb_array (numpy.ndarray or ValueArray) – Net-benefit samples with shape (n_samples, n_strategies).

  • parameter_samples (numpy.ndarray, PSASample, or dict[str, numpy.ndarray]) – PSA parameter samples aligned to nb_array.

  • parameters_of_interest (list[str]) – Parameter names to retain for the EVPPI calculation.

  • population (float, optional) – Population size for population-scaled EVPPI.

  • time_horizon (float, optional) – Time horizon in years for population scaling.

  • discount_rate (float, optional) – Annual discount rate used for population scaling.

  • n_regression_samples (int, optional) – Number of samples to use in the regression approximation.

  • chunk_size (int, optional) – Optional batch size for chunked evaluation.

  • regression_model (RegressionModelProtocol or type, optional) – Optional regression model used by the analysis layer.

Returns:

EVPPI on a per-decision basis unless population scaling is requested.

Return type:

float

Notes

EVPPI measures the gain from resolving a subset of uncertain parameters while leaving the remainder uncertain:

\[\mathrm{EVPPI}(x) = E_x\left[\max_d E[NB_d \mid x]\right] - \max_d E[NB_d].\]

The implementation delegates approximation details to DecisionAnalysis, so the precise estimator can vary with the chosen regression model or sample controls.

References

Strong, M., Oakley, J. E., & Brennan, A. (2014). Estimating multiparameter partial expected value of perfect information from the posterior distribution. Medical Decision Making, 34(3), 314-326. Ades, A. E., Lu, G., & Claxton, K. (2004). Expected value of sample information calculations in medical decision modeling.

Examples

>>> import numpy as np
>>> from voiage.methods.basic import evppi
>>> from voiage.schema import ParameterSet
>>> nb = np.array([[10.0, 12.0], [11.0, 9.0], [13.0, 14.0]])
>>> params = ParameterSet.from_numpy_or_dict({
...     "effect": np.array([0.1, 0.2, 0.3]),
...     "cost": np.array([1.0, 1.1, 0.9]),
... })
>>> round(evppi(nb, params, ["effect"]), 6) >= 0.0
True

voiage.methods.calibration module

Value of information helpers for model calibration studies.

The main entry point is voi_calibration, which estimates the value of collecting calibration data under user-supplied study and process models.

voiage.methods.calibration.voi_calibration(cal_study_modeler: Callable[[ParameterSet, dict[str, object], dict[str, object]], ValueArray] | None = None, psa_prior: ParameterSet | None = None, calibration_study_design: dict[str, object] | None = None, calibration_process_spec: dict[str, object] | None = None, population: float | None = None, discount_rate: float | None = None, time_horizon: float | None = None, n_outer_loops: int = 20, **kwargs: object) float[source]

Calculate the value of information for a calibration study.

Parameters:
  • cal_study_modeler (callable, optional) – Modeler that maps PSA samples and calibration assumptions to net-benefit samples.

  • psa_prior (ParameterSet) – Prior PSA samples representing current uncertainty.

  • calibration_study_design (dict[str, object]) – Calibration study design specification.

  • calibration_process_spec (dict[str, object]) – Calibration process specification.

  • population (float, optional) – Population size for population scaling.

  • discount_rate (float, optional) – Annual discount rate used for population scaling.

  • time_horizon (float, optional) – Time horizon in years for population scaling.

  • n_outer_loops (int, default=20) – Number of outer Monte Carlo draws.

  • **kwargs (object) – Additional modeler-specific options.

Returns:

Calibration VOI on a per-decision basis unless population scaling is requested.

Return type:

float

Notes

If no modeler is supplied, the built-in calibration modeler is used.

voiage.methods.calibration.sophisticated_calibration_modeler(psa_samples: ParameterSet, study_design: dict[str, object], process_spec: dict[str, object]) ValueArray[source]

Run the built-in calibration study modeler.

Parameters:
  • psa_samples (ParameterSet) – Prior parameter samples.

  • study_design (dict[str, object]) – Calibration study design specification.

  • process_spec (dict[str, object]) – Calibration process specification.

Returns:

Net-benefit samples for the strategies under the calibrated model.

Return type:

ValueArray

Notes

The built-in modeler is a testing-oriented approximation that simulates the effect of calibration by shrinking uncertainty toward target values.

voiage.methods.ceaf module

Cost-effectiveness acceptability frontier calculations.

class voiage.methods.ceaf.CEAFResult(wtp_thresholds: ndarray, optimal_strategy_indices: ndarray, optimal_strategy_names: list[str], acceptability_probabilities: ndarray, probability_lower: ndarray, probability_upper: ndarray, expected_net_benefit: ndarray, reporting: dict[str, object])[source]

Bases: object

Container for a cost-effectiveness acceptability frontier result.

wtp_thresholds

Willingness-to-pay thresholds used for the frontier.

Type:

numpy.ndarray

optimal_strategy_indices

Index of the expected-optimal strategy at each threshold.

Type:

numpy.ndarray

optimal_strategy_names

Names of the expected-optimal strategies.

Type:

list[str]

acceptability_probabilities

Probability that the expected-optimal strategy is cost-effective.

Type:

numpy.ndarray

probability_lower

Lower uncertainty band for the acceptability probability.

Type:

numpy.ndarray

probability_upper

Upper uncertainty band for the acceptability probability.

Type:

numpy.ndarray

expected_net_benefit

Expected net benefit of the selected strategy at each threshold.

Type:

numpy.ndarray

wtp_thresholds: ndarray
optimal_strategy_indices: ndarray
optimal_strategy_names: list[str]
acceptability_probabilities: ndarray
probability_lower: ndarray
probability_upper: ndarray
expected_net_benefit: ndarray
reporting: dict[str, object]
voiage.methods.ceaf.calculate_ceaf(value_array: ValueArray, wtp_thresholds: ndarray | list[float], strategy_names: list[str] | None = None, confidence_level: float = 0.95) CEAFResult[source]

Calculate a cost-effectiveness acceptability frontier.

Parameters:
  • value_array (ValueArray) – 3D net-benefit surface with samples, strategies, and WTP thresholds.

  • wtp_thresholds (numpy.ndarray or list[float]) – Willingness-to-pay thresholds used for the frontier.

  • strategy_names (list[str], optional) – Override strategy names.

  • confidence_level (float, default=0.95) – Confidence level used to build the probability band.

Returns:

Frontier result with optimal strategies, probabilities, and uncertainty bounds.

Return type:

CEAFResult

Notes

At each willingness-to-pay threshold \(\lambda\), CEAF selects the strategy with the largest expected net benefit:

\[d^*(\lambda) = \arg\max_d E[NB_d(\lambda)].\]

The acceptability probability is the fraction of PSA samples for which the selected strategy is also optimal under the sample-level net benefits.

References

Fenwick, E., Claxton, K., & Sculpher, M. (2001). Representing uncertainty: the cost-effectiveness acceptability curve, the cost-effectiveness acceptability frontier, and the expected value of sample information. Briggs, A. H., O’Brien, B. J., & Blackhouse, G. (2002). Thinking outside the box: CEAF as a decision summary.

Examples

>>> import numpy as np
>>> from voiage.methods.ceaf import calculate_ceaf
>>> from voiage.schema import ValueArray
>>> values = np.array(
...     [
...         [[10.0, 11.0], [12.0, 9.0]],
...         [[9.0, 10.5], [11.0, 10.0]],
...     ]
... )
>>> va = ValueArray.from_numpy_perspectives(
...     values,
...     strategy_names=["A", "B"],
...     perspective_names=["10000", "20000"],
... )
>>> result = calculate_ceaf(va, [10000.0, 20000.0])
>>> result.wtp_thresholds.tolist()
[10000.0, 20000.0]

voiage.methods.dominance module

Dominance and ICER analysis for cost-effectiveness results.

class voiage.methods.dominance.DominanceResult(strategy_names: list[str], costs: ndarray, effects: ndarray, frontier_indices: list[int], strongly_dominated_indices: list[int], extended_dominated_indices: list[int], status: list[str], incremental_costs: ndarray, incremental_effects: ndarray, icers: ndarray, reporting: dict[str, object])[source]

Bases: object

Structured dominance-analysis result.

strategy_names

Strategy labels in the original input order.

Type:

list[str]

costs

Strategy costs.

Type:

numpy.ndarray

effects

Strategy effects.

Type:

numpy.ndarray

frontier_indices

Indices on the cost-effectiveness frontier.

Type:

list[int]

strongly_dominated_indices

Indices removed by strong dominance.

Type:

list[int]

extended_dominated_indices

Indices removed by extended dominance.

Type:

list[int]

status

Per-strategy status labels.

Type:

list[str]

incremental_costs

Incremental costs between frontier strategies.

Type:

numpy.ndarray

incremental_effects

Incremental effects between frontier strategies.

Type:

numpy.ndarray

icers

Incremental cost-effectiveness ratios along the frontier.

Type:

numpy.ndarray

Examples

>>> import numpy as np
>>> from voiage.methods.dominance import calculate_dominance
>>> result = calculate_dominance(np.array([10, 12]), np.array([1.0, 1.2]))
>>> result.frontier_indices
[0, 1]
strategy_names: list[str]
costs: ndarray
effects: ndarray
frontier_indices: list[int]
strongly_dominated_indices: list[int]
extended_dominated_indices: list[int]
status: list[str]
incremental_costs: ndarray
incremental_effects: ndarray
icers: ndarray
reporting: dict[str, object]
voiage.methods.dominance.calculate_dominance(costs: ndarray | list[float], effects: ndarray | list[float], strategy_names: list[str] | None = None) DominanceResult[source]

Identify dominance classes and frontier ICERs.

Parameters:
Returns:

Dominance classification with frontier indices and ICERs.

Return type:

DominanceResult

Notes

Strong dominance removes any strategy that is at least as costly and no more effective than another strategy, with one dimension strictly worse. Extended dominance removes frontier strategies whose incremental cost-effectiveness ratios are not strictly increasing along the frontier.

References

Drummond, M. F., Sculpher, M. J., Claxton, K., Stoddart, G. L., & Torrance, G. W. (2015). Methods for the Economic Evaluation of Health Care Programmes. Briggs, A. H., Claxton, K., & Sculpher, M. J. (2006). Decision Modelling for Health Economic Evaluation.

Examples

>>> import numpy as np
>>> from voiage.methods.dominance import calculate_dominance
>>> result = calculate_dominance(
...     costs=np.array([10.0, 12.0, 13.0]),
...     effects=np.array([1.0, 1.1, 1.3]),
...     strategy_names=["A", "B", "C"],
... )
>>> result.frontier_indices
[0, 1, 2]
voiage.methods.dominance.calculate_strong_dominance(costs: ndarray | list[float], effects: ndarray | list[float]) list[int][source]

Return indices of strongly dominated strategies.

Parameters:
Returns:

Indices of strategies that are more costly and no more effective than at least one alternative.

Return type:

list[int]

Notes

A strategy is strongly dominated if another strategy has cost less than or equal to it and effect greater than or equal to it, with at least one strict inequality.

Examples

>>> import numpy as np
>>> from voiage.methods.dominance import calculate_strong_dominance
>>> calculate_strong_dominance(np.array([10.0, 12.0]), np.array([1.0, 0.9]))
[1]
voiage.methods.dominance.cost_effectiveness_frontier(costs: ndarray | list[float], effects: ndarray | list[float]) list[int][source]

Return strategy indices on the cost-effectiveness frontier.

Parameters:
Returns:

Ordered frontier indices after removing strongly dominated strategies.

Return type:

list[int]

Notes

The frontier is the ordered subset of non-dominated strategies with strictly increasing effect and strictly improving ICERs after the extended-dominance pruning pass.

Examples

>>> import numpy as np
>>> from voiage.methods.dominance import cost_effectiveness_frontier
>>> cost_effectiveness_frontier(np.array([10.0, 12.0, 13.0]), np.array([1.0, 1.1, 1.3]))
[0, 1, 2]
voiage.methods.dominance.calculate_extended_dominance(costs: ndarray | list[float], effects: ndarray | list[float]) list[int][source]

Return indices removed from the frontier by extended dominance.

Parameters:
Returns:

Indices that are neither strongly dominated nor on the frontier.

Return type:

list[int]

Notes

Extended dominance removes strategies that fall below the linear segment between two frontier strategies and therefore cannot be optimal at any willingness-to-pay threshold.

Examples

>>> import numpy as np
>>> from voiage.methods.dominance import calculate_extended_dominance
>>> calculate_extended_dominance(np.array([10.0, 11.0, 13.0]), np.array([1.0, 1.2, 1.3]))
[]
voiage.methods.dominance.calculate_icers(costs: ndarray | list[float], effects: ndarray | list[float], frontier_indices: list[int] | None = None) tuple[ndarray, ndarray, ndarray][source]

Calculate incremental costs, effects, and ICERs along the frontier.

Parameters:
Returns:

Incremental costs, incremental effects, and ICERs.

Return type:

tuple of numpy.ndarray

Notes

For adjacent frontier strategies \(i-1\) and \(i\), the ICER is

\[\mathrm{ICER}_i = \frac{C_i - C_{i-1}}{E_i - E_{i-1}}.\]

Examples

>>> import numpy as np
>>> from voiage.methods.dominance import calculate_icers
>>> inc_costs, inc_effects, icers = calculate_icers(
...     np.array([10.0, 12.0, 13.0]),
...     np.array([1.0, 1.1, 1.3]),
... )
>>> inc_costs.tolist()
[2.0, 1.0]

voiage.methods.distributional module

Distributional and equity-weighted VOI calculations.

class voiage.methods.distributional.DistributionalEquityResult(value: float, subgroup_labels: list[str], subgroup_weights: ndarray, equity_weights: ndarray, subgroup_optimal_strategy_indices: ndarray, subgroup_optimal_strategy_names: list[str], subgroup_expected_net_benefits: ndarray, equity_weighted_expected_net_benefits: ndarray, overall_optimal_strategy_index: int, overall_optimal_strategy_name: str, social_welfare_optimal_strategy_index: int, social_welfare_optimal_strategy_name: str, social_welfare_value: float, method_maturity: str, diagnostics: dict[str, object], reporting: dict[str, object])[source]

Bases: object

Structured distributional and equity-weighted VOI result.

value: float
subgroup_labels: list[str]
subgroup_weights: ndarray
equity_weights: ndarray
subgroup_optimal_strategy_indices: ndarray
subgroup_optimal_strategy_names: list[str]
subgroup_expected_net_benefits: ndarray
equity_weighted_expected_net_benefits: ndarray
overall_optimal_strategy_index: int
overall_optimal_strategy_name: str
social_welfare_optimal_strategy_index: int
social_welfare_optimal_strategy_name: str
social_welfare_value: float
method_maturity: str
diagnostics: dict[str, object]
reporting: dict[str, object]
voiage.methods.distributional.value_of_distributional_equity(value_array: ValueArray, subgroups: ndarray | list[Any], strategy_names: list[str] | None = None, equity_weights: ndarray | list[float] | dict[str, float] | None = None, n_bins: int | None = None) DistributionalEquityResult[source]

Calculate distributional and equity-weighted value of heterogeneity.

Parameters:
  • value_array (ValueArray) – 2D net-benefit samples with shape (n_samples, n_strategies).

  • subgroups (numpy.ndarray or list[Any]) – Subgroup label for each sample.

  • strategy_names (list[str], optional) – Optional strategy labels.

  • equity_weights (sequence or mapping, optional) – Non-negative subgroup weights used for social-welfare summaries.

  • n_bins (int, optional) – Number of quantile bins to use when subgroups is numeric.

Returns:

Result containing subgroup-specific and equity-weighted summaries.

Return type:

DistributionalEquityResult

Notes

The subgroup-tailored value is computed from subgroup-specific optimal expected net benefits and compared with the single overall optimal strategy. Equity-weighted welfare is the weighted sum of subgroup mean net benefits:

\[W_d = \sum_g w_g E[NB_{d,g}], \qquad \mathrm{VOH}_{eq} = \max\left(0,\sum_g p_g \max_d E[NB_{d,g}] - \max_d E[NB_d]\right).\]

References

Cookson, R., Griffin, S., Norheim, O. F., & Culyer, A. J. (2021). Distributional cost-effectiveness analysis: Quantifying health equity impacts and trade-offs. Asaria, M., Griffin, S., & Cookson, R. (2016). Distributional cost effectiveness analysis: a tutorial.

Examples

>>> import numpy as np
>>> from voiage.methods.distributional import value_of_distributional_equity
>>> from voiage.schema import ValueArray
>>> values = np.array([
...     [10.0, 8.0],
...     [11.0, 7.0],
...     [6.0, 12.0],
...     [5.0, 13.0],
... ])
>>> result = value_of_distributional_equity(
...     ValueArray.from_numpy(values, ["A", "B"]),
...     subgroups=["low", "low", "high", "high"],
... )
>>> result.social_welfare_value >= 0.0
True

voiage.methods.heterogeneity module

Value of Heterogeneity calculations.

class voiage.methods.heterogeneity.HeterogeneityResult(value: float, subgroup_labels: list[str], subgroup_weights: ndarray, subgroup_optimal_strategy_indices: ndarray, subgroup_optimal_strategy_names: list[str], subgroup_expected_net_benefits: ndarray, overall_optimal_strategy_index: int, overall_optimal_strategy_name: str, overall_expected_net_benefit: float, reporting: dict[str, object])[source]

Bases: object

Structured Value of Heterogeneity result.

value

Value of tailoring decisions to subgroups.

Type:

float

subgroup_labels

Unique subgroup labels in analysis order.

Type:

list[str]

subgroup_weights

Population weight for each subgroup.

Type:

numpy.ndarray

subgroup_optimal_strategy_indices

Optimal strategy index per subgroup.

Type:

numpy.ndarray

subgroup_optimal_strategy_names

Optimal strategy name per subgroup.

Type:

list[str]

subgroup_expected_net_benefits

Expected net benefit of the subgroup-optimal strategy.

Type:

numpy.ndarray

overall_optimal_strategy_index

Optimal strategy index if a single decision is used for everyone.

Type:

int

overall_optimal_strategy_name

Name of the overall-optimal strategy.

Type:

str

overall_expected_net_benefit

Expected net benefit of the overall-optimal strategy.

Type:

float

value: float
subgroup_labels: list[str]
subgroup_weights: ndarray
subgroup_optimal_strategy_indices: ndarray
subgroup_optimal_strategy_names: list[str]
subgroup_expected_net_benefits: ndarray
overall_optimal_strategy_index: int
overall_optimal_strategy_name: str
overall_expected_net_benefit: float
reporting: dict[str, object]
voiage.methods.heterogeneity.value_of_heterogeneity(value_array: ValueArray, subgroups: ndarray | list[Any], strategy_names: list[str] | None = None, n_bins: int | None = None) HeterogeneityResult[source]

Calculate the value of tailoring decisions to subgroups.

Parameters:
  • value_array (ValueArray) – 2D net-benefit samples with shape (n_samples, n_strategies).

  • subgroups (numpy.ndarray or list[Any]) – Subgroup label for each sample.

  • strategy_names (list[str], optional) – Optional strategy labels.

  • n_bins (int, optional) – Number of quantile bins to use when subgroups is numeric.

Returns:

Result containing subgroup-specific and overall expected net benefits.

Return type:

HeterogeneityResult

Notes

The reported value is the gain from allowing different optimal strategies in different subgroups rather than applying one strategy to everyone:

\[\mathrm{VOH} = \max\left(0,\sum_g w_g \max_d E[NB_{d,g}] - \max_d E[NB_d]\right).\]

References

Fenwick, E., Claxton, K., & Sculpher, M. (2001). Representing uncertainty: the cost-effectiveness acceptability curve, the cost-effectiveness acceptability frontier, and the value of heterogeneity. O’Cathain, A., et al. (2021). Equity and subgroup value in economic evaluation.

Examples

>>> import numpy as np
>>> from voiage.methods.heterogeneity import value_of_heterogeneity
>>> from voiage.schema import ValueArray
>>> values = np.array([
...     [10.0, 8.0],
...     [11.0, 7.0],
...     [6.0, 12.0],
...     [5.0, 13.0],
... ])
>>> result = value_of_heterogeneity(
...     ValueArray.from_numpy(values, ["A", "B"]),
...     subgroups=["low", "low", "high", "high"],
... )
>>> result.value >= 0.0
True
voiage.methods.heterogeneity.identify_optimal_subgroups(result: HeterogeneityResult) dict[str, str][source]

Return the optimal strategy name for each subgroup.

Parameters:

result (HeterogeneityResult) – Result produced by value_of_heterogeneity().

Returns:

Mapping from subgroup label to subgroup-optimal strategy name.

Return type:

dict[str, str]

Examples

>>> import numpy as np
>>> from voiage.methods.heterogeneity import identify_optimal_subgroups, value_of_heterogeneity
>>> from voiage.schema import ValueArray
>>> result = value_of_heterogeneity(
...     ValueArray.from_numpy(np.array([[10.0, 8.0], [6.0, 12.0]]), ["A", "B"]),
...     subgroups=["low", "high"],
... )
>>> identify_optimal_subgroups(result)
{'high': 'B', 'low': 'A'}

voiage.methods.implementation module

Implementation-adjusted VOI calculations.

class voiage.methods.implementation.ImplementationAdjustedResult(value: float, baseline_expected_net_benefits: ndarray, baseline_optimal_strategy_index: int, baseline_optimal_strategy_name: str, adjusted_expected_net_benefits: ndarray, adjusted_optimal_strategy_index: int, adjusted_optimal_strategy_name: str, implementation_multiplier: float, uptake: float, adherence: float, coverage: float, implementation_delay: float, implementation_uncertainty: float, discount_rate: float, time_horizon: float | None, population: float | None, method_maturity: str, diagnostics: dict[str, object], reporting: dict[str, object])[source]

Bases: object

Structured implementation-adjusted VOI result.

value: float
baseline_expected_net_benefits: ndarray
baseline_optimal_strategy_index: int
baseline_optimal_strategy_name: str
adjusted_expected_net_benefits: ndarray
adjusted_optimal_strategy_index: int
adjusted_optimal_strategy_name: str
implementation_multiplier: float
uptake: float
adherence: float
coverage: float
implementation_delay: float
implementation_uncertainty: float
discount_rate: float
time_horizon: float | None
population: float | None
method_maturity: str
diagnostics: dict[str, object]
reporting: dict[str, object]
voiage.methods.implementation.value_of_implementation(value_array: ValueArray, uptake: float = 1.0, adherence: float = 1.0, coverage: float = 1.0, implementation_delay: float = 0.0, implementation_uncertainty: float = 0.0, discount_rate: float = 0.0, time_horizon: float | None = None, population: float | None = None, strategy_names: list[str] | None = None) ImplementationAdjustedResult[source]

Calculate the value of implementation-adjusted adoption.

Parameters:
  • value_array (ValueArray) – 2D net-benefit samples with shape (n_samples, n_strategies).

  • uptake (float, default=1.0) – Implementation fraction inputs in the range [0, 1].

  • adherence (float, default=1.0) – Implementation fraction inputs in the range [0, 1].

  • coverage (float, default=1.0) – Implementation fraction inputs in the range [0, 1].

  • implementation_delay (float, default=0.0) – Delay before the intervention is implemented, in years.

  • implementation_uncertainty (float, default=0.0) – Additional uncertainty penalty in the range [0, 1].

  • discount_rate (float, default=0.0) – Annual discount rate used to discount delayed implementation.

  • time_horizon (float, optional) – Optional time horizon for reporting and future scaling.

  • population (float, optional) – Optional population size for population-adjusted reporting.

  • strategy_names (list[str], optional) – Optional strategy labels.

Returns:

Baseline and implementation-adjusted summaries.

Return type:

ImplementationAdjustedResult

Notes

The implementation multiplier combines uptake, adherence, coverage, uncertainty, and delay:

\[m = u \times a \times c \times (1 - \delta) \times (1 + r)^{-t}.\]

The reported value is the non-negative difference between the baseline optimal expected net benefit and the adjusted optimal expected net benefit, optionally scaled by population and the discounted time horizon.

References

Claxton, K., Sculpher, M., & Palmer, S. (2011). Considerations for modelling implementation and uptake in economic evaluation. Phelps, C., & Mushlin, A. (1991). Focusing technology assessment using medical decision analysis.

Examples

>>> import numpy as np
>>> from voiage.methods.implementation import value_of_implementation
>>> from voiage.schema import ValueArray
>>> values = np.array([[10.0, 12.0], [11.0, 11.5]])
>>> result = value_of_implementation(ValueArray.from_numpy(values, ["A", "B"]))
>>> result.value >= 0.0
True

voiage.methods.network_nma module

Value of information methods for network meta-analysis models.

The main entry point is evsi_nma, which estimates EVSI for a proposed study added to a treatment network.

voiage.methods.network_nma.evsi_nma(nma_model_evaluator: Callable[[ParameterSet, TrialDesign | None, object | None], ValueArray], psa_prior_nma: ParameterSet, trial_design_new_study: TrialDesign, population: float | None = None, discount_rate: float | None = None, time_horizon: float | None = None, n_outer_loops: int = 20, n_inner_loops: int = 100, **kwargs: object) float[source]

Calculate EVSI for a proposed study in a network meta-analysis.

Parameters:
  • nma_model_evaluator (callable) – Model evaluator that maps PSA samples to net-benefit samples.

  • psa_prior_nma (ParameterSet) – Prior PSA samples for the NMA and economic model.

  • trial_design_new_study (TrialDesign) – Design of the new study to add to the network.

  • population (float, optional) – Population size for population scaling.

  • discount_rate (float, optional) – Annual discount rate used for population scaling.

  • time_horizon (float, optional) – Time horizon in years for population scaling.

  • n_outer_loops (int, default=20) – Number of outer Monte Carlo draws.

  • n_inner_loops (int, default=100) – Number of inner Monte Carlo draws.

  • **kwargs (object) – Additional model-evaluation options.

Returns:

EVSI on a per-decision basis unless population scaling is requested.

Return type:

float

voiage.methods.network_nma.sophisticated_nma_model_evaluator(psa_samples: ParameterSet, trial_design: TrialDesign | None = None, trial_data: dict[str, ndarray] | None = None) ValueArray[source]

Evaluate the NMA model and return net benefits.

Parameters:
  • psa_samples (ParameterSet) – PSA samples for the network model.

  • trial_design (TrialDesign, optional) – Optional trial design for the study.

  • trial_data (dict[str, numpy.ndarray], optional) – Optional simulated trial data.

Returns:

Net-benefit samples for the modeled strategies.

Return type:

ValueArray

voiage.methods.network_nma.calculate_nma_consistency(treatment_effects: ndarray, study_designs: list[list[int]]) float[source]

Calculate a simple consistency measure for NMA.

Parameters:
  • treatment_effects (numpy.ndarray) – Treatment-effect estimates.

  • study_designs (list[list[int]]) – Study designs describing which treatments were compared.

Returns:

A simple variance-based consistency score.

Return type:

float

voiage.methods.network_nma.simulate_nma_network_data(n_treatments: int, n_studies: int, baseline_effect: float = 0.0, heterogeneity: float = 0.1) tuple[ndarray, ndarray, list[list[int]]][source]

Simulate synthetic network meta-analysis data.

Parameters:
  • n_treatments (int) – Number of treatments in the network.

  • n_studies (int) – Number of studies to simulate.

  • baseline_effect (float, default=0.0) – Mean treatment effect around which studies are generated.

  • heterogeneity (float, default=0.1) – Standard deviation of the simulated treatment effects.

Returns:

Simulated treatment effects, standard errors, and study designs.

Return type:

tuple

voiage.methods.observational module

Value of information methods for observational study designs.

voiage.methods.observational.basic_observational_study_modeler(psa_prior: ParameterSet, observational_study_design: dict[str, object], bias_models: dict[str, object]) ValueArray[source]

Model a simple observational study update for explicit net benefits.

Parameters:
  • psa_prior (ParameterSet) – Prior parameter samples.

  • observational_study_design (dict[str, object]) – Study design specification, including optional sample size and truth.

  • bias_models (dict[str, object]) – Bias-model specification used to adjust residual uncertainty.

Returns:

Net-benefit samples after observational updating.

Return type:

ValueArray

Notes

The built-in modeler accepts explicit strategy net-benefit arrays or matched cost/effect arrays and shrinks uncertainty toward the sampled truth.

voiage.methods.observational.voi_observational(obs_study_modeler: Callable[[ParameterSet, dict[str, object], dict[str, object]], ValueArray] | None = None, psa_prior: ParameterSet | None = None, observational_study_design: dict[str, object] | None = None, bias_models: dict[str, object] | None = None, population: float | None = None, discount_rate: float | None = None, time_horizon: float | None = None, n_outer_loops: int = 20, **kwargs: object) float[source]

Calculate the value of information for an observational study.

Parameters:
  • obs_study_modeler (callable, optional) – Modeler that maps PSA samples and study assumptions to net-benefit samples.

  • psa_prior (ParameterSet) – Prior PSA samples representing current uncertainty.

  • observational_study_design (dict[str, object]) – Study design specification.

  • bias_models (dict[str, object]) – Bias-model specification.

  • population (float, optional) – Population size for population scaling.

  • discount_rate (float, optional) – Annual discount rate used for population scaling.

  • time_horizon (float, optional) – Time horizon in years for population scaling.

  • n_outer_loops (int, default=20) – Number of outer Monte Carlo draws.

  • **kwargs (object) – Additional modeler-specific options.

Returns:

Observational VOI on a per-decision basis unless population scaling is requested.

Return type:

float

voiage.methods.perspective module

Value of Perspective analysis.

This module treats decision perspective as an explicit analysis dimension. It compares the same strategies under multiple stakeholder or policy objective functions and reports the regret from applying one perspective’s decision rule under another perspective.

class voiage.methods.perspective.Perspective(id: str, label: str | None = None, cost_categories: tuple[str, ...] = (), effect_measures: tuple[str, ...] = (), utility_weights: ~collections.abc.Mapping[str, float] = <factory>, equity_weights: ~collections.abc.Mapping[str, float] = <factory>, willingness_to_pay: float | None = None, discount_rate: float | None = None, population: float | None = None, stakeholder_metadata: ~collections.abc.Mapping[str, object] = <factory>)[source]

Bases: object

Metadata for one decision-analysis perspective.

Parameters:
  • id (str) – Stable machine-readable perspective identifier.

  • label (str, optional) – Human-readable label. Defaults to id when omitted.

  • cost_categories (tuple[str, ...], default=()) – Cost categories included in the perspective.

  • effect_measures (tuple[str, ...], default=()) – Effect measures included in the perspective.

  • utility_weights (mapping[str, float], optional) – Utility weights used to construct net benefit.

  • equity_weights (mapping[str, float], optional) – Equity weights used to construct net benefit.

  • willingness_to_pay (float, optional) – Willingness-to-pay threshold for this perspective.

  • discount_rate (float, optional) – Discount rate for this perspective.

  • population (float, optional) – Population scaling factor for this perspective.

  • stakeholder_metadata (mapping[str, object], optional) – Additional stakeholder metadata.

id: str
label: str | None = None
cost_categories: tuple[str, ...] = ()
effect_measures: tuple[str, ...] = ()
utility_weights: Mapping[str, float]
equity_weights: Mapping[str, float]
willingness_to_pay: float | None = None
discount_rate: float | None = None
population: float | None = None
stakeholder_metadata: Mapping[str, object]
__post_init__() None[source]

Validate perspective metadata.

class voiage.methods.perspective.PerspectiveSet(perspectives: Sequence[Perspective | str])[source]

Bases: object

Ordered collection of unique decision perspectives.

perspectives: tuple[Perspective, ...]
__init__(perspectives: Sequence[Perspective | str])[source]

Create a PerspectiveSet from Perspective objects or ids.

property ids: list[str]

Return perspective identifiers in analysis order.

property labels: list[str]

Return perspective labels in analysis order.

class voiage.methods.perspective.ValueOfPerspectiveResult(value: float, perspective_ids: list[str], perspective_labels: list[str], strategy_names: list[str], expected_net_benefits: ~numpy.ndarray, optimal_strategy_indices: ~numpy.ndarray, optimal_strategy_names: list[str], optimal_expected_net_benefits: ~numpy.ndarray, regret_matrix: ~numpy.ndarray, switching_values: ~numpy.ndarray, consensus_strategy_index: int, consensus_strategy_name: str, consensus_weighted_expected_net_benefit: float, robust_strategy_index: int, robust_strategy_name: str, pareto_strategy_indices: list[int], pareto_strategy_names: list[str], perspective_weights: ~numpy.ndarray, reference_perspective_id: str, method_maturity: str, diagnostics: dict[str, object], reporting: dict[str, object] = <factory>)[source]

Bases: object

Structured Value of Perspective result.

value

Weighted switching value relative to the reference perspective.

Type:

float

perspective_ids

Perspective identifiers in analysis order.

Type:

list[str]

perspective_labels

Human-readable perspective labels.

Type:

list[str]

strategy_names

Strategy labels in analysis order.

Type:

list[str]

expected_net_benefits

Expected net benefit with shape (n_perspectives, n_strategies).

Type:

numpy.ndarray

optimal_strategy_indices

Perspective-specific optimal strategy index.

Type:

numpy.ndarray

optimal_strategy_names

Perspective-specific optimal strategy name.

Type:

list[str]

optimal_expected_net_benefits

Expected net benefit of each perspective-specific optimum.

Type:

numpy.ndarray

regret_matrix

Matrix where row i and column j is regret in perspective i when using the strategy optimal under perspective j.

Type:

numpy.ndarray

switching_values

Regret avoided by switching away from the reference perspective’s strategy toward each perspective’s own optimal strategy.

Type:

numpy.ndarray

consensus_strategy_index

Strategy maximizing weighted expected net benefit across perspectives.

Type:

int

consensus_strategy_name

Name of the consensus strategy.

Type:

str

consensus_weighted_expected_net_benefit

Weighted expected net benefit of the consensus strategy.

Type:

float

robust_strategy_index

Strategy maximizing the minimum expected net benefit across perspectives.

Type:

int

robust_strategy_name

Name of the robust maximin strategy.

Type:

str

pareto_strategy_indices

Strategy indices not dominated across perspectives.

Type:

list[int]

pareto_strategy_names

Strategy names not dominated across perspectives.

Type:

list[str]

perspective_weights

Normalized perspective weights used for consensus and value summaries.

Type:

numpy.ndarray

reference_perspective_id

Perspective used as the reference decision rule.

Type:

str

method_maturity

Maturity label. Value of Perspective is fixture-backed.

Type:

str

diagnostics

Deterministic diagnostics for downstream reporting.

Type:

dict[str, object]

value: float
perspective_ids: list[str]
perspective_labels: list[str]
strategy_names: list[str]
expected_net_benefits: ndarray
optimal_strategy_indices: ndarray
optimal_strategy_names: list[str]
optimal_expected_net_benefits: ndarray
regret_matrix: ndarray
switching_values: ndarray
consensus_strategy_index: int
consensus_strategy_name: str
consensus_weighted_expected_net_benefit: float
robust_strategy_index: int
robust_strategy_name: str
pareto_strategy_indices: list[int]
pareto_strategy_names: list[str]
perspective_weights: ndarray
reference_perspective_id: str
method_maturity: str
diagnostics: dict[str, object]
reporting: dict[str, object]
voiage.methods.perspective.value_of_perspective(net_benefits: ValueArray | ndarray, perspectives: PerspectiveSet | Sequence[Perspective | str] | None = None, strategy_names: Sequence[str] | None = None, perspective_names: Sequence[str] | None = None, perspective_weights: Sequence[float] | Mapping[str, float] | None = None, reference_perspective: str | int | None = None) ValueOfPerspectiveResult[source]

Compare decision value across multiple perspectives.

Parameters:
  • net_benefits (ValueArray or numpy.ndarray) – Net-benefit samples with shape (n_samples, n_strategies, n_perspectives).

  • perspectives (PerspectiveSet or sequence, optional) – Ordered perspective metadata. Plain strings are interpreted as perspective ids.

  • strategy_names (sequence of str, optional) – Strategy labels.

  • perspective_names (sequence of str, optional) – Perspective labels used when perspectives is omitted.

  • perspective_weights (sequence or mapping, optional) – Non-negative weights used for consensus and weighted switching value. Mappings must be keyed by perspective id.

  • reference_perspective (str or int, optional) – Perspective whose optimal strategy is used as the reference decision rule. Defaults to the first perspective.

Returns:

Perspective-specific optima, regret matrix, switching values, consensus and robust strategies, and Pareto strategy set.

Return type:

ValueOfPerspectiveResult

Notes

The perspective-specific optimum is

\[d^*_p = \arg\max_d E[NB_{d,p}].\]

The reported switching value compares the reference perspective’s optimal strategy with each perspective’s own optimum, and the returned value is the weighted average of those switching values.

References

Voiage contributors. Value of Perspective frontier contract and analysis notes, including the proof-of-concept preprint linked from the project documentation. Keeney, R. L., & Raiffa, H. (1993). Decisions with Multiple Objectives.

Examples

>>> import numpy as np
>>> from voiage.analysis import DecisionAnalysis
>>> from voiage.schema import ValueArray
>>> values = np.array(
...     [
...         [[10.0, 7.0], [8.0, 11.0]],
...         [[11.0, 8.0], [9.0, 10.0]],
...     ]
... )
>>> result = DecisionAnalysis(
...     ValueArray.from_numpy_perspectives(
...         values,
...         strategy_names=["A", "B"],
...         perspective_names=["payer", "societal"],
...     )
... ).value_of_perspective()
>>> result.reference_perspective_id
'payer'
voiage.methods.perspective.perspective_optimal_strategies(result: ValueOfPerspectiveResult) dict[str, str][source]

Return the optimal strategy name for each perspective.

voiage.methods.portfolio module

Value of information helpers for research portfolio optimization.

The main entry point is portfolio_voi, which selects studies subject to budget or algorithm-specific constraints.

voiage.methods.portfolio.portfolio_voi(portfolio_specification: PortfolioSpec, study_value_calculator: Callable[[PortfolioStudy], float], optimization_method: str = 'greedy', **kwargs: object) dict[str, object][source]

Optimize a portfolio of research studies.

Parameters:
  • portfolio_specification (PortfolioSpec) – Candidate studies, costs, and optional budget constraint.

  • study_value_calculator (callable) – Function that returns the value of a single study.

  • optimization_method (str, default="greedy") – Selection algorithm. Supported values include greedy, integer_programming, and dynamic_programming.

  • **kwargs (object) – Additional algorithm-specific options.

Returns:

Dictionary containing the selected studies, total value, total cost, and method details.

Return type:

dict[str, object]

Notes

The dynamic-programming path is the exact budget-constrained optimizer. Greedy selection remains available as a fast heuristic.

voiage.methods.sample_information module

Implementation of Value of Information methods related to sample information.

  • EVSI (Expected Value of Sample Information)

  • ENBS (Expected Net Benefit of Sampling)

voiage.methods.sample_information.evsi(model_func: Callable[[ParameterSet], ValueArray], psa_prior: ParameterSet, trial_design: TrialDesign, population: float | None = None, discount_rate: float | None = None, time_horizon: float | None = None, method: str = 'two_loop', n_outer_loops: int = 100, n_inner_loops: int = 1000, metamodel: str = 'linear') float[source]

Calculate expected value of sample information.

Parameters:
  • model_func (callable) – Economic model that maps a ParameterSet to a ValueArray.

  • psa_prior (ParameterSet) – Prior PSA sample used as the analysis base.

  • trial_design (TrialDesign) – Proposed study design to evaluate.

  • population (float, optional) – Population size for population scaling.

  • discount_rate (float, optional) – Annual discount rate used for population scaling.

  • time_horizon (float, optional) – Time horizon in years for population scaling.

  • method ({"two_loop", "regression", "efficient", "moment_based"}) – EVSI approximation method.

  • n_outer_loops (int, default=100) – Number of outer Monte Carlo loops for two_loop.

  • n_inner_loops (int, default=1000) – Number of inner Monte Carlo loops for two_loop.

  • metamodel (str, default="linear") – Strategy-level surrogate model used by the efficient approximation.

Returns:

EVSI on a per-decision basis unless population scaling is requested.

Return type:

float

Notes

EVSI is the increase in expected net benefit from observing a proposed study before making the decision:

\[\mathrm{EVSI} = E_y\left[\max_d E[NB_d \mid y]\right] - \max_d E[NB_d].\]

The exact two-loop estimator uses nested Monte Carlo. The efficient and moment-based estimators approximate the same preposterior target while avoiding the inner simulation loop.

References

Brennan, A., Kharroubi, S., O’Hagan, A., Chilcott, J., & Claxton, K. (2007). Calculating expected value of sample information via Bayesian numerical analysis. Heath, A., Manolopoulou, I., & Baio, G. (2018). Efficient computation of expected value of sample information using regression-based methods.

Examples

>>> import numpy as np
>>> from voiage.methods.sample_information import evsi
>>> from voiage.schema import DecisionOption, ParameterSet, TrialDesign, ValueArray
>>> def model(psa: ParameterSet) -> ValueArray:
...     values = np.column_stack([
...         10.0 + psa.parameters["shift"],
...         11.0 - psa.parameters["shift"],
...     ])
...     return ValueArray.from_numpy(values, ["A", "B"])
>>> psa = ParameterSet.from_numpy_or_dict({"shift": np.array([0.1, 0.2, 0.3])})
>>> design = TrialDesign(arms=[DecisionOption(name="A", sample_size=10)])
>>> result = evsi(model, psa, design, method="efficient")
>>> result >= 0.0
True
voiage.methods.sample_information.enbs(evsi_result: float, research_cost: float) float[source]

Calculate expected net benefit of sampling.

Parameters:
  • evsi_result (float) – Result from an EVSI calculation.

  • research_cost (float) – Total cost of the proposed research.

Returns:

EVSI - research_cost.

Return type:

float

Notes

ENBS is the net gain from commissioning a study:

\[\mathrm{ENBS} = \mathrm{EVSI} - C_\mathrm{research}.\]

References

Claxton, K. (1999). The irrelevance of inference: A decision-making approach to the stochastic evaluation of health care technologies. Jalal, H., & Alarid-Escudero, F. (2023). Cost-effectiveness and the value of information in health economic evaluation.

Examples

>>> from voiage.methods.sample_information import enbs
>>> enbs(12.5, 5.0)
7.5

voiage.methods.sequential module

Value of information methods for dynamic and sequential decision problems.

voiage.methods.sequential.sequential_voi(step_model: Callable[[ParameterSet, object, DynamicSpec], dict[str, object]], initial_psa: ParameterSet, dynamic_specification: DynamicSpec, wtp: float = 0.0, population: float | None = None, discount_rate: float | None = None, time_horizon: float | None = None, optimization_method: str = 'backward_induction', **kwargs: object) float | Generator[dict[str, object], None, None][source]

Calculate value of information for a sequential decision problem.

voiage.methods.structural module

Implementation of VOI methods for structural uncertainty.

  • Structural EVPI (Expected Value of Perfect Information for Model Structure)

  • Structural EVPPI (Expected Value of Partial Perfect Information for Model Structure)

Structural uncertainty refers to uncertainty about the fundamental form or components of the model itself (e.g., choice of parametric family for survival, inclusion/exclusion of certain pathways, alternative model paradigms like decision tree vs. Markov model vs. DES).

These methods are often more complex to implement generically as they require ways to define, sample from, and evaluate alternative model structures.

voiage.methods.structural.structural_evpi(model_structure_evaluators: list[Callable[[ParameterSet], ValueArray]], structure_probabilities: ndarray | list[float], psa_samples_per_structure: list[ParameterSet], population: float | None = None, discount_rate: float | None = None, time_horizon: float | None = None) float[source]

Calculate expected value of perfect information for model structure.

Parameters:
  • model_structure_evaluators (list[callable]) – One evaluator per candidate structure. Each evaluator maps a ParameterSet to a ValueArray.

  • structure_probabilities (numpy.ndarray or list[float]) – Prior probabilities for each structure.

  • psa_samples_per_structure (list[ParameterSet]) – PSA samples relevant to each candidate structure.

  • population (float, optional) – Population size for population scaling.

  • discount_rate (float, optional) – Annual discount rate used for population scaling.

  • time_horizon (float, optional) – Time horizon in years for population scaling.

Returns:

Structural EVPI on a per-decision basis unless population scaling is requested.

Return type:

float

Notes

This treats model structure itself as the uncertainty source rather than only parameter values within a single structure.

voiage.methods.structural.structural_evppi(model_structure_evaluators: list[Callable[[ParameterSet], ValueArray]], structure_probabilities: ndarray | list[float], psa_samples_per_structure: list[ParameterSet], structures_of_interest: list[int], population: float | None = None, discount_rate: float | None = None, time_horizon: float | None = None) float[source]

Calculate structural EVPPI for a subset of model structures.

Parameters:
  • model_structure_evaluators (list[callable]) – One evaluator per candidate structure.

  • structure_probabilities (numpy.ndarray or list[float]) – Prior probabilities for each structure.

  • psa_samples_per_structure (list[ParameterSet]) – PSA samples relevant to each candidate structure.

  • structures_of_interest (list[int]) – Indices of the structures whose uncertainty is being resolved.

  • population (float, optional) – Population size for population scaling.

  • discount_rate (float, optional) – Annual discount rate used for population scaling.

  • time_horizon (float, optional) – Time horizon in years for population scaling.

Returns:

Structural EVPPI on a per-decision basis unless population scaling is requested.

Return type:

float

voiage.methods.structural.structural_evpi_jit(all_nb_arrays: list[ndarray], structure_probabilities: ndarray | list[float], population: float | None = None, discount_rate: float | None = None, time_horizon: float | None = None) float[source]

Calculate structural EVPI with JAX acceleration.

Parameters:
  • all_nb_arrays (list[numpy.ndarray]) – Pre-evaluated net-benefit arrays, one per structure.

  • structure_probabilities (numpy.ndarray or list[float]) – Prior probabilities for each structure.

  • population (float, optional) – Population size for population scaling.

  • discount_rate (float, optional) – Annual discount rate used for population scaling.

  • time_horizon (float, optional) – Time horizon in years for population scaling.

Returns:

Structural EVPI on a per-decision basis unless population scaling is requested.

Return type:

float

voiage.methods.structural.structural_evppi_jit(all_nb_arrays: list[ndarray], structure_probabilities: ndarray | list[float], structures_of_interest: list[int], population: float | None = None, discount_rate: float | None = None, time_horizon: float | None = None) float[source]

Calculate structural EVPPI with JAX acceleration.

Parameters:
  • all_nb_arrays (list[numpy.ndarray]) – Pre-evaluated net-benefit arrays, one per structure.

  • structure_probabilities (numpy.ndarray or list[float]) – Prior probabilities for each structure.

  • structures_of_interest (list[int]) – Indices of the structures whose uncertainty is being resolved.

  • population (float, optional) – Population size for population scaling.

  • discount_rate (float, optional) – Annual discount rate used for population scaling.

  • time_horizon (float, optional) – Time horizon in years for population scaling.

Returns:

Structural EVPPI on a per-decision basis unless population scaling is requested.

Return type:

float