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

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 

6 

7 

8class SplitSuperiorization(FeasibilityPerturbation): 

9 """ 

10 A class used to perform split superiorization on a given feasibility 

11 problem. 

12 

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. 

27 

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 """ 

57 

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 

67 

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 

73 

74 self.all_x_values = [] 

75 self.all_function_values = [] # array storing all objective function values 

76 

77 # array storing all points achieved via the function reduction step 

78 self.all_x_values_function_reduction = [] 

79 

80 # array storing all objective function values achieved via the function reduction step 

81 self.all_function_values_function_reduction = [] 

82 

83 # array storing all points achieved via the basic algorithm 

84 self.all_x_values_basic = [] 

85 

86 # array storing all objective function values achieved via the basic algorithm 

87 self.all_function_values_basic = [] 

88 

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. 

102 

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

111 

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 

122 

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) 

126 

127 if self.target_perturbation_scheme is not None: 

128 self.target_f_k = self.target_perturbation_scheme.func(y) 

129 

130 self.p_k = self.basic.proximity(x_0, proximity_measures) 

131 

132 # if storage: 

133 # self._initial_storage(x_0,self.perturbation_scheme.func(x_0)) 

134 

135 while self._k < max_iter and not stop: 

136 

137 # check if a restart should be performed 

138 

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) 

142 

143 if self.target_perturbation_scheme is not None: 

144 y = self.target_perturbation_scheme.perturbation_step(y) 

145 

146 # if storage: 

147 # self._storage_function_reduction(x,self.perturbation_scheme.func(x)) 

148 

149 # perform basic step 

150 x, y = self.basic.step(x, y) 

151 

152 # if storage: 

153 # self._storage_basic_step(x,self.perturbation_scheme.func(x)) 

154 

155 # check current function and proximity values 

156 

157 if self.input_perturbation_scheme is not None: 

158 input_f_temp = self.input_perturbation_scheme.func(x) 

159 

160 if self.target_perturbation_scheme is not None: 

161 target_f_temp = self.target_perturbation_scheme.func(y) 

162 

163 p_temp = self.basic.proximity(x, y) 

164 

165 # enable different stopping criteria for different superiorization algorithms 

166 stop = self._stopping_criteria(input_f_temp, target_f_temp, p_temp) 

167 

168 # update function and proximity values 

169 if self.input_perturbation_scheme is not None: 

170 self.input_f_k = input_f_temp 

171 

172 if self.target_perturbation_scheme is not None: 

173 self.target_f_k = target_f_temp 

174 

175 self.p_k = p_temp 

176 

177 self._additional_action(x, y) 

178 

179 self._k += 1 

180 

181 return x 

182 

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. 

194 

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. 

209 

210 Returns 

211 ------- 

212 bool 

213 True if all stopping criteria are met, False otherwise. 

214 """ 

215 

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 

218 

219 constr_crit = p_temp < constr_tol 

220 stop = input_crit and target_crit and constr_crit 

221 return stop 

222 

223 def _additional_action(self, x, y): 

224 """ 

225 Perform an additional action on the given inputs. 

226 

227 Parameters 

228 ---------- 

229 x : type 

230 Description of parameter `x`. 

231 y : type 

232 Description of parameter `y`. 

233 

234 Returns 

235 ------- 

236 None 

237 """ 

238 

239 # def _initial_storage(self,x,f_input,f_target): 

240 # """ 

241 # Initialize the storage arrays for storing intermediate results. 

242 

243 # Parameters: 

244 # - x: The initial point for the optimization problem. 

245 

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 

252 

253 # self.all_x_values_function_reduction = [] 

254 # self.all_function_values_function_reduction = [] 

255 

256 # self.all_x_values_basic = [] 

257 # self.all_function_values_basic = [] 

258 

259 # #append initial values 

260 # self.all_x_values.append(x) 

261 # self.all_function_values.append(f) 

262 

263 # def _storage_function_reduction(self,x,f): 

264 # """ 

265 # Store intermediate results achieved via the function reduction step. 

266 

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. 

270 

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) 

278 

279 # def _storage_basic_step(self,x,f): 

280 # """ 

281 # Store intermediate results achieved via the basic algorithm step. 

282 

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. 

286 

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)