Python -- using regex on a class instance - python
I have a class that was taking in lists of 1's and 0's and performing GF(2) finite field arithmetic operations. It used to work until I tried to make it take the input in polynomial format. As for how the finite arithmetic will be done after fixing the regex issue, I was thinking about overloading the operators.
The actual code in parsePolyToListInput(input) works when outside the class. The problem seems to be in the regex, which errors that it will only take in a string (this makes sense), but does not seem to initialize with self.expr as a parameter (that's a problem). The #staticmethod just before the initialization was an attempt to salvage the unbound error as it the polynomial was passed in, but this is apparently completely wrong. Just to save you time if you decide to look at any of the arithmetic operations, modular inverse does not work (seems to be due to the formatting issue after every iteration of that while loop for division in the function and what the return type is):
import re
class gf2poly:
#binary arithemtic on polynomials
##staticmethod
def __init__(self,expr):
self.expr = expr
#self.expr = [int(i) for i in expr]
self.expr = gf2poly.parsePolyToListInput(self.expr)
def convert(self): #to clarify the input if necessary
convertToString = str(self.expr)
print "expression is %s"%(convertToString)
def id(self): #returns modulus 2 (1,0,0,1,1,....) for input lists
return [int(self.expr[i])%2 for i in range(len(self.expr))]
def listToInt(self): #converts list to integer for later use
result = gf2poly.id(self)
return int(''.join(map(str,result)))
def prepBinary(a,b): #converts to base 2 and orders min and max for use
a = gf2poly.listToInt(a); b = gf2poly.listToInt(b)
bina = int(str(a),2); binb = int(str(b),2)
a = min(bina,binb); b = max(bina,binb);
return a,b
#staticmethod
def outFormat(raw):
raw = str(raw[::-1]); g = [] #reverse binary string for enumeration
[g.append(i) for i,c in enumerate(raw) if c == '1']
processed = "x**"+' + x**'.join(map(str, g[::-1]))
if len(g) == 0: return 0 #return 0 if list empty
return processed #returns result in gf(2) polynomial form
def parsePolyToListInput(poly):
c = [int(i.group(0)) for i in re.finditer(r'\d+', poly)] #re.finditer returns an iterator
#m = max(c)
return [1 if x in c else 0 for x in xrange(max(c), -1, -1)]
#return d
def add(self,other): #accepts 2 lists as parameters
a = gf2poly.listToInt(self); b = gf2poly.listToInt(other)
bina = int(str(a),2); binb = int(str(b),2)
m = bina^binb; z = "{0:b}".format(m)
return z #returns binary string
def subtract(self,other): #basically same as add() but built differently
result = [self.expr[i] ^ other.expr[i] for i in range(len(max(self.expr,other.expr)))]
return int(''.join(map(str,result)))
def multiply(a,b): #a,b are lists like (1,0,1,0,0,1,....)
a,b = gf2poly.prepBinary(a,b)
g = []; bitsa = "{0:b}".format(a)
[g.append((b<<i)*int(bit)) for i,bit in enumerate(bitsa)]
m = reduce(lambda x,y: x^y,g); z = "{0:b}".format(m)
return z #returns product of 2 polynomials in gf2
def divide(a,b): #a,b are lists like (1,0,1,0,0,1,....)
a,b = gf2poly.prepBinary(a,b)
bitsa = "{0:b}".format(a); bitsb = "{0:b}".format(b)
difflen = len(str(bitsb)) - len(str(bitsa))
c = a<<difflen; q=0
while difflen >= 0 and b != 0: #a is divisor, b is dividend, b/a
q+=1<<difflen; b = b^c # b/a because of sorting in prep
lendif = abs(len(str(bin(b))) - len(str(bin(c))))
c = c>>lendif; difflen -= lendif
r = "{0:b}".format(b); q = "{0:b}".format(q)
return r,q #returns r remainder and q quotient in gf2 division
def remainder(a,b): #separate function for clarity when calling
r = gf2poly.divide(a,b)[0]; r = int(str(r),2)
return "{0:b}".format(r)
def quotient(a,b): #separate function for clarity when calling
q = gf2poly.divide(a,b)[1]; q = int(str(q),2)
return "{0:b}".format(q)
def extendedEuclideanGF2(a,b): # extended euclidean. a,b are GF(2) polynomials in list form
inita,initb=a,b; x,prevx=0,1; y,prevy = 1,0
while sum(b) != 0:
q = gf2poly.quotient(a,b);
q = list(q); q = [int(x) for x in q]
#q = list(q);
#q = tuple([int(i) for i in q])
q = gf2poly(q)
a,b = b,gf2poly.remainder(a,b);
#a = map(list, a);
#b = [list(x) for x in a];
#a = [int(x) for x in a]; b = [int(x) for x in b];
b = list(b); b = [int(x) for x in b]
#b = list(b);
#b = tuple([int(i) for i in b])
b = gf2poly(b)
#x,prevx = (prevx-q*x, x);
#y,prevy=(prevy-q*y, y)
print "types ",type(q),type(a),type(b)
#q=a//b; a,b = b,a%b; x,prevx = (prevx-q*x, x); y,prevy=(prevy-q*y, y)
#print("%d * %d + %d * %d = %d" % (inita,prevx,initb,prevy,a))
return a,prevx,prevy # returns gcd of (a,b), and factors s and t
def modular_inverse(a,mod): # where a,mod are GF(2) polynomials in list form
gcd,s,t = gf2poly.extendedEuclideanGF2(a,mod); mi = gf2poly.remainder(s,mod)
#gcd,s,t = ext_euc_alg_i(a,mod); mi = s%mod
if gcd !=1: return False
#print ("%d * %d mod %d = 1"%(a,mi,mod))
return mi # returns modular inverse of a,mod
I usually test it with this input:
a = x**14 + x**1 + x**0
p1 = gf2poly(a)
b = x**6 + x**2 + x**1
p2 = gf2poly(b)
The first thing you might notice about my code is that it's not very good. There are 2 reasons for that:
1) I wrote it so that the 1st version could do work in the finite field GF(2), and output in polynomial format. Then the next versions were supposed to be able to take polynomial inputs, and also perform the crucial 'modular inverse' function which is not working as planned (this means it's actually not working at all).
2) I'm teaching myself Python (I'm actually teaching myself programming overall), so any constructive criticism from pro Python programmers is welcome as I'm trying to break myself of beginner habits as quickly as possible.
EDIT:
Maybe some more of the code I've been testing with will help clarify what works and what doesn't:
t1 = [1,1,1]; t2 = [1,0,1]; t3 = [1,1]; t4 = [1, 0, 1, 1, 1, 1, 1]
t5 = [1,1,1,1]; t6 = [1,1,0,1]; t7 = [1,0,1,1,0]
f1 = gf2poly(t1); f2 = gf2poly(t2); f3 = gf2poly(t3); f4 = gf2poly(t4)
f5 = gf2poly(t5);f6 = gf2poly(t6);f7 = gf2poly(t7)
##print "subtract: ",a.subtract(b)
##print "add: ",a.add(b)
##print "multiply: ",gf2poly.multiply(f1,f3)
##print "multiply: ",gf2poly.multiply(f1,f2)
##print "multiply: ",gf2poly.multiply(f3,f4)
##print "degree a: ",a.degree()
##print "degree c: ",c.degree()
##print "divide: ",gf2poly.divide(f1,b)
##print "divide: ",gf2poly.divide(f4,a)
##print "divide: ",gf2poly.divide(f4,f2)
##print "divide: ",gf2poly.divide(f2,a)
##print "***********************************"
##print "quotient: ",gf2poly.quotient(f2,f5)
##print "remainder: ",gf2poly.remainder(f2,f5)
##testq = gf2poly.quotient(f4,f2)
##testr = gf2poly.remainder(f4,f2)
##print "quotient: ",testq,type(testq)
##print "remainder: ",testr,type(testr)
##print "***********************************"
##print "outFormat testp: ",gf2poly.outFormat(testq)
##print "outFormat testr: ",gf2poly.outFormat(testr)
##print "***********************************"
#print "gf2poly.modular_inverse(): ",gf2poly.modular_inverse(f2,f3)
print "p1 ",p1 #,type(f2),type(f3)
#print "parsePolyToListInput ",gf2poly.parsePolyToListInput(a)
Part of your problem is that you haven't declared self as an argument for parsePolyToListInput. When you call a method, the instance you call it on is implicitly bound as the first argument. Naming the first argument self is a convention, not a strict requirement - the instance is being bound to poly, which you then try to run a regexp over.
It looks me like there's some confusion in your design here about what's behavior of individual instances of the class and what's class-level or module-level behavior. In Python, it's perfectly acceptable to leave something that doesn't take an instance of a class as a parameter defined as a module-level function rather than shoehorning it in awkwardly. parsePolyToListInput might be one such function.
Your add implementation, similarly, has a comment saying it "accepts 2 lists as parameters". In fact, it's going to get a gf2poly instance as its first argument - this is probably right if you're planning to do operator overloading, but it means the second argument should also be a gf2poly instance as well.
EDIT:
Yeah, your example code shows a breakdown between class behavior and instance behavior. Either your multiply call should look something like this:
print "multiply: ",f1.multiply(f3)
Or multiply shouldn't be a method at all:
gfpoly.py:
def multiply(f1, f2):
a,b = prepBinary(a,b)
g = []; bitsa = "{0:b}".format(a)
[g.append((b<<i)*int(bit)) for i,bit in enumerate(bitsa)]
m = reduce(lambda x,y: x^y,g); z = "{0:b}".format(m)
return z #returns product of 2 polynomials in gf2
That latter approach is, for instance, how the standard math library does things.
The advantage of defining a multiplication method is that you could name it appropriately (http://docs.python.org/2/reference/datamodel.html#special-method-names) and use it with the * operator:
print "multiply: ",f1 *f3
Related
Fraction Value Problem in Ctypes to PARI/GP
I have written a code to compare the solution of sympy and PARI/GP, but when I give a fraction value D=13/12, I get error, TypeError: int expected instead of float. So I changed p1[i] = pari.stoi(c_long(numbers[i - 1])) to p1[i] = pari.stoi(c_float(numbers[i - 1])), but then nfroots gives no output, note that I have to use fraction in A, B, C, D which might take $10^10$ digits after decimal point. How can I solve this problem? The code is given below to download the libpari.dll file, click here - from ctypes import * from sympy.solvers import solve from sympy import Symbol pari = cdll.LoadLibrary("libpari.dll") pari.stoi.restype = POINTER(c_long) pari.cgetg.restype = POINTER(POINTER(c_long)) pari.gtopoly.restype = POINTER(c_long) pari.nfroots.restype = POINTER(POINTER(c_long)) (t_VEC, t_COL, t_MAT) = (17, 18, 19) # incomplete pari.pari_init(2 ** 19, 0) def t_vec(numbers): l = len(numbers) + 1 p1 = pari.cgetg(c_long(l), c_long(t_VEC)) for i in range(1, l): #Changed c_long to c_float, but got no output p1[i] = pari.stoi(c_long(numbers[i - 1])) return p1 def Quartic_Comparison(): x = Symbol('x') a=0;A=0;B=1;C=-7;D=13/12 #PROBLEM 1 solution=solve(a*x**4+A*x**3+B*x**2+ C*x + D, x) print(solution) V=(A,B,C,D) P = pari.gtopoly(t_vec(V), c_long(-1)) res = pari.nfroots(None, P) print("elements as long (only if of type t_INT): ") for i in range(1, pari.glength(res) + 1): print(pari.itos(res[i])) return res #PROBLEM 2 f=Quartic_Comparison() print(f) The error is - [0.158343724039430, 6.84165627596057] Traceback (most recent call last): File "C:\Users\Desktop\PARI Function ellisdivisible - Copy.py", line 40, in <module> f=Quartic_Comparison() File "C:\Users\Desktop\PARI Function ellisdivisible - Copy.py", line 32, in Quartic_Comparison P = pari.gtopoly(t_vec(V), c_long(-1)) File "C:\Users\Desktop\PARI Function ellisdivisible - Copy.py", line 20, in t_vec p1[i] = pari.stoi(c_long(numbers[i - 1])) TypeError: int expected instead of float
The PARI/C type system is very powerful and can also work with user-defined precision. Therefore PARI/C needs to use its own types system, see e.g. Implementation of the PARI types https://pari.math.u-bordeaux.fr/pub/pari/manuals/2.7.6/libpari.pdf. All these internal types are handled as pointer to long in the PARI/C world. Don't be fooled by this, but the type has nothing to do with long. It is perhaps best thought of as an index or handle, representing a variable whose internal representation is hidden from the caller. So whenever switching between PARI/C world and Python you need to convert types. Conversion are described e.g. in section 4.4.6 in the above mentioned PDF file. To convert a double to the corresponding PARI type (= t_REAL) one would therefore call the conversion function dbltor. With the definition of pari.dbltor.restype = POINTER(c_long) pari.dbltor.argtypes = (c_double,) one could get a PARI vector (t_VEC) like this: def t_vec(numbers): l = len(numbers) + 1 p1 = pari.cgetg(c_long(l), c_long(t_VEC)) for i in range(1, l): p1[i] = pari.dbltor(numbers[i - 1]) return p1 User-defined Precision But the type Python type double has limited precision (search e.g. for floating point precision on stackoverflow). Therefore if you want to work with defined precision I would recommend to use gdiv. Define it e.g. like so: V = (pari.stoi(A), pari.stoi(B), pari.stoi(C), pari.gdiv(pari.stoi(13), pari.stoi(12))) and adjust t_vec accordingly, to get a vector of these PARI numbers: def t_vec(numbers): l = len(numbers) + 1 p1 = pari.cgetg(c_long(l), c_long(t_VEC)) for i in range(1, l): p1[i] = numbers[i - 1] return p1 You then need to use realroots to calculate the roots in this case, see https://pari.math.u-bordeaux.fr/dochtml/html-stable/Polynomials_and_power_series.html#polrootsreal. You could likewise use rtodbl to convert a PARI type t_REAL back to a double. But the same applies, since with using a floating point number you would loose precision. One solution here could be to convert the result to a string and display the list with the strings in the output. Python Program A self-contained Python program that considers the above points might look like this: from ctypes import * from sympy.solvers import solve from sympy import Symbol pari = cdll.LoadLibrary("libpari.so") pari.stoi.restype = POINTER(c_long) pari.stoi.argtypes = (c_long,) pari.cgetg.restype = POINTER(POINTER(c_long)) pari.cgetg.argtypes = (c_long, c_long) pari.gtopoly.restype = POINTER(c_long) pari.gtopoly.argtypes = (POINTER(POINTER(c_long)), c_long) pari.dbltor.restype = POINTER(c_long) pari.dbltor.argtypes = (c_double,) pari.rtodbl.restype = c_double pari.rtodbl.argtypes = (POINTER(c_long),) pari.realroots.restype = POINTER(POINTER(c_long)) pari.realroots.argtypes = (POINTER(c_long), POINTER(POINTER(c_long)), c_long) pari.GENtostr.restype = c_char_p pari.GENtostr.argtypes = (POINTER(c_long),) pari.gdiv.restype = POINTER(c_long) pari.gdiv.argtypes = (POINTER(c_long), POINTER(c_long)) (t_VEC, t_COL, t_MAT) = (17, 18, 19) # incomplete precision = c_long(38) pari.pari_init(2 ** 19, 0) def t_vec(numbers): l = len(numbers) + 1 p1 = pari.cgetg(c_long(l), c_long(t_VEC)) for i in range(1, l): p1[i] = numbers[i - 1] return p1 def quartic_comparison(): x = Symbol('x') a = 0 A = 0 B = 1 C = -7 D = 13 / 12 solution = solve(a * x ** 4 + A * x ** 3 + B * x ** 2 + C * x + D, x) print(f"sympy: {solution}") V = (pari.stoi(A), pari.stoi(B), pari.stoi(C), pari.gdiv(pari.stoi(13), pari.stoi(12))) P = pari.gtopoly(t_vec(V), -1) roots = pari.realroots(P, None, precision) res = [] for i in range(1, pari.glength(roots) + 1): res.append(pari.GENtostr(roots[i]).decode("utf-8")) #res.append(pari.rtodbl(roots[i])) return res f = quartic_comparison() print(f"PARI: {f}") Test The output on the console would look like: sympy: [0.158343724039430, 6.84165627596057] PARI: ['0.15834372403942977487354358292473161327', '6.8416562759605702251264564170752683867'] Side Note Not really asked in the question, but just in case you want to avoid 13/12 you could transform your formula from to
Differential equation change of variables with sympy
I have an ordinary differential equation like this: DiffEq = Eq(-ℏ*ℏ*diff(Ψ,x,2)/(2*m) + m*w*w*(x*x)*Ψ/2 - E*Ψ , 0) I want to perform a variable change : sp.Eq(u , x*sqrt(m*w/ℏ)) sp.Eq(Ψ, H*exp(-u*u/2)) How can I do this with sympy?
Use the following function: def variable_change(ODE,dependent_var, independent_var, new_dependent_var = None, new_independent_var= None, dependent_var_relation = None, independent_var_relation = None, order = 2): if new_dependent_var == None: new_dependent_var = dependent_var if new_independent_var == None: new_independent_var = independent_var # dependent variable change if new_independent_var != independent_var: for i in range(order, -1, -1): # remplace derivate a = D(dependent_var , independent_var, i ) ξ = Function("ξ")(independent_var) b = D( dependent_var.subs(independent_var, ξ), independent_var ,i) rel = solve(independent_var_relation, new_independent_var)[0] for j in range(order, 0, -1): b = b.subs( D(ξ,independent_var,j), D(rel,independent_var,j)) b = b.subs(ξ, new_independent_var) rel = solve(independent_var_relation, independent_var)[0] b = b.subs(independent_var, rel) ODE = ODE.subs(a,b) ODE = ODE.subs(independent_var, rel) # change of variables of indpendent variable if new_dependent_var != dependent_var: ODE = (ODE.subs(dependent_var.subs(independent_var,new_independent_var) , (solve(dependent_var_relation, dependent_var)[0]))) ODE = ODE.doit().expand() return ODE.simplify() For the example posted: from sympy import * from sympy import diff as D E, ℏ ,w,m,x,u = symbols("E, ℏ , w,m,x,u") Ψ ,H = map(Function, ["Ψ ","H"]) Ψ ,H = Ψ(x), H(u) DiffEq = Eq(-ℏ*ℏ*D(Ψ,x,2)/(2*m) + m*w*w*(x*x)*Ψ/2 - E*Ψ,0) display(DiffEq) display(Eq(u , x*sqrt(m*w/ℏ))) display(Eq(Ψ, H*exp(-u*u/2))) newODE = variable_change(ODE = DiffEq, independent_var = x, new_independent_var= u, independent_var_relation = Eq(u , x*sqrt(m*w/ℏ)), dependent_var = Ψ, new_dependent_var = H, dependent_var_relation = Eq(Ψ, H*exp(-u*u/2)), order = 2) display(newODE) Under this substitution the differential equation outputted is then: Eq((-E*H + u*w*ℏ*D(H, u) + w*ℏ*H/2 - w*ℏ*D(H, (u, 2))/2)*exp(-u**2/2), 0)
If anyone is wondering how they could do it as well on CoCalc notebooks/anywhere where you can mix Sage and Python, here I defined basically the same variables and functions as OP did on his accepted answer, and then after substitution the result is converted back to Sage: # Sage objects var("E w m x u") var("h_bar", latex_name = r'\hbar') Ψ = function("Ψ")(x) H = function('H')(u) DiffEq = (-h_bar*h_bar*Ψ.diff(x, 2)/(2*m) + m*w*w*(x*x)*Ψ/2 - E*Ψ == 0) display(DiffEq) display(u == x*sqrt(m*w/h_bar)) display(Ψ == H*exp(-u*u/2)) # Function is purely sympy newODE = variable_change( ODE = DiffEq._sympy_(), independent_var = x._sympy_(), new_independent_var = u._sympy_(), independent_var_relation = (u == x*sqrt(m*w/h_bar))._sympy_(), dependent_var = Ψ._sympy_(), new_dependent_var = H._sympy_(), dependent_var_relation = (Ψ == H*exp(-u*u/2))._sympy_(), order = 2 ) display(newODE._sage_()) Note that the only difference is that here things are converted to SymPy when using as arguments inside OP's function (it'll probably break if you don't!). After you call _sympy_() only once on a variable or expression, every sympy object gets a _sage_() method to convert back. The result given was: # Sage object again 1/2*(2*h_bar*u*w*diff(H(u), u) + h_bar*w*H(u) - h_bar*w*diff(H(u), u, u) - 2*E*H(u))*e^(-1/2*u^2) == 0 Which is just OP's result, but Sage handles operands a little bit differently. Note: in order to avoid overriding stuff on Sage after importing everything from SymPy, you may want to import only diff as D, Function and solve from the main library. You might also want to rename sympy's solve to something else to avoid overriding Sage's own sage.symbolic.relation.solve.
Sympy solve() gives wrong results
I use Sympy solve() function to solve a large number of equations. All variables in the equations are defined as symbols. Variables can start with the letter P or F. I use solve() to express one specific P variable (the one that I observe) with only F variables, so I use solve() to substitute all other P variables with F variables. The sum of the coefficients before the F variables is ideally 1 or almost 1 (e.g.: 0.99). This produces good results till a certain point where the number of equations becomes pretty big and also their length. There the Sympy solve() function starts to give me wrong results. The sum of the coefficients becomes negative (e.g. -7,...). It looks like that the solve() function gets problems with substituting any carrying over all variables and their coefficients. Is there a way to correct this problem? Dictionary of equations under link: https://drive.google.com/open?id=1VBQucrDU-o1diCd6i4rR3MlRh95qycmK import json from sympy import Symbol, Add, Eq, solve # Get data # data from link above with open("C:\\\\Test\\dict.json") as f: equations = json.load(f) comp =[] expressions = [] for p, equation_components in equations.items(): p = Symbol(p) comp.append(p) expression = [] for name, multiplier in equation_components.items(): if type(multiplier) == float or type(multiplier) == int: expression.append(Symbol(name) * multiplier) else: expression.append(Symbol(name) * Symbol(multiplier)) expressions.append(Eq(p, Add(*expression))) # Solution for variable P137807 print("Solving...") # Works for slice :364 !!!!! solutions = solve(expressions[:364], comp[:364], simplify=False, rational=False) # Gives wrong results for slice :366 and above !!!!! # solutions = solve(expressions[:366], comp[:366], simplify=False, rational=False) vm_symbol = Symbol("P137807") solution_1 = solutions[vm_symbol] print("\n") print("Solution_1:") print(solution_1) print("\n") #Sum of coefficients list_sum = [] for i in solution_1.args: if str(i.args[1]) != "ANaN": list_sum.append(i.args[0]) coeff_sum = sum(list_sum) print("Sum:") print(coeff_sum) ...
I just wanted to mark the problem as solved and provide reference to the solution. Please look at numerical instability when solving n=385 linear equations with Float coefficients #17136. The solution that worked for me was to use the following solver and not the Sympy solve() function: def ssolve(eqs, syms): """return the solution of linear system of equations with symbolic coefficients and a unique solution. Examples ======== >>> eqs=[x-1,x+2*y-z-2,x+z+w-6,2*y+z+x-2] >>> v=[x,y,z,w] >>> ssolve(eqs, v) {x: 1, z: 0, w: 5, y: 1/2} """ from sympy.solvers.solveset import linear_coeffs v = list(syms) N = len(v) # convert equations to coefficient dictionaries print('checking linearity') d = [] v0 = v + [0] for e in [i.rewrite(Add) for i in eqs]: co = linear_coeffs(e, *v) di = dict([(i, c) for i, c in zip(v0, co) if c or not i]) d.append(di) print('forward solving') sol = {} impl = {} done = False while not done: # check for those that are done more = set([i for i, di in enumerate(d) if len(di) == 2]) did = 0 while more: di = d[more.pop()] c = di.pop(0) x = list(di)[0] a = di.pop(x) K = sol[x] = -c/a v.remove(x) changed = True did += 1 # update everyone else for j, dj in enumerate(d): if x not in dj: continue dj[0] += dj.pop(x)*K if len(dj) == 2: more.add(j) if did: print('found',did,'definitions') # solve implicitly for the next variable dcan = [i for i in d if len(i) > 2] if not dcan: done = True else: # take shortest first di = next(ordered(dcan, lambda i: len(i))) done = False x = next(ordered(i for i in di if i)) c = di.pop(x) for k in di: di[k] /= -c impl[x] = di.copy() di.clear() v.remove(x) # update everyone else for j, dj in enumerate(d): if x not in dj: continue done = False c = dj.pop(x) for k in impl[x]: dj[k] = dj.get(k, 0) + impl[x][k]*c have = set(sol) sol[0] = 1 while N - len(have): print(N - len(have), 'to backsub') for k in impl: if impl[k] and not set(impl[k]) - have - {0}: sol[k] = sum(impl[k][vi]*sol[vi] for vi in impl[k]) impl[k].clear() have.add(k) sol.pop(0) return sol
Solving multivariate equation for a subset of variables
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...
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)))
Python dictionary manipulating items(getting min and max)
Edit: I removed my explanation part since it was wrong but I still could not be able to convert it. I was studying list and dictionaries in python and I came accross this code. x = min(minValue, key=lambda b: min([a( \ myFunction(5,b),c) for c in something])) What is the logical equivalent of this ? It seems simple but I do not get same thing when I try to write it with a different code. . How can write this differently without whole key and lambda thing Seems like my explanation was wrong. Here is the updated code I try. for b in minValue: for c in something: minimum=min(myFunction(5,b),c) result=min(minimum) return result Note: By logical equivalent I do not mean the provided code should calculate this exactly like the code I gave but it should have the same output.
I' not sure but it can be something like this def example(minValue): data = [] for b in minValue: values = [] for c in something: values.append( a(myFunction(5,b),c) ) result = min(values) # keep `result` and `b` which gives this `result` data.append( [result, b] ) # find minimal `result` and `b` which gives this `result` x = min(data) # x = [result, b] # return `b` return x[1] #--- x = example(minValue) EDIT: there can be problem with min(data) because min will be comparing result and b and oryginal version compare only result. It may need version without min() but with: if result < min_result: min_result = result min_b = b EDIT: def key(val): min_c = something[0] min_result = a(myFunction(5,val),min_c) for c in something[1:]: result = a(myFunction(5,val),c) if result < min_result: min_result = result #min_c = c return min_result def example(minValue): min_b = minValue[0] min_result = key(min_b) for b in minValue[1:]: result = key(b) if result < min_result: min_result = result min_b = b return min_b #--- x = example(minValue)