Quick Start

Get up-and-running with APLUS in <5 minutes with this walkthrough!

1. Install the APLUS package:

pip install aplusml

2. Create your workflow configuration:

script.py
 1import aplusml
 2
 3# Create Config object. You must specify three things:
 4# 1. Metadata -- basic information about the simulation
 5# 2. Variables -- variables used in the simulation
 6# 3. States -- states in the workflow that your patients will progress through
 7config = aplusml.config.Config(
 8  metadata = aplusml.config.ConfigMetadata(
 9    name = 'My Simulation',
10  ),
11  variables = {
12    'some_constant': aplusml.config.ConfigVariable(
13      type = 'scalar',
14      value = -12.03,
15    ),
16    'some_resource': aplusml.config.ConfigVariable(
17      type = 'resource',
18      init_amount = 0,
19      max_amount = 10,
20      refill_amount = 3,
21      refill_duration = 1,
22    ),
23  },
24  states = {
25    'start' : aplusml.config.ConfigState(
26      type = 'start',
27      transitions = [
28        aplusml.config.ConfigTransition(dest = 'end_1', prob = 0.5),
29        aplusml.config.ConfigTransition(dest = 'end_2', prob = 0.5),
30      ],
31    ),
32    'end_1' : aplusml.config.ConfigState(
33      type = 'end',
34      utilities = {
35        'qalys': aplusml.config.ConfigUtility(
36          value = 1,
37        ),
38      },
39    ),
40    'end_2' : aplusml.config.ConfigState(
41      type = 'end',
42      utilities = {
43        'qalys': aplusml.config.ConfigUtility(
44          value = 2,
45        ),
46      },
47    ),
48  },
49)

3. Create a Simulation object.

script.py
50simulation: aplusml.Simulation = aplusml.Simulation.create_from_config(config)

4. Visualize the workflow via a graphviz diagram:

script.py
51# Draws workflow diagram. This will save the diagram to './output.png' and print it to your terminal.
52simulation.draw_workflow_diagram(figsize=(30,30), path_to_file='./output.png', is_display=True)

5. Create a list of patients to simulate. We simulate the flow of patients as a Poisson process with the following parameters:

  • \(p\) patients start our workflow each day, where \(p \sim \text{Poisson}(\lambda=35)\)

  • \(N\) total days will be simulated, where \(N=500\)

script.py
53import numpy as np
54
55# Set random seed for reproducibility
56np.random.seed(0)
57
58# Simulate number of patients per day
59n_admits_per_day = np.random.poisson(lam=35, size=500)
60
61# Create empty Patient objects (with proper start timesteps according to our Poisson distribution)
62patients: List[aplusml.Patient] = []
63for timestep, n_admits in enumerate(n_admits_per_day):
64    for x in range(n_admits):
65        patients.append(aplusml.Patient(
66            len(patients), # Unique ID
67            timestep, # Start timestep
68        ))
69
70# Function which matches a patient to a row in the CSV file.
71func_match_patient_to_property_column = lambda p_id, random_idx, df, col: df.iloc[random_idx][col]
72
73# Initialize patients for simulation.
74# This creates a deep copy of each object in the `patients` array using pickle, sorts them by ID, and then initializes their properties
75patients: List[aplusml.Patient] = simulation.create_patients_for_simulation(patients,
76                                                                          func_match_patient_to_property_column,
77                                                                          random_seed = 0)

6. Run the simulation:

script.py
78# Run simulation
79patients = simulation.run(patients)

7. Calculate the total utility achieved by the workflow by summing all patients’ achieved utilities:

script.py
80# Sum up the utilities achieved across all patient histories
81sum_utilities: Dict[str, float] = collections.defaultdict(float)
82for p in patients:
83    _u: dict = p.get_sum_utilities(simulation)
84    for key, val in _u.items():
85        sum_utilities[key] += val
86
87# Print results
88print(sum_utilities)

Putting it all together, we have the following APLUS script:

script.py
  1import aplusml
  2import numpy as np
  3from typing import List, Dict
  4import collections
  5
  6############################################################
  7# 1. Initialize simulation
  8############################################################
  9
 10# Create Config object. You must specify three things:
 11# 1. Metadata -- basic information about the simulation
 12# 2. Variables -- variables used in the simulation
 13# 3. States -- states in the workflow that your patients will progress through
 14config = aplusml.config.Config(
 15  metadata = aplusml.config.ConfigMetadata(
 16    name = 'My Simulation',
 17  ),
 18  variables = {
 19    'some_constant': aplusml.config.ConfigVariable(
 20      type = 'scalar',
 21      value = -12.03,
 22    ),
 23    'some_resource': aplusml.config.ConfigVariable(
 24      type = 'resource',
 25      init_amount = 0,
 26      max_amount = 10,
 27      refill_amount = 3,
 28      refill_duration = 1,
 29    ),
 30  },
 31  states = {
 32    'start' : aplusml.config.ConfigState(
 33      type = 'start',
 34      transitions = [
 35        aplusml.config.ConfigTransition(dest = 'end_1', prob = 0.5),
 36        aplusml.config.ConfigTransition(dest = 'end_2', prob = 0.5),
 37      ],
 38    ),
 39    'end_1' : aplusml.config.ConfigState(
 40        type = 'end',
 41        utilities = [
 42            aplusml.config.ConfigUtility(
 43                value = .5,
 44                unit = 'qaly',
 45            ),
 46        ],
 47    ),
 48    'end_2' : aplusml.config.ConfigState(
 49        type = 'end',
 50        utilities = [
 51            aplusml.config.ConfigUtility(
 52                value = 2,
 53                unit = 'qaly',
 54            ),
 55        ],
 56    ),
 57  },
 58)
 59
 60# Create Simulation object
 61simulation: aplusml.Simulation = aplusml.Simulation.create_from_config(config)
 62
 63# Set random seed for reproducibility
 64np.random.seed(0)
 65
 66############################################################
 67# 2. Initialize patients
 68############################################################
 69
 70# Simulate number of patients per day
 71n_admits_per_day = np.random.poisson(lam=35, size=500)
 72
 73# Create empty Patient objects (with proper start timesteps according to our Poisson distribution)
 74patients: List[aplusml.Patient] = []
 75for timestep, n_admits in enumerate(n_admits_per_day):
 76    for x in range(n_admits):
 77        patients.append(aplusml.Patient(
 78            len(patients), # Unique ID
 79            timestep, # Start timestep
 80        ))
 81
 82# Function which matches a patient to a row in the CSV file.
 83func_match_patient_to_property_column = lambda p_id, random_idx, df, col: df.iloc[random_idx][col]
 84
 85# Initialize patients for simulation.
 86# This creates a deep copy of each object in the `patients` array using pickle, sorts them by ID, and then initializes their properties
 87patients: List[aplusml.Patient] = simulation.create_patients_for_simulation(patients,
 88                                                                          func_match_patient_to_property_column,
 89                                                                          random_seed = 0)
 90
 91############################################################
 92# 3. Run simulation
 93############################################################
 94
 95patients = simulation.run(patients)
 96
 97############################################################
 98# 4. Analyze results
 99############################################################
100
101# Sum up the utilities achieved across all patient histories
102sum_utilities: Dict[str, float] = collections.defaultdict(float)
103for p in patients:
104    _u: dict = p.get_sum_utilities(simulation)
105    for key, val in _u.items():
106        sum_utilities[key] += val
107
108# Print results
109print(sum_utilities)