fvgp 4.2.2__tar.gz → 4.2.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. {fvgp-4.2.2/fvgp.egg-info → fvgp-4.2.4}/PKG-INFO +1 -1
  2. {fvgp-4.2.2 → fvgp-4.2.4}/fvgp/_version.py +3 -3
  3. {fvgp-4.2.2 → fvgp-4.2.4}/fvgp/fvgp.py +71 -11
  4. {fvgp-4.2.2 → fvgp-4.2.4}/fvgp/gp.py +49 -112
  5. {fvgp-4.2.2 → fvgp-4.2.4}/fvgp/gpMCMC.py +49 -83
  6. {fvgp-4.2.2 → fvgp-4.2.4}/fvgp/gp_marginal_density.py +4 -6
  7. {fvgp-4.2.2 → fvgp-4.2.4}/fvgp/gp_posterior.py +50 -52
  8. {fvgp-4.2.2 → fvgp-4.2.4}/fvgp/mcmc.py +15 -17
  9. {fvgp-4.2.2 → fvgp-4.2.4/fvgp.egg-info}/PKG-INFO +1 -1
  10. {fvgp-4.2.2 → fvgp-4.2.4}/tests/test_fvgp.py +34 -6
  11. {fvgp-4.2.2 → fvgp-4.2.4}/AUTHORS.rst +0 -0
  12. {fvgp-4.2.2 → fvgp-4.2.4}/CONTRIBUTING.rst +0 -0
  13. {fvgp-4.2.2 → fvgp-4.2.4}/COPYING +0 -0
  14. {fvgp-4.2.2 → fvgp-4.2.4}/HISTORY.rst +0 -0
  15. {fvgp-4.2.2 → fvgp-4.2.4}/LICENSE +0 -0
  16. {fvgp-4.2.2 → fvgp-4.2.4}/MANIFEST.in +0 -0
  17. {fvgp-4.2.2 → fvgp-4.2.4}/README.md +0 -0
  18. {fvgp-4.2.2 → fvgp-4.2.4}/docs/Makefile +0 -0
  19. {fvgp-4.2.2 → fvgp-4.2.4}/docs/make.bat +0 -0
  20. {fvgp-4.2.2 → fvgp-4.2.4}/docs/source/_static/landing.png +0 -0
  21. {fvgp-4.2.2 → fvgp-4.2.4}/docs/source/conf.py +0 -0
  22. {fvgp-4.2.2 → fvgp-4.2.4}/fvgp/__init__.py +0 -0
  23. {fvgp-4.2.2 → fvgp-4.2.4}/fvgp/deep_kernel_network.py +0 -0
  24. {fvgp-4.2.2 → fvgp-4.2.4}/fvgp/gp_data.py +0 -0
  25. {fvgp-4.2.2 → fvgp-4.2.4}/fvgp/gp_kernels.py +0 -0
  26. {fvgp-4.2.2 → fvgp-4.2.4}/fvgp/gp_likelihood.py +0 -0
  27. {fvgp-4.2.2 → fvgp-4.2.4}/fvgp/gp_lin_alg.py +0 -0
  28. {fvgp-4.2.2 → fvgp-4.2.4}/fvgp/gp_prior.py +0 -0
  29. {fvgp-4.2.2 → fvgp-4.2.4}/fvgp/gp_training.py +0 -0
  30. {fvgp-4.2.2 → fvgp-4.2.4}/fvgp.egg-info/SOURCES.txt +0 -0
  31. {fvgp-4.2.2 → fvgp-4.2.4}/fvgp.egg-info/dependency_links.txt +0 -0
  32. {fvgp-4.2.2 → fvgp-4.2.4}/fvgp.egg-info/entry_points.txt +0 -0
  33. {fvgp-4.2.2 → fvgp-4.2.4}/fvgp.egg-info/not-zip-safe +0 -0
  34. {fvgp-4.2.2 → fvgp-4.2.4}/fvgp.egg-info/requires.txt +0 -0
  35. {fvgp-4.2.2 → fvgp-4.2.4}/fvgp.egg-info/top_level.txt +0 -0
  36. {fvgp-4.2.2 → fvgp-4.2.4}/setup.cfg +0 -0
  37. {fvgp-4.2.2 → fvgp-4.2.4}/setup.py +0 -0
  38. {fvgp-4.2.2 → fvgp-4.2.4}/tests/__init__.py +0 -0
  39. {fvgp-4.2.2 → fvgp-4.2.4}/tests/latest_hps.npy +0 -0
  40. {fvgp-4.2.2 → fvgp-4.2.4}/versioneer.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: fvgp
3
- Version: 4.2.2
3
+ Version: 4.2.4
4
4
  Summary: Python package for highly flexible function-valued Gaussian processes (fvGP)
5
5
  Home-page: https://github.com/MarcusMichaelNoack/fvgp
6
6
  Author: Marcus Michael Noack
@@ -8,11 +8,11 @@ import json
8
8
 
9
9
  version_json = '''
10
10
  {
11
- "date": "2024-05-31T14:47:35-0700",
11
+ "date": "2024-06-07T11:34:45-0700",
12
12
  "dirty": false,
13
13
  "error": null,
14
- "full-revisionid": "c7d74e2e459b81c40049a2af64298d8d63111af3",
15
- "version": "4.2.2"
14
+ "full-revisionid": "c2a8c754f5e362fcd4d68857b83c2edf1bc1f5d0",
15
+ "version": "4.2.4"
16
16
  }
17
17
  ''' # END VERSION_JSON
18
18
 
@@ -1,9 +1,6 @@
1
1
  #!/usr/bin/env python
2
2
  import numpy as np
3
- import warnings
4
3
  from .gp import GP
5
- from .gp_kernels import get_distance_matrix
6
- from .gp_kernels import matern_kernel_diff1
7
4
 
8
5
 
9
6
  class fvGP(GP):
@@ -147,11 +144,6 @@ class fvGP(GP):
147
144
  False. Note, the training will always use Cholesky or LU decomposition instead of the
148
145
  inverse for stability reasons. Storing the inverse is
149
146
  a good option when the dataset is not too large and the posterior covariance is heavily used.
150
- online : bool, optional
151
- A new setting that allows optimization for online applications. Default=False. If True,
152
- calc_inv will be set to true, and the inverse and the logdet() of full dataset will only be computed
153
- once in the beginning and after that only updated. This leads to a significant speedup because
154
- the most costly aspects of a GP are entirely avoided.
155
147
  ram_economy : bool, optional
156
148
  Only of interest if the gradient and/or Hessian of the marginal log_likelihood
157
149
  is/are used for the training.
@@ -196,6 +188,74 @@ class fvGP(GP):
196
188
  logdet(K+V)
197
189
  likelihood.V : np.ndarray
198
190
  the noise covariance matrix
