def on_neighbor (self, match, direction, edge, name, loc) : if name == "*" : return sympy.Indexed(st.newstar(), direction == "?", edge or sympy.S.true, loc or sympy.S.true) else : return sympy.Indexed(name, direction == "?", edge or sympy.S.true, loc or sympy.S.true)
def load_g(self): # load all g or recompute or compute new. if self.recompute_g or not (lib.files_exist( self.g_fnames)): # generate self.g_list, self.gx_list, self.gy_list = ([] for i in range(3)) print('* Computing...', end=' ') for i in range(self.trunc_g + 1): print('g_' + str(i), end=', ') self.generate_g(i) print() # save for i in range(self.trunc_g + 1): np.savetxt(self.g_fnames[i], self.g_list[i]) else: # load self.g_list, self.gx_list, self.gy_list = self.load_sols( self.g_fnames, name='g') rulex = { sym.Indexed('gx', i): self.gx_list[i](self.t) for i in range(len(self.g_fnames)) } ruley = { sym.Indexed('gy', i): self.gy_list[i](self.t) for i in range(len(self.g_fnames)) } self.rule_g = {**rulex, **ruley}
def on_variable (self, match, name, location=None, forall=None) : if forall is not None : return sympy.Indexed(st._FORALOC, name, *forall) elif not location : return sympy.Indexed(st._THISLOC, name) elif isinstance(location, list) : return sympy.Indexed(st._NEXTLOC, name, *location) else : return sympy.Indexed(location, name)
def generate_z(self, k, total_iter=5): # load kth expansion of g for k >= 1 rulex = { sym.Indexed('zx', i): self.zx_list[i](self.t) for i in range(k) } ruley = { sym.Indexed('zy', i): self.zy_list[i](self.t) for i in range(k) } rule = {**rulex, **ruley, **self.rule_g} zhx = self.hetx_list[k].subs(rule) zhy = self.hety_list[k].subs(rule) hetx_lam = lambdify(self.t, zhx) hety_lam = lambdify(self.t, zhy) if k == 0: init = copy.deepcopy(self.z0_init) total_iter = 1 else: init = [0, 0] # Newton for mm in range(total_iter): init += lib.get_newton_jac(self.dz, self.tLC, init, hetx_lam, hety_lam, k) zu = odeint(self.dz, init, self.tLC, args=(hetx_lam, hety_lam, k), tfirst=True) if k == 0: # normalize dLC = lib.rhs([np.cos(0), np.sin(0)], 0, self.f) print('dLC', dLC, 'zu[0,:]', zu[0, :], 'z0 init', self.z0_init, 'np.dot(dLC,zu[0,:])', np.dot(dLC, zu[0, :])) zu = self.omega * zu / (np.dot(dLC, zu[0, :])) fnx = interp1d(self.tLC, zu[:, 0]) fny = interp1d(self.tLC, zu[:, 1]) self.zx_list.append( implemented_function('zx_' + str(k), self.myFun(fnx))) self.zy_list.append( implemented_function('zy_' + str(k), self.myFun(fny))) self.zx_callable.append(lambdify(self.t, self.zx_list[k](self.t))) self.zy_callable.append(lambdify(self.t, self.zy_list[k](self.t))) return zu
def calc_R2(model, x_points, y_points): display(model) # model.replace("x", "sym.Indexed(x, k)") model = model.subs(x, sym.Indexed(x, k)) display(1/len(x_points)) R2_model = sym.sqrt(1/len(x_points)*sym.Sum(((model) - sym.Indexed(y, k))**2,(k,0,len(x_points) -1))) display(R2_model) f_R2 = sym.lambdify((x, y), R2_model) R2 = f_R2(x_points, y_points) display(R2) pass
def expansion_slow(maxorder=4): """ This is the naive (and very slow) implementation of the ("hard mode" part of the) expansion. This function is intended to be a debugging tool. Do not use this in production code. Parameters ---------- maxorder : int Highest order of \alpha taken into account in the expansion. See also -------- - expansion """ res = 0 f = sp.IndexedBase('f') kres = 0 for k in range(maxorder): kres += dalpha(k)/sp.factorial(k)*((-sp.log(N))**k) for i in xrange(maxorder): res += sp.Indexed(f, i)*(kres**(i+1)) return res
def __new__(cls, base, index): if isinstance(base, (str, sympy.IndexedBase, sympy.Symbol)): return sympy.Indexed(base, index) elif not isinstance(base, sympy.Basic): raise ValueError("`base` must be of type sympy.Basic") obj = sympy.Expr.__new__(cls, base) obj._base = base obj._index = as_tuple(index) return obj
def return_indexed(base, indeces, **kw_args): if is_sequence(indeces): # Special case needed because M[*my_tuple] is a syntax error. if base.shape and len(base.shape) != len(indeces): raise Exception("Rank mismatch.") return op.IndexedArray(base, *indeces, **kw_args) else: if base.shape and len(base.shape) != 1: raise sp.Indexed("Rank mismatch.") return op.IndexedArray(base, indeces, **kw_args)
def split(self): queries = GetLocQueries(*self.condition, *self.assignment).found replace = [] matches = [] for q in queries: svar, lvar, m = self._qmatch(q) replace.append(sympy.Indexed(svar, lvar)) matches.append(m) concrete = self.subs(dict(zip(queries, replace))) for prod in product(*matches): yield concrete.subs( dict(chain.from_iterable(p.items() for p in prod)))
def check(n): """ A simple consistency check for the expansion """ coeff_c_subs_dict = {sp.Indexed(c, i):0 for i in range(n+1)} dd = debug_exp(n).subs({b1:0}).subs(coeff_c_subs_dict).removeO() for i in range(0, n): j = i+1 #print ese(j) #print dd.coeff(y, j) print "\torder {:2d} -> {:s}".format(j, str(ese(j) == dd.coeff(y, j)))
def __new__(cls, base, index): if isinstance(base, (str, sympy.IndexedBase, sympy.Symbol)): return sympy.Indexed(base, index) try: # If an AbstractFunction, pull the underlying Symbol base = base.indexed.label except AttributeError: if not isinstance(base, sympy.Basic): raise ValueError("`base` must be of type sympy.Basic") index = tuple(sympify(i) for i in as_tuple(index)) obj = sympy.Expr.__new__(cls, base, *index) obj._base = base obj._index = index return obj
def _expand(self, expr): queries = GetLocQueries(expr, match=_FORALOC).found if not queries: return [expr] matches = [] replace = [] for q in queries: s, l, m = self._qmatch(q) if not all(Star.star(k) for d in m for k in d): raise CompileError( "Matching node name is forbidden within %r" % txt(q)) matches.append(m) replace.append(sympy.Indexed(s, l)) concrete = expr.subs(dict(zip(queries, replace))) expanded = [] for match in product(*matches): d = dict(chain.from_iterable(m.items() for m in match)) expanded.append(concrete.subs(d)) return expanded
def _print_Assignment(self, expr): if isinstance(expr.lhs, sp.Array): lhs = expr.lhs rhs = expr.rhs if isinstance(expr.rhs, sp.Piecewise): # Here we modify Piecewise so each expression is now # an Assignment, and then continue on the print. expressions = [] conditions = [] for (e, c) in rhs.args: expressions.append(Assignment(lhs, e)) conditions.append(c) temp = sp.Piecewise(*zip(expressions, conditions)) return self._print(temp) lhs_code = self._print(sp.flatten(lhs.tolist())) # TODO: I think this is where I could make it so that the assignment gets pretty robust to multidimensional inputs # when I re-wrote the static trimmability function, I just had to apply .T instead of .ravel, that may be sufficient generally # since I already flatten the sympy expression that is being generated.... not sure though. rhs_code = self._print(rhs) + '.ravel()' return self._get_statement("%s = %s" % (lhs_code, rhs_code)) # I would prefer to have something like this, but isn't clear how temp = sp.Dummy() lines = [self._print(Assignment(temp, rhs))] temp = sp.Indexed(temp.name, lhs.shape) for idx, el in enumerate(lhs): lines.append('{}[{}]'.format(self._print(temp), 0)) else: if expr.rhs.func == sp.Piecewise: # The sympy/printing/codeprinter.py CodePrinter._print_Assignment explicitly # folds the assignments into each case, which is never over-written for the NumPyPrinter lhs_code = self._print(expr.lhs) rhs_code = self._print(expr.rhs) return self._get_statement("%s = %s" % (lhs_code, rhs_code)) return super()._print_Assignment(expr)
def ese(n): """ Even More Debug Stuff """ n = n-1 rese = sp.Sum((b0*sp.log(N))**y*sp.Indexed('f', n-y)*sp.binomial(n, y), (y, 0, n)).doit() return rese
def generate_i(self, k, total_iter=5): # load kth expansion of g for k >= 1 rulex = { sym.Indexed('zx', i): self.ix_list[i](self.t) for i in range(k) } ruley = { sym.Indexed('zy', i): self.iy_list[i](self.t) for i in range(k) } rule = {**rulex, **ruley, **self.rule_g} ihx = self.hetx_list[k].subs(rule) ihy = self.hety_list[k].subs(rule) hetx_lam = lambdify(self.t, ihx) hety_lam = lambdify(self.t, ihy) if k == 0: init = copy.deepcopy(self.i0_init) total_iter = 0 else: init = [0, 0] # Newton for mm in range(total_iter): if False and k == 1: fig = plt.figure() ax = fig.add_subplot(111) iu = odeint(self.di, init, self.tLC, args=(hetx_lam, hety_lam, k), tfirst=True) ax.plot(iu[:, 0]) ax.plot(iu[:, 1]) ax.set_title('mm=' + str(mm) + ', k=' + str(k)) plt.show(block=True) init += lib.get_newton_jac(self.di, self.tLC, init, hetx_lam, hety_lam, k) iu = odeint(self.di, init, self.tLC, args=(hetx_lam, hety_lam, k), tfirst=True) if k == 1: # normalize gx = lambdify(self.t, self.gx_list[1](self.t)) gy = lambdify(self.t, self.gy_list[1](self.t)) zx = lambdify(self.t, self.zx_list[0](self.t)) zy = lambdify(self.t, self.zy_list[0](self.t)) ix = lambdify(self.t, self.ix_list[0](self.t)) iy = lambdify(self.t, self.iy_list[0](self.t)) F = lib.rhs([np.cos(0), np.sin(0)], 0, self.f) g1 = np.array([gx(0), gy(0)]) z0 = np.array([zx(0), zy(0)]) i0 = np.array([ix(0), iy(0)]) J = self.jacLC(0) i1 = iu[0, :] ijg = np.dot(i0, np.dot(J, g1)) be = (self.kappa - ijg - np.dot(i1, F)) / (np.dot(z0, F)) init = iu[0, :] + be * z0 iu = odeint(self.di, init, self.tLC, args=(hetx_lam, hety_lam, k), tfirst=True) fnx = interp1d(self.tLC, iu[:, 0]) fny = interp1d(self.tLC, iu[:, 1]) self.ix_list.append( implemented_function('ix_' + str(k), self.myFun(fnx))) self.iy_list.append( implemented_function('iy_' + str(k), self.myFun(fny))) self.ix_callable.append(lambdify(self.t, self.ix_list[k](self.t))) self.iy_callable.append(lambdify(self.t, self.iy_list[k](self.t))) return iu
def generate_het(self): """ Generate heterogeneous terms for integrating the Z_i and I_i terms. Returns ------- None. """ self.hetx_list, self.hety_list = ([] for i in range(2)) # get the general expression for h in z before plugging in g,z. # column vectors ax ay for use in matrix A = [ax ay] self.ax = Matrix([[0], [0]]) self.ay = Matrix([[0], [0]]) for j in range(1, self.trunc_gh + 1): p1 = lib.kProd(j, self.dx) p2 = kp(p1, sym.eye(2)) d1 = lib.vec(lib.df(self.NIC1, self.x, j + 1)) d2 = lib.vec(lib.df(self.NIC2, self.x, j + 1)) self.ax += (1 / math.factorial(j)) * p2 * d1 self.ay += (1 / math.factorial(j)) * p2 * d2 self.A = sym.zeros(2, 2) self.A[:, 0] = self.ax self.A[:, 1] = self.ay self.z_expansion = Matrix([[self.zx], [self.zy]]) het = self.A * self.z_expansion # expand all terms self.hetx = sym.expand(het[0].subs([(self.dx1, self.gx), (self.dx2, self.gy)])) self.hety = sym.expand(het[1].subs([(self.dx1, self.gx), (self.dx2, self.gy)])) # collect all psi terms into factors of pis^k self.hetx_powers = sym.collect(self.hetx, self.psi, evaluate=False) self.hety_powers = sym.collect(self.hety, self.psi, evaluate=False) self.hetx_list = [] self.hety_list = [] counter = 0 while (counter <= self.trunc_g + 1): # save current term self.hetx_list.append(self.hetx_powers[self.psi**counter]) self.hety_list.append(self.hety_powers[self.psi**counter]) counter += 1 # substitute limit cycle for i in range(len(self.ghx_list)): self.hetx_list[i] = self.hetx_list[i].subs({ self.x1: sym.cos(2 * sym.pi * self.t), self.x2: sym.sin(2 * sym.pi * self.t), sym.Indexed('gx', 0): s(0), sym.Indexed('gy', 0): s(0) }) self.hety_list[i] = self.hety_list[i].subs({ self.x1: sym.cos(2 * sym.pi * self.t), self.x2: sym.sin(2 * sym.pi * self.t), sym.Indexed('gx', 0): s(0), sym.Indexed('gy', 0): s(0) })
def __init__( self, SIG=0.08, RHO=0.12, P=2 * np.pi, trunc_g=6, trunc_gh=3, TN=2000, dir='dat', recompute_monodromy=True, recompute_gh=False, recompute_g=False, recompute_het=False, recompute_z=False, recompute_i=False, ): """ recompute_gh : recompute het. terms for Floquet e.funs g """ # Model parameters self.SIG = SIG self.RHO = RHO self.P = P # Simulation/method parameters self.trunc_g = trunc_g # max power term in psi of Floquet e.fun g self.trunc_gh = trunc_gh # max in summation for heterogeneous term self.recompute_monodromy = recompute_monodromy self.recompute_gh = recompute_gh self.recompute_g = recompute_g self.recompute_het = recompute_het self.recompute_z = recompute_z self.recompute_i = recompute_i # find limit cycle or load self.T = 1 self.omega = 2 * np.pi self.TN = TN # find limit cycle -- easy for this problem but think of general methods # see Dan's code for general method self.tLC = np.linspace(0, self.T, self.TN) #LC_arr = odeint(rhs,[1,0],tLC,args=(f,)) # make interpolated version of LC #LC_interp_x = interp1d(tLC,LC_arr[:,0]) #LC_interp_y = interp1d(tLC,LC_arr[:,1]) # filenames and directories self.dir = 'dat/' if (not os.path.exists(self.dir)): os.makedirs(self.dir) self.model_params = '_sig=' + str(self.SIG) \ + '_rho=' + str(self.RHO) \ + '_P=' + str(self.P) self.sim_params = '_TN=' + str(self.TN) self.monodromy_fname = self.dir + 'monodromy_' + self.model_params + self.sim_params + '.txt' self.ghx_fnames = [ self.dir + 'ghx_' + str(i) + self.model_params + self.sim_params + '.d' for i in range(self.trunc_g + 1) ] self.ghy_fnames = [ self.dir + 'ghy_' + str(i) + self.model_params + self.sim_params + '.d' for i in range(self.trunc_g + 1) ] self.g_fnames = [ self.dir + 'g_' + str(i) + self.model_params + self.sim_params + '.txt' for i in range(self.trunc_g + 1) ] self.hetx_fnames = [ self.dir + 'hetx_' + str(i) + self.model_params + self.sim_params + '.d' for i in range(self.trunc_g + 1) ] self.hety_fnames = [ self.dir + 'hety_' + str(i) + self.model_params + self.sim_params + '.d' for i in range(self.trunc_g + 1) ] self.A_fname = self.dir + 'A_' + self.model_params + self.sim_params + '.d' self.z_fnames = [ self.dir + 'z_' + str(i) + self.model_params + self.sim_params + '.txt' for i in range(self.trunc_g + 1) ] self.i_fnames = [ self.dir + 'i_' + str(i) + self.model_params + self.sim_params + '.txt' for i in range(self.trunc_g + 1) ] # Symbolic variables and functions self.eye = np.identity(2) self.psi = sym.symbols('psi') self.x1, self.x2, self.x3, self.t = symbols('x1 x2,x3, t') self.dx1, self.dx2, self.dx3 = symbols('dx1 dx2 dx3') self.dx = Matrix([[self.dx1, self.dx2]]) self.x = Matrix([[self.x1, self.x2]]) R2 = self.x1**2 + self.x2**2 self.NIC1 = self.P * (self.SIG * self.x1 * (1 - R2) - self.x2 * (1 + self.RHO * (R2 - 1))) self.NIC2 = self.P * (self.SIG * self.x2 * (1 - R2) + self.x1 * (1 + self.RHO * (R2 - 1))) #self.rhs_sym = Matrix([self.NIC1,self.NIC2]) # symbol J on LC. self.jacLC_symbolic = Matrix( [[diff(self.NIC1, self.x1), diff(self.NIC1, self.x2)], [diff(self.NIC2, self.x1), diff(self.NIC2, self.x2)]]).subs([(self.x1, sym.cos(2 * pi * self.t)), (self.x2, sym.sin(2 * pi * self.t))]) # make RHS and Jacobian callable functions self.f = lambdify((self.x1, self.x2), [self.NIC1, self.NIC2]) #jac = sym.lambdify((x1,x2),Jac) self.jacLC = lambdify((self.t), self.jacLC_symbolic) # assume gx is the first coordinate of Floquet eigenfunction g # brackets denote Taylor expansion functions # now substitute Taylor expansion dx = gx[0] + gx[1] + gx[2] + ... i_sym = sym.symbols('i_sym') # summation index self.gx = sym.Sum(self.psi**i_sym * sym.Indexed('gx', i_sym), (i_sym, 0, self.trunc_g)).doit() self.gy = sym.Sum(self.psi**i_sym * sym.Indexed('gy', i_sym), (i_sym, 0, self.trunc_g)).doit() self.zx = sym.Sum(self.psi**i_sym * sym.Indexed('zx', i_sym), (i_sym, 0, self.trunc_g)).doit() self.zy = sym.Sum(self.psi**i_sym * sym.Indexed('zy', i_sym), (i_sym, 0, self.trunc_g)).doit() self.ix = sym.Sum(self.psi**i_sym * sym.Indexed('ix', i_sym), (i_sym, 0, self.trunc_g)).doit() self.iy = sym.Sum(self.psi**i_sym * sym.Indexed('iy', i_sym), (i_sym, 0, self.trunc_g)).doit() # Run method self.load_monodromy() # get monodromy matrix self.load_gh() # get heterogeneous terms for g self.load_g() # get g #t0 = time.time() self.load_het() self.load_z() self.load_i()
def generate_g(self, k, total_iter=4): # load kth expansion of g for k >= 0 if k == 0: # g0 is 0 self.g_list.append(np.zeros((self.TN, 2))) self.gx_list.append(implemented_function('gx_0', lambda t: 0)) self.gy_list.append(implemented_function('gy_0', lambda t: 0)) return rulex = { sym.Indexed('gx', i): self.gx_list[i](self.t) for i in range(k) } ruley = { sym.Indexed('gy', i): self.gy_list[i](self.t) for i in range(k) } rule = {**rulex, **ruley} # apply replacement self.ghx_list[k] = self.ghx_list[k].subs(rule) self.ghy_list[k] = self.ghy_list[k].subs(rule) # lambdify heterogeneous terms for use in integration hetx_lam = lambdify(self.t, self.ghx_list[k]) hety_lam = lambdify(self.t, self.ghy_list[k]) self.method = 'RK45' self.rtol = 1e-4 self.atol = 1e-8 # find intial condtion if k == 1: #init = [0,0] init = copy.deepcopy(self.g1_init) total_iter = 1 else: init = [0, 0] # Newton for mm in range(total_iter): out = lib.get_newton_jac(self, self.dg, -self.tLC, init, hetx_lam, hety_lam, k) print(out) init += out # get full solution gu = odeint(self.dg, init, -self.tLC, args=(hetx_lam, hety_lam, k), tfirst=True) gu = gu[::-1, :] # save soluton as lambda functions self.g_list.append(gu) fnx = interp1d(self.tLC, gu[:, 0], fill_value='extrapolate') fny = interp1d(self.tLC, gu[:, 1], fill_value='extrapolate') self.gx_list.append( implemented_function('gx_' + str(k), self.myFun(fnx))) self.gy_list.append( implemented_function('gy_' + str(k), self.myFun(fny))) if True and k == 1: fig = plt.figure() ax = fig.add_subplot(111) ax.plot(self.tLC, gu) ax.set_title('g1') plt.show(block=True) if True and k == 2: t = np.linspace(0, 1, 100) #fig = plt.figure() #ax = fig.add_subplot(111) #ax.plot(t,hetx_lam(t)) #ax.set_title('hetx_lam') #plt.show(block=True) fn = lambdify(self.t, self.gx_list[1](self.t)) fig = plt.figure() ax = fig.add_subplot(111) ax.plot(t, fn(t)) y = self.g_list[1][:, 0] ax.plot(np.linspace(0, 1, len(y)), y) ax.set_title('gx_list[1]') plt.show(block=True)
kpc = 1e3 # in units of pc autocm = 1.4960e13 #1 AU in cm pi = np.pi # Define starting coordinates on source plane (x,y) in dimensionless coordinates (u_x, u_y) # where u_x = (x / a_x) and a_x is the characteristic length scale (same goes for u_y). # This is done using Sympy u_x, u_y = sym.symbols('u_x u_y') A, B = 1.5e-2, 5 #Use Sympy to find derivatives of the potential N, j, theta, phi, sigma = sym.symbols('N j theta phi sigma') #name variables # Define various lens geometries gaussrand = sigma * sym.sqrt(2/N) * sym.Sum(sym.cos(u_y*sym.cos(sym.Indexed(theta, j)) + \ u_x*sym.sin(sym.Indexed(theta, j)) + sym.Indexed(phi, j)), (j, 1, N)) #gaussrand = 2 * sym.sqrt(2) * sym.cos(u_y*sym.cos(0.25*np.pi) + u_x*sym.sin(0.25*np.pi) + 2*np.pi) gauss = sym.exp(-u_x**2 - u_y**2) #gaussian ring = 2.7182 * (u_x**2 + u_y**2) * gauss #ring rectgauss = sym.exp(-u_x**4 - u_y**4) stgauss = gauss * (1. - A * (sym.sin(B * (u_x)) + sym.sin(B * (u_y - 2 * pi * 0.3))) ) #rectangular gaussian asymgauss = sym.exp(-u_x**2 - u_y**4) #asymmetrical gaussian supergauss2 = sym.exp(-(u_x**2 + u_y**2)**2) #gaussian squared supergauss3 = sym.exp(-(u_x**2 + u_y**2)**3) #gaussian cubed superlorentz = 1. / ( (u_x**2 + u_y**2)**2 + 1.) #lorentzian with width (gamma) of 2 # Define preferred lens geometry (use gauss as test case)
def generate_gh(self): """ generate heterogeneous terms for the Floquet eigenfunctions g. Returns ------- list of symbolic heterogeneous terms in self.ghx_list, self.ghy_list. """ self.ghx_list = [] self.ghy_list = [] # get the general expression for h before plugging in g. self.hx = 0 self.hy = 0 for i in range(2, self.trunc_gh + 1): # all x1,x2 are evaluated on limit cycle x=cos(t), y=sin(t) p = lib.kProd(i, self.dx) d1 = lib.vec(lib.df(self.NIC1, self.x, i)) d2 = lib.vec(lib.df(self.NIC2, self.x, i)) self.hx += (1 / math.factorial(i)) * np.dot(p, d1) self.hy += (1 / math.factorial(i)) * np.dot(p, d2) self.hx = sym.Matrix(self.hx) self.hy = sym.Matrix(self.hy) # expand all terms self.hx = sym.expand( self.hx.subs([(self.dx1, self.gx), (self.dx2, self.gy)])) self.hy = sym.expand( self.hy.subs([(self.dx1, self.gx), (self.dx2, self.gy)])) # collect all psi terms into list of some kind self.tempx = sym.collect(self.hx[0], self.psi, evaluate=False) self.tempy = sym.collect(self.hy[0], self.psi, evaluate=False) counter = 0 while (counter <= self.trunc_g + 1): # save current term self.ghx_list.append(self.tempx[self.psi**counter]) self.ghy_list.append(self.tempy[self.psi**counter]) counter += 1 # substitute limit cycle. maybe move elsewhere. for i in range(len(self.ghx_list)): self.ghx_list[i] = self.ghx_list[i].subs({ self.x1: sym.cos(2 * sym.pi * self.t), self.x2: sym.sin(2 * sym.pi * self.t), sym.Indexed('gx', 0): s(0), sym.Indexed('gy', 0): s(0) }) self.ghy_list[i] = self.ghy_list[i].subs({ self.x1: sym.cos(2 * sym.pi * self.t), self.x2: sym.sin(2 * sym.pi * self.t), sym.Indexed('gx', 0): s(0), sym.Indexed('gy', 0): s(0) })
def calc_R2(model, x_points, y_points): # Calculate R^2 model = model.subs(x, sym.Indexed(x, k)) R2_model = sym.sqrt(1 / len(x_points) * sym.Sum( ((model) - sym.Indexed(y, k))**2, (k, 0, len(x_points) - 1))) f_R2 = sym.lambdify((x, y), R2_model) return f_R2(x_points, y_points)
def fit_model(str_model, x_points, y_points): # Fit a model to a dataset of (x, y) points # Interpret and evaluate the given model still_searching = True model = str_model.replace('x', 'sym.Indexed(x, k)') free_vars = [] free_vars_indices = [] while still_searching: match = re.search(r"v_\d+", model) if not match: still_searching = False continue matching_text = match.group() var_num = re.search(r"\d+", matching_text).group() model = model[:match.span()[0]] + "sym.Indexed(v," + \ str(var_num) + ")" + model[match.span()[1]:] free_vars.append(eval("sym.Indexed(v," + str(var_num) + ")")) free_vars_indices.append(int(var_num)) model = eval(model) # Symbols used but this time declared inside function j, k, n, v, x, y, a = sym.symbols('j k n v x y, a') # Number of free variables in the model num_free_vars = len(free_vars) # To be minimized E = sym.Sum((model - sym.Indexed(y, k))**2, (k, 0, len(x_points) - 1)) solved_eqs = [] # List of partially solved equations # to_display("Starting now", "debug") for var_num in free_vars_indices: print("v_" + str(var_num)) # Print this iteration number eq = E.diff(sym.Indexed(v, var_num)) # Find the derivative # Lambdify the newly created equation f = sym.lambdify((x, y, *free_vars), eq) # Solve the equation as much as possible solved_eq = f(x_points, y_points, *free_vars) # Add the soved equation to the list of solved equations solved_eqs.append(solved_eq) # Solve all the equations for all the free variables solved = sym.solve((solved_eqs), (free_vars), simplify=False) # Create list of evenly distibuted x-points x_list = np.linspace(np.min(x_points) - 1, np.max(x_points) + 1, 10000) # Find variables in model str and replace with solved[sym.Indexed(v,n)] still_searching = True solved_model = str_model while still_searching: match = re.search(r"v_\d+", solved_model) if not match: still_searching = False continue matching_text = match.group() var_num = pattern = r"\d+" var_num = re.search(r"\d+", matching_text).group() if not sym.Indexed(v, var_num) in solved: print("excluding {}".format(var_num)) solved_model = solved_model[:match.span( )[0]] + "0" + solved_model[match.span()[1]:] continue solved_model = solved_model[:match.span( )[0]] + "solved[sym.Indexed(v," + str( var_num) + ")]" + solved_model[match.span()[1]:] # Evaluating the solved model solved_model_eval = eval(solved_model) # Generate y-coords for each x-coord y_generator = sym.lambdify((x), solved_model_eval) y_list = y_generator(x_list) # Setup figure fig = plt.figure() ax = fig.add_axes([0, 0, 1, 1]) fig = ax.set_xlim((np.min(x_points) - 0.02, np.max(x_points) + 0.02)) fig = ax.set_ylim((np.min(y_points) - 0.02, np.max(y_points) + 0.02)) # R^2 print("R^2:") print(calc_R2(solved_model_eval, x_points, y_points), "R2") # Return model return (x_list, y_list)
def fit_model(str_model, x_points, y_points): still_searching = True model = str_model.replace('x', 'sym.Indexed(x, k)') free_vars = [] free_vars_indices = [] while still_searching: match = re.search(r"v_\d+", model) if not match: still_searching = False continue matching_text = match.group() var_num = re.search(r"\d+", matching_text).group() model = model[:match.span()[0]] + "sym.Indexed(v," + str( var_num) + ")" + model[match.span()[1]:] free_vars.append(eval("sym.Indexed(v," + str(var_num) + ")")) free_vars_indices.append(int(var_num)) # print(model) model = eval(model) # Symbols used j, k, n, v, x, y, a = sym.symbols('j k n v x y, a') # Model to use num_free_vars = len(free_vars) # model = sym.Indexed(v, 1) * sym.sin(sym.Indexed(x, k)) + sym.Indexed(v,2) * sym.cos(sym.Indexed(x, k)) # model = Indexed(v, 5)*Indexed(x, k)**4 + Indexed(v, 4)*Indexed(x, k)**3 + Indexed(v, 3)*Indexed(x, k)**2 + Indexed(v, 2)*Indexed(x, k)**1 + Indexed(v, 1)*Indexed(x, k)**0 to_display("Model to fit:", "text") to_display(model, "math") # To be minimized E = sym.Sum((model - sym.Indexed(y, k))**2, (k, 0, len(x_points) - 1)) to_display("Equation to minimize:", "text") to_display(E, "math") # List of variables to solve for to_display("Free variables to solve for:", "text") to_display(free_vars, "math") solved_eqs = [] print("Starting now") for var_num in free_vars_indices: print(var_num) to_display("Solving for: ", "text") to_display(sym.Indexed(v, var_num), "math") eq = E.diff(sym.Indexed(v, var_num)) to_display(eq, "math") f = sym.lambdify((x, y, *free_vars), eq) solved_eq = f(x_points, y_points, *free_vars) to_display(solved_eq, "math") solved_eqs.append(solved_eq) # Solve n equations with n unknowns solved = sym.solve((solved_eqs), (free_vars), quick=True) # Create list of evenly distibuted x-points x_list = np.linspace(np.min(x_points) - 1, np.max(x_points) + 1, 10000) # solved_model = solved[sym.Indexed(v, 1)] * sym.sin(x) + solved[sym.Indexed(v,2)] * sym.cos(x) still_searching = True solved_model = str_model while still_searching: match = re.search(r"v_\d+", solved_model) if not match: still_searching = False continue matching_text = match.group() var_num = pattern = r"\d+" var_num = re.search(r"\d+", matching_text).group() if not sym.Indexed(v, var_num) in solved: print("excluding {}".format(var_num)) solved_model = solved_model[:match.span( )[0]] + "0" + solved_model[match.span()[1]:] continue solved_model = solved_model[:match.span( )[0]] + "solved[sym.Indexed(v," + str( var_num) + ")]" + solved_model[match.span()[1]:] solved_model_eval = eval(solved_model) to_display("Solved model evaluated:", "text") to_display(solved_model_eval, "math") # Generate y-coords for each x-coord y_generator = sym.lambdify((x), solved_model_eval) y_list = y_generator(x_list) # Setup figure fig = plt.figure() ax = fig.add_axes([0, 0, 1, 1]) fig = ax.set_xlim((np.min(x_points) - 2, np.max(x_points) + 2)) fig = ax.set_ylim((np.min(y_points) - 2, np.max(y_points) + 2)) # Display figure fig = ax.scatter(x_points, y_points, color='black') fig = ax.plot(x_list, y_list) if not should_display["diagram"]: plt.close() # Don't display plt.show() # R^2 to_display(calc_R2(solved_model_eval, x_points, y_points), "R2")
def expansion(maxorder=4): """ A function to compute the expansion of finite volume correction parameters f_i(N) in terms of f_i, c_i, N, and the beta function of the theory. Parameters ---------- maxorder : int Highest order of \alpha taken into account in the expansion. References ---------- For details see, e.g., 'Bali et al., PRD 89, 054505 (2014)' """ res = 0 #_ii = sp.symbols("_ii") f = sp.IndexedBase('f') kres = 0 # "hard mode" expansion (coefficients f[i] ) #--------------------------------------------------------------------------- for k in range(maxorder): kres += dalpha(k)/sp.factorial(k)*((-sp.log(N))**k) # Use a simpler symbol for alpha once we have the expansion kres = kres.subs(alpha(x), y).expand() #kres = kres.removeO() for i in xrange(maxorder): order_cutoff = maxorder+1 if i > 0: order_cutoff = maxorder + 1 - i if DEBUG_FLAG: print "\tterm:{:02d}/{:02d}".format(i+1, maxorder) # Remove powers that, when kres is raised to power i, will be # of order larger than maxorder kres_to_order = kres + sp.O(y**order_cutoff) # Make aux an expansion up to order (maxorder) aux = kres_to_order.removeO() # The previous line is necessary! # (spympy.O(x**n)+sympy.O(x**m) = spympy.O(x**min(n, m))) aux = aux + sp.O(y**(maxorder+1)) aux = rec_power(aux, (i+1)) # Make aux an expansion up to order (maxorder) again # spympy.O(x**n)*sympy.O(x**m) = sympy.O(x**(n+m)) aux = aux + sp.O(y**(maxorder+1)) aux = aux.expand(y) res += sp.Indexed(f, i)*(aux) res = res.expand() # "soft mode" expansion (coefficients c[i]) #--------------------------------------------------------------------------- hard_exp = 1 for i in xrange(maxorder-1): hard_exp += sp.Indexed(c, i)*y**(i+1) res = res*hard_exp res = res.expand() return res
def fit_func_b1_c(xx, NN, i, ORD, bb0, bb1, known, *args): """ Fit function describing the finite volume effects for a given order for a symmetric lattice with V=L*L. This function is specialised for the case where the c_i coefficients are fit parameters and the \beta-function coefficients \beta_0 and \beta_1 are set to their physical values. All \beta_j with j>1 are set to zero. WARNING!!! ---------- Note that the coeffs in the PCM calculation are indexed differently (c_n corresponds to order \alpha^n , not \alpha^(n+1) Parameters ---------- xx : float The linear lattice extend L (V=L*L). NN : int The rank N of the SU(N) matrices of the Principal Chiral model. i : int The expansion order. ORD : int The highest expansion order considered in the calculation. This is has to be known to calculate the total number of free parameters in the fits. bb0 : float The value of the \beta_0 coefficient of the \beta-function of the Principal Chiral model. bb1 : float The value of the \beta_1 coefficient of the \beta-function of the Principal Chiral model. known : int The number of known infinite volume expansion coefficients used as input for the fits. args : array_type An array that holds all the fit coefficients Returns ------- The fit function for given order i, rank N and lattice size xx. """ # Check if logsum already computed ... try: logsum = logsum_b1_c_dict[(i, ORD)] # ... and compute if unknown except KeyError: #print expansion_coefficient(i) # Symbols for lambdify lgN, f = sp.symbols("lgN, f") global c # c[ORD/2-2] and f[ORD/2-1] are not distinguishable in fits log_exp = expansion_coefficient(i-1) log_exp = log_exp.subs({sp.log(N):lgN, sp.Indexed(c, int(np.floor(ORD/2.))-2):0}) #Generate logsum function of given order i logsum = sp.lambdify((b0, b1, lgN, f, c), log_exp, modules="numpy") # Update the global dict logsum_b1_c_dict[(i, ORD)] = logsum numfitcoef = int(np.floor(ORD/2.)) + 1 - known idx_c_coef = int(np.floor(ORD/2.)) + numfitcoef xx = np.array(xx) xx_log = np.log(xx) if i < known: return pcm.coef(2*i, NN) + logsum(bb0, bb1, xx_log, args[numfitcoef:idx_c_coef], args[idx_c_coef:])/xx**2 else: return args[int(i)-known] + logsum(bb0, bb1, xx_log, args[numfitcoef:idx_c_coef], args[idx_c_coef:])/xx**2
def epc_string(n, bb1=False, c_coeffs=False, ToFloat=True): """ Return a string of expansion coefficient n for use in output *.dat files. Numerical expressions are evaluated as far as possible and N is replaced by x (for plotting in gnuplot). Moreover f[j] is replaced by f_b0_j or f_b1_j, depending on the value of bb1. Results are cached for later use. Parameters ---------- n : int Desired coefficient order. Keep in mind the index convention of the expansion_coefficient function! bb1 : bool Flag to toggle inclusion/exclusion of beta_1 terms. Default is False. c_coeffs : bool Flag to toggle inclusion/exclusion of c_i coefficients. Default is False. ToFloat : bool If True numerical expressions (like ratios) are evaluates as far as possible. Default is True. Returns ------- The expansion coefficient of order n converted to a string. """ try: ep_str = epc_strings[(n, bb1, c_coeffs, ToFloat)] return ep_str except KeyError: ep_n = expansion_coefficient(n) ep_n = ep_n.subs(N, x) if ToFloat: ep_n = sp.N(ep_n) #print ep_n if not bb1: ep_n = ep_n.subs(b1, 0) if not c_coeffs: coeff_c_subs_dict = {sp.Indexed(c, i):0 for i in range(n)} ep_n = ep_n.subs(coeff_c_subs_dict) ep_n = str(ep_n) # Update global dict if bb1: ep_n = re.sub(r'f\[(\d*)\]', r'f_b1_\1', ep_n) ep_n = re.sub(r'c\[(\d*)\]', r'c_b1_\1', ep_n) else: ep_n = re.sub(r'f\[(\d*)\]', r'f_b0_\1', ep_n) ep_n = re.sub(r'c\[(\d*)\]', r'c_b0_\1', ep_n) epc_strings[(n, bb1, c_coeffs, ToFloat)] = ep_n return ep_n