Solving algebra equations in python - python

I'm new to programming and I'm having a hard time solving this equation using Python.
I would like for the system to give me the value for X.
((X-5)/(2) + (X/4) + (X-12)/(3))

Sympy looks promising, especially section 3.2.4, "Equation Solving".

Assuming your right hand side of equation is some given value or expression:
import sympy as sym
x = sym.Symbol("x")
RHS = 13
LHS = (x - 5)/2 + x/4 + (x - 12)/3
eqn = LHS - RHS
soln = sym.solve(eqn, x)
print(soln)
This yields the solution x = 18. Replace RHS with your own value or expression. If there is nothing, simply put RHS to be 0; which gives the solution x = 6.
If you want to solve your equation step by step, you are still going to need SymPy:
https://docs.sympy.org/latest/install.html

Related

How do you write Ranged Inequality Constraint in Pyomo

I'm new to Pyomo and I need help writing this equation in Pyomo.
I'm trying to write a (ranged inequality) constraint equation in Pyomo.
Here is the equation:
So far I wrote these 2 versions:
Version 1: Not sure if this correct
model.amount_of_energy_con = pe.ConstraintList()
for t in model.time:
lhs = 0
rhs = sum(model.c_ratings[s] * model.boat_capacity * model.charging[b, t, s] * model.boats_availability[b][t] for b in model.boats for s in model.chargers)
body = sum(model.charge_energy[b, t, s] for b in model.boats for s in model.chargers)
model.amount_of_energy_con.add(lhs <= body)
model.amount_of_energy_con.add(body <= rhs)
Version 2: I think this is not correct
model.amount_of_energy_con = pe.ConstraintList()
for t in model.time:
lhs = 0
rhs = sum(model.c_ratings[s] * model.boat_capacity * model.charging[b, t, s] * model.boats_availability[b][t] for b in model.boats for s in model.chargers)
body = sum(model.charge_energy[b, t, s] for b in model.boats for s in model.chargers)
#model.amount_of_energy_con.add(expr=pe.inequality(lhs, body, rhs))
model.amount_of_energy_con.add(lhs, body, rhs)
Note:
All the subscripts in the equation are elements of 3 different sets. s Elements of Set S (model.chargers), b Elements of Set B (model.boats), t Elements of Set T (model.time).
C-rate, Availability, Battery capacity are given parameters while E and Charging are Variables in Pyomo.
Please, let me know what you think and how to write it in Pyomo. Generally if there is something you think I'm doing wrong, please me know and also if you need my full code, data and further explanation let me know as well.
Thank you so much for your help
This solution works for me:
model.amount_of_energy_con = pe.ConstraintList()
for t in model.time:
for b in model.boats:
for s in model.chargers:
lhs = model.charge_energy[b, t, s]
rhs = model.c_rating[s] * model.boat_battery_capacity * boats_availability[b, t] * model.charging[b, t, s]
model.amount_of_energy_con.add(expr= (lhs <= rhs))
The problem with those previous versions I posted above in the question are:
The sum() function/ method will do sum of the variables and parameters which is not what I want because the equation doesn't have summation. The 2 versions above will work if we are trying to do summation of the variables on the right and left hand side separately.
The 0 in the range inequalities/ left hand side was covered using the "within parameter" when writing the charge_energy variable as follows model.charge_energy = pe.Var(model.boats, model.time, model.chargers, within=pe.NonNegativeReals).
Thank you.

Finding roots of a non linear expression when multiplied with a linear expression

