def main(): # sequence = "DdDddUUdDD" # lower_bound = 10 ** 6 sequence = "UDDDUdddDDUDDddDdDddDDUDDdUUDd" lower_bound = 10**15 p = x for ch in reversed(sequence): if ch == "D": p = 3 * p elif ch == "U": p = (3 * p - 2) / 4 elif ch == "d": p = (3 * p + 1) / 2 else: raise NotImplementedError p = Poly(p) print(p) a, b = p.all_coeffs() n_a, d_a = sympy.fraction(a) n_b, d_b = sympy.fraction(b) assert d_a == d_b d = d_a r = (-n_b) * pow(n_a, -1, d) % d assert (r * n_a + n_b) % d == 0 n_a %= d n_b %= d minimal = int(a * r + b) step = int(a * d) offset = math.ceil((lower_bound + 1 - minimal) / step) print(f"{minimal} + {step} * {offset} = {minimal + step * offset}")
def _sqrt_symbolic_denest(a, b, r): """Given an expression, sqrt(a + b*sqrt(b)), return the denested expression or None. Algorithm: If r = ra + rb*sqrt(rr), try replacing sqrt(rr) in ``a`` with (y**2 - ra)/rb, and if the result is a quadratic, ca*y**2 + cb*y + cc, and (cb + b)**2 - 4*ca*cc is 0, then sqrt(a + b*sqrt(r)) can be rewritten as sqrt(ca*(sqrt(r) + (cb + b)/(2*ca))**2). Examples ======== >>> from sympy.simplify.sqrtdenest import _sqrt_symbolic_denest, sqrtdenest >>> from sympy import sqrt, Symbol >>> from sympy.abc import x >>> a, b, r = 16 - 2*sqrt(29), 2, -10*sqrt(29) + 55 >>> _sqrt_symbolic_denest(a, b, r) sqrt(11 - 2*sqrt(29)) + sqrt(5) If the expression is numeric, it will be simplified: >>> w = sqrt(sqrt(sqrt(3) + 1) + 1) + 1 + sqrt(2) >>> sqrtdenest(sqrt((w**2).expand())) 1 + sqrt(2) + sqrt(1 + sqrt(1 + sqrt(3))) Otherwise, it will only be simplified if assumptions allow: >>> w = w.subs(sqrt(3), sqrt(x + 3)) >>> sqrtdenest(sqrt((w**2).expand())) sqrt((sqrt(sqrt(sqrt(x + 3) + 1) + 1) + 1 + sqrt(2))**2) Notice that the argument of the sqrt is a square. If x is made positive then the sqrt of the square is resolved: >>> _.subs(x, Symbol('x', positive=True)) sqrt(sqrt(sqrt(x + 3) + 1) + 1) + 1 + sqrt(2) """ a, b, r = map(sympify, (a, b, r)) rval = _sqrt_match(r) if not rval: return None ra, rb, rr = rval if rb: y = Dummy('y', positive=True) try: newa = Poly(a.subs(sqrt(rr), (y**2 - ra) / rb), y) except PolynomialError: return None if newa.degree() == 2: ca, cb, cc = newa.all_coeffs() cb += b if _mexpand(cb**2 - 4 * ca * cc).equals(0): z = sqrt(ca * (sqrt(r) + cb / (2 * ca))**2) if z.is_number: z = _mexpand(Mul._from_args(z.as_content_primitive())) return z
def _sqrt_symbolic_denest(a, b, r): """Given an expression, sqrt(a + b*sqrt(b)), return the denested expression or None. Algorithm: If r = ra + rb*sqrt(rr), try replacing sqrt(rr) in ``a`` with (y**2 - ra)/rb, and if the result is a quadratic, ca*y**2 + cb*y + cc, and (cb + b)**2 - 4*ca*cc is 0, then sqrt(a + b*sqrt(r)) can be rewritten as sqrt(ca*(sqrt(r) + (cb + b)/(2*ca))**2). Examples ======== >>> from sympy.simplify.sqrtdenest import _sqrt_symbolic_denest, sqrtdenest >>> from sympy import sqrt, Symbol >>> from sympy.abc import x >>> a, b, r = 16 - 2*sqrt(29), 2, -10*sqrt(29) + 55 >>> _sqrt_symbolic_denest(a, b, r) sqrt(-2*sqrt(29) + 11) + sqrt(5) If the expression is numeric, it will be simplified: >>> w = sqrt(sqrt(sqrt(3) + 1) + 1) + 1 + sqrt(2) >>> sqrtdenest(sqrt((w**2).expand())) 1 + sqrt(2) + sqrt(1 + sqrt(1 + sqrt(3))) Otherwise, it will only be simplified if assumptions allow: >>> w = w.subs(sqrt(3), sqrt(x + 3)) >>> sqrtdenest(sqrt((w**2).expand())) sqrt((sqrt(sqrt(sqrt(x + 3) + 1) + 1) + 1 + sqrt(2))**2) Notice that the argument of the sqrt is a square. If x is made positive then the sqrt of the square is resolved: >>> _.subs(x, Symbol('x', positive=True)) sqrt(sqrt(sqrt(x + 3) + 1) + 1) + 1 + sqrt(2) """ a, b, r = map(sympify, (a, b, r)) rval = _sqrt_match(r) if not rval: return None ra, rb, rr = rval if rb: y = Dummy('y', positive=True) try: newa = Poly(a.subs(sqrt(rr), (y**2 - ra)/rb), y) except PolynomialError: return None if newa.degree() == 2: ca, cb, cc = newa.all_coeffs() cb += b if _mexpand(cb**2 - 4*ca*cc).equals(0): z = sqrt(ca*(sqrt(r) + cb/(2*ca))**2) if z.is_number: z = _mexpand(Mul._from_args(z.as_content_primitive())) return z
def _valid_expr(expr): """ return coefficients of expr if it is a univariate polynomial with integer coefficients else raise a ValueError. """ if not expr.is_polynomial(): raise ValueError("The expression should be a polynomial") polynomial = Poly(expr) if not polynomial.is_univariate: raise ValueError("The expression should be univariate") if not polynomial.domain == ZZ: raise ValueError("The expression should should have integer coefficients") return polynomial.all_coeffs()
def _solve_inequality(ie, s): """ A hacky replacement for solve, since the latter only works for univariate inequalities. """ from sympy import Poly if not ie.rel_op in ('>', '>=', '<', '<='): raise NotImplementedError expr = ie.lhs - ie.rhs p = Poly(expr, s) if p.degree() != 1: raise NotImplementedError('%s' % ie) a, b = p.all_coeffs() if a.is_positive: return ie.func(s, -b/a) elif a.is_negative: return ie.func(-b/a, s) else: raise NotImplementedError
def _solve_inequality(ie, s): """ A hacky replacement for solve, since the latter only works for univariate inequalities. """ from sympy import Poly if not ie.rel_op in ('>', '>=', '<', '<='): raise NotImplementedError expr = ie.lhs - ie.rhs p = Poly(expr, s) if p.degree() != 1: raise NotImplementedError('%s' % ie) a, b = p.all_coeffs() if a.is_positive: return ie.func(s, -b / a) elif a.is_negative: return ie.func(-b / a, s) else: raise NotImplementedError
def _solve_inequality(ie, s): """ A hacky replacement for solve, since the latter only works for univariate inequalities. """ if not ie.rel_op in (">", ">=", "<", "<="): raise NotImplementedError expr = ie.lhs - ie.rhs try: p = Poly(expr, s) except PolynomialError: raise NotImplementedError if p.degree() != 1: raise NotImplementedError("%s" % ie) a, b = p.all_coeffs() if a.is_positive: return ie.func(s, -b / a) elif a.is_negative: return ie.func(-b / a, s) else: raise NotImplementedError
def _solve_inequality(ie, s): """ A hacky replacement for solve, since the latter only works for univariate inequalities. """ expr = ie.lhs - ie.rhs try: p = Poly(expr, s) if p.degree() != 1: raise NotImplementedError except (PolynomialError, NotImplementedError): try: return reduce_rational_inequalities([[ie]], s) except PolynomialError: return solve_univariate_inequality(ie, s) a, b = p.all_coeffs() if a.is_positive or ie.rel_op in ('!=', '=='): return ie.func(s, -b/a) elif a.is_negative: return ie.reversed.func(s, -b/a) else: raise NotImplementedError
def _solve_inequality(ie, s, assume=True): """ A hacky replacement for solve, since the latter only works for univariate inequalities. """ if not ie.rel_op in ('>', '>=', '<', '<='): raise NotImplementedError expr = ie.lhs - ie.rhs try: p = Poly(expr, s) if p.degree() != 1: raise NotImplementedError except (PolynomialError, NotImplementedError): try: n, d = expr.as_numer_denom() return reduce_rational_inequalities([[ie]], s, assume=assume) except PolynomialError: return solve_univariate_inequality(ie, s, assume=assume) a, b = p.all_coeffs() if a.is_positive: return ie.func(s, -b/a) elif a.is_negative: return ie.func(-b/a, s) else: raise NotImplementedError
def _solve_inequality(ie, s, assume=True): """ A hacky replacement for solve, since the latter only works for univariate inequalities. """ if not ie.rel_op in ('>', '>=', '<', '<='): raise NotImplementedError expr = ie.lhs - ie.rhs try: p = Poly(expr, s) if p.degree() != 1: raise NotImplementedError except (PolynomialError, NotImplementedError): try: n, d = expr.as_numer_denom() return reduce_rational_inequalities([[ie]], s, assume=assume) except PolynomialError: return solve_univariate_inequality(ie, s, assume=assume) a, b = p.all_coeffs() if a.is_positive: return ie.func(s, -b / a) elif a.is_negative: return ie.func(-b / a, s) else: raise NotImplementedError
def _get_const_characteristic_eq_sols(r, func, order): r""" Returns the roots of characteristic equation of constant coefficient linear ODE and list of collectterms which is later on used by simplification to use collect on solution. The parameter `r` is a dict of order:coeff terms, where order is the order of the derivative on each term, and coeff is the coefficient of that derivative. """ x = func.args[0] # First, set up characteristic equation. chareq, symbol = S.Zero, Dummy('x') for i in r.keys(): if type(i) == str or i < 0: pass else: chareq += r[i] * symbol**i chareq = Poly(chareq, symbol) # Can't just call roots because it doesn't return rootof for unsolveable # polynomials. chareqroots = roots(chareq, multiple=True) if len(chareqroots) != order: chareqroots = [rootof(chareq, k) for k in range(chareq.degree())] chareq_is_complex = not all(i.is_real for i in chareq.all_coeffs()) # Create a dict root: multiplicity or charroots charroots = defaultdict(int) for root in chareqroots: charroots[root] += 1 # We need to keep track of terms so we can run collect() at the end. # This is necessary for constantsimp to work properly. collectterms = [] gensols = [] conjugate_roots = [] # used to prevent double-use of conjugate roots # Loop over roots in theorder provided by roots/rootof... for root in chareqroots: # but don't repoeat multiple roots. if root not in charroots: continue multiplicity = charroots.pop(root) for i in range(multiplicity): if chareq_is_complex: gensols.append(x**i * exp(root * x)) collectterms = [(i, root, 0)] + collectterms continue reroot = re(root) imroot = im(root) if imroot.has(atan2) and reroot.has(atan2): # Remove this condition when re and im stop returning # circular atan2 usages. gensols.append(x**i * exp(root * x)) collectterms = [(i, root, 0)] + collectterms else: if root in conjugate_roots: collectterms = [(i, reroot, imroot)] + collectterms continue if imroot == 0: gensols.append(x**i * exp(reroot * x)) collectterms = [(i, reroot, 0)] + collectterms continue conjugate_roots.append(conjugate(root)) gensols.append(x**i * exp(reroot * x) * sin(abs(imroot) * x)) gensols.append(x**i * exp(reroot * x) * cos(imroot * x)) # This ordering is important collectterms = [(i, reroot, imroot)] + collectterms return gensols, collectterms