1+ from typing import Callable
2+ import math
3+
4+ import torch
5+ from torch import Tensor
6+
7+
8+ PISTON_LBS = torch .tensor ([30 , 0.005 , 0.002 , 1000 , 90_000 , 290 , 340 ])
9+ PISTON_UBS = torch .tensor ([60 , 0.020 , 0.010 , 5000 , 110_000 , 296 , 360 ])
10+
11+ BOREHOLE_LBS = torch .tensor ([0.05 , 100 , 63_070 , 990 , 63.1 , 700 , 1120 , 9855 ])
12+ BOREHOLE_UBS = torch .tensor ([0.15 , 50_000 , 115_600 , 1110 , 116.0 , 820 , 1680 , 12_045 ])
13+
14+ OTL_CIRCUIT_LBS = torch .tensor ([ 50 , 25 , 0.5 , 1.2 , 0.25 , 50 ])
15+ OTL_CIRCUIT_UBS = torch .tensor ([150 , 70 , 3.0 , 2.5 , 1.20 , 300 ])
16+
17+ WING_WEIGHT_LBS = torch .tensor ([150 , 220 , 6 , - 10 , 16 , 0.5 , 0.08 , 2.5 , 1700 , 0.025 ])
18+ WING_WEIGHT_UBS = torch .tensor ([200 , 300 , 10 , 10 , 45 , 1.0 , 0.18 , 6.0 , 2500 , 0.080 ])
19+
20+
21+ def rescale (ls : Tensor , lbs : float | Tensor , ubs : int | Tensor ) -> Tensor :
22+ ls = 0.5 * (ls + 1.0 )
23+ ls = lbs + ls * (ubs - lbs )
24+ return ls
25+
26+
27+ def ackley (ls : Tensor ) -> Tensor :
28+ ls = rescale (ls , - 32.768 , 32.768 )
29+ fxs = (
30+ - 20.0 * torch .exp (- 0.2 * ls .square ().mean (dim = 1 ).sqrt ())
31+ - torch .exp (torch .cos (2 * torch .pi * ls ).mean (dim = 1 )) + 20 + math .exp (1.0 )
32+ )
33+ return fxs
34+
35+
36+ def alpine (ls : Tensor ) -> Tensor :
37+ # Mistake in Strossner et al.: should have ls[:, :1].
38+ ls = rescale (ls , - 10.0 , 10.0 )
39+ fxs = torch .sum (torch .abs (ls * torch .sin (ls ) + 0.1 * ls ), dim = 1 )
40+ return fxs
41+
42+
43+ def dixon (ls : Tensor ) -> Tensor :
44+ ls = rescale (ls , - 10.0 , 10.0 )
45+ fls = (ls [:, 0 ] - 1.0 ) ** 2
46+ for i in range (1 , 7 ):
47+ fls += (i + 1 ) * (2.0 * ls [:, i ] ** 2 - ls [:, i - 1 ]) ** 2
48+ return fls
49+
50+
51+ def exponential (ls : Tensor ) -> Tensor :
52+ fls = - torch .exp (- 0.5 * torch .sum (ls ** 2 , dim = 1 ))
53+ return fls
54+
55+
56+ def griewank (ls : Tensor ) -> Tensor :
57+ # Mistake in Strosser et al.: missing sqrt().
58+ ls = rescale (ls , - 600.0 , 600.0 )
59+ is_ = torch .arange (1 , 8 )
60+ fls = (
61+ torch .sum ((ls ** 2 ) / 4000.0 , dim = 1 )
62+ - torch .prod (torch .cos (ls / is_ ), dim = 1 )
63+ + 1
64+ )
65+ return fls
66+
67+
68+ def michaelwicz (ls : Tensor ) -> Tensor :
69+ ls = rescale (ls , 0.0 , torch .pi )
70+ is_ = torch .arange (1 , 8 )
71+ fls = - torch .sum (
72+ torch .sin (ls ) * torch .sin (is_ * ls ** 2 / torch .pi ) ** 20 ,
73+ dim = 1
74+ )
75+ return fls
76+
77+
78+ def piston (ls : Tensor ) -> Tensor :
79+ # Mistake in Strossner et al.: A not inside sqrt() when computing V.
80+ ls = rescale (ls , PISTON_LBS , PISTON_UBS )
81+ M , S , V0 , k , P0 , Ta , T0 = ls .T
82+ A = P0 * S + 19.62 * M - (k * V0 )/ S
83+ V = (S / (2 * k )) * (torch .sqrt (A ** 2 + 4 * k * (P0 * V0 / T0 )* Ta ) - A )
84+ fls = 2 * torch .pi * torch .sqrt (M / (k + S ** 2 * (P0 * V0 / T0 ) * (Ta / V ** 2 )))
85+ return fls
86+
87+
88+ def qing (ls : Tensor ) -> Tensor :
89+ ls = rescale (ls , 0.0 , 500.0 )
90+ is_ = torch .arange (1 , 8 )
91+ fls = torch .sum ((ls ** 2 - is_ )** 2 , dim = 1 )
92+ return fls
93+
94+
95+ def rastrigin (ls : Tensor ) -> Tensor :
96+ ls = rescale (ls , - 5.12 , 5.12 )
97+ fls = 70 + torch .sum (ls ** 2 - 10.0 * torch .cos (2.0 * torch .pi * ls ), dim = 1 )
98+ return fls
99+
100+
101+ def rosenbrock (ls : Tensor ) -> Tensor :
102+ ls = rescale (ls , - 2.048 , 2.048 )
103+ fls = torch .zeros ((ls .shape [0 ],))
104+ for i in range (6 ):
105+ fls += (
106+ 100.0 * torch .square (ls [:, i + 1 ] - ls [:, i ]** 2 )
107+ + torch .square (1.0 - ls [:, i ])
108+ )
109+ return fls
110+
111+
112+ def schaffer (ls : Tensor ) -> Tensor :
113+ ls = rescale (ls , - 100.0 , 100.0 )
114+ fls = torch .zeros ((ls .shape [0 ],))
115+ for i in range (6 ):
116+ ls_sq = ls [:, i ]** 2 + ls [:, i + 1 ]** 2
117+ fls += (
118+ 0.5
119+ + (torch .sin (torch .sqrt (ls_sq )).square () - 0.5 )
120+ / (1.0 + 0.001 * ls_sq ).square ()
121+ )
122+ return fls
123+
124+
125+ def schwefel (ls : Tensor ) -> Tensor :
126+ ls = rescale (ls , - 500.0 , 500.0 )
127+ return 2932.8803 - torch .sum (ls * torch .sin (torch .abs (ls )** 0.5 ), dim = 1 )
128+
129+
130+ def borehole (ls : Tensor ) -> Tensor :
131+ ls = rescale (ls , BOREHOLE_LBS , BOREHOLE_UBS )
132+ rw , r , Tu , Hu , Tl , Hl , L , Kw = ls .T
133+ d1 = torch .log (r / rw )
134+ d2 = (2.0 * L * Tu ) / (torch .log (r / rw ) * rw ** 2 * Kw )
135+ d3 = Tu / Tl
136+ fls = 2 * torch .pi * Tu * (Hu - Hl ) / (d1 * (1.0 + d2 + d3 ))
137+ return fls
138+
139+
140+ def otl_circuit (ls : Tensor ) -> Tensor :
141+ ls = rescale (ls , OTL_CIRCUIT_LBS , OTL_CIRCUIT_UBS )
142+ b1 , b2 , f , c1 , c2 , beta = ls .T
143+ x = beta * (c2 + 9.0 )
144+ t1 = (12 * b2 / (b1 + b2 ) + 0.74 ) * x / (x + f )
145+ t2 = (11.35 * f ) / (x + f )
146+ t3 = (0.74 * f * x ) / ((x + f )* c1 )
147+ Vm = t1 + t2 + t3
148+ return Vm
149+
150+
151+ def robot_arm (ls : Tensor ) -> Tensor :
152+ # Mistake in Strosser et al.: Indexing issues in sum.
153+ ts = rescale (ls [:, :4 ], 0.0 , 2.0 * torch .pi )
154+ Ls = rescale (ls [:, 4 :], 0.0 , 1.0 )
155+ u = torch .zeros ((ls .shape [0 ],))
156+ v = torch .zeros ((ls .shape [0 ],))
157+ for i in range (4 ):
158+ theta_i = torch .sum (ts [:, :i + 1 ], dim = 1 )
159+ u += Ls [:, i ] * torch .cos (theta_i )
160+ v += Ls [:, i ] * torch .sin (theta_i )
161+ return torch .sqrt (u ** 2 + v ** 2 )
162+
163+
164+ def wing_weight (ls : Tensor ) -> Tensor :
165+ ls = rescale (ls , WING_WEIGHT_LBS , WING_WEIGHT_UBS )
166+ Sw , Wf , A , delta , q , lamb , tc , Nz , Wd , Wp = ls .T
167+ delta *= (torch .pi / 180 ) # degrees to radians
168+ fls = (
169+ 0.036
170+ * Sw ** 0.758
171+ * Wf ** 0.0035
172+ * (A / torch .cos (delta )** 2 )** 0.6
173+ * q ** 0.006
174+ * lamb ** 0.04
175+ * (100 * tc / torch .cos (delta ))** - 0.3
176+ * (Nz * Wd )** 0.49
177+ + Sw * Wp
178+ )
179+ return fls
180+
181+
182+ def friedman (ls : Tensor ) -> Tensor :
183+ ls = rescale (ls , 0.0 , 1.0 )
184+ fls = (
185+ 10.0 * torch .sin (torch .pi * ls [:, 0 ]* ls [:, 1 ])
186+ + 20.0 * (ls [:, 2 ]- 0.5 )** 2
187+ + 10.0 * ls [:, 3 ]
188+ + 5.0 * ls [:, 4 ]
189+ )
190+ return fls
191+
192+
193+ def gnl (ls : Tensor ) -> Tensor :
194+ ls = rescale (ls , 0.0 , 1.0 )
195+ fls = (
196+ torch .exp (torch .sin ((0.9 * (ls [:, 0 ]+ 0.48 ))** 10.0 ))
197+ + ls [:, 1 ]* ls [:, 2 ]
198+ + ls [:, 3 ]
199+ )
200+ return fls
201+
202+
203+ def dnp_8d (ls : Tensor ) -> Tensor :
204+ ls = rescale (ls , 0.0 , 1.0 )
205+ t1 = 4.0 * (ls [:, 0 ] - 2.0 + 8.0 * ls [:, 1 ] - 8.0 * ls [:, 1 ]** 2 )** 2
206+ t2 = (3.0 - 4.0 * ls [:, 1 ])** 2
207+ t3 = 16.0 * torch .sqrt (ls [:, 2 ]+ 1.0 ) * (2.0 * ls [:, 2 ] - 1.0 )** 2
208+ t4 = torch .zeros ((ls .shape [0 ],))
209+ for i in range (3 , 8 ):
210+ t4 += (i + 1 ) * torch .log (1.0 + torch .sum (ls [:, 2 :i + 1 ], dim = 1 ))
211+ return t1 + t2 + t3 + t4
212+
213+
214+ def dnp_exp (ls : Tensor ) -> Tensor :
215+ ls = rescale (ls , 0.0 , 1.0 )
216+ fls = 100 * (
217+ torch .exp (- 2.0 / (ls [:, 0 ]** 1.75 ))
218+ + torch .exp (- 2.0 / (ls [:, 1 ]** 1.5 ))
219+ + torch .exp (- 2.0 / (ls [:, 2 ]** 1.25 ))
220+ )
221+ return fls
222+
223+
224+ def normalise_cs (cs : Tensor , dim : int , b : int , h : int ) -> Tensor :
225+ c_norm = (dim ** h / b ) * cs .abs ().sum ()
226+ return cs / c_norm
227+
228+
229+ def build_genz_1 (dim : int ) -> Callable :
230+ # Oscillatory Genz
231+
232+ w = torch .rand (1 )
233+ cs = torch .rand (dim )
234+ cs = normalise_cs (cs , dim , b = 284.6 , h = 1.5 )
235+
236+ def genz_1 (ls : Tensor ) -> Tensor :
237+ fls = torch .cos (2 * torch .pi * w + torch .sum (cs * 0.5 * (ls + 1 ), dim = 1 ))
238+ return fls
239+
240+ return genz_1
241+
242+
243+ def build_genz_2 (dim : int ) -> Callable :
244+ # Corner peak Genz
245+
246+ cs = torch .rand (dim )
247+ cs = normalise_cs (cs , dim , b = 185.0 , h = 2.0 )
248+
249+ def genz_2 (ls : Tensor ) -> Tensor :
250+ fls = (1.0 + torch .sum (cs * 0.5 * (ls + 1 ), dim = 1 )) ** - (dim - 1 )
251+ return fls
252+
253+ return genz_2
254+
255+ def build_genz_3 (dim : int ) -> Callable :
256+ # Continuous Genz
257+
258+ ws = torch .rand (dim )
259+ cs = torch .rand (dim )
260+ cs = normalise_cs (cs , dim , b = 2040.0 , h = 2.0 )
261+
262+ def genz_3 (ls : Tensor ) -> Tensor :
263+ fls = torch .exp (- torch .sum (cs ** 2 * torch .abs (0.5 * (ls + 1 ) - ws ), dim = 1 ))
264+ return fls
265+
266+ return genz_3
267+
268+
269+ FUNCTIONS = {
270+ r"Ackley" : (ackley , 7 ),
271+ r"Alpine" : (alpine , 7 ),
272+ r"Dixon" : (dixon , 7 ),
273+ r"Exponential" : (exponential , 7 ),
274+ r"Griewank" : (griewank , 7 ),
275+ r"Michaelwicz" : (michaelwicz , 7 ),
276+ r"Piston" : (piston , 7 ),
277+ r"Qing" : (qing , 7 ),
278+ r"Rastrigin" : (rastrigin , 7 ),
279+ r"Rosenbrock" : (rosenbrock , 7 ),
280+ r"Schaffer" : (schaffer , 7 ),
281+ r"Schwefel" : (schwefel , 7 ),
282+ r"Borehole" : (borehole , 8 ),
283+ r"OTL Circuit" : (otl_circuit , 6 ),
284+ r"Robot Arm" : (robot_arm , 8 ),
285+ r"Wing Weight" : (wing_weight , 10 ),
286+ r"Friedman" : (friedman , 5 ),
287+ r"G\&L" : (gnl , 6 ),
288+ r"D\&P 8D" : (dnp_8d , 8 ),
289+ r"D\&P Exp" : (dnp_exp , 3 )
290+ }
0 commit comments