Here is a simple polynomial equation:
b^2 + 2b + 1 = 0
I could easily solve this as:
import numpy as np
from scipy.optimize import fsolve
eq = lambda b : np.power(b,2) + 2*b + 1
fsolve(eq, np.linspace(0,1,2))
Similarly I could solve any equation, that has finite number of terms. But how do I solve an equation with infinite number of terms which is given as :
The above equation could be written as :
5 = (1 - l) * (5.5 + 4.0*l + 4*l^2 + 6*l^3 + 5*l^4 + 5*l^5 + 5*l^6 + 5*l^7 + 5*l^8 + 5*l^9 + 5*l^10 )
when n goes from 1 to 10. But I want to solve this for sufficiently large value of n such that LHS ~= RHS.
I know the values of LHS and G1 -> Ginf but cannot understand how could I compute the value of lambda here.
I tried looking at numpy polynomial functions but could not find a function that is relevant here.
The following glosses over the fact that I do not 100% understand the coefficient notation G_t:t+n (what kind of dependency is that supposed to indicate exactly?)
Obviously, the solution will depend on coefficients. If as your example suggests, the coefficients are all equal above some index n_0 then your r.h.s. expression is a telescoping sum and equal to G_t:1 + sum_1^n_0 [G_t:n - G_t:n+1] l^n`. Be sure to note that this sum is finite, so you know how to proceed from here.
One caveat: you must have |l| < 1 otherwise the series does not converge and the r.h.s. is undefined, although some kind of continuation argument may be possible.

Obtaining coefficients of complex expressions in sympy

I have a relatively simple complex sympy expression which one can easily read the coefficients off of the variables. However coeff function does not appear to be working correctly
import sympy as sp
a,b = sp.symbols("a, b")
expr = 2640.0*a - 4.5*(1 + 1j)*(264.0*a + 264.0*b) - 4.5*(+1 - 1j)*(264.0*a + 264.0*b)
print(expr.coeff(a))
> 2640.00000000000
print(sp.simplify(expr))
> 264.0*a - 2376.0*b
I would expect the output of expr.coeff(a) to return 264.0 but it clearly isnt? Any help is appreciated.
coeff gives coefficients of the expression at the top level. If you use expand before looking for the coefficient then you will get the mathematical (not expression-dependent-literal) coefficient. If you know the expression is linear in the symbol of interest, you could also differentiate once:
>>> expr.diff(a)
264.000000000000
>>> expr.expand().coeff(a)
264.000000000000
Poly automatically expands expressions and allows queries for monomials, too:
>>> Poly(expr).coeff_monomial(a)
264.000000000000
Your first expression has 2640.0 as the coefficient of a. As you can see, the coefficient becomes zero only after simplifying it. Indeed, if you print the coefficient after simplifying the expression, you get 264.0
import sympy as sp
a,b = sp.symbols("a, b")
expr = 2640.0*a - 4.5*(1 + 1j)*(264.0*a + 264.0*b) - 4.5*(+1 - 1j)*(264.0*a + 264.0*b)
print(expr.coeff(a))
# 2640.00000000000
print(sp.simplify(expr))
# 264.0*a - 2376.0*b
print(sp.simplify(expr).coeff(a)) # <--- Simplified expression
# 264.000000000000

Sympy's subs limitations

I am working with some long equations but not really complex, and I wanted to use sympy to simplify and "factorize" them. But I have encountered a few problems. Here is a list of some minimal examples:
Problem 1: symmetry
from sympy import *
from __future__ import division
a = symbols('a')
b = symbols('b')
expr = 1/12*b + 1
expr.subs(1/12*b, a)
expr.subs(b*1/12, a)
The first line gives the expected result (ie. a+1) while in the second one there is no substitution.
Problem 2: factorized expressions
Some parts of the expression are factorized and when I expand the expression they get simplified, thus making the substitution impossible. For example
(((x+1)**2-x).expand()).subs(x**2+2*x, y+1)
will give x^2+x+1 and what I am looking for is y+2-x.
Question
Is there a way to solve these problems ? Or maybe I should use another symbolic mathematical tool ? Any suggestions are welcomed.
There is a major gotcha in SymPy, which is that, because of the way Python works, number/number gives a floating point (or does integer division if you use Python 2 and don't from __future__ import division).
In the first case and in your original expression, Python evaluates 1/12*b from left to right. 1/12 is evaluated by Python to give 0.08333333333333333, which is then multiplied by b. In the second case, b*1 is evaluated as b. Then b/12 is evaluated by SymPy (because b is a SymPy object), to give Rational(1, 12)*b.
Due to the inexact nature of floating point numbers, SymPy does not see the float 0.08333333333333333 as equal to the rational 1/12.
There is some more discussion of this issue here. As a workaround, you should avoid direct integer/integer without wrapping it somehow, so that SymPy can create a rational. The following will all create a rational:
b/12
Rational(1, 12)*b
S(1)/12*b
For (((x+1)**2-x).expand()).subs(x**2+2*x, y+1) the issue is that x**2 + 2*x does not appear exactly in the expression, which is x**2 + x + 1. SymPy generally only replaces things that it sees exactly.
It seems you don't mind adding and subtracting an x to make the replacement work. So I would suggest doing instead (((x+1)**2-x).expand()).subs(x**2, y+1 - 2*x). By only substituting a single term (x**2), the substitution will always work, and the 2*x will cancel out to leave whatever x term remains (in this case, -x).
Here's a possible solution to your problems:
from sympy import *
a = symbols('a')
b = symbols('b')
expr = 1 / 12 * b + 1
print(expr.subs((1 / 12) * b, a))
print(expr.subs(b * (1 / 12), a))
x = symbols('x')
y = symbols('y')
expr = ((x + 1)**2 - x).expand()
print(expr.subs(x**2 + x, y - x + 1))
Regarding problem 1, note that 1/12*b and b*1/12 are not the same thing in sympy. The first is a floating number mutliplied by a symbol, whereas the second is an exact symbolic expression (you can check it out by a simple print statement). Since expr contains 1/12*b, it is not surprising that the second subs does not work.
Regarding problem 2, the subs rule you provide is ambiguous. In particular the substitution rule implies that equation x**2+2*x==y+1. However, this equation has many interpretations, e.g,
x**2 == y + 1 - 2*x (this is the one you consider),
x**2 + x == y + 1 - x,
x == (y + 1 - x**2)/2,
For this reason, I consider sympy refusing to perform a substitution is actually a correct approach.
If it is the first interpretation you want, it is better to explicitly provide it in the subs rule, i.e.,
(((x+1)**2-x).expand()).subs(x**2, -2*x + y + 1)
-x + y + 2

How can I use sympy to find the error in approximation of a definite integral?

Our assignment is to use sympy to evaluate the exact definite integral of a function and then compare it with the approximation of the definite integral obtained from another python function we wrote. With simple polynomial functions my code works fine, but with a complicated sine function it keeps either breaking or returning nan.
from numpy import *
def simpson(f,a,b,n):
if n<=0 or n%2!=0:
print('Error: the number of subintervals must be a positive even number')
return float('NaN')
h = float(b - a) / float(n)
x = arange(a,b+h,h)
fx = f(x)
fx[1:n:2] *= 4.0
fx[2:n:2] *= 2.0
return (h/3.)*sum(fx)
this is in one file (simpandtrap) and gives the approximation for the definite integral of f from a to b using a simpson's rule approximation with n subintervals
from pylab import *
def s(x):
return x*sin(3./(x+(x==0)))
This is the function giving me trouble, in a file called assignment8functions
import assignment8functions as a
import SimpAndTrap as st
import sympy as sp
x = sp.symbols('x')
Exact_int_q = sp.integrate(a.q(x),(x,0,2)).evalf(25)
Exact_int_s = sp.integrate(x*sp.sin(3./(x)),(x,0,2)).evalf(25)
q(x) is another function we're supposed to use that everything works fine for - it's just a polynomial. When I try to do the integration the same way it breaks, so I had to put the function for s(x) directly into the call instead of importing the one from the other file
n = a.array([10,100,1000,10000,10000,1000000])
s_error_simp_array = a.zeros(6)
for i in a.arange(6):
s_error_simp_array[i] = abs(Exact_int_s - st.simpson(a.s,0,2,n[i])
here I try to find the error in the approximation. the problem is first of all that Exact_int_s is apparently -4.5*Si(zoo) + 8.16827746848576, and I have no idea what that's supposed to mean, and also that the simpson function always returns nan.
I know it's a lot of words and code, but does anybody know what's wrong?
To avoid the answer -4.5*Si(zoo)+ 8.--- just start the integration at a small positive number, e.g.:
x = sp.Symbol('x')
print sp.integrate( x * sin(3./x), (x, 0.000001, 2) )
and you'll get an answer like 1.0996940...
You can justify this because |s(x)| <= x for small x, so the interval [0, epsilon] can't contribute that much.
Btw - your simpson implemention seems to check out.

Categories