def recalculate(dataset): """Recalculate parameterized relationships within a dataset. Modifies values in place. Creates a ``TolerantParameterSet``, populates it with named parameters with a dataset, and then gets the evaluation order the graph of parameter relationships. After reevaluating all named parameters, creates an ``Interpreter`` with named parameters and all of numpy in its namespace. This interpreter is used to evaluate all other formulas in the dataset. Formulas that divide by zero are evaluated to zero. Returns the modified dataset.""" interpreter = Interpreter() parameter_set = TolerantParameterSet(extract_named_parameters(dataset)) for key, value in parameter_set.evaluate().items(): interpreter.symtable[key] = value for exc in iterate_all_parameters(dataset): if 'formula' in exc: try: exc['amount'] = interpreter(exc['formula']) except ZeroDivisionError: exc['amount'] = 0 elif 'variable' in exc: exc['amount'] = interpreter.symtable[exc['variable']] else: raise ValueError # https://github.com/OcelotProject/Ocelot/issues/111 for obj in iterate_all_uncertainties(dataset): if obj.get('uncertainty'): get_uncertainty_class(obj).repair(obj) return dataset
def recalculate(dataset): """Recalculate parameterized relationships within a dataset. Modifies values in place. Creates a ``TolerantParameterSet``, populates it with named parameters with a dataset, and then gets the evaluation order the graph of parameter relationships. After reevaluating all named parameters, creates an ``Interpreter`` with named parameters and all of numpy in its namespace. This interpreter is used to evaluate all other formulas in the dataset. Formulas that divide by zero are evaluated to zero. Returns the modified dataset.""" interpreter = Interpreter() parameter_set = TolerantParameterSet(extract_named_parameters(dataset)) for key, value in list(parameter_set.evaluate().items()): interpreter.symtable[key] = value for exc in iterate_all_parameters(dataset): if 'formula' in exc: try: exc['amount'] = interpreter(exc['formula']) except ZeroDivisionError: exc['amount'] = 0 elif 'variable' in exc: exc['amount'] = interpreter.symtable[exc['variable']] else: raise ValueError # https://github.com/OcelotProject/Ocelot/issues/111 for obj in iterate_all_uncertainties(dataset): if obj.get('uncertainty'): get_uncertainty_class(obj).repair(obj) return dataset
def match_rule(rule, expression, pre_context, post_context): symbols = {} aeval = Interpreter() if not obtain_symbols(symbols,rule[1],expression): return False if not obtain_symbols(symbols,rule[0],pre_context): return False if not obtain_symbols(symbols,rule[2],post_context): return False aeval.symtable = symbols if rule[3] != None: conditions = rule[3].replace(" ","").split(",") for cond in conditions: if not aeval(cond): return False sfinal = "" res_split = split_symbols(rule[4]) for r in res_split: if r.find("(")>=0: sfinal += r[:r.find("(")+1] temp = aeval(r[r.find("(")+1:-1]) if type(temp)==tuple: sfinal += str(temp[0]) for t in temp[1:]: sfinal += "," sfinal += str(t) else: sfinal += str(temp) sfinal += ")" else: sfinal += r return sfinal
def _process(self,): with open(self.prism_result_file, "r") as fptr: lines = fptr.readlines() max_param_idx = 0 aeval = Interpreter() for line in lines: if len(line) > 7: if line[0:6] == 'Result': param_idx, bscc_str = self.process_result_line(line) if param_idx > max_param_idx: max_param_idx = param_idx try: bscc_expr = aeval.parse(bscc_str) except Exception as ex: raise(ex) # sys.exit(ex) self.bscc_str_pfuncs.append(bscc_str) self.bscc_ast_pfuncs.append(bscc_expr) elif line[0:30] == 'Parametric model checking: P=?': pattern = re.compile(r'\[ F (.*?)\]') sbscc = re.search(pattern, line).group(1) sbscc = sbscc.rstrip().lstrip() bscc_label, _ = self.process_bscc_label(sbscc) self.bscc_labels.append(bscc_label) self.params_count = max_param_idx + 1
def match_rule(rule, expression, pre_context, post_context): symbols = {} aeval = Interpreter() if not obtain_symbols(symbols, rule[1], expression): return False if not obtain_symbols(symbols, rule[0], pre_context): return False if not obtain_symbols(symbols, rule[2], post_context): return False aeval.symtable = symbols if rule[3] != None: conditions = rule[3].replace(" ", "").split(",") for cond in conditions: if not aeval(cond): return False sfinal = "" res_split = split_symbols(rule[4]) for r in res_split: if r.find("(") >= 0: sfinal += r[:r.find("(") + 1] temp = aeval(r[r.find("(") + 1:-1]) if type(temp) == tuple: sfinal += str(temp[0]) for t in temp[1:]: sfinal += "," sfinal += str(t) else: sfinal += str(temp) sfinal += ")" else: sfinal += r return sfinal
def evaluate_dice_list(self): """ Evaluates each dice in the dice list, constructs and evaluates final string """ if self.verbosity: print(f"--> evaluate_dice_list") self.eval_expression = "" for i in range(len(self.dice_list)): if isinstance(self.dice_list[i], Die): if self.verbosity: print(f"dice_list[{i}] is Die") roll_result = self.dice_list[i].evaluate() if self.verbosity: print(f"roll_result: {roll_result}") self.eval_expression += str(roll_result) else: if self.verbosity: print(f"dice_list[{i}] is not Die") self.eval_expression += self.dice_list[i] # Evaluate the constructed string aeval = Interpreter() self.result = aeval.eval(self.eval_expression) if self.verbosity: print(f"result: {self.result}")
def determine_category(self, relation_list, app_data_dict, attr_keys_search_mongo, server): ''' determine category by relation :param principal: the value user input :return: category_id ''' aeval = Interpreter() category_id = None for rl in relation_list: agg_cmp = [] relation_dict = json.loads( rl['relation']) # convert the 'relation' json to dict if set(list(relation_dict.keys())) != set(attr_keys_search_mongo): continue for kk, vv in relation_dict.items(): # evaluation the relation using the value of application if kk not in app_data_dict: agg_cmp.append(False) else: aeval.symtable['VALUE'] = app_data_dict.get(kk) agg_cmp.append(aeval(vv)) if np.array(agg_cmp).all(): category_id = rl['category_id'] break if category_id is not None: return category_id else: # cannot match the relation, just return the default one logging.warning('cannot match category, load default category_id') res_out = self.category_ID_access.read_default_category_id(server) return res_out['category_id']
def __init__(self, asteval=None, usersyms=None): """ Arguments --------- asteval : :class:`asteval.Interpreter`, optional Instance of the `asteval.Interpreter` to use for constraint expressions. If None (default), a new interpreter will be created. **Warning: deprecated**, use `usersyms` if possible! usersyms : dict, optional Dictionary of symbols to add to the :class:`asteval.Interpreter` (default is None). """ super().__init__(self) self._asteval = asteval if asteval is None: self._asteval = Interpreter() else: msg = ("The use of the 'asteval' argument for the Parameters class" " was deprecated in lmfit v0.9.12 and will be removed in a " "later release. Please use the 'usersyms' argument instead!") warnings.warn(FutureWarning(msg)) self._asteval = asteval _syms = {} _syms.update(SCIPY_FUNCTIONS) if usersyms is not None: _syms.update(usersyms) for key, val in _syms.items(): self._asteval.symtable[key] = val
def __init__(self, asteval=None, usersyms=None, *args, **kwds): """ Arguments --------- asteval : :class:`asteval.Interpreter`, optional Instance of the asteval Interpreter to use for constraint expressions. If None, a new interpreter will be created. Warning: *deprecated, use usersyms if possible* usersyms : dictionary of symbols to add to the :class:`asteval.Interpreter`. *args : optional Arguments. **kwds : optional Keyword arguments. """ super(Parameters, self).__init__(self) self._asteval = asteval if self._asteval is None: self._asteval = Interpreter() _syms = {} _syms.update(SCIPY_FUNCTIONS) if usersyms is not None: _syms.update(usersyms) for key, val in _syms.items(): self._asteval.symtable[key] = val self.update(*args, **kwds)
def eval_bscc_pfuncs(self, ): aeval = Interpreter() if config.models['use_old_model']: aeval.symtable['p'] = self.params else: aeval.symtable['r'] = self.params return [aeval.run(f) for f in self.bscc_ast_pfuncs]
async def calc(self, ctx, *, expression: str): """ Evaluates a math expression. """ terp = Interpreter() result = terp.eval(expression) if result != '' and result is not None: await ctx.send(result) else: await ctx.send('Empty result.')
def test_eval(): aeval = Interpreter() expr_str = "r[0]**4 * r[1]**2 +" * 10000 + '2*r[2]' with DeepRecursionCtx(): expr = aeval.parse(expr_str) aeval.symtable['r'] = [1, 2, 3] res = aeval.eval(expr) assert not math.isnan(res)
def expr(expression, context=None): if context is None: context = dict() interpreter = Interpreter() for variable, value in context.items(): interpreter.symtable[variable] = value return interpreter(expression)
def do_conversion(in_val, expr): aeval = Interpreter() try: aeval.symtable['x'] = in_val aeval(expr) value = aeval.symtable['Value'] except (KeyError, SyntaxError) as e: print(str(e)) value = None return value
def _objective_function(self, x): """ Abstract Objective Function Call :param x: Input Variable :return: Function Value of Objective """ aeval = Interpreter() exprc = aeval.parse(self.objective) aeval.symtable['x'] = x return aeval.run(exprc)
def run(self, script,data): for k,v in self.stateData.items(): data[k] = v data['stateData'] = self.stateData interpreter = Interpreter(data) interpreter.eval(script,0,True) for k,v in interpreter.symtable.items(): if type(v) in [str,int,float,bool]: #print 'saving {} in stateData'.format(k) self.stateData[k] = v interpreter = None
def tpl_write( pardict, f, outflnm ): ''' Write model input file using PEST template file :param pardict: Dictionary of parameter values :type pardict: dict :param f: File handle or file name of PEST template file :type f: str or file handle :param outflnm: Name of model input file to be written :type outflnm: str ''' # Check if f is a string or file and read in lines if isinstance( f, file ): t = f.read() fnm = f.name f.close() elif isinstance( f, str ): fnm = f with open( f, 'r') as fh: t = fh.read() fh.close() # Make sure file is PEST TPL file lh = t.split('\n')[0] k = lh.split() if k[0] != 'ptf': print fnm+" does not appear to be a PEST template file" return else: tok = k[1] # Collect parameter identifier character t = re.sub( lh+'\n', '', t) # Complile regex pattern p = re.compile(tok+'[^'+tok+']*'+tok) # Find all parameter identifiers in file ms = p.findall(t) pd = {} # Pattern dictionary # Create evaluation interpreter aeval = Interpreter() for k,v in pardict.items(): aeval.symtable[k] = v # Evaluate all unique expressions for m in ms: pstr = m.split(tok)[1].strip() if pstr not in pd: pd[m] = aeval(pstr) # Perform substitutions for k,v in pd.items(): t = re.sub( re.escape(k), str(v), t) # Write output file fout = open( outflnm, 'w' ) fout.write(t) fout.close()
def get_interpreter(self, evaluate_first=True): """Get an instance of ``asteval.Interpreter`` that is prepopulated with global and local symbol names and values.""" if evaluate_first: self.evaluate_and_set_amount_field() interpreter = Interpreter() for key, value in self.global_params.items(): interpreter.symtable[key] = value for key, value in self.params.items(): interpreter.symtable[key] = value['amount'] return interpreter
def test_readonly_symbols(self): def foo(): return 31 usersyms = { "a": 10, "b": 11, "c": 12, "d": 13, "foo": foo, "bar": foo, "x": 5, "y": 7 } aeval = Interpreter(usersyms=usersyms, readonly_symbols={"a", "b", "c", "d", "foo", "bar"}) aeval("a = 20") aeval("def b(): return 100") aeval("c += 1") aeval("del d") aeval("def foo(): return 55") aeval("bar = None") aeval("x = 21") aeval("y += a") assert(aeval("a") == 10) assert(aeval("b") == 11) assert(aeval("c") == 12) assert(aeval("d") == 13) assert(aeval("foo()") == 31) assert(aeval("bar()") == 31) assert(aeval("x") == 21) assert(aeval("y") == 17) assert(aeval("abs(8)") == 8) assert(aeval("abs(-8)") == 8) aeval("def abs(x): return x*2") assert(aeval("abs(8)") == 16) assert(aeval("abs(-8)") == -16) aeval2 = Interpreter(builtins_readonly=True) assert(aeval2("abs(8)") == 8) assert(aeval2("abs(-8)") == 8) aeval2("def abs(x): return x*2") assert(aeval2("abs(8)") == 8) assert(aeval2("abs(-8)") == 8)
def calculate_callback(self): """ Callback for when they hit calculate :return: """ # Create the interpreter from asteval import Interpreter aeval = Interpreter() # Grab the calculation from the text box which the user wants to do calculation = str(self.calculation_text.text()) lhs = calculation.split('=')[0].strip() # Use the package asteval to do the calculation, we are going to # assume here that the lhs of the equals sign is going to be the output named variable try: if lhs in self.data_components: raise KeyError( '{} is already in the data components, use a different variable on the left hand side.' .format(lhs)) # Pull in the required data and run the calculation for dc in self.data_components: if dc in calculation: aeval.symtable[dc] = self.data[dc] aeval(calculation) # Pull out the output data and add to the proper drop-downs out_data = aeval.symtable[lhs] self.data.add_component(out_data, lhs) # Add the new data to the list of available data for arithemitic operations self.data_components.append(lhs) self.close() except KeyError as e: self.calculation_text.setStyleSheet( "background-color: rgba(255, 0, 0, 128);") # Display the error in the Qt popup if aeval.error_msg: self.error_label_text.setText('{}'.format(aeval.error_msg)) else: self.error_label_text.setText('{}'.format(e)) self.error_label_text.setStyleSheet("color: rgba(255, 0, 0, 128)")
def _parse_str2ast(self, ): aeval = Interpreter() # Parse init vector to AST expressions state_count = len(self.state_list) self.init_ast_pfuncs = [None] * state_count for i, s in enumerate(self.init_str_pfuncs): self.init_ast_pfuncs[i] = aeval.parse(s) # Parse transition matrix to AST expressions self.trans_ast_pfuncs = [[None] * state_count for i in range(0, state_count)] for i in range(0, state_count): for j in range(0, state_count): self.trans_ast_pfuncs[i][j] = aeval.parse( self.trans_str_pfuncs[i][j])
def test_bscc_eval(parser): parser.process() bscc_ast_pfuncs = parser.bscc_ast_pfuncs bscc_str_pfuncs = parser.bscc_str_pfuncs assert len(bscc_ast_pfuncs) != 0 assert len(bscc_str_pfuncs) != 0 for f in bscc_str_pfuncs: assert f is not None assert len(f) != 0 r = [0.11, 0.22, 0.33] aeval = Interpreter() aeval.symtable['r'] = r eval_bscc = [aeval.run(f) for f in bscc_ast_pfuncs] assert not np.isnan(np.sum(eval_bscc))
def get_group_tag(user_id, group_tags, server_name, data, rule_check_data): aeval = Interpreter() default_tag = group_tags['default']['tag'] # if server_name == 'omega_withdraw': # if not user_id: # group_tag = default_tag # return group_tag, False # group_tag_info = rule_check_data.get_group_tag(user_id) # group_tag = group_tag_info[-1]['group_tag'] if group_tag_info else None # if not group_tag: # group_tag = default_tag # return group_tag, not group_tag == default_tag if 'control_group' in group_tags: group_tag = group_tags['control_group']['tag'] prob = group_tags['control_group']['prob'] max_num = group_tags['control_group']['max_num_per_day'] not_cgs = group_tags['control_group']['not_cg_condition'] if max_num > 0: start_time = datetime.now().date() end_time = start_time + timedelta(days=1) nonce_num = rule_check_data.get_cg_count_by_date(start_time, end_time, group_tag) cg_num = nonce_num[0]['cg_num'] if nonce_num else 0 logging.info('nonce num:{}, max num:{}'.format(cg_num, max_num)) if cg_num >= max_num: return default_tag, False res = False for not_c in not_cgs: result = True for kk, vv in not_c.items(): value = data.get(kk) if value: aeval.symtable['VALUE'] = value is_match = aeval(vv) result = result and is_match else: result = False continue res = res or result rand_prob = np.random.rand(1)[0] logging.info('rand prob: {}, control group prob:{}'.format(rand_prob, prob)) if (not res) and rand_prob <= prob: return group_tag, True return default_tag, False
def operator_expr(self, expr): """Evaluate an expression composed of single-mode operators. See ``Mode.OPERATORS`` for the full list of supported operators. Args: expr (str): String representation of the operator expression to evaluate. Returns: ``qutip.Qobj``: Evaluated operator expression. """ symbols = {name: getattr(self, name) for name in self.OPERATORS} symtable = make_symbol_table(use_numpy=True, **symbols) aeval = Interpreter(symtable=symtable) return aeval.eval(expr)
def post(self, text): import pprint pp = pprint.PrettyPrinter(indent=4, depth=9) odds = self.config.get("behaviour", "reply_to_last_tweet_odds", fallback="0") import asteval from asteval import Interpreter aeval = Interpreter() odds = aeval(odds) pp.pprint(odds) import random if random.random() < odds: print("replying to last tweet") # randomly reply to last tweet tweets = self.twitter.statuses.user_timeline( screen_name=self.username, count=1) last_tweet_id = tweets[0]["id"] self.twitter.statuses.update(status=text, in_reply_to_status_id=last_tweet_id) else: print("not replying to last tweet") self.twitter.statuses.update(status=text)
def setUp(self): self.interp = Interpreter() self.symtable = self.interp.symtable self.set_stdout() self.set_stderr() if not HAS_NUMPY: self.interp("arange = range")
def test_stringio(self): """ test using stringio for output/errors """ out = StringIO() err = StringIO() intrep = Interpreter(writer=out, err_writer=err) intrep("print('out')") self.assertEqual(out.getvalue(), 'out\n')
def evaluate(eval_code, input_variables={}, output_variables=[]): """Evaluates a given expression, with the timeout given as decorator. Args: eval_code (str): The code to be evaluated. input_variables (dict): dictionary of input variables and their values. output_variables (array): array of names of output variables. Returns: dict: the output variables or empty. """ # FIXME: use_numpy the process blocks infinitely at the return statement import time sym = make_symbol_table(time=time, use_numpy=False, range=range, **input_variables) aeval = Interpreter( symtable = sym, use_numpy = False, no_if = False, no_for = False, no_while = False, no_try = True, no_functiondef = True, no_ifexp = False, no_listcomp = True, no_augassign = False, # e.g., a += 1 no_assert = True, no_delete = True, no_raise = True, no_print = False) aeval(eval_code) symtable = {x: sym[x] for x in sym if x in output_variables} return symtable
def _eval(s, error=None, usersyms=None, **kwargs): error = error or 'cannot be eval!' from asteval import Interpreter usersyms = sh.combine_dicts(_usersyms, usersyms or {}) return Or(And(str, Use(Interpreter(usersyms=usersyms).eval), s), s, error=error)
def model(self, value): if callable(value): model = value() else: model = value self._model = model self.current_result = None self._current_params = model.make_params() # Use these to evaluate any Parameters that use expressions. self.asteval = Interpreter() self.namefinder = NameFinder() self._finalize_model(value) self.guess()
def __call__(self, parents, accumulator) -> str: """ Execute an action and ship its result """ parent_symbols = { k: ParentSymbol(accumulator[v.id_]) for k, v in self.format_node_names(parents).items() } # children_symbols = {k: ChildSymbol(v.id_) for k, v in self.format_node_names(children).items()} syms = make_symbol_table(use_numpy=False, **parent_symbols) aeval = Interpreter(usersyms=syms, no_while=True, no_try=True, no_functiondef=True, no_ifexp=False, no_augassign=True, no_assert=True, no_delete=True, no_raise=True, no_print=True, use_numpy=False, builtins_readonly=True) aeval(self.transform) output = aeval.symtable.get("result", None) if len(aeval.error) > 0: raise TransformException return output
def test_custom_symtable(self): "test making and using a custom symbol table" if HAS_NUMPY: def cosd(x): "cos with angle in degrees" return np.cos(np.radians(x)) def sind(x): "sin with angle in degrees" return np.sin(np.radians(x)) def tand(x): "tan with angle in degrees" return np.tan(np.radians(x)) sym_table = make_symbol_table(cosd=cosd, sind=sind, tand=tand) aeval = Interpreter(symtable=sym_table) aeval("x1 = sind(30)") aeval("x2 = cosd(30)") aeval("x3 = tand(45)") x1 = aeval.symtable['x1'] x2 = aeval.symtable['x2'] x3 = aeval.symtable['x3'] assert_allclose(x1, 0.50, rtol=0.001) assert_allclose(x2, 0.866025, rtol=0.001) assert_allclose(x3, 1.00, rtol=0.001)
class Python(Plugin): def on_attach(self, config): self.env = Interpreter() def on_message(self, message): # also text starts with '>>>' will be interpreted as python if message['text'].startswith('>>>'): return self.py(message['text'][12:].strip()) @command def py(self, *args): """evaluates python code ex) !py 1+1 """ # XXX: parser unwraps double quote of outside of argument line = u' '.join(args) print self.env.eval(line) return unicode(self.env.eval(line))
def on_attach(self, config): self.env = Interpreter()
class BaseFitter(object): __doc__ = _COMMON_DOC + """ Parameters ---------- data : array-like model : lmfit.Model optional initial Model to use, maybe be set or changed later """ + _COMMON_EXAMPLES_DOC def __init__(self, data, model=None, **kwargs): self._data = data self.kwargs = kwargs # GUI-based subclasses need a default value for the menu of models, # and so an arbitrary default is applied here, for uniformity # among the subclasses. if model is None: model = ExponentialModel self.model = model def _on_model_value_change(self, name, value): self.model = value def _on_fit_button_click(self, b): self.fit() def _on_guess_button_click(self, b): self.guess() @property def data(self): return self._data @data.setter def data(self, value): self._data = value @property def model(self): return self._model @model.setter def model(self, value): if callable(value): model = value() else: model = value self._model = model self.current_result = None self._current_params = model.make_params() # Use these to evaluate any Parameters that use expressions. self.asteval = Interpreter() self.namefinder = NameFinder() self._finalize_model(value) self.guess() def _finalize_model(self, value): # subclasses optionally override to update display here pass @property def current_params(self): """Each time fit() is called, these will be updated to reflect the latest best params. They will be used as the initial guess for the next fit, unless overridden by arguments to fit().""" return self._current_params @current_params.setter def current_params(self, new_params): # Copy contents, but retain original params objects. for name, par in new_params.items(): self._current_params[name].value = par.value self._current_params[name].expr = par.expr self._current_params[name].vary = par.vary self._current_params[name].min = par.min self._current_params[name].max = par.max # Compute values for expression-based Parameters. self.__assign_deps(self._current_params) for _, par in self._current_params.items(): if par.value is None: self.__update_paramval(self._current_params, par.name) self._finalize_params() def _finalize_params(self): # subclasses can override this to pass params to display pass def guess(self): count_indep_vars = len(self.model.independent_vars) guessing_successful = True try: if count_indep_vars == 0: guess = self.model.guess(self._data) elif count_indep_vars == 1: key = self.model.independent_vars[0] val = self.kwargs[key] d = {key: val} guess = self.model.guess(self._data, **d) self.current_params = guess except NotImplementedError: guessing_successful = False return guessing_successful def __assign_deps(self, params): # N.B. This does not use self.current_params but rather # new Parameters that are being built by self.guess(). for name, par in params.items(): if par.expr is not None: par.ast = self.asteval.parse(par.expr) check_ast_errors(self.asteval.error) par.deps = [] self.namefinder.names = [] self.namefinder.generic_visit(par.ast) for symname in self.namefinder.names: if (symname in self.current_params and symname not in par.deps): par.deps.append(symname) self.asteval.symtable[name] = par.value if par.name is None: par.name = name def __update_paramval(self, params, name): # N.B. This does not use self.current_params but rather # new Parameters that are being built by self.guess(). par = params[name] if getattr(par, 'expr', None) is not None: if getattr(par, 'ast', None) is None: par.ast = self.asteval.parse(par.expr) if par.deps is not None: for dep in par.deps: self.__update_paramval(params, dep) par.value = self.asteval.run(par.ast) out = check_ast_errors(self.asteval.error) if out is not None: self.asteval.raise_exception(None) self.asteval.symtable[name] = par.value def fit(self, *args, **kwargs): "Use current_params unless overridden by arguments passed here." guess = dict(self.current_params) guess.update(self.kwargs) # from __init__, e.g. x=x guess.update(kwargs) self.current_result = self.model.fit(self._data, *args, **guess) self.current_params = self.current_result.params
import numpy as np import pandas as pd from pandas import Series, DataFrame import os from asteval import Interpreter aeval = Interpreter() aeval.symtable['I'] = 1j from ast import literal_eval from utils import _scalar_mul, _abs2, _minus def read_sc_2(p_cm_vecs, path, verbose=True, j=1): """ Read subduction coefficients from SO(3) to irreducible representations of appropriate little group of rotational symmetry for lattice in a reference frame moving with momentum p_cm \in list_p_cm Parameters ---------- p_cm_vecs : list Center of mass momentum of the lattice. Used to specify the appropriate little group of rotational symmetry. Contains integer 3-vectors path : string Path to files with subduction coefficients Returns ------- df : pd.DataFrame
class Parameters(OrderedDict): """An ordered dictionary of all the Parameter objects required to specify a fit model. All minimization and Model fitting routines in lmfit will use exactly one Parameters object, typically given as the first argument to the objective function. All keys of a Parameters() instance must be strings and valid Python symbol names, so that the name must match ``[a-z_][a-z0-9_]*`` and cannot be a Python reserved word. All values of a Parameters() instance must be Parameter objects. A Parameters() instance includes an asteval interpreter used for evaluation of constrained Parameters. Parameters() support copying and pickling, and have methods to convert to and from serializations using json strings. """ def __init__(self, asteval=None, usersyms=None, *args, **kwds): """ Arguments --------- asteval : :class:`asteval.Interpreter`, optional Instance of the asteval Interpreter to use for constraint expressions. If None, a new interpreter will be created. Warning: *deprecated, use usersyms if possible* usersyms : dictionary of symbols to add to the :class:`asteval.Interpreter`. *args : optional Arguments. **kwds : optional Keyword arguments. """ super(Parameters, self).__init__(self) self._asteval = asteval if self._asteval is None: self._asteval = Interpreter() _syms = {} _syms.update(SCIPY_FUNCTIONS) if usersyms is not None: _syms.update(usersyms) for key, val in _syms.items(): self._asteval.symtable[key] = val self.update(*args, **kwds) def copy(self): """Parameters.copy() should always be a deepcopy.""" return self.__deepcopy__(None) def __copy__(self): """Parameters.copy() should always be a deepcopy.""" return self.__deepcopy__(None) def __deepcopy__(self, memo): """Implementation of Parameters.deepcopy(). The method needs to make sure that asteval is available and that all individual Parameter objects are copied. """ _pars = Parameters(asteval=None) # find the symbols that were added by users, not during construction unique_symbols = {key: self._asteval.symtable[key] for key in self._asteval.user_defined_symbols()} _pars._asteval.symtable.update(unique_symbols) # we're just about to add a lot of Parameter objects to the newly parameter_list = [] for key, par in self.items(): if isinstance(par, Parameter): param = Parameter(name=par.name, value=par.value, min=par.min, max=par.max) param.vary = par.vary param.brute_step = par.brute_step param.stderr = par.stderr param.correl = par.correl param.init_value = par.init_value param.expr = par.expr param.user_data = par.user_data parameter_list.append(param) _pars.add_many(*parameter_list) return _pars def __setitem__(self, key, par): """TODO: add magic method docstring.""" if key not in self: if not valid_symbol_name(key): raise KeyError("'%s' is not a valid Parameters name" % key) if par is not None and not isinstance(par, Parameter): raise ValueError("'%s' is not a Parameter" % par) OrderedDict.__setitem__(self, key, par) par.name = key par._expr_eval = self._asteval self._asteval.symtable[key] = par.value def __add__(self, other): """Add Parameters objects.""" if not isinstance(other, Parameters): raise ValueError("'%s' is not a Parameters object" % other) out = deepcopy(self) params = other.values() out.add_many(*params) return out def __iadd__(self, other): """Add/assign Parameters objects.""" if not isinstance(other, Parameters): raise ValueError("'%s' is not a Parameters object" % other) params = other.values() self.add_many(*params) return self def __array__(self): """Convert Parameters to array.""" return array([float(k) for k in self.values()]) def __reduce__(self): """Reduce Parameters instance such that it can be pickled.""" # make a list of all the parameters params = [self[k] for k in self] # find the symbols from _asteval.symtable, that need to be remembered. sym_unique = self._asteval.user_defined_symbols() unique_symbols = {key: deepcopy(self._asteval.symtable[key]) for key in sym_unique} return self.__class__, (), {'unique_symbols': unique_symbols, 'params': params} def __setstate__(self, state): """Unpickle a Parameters instance. Parameters ---------- state : dict state['unique_symbols'] is a dictionary containing symbols that need to be injected into _asteval.symtable state['params'] is a list of Parameter instances to be added """ # first update the Interpreter symbol table. This needs to be done # first because Parameter's early in the list may depend on later # Parameter's. This leads to problems because add_many eventually leads # to a Parameter value being retrieved with _getval, which, if the # dependent value hasn't already been added to the symtable, leads to # an Error. Another way of doing this would be to remove all the expr # from the Parameter instances before they get added, then to restore # them. self._asteval.symtable.update(state['unique_symbols']) # then add all the parameters self.add_many(*state['params']) def eval(self, expr): """Evaluate a statement using the asteval Interpreter. Parameters ---------- expr : string An expression containing parameter names and other symbols recognizable by the asteval Interpreter. Returns ------- The result of the expression. """ return self._asteval.eval(expr) def update_constraints(self): """Update all constrained parameters, checking that dependencies are evaluated as needed.""" requires_update = {name for name, par in self.items() if par._expr is not None} updated_tracker = set(requires_update) def _update_param(name): """Update a parameter value, including setting bounds. For a constrained parameter (one with an `expr` defined), this first updates (recursively) all parameters on which the parameter depends (using the 'deps' field). """ par = self.__getitem__(name) if par._expr_eval is None: par._expr_eval = self._asteval for dep in par._expr_deps: if dep in updated_tracker: _update_param(dep) self._asteval.symtable[name] = par.value updated_tracker.discard(name) for name in requires_update: _update_param(name) def pretty_repr(self, oneline=False): """Return a pretty representation of a Parameters class. Parameters ---------- oneline : bool, optional If True prints a one-line parameters representation (default is False). Returns ------- s: str Parameters representation. """ if oneline: return super(Parameters, self).__repr__() s = "Parameters({\n" for key in self.keys(): s += " '%s': %s, \n" % (key, self[key]) s += " })\n" return s def pretty_print(self, oneline=False, colwidth=8, precision=4, fmt='g', columns=['value', 'min', 'max', 'stderr', 'vary', 'expr', 'brute_step']): """Pretty-print of parameters data. Parameters ---------- oneline : bool, optional If True prints a one-line parameters representation (default is False). colwidth : int, optional Column width for all columns specified in :attr:`columns`. precision : int, optional Number of digits to be printed after floating point. fmt : {'g', 'e', 'f'}, optional Single-character numeric formatter. Valid values are: 'f' floating point, 'g' floating point and exponential, or 'e' exponential. columns : :obj:`list` of :obj:`str`, optional List of :class:`Parameter` attribute names to print. """ if oneline: print(self.pretty_repr(oneline=oneline)) return name_len = max(len(s) for s in self) allcols = ['name'] + columns title = '{:{name_len}} ' + len(columns) * ' {:>{n}}' print(title.format(*allcols, name_len=name_len, n=colwidth).title()) numstyle = '{%s:>{n}.{p}{f}}' # format for numeric columns otherstyles = dict(name='{name:<{name_len}} ', stderr='{stderr!s:>{n}}', vary='{vary!s:>{n}}', expr='{expr!s:>{n}}', brute_step='{brute_step!s:>{n}}') line = ' '.join([otherstyles.get(k, numstyle % k) for k in allcols]) for name, values in sorted(self.items()): pvalues = {k: getattr(values, k) for k in columns} pvalues['name'] = name # stderr is a special case: it is either numeric or None (i.e. str) if 'stderr' in columns and pvalues['stderr'] is not None: pvalues['stderr'] = (numstyle % '').format( pvalues['stderr'], n=colwidth, p=precision, f=fmt) elif 'brute_step' in columns and pvalues['brute_step'] is not None: pvalues['brute_step'] = (numstyle % '').format( pvalues['brute_step'], n=colwidth, p=precision, f=fmt) print(line.format(name_len=name_len, n=colwidth, p=precision, f=fmt, **pvalues)) def _repr_html_(self): """Returns a HTML representation of parameters data.""" return params_html_table(self) def add(self, name, value=None, vary=True, min=-inf, max=inf, expr=None, brute_step=None): """Add a Parameter. Parameters ---------- name : str Name of parameter. Must match ``[a-z_][a-z0-9_]*`` and cannot be a Python reserved word. value : float, optional Numerical Parameter value, typically the *initial value*. vary : bool, optional Whether the Parameter is varied during a fit (default is True). min : float, optional Lower bound for value (default is `-numpy.inf`, no lower bound). max : float, optional Upper bound for value (default is `numpy.inf`, no upper bound). expr : str, optional Mathematical expression used to constrain the value during the fit. brute_step : float, optional Step size for grid points in the `brute` method. Examples -------- >>> params = Parameters() >>> params.add('xvar', value=0.50, min=0, max=1) >>> params.add('yvar', expr='1.0 - xvar') which is equivalent to: >>> params = Parameters() >>> params['xvar'] = Parameter(name='xvar', value=0.50, min=0, max=1) >>> params['yvar'] = Parameter(name='yvar', expr='1.0 - xvar') """ if isinstance(name, Parameter): self.__setitem__(name.name, name) else: self.__setitem__(name, Parameter(value=value, name=name, vary=vary, min=min, max=max, expr=expr, brute_step=brute_step)) def add_many(self, *parlist): """Add many parameters, using a sequence of tuples. Parameters ---------- parlist : :obj:`sequence` of :obj:`tuple` or :class:`Parameter` A sequence of tuples, or a sequence of `Parameter` instances. If it is a sequence of tuples, then each tuple must contain at least the name. The order in each tuple must be `(name, value, vary, min, max, expr, brute_step)`. Examples -------- >>> params = Parameters() # add with tuples: (NAME VALUE VARY MIN MAX EXPR BRUTE_STEP) >>> params.add_many(('amp', 10, True, None, None, None, None), ... ('cen', 4, True, 0.0, None, None, None), ... ('wid', 1, False, None, None, None, None), ... ('frac', 0.5)) # add a sequence of Parameters >>> f = Parameter('par_f', 100) >>> g = Parameter('par_g', 2.) >>> params.add_many(f, g) """ for para in parlist: if isinstance(para, Parameter): self.__setitem__(para.name, para) else: param = Parameter(*para) self.__setitem__(param.name, param) def valuesdict(self): """Return an ordered dictionary of parameter values. Returns ------- OrderedDict An ordered dictionary of :attr:`name`::attr:`value` pairs for each Parameter. """ return OrderedDict((p.name, p.value) for p in self.values()) def dumps(self, **kws): """Represent Parameters as a JSON string. Parameters ---------- **kws : optional Keyword arguments that are passed to `json.dumps()`. Returns ------- str JSON string representation of Parameters. See Also -------- dump(), loads(), load(), json.dumps() """ params = [p.__getstate__() for p in self.values()] sym_unique = self._asteval.user_defined_symbols() unique_symbols = {key: encode4js(deepcopy(self._asteval.symtable[key])) for key in sym_unique} return json.dumps({'unique_symbols': unique_symbols, 'params': params}, **kws) def loads(self, s, **kws): """Load Parameters from a JSON string. Parameters ---------- **kws : optional Keyword arguments that are passed to `json.loads()`. Returns ------- :class:`Parameters` Updated Parameters from the JSON string. Notes ----- Current Parameters will be cleared before loading the data from the JSON string. See Also -------- dump(), dumps(), load(), json.loads() """ self.clear() tmp = decode4js(json.loads(s, **kws)) state = {'unique_symbols': tmp['unique_symbols'], 'params': []} for parstate in tmp['params']: _par = Parameter() _par.__setstate__(parstate) state['params'].append(_par) self.__setstate__(state) return self def dump(self, fp, **kws): """Write JSON representation of Parameters to a file-like object. Parameters ---------- fp : file-like object An open and ``.write()``-supporting file-like object. **kws : optional Keyword arguments that are passed to `dumps()`. Returns ------- None or int Return value from `fp.write()`. None for Python 2.7 and the number of characters written in Python 3. See Also -------- dump(), load(), json.dump() """ return fp.write(self.dumps(**kws)) def load(self, fp, **kws): """Load JSON representation of Parameters from a file-like object. Parameters ---------- fp : file-like object An open and ``.read()``-supporting file-like object. **kws : optional Keyword arguments that are passed to `loads()`. Returns ------- :class:`Parameters` Updated Parameters loaded from `fp`. See Also -------- dump(), loads(), json.load() """ return self.loads(fp.read(), **kws)