2121from pytuq .utils .mindex import get_mi
2222from pytuq .lreg .lreg import lsq
2323from pytuq .lreg .anl import anl
24+ from pytuq .lreg .bcs import bcs
2425
2526
2627class PCE :
@@ -33,12 +34,13 @@ class PCE:
3334 pctype (list[str]): Type of PC polynomial used.
3435 outdim (int): Physical dimensionality, i.e. # of output variables.
3536 lreg (lreg object): Linear regression object used for fitting the model.
37+ mindex (int np.ndarray): Multiindex array carrying the powers to which the basis functions will be raised to within the PC terms.
3638 regression_method (str): Method used for linear regression. ex] anl, opt, lsq
3739 _x_train (np.ndarray): Input training data
3840 _y_train (np.ndarray): Output training data, corresponding to x_train
3941 """
4042
41- def __init__ (self , pce_dim , pce_order , pce_type , ** kwargs ):
43+ def __init__ (self , pce_dim , pce_order , pce_type , verbose = 0 , ** kwargs ):
4244 r"""Initializes a Polynomial Chaos Random Variable (PCRV) with, at minimum:
4345 stochastic dimensionality, order, and polynomial chaos (PC) type.
4446
@@ -48,6 +50,7 @@ def __init__(self, pce_dim, pce_order, pce_type, **kwargs):
4850 pce_order (int): Order of the PC expansion.
4951 pce_type (str or list): PC type. Either a list of :math:`s` strings (one per stochastic dimension),
5052 or a single string for all dimensions. Supported types include 'LU' (Legendre) and 'HG' (Hermite-Gaussian).
53+ verbose (int): Output verbosity. Higher values print out more information. Default of 0
5154 pce_outdim (int, optional): Physical dimensionality :math:`s` of the PC random variable/vector.
5255 Default of 1 indicates a scalar-valued output.
5356 mi (list or np.ndarray, optional): List of :math:`d` multiindex arrays, each of size :math:`(K_i,s)` for :math:`i=1, \dots, d`.
@@ -66,18 +69,24 @@ def __init__(self, pce_dim, pce_order, pce_type, **kwargs):
6669 self .order = pce_order
6770 self .pctype = pce_type # Choose from options: 'LU', 'HG', or mix of ['HG', 'LU']
6871 self .outdim = kwargs .get ('pce_outdim' , 1 ) # Scalar valued output
72+ self .verbose = verbose
6973
7074 self .lreg = None
7175 self ._x_train = None
7276 self ._y_train = None
7377 self .regression_method = None
7478
79+ # Get the original multiindex, before possible modification in build
80+ self .mindex = kwargs .get ('mi' , get_mi (self .order , self .sdim ))
81+
7582 self .pcrv = PCRV (self .outdim , self .sdim , self .pctype ,
76- mi = kwargs . get ( 'mi' , get_mi ( self .order , self . sdim )) ,
77- cfs = kwargs .get ('cfs' ))
83+ mi = self .mindex ,
84+ cfs = kwargs .get ('cfs' ))
7885
79- print (self .pcrv , end = '\n \n ' )
80- # self.pcrv.printInfo() # Useful for vector valued functions
86+ if self .verbose > 0 :
87+ print ("Constructed PC Surrogate with the following attributes:" )
88+ print (self .pcrv , end = '\n \n ' )
89+ # self.pcrv.printInfo()
8190
8291 def set_training_data (self , x_train , y_train ):
8392 r"""Sets the training data with validation.
@@ -127,11 +136,14 @@ def build(self, **kwargs):
127136 - prior_var (float): Available for regression type 'anl', method 'full'.
128137
129138 Returns:
130- np.ndarray: Coefficients for matrix
139+ np.ndarray: PC coefficients
131140 """
132141 if self ._x_train is None or self ._y_train is None :
133142 raise RuntimeError ("Training data must be set using set_training_data() before calling build()." )
134143
144+ # Reset the multiindex and coefficients
145+ self .pcrv .setMiCfs (self .mindex , cfs = None )
146+
135147 regression = kwargs .get ('regression' , 'lsq' )
136148
137149 if regression == 'lsq' :
@@ -142,11 +154,15 @@ def build(self, **kwargs):
142154 self .lreg = anl (method = 'vi' , datavar = kwargs .get ('datavar' ), cov_nugget = kwargs .get ('cov_nugget' , 0.0 ))
143155 else :
144156 self .lreg = anl (datavar = kwargs .get ('datavar' ), prior_var = kwargs .get ('prior_var' ), cov_nugget = kwargs .get ('cov_nugget' , 0.0 ))
157+ elif regression == 'bcs' :
158+ self .lreg = bcs (eta = kwargs .get ('eta' , 1.e-8 ), datavar_init = kwargs .get ('datavar_init' ))
145159 else :
146160 raise ValueError (f"Regression method '{ regression } ' is not recognized and/or supported yet." )
147161
148162 self .regression_method = type (self .lreg ).__name__
149- print ("Regression method:" , self .regression_method )
163+
164+ if self .verbose > 0 :
165+ print ("Regression method:" , self .regression_method )
150166
151167 def basisevaluator (x , pars ):
152168 self .pcrv , = pars
@@ -155,6 +171,10 @@ def basisevaluator(x, pars):
155171 self .lreg .setBasisEvaluator (basisevaluator , (self .pcrv ,))
156172 self .lreg .fit (self ._x_train , self ._y_train )
157173
174+ # Update the multi-index and coefficients retained by BCS as attributes of pcrv object
175+ if regression == 'bcs' :
176+ self .pcrv .setMiCfs ([self .mindex [self .lreg .used ,:]], [self .lreg .cf ])
177+
158178 return self .lreg .cf
159179
160180 def evaluate (self , x_eval , ** kwargs ):
@@ -166,7 +186,7 @@ def evaluate(self, x_eval, **kwargs):
166186 data_variance (bool, optional): Whether to compute posterior-predictive (i.e. add data variance) or not.
167187
168188 Returns:
169- dictionary: Dictionary of predicted y-values, along with standard deviation, covariance, and variance of predictions if applicable.
189+ dict: Values for predicted y-values, standard deviation, covariance, and variance of predictions ( if applicable) as np.ndarrays.
170190 """
171191 # If single output (scalar-valued function), standard deviation and variance are calculated,
172192 # but not covariance.
0 commit comments