Solve system of 2 integer equations - python

I have a set of two equations with three unknowns that has some conditions. x, y and z must all be larger than zero. How can I solve this? There is only one solution and I already know it, but I want to know how to get to it correctly.
These are the equations:
100 = x + y + z
100 = 10x +2.5y + 0.5z
Need to find x, y and z. They are integers and positive.
This is the code I have, but that does not work:
from sympy import symbols, Eq, solve
x, y, z = symbols('x y z')
eq1 = Eq(x + y + z, 100)
eq2 = Eq(x*10 + y*2.5 + z*0.5, 100)
#eq3 = x, y, z must all be larger than zero and integers
solution = solve((eq1,eq2), (x,y,z))
solution

In sympy if you want to find integer solutions to equations then you should use diophantine. It doesn't handle systems of equations but you can put the solution from one equation into the other and call diophantine again:
In [69]: eq1 = x + y + z - 100
In [70]: eq2 = 10*x + 5*y/2 + z/2 - 100
In [71]: sol = diophantine(eq1, t, syms=[x, y, z])
In [72]: sol
Out[72]: {(t₀, t₀ + t₁, -2⋅t₀ - t₁ + 100)}
In [73]: [xt, yt, zt], = sol
In [74]: eq3 = eq2.subs({x:xt, y:yt, z:zt})
In [75]: eq3
Out[75]:
23⋅t₀
───── + 2⋅t₁ - 50
2
In [76]: t1, t2 = eq3.free_symbols
In [77]: [t1s, t2s], = diophantine(eq3, z, syms=[t1, t2])
In [78]: rep = {t1:t1s, t2:t2s}
In [79]: (xt.subs(rep), yt.subs(rep), zt.subs(rep))
Out[79]: (4⋅z₀ - 100, 500 - 19⋅z₀, 15⋅z₀ - 300)
The solution here is in terms of an integer parameter z0. This gives the set of solutions to the two equations but you also have the requirement that x, y, z are positive which constrains the possible values of z0:
In [80]: ineqs = [s.subs(rep) > 0 for s in [xt, yt, zt]]
In [81]: ineqs
Out[81]: [4⋅z₀ - 100 > 0, 500 - 19⋅z₀ > 0, 15⋅z₀ - 300 > 0]
In [82]: solve(ineqs)
Out[82]:
500
25 < z₀ ∧ z₀ < ───
19
In [83]: 500/19
Out[83]: 26.31578947368421
We see that z needs to be 26 which gives a unique solution for x, y and z:
In [84]: z, = ineqs[0].free_symbols
In [85]: (xt.subs(rep).subs(z, 26), yt.subs(rep).subs(z, 26), zt.subs(rep).subs(z, 26))
Out[85]: (4, 6, 90)

This type of problem can be solved by Z3py, a SAT/SMT solver:
from z3 import Ints, solve
x, y, z = Ints('x y z')
sol = solve(x + y + z == 100, x * 100 + y * 25 + z * 5 == 1000, x > 0, y > 0, z > 0)
print(sol)
Output: [z = 90, y = 6, x = 4].
Note that in general, Z3 only looks for one solution. To find subsequent solutions, a clause needs to be added to prohibit the already found solutions. (In this case there seems to be only one solution.)

You did not explicitly state it but according to your comment x,y and z should be integers.
This complicates matters a bit.
This is now an example of a mixed integer programming (MIP) problem.
You could take a look at the following package for solving this in python:
mip
The downside of solving MIP's is that they are NP hard. But for this small example this should not matter.

Related

How to find the difference of x -y using sympy

As you see in the code, I want to find the difference of x-y using the resulting R of solve. But, the code keeps returning x-y as value. Please help me. I am a 10 year old kid that just started coding.
import sympy as sp
x, y = sp.symbols ('x, y')
eq1 = sp.Eq(7 * x, 12 * y)
eq2 = sp.Eq(x+y, 9500)
R = sp.solve ((eq1, eq2), (x, y))
print (x-y)
The result R of sp.solve is a Python dictionary with values for x and for y:
import sympy as sp
x, y = sp.symbols('x, y')
eq1 = sp.Eq(7 * x, 12 * y)
eq2 = sp.Eq(x + y, 9500)
R = sp.solve((eq1, eq2), (x, y))
Result: {x: 6000, y: 3500}
To apply the resulting dictionary to an expression, use subs(R):
print((x - y).subs(R))
Result: 2500

I got an empty list when solving two equation

I tried to solve two simple equations but I got nothing.
from sympy import *
x, y = symbols('x y')
eq1=Function('eq1')
eq2=Function('eq2')
eq1 = Eq(x + y , 1) # x + y = 1
eq2 = Eq(x + y ,3) # x + y = 3
ans = solve([eq1, eq2] , [x, y])
print(ans)
I got
[]
You set everything up ok. The empty list is the way that solve tells you that it could not find a solution for x and y that satisfied the equations. And, indeed, there are no values which, when added, will give two different results (as others have noted).

Restricting domain of solution set when using SymPy solve in the multiple variables case

