(python) solving transcendental equation - python

i need to solve following equation:
0 = -1 / x**0.5) - 2 * log((alpha * x**0.5) + beta)
alpha and beta are given, i just need to iterate x until a certain extent.
I'm not a great python programmer, but like to implement this one.
How might this be possible?
Best regards

The smartest to do would be to implement a solve function like Stanislav recommended. You can't just iterate over values of x until the equation reaches 0 due to Floating Point Arithmetic. You would have to .floor or .ceil your value to avoid an infinity loop. An example of this would be something like:
x = 0
while True:
x += 0.1
print(x)
if x == 10:
break
Here you'd think that x eventually reaches 10 when it adds 0.1 to 9.9, but this will continue forever. Now, I don't know if your values are integers or floats, but what I'm getting at is: Don't iterate. Use already built solve libraries.

Related

How do I evaluate this equation in z3 for python

I'm trying to evaluate a simple absolute value inequality like this using z3.
x = Int("x")
y = Int("y")
def abs(x):
return If(x >= 0,x,-x)
solve(abs( x / 1000 - y / 1000 ) < .01, y==1000)
The output is no solution every time. I know this is mathematically possible, I just can't figure out how z3 does stuff like this.
This is a common gotcha in z3py bindings. Constants are "promoted" to fit into the right type, following the usual Python methodology. But more often than not, it ends up doing the wrong conversion, and you end up with a very confusing situation.
Since your variables x and y are Int values, the comparison against .01 forces that constant to be 0 to fit the types, and that's definitely not what you wanted to say. The general advice is simply not to mix-and-match arithmetic like this: Cast this as a problem over real-values, not integers. (In general SMTLib doesn't allow mixing-and-matching types in numbers, though z3py does. I think that's misguided, but that's a different discussion.)
To address your issue, the simplest thing to do would be to wrap 0.01 into a real-constant, making the z3py bindings interpret it correctly. So, you'll have:
from z3 import *
x = Int("x")
y = Int("y")
def abs(x):
return If(x >= 0,x,-x)
solve(abs( x / 1000 - y / 1000 ) < RealVal(.01), y==1000)
Note the use of RealVal. This returns:
[x = 1000, y = 1000]
I guess this is what you are after.
But I'd, in general, recommend against using conversions like this. Instead, be very explicit yourself, and cast this as a problem, for instance, over Real values. Note that your division / 1000 is also interpreted in this equation as an integer division, i.e., one that produces an integer result. So, I'm guessing this isn't really what you want either. But I hope this gets you started on the right path.
Int('a') < 0.01 is turned (rightly or wrongly) into Int('a') < 0 and clearly the absolute value can never be smaller than 0.
I believe you want Int('a') <= 0 here.
Examples:
solve(Int('a') < 0.01, Int('a') > -1)
no solution
solve(Int('a') <= 0.01, Int('a') > -1)
[a = 0]
Int('a') < 0.01
a < 0

When I try to solve a equation python only uses integers

