11"""This module holds the Scenario Class"""
22
3- from collections .abc import Iterable , Mapping
3+ from collections .abc import Iterable
4+ from dataclasses import dataclass
45
5- from tabulate import tabulate
66
7- from .variable import Input , Meta , Output , Variable
7+ from .variable import Variable
88
99
10+ @dataclass
1011class Scenario :
1112 """A scenario defines the setting by listing the endogenous variables, their
1213 datatypes, distributions, and any constraints over them. This is a common
@@ -24,134 +25,9 @@ class Scenario:
2425 :attr constraints:
2526 """
2627
27- variables : Mapping [str , Variable ]
28- constraints : set [str ]
29-
30- def __init__ (self , variables : Iterable [Variable ] = None , constraints : set [str ] = None ):
31- if variables is not None :
32- self .variables = {v .name : v for v in variables }
33- else :
34- self .variables = {}
28+ def __init__ (self , variables : Iterable [Variable ], constraints : set [str ] = None ):
29+ self .variables = {v .name : v for v in variables }
3530 if constraints is not None :
3631 self .constraints = set (constraints )
3732 else :
3833 self .constraints = set ()
39-
40- self .prime = {}
41- self .unprime = {}
42- self .treatment_variables = {}
43-
44- def __str__ (self ):
45- """Returns a printable string of a scenario.
46-
47- Example output::
48-
49- Modelling scenario with variables:
50- ------ --------------- -----
51- INPUT location str
52- INPUT n_days int
53- INPUT pop_size int
54- META average_age int
55- META household_size float
56- OUTPUT cum_deaths int
57- OUTPUT cum_infections int
58- OUTPUT cum_quarantined int
59- ------ --------------- -----
60- And constraints:
61- n_days <= 365
62- n_days >= 60
63- average_age > 0
64-
65- :return: A printable version of a scenario.
66- :rtype: str
67- """
68-
69- def indent (txt , spaces = 4 ):
70- return "\n " .join (" " * spaces + ln for ln in txt .splitlines ())
71-
72- string = "Modelling scenario with variables:\n "
73- string += indent (
74- tabulate (
75- sorted (
76- [(v .typestring (), v .name , v .datatype .__name__ ) for v in self .variables .values ()],
77- )
78- )
79- )
80- if len (self .constraints ) > 0 :
81- string += "\n And constraints:\n "
82- string += "\n " .join ([str (c ) for c in self .constraints ])
83- return string
84-
85- def _fresh (self , variable : Variable ) -> Variable :
86- """Create a "primed" version of the given variable to represent the CI
87- treatment values, e.g. if a variable v represents the control value,
88- then a variable v' will be created to represent the treatment value.
89-
90- :param Variable variable: The variable to "prime".
91- :return: A fresh "primed" variable.
92- :rtype: Variable
93- """
94- vname = variable .name
95- while vname in self .variables :
96- vname += "'"
97- return variable .copy (vname )
98-
99- def setup_treatment_variables (self ) -> None :
100- """Create a mirror of the current variable set with "primed" variables
101- to represent the treatment values. Corresponding constraints are added
102- to the contraint set such that the "primed" variables are constrained in
103- the same way as their unprimed counterparts.
104- """
105- for k , v in self .variables .items ():
106- v_prime = self ._fresh (v )
107- self .treatment_variables [k ] = v_prime
108- self .prime [k ] = v_prime .name
109- self .unprime [v_prime .name ] = k
110-
111- def variables_of_type (self , t : type ) -> set [Variable ]:
112- """Get the set of scenario variables of a particular type, e.g. Inputs.
113-
114- :param type t: The type of variable to return, where t extends Variable.
115- :return: A set of scenario variables of the supplied type.
116- :rtype: {Variable}
117- """
118- return {v for v in self .variables .values () if isinstance (v , t )}
119-
120- def inputs (self ) -> set [Input ]:
121- """Get the set of scenario inputs.
122-
123- :return: The scenario inputs.
124- :rtype: {Input}
125- """
126- return self .variables_of_type (Input )
127-
128- def outputs (self ) -> set [Output ]:
129- """Get the set of scenario outputs.
130-
131- :return: The scenario outputs.
132- :rtype: {Output}
133- """
134- return self .variables_of_type (Output )
135-
136- def metas (self ) -> set [Meta ]:
137- """Get the set of scenario metavariables.
138-
139- :return: The scenario metavariables.
140- :rtype: {Input}
141- """
142- return self .variables_of_type (Meta )
143-
144- def hidden_variables (self ) -> set [Variable ]:
145- """Get the set of hidden variables
146-
147- :return The variables marked as hidden.
148- :rtype: {Variable}
149- """
150- return {v for v in self .variables .values () if v .hidden }
151-
152- def add_variable (self , v : Variable ) -> None :
153- """Add variable to variables attribute
154-
155- :param v: Variable to be added
156- """
157- self .variables [v .name ]: v
0 commit comments