Skip to content

Commit bcdb323

Browse files
authored
feat: Allow arbitrary values as categoricals/constants/ordinals (#376)
* feat: Allow arbitrary values as categoricals * fix: Allow constants to have arbitrary values * feat(Constant): Fix transformation issues with `to_vector`
1 parent 82e14ea commit bcdb323

File tree

13 files changed

+609
-152
lines changed

13 files changed

+609
-152
lines changed

changelog.md

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
# Version 1.1.0
2+
3+
* FEAT #376: Allow arbitrary values for `Categorical`, `Ordinal`, and `Constant` hyperparameters.
4+
* FIX #375: Use `object` dtype for `Constant` np.array of values to prevent numpy type conversions of values.
5+
6+
17
# Version 1.0.1
28

39
* FIX #373: Fix `ForbiddenEqualsRelation` when evaluating on vectors of values.
@@ -92,7 +98,7 @@
9298

9399
# Version 0.4.15
94100

95-
* Add `pyproject.toml` to support wheel installation as required in
101+
* Add `pyproject.toml` to support wheel installation as required in
96102
[PEP518](https://medium.com/@grassfedcode/pep-517-and-518-in-plain-english-47208ca8b7a6)
97103

98104
# Version 0.4.14
@@ -120,7 +126,7 @@
120126
* ADD #135: Add weights to the sampling of categorical hyperparameters.
121127
* MAINT #129: Performance improvements for the generation of neighbor configurations.
122128
* MAINT #130: Test the installability of a distribution on travis-ci.
123-
* FIX #140: Fixes a bug which led to samples lower than the lower bound of
129+
* FIX #140: Fixes a bug which led to samples lower than the lower bound of
124130
`UniformFloatHyperparemeter` if the lower bound was larger than zero and quantization was used.
125131
* FIX # 138: Fixes a bug in which the readme wasn't read correctly on systems not using UTF8 as
126132
their default encoding.
@@ -145,29 +151,29 @@
145151

146152
# Version 0.4.9
147153

148-
* Fixes an issue where adding a new forbidden for an unknown hyperparameter
154+
* Fixes an issue where adding a new forbidden for an unknown hyperparameter
149155
did not result in an immediate exception.
150156
* Add a new argument `vector` to `util.deactivate_inactive_hyperparameters`
151157
* Make the number of categories a public variable for categorical and
152158
ordinal hyperparameters
153159

154160
# Version 0.4.8
155161

156-
* Fixes an issue which made serialization of `ForbiddenInCondition` to json
162+
* Fixes an issue which made serialization of `ForbiddenInCondition` to json
157163
fail.
158-
* MAINT #101: Improved error message on setting illegal value in a
164+
* MAINT #101: Improved error message on setting illegal value in a
159165
configuration.
160166
* DOC #91: Added a documentation to automl.github.io/ConfigSpace
161167

162168
# Version 0.4.7
163169

164170
* Tests Python3.7.
165-
* Fixes #87: better handling of Conjunctions when adding them to the
171+
* Fixes #87: better handling of Conjunctions when adding them to the
166172
configuration space.
167173
* MAINT: Improved type annotation in `util.py` which results in improved
168174
performance (due to better Cython optimization).
169-
* MAINT: `util.get_one_exchange_neighborhood` now accepts two arguments
170-
`num_neighbors` and `stdev` which govern the neighborhood creation behaviour
175+
* MAINT: `util.get_one_exchange_neighborhood` now accepts two arguments
176+
`num_neighbors` and `stdev` which govern the neighborhood creation behaviour
171177
of several continuous hyperparameters.
172178
* NEW #85: Add function to obtain active hyperparameters
173179
* NEW #84: Add field for meta-data to the configuration space object.
@@ -291,21 +297,21 @@
291297

292298
# Version 0.2.1
293299

294-
* FIX: bug which changed order of hyperparameters when adding new
295-
hyperparameter. This was non-deterministic due to the use of dict instead
300+
* FIX: bug which changed order of hyperparameters when adding new
301+
hyperparameter. This was non-deterministic due to the use of dict instead
296302
of OrderedDict.
297303
* FIX: compare configurations with == instead of numpy.allclose.
298304
* FIX: issue 2, syntax error no longer present during installation
299305
* FIX: json serialization of configurations and their hyperparameters can now
300-
be deserialized by json and still compare equal
306+
be deserialized by json and still compare equal
301307

302308
# Version 0.2
303309

304-
* FIX: bug which made integer values have different float values in the
310+
* FIX: bug which made integer values have different float values in the
305311
underlying vector representation.
306-
* FIX: bug which could make two configuration spaces compare unequal due to
312+
* FIX: bug which could make two configuration spaces compare unequal due to
307313
the use of defaultdict
308-
* FEATURE: new feature add_configuration_space, which allows to add a whole
314+
* FEATURE: new feature add_configuration_space, which allows to add a whole
309315
configuration space into an existing configuration space
310316
* FEATURE: python3.5 support
311317
* FIX: add function get_parent() to Conjunctions (issue #1)

docs/index.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,28 @@ Those are introduced in the [user guide](./guide.md)
2626
* You can now use your editor to jump to definition and see the source code.
2727
* Contribute more easily!
2828

29+
There is no also better support in Categorical, Ordinal and Constant hyperparameters,
30+
for arbitrary values, for example:
31+
32+
```python
33+
from dataclasses import dataclass
34+
from ConfigSpace import ConfigurationSpace, Constant
35+
36+
@dataclass
37+
class A:
38+
a: int
39+
40+
def f() -> None:
41+
return None
42+
43+
cs = ConfigurationSpace({
44+
"cat": [True, False, None],
45+
"othercat": [A(1), f],
46+
"constant": Constant("constant": (24, 25)),
47+
})
48+
```
49+
50+
2951
With this, we have also deprecated many of the previous functions, simplifying the API
3052
where possible or improving it's clarity. We have tried hard to keep everything backwards
3153
compatible, and also recommend the new functionality to use!

src/ConfigSpace/api/types/categorical.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from typing_extensions import TypeAlias
66

77
from ConfigSpace.hyperparameters import CategoricalHyperparameter, OrdinalHyperparameter
8+
from ConfigSpace.types import NotSet, _NotSet
89

910
# We only accept these types in `items`
1011
T: TypeAlias = Union[str, int, float]
@@ -16,7 +17,7 @@ def Categorical(
1617
name: str,
1718
items: Sequence[T],
1819
*,
19-
default: T | None = None,
20+
default: T | _NotSet = NotSet,
2021
weights: Sequence[float] | None = None,
2122
ordered: Literal[False],
2223
meta: dict | None = None,
@@ -29,7 +30,7 @@ def Categorical(
2930
name: str,
3031
items: Sequence[T],
3132
*,
32-
default: T | None = None,
33+
default: T | _NotSet = NotSet,
3334
weights: Sequence[float] | None = None,
3435
ordered: Literal[True],
3536
meta: dict | None = None,
@@ -42,7 +43,7 @@ def Categorical(
4243
name: str,
4344
items: Sequence[T],
4445
*,
45-
default: T | None = None,
46+
default: T | _NotSet = NotSet,
4647
weights: Sequence[float] | None = None,
4748
ordered: bool = ...,
4849
meta: dict | None = None,
@@ -53,7 +54,7 @@ def Categorical(
5354
name: str,
5455
items: Sequence[T],
5556
*,
56-
default: T | None = None,
57+
default: T | _NotSet = NotSet,
5758
weights: Sequence[float] | None = None,
5859
ordered: bool = False,
5960
meta: dict | None = None,

src/ConfigSpace/conditions.py

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -37,21 +37,13 @@
3737
import numpy as np
3838
from more_itertools import all_equal, unique_everseen
3939

40-
from ConfigSpace.types import f64
40+
from ConfigSpace.types import NotSet, f64
4141

4242
if TYPE_CHECKING:
4343
from ConfigSpace.hyperparameters.hyperparameter import Hyperparameter
4444
from ConfigSpace.types import Array, Mask
4545

4646

47-
class _NotSet:
48-
def __repr__(self) -> str:
49-
return "ValueNotSetObject"
50-
51-
52-
NotSet = _NotSet() # Sentinal value for unset values
53-
54-
5547
class Condition(ABC):
5648
def __init__(
5749
self,

src/ConfigSpace/configuration.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,9 @@
66

77
import numpy as np
88

9-
from ConfigSpace.conditions import NotSet
109
from ConfigSpace.exceptions import IllegalValueError
1110
from ConfigSpace.hyperparameters import FloatHyperparameter
12-
from ConfigSpace.types import f64
11+
from ConfigSpace.types import NotSet, f64
1312

1413
if TYPE_CHECKING:
1514
from ConfigSpace.configuration_space import ConfigurationSpace

src/ConfigSpace/configuration_space.py

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -110,13 +110,9 @@ def _parse_hyperparameters_from_dict(
110110
raise ValueError(f"Can't have empty list for categorical {name}")
111111

112112
yield CategoricalHyperparameter(name, hp)
113-
114-
# If it's an allowed type, it's a constant
115-
elif isinstance(hp, (int, str, float)):
116-
yield Constant(name, hp)
117-
118113
else:
119-
raise ValueError(f"Unknown value '{hp}' for '{name}'")
114+
# It's a constant
115+
yield Constant(name, hp)
120116

121117

122118
class ConfigurationSpace(Mapping[str, Hyperparameter]):

0 commit comments

Comments
 (0)