I have a polynomial equation and Y, How can I find X? - python

Consider it:
X = [1, 2, 3]
p = np.poly1d(X)
print('x: ', X, 'y: ', p(X))
output >> x: [1, 2, 3] y: [ 6 11 18]
what if I want to find x based on y?
x: [?, ?, ?] y: [ 6 11 18]

np.poly1d(X) means you create a polynomial of the required degree where X are its coefficients. Let's call them a, b, and c. So practically you have the expression
a*x**2 + b*x + c
When you then pass these three values for x, you get the following 3 equations
a**3 + b*a + c = 6
a*b**2 + b**2 + c = 11
a*c**2 + b*c + c = 18
There might be an algebraic way you can solve them yourself, but after a quick think I didn't come up with anything. However, sympy will happily solve this system of equations for you.
import numpy as np
import sympy as sym
def generate_y(X):
return np.poly1d(X)(X)
def solve_x(Y):
a, b, c = sym.symbols('a b c')
e1 = sym.Eq(a**3 + b*a + c, Y[0])
e2 = sym.Eq(a*b**2 + b**2 + c, Y[1])
e3 = sym.Eq(a*c**2 + b*c + c, Y[2])
return sym.solvers.solve([e1, e2, e3], [a, b, c])
For example
>>> solve_x(generate_y([1, 2, 3]))
[(1, 2, 3)]
>>> solve_x(generate_y([-5, 105, 2]))
[(-5, 105, 2)]
You could generalise this for nth order polynomials by creating the symbolic expressions dynamically, but for higher order you'll run into problems (such is life) and for 1st order you'll have multiple solutions.
def solve_x(Y):
symbols = sym.symbols('a:z')[:len(Y)]
X = sym.symbols('X')
expr = sum(s*X**i for i, s in enumerate(symbols[::-1]))
eqns = [sym.Eq(expr.subs({X: s}), y) for s, y in zip(symbols, Y)]
return sym.solvers.solve(eqns, symbols)
Usage
>>> solve_x(generate_y([1, 2]))
[(1, 2), (-1 + sqrt(2), 2*sqrt(2)), (-sqrt(2) - 1, -2*sqrt(2))]
>>> solve_x(generate_y([1, 2, 3, 4]))
# still computing...

Related

Multiple arguments with function and scipy

Following code needs to be optimized and minimised with respect to x by using scipy optimizer.
The issue is it works with single argument but when function is taken multiple values, it can't handle it.
This code works well.
from scipy.optimize import root
b = 1
def func(x):
# result when x = 0, but result equation depends also on b value.
result = x + b
return result
sol = root(func, 0.1)
print(sol.x, sol.fun)
But this is not working.....
b =[ 1, 2, 3, 4, 5]
def func(x, b):
# result when x = 0, but result equation depends also on b value.
result = x + b
return result
for B in b:
sol = root(lambda x,B: func(x, B), 0.1)
print(sol.x, sol.fun)
How can result obtain with iteration through b?
As #hpaulj mentioned, root accepts an args parameter that will be passed onto func. So, we can make the script more flexible:
from scipy.optimize import root
def func(x, *args):
result = 0
for i, a in enumerate(args):
result += a * x ** i
return result
coeff_list = [(6, 3), (-3, 2, 1), (-6, 1, 2)]
for coeffs in coeff_list:
sol = root(func, [-4, 4][:len(coeffs)-1], args = coeffs)
print(*coeffs, sol.x, sol.fun)
Output:
6 3 [-2.] [8.8817842e-16]
-3 2 1 [-3. 1.] [ 1.46966528e-09 -4.00870892e-10]
-6 1 2 [-2. 1.5] [-6.83897383e-14 4.97379915e-14]
Initial answer
I don't understand the need for your lambda function:
from scipy.optimize import root
def func(x):
# result when x = 0, but result equation depends also on b value.
result = x + b
return result
B =[ 1, 2, 3, 4, 5]
for b in B:
sol = root(func, 0.1)
print(b, sol.x, sol.fun)
Output:
1 [-1.] [0.]
2 [-2.] [0.]
3 [-3.] [0.]
4 [-4.] [0.]
5 [-5.] [0.]
I don't see in the scipy documentation any hint of how to pass parameters to func. But this approach also works for multiple parameters:
from scipy.optimize import root
def func(x):
#depending on the parameters, this has 0, 1 or 2 solutions
result = a * x ** 2 + b * x + c
return result
A = range(3)
B = [3, 2, 1]
C = [6, -3, -6]
for a, b, c in zip(A, B, C):
sol = root(func, [-4, 4])
print(a, b, c, sol.x, sol.fun)
Output:
0 3 6 [-2. -2.] [ 8.8817842e-16 0.0000000e+00]
1 2 -3 [-3. 1.] [ 1.46966528e-09 -4.00870892e-10]
2 1 -6 [-2. 1.5] [-6.83897383e-14 4.97379915e-14]

