Skip to content

Commit 7876726

Browse files
authored
Merge pull request #8 from ousema-bouaneni/main
CI test failure fix and replacement of poetry and mkapi by pixi and mkdocstrings
2 parents 1421359 + 4e93f12 commit 7876726

File tree

12 files changed

+152
-79
lines changed

12 files changed

+152
-79
lines changed

.github/workflows/ci.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name: CI
22

3-
on: [push]
3+
on: [push, pull_request]
44

55
jobs:
66

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,4 @@ poetry.lock
99
**/__pycache__/*
1010
temp*.yml
1111
.mypy*
12+
*ipynb*

docs/index.md

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
1-
# Welcome to MkDocs
1+
# Reference
22

3-
For full documentation visit [mkdocs.org](https://www.mkdocs.org).
4-
5-
The solution to all the problems is hidden in the source code of this page.
3+
::: dyno
4+
options:
5+
docstring_style: numpy
6+
separate_signature: false
7+
show_signature_annotations: false
8+
docstring_section_style: table

dyno/language.py

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
# copied from dolo
44

5-
from .types import Vector, Matrix
5+
from .typedefs import TVector, TMatrix
66

77
from dolang.language import greek_tolerance, language_element # type: ignore
88

@@ -15,6 +15,20 @@ class NotPositiveSemidefinite(np.linalg.LinAlgError):
1515
pass
1616

1717

18+
@language_element
19+
def Matrix(*lines):
20+
mat = np.array(lines, np.float64)
21+
assert mat.ndim == 2
22+
return mat
23+
24+
25+
@language_element
26+
def Vector(*elements):
27+
mat = np.array(elements, np.float64)
28+
assert mat.ndim == 1
29+
return mat
30+
31+
1832
@language_element
1933
class Normal:
2034
"""Multivariate normal process class, can be used to model white noise.
@@ -40,13 +54,15 @@ class Normal:
4054
dimension
4155
"""
4256

43-
Μ: Vector # this is capital case μ, not M... 😭
44-
Σ: Matrix
57+
Μ: TVector # this is capital case μ, not M... 😭
58+
Σ: TMatrix
59+
60+
signature = {"Σ": "Matrix", "Μ": "Optional[Vector]"}
4561

4662
@greek_tolerance
4763
def __init__(self, Σ, Μ=None):
4864

49-
Sigma = Σ
65+
Sigma = np.array(Σ)
5066
mu = Μ
5167

5268
self.Σ = np.atleast_2d(np.array(Sigma, dtype=float))
@@ -103,7 +119,7 @@ def Σ(self):
103119
104120
Returns
105121
-------
106-
Matrix
122+
TMatrix
107123
Covariance matrix of the process
108124
"""
109125
assert len(self.processes) == 1

dyno/misc.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import numpy as np
2-
from .types import Vector, Matrix
2+
from .typedefs import TVector, TMatrix
33
from typing import Callable
44

55

66
def jacobian(
7-
func: Callable[[Vector], Vector], initial: Vector, delta: float = 1e-3
8-
) -> Matrix:
7+
func: Callable[[TVector], TVector], initial: TVector, delta: float = 1e-3
8+
) -> TMatrix:
99
"""Jacobian calculation with finite differences
1010
1111
Parameters

dyno/model.py

Lines changed: 29 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,9 @@
88

99
from abc import ABC, abstractmethod
1010

11-
from typing import Callable, Self, overload, Literal
12-
from .types import Vector, Matrix, IRFType, Solver, SymbolType, DynamicFunction
11+
from typing import Callable, overload, Literal, Any
12+
from typing_extensions import Self
13+
from .typedefs import TVector, TMatrix, IRFType, Solver, SymbolType, DynamicFunction
1314
from pandas import DataFrame
1415
from .language import Normal
1516

@@ -19,7 +20,7 @@ class RecursiveSolution:
1920
2021
Attributes
2122
----------
22-
X, Y, Σ: (N,N) matrix
23+
X, Y, Σ: (N,N) Matrix
2324
parameters of the stationary VAR process $y_t = Xy_{t-1} + Yε_t$, where Σ is the covariance matrix of $ε_t$
2425
2526
symbols: dict[SymbolType, list[str]]
@@ -35,12 +36,12 @@ class RecursiveSolution:
3536

3637
def __init__(
3738
self: Self,
38-
X: Matrix,
39-
Y: Matrix,
40-
Σ: Matrix,
39+
X: TMatrix,
40+
Y: TMatrix,
41+
Σ: TMatrix,
4142
symbols: dict[SymbolType, list[str]],
42-
x0: Vector | None = None,
43-
evs: Vector | None = None,
43+
x0: TVector | None = None,
44+
evs: TVector | None = None,
4445
) -> None:
4546

4647
self.x0 = x0
@@ -73,25 +74,31 @@ def describe(self: Self) -> str:
7374

7475
@overload
7576
def dynamic(
76-
self: Self, y0: Vector, y1: Vector, y2: Vector, e: Vector, p: Vector
77-
) -> Vector:
77+
self: Self, y0: TVector, y1: TVector, y2: TVector, e: TVector, p: TVector
78+
) -> TVector:
7879
pass
7980

8081
@overload
8182
def dynamic(
82-
self: Self, y0: Vector, y1: Vector, y2: Vector, e: Vector, p: Vector, diff: bool
83-
) -> tuple[Vector, Matrix, Matrix, Matrix, Matrix]:
83+
self: Self,
84+
y0: TVector,
85+
y1: TVector,
86+
y2: TVector,
87+
e: TVector,
88+
p: TVector,
89+
diff: bool,
90+
) -> tuple[TVector, TMatrix, TMatrix, TMatrix, TMatrix]:
8491
pass
8592

8693
def dynamic(
8794
self: Self,
88-
y0: Vector,
89-
y1: Vector,
90-
y2: Vector,
91-
e: Vector,
92-
p: Vector,
95+
y0: TVector,
96+
y1: TVector,
97+
y2: TVector,
98+
e: TVector,
99+
p: TVector,
93100
diff: bool = False,
94-
) -> Vector | tuple[Vector, Matrix, Matrix, Matrix, Matrix]:
101+
) -> TVector | tuple[TVector, TMatrix, TMatrix, TMatrix, TMatrix]:
95102
"""function f describing the behavior of the dynamic system $f(y_{t+1}, y_t, y_{t-1}, ε_t, p) = 0$
96103
97104
Parameters
@@ -125,18 +132,18 @@ def dynamic(
125132
return r
126133

127134
@overload
128-
def compute(self: Self, calibration: dict[str, float] = {}) -> Vector:
135+
def compute(self: Self, calibration: dict[str, float] = {}) -> TVector:
129136
pass
130137

131138
@overload
132139
def compute(
133140
self: Self, calibration: dict[str, float] = {}, diff: bool = False
134-
) -> tuple[Vector, Matrix, Matrix, Matrix, Matrix]:
141+
) -> tuple[TVector, TMatrix, TMatrix, TMatrix, TMatrix]:
135142
pass
136143

137144
def compute(
138145
self: Self, calibration: dict[str, float] = {}, diff: bool = False
139-
) -> Vector | tuple[Vector, Matrix, Matrix, Matrix, Matrix]:
146+
) -> TVector | tuple[TVector, TMatrix, TMatrix, TMatrix, TMatrix]:
140147
"""Computes the dynamic function's value based on calibration state and parameters
141148
142149
Parameters
@@ -148,7 +155,7 @@ def compute(
148155
149156
Returns
150157
-------
151-
Vector|tuple[Vector, Matrix, Matrix, Matrix, Matrix]
158+
TVector|tuple[TVector, TMatrix, TMatrix, TMatrix, TMatrix]
152159
value of the dynamic function at the state described by calibration, as well as its partial derivatives if diff is set to True
153160
"""
154161
c = self.get_calibration(**calibration)

dyno/simul.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import pandas as pd
33
from .model import RecursiveSolution
44

5-
from .types import IRFType
5+
from .typedefs import IRFType
66

77

88
def irf(

dyno/solver.py

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
import numpy as np
22
from numpy.linalg import solve as linsolve
33
from scipy.linalg import ordqz
4-
from .types import Vector, Matrix, Solver
4+
from .typedefs import TVector, TMatrix, Solver
55

66

77
def solve(
8-
A: Matrix, B: Matrix, C: Matrix, method: Solver = "qz", options={}
9-
) -> tuple[Matrix, Vector | None]:
8+
A: TMatrix, B: TMatrix, C: TMatrix, method: Solver = "qz", options={}
9+
) -> tuple[TMatrix, TVector | None]:
1010
"""Solves AX² + BX + C = 0 for X using the chosen method
1111
1212
Parameters
@@ -52,8 +52,8 @@ class NoConvergence(Exception):
5252

5353

5454
def solve_ti(
55-
A: Matrix, B: Matrix, C: Matrix, T: int = 10000, tol: float = 1e-10
56-
) -> tuple[Matrix, None]:
55+
A: TMatrix, B: TMatrix, C: TMatrix, T: int = 10000, tol: float = 1e-10
56+
) -> tuple[TMatrix, None]:
5757
"""Solves AX² + BX + C = 0 for X using fixed-point iteration.
5858
5959
Parameters
@@ -102,8 +102,8 @@ def solve_ti(
102102

103103

104104
def solve_qz(
105-
A: Matrix, B: Matrix, C: Matrix, tol: float = 1e-15
106-
) -> tuple[Matrix, Vector]:
105+
A: TMatrix, B: TMatrix, C: TMatrix, tol: float = 1e-15
106+
) -> tuple[TMatrix, TVector]:
107107
"""Solves AX² + BX + C = 0 for X using QZ decomposition.
108108
109109
Parameters
@@ -142,7 +142,7 @@ def solve_qz(
142142
return X, np.sort(λ_all).reshape(2 * n)
143143

144144

145-
def decompose_blocks(Z: Matrix) -> tuple[Matrix, Matrix, Matrix, Matrix]:
145+
def decompose_blocks(Z: TMatrix) -> tuple[TMatrix, TMatrix, TMatrix, TMatrix]:
146146
"""Decomposes square matrix Z into four square blocks Z11, Z12, Z21, Z22 such that Z can be written as:
147147
```
148148
[Z11, Z12]
@@ -189,7 +189,7 @@ def genev(α: float, β: float, tol: float = 1e-9) -> float:
189189
return np.inf
190190

191191

192-
def vgenev(α: Vector, β: Vector, tol: float = 1e-9) -> Vector:
192+
def vgenev(α: TVector, β: TVector, tol: float = 1e-9) -> TVector:
193193
"""
194194
Computes the generalized eigenvalues λ = α/β, vectorized version of `genev`
195195
@@ -207,7 +207,7 @@ def vgenev(α: Vector, β: Vector, tol: float = 1e-9) -> Vector:
207207
return (np.array([genev(a, b) for a, b in zip(α, β)])).reshape(len(α))
208208

209209

210-
def moments(X: Matrix, Y: Matrix, Σ: Matrix) -> tuple[Matrix, Matrix]:
210+
def moments(X: TMatrix, Y: TMatrix, Σ: TMatrix) -> tuple[TMatrix, TMatrix]:
211211
"""
212212
Computes conditional and unconditional moments of stationary process $y_t = X y_{t-1} + Y e_t$
213213
@@ -230,19 +230,19 @@ def moments(X: Matrix, Y: Matrix, Σ: Matrix) -> tuple[Matrix, Matrix]:
230230
231231
Applying the linear covariance operator to both sides of the equation $y_t = X y_{t-1} + Y e_t$ yields
232232
$$
233-
\mathrm{Cov}(y_t) = X ⋅ \mathrm{Cov}(y_{t-1}) ⋅ X^* + Y ⋅ \mathrm{Cov}(e_t) ⋅ Y^*
233+
\\mathrm{Cov}(y_t) = X ⋅ \\mathrm{Cov}(y_{t-1}) ⋅ X^* + Y ⋅ \\mathrm{Cov}(e_t) ⋅ Y^*
234234
$$
235-
By stationarity of $y_t$, $\mathrm{Cov}(y_t) = \mathrm{Cov}(y_{t-1}) := \Gamma$, so
235+
By stationarity of $y_t$, $\\mathrm{Cov}(y_t) = \\mathrm{Cov}(y_{t-1}) := Γ$, so
236236
$$
237237
Γ = X Γ X^* + Γ₀
238238
$$
239239
By applying the [Vec-operator](https://en.wikipedia.org/wiki/Vectorization_(mathematics)#Compatibility_with_Kronecker_products), we get the following equation:
240240
$$
241-
\mathrm{Vec}(Γ) = (X ⊗ X) \mathrm{Vec}(Γ) + \mathrm{Vec}(Γ₀)
241+
\\mathrm{Vec}(Γ) = (X ⊗ X) \\mathrm{Vec}(Γ) + \\mathrm{Vec}(Γ₀)
242242
$$
243243
Which gives the following solution
244244
$$
245-
\mathrm{Vec}(Γ) = (I_{N^2} - X ⊗ X)^{-1} \mathrm{Vec}(Γ₀)
245+
\\mathrm{Vec}(Γ) = (I_{N^2} - X ⊗ X)^{-1} \\mathrm{Vec}(Γ₀)
246246
$$
247247
"""
248248

dyno/types.py renamed to dyno/typedefs.py

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,11 @@
22
from typing import Literal, TypeVar, Callable
33

44
DType = TypeVar("DType", bound=np.generic)
5-
Vector = np.ndarray[tuple[int], DType]
6-
Matrix = np.ndarray[tuple[int, int], DType]
5+
TVector = np.ndarray[tuple[int], DType]
6+
TMatrix = np.ndarray[tuple[int, int], DType]
77

88
Solver = Literal["ti", "qz"]
99
SymbolType = Literal["endogenous", "exogenous", "parameters"]
1010
IRFType = Literal["level", "log-deviation", "deviation"]
1111

12-
DynamicFunction = Callable[
13-
[Vector, Vector, Vector, Vector, Vector, Vector],
14-
Vector | tuple[Vector, Matrix, Matrix, Matrix, Matrix],
15-
]
12+
DynamicFunction = Callable[[TVector, TVector, TVector, TVector, TVector, TVector], None]

mkdocs.yml

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ site_name: Dyno 🦖
22

33
plugins:
44
- search # necessary for search to work
5-
- mkapi
5+
- mkdocstrings
66

77
markdown_extensions:
88
- mdx_math
@@ -33,6 +33,4 @@ extra_javascript:
3333
- https://cdn.jsdelivr.net/npm/vega-embed@5
3434

3535
nav:
36-
- index.md
37-
- Reference:
38-
- $api/dyno.***
36+
- index.md

0 commit comments

Comments
 (0)