Skip to content

Commit 227403c

Browse files
committed
Modular research package
1 parent ea0462c commit 227403c

File tree

12 files changed

+521
-467
lines changed

12 files changed

+521
-467
lines changed

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@
88
.history/
99
*.vsix
1010

11+
### Python ###
12+
__pycache__/
13+
*.pyc
14+
1115
### MacOS ###
1216
*.DS_Store
1317

2023_4_EEICT/context.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import sys
2+
import os
3+
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
4+
5+
import research

2023_4_EEICT/main.py

Lines changed: 25 additions & 305 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
11
import numpy as np
22
import os
33
import datetime
4-
import itertools
5-
import plotly.graph_objects as go
6-
import plotly.io as pio
74

8-
pio.kaleido.scope.mathjax = None # Surpress Plotly PDF export mathjax warning
5+
from context import research as rs
96

107
path = os.path.dirname(__file__)
118

@@ -30,331 +27,54 @@
3027
"time": datetime.datetime.now().strftime("%Y/%m/%d, %H:%M:%S")
3128
}
3229

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-
31030
nSimulations = simSetup["nSimulations"]
31131

31232
allResults = np.zeros((nSimulations, 3))
31333

31434
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"])
31737
allPos = np.append(trainPos, testPos, axis=0)
31838

319-
trueGP = GaussianProcess()
39+
trueGP = rs.gpr.GaussianProcess()
32040
trueGP.setMeanFuncConst(simSetup["meanGP"]["value"])
32141
trueGP.setCovFuncSquaredExp(simSetup["covGP"]["var"], simSetup["covGP"]["var_x"])
32242

323-
allRealizations = realizeGP(trueGP, allPos, simSetup["regCoef"])
43+
allRealizations = rs.gpr.realizeGP(trueGP, allPos, simSetup["regCoef"])
32444
trainRealizations = allRealizations[0:trainPos.shape[0]]
32545
trainObs = trainRealizations + np.random.normal(0, np.sqrt(simSetup["obsVar"]), trainPos.shape[0])
32646

32747
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"])
32949

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"])
33252

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"])
33555

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)
33959

34060
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")
34969
else:
35070
print("simulationID: %d / %d"%(simulationID+1, nSimulations), end="\r")
35171

35272
results = np.average(allResults, axis=0)
353-
print("\nRMSE postMeanTrue: %s, postMeanObs: %s, postMeanMC: %s"%(sigDig(results[0]), sigDig(results[1]), sigDig(results[2])))
73+
print("\nRMSE postMeanTrue: %s, postMeanObs: %s, postMeanMC: %s"%(rs.sigDig(results[0]), rs.sigDig(results[1]), rs.sigDig(results[2])))
35474

35575
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]))
35979
with open(path + "/results.tex", 'w') as res:
36080
res.write(resultsStr)

Localization/context.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import sys
2+
import os
3+
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
4+
5+
import research

0 commit comments

Comments
 (0)