I am working on a new project, it is like a math site. I am trying to create a program that will solve equations.
It is working normally with simple equations for example x + 10 = 12, however when I try to do equations with exponents like x**2 + 3 = 5 it doesn't give me anything. I believe that this python code doesn't work with decimals.
Code in below
import math
def solve():
x = -1000
while x < 1001:
if x**2 + 1 == 4:
print("x = " + str(x))
x += 1
solve()
I expect the output to be 1.73205080757 and -1.73205080757.
However I get nothing (Because it couldn't find an answer).
You're expecting an answer that's between 1 & 2. You're starting at -1000 and incrementing by 1. So you'll go from -1000 to 0 to 1 to 2 to 3....skipping over your expected answer altogether.
You should be using something like: https://en.wikipedia.org/wiki/Newton%27s_method
(With floats i.e x=1.0)
Looking at your code, your minimal step is 1 (x was increased by x += 1), hence x can be only integer. There is no such integer can full-fill your condition x**2 + 1 == 4
this will only check integer values from x = - 1000 to x = 1000, ie it will ask is -1000 the answer? No, is -999 the answer? No etc, and never try 1.7 or 1.73 or 1.73...! The answer is a float not an integer, so the method as written can't possibly get it. You would need somehow to iterate closer and closer answers. This is a question of mathematical algorithm design I think, you can first look up math formulae how to approximate quadratic solutions (probably some 17th century mathematician did the formula!), then try convert this formula into Python. If you don't know about float, int, "duck typing" in Python difference, try googling this also may help you.
The code doesn't give nor will give the solution you expect because of two reasons:
The while loop increments x by 1 at each step, so there is no way x can be a float number. It will always be an integer.
The solution you expect for this case has infinite decimals, so even if x were a float, it could never be the desired value in order to solve the equation.
As a remark/suggestion, if you are trying to solve an equation in python, why don't you just create a function that give the result to an equation of the form: x^2 +a = b. The following code should be an example:
import numpy as np
def solve_prueba(a,b):
"""
The function solves a function of the form x^2 + a = b
"""
x = np.sqrt((b-a))
return x
This way is much more time effective rather than create a while loop has to pass over all the numbers with their infinite decimals to give the solution to a given equation.
Good luck!
It is not necessary to start at -1000 and go up to 1000 since you are looking for a value from 1 to 2. In your code, you increment with 1, which means that x will never be a decimal value. You could however increment with a very small number (e.g.) x += 0.0000000000001.
If you use this small increment, you should probably use math.isclose() instead of ==, because small float values tend to have some precision error. Like in your expected answer where you expect the outcome to be 1.73205080757 altough 1.73205080757**2 + 1 == 4.000000000003889 and not 4.
Using math.isclose((x**2 + 3), 4, rel_tol=1e-9) like this, it checks if the calculation from x**2 + 3 is somewhere close to 4 with a tolerance of 1e-9, which would output the values that you expect from this equation.
So for your code:
import math
def solve():
x = -1000
while x < 1001:
if math.isclose((x**2 + 1), 4, rel_rol=1e-9):
print("x = " + str(x))
x += 0.0000000000001
solve()

Adding lazy constraint in python-Gurobi interface

I am trying to add some lazy constraints to the first stage of a stochastic programming problem. For example, the optimal solution shows me that locations 16 and 20 are chosen together which I don't want to so I want to add a lazy constraint as follows:
First Stage
x1 + x2 + ... + x40 = 5
z_i,l <= x_i i=1,..,40 and l=1,2
Second Stage
....
def mycallback(model,where):
if where == GRB.Callback.MIPSOL:
sol = model.cbGetSolution([model._vars[s] for s in range(1,40)])
if sol[16] + sol[20] == 2:
Exp = LinExpr([(1,model._vars[16]),(1,model._vars[20])])
model.cbLazy(Exp <= 1)
model._vars = x
model.optimize(mycallback)
But after running this function, locations 16 and 20 are still in the optimal solution. Could you please let me know how should I attack this issue?
In your code, the test
if sol[16] + sol[20] == 2:
is comparing the sum of two floating point numbers with an integer using equality. Even if you declare decision variables to be integer, the solution values are floating point numbers. The floating point numbers don't even need to have integer values. Gurobi has a parameter IntFeasTol, which determines how far a value can be from 0 or 1 and still be considered binary. The default is 1e-5, so 0.999991 would be considered an integer. Your check should something like
if sol[16] + sol[20] > 1.5:

Compute cosine without import math in python

I have a general idea of what to do, but my code is a mess and I'm having some trouble writing the algorithm in python for
cos(x)=1-(x^2)/2!+(x^4)/4!-(x^6)/6!+...
where x is in radians, computing cos(x) after 20 terms using while loops. So far what I've written is
x = float(input("Enter a value for x in degrees."))
x = (x*3.14159)/180
num_of_terms = 0
num = 1.0 ##numerator
y = 1.0
cosx = 1.0
while num_of_terms<1:
num_of_terms+=1
cosx = (num/y)
while num_of_terms>=1 and num_of_terms<=20:
num_of_terms+=1
num = num*(x*x)
y = y*num_of_terms*(num_of_terms-1)
if num_of_terms%2==0:
cosx = cosx+(-num/y)
else:
cosx = cosx+(num/y)
print(cosx)
I don't know how close I even am to being correct (I know it's wrong in at least some places so I can't properly check using math.cos) but the main question I have is how to switch from positive --> negative each term. The assignment states that I cannot use exponentiation operators, and before I was trying to do something like
x = float(input("Enter a value for x in degrees."))
x = (x*3.14)/180
num_of_terms = 0
y = 0
z = 1
cosx = ((-1)**(z-1))*((x**z)/(y))
so that the sign would switch for every other term. Now I have (as you can see above)
if num_of_terms%2==0:
cosx = cosx+(-num/y)
else:
cosx = cosx+(num/y)
which is incorrect, or at least the output I'm getting is incorrect.
You can handle the sign quite simply:
sign = -1
while num_of_terms <= 20:
sign = -sign
...
cosx += sign * num/y
You also have a structure problem in your loops: the first loop will terminate after one iteration ... except you've properly prevented it from getting back there. This is poor use of a loop.
Just initialize your variables before the loop, and then proceed as expected. Since you know how many times to iterate, use a for instead of a while.
cosx = (num/y)
for num_of_terms in range(1, 21):
...
You will find other computational problems in your code. Print out values each time through the loop to help track your execution and computations. At the start, just go through 3 or 4 times instead of 20.
For the factorial, keep a running product: it's like a running sum, except that you initialize it at 1, and multiply each time through the loop.
Okay; stick with the while. Now, manage your loop index and computational index. If you're doing term #1, what should the exponent be? What numbers do you multiply into y? Now identify the same values for term #2 and term #3.
More directly, stick in a print statement to track num_of_terms, y, and cosx. When you're doing term #3, what is y? It should be 4! or 6! (depending on how you number your terms), but it's not. Where did you go wrong?
Your problem is in the computation of the factorial. You're multiplying by num_of_terms, which only increments by one each time through the loop - you need something that changes by 2 each time through the loop. At least you're correctly multiplying both that number and the number-1.

Python Pi approximation

So I have to approximate Pi with following way: 4*(1-1/3+1/5-1/7+1/9-...). Also it should be based on number of iterations. So the function should look like this:
>>> piApprox(1)
4.0
>>> piApprox(10)
3.04183961893
>>> piApprox(300)
3.13825932952
But it works like this:
>>> piApprox(1)
4.0
>>> piApprox(10)
2.8571428571428577
>>> piApprox(300)
2.673322240709928
What am I doing wrong? Here is the code:
def piApprox(num):
pi=4.0
k=1.0
est=1.0
while 1<num:
k+=2
est=est-(1/k)+1/(k+2)
num=num-1
return pi*est
This is what you're computing:
4*(1-1/3+1/5-1/5+1/7-1/7+1/9...)
You can fix it just by adding a k += 2 at the end of your loop:
def piApprox(num):
pi=4.0
k=1.0
est=1.0
while 1<num:
k+=2
est=est-(1/k)+1/(k+2)
num=num-1
k+=2
return pi*est
Also the way you're counting your iterations is wrong since you're adding two elements at the time.
This is a cleaner version that returns the output that you expect for 10 and 300 iterations:
def approximate_pi(rank):
value = 0
for k in xrange(1, 2*rank+1, 2):
sign = -(k % 4 - 2)
value += float(sign) / k
return 4 * value
Here is the same code but more compact:
def approximate_pi(rank):
return 4 * sum(-float(k%4 - 2) / k for k in xrange(1, 2*rank+1, 2))
Important edit:
whoever expects this approximation to yield PI -- quote from Wikipedia:
It converges quite slowly, though – after 500,000 terms, it produces
only five correct decimal digits of π
Original answer:
This is an educational example. You try to use a shortcut and attempt to implement the "oscillating" sign of the summands by handling two steps for k in the same iteration. However, you adjust k only by one step per iteration.
Usually, in math at least, an oscillating sign is achieved with (-1)**i. So, I have chosen this for a more readable implementation:
def pi_approx(num_iterations):
k = 3.0
s = 1.0
for i in range(num_iterations):
s = s-((1/k) * (-1)**i)
k += 2
return 4 * s
As you can see, I have changed your approach a bit, to improve readability. There is no need for you to check for num in a while loop, and there is no particular need for your pi variable. Your est actually is a sum that grows step by step, so why not call it s ("sum" is a built-in keyword in Python). Just multiply the sum with 4 in the end, according to your formula.
Test:
>>> pi_approx(100)
3.1514934010709914
The convergence, however, is not especially good:
>>> pi_approx(100) - math.pi
0.009900747481198291
Your expected output is flaky somehow, because your piApprox(300) (should be 3.13825932952, according to your) is too far away from PI. How did you come up with that? Is that possibly affected by an accumulated numerical error?
Edit
I would not trust the book too much in regard of what the function should return after 10 and 300 iterations. The intermediate result, after 10 steps, should be rather free of numerical errors, indeed. There, it actually makes a difference whether you take two steps of k at the same time or not. So this most likely is the difference between my pi_approx(10) and the books'. For 300 iterations, numerical error might have severely affected the result in the book. If this is an old book, and they have implemented their example in C, possibly using single precision, then a significant portion of the result may be due to accumulation of numerical error (note: this is a prime example for how bad you can be affected by numerical errors: a repeated sum of small and large values, it does not get worse!).
What counts is that you have looked at the math (the formula for PI), and you have implemented a working Python version of approximating that formula. That was the learning goal of the book, so go ahead and tackle the next problem :-).
def piApprox(num):
pi=4.0
k=3.0
est=1.0
while 1<num:
est=est-(1/k)+1/(k+2)
num=num-1
k+=4
return pi*est
Also for real task use math.pi
Here is a slightly simpler version:
def pi_approx(num_terms):
sign = 1. # +1. or -1.
pi_by_4 = 1. # first term
for div in range(3, 2 * num_terms, 2): # 3, 5, 7, ...
sign = -sign # flip sign
pi_by_4 += sign / div # add next term
return 4. * pi_by_4
which gives
>>> for n in [1, 10, 300, 1000, 3000]:
... print(pi_approx(n))
4.0
3.0418396189294032
3.1382593295155914
3.140592653839794
3.1412593202657186
While all of these answers are perfectly good approximations, if you are using the Madhava-Leibniz Series than you should arrive at ,"an approximation of π correct to 11 decimal places as 3.14159265359" within in first 21 terms according to this website: https://en.wikipedia.org/wiki/Approximations_of_%CF%80
Therefore, a more accurate solution could be any variation of this:
import math
def estimate_pi(terms):
ans = 0.0
for k in range(terms):
ans += (-1.0/3.0)**k/(2.0*k+1.0)
return math.sqrt(12)*ans
print(estimate_pi(21))
Output: 3.141592653595635

Categories