1
1
import numpy as np
2
2
import os
3
3
import datetime
4
- import itertools
5
- import plotly .graph_objects as go
6
- import plotly .io as pio
7
4
8
- pio . kaleido . scope . mathjax = None # Surpress Plotly PDF export mathjax warning
5
+ from context import research as rs
9
6
10
7
path = os .path .dirname (__file__ )
11
8
30
27
"time" : datetime .datetime .now ().strftime ("%Y/%m/%d, %H:%M:%S" )
31
28
}
32
29
33
- ################################################################################
34
-
35
- def rmse (estimates , realizations ):
36
- """Evaluate RMSE of given vector of estimated values based on given vector true realized values"""
37
-
38
- nPoints = estimates .size
39
- if nPoints != realizations .size :
40
- raise Exception ("count of estimates and realizations must be equal" )
41
-
42
- diff = estimates - realizations
43
- squares = np .power (diff , 2 )
44
- sum = np .sum (squares )
45
- error = np .sqrt (sum / nPoints )
46
- return error
47
-
48
- def sigDig (num ):
49
- """Print real number into string with 4 significant digits"""
50
- strOut = ""
51
- strIn = str (num )
52
- if "." in strIn :
53
- precIndex = strIn .find ("." )
54
- if precIndex == 1 and strIn [0 ] == "0" :
55
- numChars = 6
56
- else :
57
- numChars = 5
58
- for i in range (numChars ):
59
- if i < len (strIn ):
60
- strOut += strIn [i ]
61
- else :
62
- strOut += "0"
63
- return strOut
64
-
65
- def addKeyValue (text , key , value ):
66
- addition = "\\ newcommand{\%s}{%s}\n " % (key , value )
67
- text = text + addition
68
- return text
69
-
70
-
71
- ################################################################################
72
-
73
- def squaredExpCovFunc (x_a , x_b , var , var_x ):
74
- """Squared exponential covariance function"""
75
-
76
- if x_a .size != x_b .size or var <= 0 or var_x <= 0 :
77
- raise Exception ("invalid squared exponential function parameters" )
78
-
79
- return var * np .exp (- ((np .linalg .norm (x_a - x_b )** 2 )/ (2 * var_x )))
80
-
81
- class GaussianProcess :
82
- def __init__ (self ):
83
- self .meanType = "undefined"
84
- self .covType = "undefined"
85
-
86
- def setMeanFuncConst (self , value ):
87
- self .meanType = "constant"
88
- self .meanValue = value
89
-
90
- def setCovFuncSquaredExp (self , var , var_x ):
91
- self .covType = "squared exponential"
92
- self .var = var
93
- self .var_x = var_x
94
-
95
- def meanFunc (self , x_a ):
96
- if self .meanType == "constant" :
97
- return self .meanValue
98
-
99
- def covFunc (self , x_a , x_b ):
100
- if self .covType == "squared exponential" :
101
- return squaredExpCovFunc (x_a , x_b , self .var , self .var_x )
102
-
103
- ################################################################################
104
-
105
- def genTrainPosUni (size , nPos ):
106
- """Generate column vector of training positions uniformly distributed in given space size"""
107
-
108
- pos = np .zeros ((nPos , len (size )))
109
-
110
- for posID in range (nPos ):
111
- for dimID in range (len (size )):
112
- pos [posID , dimID ] = np .random .uniform (low = 0 , high = size [dimID ])
113
-
114
- return pos
115
-
116
- def genTestPosGrid (size , res ):
117
- """Generate column vector of test positions representing grid over given space size in given resolution"""
118
-
119
- step = 1 / res
120
- dimSteps = []
121
- for dimID in range (len (size )):
122
- nSteps = int (size [dimID ]/ step ) + 1 # Include 1 point at the end to span to full range
123
- sequence = range (nSteps )
124
- steps = [i * step for i in sequence ]
125
- dimSteps .append (steps )
126
-
127
- # var = np.meshgrid(*dimSteps) # Possible to evaluate only using NumPy
128
-
129
- posGridList = list (itertools .product (* dimSteps ))
130
- posGrid = np .zeros ((len (posGridList ), len (size )))
131
- for posID in range (len (posGridList )):
132
- posGrid [posID , :] = np .asarray (posGridList [posID ])
133
-
134
- return posGrid
135
-
136
- ################################################################################
137
-
138
- def plotData (size , res , data , pos , posColor = "White" , filePath = "fig" , show = False ):
139
- step = 1 / res
140
- dimSteps = []
141
- for dimID in range (len (size )):
142
- nSteps = int (size [dimID ]/ step ) + 1
143
- steps = range (nSteps )
144
- steps = [i * step for i in steps ]
145
- dimSteps .append (steps )
146
-
147
- newShape = (len (dimSteps [0 ]), len (dimSteps [1 ]))
148
- dataPlot = np .transpose (np .reshape (data , newShape ))
149
-
150
- fig = go .Figure ()
151
- fig .add_trace (
152
- go .Contour (
153
- x = dimSteps [0 ],
154
- y = dimSteps [1 ],
155
- z = dataPlot ,
156
- contours_coloring = "heatmap"
157
- )
158
- )
159
- fig .add_trace (
160
- go .Scatter (
161
- mode = "markers" ,
162
- x = pos [:, 0 ],
163
- y = pos [:, 1 ],
164
- marker = dict (
165
- color = posColor ,
166
- size = 10 ,
167
- line = dict (
168
- color = "Black" ,
169
- width = 2
170
- )
171
- )
172
- )
173
- )
174
- fig .update_xaxes (
175
- title_text = "Spatial dimension X"
176
- )
177
- fig .update_yaxes (
178
- title_text = "Spatial dimension Y" ,
179
- scaleanchor = "x" ,
180
- scaleratio = 1
181
- )
182
- fig .update_layout (
183
- width = 600 , height = 300 ,
184
- font_family = "Serif" , font_size = 15 ,
185
- margin = dict (l = 0 , r = 0 , t = 0 , b = 0 ),
186
- )
187
- fig .write_image (filePath )
188
- if show :
189
- fig .show ()
190
-
191
- ################################################################################
192
-
193
- def meanVecGP (gp , pos ):
194
- """Get GP mean values at given positions"""
195
-
196
- nPos = pos .shape [0 ]
197
- meanVec = np .zeros (nPos )
198
- for i in range (nPos ):
199
- meanVec [i ] = gp .meanFunc (pos [i , :])
200
-
201
- return meanVec
202
-
203
- def covMatGP (gp , pos ):
204
- """Get GP covariance matrix at given positions"""
205
-
206
- nPos = pos .shape [0 ]
207
- covMat = np .zeros ((nPos , nPos ))
208
- for row in range (nPos ):
209
- for col in range (nPos ):
210
- covMat [row , col ] = gp .covFunc (pos [row , :], pos [col , :])
211
-
212
- return covMat
213
-
214
- def realizeGP (gp , pos , regCoef ):
215
- """Generate realization vector of given GP on given positions"""
216
-
217
- nPos = pos .shape [0 ]
218
- meanVec = meanVecGP (gp , pos )
219
- covMat = covMatGP (gp , pos ) + regCoef * np .identity (nPos ) # Regularization ensuring positive definiteness
220
- choleskyCovMat = np .linalg .cholesky (covMat )
221
- iidGaussVec = np .random .normal (0 , 1 , nPos ) # Vector of iid Gaussian zero mean unit st. d. RVs
222
-
223
- realizationVec = meanVec + np .dot (choleskyCovMat , iidGaussVec )
224
-
225
- return realizationVec
226
-
227
- def gpr (gp , trainPos , testPos , trainObs , obsVar ):
228
- """GPR standard evaluation"""
229
-
230
- nTrainPos = trainPos .shape [0 ]
231
- if nTrainPos != trainObs .size :
232
- raise Exception ("different number of training positions and function observations" )
233
-
234
- meanVec_m = meanVecGP (gp , trainPos )
235
-
236
- covMat_K = covMatGP (gp , trainPos )
237
- covMat_Q = covMat_K + obsVar * np .identity (nTrainPos )
238
- covMatInv_Q = np .linalg .inv (covMat_Q )
239
-
240
- nTestPos = testPos .shape [0 ]
241
- if nTestPos < 1 :
242
- raise Exception ("at least 1 test position must be provided" )
243
- postDistMat = np .zeros ((nTestPos , 2 ))
244
-
245
- for testPosID in range (nTestPos ):
246
- crossCovVec_c = np .zeros (nTrainPos )
247
- for trainPosID in range (nTrainPos ):
248
- crossCovVec_c [trainPosID ] = gp .covFunc (testPos [testPosID , :], trainPos [trainPosID , :])
249
-
250
- c_t_dot_Q_inv = np .dot (crossCovVec_c , covMatInv_Q )
251
-
252
- postMean = gp .meanFunc (testPos ) + np .dot (c_t_dot_Q_inv , (trainObs - meanVec_m ))
253
- postVar = gp .covFunc (testPos , testPos ) - np .dot (c_t_dot_Q_inv , crossCovVec_c )
254
- postDistMat [testPosID , :] = np .array ([postMean , postVar ])
255
-
256
- return postDistMat
257
-
258
- ################################################################################
259
-
260
- def genPosSample (pos , var ):
261
- """Generate vector of positions with AWGN according to provided positions and variance"""
262
-
263
- posSample = np .zeros ((pos .shape [0 ], pos .shape [1 ]))
264
-
265
- for posID in range (pos .shape [0 ]):
266
- for dimID in range (pos .shape [1 ]):
267
- posSample [posID , dimID ] = pos [posID , dimID ] + np .random .normal (0 , np .sqrt (var ))
268
-
269
- return posSample
270
-
271
- def genPosSamples (pos , var , nSamples ):
272
- """Generate multiple vectors of positions with AWGN according to provided positions and variance"""
273
-
274
- posSamples = np .zeros ((nSamples , pos .shape [0 ], pos .shape [1 ]))
275
-
276
- for sampleID in range (nSamples ):
277
- posSamples [sampleID , :, :] = genPosSample (pos , var )
278
-
279
- return posSamples
280
-
281
- def gprMC (gp , trainPosSamples , testPos , trainObs , obsVar ):
282
- """GPR evaluation with uncertain training positions using MC"""
283
-
284
- nTrainPosSamples = trainPosSamples .shape [0 ]
285
- nTrainPos = trainPosSamples .shape [1 ]
286
- if nTrainPos != trainObs .size :
287
- raise Exception ("different number of training positions and function observations" )
288
-
289
- nTestPos = testPos .shape [0 ]
290
- if nTestPos < 1 :
291
- raise Exception ("at least 1 test position must be provided" )
292
-
293
- postDistSamples = np .zeros ((nTrainPosSamples , nTestPos , 2 ))
294
- for sampleID in range (nTrainPosSamples ):
295
- postDistSamples [sampleID , :, :] = gpr (gp , trainPosSamples [sampleID , :, :], testPos , trainObs , obsVar )
296
-
297
- postDistMat = np .zeros ((nTestPos , 2 ))
298
- for testPosID in range (nTestPos ):
299
- postDistSamplesTest = postDistSamples [:, testPosID , :]
300
- postMean = np .average (postDistSamplesTest [:, 0 ], axis = 0 )
301
- postVar = np .average (np .sum (np .power (postDistSamplesTest , 2 ), axis = 1 )) - postMean ** 2
302
-
303
- postDistMat [testPosID , 0 ] = postMean
304
- postDistMat [testPosID , 1 ] = postVar
305
-
306
- return postDistMat
307
-
308
- ################################################################################
309
-
310
30
nSimulations = simSetup ["nSimulations" ]
311
31
312
32
allResults = np .zeros ((nSimulations , 3 ))
313
33
314
34
for simulationID in range (nSimulations ):
315
- trainPos = genTrainPosUni (simSetup ["spaceSize" ], simSetup ["nTrainPos" ])
316
- testPos = genTestPosGrid (simSetup ["spaceSize" ], simSetup ["testPosRes" ])
35
+ trainPos = rs . gpr . genTrainPosUni (simSetup ["spaceSize" ], simSetup ["nTrainPos" ])
36
+ testPos = rs . gpr . genTestPosGrid (simSetup ["spaceSize" ], simSetup ["testPosRes" ])
317
37
allPos = np .append (trainPos , testPos , axis = 0 )
318
38
319
- trueGP = GaussianProcess ()
39
+ trueGP = rs . gpr . GaussianProcess ()
320
40
trueGP .setMeanFuncConst (simSetup ["meanGP" ]["value" ])
321
41
trueGP .setCovFuncSquaredExp (simSetup ["covGP" ]["var" ], simSetup ["covGP" ]["var_x" ])
322
42
323
- allRealizations = realizeGP (trueGP , allPos , simSetup ["regCoef" ])
43
+ allRealizations = rs . gpr . realizeGP (trueGP , allPos , simSetup ["regCoef" ])
324
44
trainRealizations = allRealizations [0 :trainPos .shape [0 ]]
325
45
trainObs = trainRealizations + np .random .normal (0 , np .sqrt (simSetup ["obsVar" ]), trainPos .shape [0 ])
326
46
327
47
testRealization = allRealizations [- testPos .shape [0 ]: None ]
328
- posteriorParamTrue = gpr (trueGP , trainPos , testPos , trainObs , simSetup ["obsVar" ])
48
+ posteriorParamTrue = rs . gpr . gpr (trueGP , trainPos , testPos , trainObs , simSetup ["obsVar" ])
329
49
330
- trainPosObs = genPosSample (trainPos , simSetup ["trainPosVar" ])
331
- posteriorParamObs = gpr (trueGP , trainPosObs , testPos , trainObs , simSetup ["obsVar" ])
50
+ trainPosObs = rs . gpr . genPosSample (trainPos , simSetup ["trainPosVar" ])
51
+ posteriorParamObs = rs . gpr . gpr (trueGP , trainPosObs , testPos , trainObs , simSetup ["obsVar" ])
332
52
333
- trainPosSamples = genPosSamples (trainPosObs , simSetup ["trainPosVar" ], simSetup ["nSamplesMC" ])
334
- posteriorParamMC = gprMC (trueGP , trainPosSamples , testPos , trainObs , simSetup ["obsVar" ])
53
+ trainPosSamples = rs . gpr . genPosSamples (trainPosObs , simSetup ["trainPosVar" ], simSetup ["nSamplesMC" ])
54
+ posteriorParamMC = rs . gpr . gprMC (trueGP , trainPosSamples , testPos , trainObs , simSetup ["obsVar" ])
335
55
336
- allResults [simulationID , 0 ] = rmse (posteriorParamTrue [:, 0 ], testRealization )
337
- allResults [simulationID , 1 ] = rmse (posteriorParamObs [:, 0 ], testRealization )
338
- allResults [simulationID , 2 ] = rmse (posteriorParamMC [:, 0 ], testRealization )
56
+ allResults [simulationID , 0 ] = rs . rmse (posteriorParamTrue [:, 0 ], testRealization )
57
+ allResults [simulationID , 1 ] = rs . rmse (posteriorParamObs [:, 0 ], testRealization )
58
+ allResults [simulationID , 2 ] = rs . rmse (posteriorParamMC [:, 0 ], testRealization )
339
59
340
60
if nSimulations == 1 :
341
- plotData (simSetup ["spaceSize" ], simSetup ["testPosRes" ], testRealization , trainPos , "Blue" , path + "/realization.pdf" )
342
- plotData (simSetup ["spaceSize" ], simSetup ["testPosRes" ], posteriorParamTrue [:, 0 ], trainPos , "Blue" , path + "/postMeanTrue.pdf" )
343
- plotData (simSetup ["spaceSize" ], simSetup ["testPosRes" ], posteriorParamObs [:, 0 ], trainPosObs , "Green" , path + "/postMeanObs.pdf" )
344
- plotData (simSetup ["spaceSize" ], simSetup ["testPosRes" ], posteriorParamMC [:, 0 ], trainPosObs , "Green" , path + "/postMeanObsMC.pdf" )
345
-
346
- plotData (simSetup ["spaceSize" ], simSetup ["testPosRes" ], posteriorParamTrue [:, 1 ], trainPos , "Blue" , path + "/postVarTrue.pdf" )
347
- plotData (simSetup ["spaceSize" ], simSetup ["testPosRes" ], posteriorParamObs [:, 1 ], trainPosObs , "Green" , path + "/postVarObs.pdf" )
348
- plotData (simSetup ["spaceSize" ], simSetup ["testPosRes" ], posteriorParamMC [:, 1 ], trainPosObs , "Green" , path + "/postVarObsMC.pdf" )
61
+ rs . gpr . plotData (simSetup ["spaceSize" ], simSetup ["testPosRes" ], testRealization , trainPos , "Spatial function value" , "Blue" , path + "/realization.pdf" )
62
+ rs . gpr . plotData (simSetup ["spaceSize" ], simSetup ["testPosRes" ], posteriorParamTrue [:, 0 ], trainPos , "Posterior mean" , "Blue" , path + "/postMeanTrue.pdf" )
63
+ rs . gpr . plotData (simSetup ["spaceSize" ], simSetup ["testPosRes" ], posteriorParamObs [:, 0 ], trainPosObs , "Posterior mean" , "Green" , path + "/postMeanObs.pdf" )
64
+ rs . gpr . plotData (simSetup ["spaceSize" ], simSetup ["testPosRes" ], posteriorParamMC [:, 0 ], trainPosObs , "Posterior mean" , "Green" , path + "/postMeanObsMC.pdf" )
65
+
66
+ rs . gpr . plotData (simSetup ["spaceSize" ], simSetup ["testPosRes" ], posteriorParamTrue [:, 1 ], trainPos , "Posterior variance" , "Blue" , path + "/postVarTrue.pdf" )
67
+ rs . gpr . plotData (simSetup ["spaceSize" ], simSetup ["testPosRes" ], posteriorParamObs [:, 1 ], trainPosObs , "Posterior variance" , "Green" , path + "/postVarObs.pdf" )
68
+ rs . gpr . plotData (simSetup ["spaceSize" ], simSetup ["testPosRes" ], posteriorParamMC [:, 1 ], trainPosObs , "Posterior variance" , "Green" , path + "/postVarObsMC.pdf" )
349
69
else :
350
70
print ("simulationID: %d / %d" % (simulationID + 1 , nSimulations ), end = "\r " )
351
71
352
72
results = np .average (allResults , axis = 0 )
353
- print ("\n RMSE postMeanTrue: %s, postMeanObs: %s, postMeanMC: %s" % (sigDig (results [0 ]), sigDig (results [1 ]), sigDig (results [2 ])))
73
+ print ("\n RMSE postMeanTrue: %s, postMeanObs: %s, postMeanMC: %s" % (rs . sigDig (results [0 ]), rs . sigDig (results [1 ]), rs . sigDig (results [2 ])))
354
74
355
75
resultsStr = ""
356
- resultsStr = addKeyValue (resultsStr , "rmseTrue" , sigDig (results [0 ]))
357
- resultsStr = addKeyValue (resultsStr , "rmseObs" , sigDig (results [1 ]))
358
- resultsStr = addKeyValue (resultsStr , "rmseObsMC" , sigDig (results [2 ]))
76
+ resultsStr = rs . addKeyValue (resultsStr , "rmseTrue" , rs . sigDig (results [0 ]))
77
+ resultsStr = rs . addKeyValue (resultsStr , "rmseObs" , rs . sigDig (results [1 ]))
78
+ resultsStr = rs . addKeyValue (resultsStr , "rmseObsMC" , rs . sigDig (results [2 ]))
359
79
with open (path + "/results.tex" , 'w' ) as res :
360
80
res .write (resultsStr )
0 commit comments