def ifThenElse(condition, val1, val2, *args, **kwargs): # for future implementation assert len(args) == 0 and len(kwargs) == 0 Val1 = atleast_oofun(val1)#fixed_oofun(val1) if not isinstance(val1, oofun) else val1 #if np.isscalar(val1): raise 0 Val2 = atleast_oofun(val2)#fixed_oofun(val2) if not isinstance(val2, oofun) else val2 if isinstance(condition, bool): return Val1 if condition else Val2 elif isinstance(condition, oofun): f = lambda conditionResult, value1Result, value2Result: value1Result if conditionResult else value2Result # !!! Don't modify it elseware function will evaluate both expressions despite of condition value r = oofun(f, [condition, val1, val2]) r.D = lambda point, *args, **kwargs: (Val1.D(point, *args, **kwargs) if isinstance(Val1, oofun) else {}) if condition(point) else \ (Val2.D(point, *args, **kwargs) if isinstance(Val2, oofun) else {}) r._D = lambda point, *args, **kwargs: (Val1._D(point, *args, **kwargs) if isinstance(Val1, oofun) else {}) if condition(point) else \ (Val2._D(point, *args, **kwargs) if isinstance(Val2, oofun) else {}) r.d = errFunc # TODO: try to set correct value from val1, val2 if condition is fixed # def getOrder(Vars=None, fixedVars=None, *args, **kwargs): # dep = condition.getDep() # if Vars is not None and dep.is return r else: raise FuncDesignerException('ifThenElse requires 1st argument (condition) to be either boolean or oofun, got %s instead' % type(condition))
def integrator(func, domain, **kwargs): if not scipyInstalled: raise FuncDesignerException( 'to use scipy_integrate_quad you should have scipy installed, see scipy.org' ) # if not isinstance(domain, dict) or len(domain) != 1: # raise FuncDesignerException('currently integration domain must be of type Pythoon dict {integr_var:(val_from, val_to)} only') #integration_var = domain.keys()[0] #_from, _to = domain.values()[0] integration_var, a, b = domain if not isinstance(integration_var, oovar): raise FuncDesignerException( 'integration variable must be FuncDesigner oovar') a, b, func = atleast_oofun(a), atleast_oofun(b), atleast_oofun(func) def f(point=None): p2 = point.copy() #if integration_var not in p2: #p2[integration_var] = 0.0 # to ajust size, currently only R^1 is implemented #T = FuncDesignerTranslator(p2) def vect_func(x): p2[integration_var] = x tmp = func(p2) if np.isscalar(tmp): return tmp elif tmp.size == 1: return np.asscalar(tmp) else: FuncDesignerException( 'incorrect data type, probably bug in uncDesigner kernel') #vect_func = lambda x: func(T.vector2point(x)) # TODO: better handling of fixed variables return integrate.quad(vect_func, a(point), b(point), **kwargs)[0] # def aux_f(point): # point = oopoint(_point) # if a(point).size != b(point).size: raise FuncDesignerException('sizes of point-from and point-to must be equal') # if a(point).size != 1 or b(point).size != 1: raise FuncDesignerException('currently integration is implemented for single variable only') # dep = a._getDep() | b._getDep() | func._getDep() # involved_vars = set(point.keys()).add(integration_var) # if not dep.issubset(involved_vars): raise FuncDesignerException('user-provided point for integration has no information on some variables') # # p2 = point.copy() # if integration_var not in p2: # p2[integration_var] = 0.0 # to ajust size, currently only R^1 is implemented # T = FuncDesignerTranslator(p2) # vect_func = lambda x: func(T.vector2point(x)) # TODO: derivatives # !!!!!!!!!!!!! TODO: derivatives should not be zeros! Fix it! r = oofun(f, None) r.fun = lambda *args: f(point=r._Point) # TODO : use decorators here tmp_f = r._getFunc tmp_D = r._D def aux_f(*args, **kwargs): if isinstance(args[0], dict): r._Point = args[0] return tmp_f(*args, **kwargs) def aux_D(*args, **kwargs): raise FuncDesignerException( 'derivatives from scipy_quad are not implemented yet') if isinstance(args[0], dict): r._Point = args[0] return tmp_D(*args, **kwargs) r._getFunc = aux_f r._D = aux_D return r
def __init__(self, equations, startPoint, *args, **kwargs): if len(args) > 2: raise FuncDesignerException('incorrect ode definition, too many args are obtained') if not isinstance(equations, dict): raise FuncDesignerException('1st argument of ode constructor should be Python dict') if not isinstance(startPoint, dict): raise FuncDesignerException('2nd argument of ode constructor should be Python dict') if len(args) == 2: print(""" FuncDesigner warning: you're using obsolete ode() API, now time should be passed as 3rd argument {timeVariable: times} or just array of times if equations are time-independend""") timeVariable, times = args[0], args[1] else: if len(args) != 1 or type(args[0]) not in (dict, list, tuple, ndarray): raise FuncDesignerException('3rd argument of ode constructor must be dict {timeVariable:array_of_times} or just array_of_times') if type(args[0]) == dict: if len(args[0]) != 1: raise FuncDesignerException('in time argument dict has to have exactly 1 entry') timeVariable, times = list(args[0].items())[0] if not isinstance(timeVariable, oovar): raise FuncDesignerException('incorrect time variable, must be FuncDesigner oofun') else: times = args[0] timeVariable = None self.timeVariable = timeVariable if timeVariable is not None and timeVariable in equations: raise FuncDesignerException("ode: differentiation of a variable by itself (time by time) is treated as a potential bug and thus is forbidden") if not (isinstance(times, (list, tuple)) or (isinstance(times, ndarray) and times.ndim == 1)): raise FuncDesignerException('incorrect user-defined time argument, must be Python list or numpy array of time values') self.times = times self._fd_func, self._startPoint, self._timeVariable, self._times, self._kwargs = equations, startPoint, timeVariable, times, kwargs startPoint = startPoint.copy()#dict((key, val) for key, val in startPoint.items()) if timeVariable is not None: startPoint[timeVariable] = times[0] y0 = [] Funcs = [] # setting oovar.size is risky - it can affect code written after the ode is solved # thus Point4TranslatorAssignment is used instead Point4TranslatorAssignment = {} for v, func in equations.items(): func = atleast_oofun(func) # if not isinstance(func, oofun): # func = fixed_oofun(func) if not isinstance(v, oovar): raise FuncDesignerException('ode: dict keys must be FuncDesigner oovars, got "%s" instead' % type(v)) startFVal = asarray(func(startPoint)) y0.append(asarray(startPoint[v])) Funcs.append(func) Point4TranslatorAssignment[v] = startFVal if startFVal.size != asarray(startPoint[v]).size or (hasattr(v, 'size') and isscalar(v.size) and startFVal.size != v.size): raise FuncDesignerException('error in user-defined data: oovar "%s" size is not equal to related function value in start point' % v.name) self.y0 = hstack(y0) self.varSizes = [y.size for y in y0] ooT = FuncDesignerTranslator(Point4TranslatorAssignment) self.ooT = ooT def func(y, t): tmp = dict(ooT.vector2point(y)) if timeVariable is not None: tmp[timeVariable] = t r = hstack([func(tmp) for func in Funcs]) return r self.func = func _FDVarsID = _getDiffVarsID() def derivative(y, t): # print('d') tmp = dict(ooT.vector2point(y)) if timeVariable is not None: tmp[timeVariable] = t r = [] for func in Funcs: tt = func.D(tmp, fixedVarsScheduleID = _FDVarsID) if timeVariable is not None: tt.pop(timeVariable, None) r.append(ooT.pointDerivative2array(tt)) return vstack(r) self.derivative = derivative self.Point4TranslatorAssignment = Point4TranslatorAssignment
def integrator(func, domain, **kwargs): if not scipyInstalled: raise FuncDesignerException("to use scipy_integrate_quad you should have scipy installed, see scipy.org") # if not isinstance(domain, dict) or len(domain) != 1: # raise FuncDesignerException('currently integration domain must be of type Pythoon dict {integr_var:(val_from, val_to)} only') # integration_var = domain.keys()[0] # _from, _to = domain.values()[0] integration_var, a, b = domain if not isinstance(integration_var, oovar): raise FuncDesignerException("integration variable must be FuncDesigner oovar") a, b, func = atleast_oofun(a), atleast_oofun(b), atleast_oofun(func) def f(point=None): p2 = point.copy() # if integration_var not in p2: # p2[integration_var] = 0.0 # to ajust size, currently only R^1 is implemented # T = FuncDesignerTranslator(p2) def vect_func(x): p2[integration_var] = x tmp = func(p2) if np.isscalar(tmp): return tmp elif tmp.size == 1: return np.asscalar(tmp) else: FuncDesignerException("incorrect data type, probably bug in uncDesigner kernel") # vect_func = lambda x: func(T.vector2point(x)) # TODO: better handling of fixed variables return integrate.quad(vect_func, a(point), b(point), **kwargs)[0] # def aux_f(point): # point = oopoint(_point) # if a(point).size != b(point).size: raise FuncDesignerException('sizes of point-from and point-to must be equal') # if a(point).size != 1 or b(point).size != 1: raise FuncDesignerException('currently integration is implemented for single variable only') # dep = a._getDep() | b._getDep() | func._getDep() # involved_vars = set(point.keys()).add(integration_var) # if not dep.issubset(involved_vars): raise FuncDesignerException('user-provided point for integration has no information on some variables') # # p2 = point.copy() # if integration_var not in p2: # p2[integration_var] = 0.0 # to ajust size, currently only R^1 is implemented # T = FuncDesignerTranslator(p2) # vect_func = lambda x: func(T.vector2point(x)) # TODO: derivatives # !!!!!!!!!!!!! TODO: derivatives should not be zeros! Fix it! r = oofun(f, None) r.fun = lambda *args: f(point=r._Point) # TODO : use decorators here tmp_f = r._getFunc tmp_D = r._D def aux_f(*args, **kwargs): if isinstance(args[0], dict): r._Point = args[0] return tmp_f(*args, **kwargs) def aux_D(*args, **kwargs): raise FuncDesignerException("derivatives from scipy_quad are not implemented yet") if isinstance(args[0], dict): r._Point = args[0] return tmp_D(*args, **kwargs) r._getFunc = aux_f r._D = aux_D return r