def __init__(self, circ, poles, zeros, outfile): solution.__init__(self, circ, outfile) self.sol_type = "PZ" self.poles = np.sort_complex(np.array(poles).reshape((-1, ))) self.zeros = np.sort_complex(np.array(zeros).reshape((-1, ))) data = np.vstack((self.poles.reshape( (-1, 1)), self.zeros.reshape((-1, 1)))) if np.prod(self.poles.shape): for i in range(self.poles.shape[0]): self.variables += ['p%d' % i] if np.prod(self.zeros.shape): for i in range(self.zeros.shape[0]): self.variables += ['z%d' % i] for v in self.variables: self.units.update({v: "rad/s"}) self.csv_headers = [] for i in range(len(self.variables)): self.csv_headers.append("Re(%s)" % self.variables[i]) self.csv_headers.append("Im(%s)" % self.variables[i]) # save in Re/Im form sdata = data.reshape(-1).view(np.float_).reshape((-1, 1)) self._add_data(sdata) # store local data too: self.data = case_insensitive_dict() for i in range(len(self.variables)): self.data.update({self.variables[i]: data[i, 0]})
def __init__(self, circ, poles, zeros, outfile): solution.__init__(self, circ, outfile) self.sol_type = "PZ" self.poles = np.sort_complex(np.array(poles).reshape((-1,))) self.zeros = np.sort_complex(np.array(zeros).reshape((-1,))) data = np.vstack((self.poles.reshape((-1, 1)), self.zeros.reshape((-1, 1)))) if np.prod(self.poles.shape): for i in range(self.poles.shape[0]): self.variables += ['p%d' % i] if np.prod(self.zeros.shape): for i in range(self.zeros.shape[0]): self.variables += ['z%d' % i] for v in self.variables: self.units.update({v: "rad/s"}) self.csv_headers = [] for i in range(len(self.variables)): self.csv_headers.append("Re(%s)" % self.variables[i]) self.csv_headers.append("Im(%s)" % self.variables[i]) # save in Re/Im form sdata = data.reshape(-1).view(np.float_).reshape((-1, 1)) self._add_data(sdata) # store local data too: self.data = case_insensitive_dict() for i in range(len(self.variables)): self.data.update({self.variables[i]: data[i, 0]})
def myzpk2tf(self, z, p, k): z = np.atleast_1d(z) k = np.atleast_1d(k) if len(z.shape) > 1: temp = np.poly(z[0]) b = np.zeros((z.shape[0], z.shape[1] + 1), temp.dtype.char) if len(k) == 1: k = [k[0]] * z.shape[0] for i in range(z.shape[0]): b[i] = k[i] * poly(z[i]) else: b = k * np.poly(z) a = np.atleast_1d(np.poly(p)) # Use real output if possible. Copied from numpy.poly, since # we can't depend on a specific version of numpy. if issubclass(b.dtype.type, np.complexfloating): # if complex roots are all complex conjugates, the roots are real. roots = np.asarray(z, complex) pos_roots = np.compress(roots.imag > 0, roots) neg_roots = np.conjugate(np.compress(roots.imag < 0, roots)) if len(pos_roots) == len(neg_roots): if np.all(np.sort_complex(neg_roots) == np.sort_complex(pos_roots)): b = b.real.copy() if issubclass(a.dtype.type, np.complexfloating): # if complex roots are all complex conjugates, the roots are real. roots = np.asarray(p, complex) pos_roots = np.compress(roots.imag > 0, roots) neg_roots = np.conjugate(np.compress(roots.imag < 0, roots)) if len(pos_roots) == len(neg_roots): if np.all(np.sort_complex(neg_roots) == np.sort_complex(pos_roots)): a = a.real.copy() return b, a
def zpk2tf(z, p, k): """ Return polynomial transfer function representation from zeros and poles """ z = np.atleast_1d(z) k = np.atleast_1d(k) if len(z.shape) > 1: temp = np.poly(z[0]) b = np.zeros((z.shape[0], z.shape[1] + 1), temp.dtype.char) if len(k) == 1: k = [k[0]] * z.shape[0] for i in range(z.shape[0]): b[i] = k[i] * np.poly(z[i]) else: b = k * np.poly(z) a = np.atleast_1d(np.poly(p)) # Use real output if possible if issubclass(b.dtype.type, np.complexfloating): # if complex roots are all complex conjugates, the roots are real. roots = np.asarray(z, complex) pos_roots = np.compress(roots.imag > 0, roots) neg_roots = np.conjugate(np.compress(roots.imag < 0, roots)) if len(pos_roots) == len(neg_roots): if np.all( np.sort_complex(neg_roots) == np.sort_complex(pos_roots)): b = b.real.copy() if issubclass(a.dtype.type, np.complexfloating): # if complex roots are all complex conjugates, the roots are real. roots = np.asarray(p, complex) pos_roots = np.compress(roots.imag > 0, roots) neg_roots = np.conjugate(np.compress(roots.imag < 0, roots)) if len(pos_roots) == len(neg_roots): if np.all( np.sort_complex(neg_roots) == np.sort_complex(pos_roots)): a = a.real.copy() return b, a
def zpk2tf(z, p, k): """ Return polynomial transfer function representation from zeros and poles Parameters ---------- z : array_like Zeros of the transfer function. p : array_like Poles of the transfer function. k : float System gain. Returns ------- b : ndarray Numerator polynomial coefficients. a : ndarray Denominator polynomial coefficients. """ z = atleast_1d(z) k = atleast_1d(k) if len(z.shape) > 1: temp = poly(z[0]) b = zeros((z.shape[0], z.shape[1] + 1), temp.dtype.char) if len(k) == 1: k = [k[0]] * z.shape[0] for i in range(z.shape[0]): b[i] = k[i] * poly(z[i]) else: b = k * poly(z) a = atleast_1d(poly(p)) # Use real output if possible. Copied from numpy.poly, since # we can't depend on a specific version of numpy. if issubclass(b.dtype.type, numpy.complexfloating): # if complex roots are all complex conjugates, the roots are real. roots = numpy.asarray(z, complex) pos_roots = numpy.compress(roots.imag > 0, roots) neg_roots = numpy.conjugate(numpy.compress(roots.imag < 0, roots)) if len(pos_roots) == len(neg_roots): if numpy.all( numpy.sort_complex(neg_roots) == numpy.sort_complex( pos_roots)): b = b.real.copy() if issubclass(a.dtype.type, numpy.complexfloating): # if complex roots are all complex conjugates, the roots are real. roots = numpy.asarray(p, complex) pos_roots = numpy.compress(roots.imag > 0, roots) neg_roots = numpy.conjugate(numpy.compress(roots.imag < 0, roots)) if len(pos_roots) == len(neg_roots): if numpy.all( numpy.sort_complex(neg_roots) == numpy.sort_complex( pos_roots)): a = a.real.copy() return b, a
def allsortedclose(a, b, atol=1e-3, rtol=1e-3): if np.iscomplex(a).any(): a = np.sort_complex(a) else: a = np.sort(a) if np.iscomplex(b).any(): b = np.sort_complex(b) else: b = np.sort(b) return np.allclose(a, b, rtol=rtol, atol=atol)
def test_anisotropic_xi_eigenvalues(rnd_data1, rnd_data2, rnd_data3, rnd_data4, rnd_data5, rnd_data6): """ Comparison of eigenvalue calculation for xi from random complex material data. Comparing polynomial calculation from determinant, from quadratic eigenvalue problem and analytical calculation from sympy. """ lc = LocalCoordinates("1") myeps = np.zeros((3, 3), dtype=complex) myeps[0:2, 0:2] = rnd_data1 + complex(0, 1) * rnd_data2 myeps[2, 2] = rnd_data3 + complex(0, 1) * rnd_data4 #np.random.random((3, 3)) + complex(0, 1)*np.random.random((3, 3)) ((epsxx, epsxy, _), (epsyx, epsyy, _), (_, _, epszz)) = \ tuple(myeps) m = AnisotropicMaterial(lc, myeps) #n = np.random.random((3, 1)) #n = n/np.sqrt(np.sum(n*n, axis=0)) n = np.zeros((3, 1)) n[2, :] = 1 x = np.zeros((3, 1)) k = rnd_data5 + complex(0, 1) * rnd_data6 kpa = k - np.sum(n * k, axis=0) * n (eigenvalues, _) = m.calcXiEigenvectorsNorm(x, n, kpa) xiarray = m.calcXiNormZeros(x, n, kpa) # sympy check with analytical solution kx, ky, xi = sympy.symbols('k_x k_y xi') exx, exy, _, eyx, eyy, _, _, _, ezz \ = sympy.symbols('e_xx e_xy e_xz e_yx e_yy e_yz e_zx e_zy e_zz') #eps = Matrix([[exx, exy, exz], [eyx, eyy, eyz], [ezx, ezy, ezz]]) eps = sympy.Matrix([[exx, exy, 0], [eyx, eyy, 0], [0, 0, ezz]]) v = sympy.Matrix([[kx, ky, xi]]) m = -(v * v.T)[0] * sympy.eye(3) + v.T * v + eps detm = m.det().collect(xi) soldetm = sympy.solve(detm, xi) subsdict = { kx: kpa[0, 0], ky: kpa[1, 0], exx: epsxx, exy: epsxy, eyx: epsyx, eyy: epsyy, ezz: epszz, sympy.I: complex(0, 1) } analytical_solution = np.sort_complex( np.array([sol.evalf(subs=subsdict) for sol in soldetm], dtype=complex)) numerical_solution1 = np.sort_complex(xiarray[:, 0]) numerical_solution2 = np.sort_complex(eigenvalues[:, 0]) assert np.allclose(analytical_solution - numerical_solution1, 0) assert np.allclose(analytical_solution - numerical_solution2, 0)
def test_ChebyshevII_transferfunction(): N = 15 Wn = 1e3 rs = 60 chebyshevII_worth_system = cbadc.analog_system.ChebyshevII(N, Wn, rs) b, a = scipy.signal.cheby2(N, rs, Wn, btype='low', analog=True) print("b, a\n") print(b) print(a) z, p, k = scipy.signal.cheby2(N, rs, Wn, btype='low', analog=True, output='zpk') print("z,p,k") print(z) print(np.sort_complex(p)) print(k) ss_z, ss_p, ss_k = chebyshevII_worth_system.zpk() print("State Space model as zpk") print(ss_z) print(ss_p) print(ss_k) w, h = scipy.signal.freqs(b, a) tf = chebyshevII_worth_system.transfer_function_matrix(w) print(chebyshevII_worth_system) if not np.allclose(h, tf): print(h - tf) raise BaseException("Filter mismatch")
def test_ChebyshevI_transferfunction(): N = 4 Wn = 1e3 rp = np.sqrt(2) chebyshevI_worth_system = cbadc.analog_system.ChebyshevI(N, Wn, rp) b, a = scipy.signal.cheby1(N, rp, Wn, btype='low', analog=True) print("b, a\n") print(b) print(a) z, p, k = scipy.signal.cheby1(N, rp, Wn, btype='low', analog=True, output="zpk") print("z,p,k") print(z) print(np.sort_complex(p)) print(k) w, h = scipy.signal.freqs(b, a) tf = chebyshevI_worth_system.transfer_function_matrix(w) if not np.allclose(h, tf): print(h - tf) raise BaseException("Filter mismatch")
def test_ButterWorth_transferfunction(): N = 7 Wn = 1e3 butter_worth_system = cbadc.analog_system.ButterWorth(N, Wn) print(butter_worth_system) b, a = scipy.signal.butter(N, Wn, btype='low', analog=True) print("b, a\n") print(b) print(a) z, p, k = scipy.signal.butter(N, Wn, btype='low', output="zpk", analog=True) print("z,p,k") print(z) print(np.sort_complex(p)) print(k) print(zpk2abcd(z, p, k)) w, h = scipy.signal.freqs(b, a) tf = butter_worth_system.transfer_function_matrix(w)[:, 0, :].flatten() if not np.allclose(h, tf): # print(h, tf) print(h - tf) raise BaseException("Filter mismatch")
def test_Cauer_transferfunction(): N = 11 Wn = 1e3 rp = np.sqrt(2) rs = 60 cauer_worth_system = cbadc.analog_system.Cauer(N, Wn, rp, rs) b, a = scipy.signal.ellip(N, rp, rs, Wn, btype='low', analog=True) print("b, a\n") print(b) print(a) print(cauer_worth_system) w, h = scipy.signal.freqs(b, a) z, p, k = scipy.signal.ellip(N, rp, rs, Wn, btype='low', analog=True, output='zpk') print("z,p,k") print(z) print(np.sort_complex(p)) print(k) tf = cauer_worth_system.transfer_function_matrix(w) print(cauer_worth_system) if not np.allclose(h, tf): print(h - tf) raise BaseException("Filter mismatch")
def test_sort_complex(self): ma = Masked(np.array([1 + 2j, 0 + 4j, 3 + 0j, -1 - 1j]), mask=[True, False, False, False]) o = np.sort_complex(ma) indx = np.lexsort((ma.unmasked.imag, ma.unmasked.real, ma.mask)) expected = ma[indx] assert_masked_equal(o, expected)
def sort_and_output(self, E0): n = OPT_numdgt() self._out.setfloatwidth(n, n) Q = [] for i in E0.transpose(): if (i[1]): q = i[0] / i[1] im = np.imag(q) im = fixzero(im, 1e8) re = np.real(q) if (abs(re) > 1e8): continue re = fixzero(re, 1e8) Q.append(re + 1j * im) Q = np.array(Q) Q = np.sort_complex(1j * Q) / 1j # Q = np.sort_complex(Q) for i in Q: # print(' {:.6e}'.format(i)) # use outdata... self._out << np.real(i) if (np.imag(i) < 0): self._out << "- j*" else: self._out << "+ j*" self._out << abs(np.imag(i)) self._out << "\n"
def compute_quadratic_state_integral_ALDS(H, x0, T, dt=None): ''' Assuming the state x(t) evolves in time according to a linear dynamic: dx(t)/dt = H * x(t) Compute the following integral: int_{0}^{T} x(t)^T * x(t) dt ''' if (dt is None): w, V = eig(H) # H = V*matlib.diagflat(w)*V^{-1} print "Eigenvalues H:", np.sort_complex(w).T Lambda_inv = matlib.diagflat(1.0 / w) e_2T_Lambda = matlib.diagflat(np.exp(2 * T * w)) int_e_2T_Lambda = 0.5 * Lambda_inv * (e_2T_Lambda - matlib.eye(n)) # V_inv = np.linalg.inv(V) # cost = x0.T*(V_inv.T*(int_e_2T_Lambda*(V_inv*x0))) V_inv_x0 = np.linalg.solve(V, x0) cost = V_inv_x0.T * int_e_2T_Lambda * V_inv_x0 return cost[0, 0] N = int(T / dt) x = simulate_ALDS(H, x0, dt, N) cost = 0.0 not_finite_warning_printed = False for i in range(N): if (np.all(np.isfinite(x[:, i]))): cost += dt * (x[:, i].T * x[:, i])[0, 0] elif (not not_finite_warning_printed): print 'WARNING: x is not finite at time step %d' % (i) #, x[:,i].T not_finite_warning_printed = True return cost
def t3_sort_complex(complex_array): if len(complex_array) == 0: return (np.array([]), np.array([])) data = [[abs(i), i] for i in complex_array] data.sort(key=lambda data: data[0]) return (np.array(data)[:, 1], np.flip(np.sort_complex(complex_array), axis=0))
def map2k(maps, field_deg, k_max): field_deg = np.float64(field_deg) # k_max = k_max.astype(np.int) nside = maps.shape[0] # print(nside) ft_map = np.fft.rfft2(maps) * nside P = abs(ft_map)**2 l_min = 360.0 / field_deg #ell minimum ell=2pi/theta l_max = nside * l_min ly = np.fft.fftfreq(nside) * l_max #* l_max lx = np.fft.rfftfreq(nside) * l_max l = np.sqrt(lx[np.newaxis, :]**2 + ly[:, np.newaxis]**2) p_l = 1.0j * P + l pl = np.zeros(nside * (nside // 2 + 1), dtype='complex') p_l = np.sort_complex(p_l) p_l = p_l.reshape((1, len(pl))) pl[:] = p_l[0, :] # print(pl.shape) p_ll = interpolate.interp1d(pl.real, pl.imag, bounds_error=False, kind='linear', fill_value=0.0) ell = np.arange(k_max) C_l = p_ll(ell) return ell, C_l
def sortColumns(matrix): new_matrix = [] print("wymair macierzy: ", np.shape(matrix)) for i in range(len(matrix[0, :])): column = matrix[:, i] new_matrix.append(np.sort_complex(column)) return np.array(new_matrix).transpose()
def test_sort_complex_1(self): IntTestData = [5, 3, 6, 2, 1] ComplexTextData = [1 + 2j, 2 - 1j, 3 - 2j, 3 - 3j, 3 + 5j] a = np.sort(IntTestData) print(a) b = np.sort_complex(IntTestData) print(b) c = np.sort(ComplexTextData) print(c) d = np.sort_complex(ComplexTextData) print(d)
def compute_closed_loop_eigenvales(robot, gains_array): ''' Compute eigenvalues of linear part of closed-loop system: d3f = -Kd_bar*d2f - (K*Upsilon+Kp_bar)*df - Kp_bar*K*A*Kf*e_f + ... ''' ny=3 ei_cls_f = matlib.empty((3*nf,T), dtype=complex)*np.nan ei_cls = matlib.empty((3*nf+2*ny,T), dtype=complex)*np.nan for t in range(T): H = compute_closed_loop_transition_matrix(gains_array, robot, q[:,t], v[:,t]) H_f = H[2*ny:, 2*ny:] ei_cls_f[:,t] = np.sort_complex(eigvals(H_f)).reshape((3*nf,1)) ei_cls[:,t] = np.sort_complex(eigvals(H)).reshape((3*nf+2*ny,1)) plot_stats_eigenvalues(ei_cls_f, name='Closed-loop force tracking') plot_stats_eigenvalues(ei_cls, name='Closed-loop momentum tracking') return ei_cls
def t3_sort_complex(complex_array): if len(complex_array) == 0: return (np.array([]), np.array([])) tup = np.sort_complex(complex_array) module_array = np.array([abs(i) for i in complex_array]) x = module_array.argsort() return (complex_array[x], np.flip(tup, axis=0))
def compare_eigenvalues(values_test, values_answer, ds_name): # first sort values: first on real part, then on imaginary part values_test = np.sort_complex(values_test) values_answer = np.sort_complex(values_answer) fig, ax = plt.subplots(1, figsize=(12, 8)) fail_idxs = [] for i, val_test in enumerate(values_test): # calculate distance from this point to all points distances = np.sqrt((values_answer.real - val_test.real)**2 + (values_answer.imag - val_test.imag)**2) # find point with closest distance match = values_answer[distances.argmin()] # answer + test in pixels x_answ, y_answ = ax.transData.transform((match.real, match.imag)) x_test, y_test = ax.transData.transform((val_test.real, val_test.imag)) # get distance between both in pixels dist_pix = np.sqrt((x_answ - x_test)**2 + (y_answ - y_test)**2) try: # distance in pixels should lie below tolerance assert dist_pix < PIX_TOL except AssertionError: fail_idxs.append(i) ax.clear() # this should be empty if all values match. If not, raise error and save log if fail_idxs: for i in fail_idxs: val_test = values_test[i] val_answ = values_answer[i] print(f"FAIL: {val_test} >> {val_answ} (test >> answer)") ax.plot(val_test.real, val_test.imag, ".g", markersize=3) ax.plot(val_answ.real, val_answ.imag, "xr", markersize=3) ax.set_title(ds_name, fontsize=15) ax.set_xlabel(r"Re($\omega$)", fontsize=15) ax.set_ylabel(r"Im($\omega$)", fontsize=15) ax.tick_params(which="both", labelsize=15) ax.legend(["test results", "answer results"], loc="best", fontsize=13) print(f">>> FAILED EIGENVALUES: {len(fail_idxs)}/{len(values_answer)}") filename = (output / f"FAILED_{ds_name}.png").resolve() fig.savefig(filename, dpi=400) plt.close(fig) raise AssertionError plt.close(fig)
def sort_func(): x = np.array([3, 1, 2]) print("x ", x) # 数组排序 print("np.sort(a) ", np.sort(x)) # 多维数组排序 a = np.array([[1, 5, 4], [3, 2, 1]]) print("x ", a) # 数组排序 sort along the last axis print("np.sort(a) ", np.sort(a)) # sort the flattened array print(" np.sort(a, axis=None) ", np.sort(a, axis=None)) # sort along the first axis print(" np.sort(a, axis=0) ", np.sort(a, axis=0)) # 使用键序列执行间接排序。 surnames = ('Hertz', 'Galilei', 'Hertz') first_names = ('Heinrich', 'Galileo', 'Gustav') ind = np.lexsort((first_names, surnames)) print("ind", ind) rs = [surnames[i] + ", " + first_names[i] for i in ind] print("rs", rs) # 返回将数组分类的索引 返回索引 x = np.array([3, 1, 2]) print("np.argsort(x)", np.argsort(x)) # 排序后重新赋值到新的数组中 rs = [x[i] for i in ind] print("rs", rs) # 返回沿第一个轴排序的数组的副本。 x = np.array([3, 1, 2]) print("np.msort(x)", np.msort(x)) y = np.sort_complex([5, 3, 6, 2, 1]) print("y", y) # numpy.argmax 返回沿轴的最大值的索引 a = np.arange(6).reshape(2, 3) print("a", a) print("np.argmax(a)", np.argmax(a)) # numpy.argpartition a = np.array([[np.nan, 4], [2, 3]]) print("np.nanargmax(a)", np.nanargmax(a)) a = np.arange(6).reshape(2, 3) print("a", a) print("np.argmin(a)", np.argmin(a)) # 找到非零的数组元素的索引,按元素分组 x = np.argwhere(x > 1) print("x", x) x = np.where(x > 1) print("x", x) # 查找要插入元素以维持顺序的索引 x = np.searchsorted([1, 2, 3, 4, 5], 3) print("x", x)
def quartic_roots(k, x1, x2, x3): K = complex128(ellipk(k**2)) e0 = complex128((x1*j - x2)**2 + .25 * K**2) e1 = complex128(4*(x1*j-x2)*x3) e2 = complex128(4*(x3**2) - 2 * (x1**2) - 2 * (x2**2) + (K**2) * (k**2 - 0.5)) e3 = complex128(4*x3*(x2 + j*x1)) e4 = complex128(x2**2 - x1**2 + 2*j*x1*x2 + 0.25*K**2) return sort_complex(roots([e4, e3, e2, e1, e0])) # I put the sort_complex to have a canonical form, so that when we order them they will vary continuously
def get_highest_val(a): arr = [] for v in a: arr.append(v) arr = np.sort_complex(np.array(arr)) if len(arr) != 0: ret = arr[-1] else: ret = 0 return ret
def compute_cl_poles(ctl_num, ctl_den): ctl_tf = control.tf(ctl_num, ctl_den, dt) #print(ctl_tf) cl_tf = control.feedback(dt_tf, ctl_tf, sign=-1) #print control.damp(cl_tf) #print(cl_tf) cl_poles_d = control.pole(cl_tf) #print(cl_polesd) cl_poles_c = np.sort_complex(np.log(cl_poles_d) / dt) print('cl_poles_c\n{}'.format(cl_poles_c)) return cl_poles_d
def cplxpair(x, tol=100): """ Sort complex numbers into complex conjugate pairs. This function replaces MATLAB's cplxpair for vectors. """ x = carray(x) x = np.atleast_1d(x.squeeze()) x = x.tolist() x = [np.real_if_close(i, tol) for i in x] xreal = np.array(list(filter(np.isreal, x))) xcomplex = np.array(list(filter(np.iscomplex, x))) xreal = np.sort_complex(xreal) xcomplex = np.sort_complex(xcomplex) xcomplex_ipos = xcomplex[xcomplex.imag > 0.] xcomplex_ineg = xcomplex[xcomplex.imag <= 0.] if len(xcomplex_ipos) != len(xcomplex_ineg): raise ValueError("Complex numbers can't be paired.") res = [] for i, j in zip(xcomplex_ipos, xcomplex_ineg): if not abs(i - np.conj(j)) < tol * eps: raise ValueError("Complex numbers can't be paired.") res += [j, i] return np.hstack((np.array(res), xreal))
def optimize_gains(robot, gains_array, q0, v0, niter=10): nominal_gains_array = copy.deepcopy(gains_array) H = compute_closed_loop_transition_matrix(gains_array, robot, q0, v0) # step_response(H, N=10000, plot=0) print "Initial gains:", gains_array.T # print "Initial normalized gains:", normalize_gains_array(gains_array, nominal_gains_array).T print "Initial eigenvalues:\n", np.sort_complex(eigvals(H)).T; print "Initial cost", cost_function(np.ones_like(gains_array), robot, q0, v0, nominal_gains_array) #optimize gain global nit nit = 0 opt_res = basinhopping(cost_function, np.ones_like(gains_array), niter, disp=False, T=0.1, stepsize=.01, minimizer_kwargs={'args':(robot, q0, v0, nominal_gains_array)}, callback=callback) opt_gains = denormalize_gains_array(opt_res.x, nominal_gains_array); # print opt_res, '\n' #Plot step response H = compute_closed_loop_transition_matrix(opt_gains, robot, q0, v0) # step_response(H, N=10000, plot=0) print "Optimal gains: ", opt_gains print "Optimal normalized gains:", normalize_gains_array(opt_gains, nominal_gains_array).T print "Optimal eigenvalues:\n", list(np.sort_complex(eigvals(H)).T) return opt_gains
def StateConcurrence(mat_4x4): ''' Method that calculates the concurrence of any 2 qubit state, returns 0 if the state is pure and returns max(0, E_1 - E_2 - E_3 - E_4) where E are the eigenvalues in descending order of the matrix R = sqrt(sqrt(rho) rho_tilde sqrt(rho)) and rho_tilde is worked out using pauli_y outer pauli_y rho* pauli_y outer pauli_y ''' pauli_y = np.zeros(shape=(2, 2), dtype=complex) pauli_y[0, 1] = -1j pauli_y[1, 0] = 1j transform = np.outer(pauli_y, pauli_y) buf = np.matmul(transform, np.conj(mat_4x4)) # buffer variable for 3 matrix mult rho_tilde = np.matmul(buf, transform) root_rho = sqrtm( mat_4x4 ) # we now have all the matrices to make the argument in sqrt() for R buf2 = np.matmul(root_rho, rho_tilde) # bufer variable for 3 matrix mult root_arg = np.matmul(buf2, root_rho) big_R = sqrtm(root_arg) # now we have R we work out its eigenvalues try: eigenvalue_array = np.linalg.eigvals(big_R) except np.linalg.LinAlgError: print(big_R) print(mat_4x4) return 0 #now we sort the eigenvalues into ascending order, taking their moduli np.sort_complex(eigenvalue_array) #print(eigenvalue_array) #print(eigenvalue_array, 'EIGENS', len(eigenvalue_array)) concurrence_complex = 2 * eigenvalue_array[0] - np.sum(eigenvalue_array) #floating point error means it will never be 0 so we return the mixed state #concurrence and if it falls below a certain threshold we can call it "0" return np.abs(concurrence_complex)
def test_dense_ising_T_real(seed_rng): T = 3 J = np.random.normal() g = np.random.normal() h = np.random.normal() init = np.random.normal(size=(2, 2)) + 1.0j * np.random.normal(size=(2, 2)) init = init.T.conj() + init init = init @ init init /= np.trace(init) #init is a proper density matrix diT = dense.ising.ising_T(T, J, g, h, init) assert diT.dtype == np.complex_ assert diT.shape == (4**T, 4**T) ditev = la.eigvals(diT) ditevc = np.zeros((4**T)) ditevc[-1] = 1.0 assert np.sort_complex(ditev) == pytest.approx(ditevc, rel=5e-4, abs=5e-4)
def roots(self): """return the roots of the characteristic equation. possible cases for roots: Case 1: mu1 = a1 + j*b1 mu2 = a2 + j*b2 mu3 = cc(mu1) mu4 = cc(mu2) Case 2: mu1 = mu2 = a + j*b mu3 = mu4 = cc(mu1) For the orthotropic case (A16 = A26 = 0): purely imaginary roots, ai = 0 """ # LTH-FL 33100-05, or better: lehknitskij # NOTE: this is for fluxes, not stresses # get coefficients out of compliance matrix a = np.linalg.inv(self._lam.A()) c4 = a[0, 0] # a11 c3 = -2 * a[0, 2] # -2*a16 c2 = 2 * a[0, 1] + a[2, 2] # 2*a12 + a66 c1 = -2 * a[1, 2] # -2*a26 c0 = a[1, 1] # a22 # build polynomial and calculate roots # TODO: that algorithm is not too accurate -> find anything better?? poly = np.polynomial.Polynomial([c0, c1, c2, c3, c4]) roots = poly.roots() # verify that they are correct: value <= TOL TOL = 1e-9 assert all([abs(poly(r)) < TOL for r in roots]) # the 4 roots are either complex, then there is two pairs of congujate complex numbers. # Or they are purely imaginary. # In either case we want the roots with positive imaginary parts only. #print('number of roots found:', len(roots)) #print(roots) proots = roots[roots.imag > 0] # make sure its 2 roots. Should be ... assert len(proots) == 2 # set real part to zero if < 1e-9 proots.real[np.abs(proots.real) < 1e-9] = 0 return np.sort_complex(proots)
def test_dense_ising_T_pi4(): T = 3 J = np.pi / 4 g = np.pi / 4 h = 1.0 # init=np.random.normal(size=(2,2))+1.0j*np.random.normal(size=(2,2)) # init=init.T.conj()+init # init=init@init # init/=np.trace(init)#init is a proper density matrix init = np.eye(2) / 2 diT = dense.ising.ising_T(T, J, g, h, init) assert diT.dtype == np.complex_ assert diT.shape == (64, 64) ditev, ditevv = la.eig(diT) ditevc = np.zeros((4**T)) ditevc[-1] = 1.0 pdev = ditevv[:, np.argmax(np.abs(ditev))] print(pdev / pdev[0]) assert np.sort_complex(ditev) == pytest.approx(ditevc, rel=5e-4, abs=5e-4) assert pdev / pdev[0] == pytest.approx(dense.ising.perfect_dephaser_im(T))
def Complete_Format(self, Packet_Number): if self.Check_effection(Packet_Number): return 1 Bfee_count = self.Get_Bfee_count(Packet_Number) Perm = self.Get_Perm(Packet_Number) Nrx = self.Get_Nrx(Packet_Number) Ntx = self.Get_Ntx(Packet_Number) Noise = self.Get_Noise(Packet_Number) RSSI = self.Get_RSSI(Packet_Number) CSI = np.sort_complex(np.zeros((30, 3, 2))) #self.CSI = np.complex(self.CSI) CSI_Packet = self.Get_CSI(Packet_Number) if (len(CSI_Packet) < 20): return CSI_Packet count = 0 for Subcarrier in range(30): for Nrx_n in range(len(Nrx)): for Ntx_n in range(len(Ntx)): CSI[Subcarrier, Nrx_n, Ntx_n] = CSI_Packet[count] count = count + 1 return [Bfee_count, Perm, Nrx, Ntx, Noise, RSSI, CSI]
def parfiltid(input, out, p, NFIR = 1): # We don't want to have any poles in the origin; For that we have the parallel FIR part. # Remove nonzeros p = p[p.nonzero()] # making the filter stable by flipping the poles into the unit circle for k in range(p.size): if abs(p[k]) > 1: p[k] = 1.0/np.conj(p[k]) # Order it to complex pole pairs + real ones afterwards p = np.sort_complex(p) # in order to have second-order sections only (i.e., no first order) pnum = len(p) # number of poles ppnum = 2 * np.floor(pnum/2) # the even part of pnum ODD = 0 #if pnum is odd if pnum > ppnum: ODD = 1 OUTL = len(out) INL = len(input) # making input the same length as the output if INL > OUTL: input = input[:OUTL] if INL < OUTL: input = np.hstack([input, np.zeros(OUTL - INL, dtype=np.float64)]) L = OUTL # Allocate memory M = np.zeros((input.size, p.size + NFIR), dtype=np.float64) # constructing the modeling signal matrix for k in range(0, int(ppnum), 2): #second-order sections #impluse response of the two-pole filter resp = sig.lfilter(np.array([1]), np.poly(p[k:k+2]), input) M[:,k] = resp #the response delayed by one sample M[:,k+1] = np.hstack((0., resp[:L-1])) # if the number of poles is odd, we have a first-order section if ODD: resp = sig.lfilter(np.array([1]), np.poly(p[-1]),input) M[:,pnum-1] = resp # parallel FIR part for k in range(0, NFIR): M[:,pnum+k] = np.hstack([np.zeros(k, dtype=np.float64), input[:L-k+1]]) y = out # Looking for min(||y-M*par||) as a function of par: # least squares solution by equation solving mconj = M.conj().T A = np.dot(mconj, M) b = np.dot(mconj, y) par = np.linalg.solve(A, b) #print (np.dot(A, par) == b).all() # Allocate memory size = int(np.ceil(ppnum/2)) Am = np.zeros((3, size), dtype=np.float64) Bm = np.zeros((2, size), dtype=np.float64) # constructing the Bm and Am matrices for k in range(0, size): Am[:,k] = np.poly(p[2*k:2*k+2]) Bm[:,k] = np.hstack(par[2*k:2*k+2]) # we extend the first-order section to a second-order one by adding zero coefficients if ODD: Am = np.append(Am, np.vstack(np.hstack([np.poly(p[pnum]),0.])), 1) Bm = np.append(Bm, np.vstack([par[pnum], 0.]), 1) FIR = [] # constructing the FIR part if NFIR > 0: FIR = np.hstack(par[pnum:pnum+NFIR]) return Bm, Am, FIR
import numpy as np np.sort_complex([5, 3, 6, 2, 1]) np.sort_complex([1 + 2j, 2 - 1j, 3 - 2j, 3 - 3j, 3 + 5j])
def calculate_singularities(mc, input_source=None, output_port=None, MNA=None, x0=None, shift=0, outfile=None, verbose=0): """Calculate poles and zeros. By default, only poles are calculated, as they need no information other than the circuit description. To activate zeros calculation, it is necessary: * to specify an input source (``input_source``), * to specify an output port (``output_port``). **Parameters:** mc : circuit instance The circuit to be analyzed. input_source : string or element, optional If zeros are to be calculated, set this to the input surce. output_port : external node (ref. to gnd) or tuple of external nodes, opt If zeros are to be calculated, set this to the output nodes. MNA : ndarray, optional The Modified Nodal Analysis matrix, if available. In case the circuit is non-linear, MNA should include the contributes of the non-linear elements (ie the Jacobian :math:`J`). x0 : ndarray or op_solution, optional The linearization point. Only needed for non-linear circuits. shift : float, optional Shift frequency at which the algorithm should be run. outfile : str or None, optional The data filename. verbose : int, optional Verbosity level, from 0 (silent, default) to 6 (debug). **Returns:** pz_sol : pz_solution instance The PZ solution """ calc_zeros = (input_source is not None) and (output_port is not None) if calc_zeros: if type(input_source) not in py3compat.string_types: input_source = input_source.part_id if type(output_port) in py3compat.string_types: output_port = plotting._split_netlist_label(output_port)[0] output_port = [o[1:] for o in output_port] output_port = [o.lower() for o in output_port] if len(output_port) == 1: # we refer to the ground implicitely output_port += ['0'] if np.isscalar(output_port): output_port = (output_port, mc.gnd) if (type(output_port) == tuple or type(output_port) == list) \ and type(output_port[0]) in py3compat.string_types: output_port = [mc.ext_node_to_int(o) for o in output_port] we_got_source = False for e in mc: if e.part_id == input_source: we_got_source = True break if not we_got_source: raise ValueError('Source %s not found in circuit.' % input_source) RIIN = [] ROUT = [] if MNA is None: MNA, N = dc_analysis.generate_mna_and_N(mc) if mc.is_nonlinear(): # setup x0 if x0 is None: printing.print_warning("PZ: No linearization point provided. Using x0 = 0.") x0 = np.zeros((MNA.shape[0] - 1, 1)) else: if isinstance(x0, results.op_solution): x0 = x0.asarray() # else # hopefully x0 is an ndarray! printing.print_info_line(("Using the supplied op as " + "linearization point.", 5), verbose) J, _ = dc_analysis.build_J_and_Tx(x0, MNA.shape[0]-1, mc, time=0., sparse=False) MNA[1:, 1:] += J D = transient.generate_D(mc, MNA[1:, 1:].shape) MNAinv = np.linalg.inv(MNA[1:, 1:] + shift*D[1:, 1:]) nodes_m1 = mc.get_nodes_number() - 1 vde1 = -1 MC = np.zeros((MNA.shape[0] - 1, 1)) TCM = None dei_source = 0 for e1 in mc: if circuit.is_elem_voltage_defined(e1): vde1 += 1 if isinstance(e1, components.Capacitor): MC[e1.n1 - 1, 0] += 1. if e1.n1 > 0 else 0. MC[e1.n2 - 1, 0] -= 1. if e1.n2 > 0 else 0. elif isinstance(e1, components.Inductor): MC[nodes_m1 + vde1] += -1. elif calc_zeros and e1.part_id == input_source: if isinstance(e1, components.sources.VSource): MC[nodes_m1 + vde1] += -1. elif isinstance(e1, components.sources.ISource): MC[e1.n1 - 1, 0] += 1. if e1.n1 > 0 else 0. MC[e1.n2 - 1, 0] -= 1. if e1.n2 > 0 else 0. else: raise Exception("Unknown input source type %s" % input_source) else: continue TV = -1. * np.dot(MNAinv, MC) dei_victim = 0 vde2 = -1 for e2 in mc: if circuit.is_elem_voltage_defined(e2): vde2 += 1 if isinstance(e2, components.Capacitor): v = 0 if e2.n1: v += TV[e2.n1 - 1, 0] if e2.n2: v -= TV[e2.n2 - 1, 0] elif isinstance(e2, components.Inductor): v = TV[nodes_m1 + vde2, 0] else: continue if calc_zeros and e1.part_id == input_source: RIIN += [v] else: if not dei_source: TCM = _enlarge_matrix(TCM) TCM[dei_victim, dei_source] = v*e1.value dei_victim += 1 if calc_zeros and e1.part_id == input_source: ROUTIN = 0 o1, o2 = output_port if o1: ROUTIN += TV[o1 - 1, 0] if o2: ROUTIN -= TV[o2 - 1, 0] else: dei_source += 1 # reset, get ready to restart MC[:, :] = 0. if TCM is not None: if np.linalg.det(TCM): poles = 1./(2.*np.pi)*(1./np.linalg.eigvals(TCM) + shift) else: return calculate_singularities(mc, input_source, output_port, MNA=MNA, outfile=outfile, shift=shift+np.abs(1+np.random.uniform())*1e3) else: poles = [] if calc_zeros and TCM is not None: # re-loop, get the ROUT elements vde1 = -1 MC = np.zeros((MNA.shape[0] - 1, 1)) ROUT = [] for e1 in mc: if circuit.is_elem_voltage_defined(e1): vde1 += 1 if isinstance(e1, components.Capacitor): MC[e1.n1 - 1, 0] += 1. if e1.n1 > 0 else 0. MC[e1.n2 - 1, 0] -= 1. if e1.n2 > 0 else 0. elif isinstance(e1, components.Inductor): MC[nodes_m1 + vde1, 0] += -1. else: continue TV = -1.*np.dot(MNAinv, MC) v = 0 o1, o2 = output_port if o1: v += TV[o1 - 1, 0] if o2: v -= TV[o2 - 1, 0] ROUT += [v*e1.value] # reset, get ready to restart MC[:, :] = 0. # Reshape the matrices and evaluate the zero correction. RIIN = np.array(RIIN).reshape((-1, 1)) RIIN = np.tile(RIIN, (1, RIIN.shape[0])) ROUT = np.diag(np.atleast_1d(np.array(ROUT))) if ROUT.any(): try: if not np.all(ROUTIN) or not np.isfinite(ROUTIN): # immediate catch raise ValueError("ROUT-IN is either Inf, NaN or null") ZTCM = TCM - np.dot(RIIN, ROUT)/ROUTIN if not (np.isfinite(ZTCM).all()): raise ValueError("Array contains infs, NaNs or both") # immediate catch eigvals = np.linalg.eigvals(ZTCM) if not np.all(eigvals) or not np.isfinite(eigvals).all(): # immediate catch raise ValueError("ZTCM eigenvalues contain either Inf, NaN or null values") zeros = 1./(2.*np.pi)*(1./np.linalg.eigvals(ZTCM) + shift) except ValueError: return calculate_singularities(mc, input_source, output_port, MNA=MNA, outfile=outfile, shift=shift+np.abs(np.random.uniform()+1)*1e3) elif shift < 1e12: return calculate_singularities(mc, input_source, output_port, MNA=MNA, outfile=outfile, shift=shift*np.abs(np.random.uniform()+1)*10) else: zeros = [] else: zeros = [] poles = np.array([a for a in poles if np.abs(a) < options.pz_max], dtype=np.complex_) zeros = np.array([a for a in zeros if np.abs(a) < options.pz_max], dtype=np.complex_) poles = np.sort_complex(poles) zeros = np.sort_complex(zeros) res = results.pz_solution(mc, poles, zeros, outfile) return res
def datestr2num(s): return datetime.datetime.strptime(s,"%d-%m-%Y").toordinal() dates,closes = np.loadtxt('AAPL.csv',delimiter=',',usecols=(1,6),\ converters={1:datestr2num},unpack=True) indices =np.lexsort((dates,closes)) print "Indices",indices print ["%s %s" % (datetime.date.fromordinal(int(dates[i])),closes[i]) for i in indices] print u"复数" #设置随机种子 np.random.seed(42) complex_numbers = np.random.random(5) + 1j*np.random.random(5) print "Complex numbers\n",complex_numbers print "Sorted\n",np.sort_complex(complex_numbers) print u"搜索" #argmax返回数组中最大值对应的下标 a= np.array([2,4,8]) print "argmax",np.argmax(a) #nanargmax提供相同功能,但忽略NaN值 #argmin和nanargmin功能类似,只是换成最小值 #argwhere根据条件搜索非零元素,并分组返回对应下标 #searchsorted可以为指定的插入值寻找维持数组排序的索引位置 #这个位置可以保持数组有序性 a =np.arange(5) indices = np.searchsorted(a,[-2,7]) print "Indices",indices print "The full array", np.insert(a,indices,[-2,7]) print u"抽取元素"
def pair_complex_numbers(a, tol=1e-9, realness_tol=1e-9, positives_first=False, reals_first=True): """ Given an array-like somearray, it first tests and clears out small imaginary parts via `numpy.real_if_close`. Then pairs complex numbers together as consecutive entries. A real array is returned as is. Parameters ---------- a : array_like Array like object needs to be paired tol: float The sensitivity threshold for the real and complex parts to be assumed as equal. realness_tol: float The sensitivity threshold for the complex parts to be assumed as zero. positives_first: bool The boolean that defines whether the positive complex part should come first for the conjugate pairs reals_first: bool The boolean that defines whether the real numbers are at the beginning or the end of the resulting array. Returns ------- paired_array : ndarray The resulting paired array """ try: array_r_j = np.array(a, dtype='complex').flatten() except: raise ValueError('Something in the argument array prevents me to ' 'convert the entries to complex numbers.') # is there anything to pair? if array_r_j.size == 0: return np.array([], dtype='complex') # is the array 1D or more? if array_r_j.ndim > 1 and np.min(array_r_j.shape) > 1: raise ValueError('Currently, I can\'t deal with matrices, so I ' 'need 1D arrays.') # A shortcut for splitting a complex array into real and imag parts def return_imre(arr): return np.real(arr), np.imag(arr) # a close to realness function that operates element-wise real_if_close_array = np.vectorize( lambda x: np.real_if_close(x, realness_tol), otypes=[np.complex_], doc='Elementwise numpy.real_if_close') array_r_j = real_if_close_array(array_r_j) array_r, array_j = return_imre(array_r_j) # are there any complex numbers to begin with or all reals? # if not kick the argument back as a real array imagness = np.abs(array_j) >= realness_tol # perform the imaginary entry separation once array_j_ent = array_r_j[imagness] num_j_ent = array_j_ent.size if num_j_ent == 0: # If no complex entries exist sort and return unstable first return np.sort(array_r) elif num_j_ent % 2 != 0: # Check to make sure there are even number of complex numbers # Otherwise stop with "odd number --> no pair" error. raise ValueError('There are odd number of complex numbers to ' 'be paired!') else: # Still doesn't distinguish whether they are pairable or not. sorted_array_r_j = np.sort_complex(array_j_ent) sorted_array_r, sorted_array_j = return_imre(sorted_array_r_j) # Since the entries are now sorted and appear as pairs, # when summed with the next element the result should # be very small if any(np.abs(sorted_array_r[:-1:2] - sorted_array_r[1::2]) > tol): # if any difference is bigger than the tolerance raise ValueError('Pairing failed for the real parts.') # Now we have sorted the real parts and they appear in pairs. # Next, we have to get rid of the repeated imaginary, if any, # parts in the --... , ++... pattern due to sorting. Note # that the non-repeated imaginary parts now have the pattern # -,+,-,+,-,... and so on. So we can check whether sign is # not alternating for the existence of the repeatedness. def repeat_sign_test(myarr, mylen): # Since we separated the zero imaginary parts now any sign # info is either -1 or 1. Hence we can test whether -1,1 # pattern is present. Otherwise we count how many -1s occured # double it for the repeated region. Then repeat until we # we exhaust the array with a generator. x = 0 myarr_sign = np.sign(myarr).astype(int) while x < mylen: if np.array_equal(myarr_sign[x:x+2], [-1, 1]): x += 2 elif np.array_equal(myarr_sign[x:x+2], [1, -1]): myarr[x:x+2] *= -1 x += 2 else: still_neg = True xl = x+2 while still_neg: if myarr_sign[xl] == 1: still_neg = False else: xl += 1 yield x, xl - x x += 2*(xl - x) for ind, l in repeat_sign_test(sorted_array_j, num_j_ent): indices = np.dstack( (range(ind, ind+l), range(ind+2*l-1, ind+l-1, -1)) )[0].reshape(1, -1) sorted_array_j[ind:ind+2*l] = sorted_array_j[indices] if any(np.abs(sorted_array_j[:-1:2] + sorted_array_j[1::2]) > tol): # if any difference is bigger than the tolerance raise ValueError('Pairing failed for the complex parts.') # Finally we have a properly sorted pairs of complex numbers # We can now combine the real and complex parts depending on # the choice of positives_first keyword argument # Force entries to be the same for each of the pairs. sorted_array_j = np.repeat(sorted_array_j[::2], 2) paired_cmplx_part = np.repeat(sorted_array_r[::2], 2).astype(complex) if positives_first: sorted_array_j[::2] *= -1 else: sorted_array_j[1::2] *= -1 paired_cmplx_part += sorted_array_j*1j if reals_first: return np.r_[np.sort(array_r_j[~imagness]), paired_cmplx_part] else: return np.r_[paired_cmplx_part, np.sort(array_r_j[~imagness])]
def pretty_lti(arg): """Given the lti object ``arg`` return a *pretty* representation.""" z, p, k = _get_zpk(arg) z = np.atleast_1d(z) p = np.atleast_1d(p) z = np.round(np.real_if_close(z), 4) p = np.round(np.real_if_close(p), 4) k = np.round(np.real_if_close(k), 4) signs = {1:'+', -1:'-'} if not len(z) and not len(p): return "%g" % k ppstr = ["", "", ""] if np.allclose(k, 0., atol=1e-5): return "0" if k != 1: if np.isreal(k): ppstr[1] = "%g " % k else: # quadrature modulators support ppstr[1] += "(%g %s %gj) " % (np.real(k), signs[np.sign(np.imag(k))], np.abs(np.imag(k))) for i, s in zip((0, 2), (z, p)): rz = None m = 1 try: sorted_singularities = cplxpair(s) quadrature = False except ValueError: # quadrature modulator sorted_singularities = np.sort_complex(s) quadrature = True for zindex, zi in enumerate(sorted_singularities): zi = np.round(np.real_if_close(zi), 4) if np.isreal(zi) or quadrature: if len(sorted_singularities) > zindex + 1 and \ sorted_singularities[zindex + 1] == zi: m += 1 continue if zi == 0.: ppstr[i] += "z" elif np.isreal(zi): ppstr[i] += "(z %s %g)" % (signs[np.sign(-zi)], np.abs(zi)) else: ppstr[i] += "(z %s %g %s %gj)" % (signs[np.sign(np.real(-zi))], np.abs(np.real(zi)), signs[np.sign(np.imag(-zi))], np.abs(np.imag(zi))) if m == 1: ppstr[i] += " " else: ppstr[i] += "^%d " % m m = 1 else: if len(sorted_singularities) > zindex + 2 and \ sorted_singularities[zindex + 2] == zi: m += .5 continue if rz is None: rz = zi continue ppstr[i] += "(z^2 %s %gz %s %g)" % \ (signs[np.sign(np.real_if_close(np.round(-rz - zi, 3)))], np.abs(np.real_if_close(np.round(-rz - zi, 3))), signs[np.sign(np.real_if_close(np.round(rz * zi, 4)))], np.abs(np.real_if_close(np.round(rz * zi, 4)))) if m == 1: ppstr[i] += " " else: ppstr[i] += "^%d " % m rz = None m = 1 ppstr[i] = ppstr[i][:-1] if len(ppstr[i]) else "1" if ppstr[2] == '1': return ppstr[1] + ppstr[0] else: if ppstr[0] == '1' and len(ppstr[1]) and float(ppstr[1]) != 1.: ppstr[0] = ppstr[1][:-1] ppstr[1] = "" space_pad_ln = len(ppstr[1]) fraction_line = "-" * (max(len(ppstr[0]), len(ppstr[2])) + 2) ppstr[1] += fraction_line ppstr[0] = " "*space_pad_ln + ppstr[0].center(len(fraction_line)) ppstr[2] = " "*space_pad_ln + ppstr[2].center(len(fraction_line)) return "\n".join(ppstr)