Coverage for moptipy / tests / on_intspaces.py: 92%

53 statements  

« prev     ^ index     » next       coverage.py v7.13.0, created at 2025-12-15 11:18 +0000

1"""Test stuff on integer spaces.""" 

2 

3from typing import Any, Callable, Iterable, cast 

4 

5import numpy as np 

6from numpy.random import Generator, default_rng 

7from pycommons.types import type_error 

8 

9from moptipy.api.operators import Op0, Op1, Op2 

10from moptipy.spaces.intspace import IntSpace 

11from moptipy.tests.op0 import validate_op0 

12from moptipy.tests.op1 import validate_op1 

13from moptipy.tests.op2 import validate_op2 

14 

15 

16def intspaces_for_tests( 

17 space_filter: Callable[[IntSpace], bool] | None = None)\ 

18 -> Iterable[IntSpace]: 

19 """ 

20 Get a sequence of integer spaces for tests. 

21 

22 :param perm_filter: an optional filter to sort out permutations we cannot 

23 use for testing 

24 :returns: the sequence of SignedPermutations 

25 """ 

26 r = default_rng() 

27 pwrs: list[IntSpace] = [ 

28 IntSpace(1, 0, 1), 

29 IntSpace(2, 0, 1), 

30 IntSpace(9, 0, 1), 

31 IntSpace(1, -1, 1), 

32 IntSpace(2, -1, 1), 

33 IntSpace(13, -1, 1), 

34 IntSpace(1, -12, 17), 

35 IntSpace(2, -11, 9), 

36 IntSpace(16, -23, 25), 

37 IntSpace(1, 0, 127), 

38 IntSpace(2, -128, 127), 

39 IntSpace(1, -128, 128), 

40 IntSpace(1, -2**15, 2**15 - 1), 

41 IntSpace(1, -2**15, 2**15), 

42 IntSpace(*map(int, ( 

43 r.integers(1, 100), r.integers(0, 10), r.integers(10, 100)))), 

44 IntSpace(*map(int, ( 

45 r.integers(1, 100), r.integers(-100, 0), r.integers(1, 100)))), 

46 IntSpace(*map(int, ( 

47 r.integers(1, 100), r.integers(-100, -10), 

48 r.integers(-9, 100))))] 

49 if space_filter is not None: 

50 if not callable(space_filter): 

51 raise type_error(space_filter, "perm_filter", None, call=True) 

52 pwrs = [p for p in pwrs if space_filter(p)] 

53 r.shuffle(cast("list", pwrs)) 

54 return pwrs 

55 

56 

57def make_ints_valid(space: IntSpace) -> \ 

58 Callable[[Generator, np.ndarray], np.ndarray]: 

59 """ 

60 Create a function that can make an int vector valid. 

61 

62 :param space: the integer space 

63 :returns: the function 

64 """ 

65 def __make_valid(prnd: Generator, x: np.ndarray, ppp=space) -> np.ndarray: 

66 np.copyto(x, prnd.integers(low=ppp.min_value, high=ppp.max_value, 

67 size=ppp.dimension, endpoint=True)) 

68 return x 

69 return __make_valid 

70 

71 

72def validate_op0_on_1_intspace( 

73 op0: Op0 | Callable[[IntSpace], Op0], 

74 search_space: IntSpace, 

75 number_of_samples: int | None = None, 

76 min_unique_samples: int | Callable[[ 

77 int, IntSpace], int] | None = None) -> None: 

78 """ 

79 Validate the nullary operator on one `IntSpace` instance. 

80 

81 :param op0: the operator or operator factory 

82 :param search_space: the search space 

83 :param number_of_samples: the optional number of samples 

84 :param min_unique_samples: the optional unique samples 

85 """ 

86 args: dict[str, Any] = { 

87 "op0": op0(search_space) if callable(op0) else op0, 

88 "search_space": search_space, 

89 "make_search_space_element_valid": 

90 make_ints_valid(search_space), 

91 } 

92 if number_of_samples is not None: 

93 args["number_of_samples"] = number_of_samples 

94 if min_unique_samples is not None: 

95 args["min_unique_samples"] = min_unique_samples 

96 validate_op0(**args) 

97 

98 

99def validate_op0_on_intspaces( 

100 op0: Op0 | Callable[[IntSpace], Op0], 

101 number_of_samples: int | None = None, 

102 min_unique_samples: int | Callable[[ 

103 int, IntSpace], int] | None = None, 

104 space_filter: Callable[[IntSpace], bool] | None = None) \ 

