Skip to content

Commit

Permalink
Fides 0.7.3 (#48)
Browse files Browse the repository at this point in the history
* Verify options are of correct type (#45)

* Verify options are of correct type

Wasn't checked so far and led to very uninformative errors if wrong options were passed.

* Apply suggestions from code review

Co-authored-by: Fabian Fröhlich <[email protected]>

* fix runtime warning for unbouned vars, fixes #46

* fixup

* fix refined step

* move validation check, reenable passing strs for enums

* fixup option validation, remove deprecated checks

* Update version.py

Co-authored-by: Daniel Weindl <[email protected]>
  • Loading branch information
FFroehlich and dweindl authored Nov 27, 2021
1 parent 4a666b5 commit 0ea8078
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 47 deletions.
46 changes: 46 additions & 0 deletions fides/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@
import enum
import numpy as np

from numbers import Real, Integral
from pathlib import PosixPath, WindowsPath

from typing import Dict


class Options(str, enum.Enum):
"""
Expand Down Expand Up @@ -91,3 +96,44 @@ class ExitFlag(int, enum.Enum):
FTOL = 1 #: Converged according to fval difference
XTOL = 2 #: Converged according to x difference
GTOL = 3 #: Converged according to gradient norm


def validate_options(options: Dict):
"""Check if the chosen options are valid"""
expected_types = {
Options.MAXITER: Integral,
Options.MAXTIME: Real,
Options.FATOL: Real,
Options.FRTOL: Real,
Options.XTOL: Real,
Options.GATOL: Real,
Options.GRTOL: Real,
Options.SUBSPACE_DIM: (SubSpaceDim, str),
Options.STEPBACK_STRAT: (StepBackStrategy, str),
Options.THETA_MAX: Real,
Options.DELTA_INIT: Real,
Options.MU: Real,
Options.ETA: Real,
Options.GAMMA1: Real,
Options.GAMMA2: Real,
Options.HISTORY_FILE: (str, PosixPath, WindowsPath),
}
for option_key, option_value in options.items():
try:
option = Options(option_key)
except ValueError:
raise ValueError(f'{option_key} is not a valid options field.')

if option_key is Options.SUBSPACE_DIM:
option_value = SubSpaceDim(option_value)

if option_key is Options.STEPBACK_STRAT:
option_value = StepBackStrategy(option_value)

expected_type = expected_types[option]
if not isinstance(option_value, expected_type):
if expected_type == Integral and int(option_value) == option_value:
continue
raise TypeError(f'Type mismatch for option {option_key}. '
f'Expected {expected_type} but got '
f'{type(option_value)}')
46 changes: 2 additions & 44 deletions fides/minimize.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,11 @@
HybridFraction, FX, IterativeHessianApproximation, TSSM, GNSBFGS
)
from .constants import (
Options, ExitFlag, DEFAULT_OPTIONS, StepBackStrategy, SubSpaceDim
Options, ExitFlag, DEFAULT_OPTIONS, StepBackStrategy, SubSpaceDim,
validate_options
)
from .logging import create_logger
from collections import defaultdict
from numbers import Real, Integral
from pathlib import PosixPath, WindowsPath
from typing import Callable, Dict, Optional, Tuple, Union, List


Expand Down Expand Up @@ -832,50 +831,9 @@ def check_in_bounds(self, x: Optional[np.ndarray] = None):
f'{diff[ix]} {pointstr}')

def get_option(self, option):
if option not in Options:
raise ValueError(f'{option} is not a valid option name.')

if option not in DEFAULT_OPTIONS:
raise ValueError(f'{option} is missing its default option.')

return self.options.get(option, DEFAULT_OPTIONS.get(option))


def _min_max_evs(mat: np.ndarray):
evs = np.linalg.eigvals(mat)
return np.real(np.min(evs)), np.real(np.max(evs))


def validate_options(options: Dict):
"""Check if the chosen options are valid"""
expected_types = {
Options.MAXITER: Integral,
Options.MAXTIME: Real,
Options.FATOL: Real,
Options.FRTOL: Real,
Options.XTOL: Real,
Options.GATOL: Real,
Options.GRTOL: Real,
Options.SUBSPACE_DIM: SubSpaceDim,
Options.STEPBACK_STRAT: StepBackStrategy,
Options.THETA_MAX: Real,
Options.DELTA_INIT: Real,
Options.MU: Real,
Options.ETA: Real,
Options.GAMMA1: Real,
Options.GAMMA2: Real,
Options.HISTORY_FILE: (str, PosixPath, WindowsPath),
}
for option_key, option_value in options.items():
try:
option = Options(option_key)
except ValueError:
raise ValueError(f'{option_key} is not a valid options field.')

expected_type = expected_types[option]
if not isinstance(option_value, expected_type):
if expected_type == Integral and int(option_value) == option_value:
continue
raise TypeError(f'Type mismatch for option {option_key}. '
f'Expected {expected_type} but got '
f'{type(option_value)}')
2 changes: 0 additions & 2 deletions fides/trust_region.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,6 @@ def trust_region(x: np.ndarray,
SubSpaceDim.FULL: TRStepFull,
SubSpaceDim.STEIHAUG: TRStepSteihaug,
}
if subspace_dim not in step_options:
raise ValueError('Invalid choice of subspace dimension.')
tr_step = step_options[subspace_dim](x, sg, hess, scaling, g_dscaling,
delta, theta, ub, lb, logger)
tr_step.calculate()
Expand Down
2 changes: 1 addition & 1 deletion fides/version.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "0.7.2"
__version__ = "0.7.3"
17 changes: 17 additions & 0 deletions tests/test_minimize.py
Original file line number Diff line number Diff line change
Expand Up @@ -382,3 +382,20 @@ def test_wrong_options():
fun, ub=ub, lb=lb, verbose=logging.INFO,
options={Options.FATOL: 'not a number'}
)

# check we can pass floats for ints
Optimizer(
fun, ub=ub, lb=lb, verbose=logging.INFO,
options={Options.MAXITER: 1e4}
)
with pytest.raises(ValueError):
Optimizer(
fun, ub=ub, lb=lb, verbose=logging.INFO,
options={Options.SUBSPACE_DIM: 'invalid_subspace'}
)

# check we can pass strings for enums
Optimizer(
fun, ub=ub, lb=lb, verbose=logging.INFO,
options={Options.SUBSPACE_DIM: '2D'}
)

0 comments on commit 0ea8078

Please sign in to comment.