@@ -12,6 +12,8 @@ class Analytical:
1212 Offset value. Defaults to 0.0.
1313 seed (int):
1414 Seed value for random number generation. Defaults to 126.
15+ fun_control (dict):
16+ Dictionary containing control parameters for the function. Defaults to None.
1517
1618 Notes:
1719 See [Numpy Random Sampling](https://numpy.org/doc/stable/reference/random/index.html#random-quick-start)
@@ -29,12 +31,22 @@ class Analytical:
2931 Dictionary containing control parameters for the function.
3032 """
3133
32- def __init__ (self , offset : float = 0.0 , sigma = 0.0 , seed : int = 126 ) -> None :
34+ def __init__ (self , offset : float = 0.0 , sigma = 0.0 , seed : int = 126 , fun_control = None ) -> None :
3335 self .offset = offset
3436 self .sigma = sigma
3537 self .seed = seed
3638 self .rng = default_rng (seed = self .seed )
37- self .fun_control = {"sigma" : sigma , "seed" : None , "sel_var" : None }
39+ self .fun_control = {"offset" : offset , "sigma" : self .sigma , "seed" : self .seed }
40+ # overwrite fun_control with user input if provided
41+ if fun_control is not None :
42+ self .fun_control = fun_control
43+ # check if fun_control contains offset, sigma and seed, if not, add them
44+ if "offset" not in self .fun_control :
45+ self .fun_control ["offset" ] = self .offset
46+ if "sigma" not in self .fun_control :
47+ self .fun_control ["sigma" ] = self .sigma
48+ if "seed" not in self .fun_control :
49+ self .fun_control ["seed" ] = self .seed
3850
3951 def __repr__ (self ) -> str :
4052 return f"analytical(offset={ self .offset } , sigma={ self .sigma } , seed={ self .seed } )"
@@ -142,19 +154,67 @@ def fun_linear(self, X: np.ndarray, fun_control: Optional[Dict] = None) -> np.nd
142154 dict with entries `sigma` (noise level) and `seed` (random seed).
143155
144156 Returns:
145- np.ndarray: A 1D numpy array with shape (n,) containing the calculated values.
157+ np.ndarray: A 1D numpy array with shape (n,) containing the calculated values, which were obtained by
158+ summing the weighted input values after subtracting the offset. Noise can be added to the output. An intercept
159+ can be provided by setting the `alpha` key in the `fun_control` dictionary. If the `beta` key is provided, the
160+ weighted sum is computed. If `beta` is not provided, the sum of the input values is computed.
146161
147162 Examples:
148- >>> from spotpython.fun.objectivefunctions import analytical
163+ >>> from spotpython.fun.objectivefunctions import Analytical
149164 >>> import numpy as np
150- >>> X = np.array([[1, 2, 3], [4, 5, 6]])
151- >>> fun = analytical()
152- >>> fun.fun_linear(X)
153- array([ 6., 15.])
165+ >>> # Without offset and without noise
166+ >>> user_fun = UserAnalytical()
167+ >>> X = np.array([[0, 0, 0], [1, 1, 1]])
168+ >>> results = user_fun.fun_user_function(X)
169+ >>> print(results)
170+ >>>
171+ >>> # With offset and without noise
172+ >>> user_fun = UserAnalytical(offset=1.0)
173+ >>> X = np.array([[0, 0, 0], [1, 1, 1]])
174+ >>> results = user_fun.fun_user_function(X)
175+ >>> print(results)
176+ >>>
177+ >>> # With offset and noise
178+ >>> user_fun = UserAnalytical(offset=1.0, sigma=0.1, seed=1)
179+ >>> X = np.array([[0, 0, 0], [1, 1, 1]])
180+ >>> results = user_fun.fun_user_function(X)
181+ >>> print(results)
182+ >>>
183+ >>> # Provide alpha (intercept), no beta
184+ >>> fun_control = {"alpha": 10.0}
185+ >>> fun.fun_linear(X, fun_control=fun_control)
186+ >>> array([16., 25.])
187+ >>>
188+ >>> # Provide alpha and beta (weighted sum with intercept)
189+ >>> fun_control = {"alpha": 2.0, "beta": [1.0, 2.0, 3.0]}
190+ >>> fun.fun_linear(X, fun_control=fun_control)
191+ array([14., 32.])
192+ [0. 3.]
193+ [3. 0.]
194+ [3.03455842 0.08216181]
154195
155196 """
156197 X = self ._prepare_input_data (X , fun_control )
157- y = np .sum (X , axis = 1 )
198+ offset = np .ones (X .shape [1 ]) * self .offset
199+
200+ alpha = self .fun_control .get ("alpha" , 0.0 )
201+ beta = self .fun_control .get ("beta" , None )
202+ if beta is not None :
203+ # check if beta is a numpy array
204+ if not isinstance (beta , np .ndarray ):
205+ # convert beta to numpy array of shape (n,), where n is the number of columns in X
206+ beta = np .array (beta )
207+ if beta .shape [0 ] != X .shape [1 ]:
208+ raise Exception ("beta must have the same number of elements as the number of columns in X" )
209+
210+ # Compute the linear response
211+ if beta is not None :
212+ # Weighted sum with intercept
213+ y = alpha + np .dot (X - offset , beta )
214+ else :
215+ # Original behavior: just sum the rows
216+ y = alpha + np .sum (X - offset , axis = 1 )
217+
158218 return self ._add_noise (y )
159219
160220 def fun_sphere (self , X : np .ndarray , fun_control : Optional [Dict ] = None ) -> np .ndarray :
0 commit comments