1
1
from autokoopman .observable import SymbolicObservable , KoopmanObservable
2
2
import math
3
3
import numpy as np
4
- import sympy as sp
5
- from scipy .stats import cauchy , laplace
6
- from scipy .optimize import nnls
7
4
8
5
9
6
def make_gaussian_kernel (sigma = 1.0 ):
10
- """the baseline"""
11
- def kernel (x , xp ):
12
- return np .exp (- np .linalg .norm (x - xp )** 2.0 / (2.0 * sigma ** 2.0 ))
13
- return kernel
7
+ """the baseline"""
8
+
9
+ def kernel (x , xp ):
10
+ return np .exp (- np .linalg .norm (x - xp ) ** 2.0 / (2.0 * sigma ** 2.0 ))
11
+
12
+ return kernel
14
13
15
14
16
15
def rff_reweighted_map (n , X , Y , wx , wy , sigma = 1.0 ):
17
- """build a RFF explicit feature map"""
18
- assert len (X ) == len (Y )
19
- R = n
20
- D = X .shape [1 ]
21
- N = len (X )
22
- W = np .random .normal (loc = 0 , scale = (1.0 / np .sqrt (sigma )), size = (R , D ))
23
- b = np .random .uniform (- np .pi , np .pi , size = R )
24
-
25
- # get ground truth kernel for training
26
- kernel = make_gaussian_kernel (sigma )
27
-
28
- # solve NNLS problem
29
- M = np .zeros ((N , R ))
30
- bo = np .zeros ((N ,))
31
- for jdx , (xi , yi , wxi , wyi ) in enumerate (zip (X , Y , wx , wy )):
32
- wi = np .sum (wxi ) * np .sum (wyi )
33
- k = wi * kernel (xi , yi )
34
- if np .isclose (np .abs (wi ), 0.0 ):
35
- continue
36
- bo [jdx ] = k
37
- for idx , (omegai , bi ) in enumerate (zip (W , b )):
38
- M [jdx , idx ] = wi * np .cos (np .dot (omegai , xi ) + bi ) * np .cos (np .dot (omegai , yi ) + bi )
39
-
40
- a , _ = nnls (M , bo , maxiter = 1000 )
41
-
42
- # get new values
43
- new_idxs = (np .abs (a ) > 3E-5 )
44
- W = W [new_idxs ]
45
- b = b [new_idxs ]
46
- a = a [new_idxs ]
47
-
48
- return a , W , b
16
+ """build a RFF explicit feature map"""
17
+ from scipy .optimize import nnls
18
+
19
+ assert len (X ) == len (Y )
20
+ R = n
21
+ D = X .shape [1 ]
22
+ N = len (X )
23
+ W = np .random .normal (loc = 0 , scale = (1.0 / np .sqrt (sigma )), size = (R , D ))
24
+ b = np .random .uniform (- np .pi , np .pi , size = R )
25
+
26
+ # get ground truth kernel for training
27
+ kernel = make_gaussian_kernel (sigma )
28
+
29
+ # solve NNLS problem
30
+ M = np .zeros ((N , R ))
31
+ bo = np .zeros ((N ,))
32
+ for jdx , (xi , yi , wxi , wyi ) in enumerate (zip (X , Y , wx , wy )):
33
+ wi = np .sum (wxi ) * np .sum (wyi )
34
+ k = wi * kernel (xi , yi )
35
+ if np .isclose (np .abs (wi ), 0.0 ):
36
+ continue
37
+ bo [jdx ] = k
38
+ for idx , (omegai , bi ) in enumerate (zip (W , b )):
39
+ M [jdx , idx ] = (
40
+ wi * np .cos (np .dot (omegai , xi ) + bi ) * np .cos (np .dot (omegai , yi ) + bi )
41
+ )
42
+
43
+ a , _ = nnls (M , bo , maxiter = 1000 )
44
+
45
+ # get new values
46
+ new_idxs = np .abs (a ) > 3e-5
47
+ W = W [new_idxs ]
48
+ b = b [new_idxs ]
49
+ a = a [new_idxs ]
50
+
51
+ return a , W , b
49
52
50
53
51
54
def subsampled_dense_grid (d , D , gamma , deg = 8 ):
52
- """sparse grid gaussian quadrature"""
53
- points , weights = np .polynomial .hermite .hermgauss (deg )
54
- points *= 2 * math .sqrt (gamma )
55
- weights /= math .sqrt (math .pi )
56
- # Now @weights must sum to 1.0, as the kernel value at 0 is 1.0
57
- subsampled_points = np .random .choice (points , size = (D , d ), replace = True , p = weights )
58
- subsampled_weights = np .ones (D ) / math .sqrt (D )
59
- return subsampled_points , subsampled_weights
55
+ """sparse grid gaussian quadrature"""
56
+ points , weights = np .polynomial .hermite .hermgauss (deg )
57
+ points *= 2 * math .sqrt (gamma )
58
+ weights /= math .sqrt (math .pi )
59
+ # Now @weights must sum to 1.0, as the kernel value at 0 is 1.0
60
+ subsampled_points = np .random .choice (points , size = (D , d ), replace = True , p = weights )
61
+ subsampled_weights = np .ones (D ) / math .sqrt (D )
62
+ return subsampled_points , subsampled_weights
60
63
61
64
62
65
def dense_grid (d , D , gamma , deg = 8 ):
63
- """dense grid gaussian quadrature"""
64
- points , weights = np .polynomial .hermite .hermgauss (deg )
65
- points *= 2 * math .sqrt (gamma )
66
- weights /= math .sqrt (math .pi )
67
- points = np .atleast_2d (points ).T
68
- return points , weights
66
+ """dense grid gaussian quadrature"""
67
+ points , weights = np .polynomial .hermite .hermgauss (deg )
68
+ points *= 2 * math .sqrt (gamma )
69
+ weights /= math .sqrt (math .pi )
70
+ points = np .atleast_2d (points ).T
71
+ return points , weights
69
72
70
73
71
74
def sparse_grid_map (n , d , sigma = 1.0 ):
72
- """sparse GQ explicit map"""
73
- d , D = d , n
74
- gamma = 1 / (2 * sigma * sigma )
75
- points , weights = subsampled_dense_grid (d , D , gamma = gamma )
76
- def inner (x ):
77
- prod = x @ points .T
78
- return np .hstack ((weights * np .cos (prod ), weights * np .sin (prod )))
79
- return inner
75
+ """sparse GQ explicit map"""
76
+ d , D = d , n
77
+ gamma = 1 / (2 * sigma * sigma )
78
+ points , weights = subsampled_dense_grid (d , D , gamma = gamma )
79
+
80
+ def inner (x ):
81
+ prod = x @ points .T
82
+ return np .hstack ((weights * np .cos (prod ), weights * np .sin (prod )))
83
+
84
+ return inner
80
85
81
86
82
87
def dense_grid_map (n , d , sigma = 1.0 ):
83
- """dense GQ explicit map"""
84
- d , D = d , n
85
- gamma = 1 / (2 * sigma * sigma )
86
- points , weights = dense_grid (d , D , gamma = gamma )
87
- def inner (x ):
88
- prod = x @ points .T
89
- return np .hstack ((weights * np .cos (prod ), weights * np .sin (prod )))
90
- return inner
88
+ """dense GQ explicit map"""
89
+ d , D = d , n
90
+ gamma = 1 / (2 * sigma * sigma )
91
+ points , weights = dense_grid (d , D , gamma = gamma )
92
+
93
+ def inner (x ):
94
+ prod = x @ points .T
95
+ return np .hstack ((weights * np .cos (prod ), weights * np .sin (prod )))
96
+
97
+ return inner
91
98
92
99
93
100
def quad_reweighted_map (n , X , Y , wx , wy , sigma = 1.0 ):
94
- """build a RFF explicit feature map"""
95
- assert len (X ) == len (Y )
96
- R = int (n / 2.0 )
97
- D = X .shape [1 ]
98
- N = len (X )
99
- W , a = subsampled_dense_grid (D , R , gamma = 1 / (2 * sigma * sigma ))
100
- #W = np.random.normal(loc=0, scale=(1.0/np.sqrt(sigma)), size=(R, D))
101
- b = np .random .uniform (- np .pi , np .pi , size = R )
102
- #print(X.shape, W.shape)
103
- #b = np.arccos(-np.sqrt(np.cos(2*X.T.dot(W)) + 1)/np.sqrt(2.0))
104
- #print(b)
105
-
106
- # get ground truth kernel for training
107
- kernel = make_gaussian_kernel (sigma )
108
-
109
- # solve NNLS problem
110
- M = np .zeros ((N , R ))
111
- bo = np .zeros ((N ,))
112
- for jdx , (xi , yi , wxi , wyi ) in enumerate (zip (X , Y , wx , wy )):
113
- k = kernel (xi , yi )
114
- bo [jdx ] = k
115
- for idx , (omegai , ai , bi ) in enumerate (zip (W , a , b )):
116
- M [jdx , idx ] = np .cos (np .dot (omegai , xi - yi ))
117
-
118
- a , _ = nnls (M , bo , maxiter = 1000 )
119
-
120
- # get new values
121
- new_idxs = (np .abs (a ) > 1E-7 )
122
- W = W [new_idxs ]
123
- b = b [new_idxs ]
124
- a = a [new_idxs ]
125
-
126
- return a , W , b
101
+ """build a RFF explicit feature map"""
102
+ from scipy .optimize import nnls
103
+
104
+ assert len (X ) == len (Y )
105
+ R = int (n / 2.0 )
106
+ D = X .shape [1 ]
107
+ N = len (X )
108
+ W , a = subsampled_dense_grid (D , R , gamma = 1 / (2 * sigma * sigma ))
109
+ # W = np.random.normal(loc=0, scale=(1.0/np.sqrt(sigma)), size=(R, D))
110
+ b = np .random .uniform (- np .pi , np .pi , size = R )
111
+ # print(X.shape, W.shape)
112
+ # b = np.arccos(-np.sqrt(np.cos(2*X.T.dot(W)) + 1)/np.sqrt(2.0))
113
+ # print(b)
114
+
115
+ # get ground truth kernel for training
116
+ kernel = make_gaussian_kernel (sigma )
117
+
118
+ # solve NNLS problem
119
+ M = np .zeros ((N , R ))
120
+ bo = np .zeros ((N ,))
121
+ for jdx , (xi , yi , wxi , wyi ) in enumerate (zip (X , Y , wx , wy )):
122
+ k = kernel (xi , yi )
123
+ bo [jdx ] = k
124
+ for idx , (omegai , ai , bi ) in enumerate (zip (W , a , b )):
125
+ M [jdx , idx ] = np .cos (np .dot (omegai , xi - yi ))
126
+
127
+ a , _ = nnls (M , bo , maxiter = 1000 )
128
+
129
+ # get new values
130
+ new_idxs = np .abs (a ) > 1e-7
131
+ W = W [new_idxs ]
132
+ b = b [new_idxs ]
133
+ a = a [new_idxs ]
134
+
135
+ return a , W , b
127
136
128
137
129
138
class ReweightedRFFObservable (SymbolicObservable ):
130
- def __init__ (self , dimension , num_features , gamma , X , Y , wx , wy , feat_type = 'rff' ):
139
+ def __init__ (self , dimension , num_features , gamma , X , Y , wx , wy , feat_type = "rff" ):
140
+ import sympy as sp
141
+
131
142
self .dimension , self .num_features = dimension , num_features
132
143
n = num_features
133
- if feat_type == 'quad' :
134
- self .a , self .W , self .b = quad_reweighted_map (n , X , Y , wx , wy , np .sqrt (1 / (2 * gamma )))
135
- elif feat_type == 'rff' :
136
- self .a , self .W , self .b = rff_reweighted_map (n , X , Y , wx , wy , np .sqrt (1 / (2 * gamma )))
144
+ if feat_type == "quad" :
145
+ self .a , self .W , self .b = quad_reweighted_map (
146
+ n , X , Y , wx , wy , np .sqrt (1 / (2 * gamma ))
147
+ )
148
+ elif feat_type == "rff" :
149
+ self .a , self .W , self .b = rff_reweighted_map (
150
+ n , X , Y , wx , wy , np .sqrt (1 / (2 * gamma ))
151
+ )
137
152
else :
138
- raise ValueError (' feat_type must be quad or rff' )
139
-
153
+ raise ValueError (" feat_type must be quad or rff" )
154
+
140
155
# make sympy variables for each of the state dimensions
141
- self .variables = [f' x{ i } ' for i in range (self .dimension )]
156
+ self .variables = [f" x{ i } " for i in range (self .dimension )]
142
157
self ._observables = sp .symbols (self .variables )
143
158
X = sp .Matrix (self ._observables )
144
-
159
+
145
160
# build observables sympy expressions from self.weights from self.weights, x.T @ points
146
161
self .expressions = []
147
162
for ai , wi , bi in zip (self .a , self .W , self .b ):
148
163
self .expressions .append (np .sqrt (ai ) * sp .cos (X .dot (wi )))
149
164
self .expressions .append (np .sqrt (ai ) * sp .sin (X .dot (wi )))
150
165
151
- super (ReweightedRFFObservable , self ).__init__ (self .variables , self .expressions )
166
+ super (ReweightedRFFObservable , self ).__init__ (self .variables , self .expressions )
0 commit comments