105 -> None: 

106 """ 

107 Validate the nullary operator on several `IntSpace` instances. 

108 

109 :param op0: the operator or operator factory 

110 :param number_of_samples: the optional number of samples 

111 :param min_unique_samples: the optional unique samples 

112 :param space_filter: an optional filter to sort out permutations we cannot 

113 use for testing 

114 """ 

115 for pwr in intspaces_for_tests(space_filter): 

116 validate_op0_on_1_intspace( 

117 op0, pwr, number_of_samples, min_unique_samples) 

118 

119 

120def validate_op1_on_1_intspace( 

121 op1: Op1 | Callable[[IntSpace], Op1], 

122 search_space: IntSpace, 

123 number_of_samples: int | None = None, 

124 min_unique_samples: int | Callable[[ 

125 int, IntSpace], int] | None = None) -> None: 

126 """ 

127 Validate the unary operator on one `IntSpace` instance. 

128 

129 :param op1: the operator or operator factory 

130 :param search_space: the search space 

131 :param number_of_samples: the optional number of samples 

132 :param min_unique_samples: the optional unique samples 

133 """ 

134 args: dict[str, Any] = { 

135 "op1": op1(search_space) if callable(op1) else op1, 

136 "search_space": search_space, 

137 "make_search_space_element_valid": 

138 make_ints_valid(search_space), 

139 } 

140 if number_of_samples is not None: 

141 args["number_of_samples"] = number_of_samples 

142 if min_unique_samples is not None: 

143 args["min_unique_samples"] = min_unique_samples 

144 validate_op1(**args) 

145 

146 

147def validate_op1_on_intspaces( 

148 op1: Op1 | Callable[[IntSpace], Op1], 

149 number_of_samples: int | None = None, 

150 min_unique_samples: int | Callable[[ 

151 int, IntSpace], int] | None = None, 

152 space_filter: Callable[[IntSpace], bool] | None = None) \ 

153 -> None: 

154 """ 

155 Validate the unary operator on several `IntSpace` instances. 

156 

157 :param op1: the operator or operator factory 

158 :param number_of_samples: the optional number of samples 

159 :param min_unique_samples: the optional unique samples 

160 :param space_filter: an optional filter to sort out permutations we cannot 

161 use for testing 

162 """ 

163 for pwr in intspaces_for_tests(space_filter): 

164 validate_op1_on_1_intspace( 

165 op1, pwr, number_of_samples, min_unique_samples) 

166 

167 

168def validate_op2_on_1_intspace( 

169 op2: Op2 | Callable[[IntSpace], Op2], 

170 search_space: IntSpace, 

171 number_of_samples: int | None = None, 

172 min_unique_samples: 

173 int | Callable[[int, IntSpace], int] | None 

174 = None) -> None: 

175 """ 

176 Validate the binary operator on one `IntSpace` instance. 

177 

178 :param op2: the operator or operator factory 

179 :param search_space: the search space 

180 :param number_of_samples: the optional number of samples 

181 :param min_unique_samples: the optional unique samples 

182 """ 

183 args: dict[str, Any] = { 

184 "op2": op2(search_space) if callable(op2) else op2, 

185 "search_space": search_space, 

186 "make_search_space_element_valid": make_ints_valid(search_space), 

187 } 

188 if number_of_samples is not None: 

189 args["number_of_samples"] = number_of_samples 

190 if min_unique_samples is not None: 

191 args["min_unique_samples"] = min_unique_samples 

192 validate_op2(**args) 

193 

194 

195def validate_op2_on_intspaces( 

196 op2: Op2 | Callable[[IntSpace], Op2], 

197 number_of_samples: int | None = None, 

198 min_unique_samples: 

199 int | Callable[[int, IntSpace], int] | None = None, 

200 space_filter: Callable[[IntSpace], bool] | None = None) -> None: 

201 """ 

202 Validate the binary operator on several `IntSpace` instances. 

203 

204 :param op2: the operator or operator factory 

205 :param number_of_samples: the optional number of samples 

206 :param min_unique_samples: the optional unique samples 

207 :param space_filter: an optional filter to sort out permutations we cannot 

208 use for testing 

209 """ 

210 for bst in intspaces_for_tests(space_filter): 

211 validate_op2_on_1_intspace( 

212 op2, bst, number_of_samples, min_unique_samples)