Coverage for moptipyapps / spoc / spoc_4 / challenge_1 / beginner / objective_with_penalty.py: 43%
44 statements
« prev ^ index » next coverage.py v7.13.5, created at 2026-04-03 04:37 +0000
« prev ^ index » next coverage.py v7.13.5, created at 2026-04-03 04:37 +0000
1"""
2The objective function of the beginner problem.
4>>> inst = Instance("matching-i")
5>>> obj = BeginnerObjectiveP(inst)
7>>> test_x = np.ndarray(inst.n, dtype=np.bool)
8>>> test_x.fill(0)
10>>> obj.evaluate(test_x)
110
13>>> test_x[0] = 1
14>>> obj.evaluate(test_x)
15-267
16>>> inst[0, -1]
17np.int64(267)
19The clash of two orbits incurs a penalty:
21>>> test_x[2234] = 1
22>>> obj.evaluate(test_x)
23125518718
25>>> inst.penalty - 267 - 7636
26125518718
27"""
29from typing import Final
31import numba # type: ignore
32import numpy as np
33from moptipy.api.objective import Objective
34from moptipy.utils.logger import KeyValueLogSection
36from moptipyapps.spoc.spoc_4.challenge_1.beginner.base_obj import (
37 BaseObjectWithArrays,
38)
39from moptipyapps.spoc.spoc_4.challenge_1.beginner.instance import Instance
42@numba.njit(cache=True, inline="always", fastmath=False, boundscheck=False)
43def _compute(x: np.ndarray, data: np.ndarray, penalty: int,
44 earth: np.ndarray, lunar: np.ndarray, dest: np.ndarray) -> int:
45 """
46 Compute the objective function of the beginner problem.
48 :param x: the candidate solution
49 :param data: the orbit data
50 :param penalty: the penalty for clashes
51 :param earth: the earth orbits
52 :param lunar: the lunar orbits
53 :param dest: the destination orbits
54 :return: the objective value, minus the offset
55 """
56 earth.fill(0)
57 lunar.fill(0)
58 dest.fill(0)
59 result: int = 0
60 for i, use in enumerate(x):
61 if not use:
62 continue
63 ue, ul, ud, uo = data[i, :]
64 if earth[ue]:
65 result += penalty
66 else:
67 earth[ue] = 1
68 if lunar[ul]:
69 result += penalty
70 else:
71 lunar[ul] = 1
72 if dest[ud]:
73 result += penalty
74 else:
75 dest[ud] = 1
76 result -= uo
77 return int(result)
80class BeginnerObjectiveP(BaseObjectWithArrays, Objective):
81 """The objective function of the beginner problem."""
83 def __init__(self, instance: Instance) -> None:
84 """
85 Create the objective function of the beginner problem.
87 :param instance: the instance of the objective function.
88 """
89 super().__init__(instance)
90 #: the penalty
91 self.__p: Final[int] = instance.penalty
93 def evaluate(self, x) -> int:
94 """
95 Evaluate the objective function of the beginner problem.
97 :param x: the solution vector
98 :return: the result
99 """
100 return _compute(x, self.instance, self.__p, self.earth,
101 self.lunar, self.dest)
103 def lower_bound(self) -> int:
104 """
105 Get the lower bound.
107 :return: the lower bound
108 """
109 return 1 - self.__p
111 def upper_bound(self) -> int:
112 """
113 Get the upper bound.
115 :return: the upper bound
116 """
117 return self.instance.n * 3 * self.__p
119 def __str__(self) -> str:
120 """
121 Get the name of the objective function.
123 :return: the name of the objective function
124 """
125 return "spoc4beginnerP"
127 def log_parameters_to(self, logger: KeyValueLogSection) -> None:
128 """
129 Log all parameters of this component as key-value pairs.
131 :param logger: the logger for the parameters
132 """
133 super().log_parameters_to(logger)
134 with logger.scope("i") as inst:
135 self.instance.log_parameters_to(inst)