Skip to content

Commit

Permalink
D. Jabs:
Browse files Browse the repository at this point in the history
- Optimized imports
- Now shape can only be a tuple and not an int anymore
  • Loading branch information
Dennis Jabs committed Nov 15, 2023
1 parent ba2ca17 commit 9f964f0
Show file tree
Hide file tree
Showing 15 changed files with 194 additions and 179 deletions.
5 changes: 1 addition & 4 deletions PyHyperparameterSpace/configuration.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
from typing import Mapping, Iterator, Any, Union
import numpy as np
import yaml
import json
from typing import Any, Iterator, Mapping


class HyperparameterConfiguration(Mapping[str, Any]):
Expand Down
2 changes: 0 additions & 2 deletions PyHyperparameterSpace/dist/abstract_dist.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
from abc import ABC, abstractmethod
from typing import Any, Union, Iterable
import numpy as np


class Distribution(ABC):
Expand Down
2 changes: 1 addition & 1 deletion PyHyperparameterSpace/dist/categorical.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from typing import Union
import numpy as np

import numpy as np

from PyHyperparameterSpace.dist.abstract_dist import Distribution

Expand Down
1 change: 1 addition & 0 deletions PyHyperparameterSpace/dist/continuous.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from typing import Union

import numpy as np

from PyHyperparameterSpace.dist.abstract_dist import Distribution
Expand Down
22 changes: 10 additions & 12 deletions PyHyperparameterSpace/hp/abstract_hp.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
from abc import ABC, abstractmethod
from typing import Union, Iterable, Any
import numpy as np
from typing import Any, Iterable, Union

from PyHyperparameterSpace.dist.abstract_dist import Distribution
from PyHyperparameterSpace.dist.continuous import Normal
import numpy as np


