|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import copy |
|
import re |
|
|
|
|
|
class TrialShortNamer: |
|
PREFIX = "hp" |
|
DEFAULTS = {} |
|
NAMING_INFO = None |
|
|
|
@classmethod |
|
def set_defaults(cls, prefix, defaults): |
|
cls.PREFIX = prefix |
|
cls.DEFAULTS = defaults |
|
cls.build_naming_info() |
|
|
|
@staticmethod |
|
def shortname_for_word(info, word): |
|
if len(word) == 0: |
|
return "" |
|
short_word = None |
|
if any(char.isdigit() for char in word): |
|
raise Exception(f"Parameters should not contain numbers: '{word}' contains a number") |
|
if word in info["short_word"]: |
|
return info["short_word"][word] |
|
for prefix_len in range(1, len(word) + 1): |
|
prefix = word[:prefix_len] |
|
if prefix in info["reverse_short_word"]: |
|
continue |
|
else: |
|
short_word = prefix |
|
break |
|
|
|
if short_word is None: |
|
|
|
def int_to_alphabetic(integer): |
|
s = "" |
|
while integer != 0: |
|
s = chr(ord("A") + integer % 10) + s |
|
integer //= 10 |
|
return s |
|
|
|
i = 0 |
|
while True: |
|
sword = word + "#" + int_to_alphabetic(i) |
|
if sword in info["reverse_short_word"]: |
|
continue |
|
else: |
|
short_word = sword |
|
break |
|
|
|
info["short_word"][word] = short_word |
|
info["reverse_short_word"][short_word] = word |
|
return short_word |
|
|
|
@staticmethod |
|
def shortname_for_key(info, param_name): |
|
words = param_name.split("_") |
|
|
|
shortname_parts = [TrialShortNamer.shortname_for_word(info, word) for word in words] |
|
|
|
|
|
|
|
separators = ["", "_"] |
|
|
|
for separator in separators: |
|
shortname = separator.join(shortname_parts) |
|
if shortname not in info["reverse_short_param"]: |
|
info["short_param"][param_name] = shortname |
|
info["reverse_short_param"][shortname] = param_name |
|
return shortname |
|
|
|
return param_name |
|
|
|
@staticmethod |
|
def add_new_param_name(info, param_name): |
|
short_name = TrialShortNamer.shortname_for_key(info, param_name) |
|
info["short_param"][param_name] = short_name |
|
info["reverse_short_param"][short_name] = param_name |
|
|
|
@classmethod |
|
def build_naming_info(cls): |
|
if cls.NAMING_INFO is not None: |
|
return |
|
|
|
info = { |
|
"short_word": {}, |
|
"reverse_short_word": {}, |
|
"short_param": {}, |
|
"reverse_short_param": {}, |
|
} |
|
|
|
field_keys = list(cls.DEFAULTS.keys()) |
|
|
|
for k in field_keys: |
|
cls.add_new_param_name(info, k) |
|
|
|
cls.NAMING_INFO = info |
|
|
|
@classmethod |
|
def shortname(cls, params): |
|
cls.build_naming_info() |
|
assert cls.PREFIX is not None |
|
name = [copy.copy(cls.PREFIX)] |
|
|
|
for k, v in params.items(): |
|
if k not in cls.DEFAULTS: |
|
raise Exception(f"You should provide a default value for the param name {k} with value {v}") |
|
if v == cls.DEFAULTS[k]: |
|
|
|
continue |
|
|
|
key = cls.NAMING_INFO["short_param"][k] |
|
|
|
if isinstance(v, bool): |
|
v = 1 if v else 0 |
|
|
|
sep = "" if isinstance(v, (int, float)) else "-" |
|
e = f"{key}{sep}{v}" |
|
name.append(e) |
|
|
|
return "_".join(name) |
|
|
|
@classmethod |
|
def parse_repr(cls, repr): |
|
repr = repr[len(cls.PREFIX) + 1 :] |
|
if repr == "": |
|
values = [] |
|
else: |
|
values = repr.split("_") |
|
|
|
parameters = {} |
|
|
|
for value in values: |
|
if "-" in value: |
|
p_k, p_v = value.split("-") |
|
else: |
|
p_k = re.sub("[0-9.]", "", value) |
|
p_v = float(re.sub("[^0-9.]", "", value)) |
|
|
|
key = cls.NAMING_INFO["reverse_short_param"][p_k] |
|
|
|
parameters[key] = p_v |
|
|
|
for k in cls.DEFAULTS: |
|
if k not in parameters: |
|
parameters[k] = cls.DEFAULTS[k] |
|
|
|
return parameters |
|
|