88
99import numpy as np
1010
11+ from scipy .stats import multivariate_normal
12+
1113
1214class NotPositiveSemidefinite (np .linalg .LinAlgError ):
1315 """An exception raised when a normal process is created with a covariance matrix that is not positive semidefinite"""
@@ -29,16 +31,48 @@ def Vector(*elements):
2931 return mat
3032
3133
34+ class Exogenous :
35+ pass
36+
37+
38+ class Deterministic (Exogenous ):
39+ """Deterministic exogenous variables clas
40+
41+ Parameters
42+ ----------
43+ horizon: int
44+ time horizon over which the perfect foresight solver will simulate the model
45+
46+ values_dict: dict[str, list[float]]
47+ dictionary containing the values that each exogenous variable takes on at each time period before the horizon,
48+ empty fields are assumed to be zero
49+ """
50+
51+ horizon : int
52+ """time horizon over which the model will be simulated"""
53+
54+ values : dict [str , list [float ]]
55+ """values taken on by each exogenous variable"""
56+
57+ def __init__ (self , horizon : int , values_dict : dict [str , list [float ]]):
58+ horizon = max (horizon , max ([len (periods ) for periods in values_dict .values ()]))
59+ for var , values in values_dict .items ():
60+ if len (values ) < horizon :
61+ values_dict [var ] = pad_list (values , horizon )
62+ self .horizon = horizon
63+ self .values = values_dict
64+
65+
3266@language_element
33- class Normal :
67+ class Normal ( Exogenous ) :
3468 """Multivariate normal process class, can be used to model white noise.
3569
3670 Parameters
3771 ----------
3872 Μ: d Vector | None
3973 Mean vector for the normal process, taken to be equal to zero if not passed
4074
41- Σ : (d,d) Matrix
75+ Σ: (d,d) Matrix
4276 Covariance matrix for the normal process, needs to be positive semidefinite
4377
4478 Attributes
@@ -61,39 +95,30 @@ class Normal:
6195
6296 @greek_tolerance
6397 def __init__ (self , Σ , Μ = None ):
64-
6598 Sigma = np .array (Σ )
6699 mu = Μ
67-
68100 self .Σ = np .atleast_2d (np .array (Sigma , dtype = float ))
69101 try :
70102 assert np .array_equal (Sigma , Sigma .T )
71- np .linalg .cholesky (Sigma )
72- except (AssertionError , np .linalg .LinAlgError ):
73- raise (
74- NotPositiveSemidefinite ,
103+ assert np .all (np .linalg .eigvalsh (Sigma ) > - 1e-12 )
104+ except AssertionError :
105+ raise NotPositiveSemidefinite (
75106 "Σ can't be used as a covariance matrix as it is not positive semidefinite" ,
76107 )
77-
78108 self .d = len (self .Σ )
79109 if mu is None :
80110 self .Μ = np .array ([0.0 ] * self .d )
81111 else :
82112 self .Μ = np .array (mu , dtype = float )
83113
84114 assert self .Σ .shape [0 ] == self .d
85- assert self .Σ .shape [0 ] == self .d
86-
115+ assert self .Σ .shape [1 ] == self .d
87116 # this class wraps functionality from scipy
88- import scipy .stats
89-
90- self ._dist_ = scipy .stats .multivariate_normal (
91- mean = self .Μ , cov = self .Σ , allow_singular = True
92- )
117+ self ._dist_ = multivariate_normal (mean = self .Μ , cov = self .Σ , allow_singular = True )
93118
94119
95120@language_element
96- class ProductNormal :
121+ class ProductNormal ( Exogenous ) :
97122 """Product of multivariate normal processes
98123
99124 Parameters
@@ -124,3 +149,7 @@ def Σ(self):
124149 """
125150 assert len (self .processes ) == 1
126151 return self .processes [0 ].Σ
152+
153+
154+ def pad_list (l : list , n : int ) -> list :
155+ return l + [0 ] * (n - len (l ))
0 commit comments