"""Functions managing the dict of formulas used by Biogeme:author: Michel Bierlaire:date: Mon May 13 13:42:50 2024"""importdifflibimportloggingfromtypingimportAnyfrombiogeme.exceptionsimportBiogemeErrorfrombiogeme.expressionsimportExpressionfromfuzzywuzzyimportfuzzlogger=logging.getLogger(__name__)# Valid names for the log likelihood. Only one of them can be present in the dict.log_like_names=['log_like','loglike']# Valid names for the weights. Only one of them can be present in the dict.weight_names=['log_like','loglike']
[docs]defcheck_validity(dict_of_formulas:dict[str,Any])->None:"""Verifies if the formulas are Biogeme expressions. If not, an exception is raised"""fork,findict_of_formulas.items():ifnotisinstance(f,Expression):raiseBiogemeError(f'Expression for "{k}" is not of type 'f"biogeme.expressions.Expression. "f"It is of type {type(f)}")
[docs]defis_similar_to(word_1:str,word_2:str)->bool:"""Checks if two words are similar."""returnfuzz.ratio(word_1,word_2)>=80
[docs]definsert_valid_keyword(dict_of_formulas:dict[str,Expression],reference_keyword:str,valid_keywords:list[str],)->dict[str,Expression]:"""Insert the reference keyword if a valid keyword is used."""key_log_like_expression:str|None=Noneforkeyindict_of_formulas:ifkey==reference_keyword:continueifkeyinvalid_keywords:ifreference_keywordindict_of_formulas:warning_msg=f'Both {reference_keyword} and {key} are defined. Only {reference_keyword} is considered.'else:warning_msg=(f'As {key} is defined, it is used to define {reference_keyword}.')key_log_like_expression=keylogger.warning(warning_msg)else:matches=difflib.get_close_matches(reference_keyword,[key],n=1,cutoff=0.8)ifmatches:logger.warning(f'Formula key "{key}" is similar to "{reference_keyword}". 'f'Did you mean to use "{reference_keyword}"?',)ifkey_log_like_expressionisnotNone:dict_of_formulas[reference_keyword]=dict_of_formulas.pop(key_log_like_expression)returndict_of_formulas
[docs]defget_expression(dict_of_formulas:dict[str,Expression],valid_keywords:list[str])->Expression|None:"""Extract the formula for specific keywords :param dict_of_formulas: as the name says... :param valid_keywords: keywords that are considered valid to represent the expression :return: the requested expression """found_name=Noneforvalid_nameinvalid_keywords:the_expression=dict_of_formulas.get(valid_name)ifthe_expressionisnotNone:iffound_nameisnotNone:error_msg=(f"This expression can be defined with the keyword "f"'{found_name}' or '{valid_name}' but not both.")raiseBiogemeError(error_msg)found_name=valid_nameiffound_nameisNone:forvalid_nameinvalid_keywords:forkeyindict_of_formulas:ifis_similar_to(valid_name,key):warning_msg=f'In the formulas, one key is "{key}". Should it be "{valid_name}" instead?'logger.warning(warning_msg)returnNonereturndict_of_formulas[found_name]