Coverage for C:\Users\t590r\Documents\GitHub\suppy\suppy\superiorization\_split_sup.py: 19%
58 statements
« prev ^ index » next coverage.py v7.6.4, created at 2025-02-05 10:12 +0100
« prev ^ index » next coverage.py v7.6.4, created at 2025-02-05 10:12 +0100
1from typing import List
2import numpy.typing as npt
3from suppy.utils import ensure_float_array
4from suppy.perturbations import Perturbation
5from ._sup import FeasibilityPerturbation
8class SplitSuperiorization(FeasibilityPerturbation):
9 """
10 A class used to perform split superiorization on a given feasibility
11 problem.
13 Parameters
14 ----------
15 basic : object
16 An instance of a split problem.
17 input_perturbation_scheme : Perturbation or None, optional
18 Perturbation scheme for the input, by default None.
19 target_perturbation_scheme : Perturbation or None, optional
20 Perturbation scheme for the target, by default None.
21 input_objective_tol : float, optional
22 Tolerance for the input objective function, by default 1e-4.
23 target_objective_tol : float, optional
24 Tolerance for the target objective function, by default 1e-4.
25 constr_tol : float, optional
26 Tolerance for the constraint, by default 1e-6.
28 Attributes
29 ----------
30 input_perturbation_scheme : Perturbation or None
31 Perturbation scheme for the input.
32 target_perturbation_scheme : Perturbation or None
33 Perturbation scheme for the target.
34 input_objective_tol : float
35 Tolerance for the input objective function.
36 target_objective_tol : float
37 Tolerance for the target objective function.
38 constr_tol : float
39 Tolerance for the constraint.
40 input_f_k : float
41 The current objective function value for the input.
42 target_f_k : float
43 The current objective function value for the target.
44 p_k : float
45 The current proximity function value.
46 _k : int
47 The current iteration number.
48 all_x_values : list
49 Array storing all points achieved via the superiorization algorithm.
50 all_function_values : list
51 Array storing all objective function values achieved via the superiorization algorithm.
52 all_x_values_function_reduction : list
53 Array storing all points achieved via the function reduction step.
54 all_function_values_function_reduction : list
55 Array storing all objective function values achieved via the function reduction step.
56 """
58 def __init__(
59 self,
60 basic, # needs to be a split problem
61 input_perturbation_scheme: Perturbation | None = None,
62 target_perturbation_scheme: Perturbation | None = None,
63 ):
64 super().__init__(basic)
65 self.input_perturbation_scheme = input_perturbation_scheme
66 self.target_perturbation_scheme = target_perturbation_scheme
68 # initialize some variables for the algorithms
69 self.input_f_k = None
70 self.target_f_k = None
71 self.p_k = None
72 self._k = 0
74 self.all_x_values = []
75 self.all_function_values = [] # array storing all objective function values
77 # array storing all points achieved via the function reduction step
78 self.all_x_values_function_reduction = []
80 # array storing all objective function values achieved via the function reduction step
81 self.all_function_values_function_reduction = []
83 # array storing all points achieved via the basic algorithm
84 self.all_x_values_basic = []
86 # array storing all objective function values achieved via the basic algorithm
87 self.all_function_values_basic = []
89 @ensure_float_array
90 def solve(
91 self,
92 x_0: npt.NDArray,
93 max_iter: int = 10,
94 storage=False,
95 input_objective_tol: float = 1e-6,
96 target_objective_tol: float = 1e-6,
97 constr_tol: float = 1e-6,
98 proximity_measures: List | None = None,
99 ) -> npt.NDArray:
100 """
101 Solves the optimization problem using the superiorization method.
103 Parameters
104 ----------
105 x_0 : npt.NDArray
106 Initial guess for the solution.
107 max_iter : int, optional
108 Maximum number of iterations to perform (default is 10).
109 storage : bool, optional
110 If True, stores intermediate results (default is False).
112 Returns
113 -------
114 npt.NDArray
115 The optimized solution after performing the superiorization method.
116 """
117 # initialization of variables
118 x = x_0
119 y = self.basic.map(x)
120 self._k = 0 # reset counter if necessary
121 stop = False
123 # initial function and proximity values
124 if self.input_perturbation_scheme is not None:
125 self.input_f_k = self.input_perturbation_scheme.func(x_0)
127 if self.target_perturbation_scheme is not None:
128 self.target_f_k = self.target_perturbation_scheme.func(y)
130 self.p_k = self.basic.proximity(x_0, proximity_measures)
132 # if storage:
133 # self._initial_storage(x_0,self.perturbation_scheme.func(x_0))
135 while self._k < max_iter and not stop:
137 # check if a restart should be performed
139 # perform the perturbation schemes update step
140 if self.input_perturbation_scheme is not None:
141 x = self.input_perturbation_scheme.perturbation_step(x)
143 if self.target_perturbation_scheme is not None:
144 y = self.target_perturbation_scheme.perturbation_step(y)
146 # if storage:
147 # self._storage_function_reduction(x,self.perturbation_scheme.func(x))
149 # perform basic step
150 x, y = self.basic.step(x, y)
152 # if storage:
153 # self._storage_basic_step(x,self.perturbation_scheme.func(x))
155 # check current function and proximity values
157 if self.input_perturbation_scheme is not None:
158 input_f_temp = self.input_perturbation_scheme.func(x)
160 if self.target_perturbation_scheme is not None:
161 target_f_temp = self.target_perturbation_scheme.func(y)
163 p_temp = self.basic.proximity(x, y)
165 # enable different stopping criteria for different superiorization algorithms
166 stop = self._stopping_criteria(input_f_temp, target_f_temp, p_temp)
168 # update function and proximity values
169 if self.input_perturbation_scheme is not None:
170 self.input_f_k = input_f_temp
172 if self.target_perturbation_scheme is not None:
173 self.target_f_k = target_f_temp
175 self.p_k = p_temp
177 self._additional_action(x, y)
179 self._k += 1
181 return x
183 def _stopping_criteria(
184 self,
185 input_f_temp,
186 target_f_temp,
187 p_temp,
188 input_objective_tol,
189 target_objective_tol,
190 constr_tol,
191 ) -> bool:
192 """
193 Check if the stopping criteria for the optimization process are met.
195 Parameters
196 ----------
197 input_f_temp : float
198 The current value of the input objective function.
199 target_f_temp : float
200 The current value of the target objective function.
201 p_temp : float
202 The current value of the constraint parameter.
203 input_objective_tol : float
204 Tolerance for the input objective function.
205 target_objective_tol : float
206 Tolerance for the target objective function.
207 constr_tol : float
208 Tolerance for the constraint.
210 Returns
211 -------
212 bool
213 True if all stopping criteria are met, False otherwise.
214 """
216 input_crit = abs(input_f_temp - self.input_f_k) < input_objective_tol
217 target_crit = abs(target_f_temp - self.target_f_k) < target_objective_tol
219 constr_crit = p_temp < constr_tol
220 stop = input_crit and target_crit and constr_crit
221 return stop
223 def _additional_action(self, x, y):
224 """
225 Perform an additional action on the given inputs.
227 Parameters
228 ----------
229 x : type
230 Description of parameter `x`.
231 y : type
232 Description of parameter `y`.
234 Returns
235 -------
236 None
237 """
239 # def _initial_storage(self,x,f_input,f_target):
240 # """
241 # Initialize the storage arrays for storing intermediate results.
243 # Parameters:
244 # - x: The initial point for the optimization problem.
246 # Returns:
247 # None
248 # """
249 # #reset objective values
250 # self.all_x_values = []
251 # self.all_function_values = [] # array storing all objective function values
253 # self.all_x_values_function_reduction = []
254 # self.all_function_values_function_reduction = []
256 # self.all_x_values_basic = []
257 # self.all_function_values_basic = []
259 # #append initial values
260 # self.all_x_values.append(x)
261 # self.all_function_values.append(f)
263 # def _storage_function_reduction(self,x,f):
264 # """
265 # Store intermediate results achieved via the function reduction step.
267 # Parameters:
268 # - x: The current point achieved via the function reduction step.
269 # - f: The current objective function value achieved via the function reduction step.
271 # Returns:
272 # None
273 # """
274 # self.all_x_values.append(x.copy())
275 # self.all_function_values.append(f)
276 # self.all_x_values_function_reduction.append(x.copy())
277 # self.all_function_values_function_reduction.append(f)
279 # def _storage_basic_step(self,x,f):
280 # """
281 # Store intermediate results achieved via the basic algorithm step.
283 # Parameters:
284 # - x: The current point achieved via the basic algorithm step.
285 # - f: The current objective function value achieved via the basic algorithm step.
287 # Returns:
288 # None
289 # """
290 # self.all_x_values_basic.append(x.copy())
291 # self.all_function_values_basic.append(f)
292 # self.all_x_values.append(x.copy())
293 # self.all_function_values.append(f)