Source code for wield.control.fitting.SISO.v2.arguments.base

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: © 2021 Massachusetts Institute of Technology.
# SPDX-FileCopyrightText: © 2021 Lee McCuller <mcculler@caltech.edu>
# NOTICE: authors should document their contributions in concisely in NOTICE
# with details inline in source files, comments, and docstrings.
"""
"""

from wield import declarative
import numpy as np

from ... import fitters_ZPK
from ...utilities import args
from ... import representations

try:
    from collections.abc import Mapping as MappingABC
except ImportError:
    from collections import Mapping as MappingABC


[docs] class ArgumentError(ValueError): pass
[docs] def mapcheck_bool(aid, aname, val): if isinstance(val, str): if val.lower() in ["true", "yes", "1"]: val = True elif val.lower() in ["false", "no", "0"]: val = False else: raise ArgumentError( ("Argument {} has unrecognized bool specifier {}").format(aname, val) ) return bool(val)
[docs] def float_check(aid, aname, val): try: return float(val) except ValueError: raise ArgumentError(("argument {}={} must be a float").format(aname, val))
[docs] def mapcheck_float(aid, aname, val): try: return float(val) except ValueError: raise ArgumentError(("argument {}={} must be a float").format(aname, val))
[docs] def mapcheck_positive_float(aid, aname, val): val = float(val) if not (val > 0): raise ArgumentError(("argument {}={} must be positive").format(aname, val)) return val
[docs] def mapcheck_nonnegative_float(aid, aname, val): val = float(val) if not (val >= 0): raise ArgumentError(("argument {}={} must not be negative").format(aname, val)) return val
[docs] def mapcheck_nonnegative_float_orNone(aid, aname, val): if isinstance(val, str): if val.lower() in ["none", "null"]: val = None if val is None: return val return mapcheck_nonnegative_float(aid, aname, val)
[docs] def mapcheck_positive_float_orNone(aid, aname, val): if isinstance(val, str): if val.lower() in ["none", "null"]: val = None if val is None: return val return mapcheck_positive_float(aid, aname, val)
[docs] def mapcheck_int(aid, aname, val): try: val = int(val) except ValueError: raise ArgumentError(("argument {}={} must be an integer").format(aname, val)) return val
[docs] def mapcheck_positive_int(aid, aname, val): try: val = int(val) except ValueError: raise ArgumentError(("argument {}={} must be an integer").format(aname, val)) # TODO error reporting if not (val > 0): raise ArgumentError(("argument {}={} must be positive").format(aname, val)) if not (val - float(val) == 0): raise ArgumentError(("argument {}={} must be an integer").format(aname, val)) return val
[docs] def mapcheck_nonnegative_int(aid, aname, val): try: val = int(val) except ValueError: raise ArgumentError(("argument {}={} must be an integer").format(aname, val)) # TODO error reporting if not (val >= 0): raise ArgumentError(("argument {}={} must be non-negative").format(aname, val)) if not (val - float(val) == 0): raise ArgumentError(("argument {}={} must be an integer").format(aname, val)) return val
[docs] def mapcheck_positive_int_orNone(aid, aname, val): if isinstance(val, str): if val.lower() in ["none", "null"]: val = None if val is None: return val return mapcheck_positive_int(aid, aname, val)
[docs] def mapcheck_nonnegative_int_orNone(aid, aname, val): if isinstance(val, str): if val.lower() in ["none", "null"]: val = None if val is None: return val return mapcheck_nonnegative_int(aid, aname, val)
[docs] def mapcheck_int_orNone(aid, aname, val): if isinstance(val, str): if val.lower() in ["none", "null"]: val = None if val is None: return val return mapcheck_int(aid, aname, val)
[docs] def kw_ZPKrep_build(args, kwargs): """ """ kw = dict() ZPKrep = None for arg in args: if isinstance(arg, MappingABC): kw.update(arg) elif isinstance( arg, ( representations.ZPKwData, fitters_ZPK.MultiReprFilterBase, ), ): if ZPKrep is None: ZPKrep = arg.ZPKrep else: raise ArgumentError( "Only a single ZPKrep may be specified" " in positional arguments" ) else: raise ArgumentError( "Positional Arguments are not allowed," " except for a single master ZPKrep, or a set of" " default keyword argument dictionaries" ) kw.update(kwargs) return kw, ZPKrep
[docs] def grab_kwarg_hints(aid, kw, kwdesc, kwput=None): def eval_hint(hint_name): kwmeta = kwdesc[hint_name] reqs = kwmeta.get("require_hints", None) if reqs is not None: for hname in reqs: if not aid.hint_has(hname): eval_hint(hname) if not aid.hint_has(hname): raise RuntimeError("Hint/Kwarg evaluation out of order. BUG!") found = _grab_kwargs(aid, kw, kwmeta, hint_name, kwput=kwput) if found: aid.hint_setdefault(hint_name, next(iter(found.values()))) # TODO, make better error message for case when default is not given try: default = kwmeta["default"] except KeyError: pass else: if callable(default): default = default(aid, hint_name) aid.hint_setdefault(hint_name, default) for hint_name in kwdesc.keys(): eval_hint(hint_name)
[docs] def grab_kwargs(aid, kw, kwdesc, argname, kwput=None): kwmeta = kwdesc[argname] found = _grab_kwargs(aid, kw, kwmeta, argname, kwput=kwput) if found: return next(iter(found.values())) # TODO, make better error message for case when default is not given default = kwmeta["default"] if callable(default): default = default(aid, argname) return default
def _grab_kwargs(aid, kw, kwmeta, argname, kwput=None): reqs = kwmeta.get("require_hints", None) if reqs is not None: for hname in reqs: if not aid.hint_has(hname): raise RuntimeError("Hint/Kwarg evaluation out of order. BUG!") drop_val = kwmeta.get("drop_val", args.UNSPEC) drop_vals = list(kwmeta.get("drop_vals", [])) if drop_val is not args.UNSPEC: drop_vals.extend(drop_val) pop = kwmeta.get("pop", True) mapcheck = kwmeta.get("mapcheck", None) found = {} # use a list to modify it from the function discrepancy = [False] def check_find(aname): if pop: val = kw.pop(aname, args.UNSPEC) else: val = kw.get(aname, args.UNSPEC) if val is args.UNSPEC: return False if kwput is not None: kwput[aname] = val if val in drop_vals: return False if mapcheck is not None: val = mapcheck(aid, aname, val) if found: if np.any(next(iter(found.values())) != val): discrepancy[0] = True found[aname] = val return True prefname = kwmeta.get("name", argname) check_find(prefname) for aname in kwmeta.get("aliases", []): check_find(aname) for aname in kwmeta.get("aliases_bad", []): if check_find(aname): aid.log_warn( 2, "Argument '{}' is a deprecated alias." " Use '{}' instead".format(aname, prefname), ) if discrepancy[0]: kv_strs = [] for k, v in found.items(): kv_strs.append("{}: {}".format(k, v)) raise ArgumentError( "Inconsistent values given for aliased arguments\n" + "\n".join(kv_strs) ) return found
[docs] def check_remaining_arguments(kw, kwdict): names = set() alias_map = {} bad_map = {} for hname, hdict in kwdict.items(): name = hdict.get("name", hname) names.add(name) for alias in hdict.get("aliases", []): alias_map[alias] = name for alias in hdict.get("aliases_bad", []): bad_map[alias] = name allnames = set(names) allnames.update(alias_map.keys()) allnames.update(bad_map.keys()) import difflib k_lines = dict() for k in kw.keys(): l = [] k_lines[k] = l matches = difflib.get_close_matches(k, allnames, n=5) print("Matches: ", k, matches) mainset = set() for match in matches: if match in names: mainset.add(name) l.append("'{}'".format(match)) elif match in alias_map: mainmatch = alias_map[match] l.append("'{}', alias for '{}'".format(match, mainmatch)) else: mainmatch = bad_map[match] l.append("'{}', deprecated alias for '{}'".format(match, mainmatch)) stack_lines = [] for k, lines in sorted(k_lines.items()): if len(lines) > 0: stack_lines.append("'{}':\n\t".format(k) + "\n\t".join(lines)) else: stack_lines.append("'{}': <no similar arguments recognized>".format(k)) raise ArgumentError( ( "Unrecognized keyword arguments. Listed with potential matches below," "\nor call with argument 'help'=True for more details\n" "{}" ).format("\n".join(stack_lines)) ) return
[docs] def cplx_iIjJ(val): val = val.replace("i", "j") val = val.replace("I", "j") val = val.replace("J", "j") return complex(val)
[docs] def cplx_iIjJ_list_inner(val): vals = val.split() vals2 = [] for v in vals: vals2.extend(v.split(",")) vals3 = [] for v in vals2: vals3.extend(v.split(";")) return [cplx_iIjJ(v) for v in vals3 if v != ""]
[docs] def cplx_iIjJ_list(val): vals = val.split(":") val = vals[0] vals = vals[1:] val = cplx_iIjJ_list_inner(val) if vals: val_c = vals[0] vals = vals[1:] assert(not vals) val_c = cplx_iIjJ_list_inner(val_c) val.extend(val_c) val.extend(np.asarray(val_c).conjugate()) return val
[docs] def transfer_kw(kwA, kwB, kwdict, pop=False): for hname, hdict in kwdict.items(): if pop: name = hdict.pop("name", hname) else: name = hdict.get("name", hname) normalize = hdict.get("normalize", None) val = kwA.get(name, declarative.NOARG) if val is not declarative.NOARG: if normalize is not None: val = normalize(val) kwB[name] = val for aname in hdict.get("aliases", []): if pop: val = kwA.pop(aname, declarative.NOARG) else: val = kwA.get(aname, declarative.NOARG) if val is not declarative.NOARG: if normalize is not None: val = normalize(val) kwB[aname] = val for aname in hdict.get("aliases_bad", []): if pop: val = kwA.pop(aname, declarative.NOARG) else: val = kwA.get(aname, declarative.NOARG) if val is not declarative.NOARG: if normalize is not None: val = normalize(val) kwB[aname] = val