191
+
192
+
193
+ This class inherits all capabilities from :py:class:`fvgp.GP`.
194
+ Check there for a full list of capabilities. Here are the most important.
195
+
196
+ Base-GP Methods:
197
+
198
+ :py:meth:`fvgp.GP.train`
199
+
200
+ :py:meth:`fvgp.GP.train_async`
201
+
202
+ :py:meth:`fvgp.GP.stop_training`
203
+
204
+ :py:meth:`fvgp.GP.kill_training`
205
+
206
+ :py:meth:`fvgp.GP.update_hyperparameters`
207
+
208
+ :py:meth:`fvgp.GP.set_hyperparameters`
209
+
210
+ :py:meth:`fvgp.GP.get_hyperparameters`
211
+
212
+ Posterior Evaluations:
213
+
214
+ :py:meth:`fvgp.GP.posterior_mean`
215
+
216
+ :py:meth:`fvgp.GP.posterior_covariance`
217
+
218
+ :py:meth:`fvgp.GP.posterior_mean_grad`
219
+
220
+ :py:meth:`fvgp.GP.posterior_covariance_grad`
221
+
222
+ :py:meth:`fvgp.GP.joint_gp_prior`
223
+
224
+ :py:meth:`fvgp.GP.joint_gp_prior_grad`
225
+
226
+ :py:meth:`fvgp.GP.gp_entropy`
227
+
228
+ :py:meth:`fvgp.GP.gp_entropy_grad`
229
+
230
+ :py:meth:`fvgp.GP.gp_kl_div`
231
+
232
+ :py:meth:`fvgp.GP.gp_kl_div_grad`
233
+
234
+ :py:meth:`fvgp.GP.gp_mutual_information`
235
+
236
+ :py:meth:`fvgp.GP.gp_total_correlation`
237
+
238
+ :py:meth:`fvgp.GP.gp_relative_information_entropy`
239
+
240
+ :py:meth:`fvgp.GP.gp_relative_information_entropy_set`
241
+
242
+ :py:meth:`fvgp.GP.posterior_probability`
243
+
244
+ :py:meth:`fvgp.GP.posterior_probability_grad`
245
+
246
+ Validation Methods:
247
+
248
+ :py:meth:`fvgp.GP.crps`
249
+
250
+ :py:meth:`fvgp.GP.rmse`
251
+
252
+ :py:meth:`fvgp.GP.make_2d_x_pred`
253
+
254
+ :py:meth:`fvgp.GP.make_1d_x_pred`
255
+
256
+ :py:meth:`fvgp.GP.log_likelihood`
257
+
258
+ :py:meth:`fvgp.GP.test_log_likelihood_gradient`
199
259
  """
200
260
 
201
261
  def __init__(
@@ -216,13 +276,14 @@ class fvGP(GP):
216
276
  gp2Scale_dask_client=None,
217
277
  gp2Scale_batch_size=10000,
218
278
  calc_inv=False,
219
- online=False,
220
279
  ram_economy=False,
221
280
  args=None,
222
281
  info=False,
223
282
  ):
224
283
 
225
- if isinstance(x_data, np.ndarray): self.orig_input_space_dim = x_data.shape[1]
284
+ if isinstance(x_data, np.ndarray):
285
+ assert np.ndim(x_data) == 2
286
+ self.orig_input_space_dim = x_data.shape[1]
226
287
  else: self.orig_input_space_dim = 1
227
288
 
228
289
  self.output_num = y_data.shape[1]
@@ -262,7 +323,6 @@ class fvGP(GP):
262
323
  gp2Scale_dask_client=gp2Scale_dask_client,
263
324
  gp2Scale_batch_size=gp2Scale_batch_size,
264
325
  calc_inv=calc_inv,
265
- online=online,
266
326
  ram_economy=ram_economy,
267
327
  args=args,
268
328
  info=info)
@@ -17,9 +17,7 @@ import sys
17
17
  # TODO: search below "TODO"
18
18
  # neither minres nor random logdet are doing a good job in gp2Scale,
19
19
  # cg is better but we might need a preconditioner , maybe a large LU?
20
- # the mcmc in default mode should not need proposal distributions explicitly
21
- # reshape posteriors if x_out
22
- # when are we really using gpu vs cpu as compute_device
20
+ # variational inference in fvgp
23
21
 
24
22
 
25
23
  class GP:
@@ -143,14 +141,6 @@ class GP:
143
141
  False. Note, the training will always use Cholesky or LU decomposition instead of the
144
142
  inverse for stability reasons. Storing the inverse is
145
143
  a good option when the dataset is not too large and the posterior covariance is heavily used.
146
- online : bool, optional
147
- A new setting that allows optimization for online applications. Default=False. If True,
148
- the inverse (if calc_inv is True), or the Cholesky factors (if calc_inv is False) and the logdet()
149
- will only be computed
150
- once in the beginning and after that only updated. This leads to a significant speedup because
151
- the most costly aspects of a GP are entirely avoided. A good indicator whether `online` is a good choice is
152
- the `append` option in the gp update. You always append data, never overwrite, online should be True
153
- to save some time.
154
144
  ram_economy : bool, optional
155
145
  Only of interest if the gradient and/or Hessian of the marginal log_likelihood is/are used for the training.
156
146
  If True, components of the derivative of the marginal log-likelihood are
@@ -169,7 +159,6 @@ class GP:
169
159
  info : bool, optional
170
160
  Provides a way how to see the progress of gp2Scale, Default is False
171
161
 
172
-
173
162
  Attributes
174
163
  ----------
175
164
  x_data : np.ndarray
@@ -210,7 +199,6 @@ class GP:
210
199
  gp2Scale_dask_client=None,
211
200
  gp2Scale_batch_size=10000,
212
201
  calc_inv=False,
213
- online=False,
214
202
  ram_economy=False,
215
203
  args=None,
216
204
  info=False
@@ -222,6 +210,8 @@ class GP:
222
210
  logger.remove()
223
211
  logger.enable("fvgp")
224
212
  logger.add(sys.stdout, filter="fvgp", level="INFO")
213
+ else:
214
+ logger.disable("fvgp")
225
215
  self.calc_inv = calc_inv
226
216
  self.gp2Scale = gp2Scale
227
217
  self.gp2Scale_dask_client = gp2Scale_dask_client
@@ -300,7 +290,6 @@ class GP:
300
290
  self.data,
301
291
  self.prior,
302
292
  self.likelihood,
303
- online=online,
304
293
  calc_inv=calc_inv,
305
294
  info=info,
306
295
  gp2Scale=gp2Scale,
@@ -369,7 +358,7 @@ class GP:
369
358
  self.prior.hyperparameters)
370
359
 
371
360
  # update marginal density
372
- self.marginal_density.update_data()
361
+ self.marginal_density.update_data(append)
373
362
  ##########################################
374
363
  self.x_data = self.data.x_data
375
364
  self.y_data = self.data.y_data
@@ -771,9 +760,9 @@ class GP:
771
760
  a constraint during training. The default is None which means the initialized or trained hyperparameters
772
761
  are used.
773
762
  x_out : np.ndarray, optional
774
- Output coordinates in case of multitask GP use; a numpy array of size (N x L),
775
- where N is the number of output points,
776
- and L is the dimensionality of the output space (most often 1).
763
+ Output coordinates in case of multitask GP use; a numpy array of size (N),
764
+ where N is the number evaluation points in the output direction.
765
+ Usually this is np.ndarray([0,1,2,...]).
777
766
 
778
767
  Return
779
768
  ------
@@ -796,9 +785,9 @@ class GP:
796
785
  a constraint during training. The default is None which means the initialized or trained hyperparameters
797
786
  are used.
798
787
  x_out : np.ndarray, optional
799
- Output coordinates in case of multitask GP use; a numpy array of size (N x L),
800
- where N is the number of output points,
801
- and L is the dimensionality of the output space.
788
+ Output coordinates in case of multitask GP use; a numpy array of size (N),
789
+ where N is the number evaluation points in the output direction.
790
+ Usually this is np.ndarray([0,1,2,...]).
802
791
  direction : int, optional
803
792
  Direction of derivative, If None (default) the whole gradient will be computed.
804
793
 
@@ -820,9 +809,9 @@ class GP:
820
809
  A numpy array of shape (V x D), interpreted as an array of input point positions or a list for
821
810
  GPs on non-Euclidean input spaces.
822
811
  x_out : np.ndarray, optional
823
- Output coordinates in case of multitask GP use; a numpy array of size (N x L),
824
- where N is the number of output points,
825
- and L is the dimensionality of the output space.
812
+ Output coordinates in case of multitask GP use; a numpy array of size (N),
813
+ where N is the number evaluation points in the output direction.
814
+ Usually this is np.ndarray([0,1,2,...]).
826
815
  variance_only : bool, optional
827
816
  If True the computation of the posterior covariance matrix is avoided which can save compute time.
828
817
  In that case the return will only provide the variance at the input points.
@@ -847,9 +836,9 @@ class GP:
847
836
  A numpy array of shape (V x D), interpreted as an array of input point positions or a list for
848
837
  GPs on non-Euclidean input spaces.
849
838
  x_out : np.ndarray, optional
850
- Output coordinates in case of multitask GP use; a numpy array of size (N x L),
851
- where N is the number of output points,
852
- and L is the dimensionality of the output space.
839
+ Output coordinates in case of multitask GP use; a numpy array of size (N),
840
+ where N is the number evaluation points in the output direction.
841
+ Usually this is np.ndarray([0,1,2,...]).
853
842
  direction : int, optional
854
843
  Direction of derivative, If None (default) the whole gradient will be computed.
855
844
 
@@ -870,9 +859,9 @@ class GP:
870
859
  A numpy array of shape (V x D), interpreted as an array of input point positions or a list for
871
860
  GPs on non-Euclidean input spaces.
872
861
  x_out : np.ndarray, optional
873
- Output coordinates in case of multitask GP use; a numpy array of size (N x L),
874
- where N is the number of output points,
875
- and L is the dimensionality of the output space.
862
+ Output coordinates in case of multitask GP use; a numpy array of size (N),
863
+ where N is the number evaluation points in the output direction.
864
+ Usually this is np.ndarray([0,1,2,...]).
876
865
 
877
866
  Return
878
867
  ------
@@ -894,9 +883,9 @@ class GP:
894
883
  direction : int
895
884
  Direction of derivative.
896
885
  x_out : np.ndarray, optional
897
- Output coordinates in case of multitask GP use; a numpy array of size (N x L),
898
- where N is the number of output points,
899
- and L is the dimensionality of the output space.
886
+ Output coordinates in case of multitask GP use; a numpy array of size (N),
887
+ where N is the number evaluation points in the output direction.
888
+ Usually this is np.ndarray([0,1,2,...]).
900
889
 
901
890
  Return
902
891
  ------
@@ -954,9 +943,9 @@ class GP:
954
943
  direction : int
955
944
  Direction of derivative.
956
945
  x_out : np.ndarray, optional
957
- Output coordinates in case of multitask GP use; a numpy array of size (N x L),
958
- where N is the number of output points,
959
- and L is the dimensionality of the output space.
946
+ Output coordinates in case of multitask GP use; a numpy array of size (N),
947
+ where N is the number evaluation points in the output direction.
948
+ Usually this is np.ndarray([0,1,2,...]).
960
949
 
961
950
  Return
962
951
  ------
@@ -1012,9 +1001,9 @@ class GP:
1012
1001
  comp_cov : np.ndarray
1013
1002
  Comparison covariance matrix for KL divergence. shape(comp_cov) = (len(x_pred),len(x_pred))
1014
1003
  x_out : np.ndarray, optional
1015
- Output coordinates in case of multitask GP use; a numpy array of size (N x L),
1016
- where N is the number of output points,
1017
- and L is the dimensionality of the output space.
1004
+ Output coordinates in case of multitask GP use; a numpy array of size (N),
1005
+ where N is the number evaluation points in the output direction.
1006
+ Usually this is np.ndarray([0,1,2,...]).
1018
1007
 
1019
1008
  Return
1020
1009
  -------
@@ -1039,9 +1028,9 @@ class GP:
1039
1028
  direction: int
1040
1029
  The direction in which the gradient will be computed.
1041
1030
  x_out : np.ndarray, optional
1042
- Output coordinates in case of multitask GP use; a numpy array of size (N x L),
1043
- where N is the number of output points,
1044
- and L is the dimensionality of the output space.
1031
+ Output coordinates in case of multitask GP use; a numpy array of size (N),
1032
+ where N is the number evaluation points in the output direction.
1033
+ Usually this is np.ndarray([0,1,2,...]).
1045
1034
 
1046
1035
  Return
1047
1036
  ------
@@ -1084,9 +1073,9 @@ class GP:
1084
1073
  A numpy array of shape (V x D), interpreted as an array of input point positions or a list for
1085
1074
  GPs on non-Euclidean input spaces.
1086
1075
  x_out : np.ndarray, optional
1087
- Output coordinates in case of multitask GP use; a numpy array of size (N x L),
1088
- where N is the number of output points,
1089
- and L is the dimensionality of the output space.
1076
+ Output coordinates in case of multitask GP use; a numpy array of size (N),
1077
+ where N is the number evaluation points in the output direction.
1078
+ Usually this is np.ndarray([0,1,2,...]).
1090
1079
 
1091
1080
  Return
1092
1081
  -------
@@ -1111,9 +1100,9 @@ class GP:
1111
1100
  A numpy array of shape (V x D), interpreted as an array of input point positions or a list for
1112
1101
  GPs on non-Euclidean input spaces.
1113
1102
  x_out : np.ndarray, optional
1114
- Output coordinates in case of multitask GP use; a numpy array of size (N x L),
1115
- where N is the number of output points,
1116
- and L is the dimensionality of the output space.
1103
+ Output coordinates in case of multitask GP use; a numpy array of size (N),
1104
+ where N is the number evaluation points in the output direction.
1105
+ Usually this is np.ndarray([0,1,2,...]).
1117
1106
 
1118
1107
  Return
1119
1108
  -------
@@ -1136,9 +1125,9 @@ class GP:
1136
1125
  A numpy array of shape (V x D), interpreted as an array of input point positions or a list for
1137
1126
  GPs on non-Euclidean input spaces.
1138
1127
  x_out : np.ndarray, optional
1139
- Output coordinates in case of multitask GP use; a numpy array of size (N x L),
1140
- where N is the number of output points,
1141
- and L is the dimensionality of the output space.
1128
+ Output coordinates in case of multitask GP use; a numpy array of size (N),
1129
+ where N is the number evaluation points in the output direction.
1130
+ Usually this is np.ndarray([0,1,2,...]).
1142
1131
 
1143
1132
  Return
1144
1133
  -------
@@ -1163,9 +1152,9 @@ class GP:
1163
1152
  A numpy array of shape (V x D), interpreted as an array of input point positions or a list for
1164
1153
  GPs on non-Euclidean input spaces.
1165
1154
  x_out : np.ndarray, optional
1166
- Output coordinates in case of multitask GP use; a numpy array of size (N x L),
1167
- where N is the number of output points,
1168
- and L is the dimensionality of the output space.
1155
+ Output coordinates in case of multitask GP use; a numpy array of size (N),
1156
+ where N is the number evaluation points in the output direction.
1157
+ Usually this is np.ndarray([0,1,2,...]).
1169
1158
 
1170
1159
  Return
1171
1160
  -------
@@ -1190,9 +1179,9 @@ class GP:
1190
1179
  comp_cov: np.nparray
1191
1180
  Covariance matrix, in R^{len(x_pred) times len(x_pred)}
1192
1181
  x_out : np.ndarray, optional
1193
- Output coordinates in case of multitask GP use; a numpy array of size (N x L),
1194
- where N is the number of output points,
1195
- and L is the dimensionality of the output space.
1182
+ Output coordinates in case of multitask GP use; a numpy array of size (N),
1183
+ where N is the number evaluation points in the output direction.
1184
+ Usually this is np.ndarray([0,1,2,...]).
1196
1185
 
1197
1186
  Return
1198
1187
  -------
@@ -1218,9 +1207,9 @@ class GP:
1218
1207
  direction : int
1219
1208
  The direction to compute the gradient in.
1220
1209
  x_out : np.ndarray, optional
1221
- Output coordinates in case of multitask GP use; a numpy array of size (N x L),
1222
- where N is the number of output points,
1223
- and L is the dimensionality of the output space.
1210
+ Output coordinates in case of multitask GP use; a numpy array of size (N),
1211
+ where N is the number evaluation points in the output direction.
1212
+ Usually this is np.ndarray([0,1,2,...]).
1224
1213
 
1225
1214
  Return
1226
1215
  -------
@@ -1229,58 +1218,6 @@ class GP:
1229
1218
  given the GP posterior at a given point.
1230
1219
  """
