3

I am using sympy to solve some equations and I am running into a problem. I have this issue with many equations but I will illustrate with an example. I have an equation with multiple variables and I want to solve this equation in terms of all variables but one is excluded. For instance the equation 0 = 2^n*(2-a) - b + 1. Here there are three variables a, b and n. I want to get the values for a and b not in terms of n so the a and b may not contain n.

2^n*(2-a) - b + 1 = 0

# Since we don't want to solve in terms of n we know that (2 - a)
# has to be zero and -b + 1 has to be zero.

2 - a = 0
a = 2

-b + 1 = 0
b = 1

I want sympy to do this. Maybe I'm just not looking at the right documentation but I have found no way to do this. When I use solve and instruct it to solve for symbols a and b sympy returns to me a single solution where a is defined in terms of n and b. I assume this means I am free to choose b and n, However I don't want to fix n to a specific value I want n to still be a variable.

Code:

import sympy

n = sympy.var("n", integer = True)
a = sympy.var("a")
b = sympy.var("b")
f = 2**n*(2-a) - b + 1

solutions = sympy.solve(f, [a,b], dict = True)
# this will return: "[{a: 2**(-n)*(2**(n + 1) - b + 1)}]". 
# A single solution where b and n are free variables.
# However this means I have to choose an n I don't want
# to that I want it to hold for any n.

I really hope someone can help me. I have been searching google for hours now...

  • just to clarify, you want to solve this as if `f` is a polynomial over `2**n` and it is equated to the zero polynomial? – Yakov Dan Jan 02 '19 at 11:02
  • @YakovDan Not entirely. My example equation only has a single `2**n` But more complex equation could in addition to that have other powers like `9^n`. –  Jan 02 '19 at 11:13
  • ok, but still you want to find values for the coefficients that would always hold, regardless of n. So if your equations would have mixed powers like `2^n` and `9^n`, you could view this as a sum of two polynomials, one over `2^n` and the other over `9^n` – Yakov Dan Jan 02 '19 at 11:16
  • @YakovDan Yes true! –  Jan 02 '19 at 12:06

1 Answers1

0

Ok, here's what I came up with. This seems to solve the type of equations you're looking for. I've provided some tests as well. Of course, this code is rough and can be easily caused to fail, so i'd take it more as a starting point than a complete solution

import sympy
n = sympy.Symbol('n')
a = sympy.Symbol('a')
b = sympy.Symbol('b')
c = sympy.Symbol('c')
d = sympy.Symbol('d')
e = sympy.Symbol('e')
f = sympy.sympify(2**n*(2-a) - b + 1)
g = sympy.sympify(2**n*(2-a) -2**(n-1)*(c+5) - b + 1)
h = sympy.sympify(2**n*(2-a) -2**(n-1)*(e-1) +(c-3)*9**n - b + 1)
i = sympy.sympify(2**n*(2-a) -2**(n-1)*(e+4) +(c-3)*9**n - b + 1 + (d+2)*9**(n+2))

def rewrite(expr):
        if expr.is_Add:
            return sympy.Add(*[rewrite(f) for f in expr.args])
        if expr.is_Mul:
            return sympy.Mul(*[rewrite(f) for f in expr.args])
        if expr.is_Pow:
            if expr.args[0].is_Number:
                if expr.args[1].is_Symbol:
                    return expr
                elif expr.args[1].is_Add: 
                    base = expr.args[0]
                    power = sympy.solve(expr.args[1])
                    sym = expr.args[1].free_symbols.pop()
                    return sympy.Mul(sympy.Pow(base,-power[0]), sympy.Pow(base,sym))
                else:
                    return expr

            else:
                return expr
        else:
            return expr




def my_solve(expr):

    if not expr.is_Add:
        return None

    consts_list = []
    equations_list = []
    for arg in expr.args:
        if not sympy.Symbol('n') in arg.free_symbols:
            consts_list.append(arg)
        elif arg.is_Mul:
            coeff_list = []
            for nested_arg in arg.args:
                if not sympy.Symbol('n') in nested_arg.free_symbols:
                    coeff_list.append(nested_arg)
            equations_list.append(sympy.Mul(*coeff_list))

    equations_list.append(sympy.Add(*consts_list))
    results = {}
    for eq in equations_list:
        var_name = eq.free_symbols.pop()
        val = sympy.solve(eq)[0]
        results[var_name] = val



    return results




print(my_solve(rewrite(f)))
print(my_solve(rewrite(g)))
print(my_solve(rewrite(h)))
print(my_solve(rewrite(i)))
Yakov Dan
  • 2,157
  • 15
  • 29