Say, I'm trying to solve the system of equations:
for θ, λ and ɸ , where a, b, c and d are complex numbers and the matrix on the LHS is a unitary matrix.
The SymPy code I have at hand does successfully do the job but there are a few edge cases it misses.
from sympy import *
def get_angles(a, b, c, d):
theta, phi, lamb = symbols('\\theta \\phi \\lambda', real=True)
a_eq = Eq(cos(theta / 2), a)
b_eq = Eq(exp(I * phi) * sin(theta / 2), b)
c_eq = Eq(-exp(I * lamb) * sin(theta / 2), c)
d_eq = Eq(exp(I * (phi + lamb)) * cos(theta / 2), d)
res = solve([a_eq, b_eq, c_eq, d_eq],
theta,
phi,
lamb,
check=False,
set=True)
return res
For instance, it doesn't restrict the range of the solutions. I did notice this answer but it only works for single variable cases. So any idea how to add the domain restrictions for the solution set, when dealing with multiple variables?
You can declare assumptions on the symbols and solve should check them e.g.:
In [12]: solve(x*(1-x))
Out[12]: [0, 1]
In [13]: x = Symbol('x', positive=True)
In [14]: solve(x*(1-x))
Out[14]: [1]
That works for some restrictions but won't work for a restriction like x<y. You can however post-process the output from solve:
In [6]: sol = [{x:1, y:2, z:3}, {x:1, y:0, z:4}, {x:3, y:2, z:1}]
In [7]: sol
Out[7]: [{x: 1, y: 2, z: 3}, {x: 1, y: 0, z: 4}, {x: 3, y: 2, z: 1}]
In [8]: cond = And(0 < x, x < z, 0 < y)
In [9]: cond
Out[9]: x > 0 ∧ y > 0 ∧ x < z
In [10]: cond.subs(sol[0])
Out[10]: True
In [11]: [s for s in sol if cond.subs(s)]
Out[11]: [{x: 1, y: 2, z: 3}]

Simplify solution for Symbolic solver for system of equations in Python (with symbolic output)

I have the following system of equations :
-2yz = a
-2xy = b
-x^2 + y^2 - z^2 = c
How can I simplify the solution for these equations using SymPy? x, y, z are unknowns. I have the following script:
from sympy import *
x, y, z = var('x y z')
a, b, c = var('a b c')
E1 = -2 * y * z - a
E2 = -2 * x * y - b
E3 = -x**2 + y ** 2 - z ** 2 - c
sols = solve([E1, E2, E3], [x, y, z])
The simplifies solution is not really palatable. Any idea?
You might consider running cse over your solutions. I will let you see what the replacments are, but here is the result:
>>> r, e = cse(flatten(sols))
>>> reshape(e, (3,)) # restore tuples of 3 solutions
[
(x1*x9, -x11*x13, x9),
(-x1*x13, x11*x9, -x13),
(-x16, x12*x17, -x15),
(x16, x17*x8, x15)]

Using Horner's method to find P(x) and P'(x)

My textbook gives the pseudo code for Horner's method as follows:
P(x) = a_n x n + a_n−1 x n−1 + ··· + a_1 x + a_0 = (x−x0)Q(x) + b0
INPUT degree n; coefficients a_0 , a_1 , . . . , a_n ; x0 .
OUTPUT y = P(x 0 ); z = P (x 0 ).
Step 1 Set y = a_n ; (Compute b n for P.)
z = a_n . (Compute b n−1 for Q.)
Step 2 For j = n − 1, n − 2, . . . , 1
set y = x0 * y + a_j ; (Compute b_j for P.)
z = x0 * z + y. (Compute b_j−1 for Q.)
Step 3 Set y = x0 + y + a_0 .
Step 4 OUTPUT (y, z);
STOP.
Now the issue I have here is that the subscript in the pseudo code does not seem to match the subscripts in the formula
I did a python implementation, but the the answers I got seemed wrong, so I changed it slightly
def horner(x0, *a):
'''
Horner's method is an algorithm to calculate a polynomial at
f(x0) and f'(x0)
x0 - The value to avaluate
a - An array of the coefficients
The degree is the polynomial is set equal to the number of coefficients
'''
n = len(a)
y = a[0]
z = a[0]
for j in range(1, n):
y = x0 * y + a[j]
z = x0 * z + y
y = x0 * y + a[-1]
print('P(x0) =', y)
print('P\'(x0) =', z)
It works pretty well, but I need someone with more experience in this regard to give it a once over.
As a very basic test I took the polynomial 2x^4 with a value of -2 for x.
To use it in the method I call it as such
horner(-2, 2, 0, 0 ,0)
The output does indeed look correct for this very simple problem. Since f(x) = 2x^4 then f(-2) = -32, but this is where my implementation gives a different result my answer is positive
I found the problem and I am adding the answer here since it may prove useful to someone in the future
Firstly there is a but in the algorithm, the loop must go up to n-1
def horner(x0, *a):
'''
Horner's method is an algorithm to calculate a polynomial at
f(x0) and f'(x0)
x0 - The value to avaluate
a - An array of the coefficients
The degree is the polynomial is set equal to the number of coefficients
'''
n = len(a)
y = a[0]
z = a[0]
for j in range(1, n - 1):
y = x0 * y + a[j]
z = x0 * z + y
y = x0 * y + a[-1]
print('P(x0) =', y)
print('P\'(x0) =', z)
Second, and this was my biggest mistake, I am not passing enough coefficients to the method
This will calculate 2x^3
horner(-2, 2, 0, 0, 0)
I actually had to call
horner(-2, 2, 0, 0, 0, 0)

Categories