def thread(func, *args, **kwargs): """ Internal threading function keyword args are not threaded """ length = None for arg in args: if isinstance(arg, iterables): if length is not None: if length != len(arg): raise FunctionException( "General::thread", "Cannot Thread over Lists of Unequal Length.", ) else: length = len(arg) if length is None: return func(*args, **kwargs) chained = list(args) for i in range(len(chained)): if not isinstance(chained[i], iterables): chained[i] = (chained[i],) * length return List.create(thread(func, *z, **kwargs) for z in zip(*chained))
def evaluate_no_lazy(expr): """ Evaluate an expression with current definitions. Does not evaluate any LazyFunctions in given expression. """ # if is iterable, apply for each element if isinstance(expr, iterables) and not isinstance(expr, s.Matrix): return List.create(evaluate_no_lazy(x) for x in expr) # if expr does not have ability to perform substitutions, return if not hasattr(expr, "xreplace"): return expr def extend(ex): # if ex is a number, return if hasattr(ex, "is_Number") and ex.is_Number: return ex # if ex is a symbol, return definitions if present if isinstance(ex, s.Symbol): st = ex.name if st in r.refs.OwnValues: return r.refs.OwnValues[st] elif st in r.refs.Constants.Dict: return r.refs.Constants.Dict[st] # if ex does not have any arguments, return if not hasattr(ex, "args") or not isinstance(ex.args, iterables): return ex # ex is supposed to be a function at this point (since args are present) f_name = type(ex).__name__ # do not make substitutions if function is explicit # since explicit functions require unevaluated args if Functions.is_explicit(f_name): return ex # evaluate args rep = {x: extend(x) for x in ex.args} ex = ex.xreplace(rep) # built-ins are automatically re-evaluated # when replacements are made by sympy # apply definitions if function has any if Functions.is_not_builtin(f_name): ex = Functions.apply_definitions(ex) return ex # evaluate inside-out return extend(expr)
def evaluate(expr): """ Evaluate an expression with current definitions. Evaluates all LazyFunctions in given expression. """ # see evaluate_no_lazy for explanation if isinstance(expr, iterables) and not isinstance(expr, s.Matrix): return List.create(LazyFunction.evaluate(x) for x in expr) if not hasattr(expr, "subs"): return expr def extend(ex): if hasattr(ex, "is_Number") and ex.is_Number: return ex if isinstance(ex, s.Symbol): st = ex.name if st in r.refs.OwnValues: return r.refs.OwnValues[st] elif st in r.refs.Constants.Dict: return r.refs.Constants.Dict[st] if not hasattr(ex, "args") or not isinstance(ex.args, iterables): return ex f_name = type(ex).__name__ if Functions.is_explicit(f_name): # if explicit lazy function, call with args un-evaluated if isinstance(ex, LazyFunction): return ex.land() return ex rep = {x: extend(x) for x in ex.args} ex = ex.xreplace(rep) if Functions.is_not_builtin(f_name): ex = Functions.apply_definitions(ex) # if lazy function, call actual function if isinstance(ex, LazyFunction): return ex.land() return ex return extend(expr)
def exec(cls, n): if isinstance(n, iterables): return List.create(Unset(x) for x in n) if isinstance(n, s.Symbol) and str(n) in r.refs.OwnValues: del r.refs.OwnValues[str(n)] return NoOutput(None)
def do_set(x, n): """Handles assignment""" refs = r.refs if isinstance(x, s.Symbol): if not is_assignable(x.name): raise FunctionException( "Set::setx", f"Symbol {x} is protected and cannot be assigned to.", ) if isinstance(x, Tag): set_tag_value(x, n) return n if isinstance(n, s.Expr): if x in n.atoms(): return None # TODO: raise refs.OwnValues[x.name] = n return n if isinstance(x, s.Function): name = type(x).__name__ # handle part assignment if name == "Part": return set_part(x, n) if not is_assignable(name): raise FunctionException("Set::set", f"Symbol {x} cannot be Assigned to.") # create dict of patterns if not present if name not in refs.DownValues: refs.DownValues[name] = {ArgsPattern(*x.args): n} # else add pattern to existing dict else: pat = ArgsPattern(*x.args) # remove duplicate if present remove_duplicate_pattern(refs.DownValues[name], pat) # update in place refs.DownValues[name].update({pat: n}) # sort dict when done # sorting is done during assignment to keep function calls fast refs.DownValues[name] = OrderedDict( sorted( refs.DownValues[name].items(), key=lambda z: z[0].importance, reverse=True, ) ) return n if isinstance(x, iterables): if isinstance(n, iterables) and len(x) == len(n): return List.create(Set(a, b) for a, b in zip(x, n)) else: raise FunctionException("Set::shape") return None