Coverage for moptipy / tests / on_signed_permutations.py: 86%

44 statements  

« prev     ^ index     » next       coverage.py v7.12.0, created at 2025-11-24 08:49 +0000

1"""Test stuff on signed permutations with repetitions.""" 

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 

10from moptipy.spaces.signed_permutations import SignedPermutations 

11from moptipy.tests.op0 import validate_op0 

12from moptipy.tests.op1 import validate_op1 

13 

14 

15def signed_permutations_for_tests( 

16 perm_filter: Callable[[SignedPermutations], bool] | None = None) \ 

17 -> Iterable[SignedPermutations]: 

18 """ 

19 Get a sequence of permutations for tests. 

20 

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

22 use for testing 

23 :returns: the sequence of SignedPermutations 

24 """ 

25 r = default_rng() 

26 pwrs: list[SignedPermutations] = [ 

27 SignedPermutations.standard(2), 

28 SignedPermutations.standard(3), 

29 SignedPermutations.standard(4), 

30 SignedPermutations.standard(5), 

31 SignedPermutations.standard(6), 

32 SignedPermutations.standard(12), 

33 SignedPermutations.standard(23), 

34 SignedPermutations.with_repetitions(2, 2), 

35 SignedPermutations.with_repetitions(2, 3), 

36 SignedPermutations.with_repetitions(3, 2), 

37 SignedPermutations.with_repetitions(3, 3), 

38 SignedPermutations.with_repetitions(5, 5), 

39 SignedPermutations.with_repetitions(int(r.integers(6, 10)), 

40 int(r.integers(2, 7))), 

41 SignedPermutations.with_repetitions(int(r.integers(2, 5)), 

42 int(r.integers(6, 10))), 

43 SignedPermutations.with_repetitions(int(r.integers(130, 500)), 

44 int(r.integers(2, 200))), 

45 SignedPermutations([1, 1, 1, 1, 1, 5, 5, 3]), 

46 SignedPermutations([2, 1, 1, 1, 1, 1])] 

47 if perm_filter is not None: 

48 if not callable(perm_filter): 

49 raise type_error(perm_filter, "perm_filter", None, call=True) 

50 pwrs = [p for p in pwrs if perm_filter(p)] 

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

52 return pwrs 

53 

54 

55def make_signed_permutation_valid(pwr: SignedPermutations) -> \ 

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

57 """ 

58 Create a function that can make permutations with repetitions valid. 

59 

60 :param pwr: the permutations 

61 :returns: the function 

62 """ 

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

64 np.copyto(x, ppp.blueprint) 

65 prnd.shuffle(x) 

66 x *= ((2 * prnd.integers(low=0, high=2, size=len(x))) - 1) 

67 return x 

68 return __make_valid 

69 

70 

71def validate_op0_on_1_signed_permutations( 

72 op0: Op0 | Callable[[SignedPermutations], Op0], 

73 search_space: SignedPermutations, 

74 number_of_samples: int | None = None, 

75 min_unique_samples: int | Callable[[ 

76 int, SignedPermutations], int] | None = None) -> None: 

77 """ 

78 Validate the nullary operator on one `SignedPermutations` instance. 

79 

80 :param op0: the operator or operator factory 

81 :param search_space: the search space 

82 :param number_of_samples: the optional number of samples 

83 :param min_unique_samples: the optional unique samples 

84 """ 

85 args: dict[str, Any] = { 

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

87 "search_space": search_space, 

88 "make_search_space_element_valid": 

89 make_signed_permutation_valid(search_space), 

90 } 

91 if number_of_samples is not None: 

92 args["number_of_samples"] = number_of_samples 

93 if min_unique_samples is not None: 

94 args["min_unique_samples"] = min_unique_samples 

95 validate_op0(**args) 

96 

97 

98def validate_op0_on_signed_permutations( 

99 op0: Op0 | Callable[[SignedPermutations], Op0], 

100 number_of_samples: int | None = None, 

101 min_unique_samples: int | Callable[[ 

102 int, SignedPermutations], int] | None = None, 

103 perm_filter: Callable[[SignedPermutations], bool] | None = None) \ 

104 -> None: 

105 """ 

106 Validate the nullary operator on several `SignedPermutations` instances. 

107 

108 :param op0: the operator or operator factory 

109 :param number_of_samples: the optional number of samples 

110 :param min_unique_samples: the optional unique samples 

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

112 use for testing 

113 """ 

114 for pwr in signed_permutations_for_tests(perm_filter): 

115 validate_op0_on_1_signed_permutations(op0, pwr, number_of_samples, 

116 min_unique_samples) 

117 

118 

119def validate_op1_on_1_signed_permutations( 

120 op1: Op1 | Callable[[SignedPermutations], Op1], 

121 search_space: SignedPermutations, 

122 number_of_samples: int | None = None, 

123 min_unique_samples: int | Callable[[ 

124 int, SignedPermutations], int] | None = None) -> None: 

125 """ 

126 Validate the unary operator on one `SignedPermutations` instance. 

127 

128 :param op1: the operator or operator factory 

129 :param search_space: the search space 

130 :param number_of_samples: the optional number of samples 

131 :param min_unique_samples: the optional unique samples 

132 """ 

133 args: dict[str, Any] = { 

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

135 "search_space": search_space, 

136 "make_search_space_element_valid": 

137 make_signed_permutation_valid(search_space), 

138 } 

139 if number_of_samples is not None: 

140 args["number_of_samples"] = number_of_samples 

141 if min_unique_samples is not None: 

142 args["min_unique_samples"] = min_unique_samples 

143 validate_op1(**args) 

144 

145 

146def validate_op1_on_signed_permutations( 

147 op1: Op1 | Callable[[SignedPermutations], Op1], 

148 number_of_samples: int | None = None, 

149 min_unique_samples: int | Callable[[ 

150 int, SignedPermutations], int] | None = None, 

151 perm_filter: Callable[[SignedPermutations], bool] | None = None) \ 

152 -> None: 

153 """ 

154 Validate the unary operator on several `SignedPermutations` instances. 

155 

156 :param op1: the operator or operator factory 

157 :param number_of_samples: the optional number of samples 

158 :param min_unique_samples: the optional unique samples 

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

160 use for testing 

161 """ 

162 for pwr in signed_permutations_for_tests(perm_filter): 

163 validate_op1_on_1_signed_permutations(op1, pwr, number_of_samples, 

164 min_unique_samples)