Source code for moptipy.spaces.intspace
"""An implementation of an integer string based search space."""
from typing import Final
import numpy as np
from pycommons.types import type_error
from moptipy.spaces.nparrayspace import NPArraySpace
from moptipy.utils.logger import KeyValueLogSection
from moptipy.utils.nputils import int_range_to_dtype
from moptipy.utils.strings import num_to_str_for_name
#: the log key for the minimum value
KEY_MIN: Final[str] = "min"
#: the log key for the maximum value
KEY_MAX: Final[str] = "max"
[docs]
class IntSpace(NPArraySpace):
"""
A space where each element is a one-dimensional numpy integer array.
Such spaces can serve as basis for implementing combinatorial
optimization and can be extended to host permutations. Their elements are
instances of :class:`numpy.ndarray`.
>>> s = IntSpace(5, -4, 99)
>>> print(s.dimension)
5
>>> print(s.min_value)
-4
>>> print(s.max_value)
99
>>> print(s.dtype)
int8
>>> s = IntSpace(5, 2, 200)
>>> print(s.dtype)
uint8
>>> s = IntSpace(5, 2, 202340)
>>> print(s.dtype)
int32
"""
def __init__(self, dimension: int,
min_value: int, max_value: int) -> None:
"""
Create the integer-based search space.
:param dimension: The dimension of the search space,
i.e., the number of decision variables.
:param min_value: the minimum value
:param max_value: the maximum value
"""
if not isinstance(min_value, int):
raise type_error(min_value, "min_value", int)
if not isinstance(max_value, int):
raise type_error(max_value, "max_value", int)
if min_value >= max_value:
raise ValueError(
f"max_value > min_value must hold, but got "
f"min_value={min_value} and max_value={max_value}.")
super().__init__(dimension, int_range_to_dtype(
min_value=min_value, max_value=max_value))
#: the lower bound, i.e., the minimum permitted value
self.min_value: Final[int] = min_value
#: the upper bound, i.e., the maximum permitted value
self.max_value: Final[int] = max_value
[docs]
def create(self) -> np.ndarray:
"""
Create an integer vector filled with the minimal value.
:return: the vector
>>> from moptipy.spaces.intspace import IntSpace
>>> s = IntSpace(dimension=12, min_value=5, max_value=332)
>>> v = s.create()
>>> print(s.to_str(v))
5;5;5;5;5;5;5;5;5;5;5;5
>>> print(v.dtype)
int16
"""
return np.full(shape=self.dimension, fill_value=self.min_value,
dtype=self.dtype)
[docs]
def validate(self, x: np.ndarray) -> None:
"""
Validate an integer string.
:param x: the integer string
:raises TypeError: if the string is not an :class:`numpy.ndarray`.
:raises ValueError: if the shape or data type of the vector is wrong
or any of its element is not finite or if an element is out of
the bounds.
"""
super().validate(x)
miv: Final[int] = self.min_value
mav: Final[int] = self.max_value
for index, item in enumerate(x):
if not (miv <= item <= mav):
raise ValueError(
f"x[{index}]={item}, but should be in {miv}..{mav}.")
[docs]
def n_points(self) -> int:
"""
Get the number of possible different integer strings.
:return: (max_value - min_value + 1) ** dimension
>>> print(IntSpace(4, -1, 3).n_points())
625
"""
return (self.max_value - self.min_value + 1) ** self.dimension
def __str__(self) -> str:
"""
Get the name of this integer space.
:return: "ints" + dimension + dtype.char + min_value + "-" + max_value
>>> print(IntSpace(4, -1, 3))
ints4bm1to3
"""
return (f"ints{self.dimension}{self.dtype.char}"
f"{num_to_str_for_name(self.min_value)}to"
f"{num_to_str_for_name(self.max_value)}")
[docs]
def log_parameters_to(self, logger: KeyValueLogSection) -> None:
"""
Log the parameters of this space to the given logger.
:param logger: the logger for the parameters
>>> from moptipy.utils.logger import InMemoryLogger
>>> space = IntSpace(7, -5, 5)
>>> space.dimension
7
>>> with InMemoryLogger() as l:
... with l.key_values("C") as kv:
... space.log_parameters_to(kv)
... text = l.get_log()
>>> text[-2]
'max: 5'
>>> text[-3]
'min: -5'
>>> text[-4]
'dtype: b'
>>> text[-5]
'nvars: 7'
>>> text[-6]
'class: moptipy.spaces.intspace.IntSpace'
>>> text[-7]
'name: ints7bm5to5'
>>> len(text)
8
"""
super().log_parameters_to(logger)
logger.key_value(KEY_MIN, self.min_value)
logger.key_value(KEY_MAX, self.max_value)