class Hyperparameter(ABC):
Expand All @@ -25,7 +23,7 @@ def __init__(
self,
name: str,
default: Any = None,
shape: Union[int, tuple[int, ...], None] = None,
shape: Union[tuple[int, ...], None] = None,
):
if isinstance(default, list):
default = np.array(default)
Expand Down Expand Up @@ -55,10 +53,10 @@ def get_default(self) -> Any:
"""
return self._default

def get_shape(self) -> Union[int, tuple[int, ...], None]:
def get_shape(self) -> tuple[int, ...]:
"""
Returns:
Union[int, tuple[int, ...], None]:
tuple[int, ...]:
Shape of the hyperparameter
"""
return self._shape
Expand Down Expand Up @@ -104,7 +102,7 @@ def _is_legal_default(self, default: Any) -> bool:
pass

@abstractmethod
def _check_shape(self, shape: Union[int, tuple[int, ...], None]) -> Union[int, tuple[int, ...], None]:
def _check_shape(self, shape: Union[tuple[int, ...], None]) -> tuple[int, ...]:
"""
Checks if the given shape is legal. A shape is called legal if it fulfills the format (...)
- (dim1, dim2, ...)
Expand All @@ -118,13 +116,13 @@ def _check_shape(self, shape: Union[int, tuple[int, ...], None]) -> Union[int, t
Shape to check
Returns:
Union[int, tuple[int, ...], None]:
tuple[int, ...]:
Legal shape
"""
pass

@abstractmethod
def _is_legal_shape(self, shape: Union[int, tuple[int, ...], None]) -> bool:
def _is_legal_shape(self, shape: tuple[int, ...]) -> bool:
"""
Returns true if the given shape fulfills the format (...)
- (dim1, dim2, ...)
Expand All @@ -134,7 +132,7 @@ def _is_legal_shape(self, shape: Union[int, tuple[int, ...], None]) -> bool:
and has the same dimension as the given default value.
Args:
shape (Union[int, tuple[int, ...], None]):
shape (tuple[int, ...]):
Shape to check
Returns:
Expand Down Expand Up @@ -206,7 +204,7 @@ def __setstate__(self, state):
def _get_sample_size(
cls,
size: Union[int, None] = None,
shape: Union[int, tuple[int, ...]] = None,
shape: Union[tuple[int, ...], None] = None,
) -> Union[int, tuple[int], None]:
"""
Returns the resulting shape of the sample, according to size and shape.
Expand Down
71 changes: 34 additions & 37 deletions PyHyperparameterSpace/hp/categorical.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from typing import Union, Iterable, Any
from typing import Any, Union

import numpy as np

from PyHyperparameterSpace.dist.abstract_dist import Distribution
Expand Down Expand Up @@ -29,7 +30,7 @@ def __init__(
name: str,
choices: list[Any],
default: Union[Any, None] = None,
shape: Union[int, tuple[int, ...], None] = None,
shape: Union[tuple[int, ...], None] = None,
distribution: Union[Distribution, None] = None,
):
if isinstance(choices, list):
Expand Down Expand Up @@ -76,7 +77,7 @@ def _check_choices(self, choices: list[Any]) -> list[Any]:
if self._is_legal_choices(choices):
return choices
else:
raise Exception(f"Illegal choices {choices}!")
raise Exception(f"Illegal choices {choices}. The argument should be a list or an np.ndarray!")

def _is_legal_choices(self, choices: Union[list[Any], None]) -> bool:
"""
Expand All @@ -96,53 +97,49 @@ def _is_legal_choices(self, choices: Union[list[Any], None]) -> bool:
return False

def _check_default(self, default: Union[Any, None]) -> Any:
if default is None:
if self._distribution is not None:
# Case: Take the option with the highest probability as default value
return self._choices[np.argmax(self._distribution.weights)]
else:
# Case: Take the first option as default value
return self._choices[0]
if default is None and self._distribution is not None:
# Case: Take the option with the highest probability as default value
return self._choices[np.argmax(self._distribution.weights)]
elif default is None and self._distribution is None:
# Case: Take the first option as default value
return self._choices[0]
elif self._is_legal_default(default):
# Case: default is given and legal
return default
else:
raise Exception(f"Illegal default {default}!")
# Case: default is illegal
raise Exception(f"Illegal default {default}. The argument should be given in choices!")

def _is_legal_default(self, default: Union[Any, None]) -> bool:
if isinstance(default, (list, np.ndarray)):
# Case: default is a vector/matrix value
return any(np.array_equal(default, choice) for choice in self._choices)
else:
# Case: default is a single value
return default in self._choices

def _check_shape(self, shape: Union[int, tuple[int, ...], None]) -> Union[int, tuple[int, ...], None]:
if shape is None:
# Case: Adjust the shape according to the given default value
if self._default is None or isinstance(self._default, (int, float, bool, str)):
# Case: default value is not given or is single dimensional
return (1,)
elif isinstance(self._default, np.ndarray):
# Case: default value is multidimensional
return self._default.shape
def _check_shape(self, shape: Union[tuple[int, ...], None]) -> tuple[int, ...]:
if shape is None and isinstance(self._choices[0], (int, float, bool, str, np.int_, np.float_, np.str_, np.bool_)):
# Case: shape is not given and values in choices are single dimensional
return 1,
elif shape is None and isinstance(self._choices[0], np.ndarray):
# Case: shape is not given and values in choices are multidimensional
return self._choices[0].shape
elif self._is_legal_shape(shape):
# Case: shape is given and legal
return shape
else:
# Case: shape is illegal
raise Exception(f"Illegal shape {shape}!")

def _is_legal_shape(self, shape: Union[int, tuple[int, ...]]) -> bool:
if shape == 1 or shape == (1,):
# Case: shape refers to single dimensional
if isinstance(self._default, (int, float, bool, str)):
return True
elif isinstance(shape, int):
# Case: shape refers to array-like dimensional
if isinstance(self._default, np.ndarray) and shape == len(self._default) and self._default.ndim == 1:
# Case: default is array-like dimensional
return True
elif isinstance(shape, tuple) and all(isinstance(s, int) for s in shape):
# Case: shape refers to multidimensional
if isinstance(self._default, np.ndarray) and shape == self._default.shape:
# Case: default value is multidimensional
return True
def _is_legal_shape(self, shape: tuple[int, ...]) -> bool:
if shape == (1,) and isinstance(self._choices[0], (int, float, bool, str, np.int_, np.float_, np.str_, np.bool_)):
# Case: shape and values in choices refers to single dimensional
return True
elif isinstance(shape, tuple) and all(isinstance(s, int) for s in shape) and \
isinstance(self._choices[0], np.ndarray) and shape == self._choices[0].shape:
# Case: shape and values in choices refers to multidimensional
return True
return False

def _check_distribution(self, distribution: Union[Distribution, None]) -> Distribution:
Expand All @@ -165,7 +162,7 @@ def _check_distribution(self, distribution: Union[Distribution, None]) -> Distri
# Case: Distribution is given and legal
return distribution
else:
raise Exception(f"Illegal distribution {distribution}!")
raise Exception(f"Illegal distribution {distribution}. The argument should be a class of Choice(...)!")

def _is_legal_distribution(self, distribution: Distribution) -> bool:
"""
Expand Down Expand Up @@ -227,7 +224,7 @@ def __hash__(self) -> int:
return hash(self.__repr__())

def __repr__(self) -> str:
text = f"Categorical({self._name}, choices={self._choices}, default={self._default}, distribution={self._distribution})"
text = f"Categorical({self._name}, choices={self._choices}, default={self._default}, shape={self._shape}, distribution={self._distribution})"
return text

def __getstate__(self) -> dict:
Expand Down
56 changes: 24 additions & 32 deletions PyHyperparameterSpace/hp/constant.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from typing import Union, Iterable, Any
from typing import Any, Union

import numpy as np

from PyHyperparameterSpace.dist.abstract_dist import Distribution
from PyHyperparameterSpace.hp.abstract_hp import Hyperparameter


Expand All @@ -10,7 +10,7 @@ class Constant(Hyperparameter):
Class to represent a constant hyperparameter, where the given default value does not get changed by the
sampling procedure.
Attributes:
Args:
name (str):
Name of the hyperparameter
Expand All @@ -25,51 +25,43 @@ def __init__(
self,
name: str,
default: Any,
shape: Union[int, tuple[int, ...], None] = None,
shape: Union[tuple[int, ...], None] = None,
):
super().__init__(name=name, shape=shape, default=default)

def _check_default(self, default: Any) -> Any:
if self._is_legal_default(default):
return default
else:
raise Exception(f"Illegal default value {default}")
raise Exception(f"Illegal default {default}. The argument should be given!")

def _is_legal_default(self, default: Any) -> bool:
if default is None:
return False
return True

def _check_shape(self, shape: Union[int, tuple[int, ...], None]) -> Union[int, tuple[int, ...]]:
if shape is None:
# Case: Adjust the shape according to the given default value
if isinstance(self._default, (int, float, bool, str)):
# Case: default is single dimensional
return (1,)
elif isinstance(self._default, np.ndarray):
# Case: default is multidimensional
return self._default.shape
def _check_shape(self, shape: Union[tuple[int, ...], None]) -> Union[tuple[int, ...]]:
if shape is None and isinstance(self._default, (int, float, bool, str, np.int_, np.float_, np.str_, np.bool_)):
# Case: shape is not given and default is single dimensional
return 1,
elif shape is None and isinstance(self._default, np.ndarray):
# Case: shape is not given and default is multidimensional
return self._default.shape
elif self._is_legal_shape(shape):
# Case: shape is given and has to be checked
return shape
else:
raise Exception(f"Illegal shape {shape}!")

def _is_legal_shape(self, shape: Union[int, tuple[int, ...]]) -> bool:
if shape == 1 or shape == (1,):
# Case: shape refers to single dimensional
if isinstance(self._default, (int, float, bool, str)):
# Case: default is single dimensional
return True
elif isinstance(shape, int):
# Case: shape refers to array-like dimensional
if isinstance(self._default, np.ndarray) and shape == len(self._default) and self._default.ndim == 1:
# Case: default is array-like dimensional
return True
elif isinstance(shape, tuple) and all(isinstance(s, int) for s in shape):
# Case: shape refers to multi-dimensional
if isinstance(self._default, np.ndarray) and shape == self._default.shape:
# Case: default is multi-dimensional
return True
# Case: shape is not valid
raise Exception(f"Illegal shape {shape}. The argument should be given in the format (dim1, ...)!")

def _is_legal_shape(self, shape: tuple[int, ...]) -> bool:
if shape == (1,) and isinstance(self._default, (int, float, bool, str, np.int_, np.float_, np.str_, np.bool_)):
# Case: shape and default refers to single dimensional
return True
elif isinstance(shape, tuple) and all(isinstance(s, int) for s in shape) and \
isinstance(self._default, np.ndarray) and shape == self._default.shape:
# Case: shape and default refers to multidimensional
return True
return False

def sample(self, random: np.random.RandomState, size: Union[int, None] = None) -> Any:
Expand Down
Loading

0 comments on commit 9f964f0

Please sign in to comment.