Coverage for moptipy / examples / bitstrings / linearharmonic.py: 71%
24 statements
« prev ^ index » next coverage.py v7.12.0, created at 2025-11-24 08:49 +0000
« prev ^ index » next coverage.py v7.12.0, created at 2025-11-24 08:49 +0000
1"""
2The linear harmonic objective function.
4The bit at index `i` for `i` in `0..n-1` has weight `i+1`. This is the penalty
5that is incurred if the bit is set to `False`.
6The best objective value, 0, is hence obtained if all bits are `True`.
7The worst objective value, i.e., `n * (n + 1) // 2`, is obtained if all bits
8are `False`.
101. Carola Doerr, Furong Ye, Naama Horesh, Hao Wang, Ofer M. Shir, and Thomas
11 Bäck. Benchmarking Discrete Optimization Heuristics with IOHprofiler.
12 Applied Soft Computing Journal. 88:106027. 2020.
13 doi: https://doi.org/10.1016/j.asoc.2019.106027
142. Stefan Droste, Thomas Jansen, and Ingo Wegener. On the Analysis of the
15 (1+1) Evolutionary Algorithm. *Theoretical Computer Science.*
16 276(1-2):51-81. April 2002.
17 doi: https://doi.org/10.1016/S0304-3975(01)00182-7
183. Thomas Weise, Zhize Wu, Xinlu Li, Yan Chen, and Jörg Lässig. Frequency
19 Fitness Assignment: Optimization without Bias for Good Solutions can be
20 Efficient. *IEEE Transactions on Evolutionary Computation (TEVC)*.
21 27(4):980-992. August 2023.
22 doi: https://doi.org/10.1109/TEVC.2022.3191698
24This is code is part of the research work of Mr. Jiazheng ZENG (曾嘉政),
25a Master's student at the Institute of Applied Optimization
26(应用优化研究所) of the School of Artificial
27Intelligence and Big Data (人工智能与大数据学院) at
28Hefei University (合肥大学) in
29Hefei, Anhui, China (中国安徽省合肥市) under the supervision of
30Prof. Dr. Thomas Weise (汤卫思教授).
31"""
33from typing import Callable, Iterator, cast
35import numba # type: ignore
36import numpy as np
38from moptipy.examples.bitstrings.bitstring_problem import BitStringProblem
41@numba.njit(nogil=True, cache=True)
42def linear_harmonic(x: np.ndarray) -> float:
43 """
44 Evaluate the linear function with harmonic weights.
46 :param x: np array representing the bit string
47 :return: the objective value
49 >>> linear_harmonic(np.array([True, True, True]))
50 0
51 >>> linear_harmonic(np.array([False, True, True]))
52 1
53 >>> linear_harmonic(np.array([True, False, True]))
54 2
55 >>> linear_harmonic(np.array([True, True, False]))
56 3
57 >>> linear_harmonic(np.array([False, False, True]))
58 3
59 >>> linear_harmonic(np.array([False, True, False]))
60 4
61 >>> linear_harmonic(np.array([True, False, False]))
62 5
63 >>> linear_harmonic(np.array([False, False, False]))
64 6
65 >>> (3 * (3 + 1)) // 2
66 6
68 >>> linear_harmonic(np.array([True, True, True, True]))
69 0
70 >>> linear_harmonic(np.array([False, True, True, True]))
71 1
72 >>> linear_harmonic(np.array([True, False, True, True]))
73 2
74 >>> linear_harmonic(np.array([True, True, False, True]))
75 3
76 >>> linear_harmonic(np.array([True, True, True, False]))
77 4
78 >>> linear_harmonic(np.array([False, False, True, True]))
79 3
80 >>> linear_harmonic(np.array([False, True, False, True]))
81 4
82 >>> linear_harmonic(np.array([False, True, True, False]))
83 5
84 >>> linear_harmonic(np.array([True, False, False, True]))
85 5
86 >>> linear_harmonic(np.array([True, False, True, False]))
87 6
88 >>> linear_harmonic(np.array([True, True, False, False]))
89 7
90 >>> linear_harmonic(np.array([False, False, False, True]))
91 6
92 >>> linear_harmonic(np.array([False, False, True, False]))
93 7
94 >>> linear_harmonic(np.array([False, True, False, False]))
95 8
96 >>> linear_harmonic(np.array([True, False, False, False]))
97 9
98 >>> linear_harmonic(np.array([False, False, False, False]))
99 10
100 >>> 4 * (4 + 1) // 2
101 10
103 # n = 1 and 0 true bits
104 >>> linear_harmonic(np.array([0]))
105 1
107 # n = 1 and 1 true bit
108 >>> linear_harmonic(np.array([1]))
109 0
111 # n = 2 and 0 true bits
112 >>> linear_harmonic(np.array([0, 0]))
113 3
115 # n = 2 and 1 true bit
116 >>> linear_harmonic(np.array([1, 0]))
117 2
119 # n = 2 and 1 true bit
120 >>> linear_harmonic(np.array([1, 0]))
121 2
123 # n = 2 and 1 true bit
124 >>> linear_harmonic(np.array([1, 0]))
125 2
127 # n = 2 and 2 true bits
128 >>> linear_harmonic(np.array([1, 1]))
129 0
131 # n = 3 and 0 true bits
132 >>> linear_harmonic(np.array([0, 0, 0]))
133 6
135 # n = 3 and 1 true bit
136 >>> linear_harmonic(np.array([0, 1, 0]))
137 4
139 # n = 3 and 1 true bit
140 >>> linear_harmonic(np.array([0, 0, 1]))
141 3
143 # n = 3 and 1 true bit
144 >>> linear_harmonic(np.array([1, 0, 0]))
145 5
147 # n = 3 and 2 true bits
148 >>> linear_harmonic(np.array([0, 1, 1]))
149 1
151 # n = 3 and 2 true bits
152 >>> linear_harmonic(np.array([1, 0, 1]))
153 2
155 # n = 3 and 2 true bits
156 >>> linear_harmonic(np.array([1, 1, 0]))
157 3
159 # n = 3 and 3 true bits
160 >>> linear_harmonic(np.array([1, 1, 1]))
161 0
163 # n = 4 and 0 true bits
164 >>> linear_harmonic(np.array([0, 0, 0, 0]))
165 10
167 # n = 4 and 1 true bit
168 >>> linear_harmonic(np.array([1, 0, 0, 0]))
169 9
171 # n = 4 and 1 true bit
172 >>> linear_harmonic(np.array([1, 0, 0, 0]))
173 9
175 # n = 4 and 1 true bit
176 >>> linear_harmonic(np.array([1, 0, 0, 0]))
177 9
179 # n = 4 and 2 true bits
180 >>> linear_harmonic(np.array([0, 1, 1, 0]))
181 5
183 # n = 4 and 2 true bits
184 >>> linear_harmonic(np.array([0, 1, 0, 1]))
185 4
187 # n = 4 and 2 true bits
188 >>> linear_harmonic(np.array([1, 0, 0, 1]))
189 5
191 # n = 4 and 3 true bits
192 >>> linear_harmonic(np.array([1, 1, 0, 1]))
193 3
195 # n = 4 and 3 true bits
196 >>> linear_harmonic(np.array([0, 1, 1, 1]))
197 1
199 # n = 4 and 3 true bits
200 >>> linear_harmonic(np.array([1, 0, 1, 1]))
201 2
203 # n = 4 and 4 true bits
204 >>> linear_harmonic(np.array([1, 1, 1, 1]))
205 0
207 # n = 5 and 0 true bits
208 >>> linear_harmonic(np.array([0, 0, 0, 0, 0]))
209 15
211 # n = 5 and 1 true bit
212 >>> linear_harmonic(np.array([0, 1, 0, 0, 0]))
213 13
215 # n = 5 and 1 true bit
216 >>> linear_harmonic(np.array([1, 0, 0, 0, 0]))
217 14
219 # n = 5 and 2 true bits
220 >>> linear_harmonic(np.array([0, 0, 1, 0, 1]))
221 7
223 # n = 5 and 2 true bits
224 >>> linear_harmonic(np.array([0, 1, 0, 1, 0]))
225 9
227 # n = 5 and 2 true bits
228 >>> linear_harmonic(np.array([1, 0, 0, 1, 0]))
229 10
231 # n = 5 and 3 true bits
232 >>> linear_harmonic(np.array([0, 0, 1, 1, 1]))
233 3
235 # n = 5 and 3 true bits
236 >>> linear_harmonic(np.array([0, 0, 1, 1, 1]))
237 3
239 # n = 5 and 3 true bits
240 >>> linear_harmonic(np.array([1, 0, 1, 0, 1]))
241 6
243 # n = 5 and 4 true bits
244 >>> linear_harmonic(np.array([1, 1, 1, 1, 0]))
245 5
247 # n = 5 and 4 true bits
248 >>> linear_harmonic(np.array([1, 1, 1, 1, 0]))
249 5
251 # n = 5 and 4 true bits
252 >>> linear_harmonic(np.array([1, 1, 1, 1, 0]))
253 5
255 # n = 5 and 5 true bits
256 >>> linear_harmonic(np.array([1, 1, 1, 1, 1]))
257 0
259 # n = 6 and 0 true bits
260 >>> linear_harmonic(np.array([0, 0, 0, 0, 0, 0]))
261 21
263 # n = 6 and 1 true bit
264 >>> linear_harmonic(np.array([0, 0, 0, 0, 1, 0]))
265 16
267 # n = 6 and 1 true bit
268 >>> linear_harmonic(np.array([0, 0, 1, 0, 0, 0]))
269 18
271 # n = 6 and 1 true bit
272 >>> linear_harmonic(np.array([0, 0, 0, 0, 0, 1]))
273 15
275 # n = 6 and 2 true bits
276 >>> linear_harmonic(np.array([1, 0, 1, 0, 0, 0]))
277 17
279 # n = 6 and 2 true bits
280 >>> linear_harmonic(np.array([0, 0, 1, 0, 1, 0]))
281 13
283 # n = 6 and 2 true bits
284 >>> linear_harmonic(np.array([0, 0, 0, 0, 1, 1]))
285 10
287 # n = 6 and 3 true bits
288 >>> linear_harmonic(np.array([0, 1, 0, 0, 1, 1]))
289 8
291 # n = 6 and 3 true bits
292 >>> linear_harmonic(np.array([1, 1, 0, 0, 0, 1]))
293 12
295 # n = 6 and 3 true bits
296 >>> linear_harmonic(np.array([1, 1, 0, 0, 1, 0]))
297 13
299 # n = 6 and 4 true bits
300 >>> linear_harmonic(np.array([1, 1, 1, 1, 0, 0]))
301 11
303 # n = 6 and 4 true bits
304 >>> linear_harmonic(np.array([1, 1, 0, 1, 1, 0]))
305 9
307 # n = 6 and 4 true bits
308 >>> linear_harmonic(np.array([1, 1, 1, 0, 0, 1]))
309 9
311 # n = 6 and 5 true bits
312 >>> linear_harmonic(np.array([1, 1, 0, 1, 1, 1]))
313 3
315 # n = 6 and 5 true bits
316 >>> linear_harmonic(np.array([1, 1, 1, 1, 1, 0]))
317 6
319 # n = 6 and 5 true bits
320 >>> linear_harmonic(np.array([1, 1, 1, 1, 0, 1]))
321 5
323 # n = 6 and 6 true bits
324 >>> linear_harmonic(np.array([1, 1, 1, 1, 1, 1]))
325 0
327 # n = 7 and 0 true bits
328 >>> linear_harmonic(np.array([0, 0, 0, 0, 0, 0, 0]))
329 28
331 # n = 7 and 1 true bit
332 >>> linear_harmonic(np.array([0, 0, 1, 0, 0, 0, 0]))
333 25
335 # n = 7 and 1 true bit
336 >>> linear_harmonic(np.array([0, 0, 0, 1, 0, 0, 0]))
337 24
339 # n = 7 and 1 true bit
340 >>> linear_harmonic(np.array([1, 0, 0, 0, 0, 0, 0]))
341 27
343 # n = 7 and 2 true bits
344 >>> linear_harmonic(np.array([0, 1, 0, 0, 0, 1, 0]))
345 20
347 # n = 7 and 2 true bits
348 >>> linear_harmonic(np.array([0, 0, 0, 0, 1, 0, 1]))
349 16
351 # n = 7 and 2 true bits
352 >>> linear_harmonic(np.array([1, 0, 0, 0, 0, 1, 0]))
353 21
355 # n = 7 and 3 true bits
356 >>> linear_harmonic(np.array([0, 1, 0, 0, 0, 1, 1]))
357 13
359 # n = 7 and 3 true bits
360 >>> linear_harmonic(np.array([1, 0, 0, 1, 0, 0, 1]))
361 16
363 # n = 7 and 3 true bits
364 >>> linear_harmonic(np.array([0, 1, 0, 0, 0, 1, 1]))
365 13
367 # n = 7 and 4 true bits
368 >>> linear_harmonic(np.array([1, 1, 0, 1, 0, 0, 1]))
369 14
371 # n = 7 and 4 true bits
372 >>> linear_harmonic(np.array([1, 0, 1, 0, 1, 0, 1]))
373 12
375 # n = 7 and 4 true bits
376 >>> linear_harmonic(np.array([0, 0, 1, 1, 1, 1, 0]))
377 10
379 # n = 7 and 5 true bits
380 >>> linear_harmonic(np.array([1, 1, 1, 0, 0, 1, 1]))
381 9
383 # n = 7 and 5 true bits
384 >>> linear_harmonic(np.array([1, 1, 1, 1, 0, 1, 0]))
385 12
387 # n = 7 and 5 true bits
388 >>> linear_harmonic(np.array([1, 1, 0, 1, 0, 1, 1]))
389 8
391 # n = 7 and 6 true bits
392 >>> linear_harmonic(np.array([1, 1, 1, 1, 1, 1, 0]))
393 7
395 # n = 7 and 6 true bits
396 >>> linear_harmonic(np.array([1, 1, 1, 1, 1, 1, 0]))
397 7
399 # n = 7 and 6 true bits
400 >>> linear_harmonic(np.array([1, 1, 0, 1, 1, 1, 1]))
401 3
403 # n = 7 and 7 true bits
404 >>> linear_harmonic(np.array([1, 1, 1, 1, 1, 1, 1]))
405 0
407 # n = 8 and 0 true bits
408 >>> linear_harmonic(np.array([0, 0, 0, 0, 0, 0, 0, 0]))
409 36
411 # n = 8 and 1 true bit
412 >>> linear_harmonic(np.array([0, 1, 0, 0, 0, 0, 0, 0]))
413 34
415 # n = 8 and 1 true bit
416 >>> linear_harmonic(np.array([0, 0, 0, 0, 1, 0, 0, 0]))
417 31
419 # n = 8 and 1 true bit
420 >>> linear_harmonic(np.array([0, 1, 0, 0, 0, 0, 0, 0]))
421 34
423 # n = 8 and 2 true bits
424 >>> linear_harmonic(np.array([0, 0, 1, 1, 0, 0, 0, 0]))
425 29
427 # n = 8 and 2 true bits
428 >>> linear_harmonic(np.array([0, 0, 1, 0, 0, 0, 1, 0]))
429 26
431 # n = 8 and 2 true bits
432 >>> linear_harmonic(np.array([0, 0, 0, 0, 0, 1, 0, 1]))
433 22
435 # n = 8 and 3 true bits
436 >>> linear_harmonic(np.array([1, 1, 0, 0, 0, 0, 0, 1]))
437 25
439 # n = 8 and 3 true bits
440 >>> linear_harmonic(np.array([1, 1, 0, 0, 0, 0, 0, 1]))
441 25
443 # n = 8 and 3 true bits
444 >>> linear_harmonic(np.array([0, 0, 0, 0, 1, 1, 0, 1]))
445 17
447 # n = 8 and 4 true bits
448 >>> linear_harmonic(np.array([1, 1, 1, 0, 0, 0, 0, 1]))
449 22
451 # n = 8 and 4 true bits
452 >>> linear_harmonic(np.array([1, 1, 1, 0, 0, 0, 0, 1]))
453 22
455 # n = 8 and 4 true bits
456 >>> linear_harmonic(np.array([1, 0, 1, 0, 0, 1, 0, 1]))
457 18
459 # n = 8 and 5 true bits
460 >>> linear_harmonic(np.array([0, 1, 1, 1, 0, 1, 0, 1]))
461 13
463 # n = 8 and 5 true bits
464 >>> linear_harmonic(np.array([0, 0, 1, 0, 1, 1, 1, 1]))
465 7
467 # n = 8 and 5 true bits
468 >>> linear_harmonic(np.array([1, 1, 1, 1, 0, 0, 1, 0]))
469 19
471 # n = 8 and 6 true bits
472 >>> linear_harmonic(np.array([0, 1, 1, 1, 1, 0, 1, 1]))
473 7
475 # n = 8 and 6 true bits
476 >>> linear_harmonic(np.array([0, 1, 1, 1, 1, 1, 1, 0]))
477 9
479 # n = 8 and 6 true bits
480 >>> linear_harmonic(np.array([1, 1, 1, 1, 0, 1, 1, 0]))
481 13
483 # n = 8 and 7 true bits
484 >>> linear_harmonic(np.array([1, 1, 1, 1, 1, 1, 0, 1]))
485 7
487 # n = 8 and 7 true bits
488 >>> linear_harmonic(np.array([1, 1, 1, 0, 1, 1, 1, 1]))
489 4
491 # n = 8 and 7 true bits
492 >>> linear_harmonic(np.array([1, 0, 1, 1, 1, 1, 1, 1]))
493 2
495 # n = 8 and 8 true bits
496 >>> linear_harmonic(np.array([1, 1, 1, 1, 1, 1, 1, 1]))
497 0
499 # n = 9 and 0 true bits
500 >>> linear_harmonic(np.array([0, 0, 0, 0, 0, 0, 0, 0, 0]))
501 45
503 # n = 9 and 1 true bit
504 >>> linear_harmonic(np.array([0, 1, 0, 0, 0, 0, 0, 0, 0]))
505 43
507 # n = 9 and 1 true bit
508 >>> linear_harmonic(np.array([0, 0, 0, 0, 0, 0, 0, 1, 0]))
509 37
511 # n = 9 and 1 true bit
512 >>> linear_harmonic(np.array([0, 0, 0, 0, 0, 1, 0, 0, 0]))
513 39
515 # n = 9 and 2 true bits
516 >>> linear_harmonic(np.array([0, 0, 0, 1, 0, 1, 0, 0, 0]))
517 35
519 # n = 9 and 2 true bits
520 >>> linear_harmonic(np.array([1, 0, 0, 1, 0, 0, 0, 0, 0]))
521 40
523 # n = 9 and 2 true bits
524 >>> linear_harmonic(np.array([1, 1, 0, 0, 0, 0, 0, 0, 0]))
525 42
527 # n = 9 and 3 true bits
528 >>> linear_harmonic(np.array([0, 0, 0, 0, 1, 0, 0, 1, 1]))
529 23
531 # n = 9 and 3 true bits
532 >>> linear_harmonic(np.array([0, 0, 1, 1, 1, 0, 0, 0, 0]))
533 33
535 # n = 9 and 3 true bits
536 >>> linear_harmonic(np.array([0, 1, 1, 0, 0, 0, 1, 0, 0]))
537 33
539 # n = 9 and 4 true bits
540 >>> linear_harmonic(np.array([1, 0, 1, 0, 0, 1, 0, 1, 0]))
541 27
543 # n = 9 and 4 true bits
544 >>> linear_harmonic(np.array([0, 0, 1, 1, 0, 1, 0, 0, 1]))
545 23
547 # n = 9 and 4 true bits
548 >>> linear_harmonic(np.array([0, 1, 0, 1, 0, 1, 0, 0, 1]))
549 24
551 # n = 9 and 5 true bits
552 >>> linear_harmonic(np.array([1, 0, 0, 1, 0, 1, 1, 0, 1]))
553 18
555 # n = 9 and 5 true bits
556 >>> linear_harmonic(np.array([1, 0, 0, 1, 1, 0, 0, 1, 1]))
557 18
559 # n = 9 and 5 true bits
560 >>> linear_harmonic(np.array([0, 1, 1, 1, 0, 1, 0, 0, 1]))
561 21
563 # n = 9 and 6 true bits
564 >>> linear_harmonic(np.array([1, 1, 0, 0, 1, 1, 1, 1, 0]))
565 16
567 # n = 9 and 6 true bits
568 >>> linear_harmonic(np.array([1, 1, 0, 1, 0, 1, 1, 0, 1]))
569 16
571 # n = 9 and 6 true bits
572 >>> linear_harmonic(np.array([1, 1, 1, 0, 1, 0, 1, 1, 0]))
573 19
575 # n = 9 and 7 true bits
576 >>> linear_harmonic(np.array([1, 1, 1, 1, 1, 1, 0, 1, 0]))
577 16
579 # n = 9 and 7 true bits
580 >>> linear_harmonic(np.array([1, 1, 1, 1, 1, 1, 1, 0, 0]))
581 17
583 # n = 9 and 7 true bits
584 >>> linear_harmonic(np.array([0, 1, 0, 1, 1, 1, 1, 1, 1]))
585 4
587 # n = 9 and 8 true bits
588 >>> linear_harmonic(np.array([1, 1, 1, 1, 1, 0, 1, 1, 1]))
589 6
591 # n = 9 and 8 true bits
592 >>> linear_harmonic(np.array([0, 1, 1, 1, 1, 1, 1, 1, 1]))
593 1
595 # n = 9 and 8 true bits
596 >>> linear_harmonic(np.array([1, 1, 1, 1, 1, 1, 0, 1, 1]))
597 7
599 # n = 9 and 9 true bits
600 >>> linear_harmonic(np.array([1, 1, 1, 1, 1, 1, 1, 1, 1]))
601 0
603 # n = 10 and 0 true bits
604 >>> linear_harmonic(np.array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]))
605 55
607 # n = 10 and 1 true bit
608 >>> linear_harmonic(np.array([0, 0, 0, 0, 0, 0, 0, 0, 1, 0]))
609 46
611 # n = 10 and 1 true bit
612 >>> linear_harmonic(np.array([0, 0, 0, 0, 1, 0, 0, 0, 0, 0]))
613 50
615 # n = 10 and 1 true bit
616 >>> linear_harmonic(np.array([0, 1, 0, 0, 0, 0, 0, 0, 0, 0]))
617 53
619 # n = 10 and 2 true bits
620 >>> linear_harmonic(np.array([0, 0, 1, 0, 0, 1, 0, 0, 0, 0]))
621 46
623 # n = 10 and 2 true bits
624 >>> linear_harmonic(np.array([0, 0, 1, 0, 1, 0, 0, 0, 0, 0]))
625 47
627 # n = 10 and 2 true bits
628 >>> linear_harmonic(np.array([0, 0, 0, 0, 0, 0, 0, 0, 1, 1]))
629 36
631 # n = 10 and 3 true bits
632 >>> linear_harmonic(np.array([1, 0, 0, 0, 0, 0, 1, 0, 0, 1]))
633 37
635 # n = 10 and 3 true bits
636 >>> linear_harmonic(np.array([0, 0, 0, 1, 0, 0, 0, 1, 1, 0]))
637 34
639 # n = 10 and 3 true bits
640 >>> linear_harmonic(np.array([0, 0, 1, 1, 0, 0, 0, 0, 0, 1]))
641 38
643 # n = 10 and 4 true bits
644 >>> linear_harmonic(np.array([0, 1, 1, 0, 0, 0, 0, 1, 1, 0]))
645 33
647 # n = 10 and 4 true bits
648 >>> linear_harmonic(np.array([0, 1, 0, 0, 0, 1, 1, 0, 1, 0]))
649 31
651 # n = 10 and 4 true bits
652 >>> linear_harmonic(np.array([0, 1, 1, 0, 0, 1, 0, 0, 0, 1]))
653 34
655 # n = 10 and 5 true bits
656 >>> linear_harmonic(np.array([1, 0, 0, 1, 0, 0, 1, 1, 1, 0]))
657 26
659 # n = 10 and 5 true bits
660 >>> linear_harmonic(np.array([0, 0, 1, 0, 1, 1, 1, 0, 1, 0]))
661 25
663 # n = 10 and 5 true bits
664 >>> linear_harmonic(np.array([0, 0, 0, 1, 1, 0, 0, 1, 1, 1]))
665 19
667 # n = 10 and 6 true bits
668 >>> linear_harmonic(np.array([1, 1, 0, 0, 1, 1, 1, 0, 0, 1]))
669 24
671 # n = 10 and 6 true bits
672 >>> linear_harmonic(np.array([0, 1, 1, 1, 1, 0, 1, 0, 0, 1]))
673 24
675 # n = 10 and 6 true bits
676 >>> linear_harmonic(np.array([0, 0, 1, 0, 1, 1, 1, 1, 0, 1]))
677 16
679 # n = 10 and 7 true bits
680 >>> linear_harmonic(np.array([1, 0, 1, 1, 1, 0, 1, 1, 1, 0]))
681 18
683 # n = 10 and 7 true bits
684 >>> linear_harmonic(np.array([1, 0, 1, 0, 1, 1, 0, 1, 1, 1]))
685 13
687 # n = 10 and 7 true bits
688 >>> linear_harmonic(np.array([1, 1, 1, 1, 1, 1, 0, 1, 0, 0]))
689 26
691 # n = 10 and 8 true bits
692 >>> linear_harmonic(np.array([1, 1, 0, 1, 1, 1, 1, 1, 1, 0]))
693 13
695 # n = 10 and 8 true bits
696 >>> linear_harmonic(np.array([1, 1, 0, 1, 1, 1, 1, 0, 1, 1]))
697 11
699 # n = 10 and 8 true bits
700 >>> linear_harmonic(np.array([1, 0, 1, 1, 1, 0, 1, 1, 1, 1]))
701 8
703 # n = 10 and 9 true bits
704 >>> linear_harmonic(np.array([1, 1, 1, 1, 1, 1, 1, 1, 0, 1]))
705 9
707 # n = 10 and 9 true bits
708 >>> linear_harmonic(np.array([1, 1, 0, 1, 1, 1, 1, 1, 1, 1]))
709 3
711 # n = 10 and 9 true bits
712 >>> linear_harmonic(np.array([1, 1, 0, 1, 1, 1, 1, 1, 1, 1]))
713 3
715 # n = 10 and 10 true bits
716 >>> linear_harmonic(np.array([1, 1, 1, 1, 1, 1, 1, 1, 1, 1]))
717 0
718 """
719 result: int = 0 # The sum of the penalty weights
720 weight: int = 1 # The current penalty weight.
722 for xx in x: # Iterate over all the bits in the array.
723 if not xx: # If the bit is False, then
724 result += weight # add the penalty weight to the result.
725 weight += 1 # Increment the penalty weight by 1. # noqa: SIM113
727 return result # Return the result.
730class LinearHarmonic(BitStringProblem):
731 """The objective function of the linear harmonic benchmark problem."""
733 def __init__(self, n: int) -> None:
734 """
735 Initialize the Linear Harmonic problem instance.
737 :param n: length of the bit string
739 >>> LinearHarmonic(5).evaluate(np.array([
740 ... False, True, False, True]))
741 4
742 """
743 super().__init__(n)
744 self.evaluate = linear_harmonic # type: ignore
746 def upper_bound(self) -> int:
747 """
748 Return the upper bound of the linear harmonic function.
750 :returns: `n * (n + 1) // 2`
752 >>> LinearHarmonic(5).upper_bound()
753 15
754 """
755 return (self.n * (self.n + 1)) // 2
757 def __str__(self) -> str:
758 """
759 Get the name of the Linear Harmonic problem instance.
761 :return: 'linearharmonic_' + n value
763 >>> print(LinearHarmonic(8))
764 linharm_8
765 """
766 return f"linharm_{self.n}"
768 @classmethod
769 def default_instances(
770 cls: type, scale_min: int = 2, scale_max: int = 333) \
771 -> Iterator[Callable[[], "LinearHarmonic"]]:
772 """
773 Get the 78 default instances of the :class:`LinearHarmonic` problem.
775 :param scale_min: the minimum permitted scale, by default `2`
776 :param scale_max: the maximum permitted scale, by default `333`
777 :returns: a sequence of default :class:`LinearHarmonic` instances
779 >>> len(list(LinearHarmonic.default_instances()))
780 78
782 >>> [x() for x in LinearHarmonic.default_instances()]
783 [linharm_2, linharm_3, linharm_4, linharm_5, linharm_6, linharm_7, \
784linharm_8, linharm_9, linharm_10, linharm_11, linharm_12, linharm_13, \
785linharm_14, linharm_15, linharm_16, linharm_17, linharm_18, linharm_19, \
786linharm_20, linharm_21, linharm_22, linharm_23, linharm_24, linharm_25, \
787linharm_26, linharm_27, linharm_28, linharm_29, linharm_30, linharm_31, \
788linharm_32, linharm_33, linharm_36, linharm_40, linharm_41, linharm_42, \
789linharm_44, linharm_48, linharm_49, linharm_50, linharm_55, linharm_59, \
790linharm_60, linharm_64, linharm_66, linharm_70, linharm_77, linharm_79, \
791linharm_80, linharm_81, linharm_85, linharm_88, linharm_90, linharm_96, \
792linharm_99, linharm_100, linharm_107, linharm_111, linharm_121, linharm_125, \
793linharm_128, linharm_144, linharm_149, linharm_169, linharm_170, \
794linharm_192, linharm_196, linharm_199, linharm_200, linharm_222, \
795linharm_225, linharm_243, linharm_256, linharm_269, linharm_289, linharm_300, \
796linharm_324, linharm_333]
797 """
798 return cast("Iterator[Callable[[], LinearHarmonic]]",
799 super().default_instances( # type: ignore
800 scale_min, scale_max))