1231
1220
  return self.posterior.posterior_probability_grad(x_pred, comp_mean, comp_cov, direction, x_out=x_out)
1232
-
1233
- ##################################################################################
1234
- ##################################################################################
1235
- ##################################################################################
1236
- ##################################################################################
1237
- ######################Compute#Covariance#Matrix###################################
1238
- ##################################################################################
1239
- ##################################################################################
1240
- def _normalize(self, data):
1241
- min_d = np.min(data)
1242
- max_d = np.max(data)
1243
- data = (data - min_d) / (max_d - min_d)
1244
- return data, min_d, max_d
1245
-
1246
- def normalize_y_data(self, y_data):
1247
- """
1248
- Function to normalize the y_data.
1249
- The user is responsible to normalize the noise accordingly.
1250
- This function will not update the object instance.
1251
-
1252
- Parameters
1253
- ----------
1254
- y_data : np.ndarray
1255
- Numpy array of shape (U).
1256
- """
1257
- return self._normalize(y_data)
1258
-
1259
- def _normalize_x_data(self, x_data):
1260
- n_x = np.empty(x_data.shape)
1261
- x_min = np.empty((len(x_data)))
1262
- x_max = np.empty((len(x_data)))
1263
- for i in range(len(self.x_data[0])):
1264
- n_x[:, i], x_min[i], x_max[i] = self._normalize(x_data[:, i])
1265
- return n_x, x_min, x_max
1266
-
1267
- def _normalize_x_pred(self, x_pred, x_min, x_max):
1268
- new_x_pred = np.empty(x_pred.shape)
1269
- for i in range(len(x_pred[0])):
1270
- new_x_pred[:, i] = (x_pred[:, i] - x_min[i]) / (x_max[i] - x_min[i])
1271
- return new_x_pred
1272
-
1273
- def _cartesian_product_noneuclid(self, x, y):
1274
- """
1275
- Input x,y have to be 2d numpy arrays
1276
- The return is the cartesian product of the two sets
1277
- """
1278
- res = []
1279
- for i in range(len(y)):
1280
- for j in range(len(x)):
1281
- res.append([x[j], y[i]])
1282
- return res
1283
-
1284
1221
  ####################################################################################
