def get_sys(self, par=None, reduce_sys=None, verbose=False): st = time.time() if reduce_sys is None: try: reduce_sys = self.fdict['reduce_sys'] except KeyError: reduce_sys = False self.fdict['reduce_sys'] = reduce_sys if par is None: par = self.p0() if not self.const_var: raise NotImplementedError('Pakage is only meant to work with OBCs') vv_v = np.array([v.name for v in self.variables]) vv_x = np.array(self.variables) dim_v = len(vv_v) # obtain matrices from pydsge # this could be further accelerated by getting them directly from the equations in pydsge AA = self.AA(par) # forward BB = self.BB(par) # contemp CC = self.CC(par) # backward bb = self.bb(par).flatten() # constraint # the special case in which the constraint is just a cut-off of another variable requires b = bb.astype(float) # define transition shocks -> state D = self.PSI(par) # mask those vars that are either forward looking or part of the constraint in_x = ~fast0(AA, 0) | ~fast0(b[:dim_v]) # reduce x vector vv_x2 = vv_x[in_x] A1 = AA[:, in_x] b1 = np.hstack((b[:dim_v][in_x], b[dim_v:])) dim_x = len(vv_x2) # define actual matrices M = np.block([[np.zeros(A1.shape), CC], [np.eye(dim_x), np.zeros((dim_x, dim_v))]]) P = np.block([[A1, -BB], [np.zeros((dim_x, dim_x)), np.eye(dim_v)[in_x]]]) c_arg = list(vv_x2).index(self.const_var) # c contains information on how the constraint var affects the system c_M = M[:, c_arg] c_P = P[:, c_arg] # get rid of constrained var b2 = np.delete(b1, c_arg) M1 = np.delete(M, c_arg, 1) P1 = np.delete(P, c_arg, 1) vv_x3 = np.delete(vv_x2, c_arg) # decompose P in singular & nonsingular rows U, s, V = nl.svd(P1) s0 = fast0(s) P2 = np.diag(s) @ V M2 = U.T @ M1 c1 = U.T @ c_M if not fast0(c1[s0], 2) or not fast0(U.T[s0] @ c_P, 2): NotImplementedError( 'The system depends directly or indirectly on whether the constraint holds in the future or not.\n' ) # actual desingularization by iterating equations in M forward P2[s0] = M2[s0] if 'x_bar' in [p.name for p in self.parameters]: x_bar = par[[p.name for p in self.parameters].index('x_bar')] elif 'x_bar' in self.parafunc[0]: pf = self.parafunc x_bar = pf[1](par)[pf[0].index('x_bar')] else: print( "Parameter `x_bar` (maximum value of the constraint) not specified. Assuming x_bar = -1 for now." ) x_bar = -1 # create the stuff that the algorithm needs N = nl.inv(P2) @ M2 A = nl.inv(P2) @ (M2 + np.outer(c1, b2)) if sum(eig(A).round(3) >= 1) - len(vv_x3): raise ValueError('BC *not* satisfied.') dim_x = len(vv_x3) OME = re_bc(A, dim_x) J = np.hstack((np.eye(dim_x), -OME)) try: cx = nl.inv(P2) @ c1 * x_bar except ParafuncError: raise SyntaxError( "At least one parameter should rather be a function of parameters ('parafunc')..." ) # check condition: n1 = N[:dim_x, :dim_x] n3 = N[dim_x:, :dim_x] cc1 = cx[:dim_x] cc2 = cx[dim_x:] bb1 = b2[:dim_x] out_msk = fast0(N, 0) & fast0(A, 0) & fast0(b2) & fast0(cx) out_msk[-len(vv_v):] = out_msk[-len(vv_v):] & fast0(self.ZZ(par), 0) # store those that are/could be reduced self.out_msk = out_msk[-len(vv_v):].copy() if not reduce_sys: out_msk[-len(vv_v):] = False s_out_msk = out_msk[-len(vv_v):] if hasattr(self, 'P'): if self.P.shape[0] < sum(~s_out_msk): P_new = np.zeros((len(self.out_msk), len(self.out_msk))) if P_new[~self.out_msk][:, ~self.out_msk].shape != self.P.shape: print( '[get_sys:]'.ljust(15, ' ') + ' Shape missmatch of P-matrix, number of states seems to differ!' ) P_new[~self.out_msk][:, ~self.out_msk] = self.P self.P = P_new elif self.P.shape[0] > sum(~s_out_msk): self.P = self.P[~s_out_msk][:, ~s_out_msk] # add everything to the DSGE object self.vv = vv_v[~s_out_msk] self.vx = np.array([v.name for v in vv_x3]) self.dim_x = dim_x self.dim_v = len(self.vv) self.par = par self.hx = self.ZZ(par)[:, ~s_out_msk], self.DD(par).squeeze() self.obs_arg = np.where(self.hx[0])[1] N2 = N[~out_msk][:, ~out_msk] A2 = A[~out_msk][:, ~out_msk] J2 = J[:, ~out_msk] self.SIG = (BB.T @ D)[~s_out_msk] self.sys = N2, A2, J2, cx[~out_msk], b2[~out_msk], x_bar if verbose: print('[get_sys:]'.ljust(15, ' ') + 'Creation of system matrices finished in %ss.' % np.round(time.time() - st, 3)) return
def irfs(self, shocklist, wannasee=None, linear=False, verbose=False): # REWRITE!! # returns time series of impule responses # shocklist: takes list of tuples of (shock, size, timing) # wannasee: list of strings of the variables to be plotted and stored slabels = self.vv olabels = self.observables args_sts = [] args_obs = [] if wannasee not in (None, 'all', 'full'): for v_raw in wannasee: v = v_raw.replace('_', '') if v in slabels: args_sts.append(list(slabels).index(v)) elif v in olabels: args_obs.append(olabels.index(v)) else: raise Exception( "Variable %s neither in states nor observables. You might want to call self.get_sys() with the 'reduce_sys = False' argument. Note that underscores '_' are discarged." % v) st_vec = np.zeros(len(self.vv)) Y = [] K = [] L = [] superflag = False st = time.time() for t in range(30): shk_vec = np.zeros(len(self.shocks)) for vec in shocklist: if vec[2] == t: shock = vec[0] shocksize = vec[1] shock_arg = self.shocks.index(shock) shk_vec[shock_arg] = shocksize shk_process = (self.SIG @ shk_vec).nonzero() for shk in shk_process: args_sts += list(shk) st_vec, (l, k), flag = self.t_func(st_vec, shk_vec, linear=linear, return_k=True) if flag: superflag = True Y.append(st_vec) K.append(k) L.append(l) if superflag and verbose: print('[irfs:]'.ljust(15, ' ') + ' No rational expectations solution found.') Y = np.array(Y) K = np.array(K) L = np.array(L) care_for_sts = np.unique(args_sts) care_for_obs = np.unique(args_obs) if wannasee is None: Z = (self.hx[0] @ Y.T).T + self.hx[1] tt = ~fast0(Z - Z.mean(axis=0), 0) llabels = list(np.array(self.observables)[tt]) + list( self.vv[care_for_sts]) X2 = Y[:, care_for_sts] X = np.hstack((Z[:, tt], X2)) elif wannasee is 'full': llabels = list(self.vv) X = Y elif wannasee is 'all': tt = ~fast0(Y - Y.mean(axis=0), 0) llabels = list(self.vv[tt]) X = Y[:, tt] else: llabels = list(self.vv[care_for_sts]) X = Y[:, care_for_sts] if care_for_obs.size: llabels = list(np.array(self.observables)[care_for_obs]) + llabels Z = ((self.hx[0] @ Y.T).T + self.hx[1])[:, care_for_obs] X = np.hstack((Z, X)) if verbose: print('[irfs:]'.ljust(15, ' ') + 'Simulation took ', np.round((time.time() - st), 5), ' seconds.') labels = [] for l in llabels: if not isinstance(l, str): l = l.name labels.append(l) return X, labels, (Y, K, L)
def get_sys(self, par=None, reduce_sys=None, l_max=None, k_max=None, ignore_tests=False, verbose=False): """Creates the transition function given a set of parameters. If no parameters are given this will default to the calibration in the `yaml` file. Parameters ---------- par : array or list, optional The parameters to parse into the transition function. (defaults to calibration in `yaml`) reduce_sys : bool, optional If true, the state space is reduced. This speeds up computation. l_max : int, optional The expected number of periods *until* the constraint binds (defaults to 3). k_max : int, optional The expected number of periods for which the constraint binds (defaults to 17). """ st = time.time() reduce_sys = reduce_sys if reduce_sys is not None else self.fdict.get( 'reduce_sys') ignore_tests = ignore_tests if ignore_tests is not None else self.fdict.get( 'ignore_tests') l_max = 3 if l_max is None else l_max k_max = 17 if k_max is None else k_max self.fdict['reduce_sys'] = reduce_sys self.fdict['ignore_tests'] = ignore_tests par = self.p0() if par is None else list(par) ppar = self.compile(par) # parsed par if not self.const_var: raise NotImplementedError('Pakage is only meant to work with OBCs') vv_v = np.array([v.name for v in self.variables]) vv_x = np.array(self.variables) dim_v = len(vv_v) # obtain matrices from pydsge # this could be further accelerated by getting them directly from the equations in pydsge AA = self.AA(ppar) # forward BB = self.BB(ppar) # contemp CC = self.CC(ppar) # backward bb = self.bb(ppar).flatten() # constraint # the special case in which the constraint is just a cut-off of another variable requires b = bb.astype(float) # define transition shocks -> state D = self.PSI(ppar) # mask those vars that are either forward looking or part of the constraint in_x = ~fast0(AA, 0) | ~fast0(b[:dim_v]) # reduce x vector vv_x2 = vv_x[in_x] A1 = AA[:, in_x] b1 = np.hstack((b[:dim_v][in_x], b[dim_v:])) dim_x = len(vv_x2) # define actual matrices M = np.block([[np.zeros(A1.shape), CC], [np.eye(dim_x), np.zeros((dim_x, dim_v))]]) P = np.block([[A1, -BB], [np.zeros((dim_x, dim_x)), np.eye(dim_v)[in_x]]]) c_arg = list(vv_x2).index(self.const_var) # c contains information on how the constraint var affects the system c_M = M[:, c_arg] c_P = P[:, c_arg] # get rid of constrained var b2 = np.delete(b1, c_arg) M1 = np.delete(M, c_arg, 1) P1 = np.delete(P, c_arg, 1) vv_x3 = np.delete(vv_x2, c_arg) # decompose P in singular & nonsingular rows U, s, V = nl.svd(P1) s0 = fast0(s) P2 = np.diag(s) @ V M2 = U.T @ M1 c1 = U.T @ c_M if not fast0(c1[s0], 2) or not fast0(U.T[s0] @ c_P, 2): raise NotImplementedError( 'The system depends directly or indirectly on whether the constraint holds in the future or not.\n' ) # actual desingularization by iterating equations in M forward P2[s0] = M2[s0] if 'x_bar' in [p.name for p in self.parameters]: x_bar = par[[p.name for p in self.parameters].index('x_bar')] elif 'x_bar' in self.parafunc[0]: pf = self.parafunc x_bar = pf[1](par)[pf[0].index('x_bar')] else: print( "Parameter `x_bar` (maximum value of the constraint) not specified. Assuming x_bar = -1 for now." ) x_bar = -1 # create the stuff that the algorithm needs N = nl.inv(P2) @ M2 A = nl.inv(P2) @ (M2 + np.outer(c1, b2)) # rounding here to allow for small numeric errors during SVD & inversion if not ignore_tests: if sum(eig(A).round(3) < 1) > len(vv_v): raise ValueError( 'B-K condition *not* satisfied (too many EV < 1).') if sum(eig(A).round(3) >= 1) > len(vv_x3): raise ValueError( 'B-K condition *not* satisfied (too many EV > 1).') dim_x = len(vv_x3) OME = re_bc(A, dim_x) J = np.hstack((np.eye(dim_x), -OME)) try: cx = nl.inv(P2) @ c1 * x_bar except ParafuncError: raise SyntaxError( "At least one parameter is a function of other parameters, and should be declared in `parafunc`." ) # check condition: n1 = N[:dim_x, :dim_x] n3 = N[dim_x:, :dim_x] cc1 = cx[:dim_x] cc2 = cx[dim_x:] bb1 = b2[:dim_x] out_msk = fast0(N, 0) & fast0(A, 0) & fast0(b2) & fast0(cx) out_msk[-len(vv_v):] = out_msk[-len(vv_v):] & fast0(self.ZZ(ppar), 0) # store those that are/could be reduced self.out_msk = out_msk[-len(vv_v):].copy() if not reduce_sys: out_msk[-len(vv_v):] = False s_out_msk = out_msk[-len(vv_v):] if hasattr(self, 'P'): if self.P.shape[0] < sum(~s_out_msk): P_new = np.zeros((len(self.out_msk), len(self.out_msk))) if P_new[~self.out_msk][:, ~self.out_msk].shape != self.P.shape: print( '[get_sys:]'.ljust(15, ' ') + ' Shape missmatch of P-matrix, number of states seems to differ!' ) P_new[~self.out_msk][:, ~self.out_msk] = self.P self.P = P_new elif self.P.shape[0] > sum(~s_out_msk): self.P = self.P[~s_out_msk][:, ~s_out_msk] # add everything to the DSGE object self.vv = vv_v[~s_out_msk] self.vx = np.array([v.name for v in vv_x3]) self.dim_x = dim_x self.dim_v = len(self.vv) self.par = par self.ppar = ppar self.hx = self.ZZ(ppar)[:, ~s_out_msk], self.DD(ppar).squeeze() self.obs_arg = np.where(self.hx[0])[1] N2 = N[~out_msk][:, ~out_msk] A2 = A[~out_msk][:, ~out_msk] J2 = J[:, ~out_msk] self.SIG = (BB.T @ D)[~s_out_msk] self.sys = N2, A2, J2, cx[~out_msk], b2[~out_msk], x_bar if verbose: print('[get_sys:]'.ljust(15, ' ') + ' Creation of system matrices finished in %ss.' % np.round(time.time() - st, 3)) preprocess(self, l_max, k_max, verbose) test = self.precalc_mat[0][1, 0, 1] if not ignore_tests and (eig(test[-test.shape[1]:]) > 1).any(): raise ValueError('Explosive dynamics detected.') return
def get_sys(self, par=None, reduce_sys=None, l_max=None, k_max=None, linear=False, tol=1e-8, ignore_tests=False, verbose=False): """Creates the transition function given a set of parameters. If no parameters are given this will default to the calibration in the `yaml` file. Parameters ---------- par : array or list, optional The parameters to parse into the transition function. (defaults to calibration in `yaml`) reduce_sys : bool, optional If true, the state space is reduced. This speeds up computation. l_max : int, optional The expected number of periods *until* the constraint binds (defaults to 3). k_max : int, optional The expected number of periods for which the constraint binds (defaults to 17). """ st = time.time() reduce_sys = reduce_sys if reduce_sys is not None else self.fdict.get( 'reduce_sys') ignore_tests = ignore_tests if ignore_tests is not None else self.fdict.get( 'ignore_tests') if l_max is not None: if l_max < 2: print('[get_sys:]'.ljust(15, ' ') + ' `l_max` must be at least 2 (is %s). Correcting...' % l_max) l_max = 2 # effective l_max is one lower because algorithm exists on l_max l_max += 1 elif hasattr(self, 'lks'): l_max = self.lks[0] else: l_max = 1 if linear else 3 if k_max is not None: pass elif hasattr(self, 'lks'): k_max = self.lks[1] else: k_max = 0 if linear else 17 self.lks = [l_max, k_max] self.fdict['reduce_sys'] = reduce_sys self.fdict['ignore_tests'] = ignore_tests par = self.p0() if par is None else list(par) try: ppar = self.pcompile(par) # parsed par except AttributeError: ppar = self.compile(par) # parsed par self.par = par self.ppar = ppar if not self.const_var: raise NotImplementedError('Package is only meant to work with OBCs') vv_v = np.array([v.name for v in self.variables]) vv_x = np.array(self.variables) dim_v = len(vv_v) # obtain matrices AA = self.AA(ppar) # forward BB = self.BB(ppar) # contemp CC = self.CC(ppar) # backward bb = self.bb(ppar).flatten().astype(float) # constraint # define transition shocks -> state D = self.PSI(ppar) # mask those vars that are either forward looking or part of the constraint in_x = ~fast0(AA, 0) | ~fast0(bb[:dim_v]) # reduce x vector vv_x2 = vv_x[in_x] A1 = AA[:, in_x] b1 = np.hstack((bb[:dim_v][in_x], bb[dim_v:])) dim_x = len(vv_x2) # define actual matrices N = np.block([[np.zeros(A1.shape), CC], [np.eye(dim_x), np.zeros((dim_x, dim_v))]]) P = np.block([[-A1, -BB], [np.zeros((dim_x, dim_x)), np.eye(dim_v)[in_x]]]) c_arg = list(vv_x2).index(self.const_var) # c contains information on how the constraint var affects the system c1 = N[:, c_arg] c_P = P[:, c_arg] # get rid of constrained var b2 = np.delete(b1, c_arg) N1 = np.delete(N, c_arg, 1) P1 = np.delete(P, c_arg, 1) vv_x3 = np.delete(vv_x2, c_arg) dim_x = len(vv_x3) M1 = N1 + np.outer(c1, b2) # solve using Klein's method OME = re_bk(M1, P1, d_endo=dim_x) J = np.hstack((np.eye(dim_x), -OME)) # desingularization of P U, s, V = nl.svd(P1) s0 = s < tol P2 = U.T @ P1 N2 = U.T @ N1 c2 = U.T @ c1 # actual desingularization by iterating equations in M forward P2[s0] = N2[s0] # I could possible create auxiallary variables to make this work. Or I get the stuff directly from the boehlgo if not fast0(c2[s0], 2) or not fast0(U.T[s0] @ c_P, 2): raise NotImplementedError( 'The system depends directly or indirectly on whether the constraint holds in the future or not.\n' ) if verbose > 1: print('[get_sys:]'.ljust(15, ' ') + ' determinant of `P` is %1.2e.' % nl.det(P2)) if 'x_bar' in [p.name for p in self.parameters]: x_bar = par[[p.name for p in self.parameters].index('x_bar')] elif 'x_bar' in self.parafunc[0]: pf = self.parafunc x_bar = pf[1](par)[pf[0].index('x_bar')] else: print( "Parameter `x_bar` (maximum value of the constraint) not specified. Assuming x_bar = -1 for now." ) x_bar = -1 try: cx = nl.inv(P2) @ c2 * x_bar except ParafuncError: raise SyntaxError( "At least one parameter is a function of other parameters, and should be declared in `parafunc`." ) # create the stuff that the algorithm needs N = nl.inv(P2) @ N2 A = nl.inv(P2) @ (N2 + np.outer(c2, b2)) out_msk = fast0(N, 0) & fast0(A, 0) & fast0(b2) & fast0(cx) out_msk[-len(vv_v):] = out_msk[-len(vv_v):] & fast0(self.ZZ(ppar), 0) # store those that are/could be reduced self.out_msk = out_msk[-len(vv_v):].copy() if not reduce_sys: out_msk[-len(vv_v):] = False s_out_msk = out_msk[-len(vv_v):] if hasattr(self, 'P'): if self.P.shape[0] < sum(~s_out_msk): P_new = np.zeros((len(self.out_msk), len(self.out_msk))) if P_new[~self.out_msk][:, ~self.out_msk].shape != self.P.shape: print( '[get_sys:]'.ljust(15, ' ') + ' Shape missmatch of P-matrix, number of states seems to differ!' ) P_new[~self.out_msk][:, ~self.out_msk] = self.P self.P = P_new elif self.P.shape[0] > sum(~s_out_msk): self.P = self.P[~s_out_msk][:, ~s_out_msk] # add everything to the DSGE object self.vv = vv_v[~s_out_msk] self.vx = np.array([v.name for v in vv_x3]) self.dim_x = dim_x self.dim_v = len(self.vv) self.hx = self.ZZ(ppar)[:, ~s_out_msk], self.DD(ppar).squeeze() self.obs_arg = np.where(self.hx[0])[1] N2 = N[~out_msk][:, ~out_msk] A2 = A[~out_msk][:, ~out_msk] J2 = J[:, ~out_msk] self.SIG = (BB.T @ D)[~s_out_msk] self.sys = N2, A2, J2, cx[~out_msk], b2[~out_msk], x_bar if verbose: print('[get_sys:]'.ljust(15, ' ') + ' Creation of system matrices finished in %ss.' % np.round(time.time() - st, 3)) preprocess(self, self.lks[0], self.lks[1], verbose) if not ignore_tests: test_obj = self.precalc_mat[0][1, 0, 1] test_con = eig(test_obj[-test_obj.shape[1]:]) > 1 if test_con.any(): raise ValueError('Explosive dynamics detected: %s EV(s) > 1' % sum(test_con)) return
def gen_sys(self, AA0, BB0, CC0, DD0, fb0, fc0, fd0, ZZ0, ZZ1, l_max, k_max, get_hx_only, parallel, verbose): """Generate system matrices expressed in the one-sided, first-order compressed dimensionality reduction given a set of parameters. Details can be found in "Efficient Solution of Models with Occasionally Binding Constraints" (Gregor Boehl). If no parameters are given this will default to the calibration in the `yaml` file. Parameters ---------- par : array or list, optional The parameters to parse into the transition function. (defaults to calibration in `yaml`) l_max : int, optional The expected number of periods *until* the constraint binds (defaults to 3). k_max : int, optional The expected number of periods for which the constraint binds (defaults to 17). verbose : bool or int, optional Level of verbosity """ st = time.time() # set default values of l_max & k_max if l_max is not None: if l_max < 2 and k_max > 0: print('[get_sys:]'.ljust(15, ' ') + ' `l_max` must be at least 2 (is %s). Correcting...' % l_max) l_max = 2 # effective l_max is one lower because algorithm exists on l_max l_max += 1 # TODO: test if true elif hasattr(self, 'lks'): l_max = self.lks[0] else: l_max = 3 if k_max is not None: pass elif hasattr(self, 'lks'): k_max = self.lks[1] else: k_max = 17 self.lks = np.array([l_max, k_max]) # start vv0 = self.vv # z-space is the space of the original variables dimx = len(vv0) dimeps = len(self.shocks) # y-space is the space of the original variables augmented by the shocks c_arg = list(vv0).index(str(self.const_var)) fc0 = -fc0 / fb0[c_arg] fb0 = -fb0 / fb0[c_arg] # create auxiliry vars for those both in A & C inall = ~fast0(AA0, 0) & ~fast0(CC0, 0) if np.any(inall): vv0 = np.hstack((vv0, [v + '_lag' for v in vv0[inall]])) AA0 = np.pad(AA0, ((0, sum(inall)), (0, sum(inall)))) BB0 = np.pad(BB0, ((0, sum(inall)), (0, sum(inall)))) CC0 = np.pad(CC0, ((0, sum(inall)), (0, sum(inall)))) DD0 = np.pad(DD0, ((0, sum(inall)), (0, 0))) fb0 = np.pad(fb0, (0, sum(inall))) fc0 = np.pad(fc0, (0, sum(inall))) if ZZ0 is not None: ZZ0 = np.pad(ZZ0, ((0, 0), (0, sum(inall)))) BB0[-sum(inall):, -sum(inall):] = np.eye(sum(inall)) BB0[-sum(inall):, :-sum(inall)][:, inall] = -np.eye(sum(inall)) CC0[:, -sum(inall):] = CC0[:, :-sum(inall)][:, inall] CC0[:, :-sum(inall)][:, inall] = 0 # create representation in y-space AA0 = np.pad(AA0, ((0, dimeps), (0, dimeps))) BB0 = sl.block_diag(BB0, np.eye(dimeps)) CC0 = np.block([[CC0, DD0], [np.zeros((dimeps, AA0.shape[1]))]]) fb0 = np.pad(fb0, (0, dimeps)) if fd0 is not None: fc0 = -np.hstack((fc0, fd0)) else: fc0 = np.pad(fc0, (0, dimeps)) inq = ~fast0(CC0, 0) | ~fast0(fc0) inp = (~fast0(AA0, 0) | ~fast0(BB0, 0)) & ~inq # check dimensionality dimq = sum(inq) dimp = sum(inp) # create hx. Do this early so that the procedure can be stopped if get_hx_only if ZZ0 is None: # must create dummies zp = np.empty(dimp) zq = np.empty(dimq) zc = np.empty(1) else: zp = ZZ0[:, inp[:-dimeps]] zq = ZZ0[:, inq[:-dimeps]] zc = ZZ1 AA = np.pad(AA0, ((0, 1), (0, 0))) BBU = np.vstack((BB0, fb0)) CCU = np.vstack((CC0, fc0)) BBR = np.pad(BB0, ((0, 1), (0, 0))) CCR = np.pad(CC0, ((0, 1), (0, 0))) BBR[-1, list(vv0).index(str(self.const_var))] = -1 fb0[list(vv0).index(str(self.const_var))] = 0 self.svv = vv0[inq[:-dimeps]] self.cvv = vv0[inp[:-dimeps]] self.vv = np.hstack((self.cvv, self.svv)) self.dimx = len(self.vv) self.dimq = dimq self.dimp = dimp self.dimy = dimp + dimq self.dimeps = dimeps self.hx = zp, zq, zc if get_hx_only: return self PU = -np.hstack((BBU[:, inq], AA[:, inp])) MU = np.hstack((CCU[:, inq], BBU[:, inp])) PR = -np.hstack((BBR[:, inq], AA[:, inp])) MR = np.hstack((CCR[:, inq], BBR[:, inp])) gg = np.pad([float(self.x_bar)], (dimp + dimq - 1, 0)) # avoid QL in jitted funcs R, Q = sl.rq(MU.T) MU = R.T PU = Q @ aca(PU) R, Q = sl.rq(MR.T) MR = R.T PR = Q @ aca(PR) gg = Q @ gg solver = 'klein' # to be implemented if solver == 'speed_kills': omg, lam = speed_kills(PU, MU, dimp, dimq, tol=1e-4) else: omg, lam = klein(PU, MU, nstates=dimq, verbose=verbose, force=False) # finally add relevant stuff to the class fq0 = fc0[inq] fp1 = fb0[inp] fq1 = fb0[inq] self.sys = omg, lam, self.x_bar self.ff = fq1, fp1, fq0 # preprocess all system matrices until (l_max, k_max) preprocess(self, PU, MU, PR, MR, gg, fq1, fp1, fq0, parallel, verbose) if verbose: print('[get_sys:]'.ljust(15, ' ') + ' Creation of system matrices finished in %ss.' % np.round(time.time() - st, 3)) return self