Coverage for C:\Users\t590r\Documents\GitHub\suppy\suppy\superiorization\_split_sup.py: 19%

1 from typing import List

2 import numpy.typing as npt

3 from suppy.utils import ensure_float_array

4 from suppy.perturbations import Perturbation

5 from ._sup import FeasibilityPerturbation

6

7

8 class 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)