def test_solve_undetermined_coeffs(): assert solve_undetermined_coeffs(a*x**2 + b*x**2 + b*x + 2*c*x + c + 1, [a, b, c], x) == \ {a: -2, b: 2, c: -1} # Test that rational functions work assert solve_undetermined_coeffs(a/x + b/(x + 1) - (2*x + 1)/(x**2 + x), [a, b], x) == \ {a: 1, b: 1} # Test cancellation in rational functions assert solve_undetermined_coeffs(((c + 1)*a*x**2 + (c + 1)*b*x**2 + (c + 1)*b*x + (c + 1)*2*c*x + (c + 1)**2)/(c + 1), [a, b, c], x) == \ {a: -2, b: 2, c: -1}
def test_solve_undetermined_coeffs(): assert solve_undetermined_coeffs(a*x**2 + b*x**2 + b*x + 2*c*x + c + 1, [a, b, c], x) == \ {a: -2, b: 2, c: -1} # Test that rational functions work assert solve_undetermined_coeffs(a/x + b/(x + 1) - (2*x + 1)/(x**2 + x), [a, b], x) == \ {a: 1, b: 1} # Test cancellation in rational functions assert solve_undetermined_coeffs(((c + 1)*a*x**2 + (c + 1)*b*x**2 + (c + 1)*b*x + (c + 1)*2*c*x + (c + 1)**2)/(c + 1), [a, b, c], x) == \ {a: -2, b: 2, c: -1}
def synthesize(polynomial, filter_implementation, filter_type, parameters): """ Implements the filter given by polynomial, with the filter_implementation and filter_type given. Assumptions: - Low-pass and high-pass filters set the resistor and find the capacitor. - Sallen-key LP filter sets R1 = R2 = Rr and C1 and C2 can vary. - Sallen-key HP filter sets C1 = C2 = Cc and R1 and R2 can vary. - MFB LP filter sets C1 = C2 = Cc and R1, R2, R3 can vary. - MFB HP filter sets R1 = R2 = R3 = Rr and C1, C2 can vary. """ s = sym.var('s') if filter_implementation == '1' and filter_type == 'lp': C = sym.var('C') targets = [C] R = parameters['R'] tf = rc_lowpass(s, R, C) if filter_implementation == '1' and filter_type == 'hp': C = sym.var('C') targets = [C] R = parameters['R'] tf = rc_highpass(s, R, C) if filter_implementation == 'sk' and filter_type == 'lp': C1, C2, s = sym.var('C1 C2 s') targets = [C1, C2] # The values we want to find Rr = parameters['Rr'] tf = sk_lowpass(s, Rr, Rr, C1, C2) if filter_implementation == 'sk' and filter_type == 'hp': R1, R2, s = sym.var('R1 R2 s') targets = [R1, R2] # The values we want to find Cc = parameters['Cc'] tf = sk_highpass(s, R1, R2, Cc, Cc) print(tf) print("I need to solve ", tf-polynomial) print("My variables are ", targets) result = solvers.solve_undetermined_coeffs(tf - polynomial, targets, 's') return result
def rsolve_poly(coeffs, f, n, **hints): """Given linear recurrence operator L of order 'k' with polynomial coefficients and inhomogeneous equation Ly = f, where 'f' is a polynomial, we seek for all polynomial solutions over field K of characteristic zero. The algorithm performs two basic steps: (1) Compute degree N of the general polynomial solution. (2) Find all polynomials of degree N or less of Ly = f. There are two methods for computing the polynomial solutions. If the degree bound is relatively small, i.e. it's smaller than or equal to the order of the recurrence, then naive method of undetermined coefficients is being used. This gives system of algebraic equations with N+1 unknowns. In the other case, the algorithm performs transformation of the initial equation to an equivalent one, for which the system of algebraic equations has only 'r' indeterminates. This method is quite sophisticated (in comparison with the naive one) and was invented together by Abramov, Bronstein and Petkovsek. It is possible to generalize the algorithm implemented here to the case of linear q-difference and differential equations. Lets say that we would like to compute m-th Bernoulli polynomial up to a constant. For this we can use b(n+1) - b(n) == m*n**(m-1) recurrence, which has solution b(n) = B_m + C. For example: >>> from sympy import Symbol, rsolve_poly >>> n = Symbol('n', integer=True) >>> rsolve_poly([-1, 1], 4*n**3, n) C0 + n**2 - 2*n**3 + n**4 For more information on implemented algorithms refer to: [1] S. A. Abramov, M. Bronstein and M. Petkovsek, On polynomial solutions of linear operator equations, in: T. Levelt, ed., Proc. ISSAC '95, ACM Press, New York, 1995, 290-296. [2] M. Petkovsek, Hypergeometric solutions of linear recurrences with polynomial coefficients, J. Symbolic Computation, 14 (1992), 243-264. [3] M. Petkovsek, H. S. Wilf, D. Zeilberger, A = B, 1996. """ f = sympify(f) if not f.is_polynomial(n): return None homogeneous = f.is_zero r = len(coeffs)-1 coeffs = [ Poly(coeff, n) for coeff in coeffs ] polys = [ Poly(0, n) ] * (r+1) terms = [ (S.Zero, S.NegativeInfinity) ] *(r+1) for i in xrange(0, r+1): for j in xrange(i, r+1): polys[i] += coeffs[j]*Binomial(j, i) if not polys[i].is_zero: (exp,), coeff = polys[i].LT() terms[i] = (coeff, exp) d = b = terms[0][1] for i in xrange(1, r+1): if terms[i][1] > d: d = terms[i][1] if terms[i][1] - i > b: b = terms[i][1] - i d, b = int(d), int(b) x = Symbol('x', dummy=True) degree_poly = S.Zero for i in xrange(0, r+1): if terms[i][1] - i == b: degree_poly += terms[i][0]*FallingFactorial(x, i) nni_roots = roots(degree_poly, x, filter='Z', predicate=lambda r: r >= 0).keys() if nni_roots: N = [max(nni_roots)] else: N = [] if homogeneous: N += [-b-1] else: N += [f.as_poly(n).degree() - b, -b-1] N = int(max(N)) if N < 0: if homogeneous: if hints.get('symbols', False): return (S.Zero, []) else: return S.Zero else: return None if N <= r: C = [] y = E = S.Zero for i in xrange(0, N+1): C.append(Symbol('C'+str(i))) y += C[i] * n**i for i in xrange(0, r+1): E += coeffs[i].as_basic()*y.subs(n, n+i) solutions = solve_undetermined_coeffs(E-f, C, n) if solutions is not None: C = [ c for c in C if (c not in solutions) ] result = y.subs(solutions) else: return None # TBD else: A = r U = N+A+b+1 nni_roots = roots(polys[r], filter='Z', predicate=lambda r: r >= 0).keys() if nni_roots != []: a = max(nni_roots) + 1 else: a = S.Zero def zero_vector(k): return [S.Zero] * k def one_vector(k): return [S.One] * k def delta(p, k): B = S.One D = p.subs(n, a+k) for i in xrange(1, k+1): B *= -Rational(k-i+1, i) D += B * p.subs(n, a+k-i) return D alpha = {} for i in xrange(-A, d+1): I = one_vector(d+1) for k in xrange(1, d+1): I[k] = I[k-1] * (x+i-k+1)/k alpha[i] = S.Zero for j in xrange(0, A+1): for k in xrange(0, d+1): B = Binomial(k, i+j) D = delta(polys[j].as_basic(), k) alpha[i] += I[k]*B*D V = Matrix(U, A, lambda i, j: int(i == j)) if homogeneous: for i in xrange(A, U): v = zero_vector(A) for k in xrange(1, A+b+1): if i - k < 0: break B = alpha[k-A].subs(x, i-k) for j in xrange(0, A): v[j] += B * V[i-k, j] denom = alpha[-A].subs(x, i) for j in xrange(0, A): V[i, j] = -v[j] / denom else: G = zero_vector(U) for i in xrange(A, U): v = zero_vector(A) g = S.Zero for k in xrange(1, A+b+1): if i - k < 0: break B = alpha[k-A].subs(x, i-k) for j in xrange(0, A): v[j] += B * V[i-k, j] g += B * G[i-k] denom = alpha[-A].subs(x, i) for j in xrange(0, A): V[i, j] = -v[j] / denom G[i] = (delta(f, i-A) - g) / denom P, Q = one_vector(U), zero_vector(A) for i in xrange(1, U): P[i] = (P[i-1] * (n-a-i+1)/i).expand() for i in xrange(0, A): Q[i] = Add(*[ (v*p).expand() for v, p in zip(V[:,i], P) ]) if not homogeneous: h = Add(*[ (g*p).expand() for g, p in zip(G, P) ]) C = [ Symbol('C'+str(i)) for i in xrange(0, A) ] g = lambda i: Add(*[ c*delta(q, i) for c, q in zip(C, Q) ]) if homogeneous: E = [ g(i) for i in xrange(N+1, U) ] else: E = [ g(i) + delta(h, i) for i in xrange(N+1, U) ] if E != []: solutions = solve(E, *C) if solutions is None: if homogeneous: if hints.get('symbols', False): return (S.Zero, []) else: return S.Zero else: return None else: solutions = {} if homogeneous: result = S.Zero else: result = h for c, q in zip(C, Q): if c in solutions: s = solutions[c]*q C.remove(c) else: s = c*q result += s.expand() if hints.get('symbols', False): return (result, C) else: return result