How to iterate in python using for i in range loop?

I wonder how can I run the code below 4 times in which, in each run the variables in z (which are a and b) takes the new number while c stays the same?
a = [1,2,3,4]
print (a)
b = [4,5,6,7]
print (b)
c = [5]
print (c)
for i in range(4):
z = (a**2)*b+c
print (z)
The output I am looking for is:
9 ---> z = (1**4)*4+5
25---> z = (2**5)*4+5
59---> z = (3**6)*4+5
117---> z = (4**7)*4+5
for i, j in zip(a, b):
z = (i**2)*j+c[0]
print (z)
I'm not sure how you get the results on the left side from the calculations on the right. Based on your descriptions, I think what you meant is:
a = [1, 2, 3, 4]
print(a)
b = [4, 5, 6, 7]
print(b)
c = [5]
print(c)
for i in range(4):
z = (a[i] ** b[i]) * 4 + c[0]
print(z)
which gives:
9 ---> z = (1**4)*4+5
133 ---> z = (2**5)*4+5
2921 ---> z = (3**6)*4+5
65541 ---> z = (4**7)*4+5

How to solve this math puzzle with Python?

A + B = 8
B + D = 8
A + C = 13
C - D = 6
How to find the values of A, B, C and D?
I assumed the values would be integers and positive and did this:
a = range(0,14)
b = c = d = a
for i in a:
for x in b:
for y in c:
for z in d:
if (a[i] + b[x] == 8 and a[i] + c[y] == 13 and b[x] + d[z] == 8 and c[y]-d[z]==6):
print(a[i],b[x],c[y],d[z])
But that does not work. Even then I extend range to a = range(-100,100).
After solving the equation by hand (with Google's help) I know that floats are involved, e.g. A = 3.5 etc.
But then how to solve it with Python.
If you know linear algebra, you can frame the question as a system of equations, which is then trivial to solve using a freely-available and popular library called numpy (hat tip #Griboullis):
import numpy as np
A = [[1, 1, 0, 0],
[0, 1, 0, 1],
[1, 0, 1, 0],
[0, 0, 1, -1]]
b = [8, 8, 13, 6]
answer = np.linalg.solve(A, b)
If you want a refresher at the matrix math/linear algebra behind this python solution, you can check out https://www.mathsisfun.com/algebra/systems-linear-equations-matrices.html.
There's no need to learn matrix theory (at least not for this).
>>> from sympy import *
>>> var('A B C D')
(A, B, C, D)
>>> solve([A+B-8,B+D-8,A+C-13,C-D-6])
{B: 9/2, D: 7/2, C: 19/2, A: 7/2}
You just need to express each equation such as A+B=8 in the form A+B-8=0 and then omit the '=0' part.

Number of pairs [duplicate]

I am trying to write a code that takes
m. a, a list of integers
n. b, an integer
and returns the number of pairs (m,n) with m,n in a such that |m-n|<=b.
So far, I've got this
def nearest_pairs(a, b):
m= []
n= int
num_pairs = 0
return num_pairs
def main():
# The nearest pairs are (1,2), (2,1), (2,5) and (5,2)
x = nearest_pairs( [1,2,5] , 3 )
print( "nearest_pairs([1, 2, 5], 3) = " , nearest_pairs([1, 2, 5], 3) )
# The nearest pairs are (1,2) and (2,1)
y = nearest_pairs( [1, 2, 5] , 2 )
print( "nearest_pairs([1, 2, 5], 2) = " , nearest_pairs([1, 2, 5], 2) )
if __name__ == '__main__':
main()
The desired output should look like
>>> nearest_pairs([1,2,5],3) = 4
where 4 is the number of close pairs according to the restrictions. However, I get an error. Could anyone lead me to the right direction?
Yours doesn't make sense. No idea what you're trying with len(a, b), but it's not even allowed, since len takes only one argument. And returning something just when you found the first counting pair? Here's a fix:
def close_pairs(l, d):
ctr = 0
for a,b in permutations(l, 2):
if (a - b) <= d and (b - a) <= d:
ctr += 1
return ctr
And here's how I'd do it:
def close_pairs(l, d):
return sum(abs(a-b) <= d for a, b in permutations(l, 2))
from itertools import permutations
def nearest_pairs(a, b):
for m, n in permutations(a, 2):
if abs(m - n) <= b:
yield (m, n)
>>> list(nearest_pairs([1, 2, 5], 3))
[(1, 2), (2, 1), (2, 5), (5, 2)]
>>> list(nearest_pairs([1, 2, 5], 2))
[(1, 2), (2, 1)]
If you just want the count:
def nearest_pairs_count(a, b):
c, l = 0, len(a)
for i in range(l):
for j in range(i + 1, l):
if abs(a[i] - a[j]) <= b:
c += 2
return c

TypeError: __getitem__() takes exactly 2 arguments (2 given) TypeError? (Python 3)

I have the following function defined:
def eigval(matrix):
a = matrix[0, 0]
b = matrix[0, 1]
c = matrix[1, 0]
d = matrix[1, 1]
c1 = (a + d) + sqrt((4 * b * c) + ((a - d)**2))
c2 = (a + d) - sqrt((4 * b * c) + ((a - d)**2))
return c1 / 2, c2 / 2
It is created to find the eigenvalues of a 2 X 2 matrix. I am using it to iteratively run the Jacobi algorithm on a matrix. The matrix passed in is a dictionary that uses tuples as keys to represent the position and floats as values. This function will work fine for about 6 iterations, but then I will get a:
TypeError: __getitem__() takes exactly 2 arguments (2 given)
on the first line of the block (the one with the a).
I am completely confused by this because like I said, it works fine for about 6 runs and then stops.
EDIT: Here's a function that creates the kind of matrix I would pass in:
(Given that the matrix will be different for each iteration)
def create():
matrix = {}
matrix[0, 0] = 2
matrix[0, 1] = 1
matrix[1, 0] = 1
matrix[1, 1] = 2
return matrix
Any help is greatly appreciated! (P.S. first post here)
Your matrix is a dict using tuples as keys, this is probably not what you want to do.
Try using nested lists:
from math import sqrt
def create():
matrix = [[1, 2], [1, 2]]
return matrix
def eigval(matrix):
a = matrix[0][0]
b = matrix[1][0]
c = matrix[0][1]
d = matrix[1][1]
c1 = (a + d) + sqrt((4 * b * c) + ((a - d)**2))
c2 = (a + d) - sqrt((4 * b * c) + ((a - d)**2))
return [c1 / 2, c2 / 2]
>>> m = create()
>>> eigval(m)
[3.0, 0.0]
Or alternatively use numpy:
import numpy
def eigval(matrix):
a = matrix[0, 0]
b = matrix[1, 0]
c = matrix[0, 1]
d = matrix[1, 1]
c1 = (a + d) + sqrt((4 * b * c) + ((a - d)**2))
c2 = (a + d) - sqrt((4 * b * c) + ((a - d)**2))
return numpy.array([c1 / 2, c2 / 2])
>>> m = numpy.array([[1, 2], [1, 2]])
>>> m
array([[1, 2],
[1, 2]])
>>> eigvalues, eigvectors = numpy.linalg.eig(m)
>>> eigvalues
array([ 0., 3.])
>>> eigval(m)
array([ 3., 0.])

Categories

Resources