1285
1222
  ####################################################################################
1286
1223
  #######################VALIDATION###################################################
@@ -3,6 +3,7 @@ import time
3
3
  import warnings
4
4
  from loguru import logger
5
5
 
6
+
6
7
  ## --------------------------------------------------------------------- ##
7
8
  # A generic Metropolis sampler. You have to supply the log likelihood #
8
9
  # function, which need not really be a likelihood function at all. #
@@ -43,18 +44,14 @@ class gpMCMC:
43
44
  Parameters
44
45
  ----------
45
46
  log_likelihood_function : Callable
46
- The log of the likelihood to be sampled.
47
- dim : int
48
- The dimensionality of the space.
49
- prior_function : Callable
47
+ The log of the likelihood to be sampled. Function of the form def likelihood(x,args) that return a scalar.
48
+ prior_function : callable
50
49
  Function to query for the prior probability of form: func(x, obj), where
51
50
  x is the current vector and obj is this gpMCMC object instance.
52
51
  proposal_distributions : iterable
53
52
  A list of object instances of ProposalDistribution.
54
53
  args : Any, optional
55
54
  Arguments that will be communicated to all Callables.
56
- bounds : np.ndarray, optional
57
- Bounds for MCMC. Not needed but encouraged. Default is [-1e6,1e6] in all directions.
58
55
 
59
56
 
60
57
  Attributes
@@ -66,28 +63,19 @@ class gpMCMC:
66
63
 
67
64
  def __init__(self,
68
65
  log_likelihood_function,
69
- dim,
70
66
  prior_function,
71
67
  proposal_distributions,
72
- args=None,
73
- bounds=None,
68
+ args=None
74
69
  ):
75
70
  self.log_likelihood_function = log_likelihood_function
76
- self.dim = dim
77
71
  self.prior_function = prior_function
78
72
  self.proposal_distributions = proposal_distributions
79
73
  self.args = args
80
74
  self.trace = None
81
75
  self.mcmc_info = None
