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)