Coverage for moptipy / spaces / intspace.py: 95%
37 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"""An implementation of an integer string based search space."""
3from typing import Final
5import numpy as np
6from pycommons.types import type_error
8from moptipy.spaces.nparrayspace import NPArraySpace
9from moptipy.utils.logger import KeyValueLogSection
10from moptipy.utils.nputils import int_range_to_dtype
11from moptipy.utils.strings import num_to_str_for_name
13#: the log key for the minimum value
14KEY_MIN: Final[str] = "min"
15#: the log key for the maximum value
16KEY_MAX: Final[str] = "max"
19class IntSpace(NPArraySpace):
20 """
21 A space where each element is a one-dimensional numpy integer array.
23 Such spaces can serve as basis for implementing combinatorial
24 optimization and can be extended to host permutations. Their elements are
25 instances of :class:`numpy.ndarray`.
27 >>> s = IntSpace(5, -4, 99)
28 >>> print(s.dimension)
29 5
30 >>> print(s.min_value)
31 -4
32 >>> print(s.max_value)
33 99
34 >>> print(s.dtype)
35 int8
36 >>> s = IntSpace(5, 2, 200)
37 >>> print(s.dtype)
38 uint8
39 >>> s = IntSpace(5, 2, 202340)
40 >>> print(s.dtype)
41 int32
42 """
44 def __init__(self, dimension: int,
45 min_value: int, max_value: int) -> None:
46 """
47 Create the integer-based search space.
49 :param dimension: The dimension of the search space,
50 i.e., the number of decision variables.
51 :param min_value: the minimum value
52 :param max_value: the maximum value
53 """
54 if not isinstance(min_value, int):
55 raise type_error(min_value, "min_value", int)
56 if not isinstance(max_value, int):
57 raise type_error(max_value, "max_value", int)
58 if min_value >= max_value:
59 raise ValueError(
60 f"max_value > min_value must hold, but got "
61 f"min_value={min_value} and max_value={max_value}.")
62 super().__init__(dimension, int_range_to_dtype(
63 min_value=min_value, max_value=max_value))
64 #: the lower bound, i.e., the minimum permitted value
65 self.min_value: Final[int] = min_value
66 #: the upper bound, i.e., the maximum permitted value
67 self.max_value: Final[int] = max_value
69 def create(self) -> np.ndarray:
70 """
71 Create an integer vector filled with the minimal value.
73 :return: the vector
75 >>> from moptipy.spaces.intspace import IntSpace
76 >>> s = IntSpace(dimension=12, min_value=5, max_value=332)
77 >>> v = s.create()
78 >>> print(s.to_str(v))
79 5;5;5;5;5;5;5;5;5;5;5;5
80 >>> print(v.dtype)
81 int16
82 """
83 return np.full(shape=self.dimension, fill_value=self.min_value,
84 dtype=self.dtype)
86 def validate(self, x: np.ndarray) -> None:
87 """
88 Validate an integer string.
90 :param x: the integer string
91 :raises TypeError: if the string is not an :class:`numpy.ndarray`.
92 :raises ValueError: if the shape or data type of the vector is wrong
93 or any of its element is not finite or if an element is out of
94 the bounds.
95 """
96 super().validate(x)
98 miv: Final[int] = self.min_value
99 mav: Final[int] = self.max_value
100 for index, item in enumerate(x):
101 if not (miv <= item <= mav):
102 raise ValueError(
103 f"x[{index}]={item}, but should be in {miv}..{mav}.")
105 def n_points(self) -> int:
106 """
107 Get the number of possible different integer strings.
109 :return: (max_value - min_value + 1) ** dimension
111 >>> print(IntSpace(4, -1, 3).n_points())
112 625
113 """
114 return (self.max_value - self.min_value + 1) ** self.dimension
116 def __str__(self) -> str:
117 """
118 Get the name of this integer space.
120 :return: "ints" + dimension + dtype.char + min_value + "-" + max_value
122 >>> print(IntSpace(4, -1, 3))
123 ints4bm1to3
124 """
125 return (f"ints{self.dimension}{self.dtype.char}"
126 f"{num_to_str_for_name(self.min_value)}to"
127 f"{num_to_str_for_name(self.max_value)}")
129 def log_parameters_to(self, logger: KeyValueLogSection) -> None:
130 """
131 Log the parameters of this space to the given logger.
133 :param logger: the logger for the parameters
135 >>> from moptipy.utils.logger import InMemoryLogger
136 >>> space = IntSpace(7, -5, 5)
137 >>> space.dimension
138 7
139 >>> with InMemoryLogger() as l:
140 ... with l.key_values("C") as kv:
141 ... space.log_parameters_to(kv)
142 ... text = l.get_log()
143 >>> text[-2]
144 'max: 5'
145 >>> text[-3]
146 'min: -5'
147 >>> text[-4]
148 'dtype: b'
149 >>> text[-5]
150 'nvars: 7'
151 >>> text[-6]
152 'class: moptipy.spaces.intspace.IntSpace'
153 >>> text[-7]
154 'name: ints7bm5to5'
155 >>> len(text)
156 8
157 """
158 super().log_parameters_to(logger)
159 logger.key_value(KEY_MIN, self.min_value)
160 logger.key_value(KEY_MAX, self.max_value)