82
- if bounds is None:
83
- self.bounds = np.zeros((dim, 2))
84
- self.bounds[:] = np.array([-1e6, 1e6])
85
- else: self.bounds = bounds
86
- warnings.warn("Thank you for trying our new MCMC. While we tested it quite a lot it's still in\n \
87
- its experimental stage. Use caution.")
88
-
89
- def run_mcmc(self, n_updates=10000,
90
- x0=None,
76
+
77
+ def run_mcmc(self, *, x0,
78
+ n_updates=10000,
91
79
  info=False,
92
80
  break_condition=None,
93
81
  run_in_every_iteration=None):
@@ -97,12 +85,12 @@ class gpMCMC:
97
85
 
98
86
  Parameters
99
87
  ----------
100
- n_updates: int, optional
101
- The log of the likelihood to be sampled.
102
88
  x0 : np.ndarray
103
89
  Starting point of the mcmc.
90
+ n_updates: int, optional
91
+ The log of the likelihood to be sampled.
104
92
  info : bool
105
- Whether to print information is the mcmc runs (use logger).
93
+ Whether to print information about the mcmc iterations (using logger).
106
94
  break_condition : callable or string or None
107
95
  A break condition that specified when the mcmc is terminated. If None,
108
96
  mcmc will run until `n_updates` is reached. If callable will get the mcmc object instance as
@@ -116,11 +104,9 @@ class gpMCMC:
116
104
  trace information : dict
117
105
  Mean and variances are presented of the last 1% of x. All other returns consider all x.
118
106
  x here are all the accepted positions in the MCMC.
119
-
120
107
  """
121
108
  start_time = time.time()
122
109
  n_updates = max(n_updates, 2)
123
- if x0 is None: x0 = np.ones(self.dim)
124
110
  if not isinstance(x0, np.ndarray): raise Exception("x0 is not a numpy array")
125
111
  if np.ndim(x0) != 1: raise Exception("x0 is not a vector in MCMC")
126
112
  if break_condition is None:
@@ -128,7 +114,8 @@ class gpMCMC:
128
114
  return False
129
115
  elif break_condition == "default":
130
116
  break_condition = self._default_break_condition
131
- else: raise Exception("No valid input for break condition provided!")
117
+ else:
118
+ raise Exception("No valid input for break condition provided!")
132
119
  if run_in_every_iteration is None: run_in_every_iteration = lambda a: False
133
120
 
134
121
  self.trace = {"f(x)": [], "x": [], "time stamp": []}
@@ -184,18 +171,20 @@ class gpMCMC:
184
171
  abs_diff = abs(latest_mean - earlier_mean)
185
172
  max_index = np.argmax(abs_diff)
186
173
  ratio = (abs_diff[max_index] / abs(latest_mean[max_index])) * 100.
187
- if ratio < 0.1: return True
188
- else: return False
189
- else: return False
174
+ if ratio < 0.1:
175
+ return True
176
+ else:
177
+ return False
178
+ else:
179
+ return False
190
180
 
191
181
  ###############################################################
192
182
  def _jump(self, x_old, obj, prior_eval, likelihood):
193
183
  x_star = x_old.copy()
194
- assert callable(obj.prop_dist)
184
+ assert callable(obj.proposal_dist)
195
185
 
196
186
  # get proposed x (x_star)
197
- x_star[obj.indices] = obj.prop_dist(x_old[obj.indices].copy(), obj)
198
-
187
+ x_star[obj.indices] = obj.proposal_dist(x_old[obj.indices].copy(), x_old, obj)
199
188
  # evaluate prior(x_star)
200
189
  prior_evaluation_x_star = self.prior_function(x_star, self.args)
201
190
  jump_trace = 0.
@@ -207,7 +196,7 @@ class gpMCMC:
207
196
  metr_ratio = np.exp(prior_evaluation_x_star + likelihood_star -
208
197
  prior_eval - likelihood)
209
198
  if np.isnan(metr_ratio): metr_ratio = 0.
210
- if metr_ratio > np.random.uniform(0, 1, 1):
199
+ if metr_ratio > np.random.uniform(0, 1, 1) or obj.auto_accept:
211
200
  x = x_star
212
201
  prior_eval = prior_evaluation_x_star
213
202
  likelihood = likelihood_star
@@ -219,19 +208,19 @@ class gpMCMC:
219
208
 
220
209
  return x, prior_eval, likelihood, jump_trace
221
210
 
222
- ###############################################################
223
-
224
211
 
225
212
  ###############################################################
226
213
  class ProposalDistribution:
227
- def __init__(self, prop_dist,
214
+ def __init__(self,
228
215
  indices,
216
+ proposal_dist="normal",
229
217
  init_prop_Sigma=None,
230
- adapt_callable=None,
218
+ adapt_callable="normal",
231
219
  r_opt=.234,
232
220
  c_0=10,
233
221
  c_1=.8,
234
222
  K=10,
223
+ auto_accept=False,
235
224
  adapt_cov=True,
236
225
  prop_args=None):
237
226
  """
@@ -239,45 +228,48 @@ class ProposalDistribution:
239
228
 
240
229
  Parameters
241
230
  ----------
242
- prop_dist : Callable
231
+ indices : iterable of int
232
+ The indices of the parameters that should be drawn from this proposal distribution.
233
+ proposal_dist : callable, optional
243
234
  A callable to calculate the proposal distribution evaluation.
244
- It is defined as `def name(x, obj)`, where `obj` is a `proposal_distribution`
235
+ It is defined as `def name(x, para, obj)`, where `obj` is a `proposal_distribution`
245
236
  object instance. The function should return a new proposal for `x`.
246
- indices : iterable of int
247
- The indices that should be drawn from this proposal distribution.
237
+ para are all other parameters. Default is a normal distribution with the default
238
+ `init_prop_sigma`.
248
239
  init_prop_Sigma : np.ndarray, optional
249
240
  If the proposal distribution is normal this is the covariance of the initial proposal distribution.
250
241
  It will be updated if adapt_callable = `normal` or a callable.
251
242
  While it is optional to provide it, it is highly recommended to do so.
252
243
  A warning will be printed in that case. A good rule of thumb
253
- is to orient yourself on the size of your domain.
244
+ is to orient yourself on the size of your domain. The default is the identity matrix.
254
245
  adapt_callable : Callable or None or string, optional
255
246
  A callable to adapt the distribution. The default is None which means
256
247
  the proposal distribution will not be adapted.
257
- Use `normal` for the default adaption procedure for normal distributions.
248
+ Use `normal` (default) for the default adaption procedure for normal distributions.
258
249
  The callable should be defined as `def adapt(index, mcmc_obj)` and not return anything
259
- but update the `mcmc_obj.prop_args`. Note, any adapt function will have to be well thought through.
250
+ but update the `ProposalDistribution.prop_args` attribute. Note, any
251
+ adapt function will have to be well thought through.
260
252
  Most adapt functions will not lead to a stationary final distributions. Use with caution.
261
253
  prop_args : Any, optional
262
- Arguments that will be available as obj attribute in `prop_dist`and `adapt_callable`.
254
+ Arguments that will be available as obj attribute in `proposal_dist`and `adapt_callable`.
263
255
 
264
256
  """
265
- # consider:
266
- # axis_std = np.linalg.norm(hps_bounds, axis=1) / 10.
267
- # init_s = np.diag(axis_std ** 2)
268
-
269
- self.prop_dist = prop_dist
270
257
  self.indices = indices
271
258
  self.r_opt = r_opt
272
259
  self.c_0 = c_0
273
260
  self.c_1 = c_1
274
261
  self.K = K
262
+ self.auto_accept = auto_accept
275
263
  self.adapt_cov = adapt_cov
276
264
  dim = len(indices)
277
265
  self.jump_trace = []
278
- if adapt_callable == "normal" and init_prop_Sigma is None:
266
+ if proposal_dist == "normal": self.proposal_dist = self.normal_proposal_dist
267
+ elif callable(proposal_dist): self.proposal_dist = proposal_dist
268
+ else: raise Exception("No proposal distribution specified!")
269
+
270
+ if proposal_dist == "normal" and init_prop_Sigma is None:
279
271
  init_prop_Sigma = np.identity(dim)
280
- warnings.warn("You are using the normal adaption mechanism for normal distributions\n \
272
+ warnings.warn("You are using the normal proposal distribution for normal distributions\n \
281
273
  but did not provide `init_prop_sigma`. This can lead to slow convergence")
282
274
 
283
275
  if callable(adapt_callable):
@@ -296,7 +288,12 @@ class ProposalDistribution:
296
288
  self.prop_args["prop_Sigma"] = init_prop_Sigma
297
289
  self.prop_args["sigma_m"] = 2.4 ** 2 / dim
298
290
 
299
- #########################################################
291
+ #########################################################
292
+ def normal_proposal_dist(self, x, hps, obj):
293
+ cov = obj.prop_args["prop_Sigma"]
294
+ proposal_hps = np.random.multivariate_normal(
295
+ mean=x, cov=cov, size=1).reshape(len(x))
296
+ return proposal_hps
300
297
 
301
298
  def _adapt(self, end, mcmc_obj):
302
299
  K = self.K
@@ -320,34 +317,3 @@ class ProposalDistribution:
320
317
 
321
318
  def _no_adapt(self, end, mcmc_obj):
322
319
  return
323
-
324
-
325
- ###############################################################
326
- ###############################################################
327
- ###############################################################
328
- ###############################################################
329
- def out_of_bounds(x, bounds):
330
- for i in range(len(x)):
331
- if x[i] < bounds[i, 0] or x[i] > bounds[i, 1]:
332
- return True
333
- return False
334
-
335
-
336
- def project_onto_bounds(x, bounds): # pragma: no cover
337
- for i in range(len(x)):
338
- if x[i] < bounds[i, 0]: x[i] = bounds[i, 0]
339
- if x[i] > bounds[i, 1]: x[i] = bounds[i, 1]
340
- return x
341
-
342
-
343
- def in_bounds(v, bounds): # pragma: no cover
344
- for i in range(len(v)):
345
- if v[i] < bounds[i, 0] or v[i] > bounds[i, 1]: return False
346
- return True
347
-
348
-
349
- def prior_func(theta, bounds): # pragma: no cover
350
- if in_bounds(theta, bounds):
351
- return 0.
352
- else:
353
- return -np.inf
@@ -11,7 +11,6 @@ class GPMarginalDensity:
11
11
  data_obj,
12
12
  prior_obj,
13
13
  likelihood_obj,
14
- online=False,
15
14
  calc_inv=False,
16
15
  info=False,
17
16
  gp2Scale=False,
@@ -21,15 +20,13 @@ class GPMarginalDensity:
21
20
  self.prior_obj = prior_obj
22
21
  self.likelihood_obj = likelihood_obj
23
22
  self.calc_inv = calc_inv
24
- self.online = online
25
23
  self.info = info
26
24
  self.y_data = data_obj.y_data
27
25
  self.gp2Scale = gp2Scale
28
26
  self.compute_device = compute_device
29
27
  if self.gp2Scale:
30
- self.online = False
31
28
  self.calc_inv = False
32
- warnings.warn("gp2Scale use forbids calc_inv=True or online=True. Both have been set to False")
29
+ warnings.warn("gp2Scale use forbids calc_inv=True; it has been set to False")
33
30
  self.KVlinalg = KVlinalg(info, compute_device)
34
31
  K, V, m = self._get_KVm()
35
32
  if self.gp2Scale: mode = self._set_gp2Scale_mode(K)
@@ -39,11 +36,12 @@ class GPMarginalDensity:
39
36
  self.KVinvY = self._set_KVinvY(K, V, m, mode)
40
37
 
41
38
  ##################################################################
42
- def update_data(self):
39
+ def update_data(self, append):
43
40
  """Update the marginal PDF when the data has changed in data likelihood or prior objects"""
44
41
  self.y_data = self.data_obj.y_data
45
42
  K, V, m = self._get_KVm()
46
- self.KVinvY = self._update_KVinvY(K, V, m)
43
+ if append: self.KVinvY = self._update_KVinvY(K, V, m)
44
+ else: self.KVinvY = self._set_KVinvY(K, V, m, self.KVlinalg.mode)
47
45
 
48
46
  def update_hyperparameters(self):
49
47
  """Update the marginal PDF when if hyperparameters have changed"""
@@ -1,31 +1,9 @@
1
1
  import numpy as np
2
- from .gp_lin_alg import solve
3
2
  from loguru import logger
4
- import warnings
5
3
  from scipy.sparse import issparse
6
4
  from .gp_lin_alg import *
7
5
 
8
6
 
9
- def cartesian_product(x, y):
10
- """
11
- Input x,y have to be 2d numpy arrays
12
- The return is the cartesian product of the two sets
13
- """
14
- res = []
15
- if isinstance(x, list) or isinstance(y, list):
16
- for i in range(len(y)):
17
- for j in range(len(x)):
18
- res.append((y[i], x[j]))
19
- return res
20
- elif isinstance(x, np.ndarray) and isinstance(y, np.ndarray):
21
- for i in range(len(y)):
22
- for j in range(len(x)):
23
- res.append(np.append(x[j], y[i]))
24
- return np.array(res)
25
- else:
26
- raise Exception("Cartesian product out of options")
27
-
28
-
29
7
  class GPposterior:
30
8
  def __init__(self,
31
9
  data_obj,
@@ -53,13 +31,15 @@ class GPposterior:
53
31
  hyperparameters = self.prior_obj.hyperparameters
54
32
 
55
33
  self._perform_input_checks(x_pred, x_out)
34
+ x_orig = x_pred.copy()
56
35
  if x_out is not None: x_pred = self.cartesian_product(x_pred, x_out)
57
36
 
58
37
  k = self.kernel(x_data, x_pred, hyperparameters, self)
59
38
  A = k.T @ KVinvY
60
39
  posterior_mean = self.mean_function(x_pred, hyperparameters, self) + A
40
+ if x_out is not None: posterior_mean = posterior_mean.reshape(len(x_orig), len(x_out), order='F')
61
41
 
62
- return {"x": x_pred,
42
+ return {"x": x_orig,
63
43
  "f(x)": posterior_mean}
64
44
 
65
45
  def posterior_mean_grad(self, x_pred, hyperparameters=None, x_out=None, direction=None):
@@ -75,6 +55,7 @@ class GPposterior:
75
55
  hyperparameters = self.prior_obj.hyperparameters
76
56
 
77
57
  self._perform_input_checks(x_pred, x_out)
58
+ x_orig = x_pred.copy()
78
59
  if x_out is not None: x_pred = self.cartesian_product(x_pred, x_out)
79
60
 
80
61
  f = self.mean_function(x_pred, hyperparameters, self)
@@ -83,20 +64,23 @@ class GPposterior:
83
64
  x1 = np.array(x_pred)
84
65
  x1[:, direction] = x1[:, direction] + eps
85
66
  mean_der = (self.mean_function(x1, hyperparameters, self) - f) / eps
86
- k = self.kernel(x_data, x_pred, hyperparameters, self)
67
+ #k = self.kernel(x_data, x_pred, hyperparameters, self)
87
68
  k_g = self.d_kernel_dx(x_pred, x_data, direction, hyperparameters)
88
69
  posterior_mean_grad = mean_der + (k_g @ KVinvY)
70
+ if x_out is not None: posterior_mean_grad = posterior_mean_grad.reshape(len(x_orig), len(x_out), order='F')
89
71
  else:
90
- posterior_mean_grad = np.zeros(x_pred.shape)
91
- for direction in range(len(x_pred[0])):
72
+ posterior_mean_grad = np.zeros((len(x_pred), x_orig.shape[1]))
73
+ for direction in range(len(x_orig[0])):
92
74
  x1 = np.array(x_pred)
93
75
  x1[:, direction] = x1[:, direction] + eps
94
76
  mean_der = (self.mean_function(x1, hyperparameters, self) - f) / eps
95
77
  k_g = self.d_kernel_dx(x_pred, x_data, direction, hyperparameters)
96
78
  posterior_mean_grad[:, direction] = mean_der + (k_g @ KVinvY)
97
79
  direction = "ALL"
80
+ if x_out is not None:
81
+ posterior_mean_grad = posterior_mean_grad.reshape(len(x_orig), len(x_orig[0]), len(x_out), order='F')
98
82
 
99
- return {"x": x_pred,
83
+ return {"x": x_orig,
100
84
  "direction": direction,
101
85
  "df/dx": posterior_mean_grad}
102
86
 
@@ -105,6 +89,7 @@ class GPposterior:
105
89
  x_data = self.data_obj.x_data.copy()
106
90
 
107
91
  self._perform_input_checks(x_pred, x_out)
92
+ x_orig = x_pred.copy()
108
93
  if x_out is not None: x_pred = self.cartesian_product(x_pred, x_out)
109
94
 
110
95
  k = self.kernel(x_data, x_pred, self.prior_obj.hyperparameters, self)
@@ -140,35 +125,45 @@ class GPposterior:
140
125
  else:
141
126
  warnings.warn("Noise could not be added, you did not provide a noise callable at initialization")
142
127
 
143
- return {"x": x_pred,
128
+ if x_out is not None:
129
+ v = v.reshape(len(x_orig), len(x_out), order='F')
130
+ if S is not None: S = S.reshape(len(x_orig), len(x_orig), len(x_out), len(x_out), order='F')
131
+
132
+ return {"x": x_orig,
144
133
  "v(x)": v,
145
134
  "S": S}
146
135
 
147
136
  def posterior_covariance_grad(self, x_pred, x_out=None, direction=None):
148
137
  x_data = self.data_obj.x_data.copy()
149
138
  self._perform_input_checks(x_pred, x_out)
139
+ x_orig = x_pred.copy()
150
140
  if x_out is not None: x_pred = self.cartesian_product(x_pred, x_out)
151
141
 
152
142
  k = self.kernel(x_data, x_pred, self.prior_obj.hyperparameters, self)
153
143
  k_covariance_prod = self.marginal_density_obj.KVlinalg.solve(k)
154
144
  if direction is not None:
155
145
  k_g = self.d_kernel_dx(x_pred, x_data, direction, self.prior_obj.hyperparameters).T
156
- kk = self.kernel(x_pred, x_pred, self.prior_obj.hyperparameters, self)
146
+ #kk = self.kernel(x_pred, x_pred, self.prior_obj.hyperparameters, self)
157
147
  x1 = np.array(x_pred)
158
148
  x2 = np.array(x_pred)
159
149
  eps = 1e-6
160
150
  x1[:, direction] = x1[:, direction] + eps
161
151
  kk_g = (self.kernel(x1, x1, self.prior_obj.hyperparameters, self) -
162
152
  self.kernel(x2, x2, self.prior_obj.hyperparameters, self)) / eps
163
- a = kk_g - (2.0 * k_g.T @ k_covariance_prod)
164
- return {"x": x_pred,
165
- "dv/dx": np.diag(a),
166
- "dS/dx": a}
153
+ dSdx = kk_g - (2.0 * k_g.T @ k_covariance_prod)
154
+ #print(dSdx.shape)
155
+ a = np.diag(dSdx)
156
+ if x_out is not None:
157
+ a = a.reshape(len(x_orig), len(x_out), order='F')
158
+ dSdx = dSdx.reshape(len(x_orig), len(x_orig), len(x_out), len(x_out), order='F')
159
+ return {"x": x_orig,
160
+ "dv/dx": a,
161
+ "dS/dx": dSdx}
167
162
  else:
168
- grad_v = np.zeros((len(x_pred), len(x_pred[0])))
169
- for direction in range(len(x_pred[0])):
163
+ grad_v = np.zeros((len(x_pred), len(x_orig[0])))
164
+ for direction in range(len(x_orig[0])):
170
165
  k_g = self.d_kernel_dx(x_pred, x_data, direction, self.prior_obj.hyperparameters).T
171
- kk = self.kernel(x_pred, x_pred, self.prior_obj.hyperparameters, self)
166
+ #kk = self.kernel(x_pred, x_pred, self.prior_obj.hyperparameters, self)
172
167
  x1 = np.array(x_pred)
173
168
  x2 = np.array(x_pred)
174
169
  eps = 1e-6
@@ -176,7 +171,10 @@ class GPposterior:
176
171
  kk_g = (self.kernel(x1, x1, self.prior_obj.hyperparameters, self) -
177
172
  self.kernel(x2, x2, self.prior_obj.hyperparameters, self)) / eps
178
173
  grad_v[:, direction] = np.diag(kk_g - (2.0 * k_g.T @ k_covariance_prod))
179
- return {"x": x_pred,
174
+
175
+ if x_out is not None: grad_v = grad_v.reshape(len(x_orig), len(x_orig[0]), len(x_out), order='F')
176
+
177
+ return {"x": x_orig,
180
178
  "dv/dx": grad_v}
181
179
 
182
180
  ###########################################################################
@@ -192,6 +190,7 @@ class GPposterior:
192
190
  post_mean = self.mean_function(x_pred, self.prior_obj.hyperparameters, self)
193
191
  joint_gp_prior_mean = np.append(prior_mean_vec, post_mean)
194
192
  joint_gp_prior_cov = np.block([[K, k], [k.T, kk]])
193
+
195
194
  return {"x": x_pred,
196
195
  "K": K + np.identity(len(K)) * 1e-9,
197
196
  "k": k,
@@ -219,10 +218,9 @@ class GPposterior:
219
218
  self.prior_obj.hyperparameters,
220
219
  self)) / (2.0 * eps)
221
220
  # post_mean = self.mean_function(x_pred, self.prior_obj.hyperparameters, self)
222
- mean_der = (self.mean_function(x1, self.prior_obj.hyperparameters, self) - self.mean_function(x2,
223
- self.prior_obj.hyperparameters,
224
- self)) / (
225
- 2.0 * eps)
221
+ mean_der = ((self.mean_function(x1, self.prior_obj.hyperparameters, self) -
222
+ self.mean_function(x2, self.prior_obj.hyperparameters,self)) /
223
+ (2.0 * eps))
226
224
  full_gp_prior_mean_grad = np.append(np.zeros(prior_mean_vec.shape), mean_der)
227
225
  prior_cov_grad = np.zeros(K.shape)
228
226
  return {"x": x_pred,
@@ -345,53 +343,53 @@ class GPposterior:
345
343
  def gp_mutual_information(self, x_pred, x_out=None):
346
344
  x_data, K = self.data_obj.x_data.copy(), self.prior_obj.K.copy() + (np.identity(len(self.prior_obj.K)) * 1e-9)
347
345
  self._perform_input_checks(x_pred, x_out)
346
+ x_orig = x_pred.copy()
348
347
  if x_out is not None: x_pred = self.cartesian_product(x_pred, x_out)
349
348
 
350
349
  k = self.kernel(x_data, x_pred, self.prior_obj.hyperparameters, self)
351
350
  kk = self.kernel(x_pred, x_pred, self.prior_obj.hyperparameters, self) + (np.identity(len(x_pred)) * 1e-9)
352
351
 
353
- joint_covariance = \
354
- np.asarray(np.block([[K, k],
355
- [k.T, kk]]))
356
- return {"x": x_pred,
352
+ joint_covariance = np.block([[K, k],[k.T, kk]])
353
+ return {"x": x_orig,
357
354
  "mutual information": self.mutual_information(joint_covariance, kk, K)}
358
355
 
359
356
  ###########################################################################
360
357
  def gp_total_correlation(self, x_pred, x_out=None):
361
358
  x_data, K = self.data_obj.x_data.copy(), self.prior_obj.K.copy() + (np.identity(len(self.prior_obj.K)) * 1e-9)
362
359
  self._perform_input_checks(x_pred, x_out)
360
+ x_orig = x_pred.copy()
363
361
  if x_out is not None: x_pred = self.cartesian_product(x_pred, x_out)
364
362
 
365
363
  k = self.kernel(x_data, x_pred, self.prior_obj.hyperparameters, self)
366
364
  kk = self.kernel(x_pred, x_pred, self.prior_obj.hyperparameters, self) + (np.identity(len(x_pred)) * 1e-9)
367
- joint_covariance = np.asarray(np.block([[K, k],
368
- [k.T, kk]]))
365
+ joint_covariance = np.block([[K, k],[k.T, kk]])
369
366
 
370
- prod_covariance = np.asarray(np.block([[K, k * 0.],
371
- [k.T * 0., kk * np.identity(len(kk))]]))
367
+ prod_covariance = np.block([[K, k * 0.],[k.T * 0., kk * np.identity(len(kk))]])
372
368
 
373
- return {"x": x_pred,
369
+ return {"x": x_orig,
374
370
  "total correlation": self.kl_div(np.zeros((len(joint_covariance))), np.zeros((len(joint_covariance))),
375
371
  joint_covariance, prod_covariance)}
376
372
 
377
373
  ###########################################################################
378
374
  def gp_relative_information_entropy(self, x_pred, x_out=None):
379
375
  self._perform_input_checks(x_pred, x_out)
376
+ x_orig = x_pred.copy()
380
377
  if x_out is not None: x_pred = self.cartesian_product(x_pred, x_out)
381
378
  kk = self.kernel(x_pred, x_pred, self.prior_obj.hyperparameters, self) + (np.identity(len(x_pred)) * 1e-9)
382
379
  post_cov = self.posterior_covariance(x_pred, x_out=None)["S"] + (np.identity(len(x_pred)) * 1e-9)
383
- return {"x": x_pred,
380
+ return {"x": x_orig,
384
381
  "RIE": self.kl_div(np.zeros((len(x_pred))), np.zeros((len(x_pred))), kk, post_cov)}
385
382
 
386
383
  ###########################################################################
387
384
  def gp_relative_information_entropy_set(self, x_pred, x_out=None):
388
385
  self._perform_input_checks(x_pred, x_out)
386
+ x_orig = x_pred.copy()
389
387
  if x_out is not None: x_pred = self.cartesian_product(x_pred, x_out)
390
388
  RIE = np.zeros((len(x_pred)))
391
389
  for i in range(len(x_pred)):
392
390
  RIE[i] = self.gp_relative_information_entropy(x_pred[i].reshape(1, len(x_pred[i])), x_out=None)["RIE"]
393
391
 
394
- return {"x": x_pred,
392
+ return {"x": x_orig,
395
393
  "RIE": RIE}
396
394
 
397
395
  ###########################################################################
@@ -53,13 +53,13 @@ def prior_func(theta,bounds):
53
53
  # #
54
54
 
55
55
 
56
- def mcmc(likelihood_fn, bounds, x0 = None, n_updates = 10000,
57
- prior_args = None,
58
- info = False, prior_fn = None,
59
- prop_Sigma = np.nan, adapt_cov = True,
60
- return_prop_Sigma_trace = False,
61
- r_opt = .234, c_0 = 10, c_1 = .8,
62
- K = 10):
56
+ def mcmc(likelihood_fn, bounds, x0=None, n_updates=10000,
57
+ prior_args=None,
58
+ info=False, prior_fn=None,
59
+ prop_Sigma=np.nan, adapt_cov=True,
60
+ return_prop_Sigma_trace=False,
61
+ r_opt=.234, c_0=10, c_1=.8,
62
+ K=10):
63
63
 
64
64
  start_time = time.time()
65
65
  n_updates = max(n_updates,2)
@@ -113,10 +113,9 @@ def mcmc(likelihood_fn, bounds, x0 = None, n_updates = 10000,
113
113
  if prior_star != -np.inf:
114
114
  likelihood_star = likelihood_fn(hyperparameters = theta_star)
115
115
  if np.isnan(likelihood_star): likelihood_star = -np.inf
116
- metr_ratio = np.exp(prior_star + likelihood_star -
117
- prior - likelihood)
116
+ metr_ratio = np.exp(prior_star + likelihood_star - prior - likelihood)
118
117
  if np.isnan(metr_ratio): metr_ratio = 0.
119
- if metr_ratio > np.random.uniform(0,1,1):
118
+ if metr_ratio > np.random.uniform(0, 1, 1):
120
119
  theta = theta_star
121
120
  prior = prior_star
122
121
  likelihood = likelihood_star
@@ -132,7 +131,7 @@ def mcmc(likelihood_fn, bounds, x0 = None, n_updates = 10000,
132
131
  sigma_m = np.exp(np.log(sigma_m) + gamma1*(r_hat - r_opt))
133
132
 
134
133
  if adapt_cov:
135
- prop_Sigma = prop_Sigma + gamma2*(np.cov(trace[:,(i - K + 1) : i]) - prop_Sigma)
134
+ prop_Sigma = prop_Sigma + gamma2*(np.cov(trace[:, (i - K + 1): i]) - prop_Sigma)
136
135
  check_chol_cont = True
137
136
  while check_chol_cont:
138
137
  try:
@@ -148,8 +147,7 @@ def mcmc(likelihood_fn, bounds, x0 = None, n_updates = 10000,
148
147
  ctime.append(time.time() - start_time)
149
148
  sigma_m_trace[i] = sigma_m
150
149
  r_trace[i] = r_hat
151
- if return_prop_Sigma_trace:
152
- prop_Sigma_trace[i,:,:] = prop_Sigma
150
+ if return_prop_Sigma_trace: prop_Sigma_trace[i, :, :] = prop_Sigma
153
151
  # Echo every 100 iterations
154
152
  if info:
155
153
  if (i % 100) == 0: logger.info("Finished {} out of {} iterations. f(x)= {}", i, n_updates, likelihood)
@@ -159,10 +157,10 @@ def mcmc(likelihood_fn, bounds, x0 = None, n_updates = 10000,
159
157
  #########################################################
160
158
 
161
159
  # Collect trace objects to return
162
- res = {'trace':trace,
163
- 'sigma_m_trace':sigma_m_trace,
164
- 'r_trace':r_trace,
165
- 'acc_prob':jump_trace.mean()}
160
+ res = {'trace': trace,
161
+ 'sigma_m_trace': sigma_m_trace,
162
+ 'r_trace': r_trace,
163
+ 'acc_prob': jump_trace.mean()}
166
164
  arg_max = np.argmax(f)
167
165
  x = np.asarray(trace.T)
168
166
  if return_prop_Sigma_trace: res['prop_Sigma_trace'] = prop_Sigma_trace
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: fvgp
3
- Version: 4.2.2
3
+ Version: 4.2.4
4
4
  Summary: Python package for highly flexible function-valued Gaussian processes (fvGP)
5
5
  Home-page: https://github.com/MarcusMichaelNoack/fvgp
6
6
  Author: Marcus Michael Noack
@@ -22,7 +22,7 @@ from distributed.utils_test import gen_cluster, client, loop, cluster_fixture, l
22
22
  from fvgp.gp_kernels import *
23
23
  from fvgp.gp_lin_alg import *
24
24
  from scipy import sparse
25
-
25
+ from fvgp.gp_kernels import *
26
26
 
27
27
 
28
28
 
@@ -69,13 +69,25 @@ def test_lin_alg():
69
69
 
70
70
 
71
71
  def test_single_task_init_basic():
72
+ def kernel(x1,x2,hps,obj):
73
+ d = get_distance_matrix(x1,x2)
74
+ return hps[0] * matern_kernel_diff1(d,3.)
75
+ def noise(x,hps,obj):
76
+ return np.identity(len(x))
72
77
  my_gp1 = GP(x_data, y_data, init_hyperparameters = np.array([1, 1, 1, 1, 1, 1]), compute_device = 'cpu', info = True)
78
+ my_gp1 = GP(x_data, y_data, init_hyperparameters = np.array([1, 1, 1, 1, 1, 1]), gp_kernel_function = kernel,
79
+ gp_noise_function=noise, compute_device = 'cpu', info = True, ram_economy=True)
80
+ my_gp1.marginal_density.neg_log_likelihood_hessian(hyperparameters=my_gp1.get_hyperparameters())
81
+ my_gp1 = GP(x_data, y_data, init_hyperparameters = np.array([1, 1, 1, 1, 1, 1]), gp_kernel_function = kernel,
82
+ gp_noise_function=noise, compute_device = 'cpu', info = True, ram_economy=False)
83
+ my_gp1.marginal_density.neg_log_likelihood_hessian(hyperparameters=my_gp1.get_hyperparameters())
73
84
  my_gp1 = GP(x_data, y_data, info = True)
74
85
  my_gp1 = GP(x_data, y_data, init_hyperparameters = np.array([1, 1, 1, 1, 1, 1]))
75
86
  my_gp1 = GP(x_data, y_data, init_hyperparameters = np.array([1, 1, 1, 1, 1, 1]), calc_inv = False, info = True)
76
87
  my_gp1 = GP(x_data, y_data, init_hyperparameters = np.array([1, 1, 1, 1, 1, 1]), args = {'a':2.})
77
88
  my_gp1.update_gp_data(x_data, y_data, append = True)
78
89
  my_gp1.update_gp_data(x_data, y_data, append = False)
90
+
79
91
 
80
92
  my_gp1 = GP(x_data, y_data, noise_variances = np.zeros(y_data.shape) + 0.01,init_hyperparameters = np.array([1, 1, 1, 1, 1, 1]), args = {'a':2.})
81
93
  my_gp1.update_gp_data(x_data, y_data, noise_variances_new = np.zeros(y_data.shape) + 0.01, append = True)
@@ -102,6 +114,7 @@ def test_single_task_init_basic():
102
114
  my_gp1.rmse(x_data[0:2] + 1., np.array([1.,2.]))
103
115
  my_gp1.make_2d_x_pred(np.array([1.,2.]),np.array([3.,4]))
104
116
  my_gp1.make_1d_x_pred(np.array([1.,2.]))
117
+ my_gp1._get_default_hyperparameter_bounds()
105
118
 
106
119
 
107
120
  def test_single_task_init_advanced():
@@ -205,7 +218,9 @@ def test_multi_task():
205
218
  my_fvgp.update_gp_data(x_data, y_data, append = False)
206
219
  my_fvgp.train(hyperparameter_bounds=np.array([[0.01,1],[0.01,10]]),
207
220
  method = "global", pop_size = 10, tolerance = 0.001, max_iter = 2)
208
- my_fvgp.posterior_mean(np.random.rand(10,5), x_out = np.zeros((1)))["f(x)"]
221
+ my_fvgp.posterior_mean(np.random.rand(10,5), x_out = np.array([0,1]))["f(x)"]
222
+ my_fvgp.posterior_mean_grad(np.random.rand(10,5), x_out = np.array([0,1]))["df/dx"]
223
+ my_fvgp.posterior_covariance(np.random.rand(10,5), x_out = np.array([0,1]))["v(x)"]
209
224
 
210
225
 
211
226
 
@@ -240,7 +255,7 @@ def test_gp2Scale(client):
240
255
  init_s = (np.diag(hps_bounds[:,1]-hps_bounds[:,0])/100.)**2
241
256
 
242
257
  from fvgp import gpMCMC
243
- def proposal_distribution(x0, obj):
258
+ def proposal_distribution(x0, hps, obj):
244
259
  cov = obj.prop_args["prop_Sigma"]
245
260
  proposal_hps = np.zeros((len(x0)))
246
261
  proposal_hps = np.random.multivariate_normal(
@@ -256,13 +271,13 @@ def test_gp2Scale(client):
256
271
  return 0. + np.sum(np.log(theta)/2.)
257
272
  else:
258
273
  return -np.inf
259
- pd = ProposalDistribution(proposal_distribution, [0,1],
274
+ pd = ProposalDistribution([0,1] ,proposal_dist=proposal_distribution,
260
275
  init_prop_Sigma = init_s, adapt_callable="normal")
261
276
 
262
277
 
263
278
 
264
279
 
265
- my_mcmc = gpMCMC(obj_func, len(hps_bounds), prior_function, [pd],
280
+ my_mcmc = gpMCMC(obj_func, prior_function, [pd],
266
281
  args={"bounds":hps_bounds})
267
282
 
268
283
  hps = np.random.uniform(
@@ -270,7 +285,20 @@ def test_gp2Scale(client):
270
285
  high = hps_bounds[:,1],
271
286
  size = len(hps_bounds))
272
287
  mcmc_result = my_mcmc.run_mcmc(x0=hps, info=True, n_updates=10, break_condition="default")
273
-
288
+ my_gp2S.set_hyperparameters(mcmc_result["x"][-1])
274
289
  x_pred = np.linspace(0,1,1000)
275
290
  mean1 = my_gp2S.posterior_mean(x_pred.reshape(-1,1))["f(x)"]
276
291
  var1 = my_gp2S.posterior_covariance(x_pred.reshape(-1,1))["v(x)"]
292
+
293
+ pd = ProposalDistribution([0,1], init_prop_Sigma = init_s)
294
+ my_mcmc = gpMCMC(obj_func, prior_function, [pd],
295
+ args={"bounds":hps_bounds})
296
+
297
+ mcmc_result = my_mcmc.run_mcmc(x0=hps, info=True, n_updates=10, break_condition="default")
298
+
299
+ pd = ProposalDistribution([0,1], init_prop_Sigma = init_s, adapt_callable = "normal")
300
+ my_mcmc = gpMCMC(obj_func, prior_function, [pd],
301
+ args={"bounds":hps_bounds})
302
+
303
+ mcmc_result = my_mcmc.run_mcmc(x0=hps, info=True, n_updates=10, break_condition="default")
304
+
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes