Problem:
We know that the apothem "a", of a regular polygon with "n" sides, can be calculated from the side "s" by the following formula:
a = s / (2*tan(π/n))
Define the perimeterPentagon function that, given a non-negative value for the apothem, returns the perimeter of the respective regular pentagon, rounding the result to three decimal places.
For example:
Test:
print(perimeterPentagon(3))
Result:
21,796
Solution attempt:
import math
def perimeterPentagon(apothem):
if apothem > 0:
s = apothem*(2*math.tan(math.pi/5))
return (s/2*math.tan(math.pi/5))
else:
return []
What have I done wrong here?
Related
I am not pratice in Sympy manipulation.
I need to find roots on particular poly:
-4x**(11/2)-24x**(9/2)-16x**(7/2)+2x**(5/2)+16x**(5)+23x**(4)+5x**(3)-x**(2)
I verified that I have 2 real solution and I find one of them with Sympy function
nsolve(mypoly,x,1).
Why the previous step doesn't look the other?
How can I proceed to find ALL roots?
Thank you to all for assistance
A.
To my knowledge, nsolve looks in the proximity of the provided initial guess to find one root for each equations.
I would plot the expression to find suitable initial guesses:
from sympy import *
from sympy.plotting import PlotGrid
expr = -4*x**(S(11)/2)-24*x**(S(9)/2)-16*x**(S(7)/2)+2*x**(S(5)/2)+16*x**(5)+23*x**(4)+5*x**(3)-x**(2)
p1 = plot(expr, (x, 0, 0.5), adaptive=False, n=1000, ylim=(-0.01, 0.05), show=False)
p2 = plot(expr, (x, 0, 5), adaptive=False, n=1000, ylim=(-200, 200), show=False)
PlotGrid(1, 2, p1, p2)
Now, we can do:
nsolve(expr, x, 0.2)
# out: 0.169003536680445
nsolve(expr, x, 4)
# out: 4.28968831654177
EDIT: to find all roots (even the complex one), we can:
compute the derivative of the expression.
convert both the expression and the derivative to numerical functions with sympy's lambdify.
visually inspect the expression in the complex plane to determine good initial values for the root finding algorithm. I'm going to use this plotting module, SymPy Plotting Backend which exposes a very handy function, plot_complex, to generate domain coloring plots. In particular, I will plot alternating black and white stripes corresponding to modulus.
use scipy's newton method to compute the actual roots. EDIT: I just discovered that nsolve works too :)
# step 1 and 2
f = lambdify(x, expr)
f_der = lambdify(x, expr.diff(x))
# step 3
from spb import plot_complex
r = (x, -1-0.8j, 4.5+0.8j)
w = r[1].real - r[2].real
h = r[1].imag - r[2].imag
# number of discretization points, watch out memory usage
n1 = 1500
n2 = int(h / w * n1)
plot_complex(expr, r, {"interpolation": "spline36"}, grid=False, coloring="e", n1=n1, n2=n2, size=(10, 5))
In the above picture we see circular stripes getting bigger and deforming. The center of these circular stripes represent a pole or a zero. But this is an easy case: there are no poles. So, from the above pictures we count 7 zeros. We already know 3, the two computed above and the value 0. Let's find the others:
from scipy.optimize import newton
r1 = newton(f, x0=-0.9+0.1j, fprime=f_der)
r2 = newton(f, x0=-0.9-0.1j, fprime=f_der)
r3 = newton(f, x0=0.6+0.6j, fprime=f_der)
r4 = newton(f, x0=0.6-0.6j, fprime=f_der)
for r in (r1, r2, r3, r4):
print(r, ": is it a zero?", expr.subs(x, r).evalf())
# out:
# (-0.9202719950522663+0.09010409402273806j) : is it a zero? -8.21787666002984e-15 + 2.06697764417957e-15*I
# (-0.9202719950522663-0.09010409402273806j) : is it a zero? -8.21787666002984e-15 - 2.06697764417957e-15*I
# (0.6323265751497729+0.6785871500619469j) : is it a zero? -2.2103533615688e-15 - 2.77549897301442e-15*I
# (0.6323265751497729-0.6785871500619469j) : is it a zero? -2.2103533615688e-15 + 2.77549897301442e-15*I
As you can see, inserting those values into the original expression get values very very close to zero. It is perfectly normal to see these kind of errors.
I just discovered that you can use also use nsolve instead of newton to compute complex roots. This makes step 1 and 2 unnecessary.
nsolve(expr, x, -0.9+0.1j)
# out: −0.920271995052266+0.0901040940227375𝑖
I'm solving an eigenvalue problem when the matrix and the eigenvectors are time dependent. The matrix has dimension 8x8 and is hermitian. The time dependent matrix has the form:
import sympy as sp
t, lbd = sp.symbols(r't,\lambda', real=True)
Had = ...
print(repr(Had))
Matrix([[2*t,0, 0, 0, 0, 0, 0,0],
[ 0,-2*t, 2*t*(1 - t), 0, 0, 0,0,0],
[0, 2*t*(1 - t),0,0, 2 - 2*t, 0,0,0],
[0,0,0,0, 0, 2 - 2*t, 0,0],
[0,0,2 - 2*t,0,0,0,0,0],
[0,0,0, 2 - 2*t,0,0, 2*t*(1 - t),0],
[0,0,0,0,0, 2*t*(1 - t),-2*t,0],
[0,0,0,0,0,0,0,2*t]])
Now the characteristic polynomial has the following for:
P = p.simplify(sp.collect(sp.factor(Had.charpoly(lbd).as_expr()),lbd))
and get
Then I choose the second term and find the solution for lambda:
P_list = sp.factor_list(P)
a,b = P_list[1]
eq,exp = sp.simplify(b)
sol = sp.solve(eq)
With that I get the roots in a list:
r_list = []
for i in range(len(sol)):
a = list(sol[i].values())
r_list.append(a[0])
Solving the problem using sp.eigenvecs:
val_mult_vec = Had.eigenvects()
e_vals = []
mults = []
e_vecs = []
for i in range(len(val_mult_vec)):
val, mult, [vec_i, vec_j] = val_mult_vec[i]
e_vals.append(val)
e_vals.append(val)
mults.append(mult)
e_vecs.append(vec_i)
e_vecs.append(vec_j)
Solving the eigenvectors I get complicated expressions like this:
But I know that this complicated expression can be expressed in terms of the solution of the second term in the characteristic polynomial something like this:
Where r1 are one of the roots of that equation. With the solution to the characteristic polynomial how can I rewrite the eigenvectors in a simplified way like the last image using sympy? rewrite e_vec[i] in terms of r_list[j]
Seems like you want to obtain a compact version of the eigenvectors.
Recepy:
We can create as many symbols as the number of eigenvalues. Each symbol represents an eigenvalue.
Loop over the eigenvectors and for each of its elements substitute the long eigenvalue expression with the respective symbol.
r_symbols = symbols("r0:%s" % len(e_vals))
final_evecs = []
for vec, val, s in zip(e_vecs, e_vals, r_symbols):
final_evecs.append(
vec.applyfunc(lambda t: t.subs(val, s))
)
final_evecs is a list containing eigenvectors in a compact notation.
Let's test one output:
final_evecs[7]
I have a list of objects with several attributes (strLabel, intX, intY) in python. I have to get the leftmost, rightmost, topmost, and bottommost values from the list, which can be a single point or multiple points. I was thinking of having a separate function that sorts the list based on intX and intY, then returning the most positive and most negative objects. How do I return those objects if there are more than 1?
Create functions to determine the property you want to get the max or min of and use it as a key:
To determine how right a point is we can look at its' x value:
def rightness(xy):
x, y = xy
return x
Similarly how top it is:
def topness(xy):
x, y = xy
return y
A set of points to test:
points = {
(1,3),
(0, 0),
(5,3),
(1,-2),
}
And simply using python's built-ins:
rightmost = max(points, key=rightness)
leftmost = min(points, key=rightness)
topmost = max(points, key=topness)
bottommost = min(points, key=topness)
The result:
print('leftmost: %s,rightmost: %s, topmost: %s, bottommost:%s' % (
leftmost, rightmost, topmost, bottommost))
To return more than one you could find the value you're looking for, and extract similar values from the set of points, suppose bottommost point is at (1, -2) you could do:
bottommosts = [p for p in points if p[1] == -2]
I am trying to write a function to calculate the binomial coefficients using this formula:
The problem I am having is that I can not mange to get the correct answer. This is an example of two ways I have tried to write the function.
def binomial(n, i):
total = 0
for j in range(1, (n-i+1)):
n = float(n)
i = float(i)
j = float(j)
product = (i+j) / j
if total == 0:
total = product
else:
total = total * product
print '%.f' %total
or like this using numpy
import numpy as np
def binomial_np(n, i):
array = np.zeros(n-i+1)
for j in range(1, (n-i+1)):
s = float(j)
n = float(n)
i = float(i)
array[j] = (i+s)/s
array = array[1 : ]
array = np.prod(array)
print '%.f' %array
Both of the functions produces almost the correct result. After looking around a bit on the forum I did find some other examples that do produce the correct result, like this one from Python Binomial Coefficient
import math
x = int(input("Enter a value for x: "))
y = int(input("Enter a value for y: "))
if y == x:
print(1)
elif y == 1: # see georg's comment
print(x)
elif y > x: # will be executed only if y != 1 and y != x
print(0)
else: # will be executed only if y != 1 and y != x and x <= y
a = math.factorial(x)
b = math.factorial(y)
c = math.factorial(x-y) # that appears to be useful to get the correct result
div = a // (b * c)
print(div)
The real question I have from this is if there is something wrong with the way I have written the formulas, or if it just isnt possible to get the correct answer this way because of how float's and number of decimals work in Python. Hope someone can point me in the right direction on what I am doing wrong here.
The slight discrepancies seem to come from using floating point arithmetic. However, if you are sure that n and i are integers, there is no need at all for floating point values in your routine. You can just do
def binomial(n, i):
result = 1
for j in range(1, n-i+1):
result = result * (i+j) // j
return result
This works because the product of 2 consecutive numbers is divisible by 1*2, the product of 3 consecutive numbers is divisible by 1*2*3, ... the product of n-i consecutive numbers is divisible by (n-i)!. The calculations in the code above are ordered to that only integers result, so you get an exact answer. This because my code does not calculate (i+j)/j as your code does; it calculates result * (i+j) and only then divides by j. This code also does a fairly good job of keeping the integer values as small as possible, which should increase speed.
If course, if n or i is float rather than integer, this may not work. Also note this code does not check that 0 <= i <= n, which should be done.
I would indeed see float precision as the main problem here. You do floating point division, which means your integers may get rounded. I suggest you maintain the numerator and denominator as separate numbers, and do the division in the end. Or, if the numbers get too big using this approach, write some gcd computation and cancel common factors along the way. But only do integer divisions (//) to avoid loss of precision.
I'm a beginner with python as my first language trying to factor a
quadratic where the equation provides the result in
factor form for example:
x^2+5x+4
Output to be (or any factors in parenthesis)
(x+4)(x+1)
So far this only gives me x but not a correct value either
CODE
def quadratic(a,b,c):
x = -b+(((b**2)-(4*a*c))**(1/2))/(2*a)
return x
print quadratic(1,5,4)
Your parentheses are in the wrong places, you're only calculating and returning one root, and (most importantly), you're using **(1/2) to calculate the square root. In Python 2, this will evaluate to 0 (integer arithmetic). To get 0.5, use (1./2) (or 0.5 directly).
This is (slightly) better:
def quadratic(a,b,c):
x1 = (-b+(b**2 - 4*a*c)**(1./2))/(2*a)
x2 = (-b-(b**2 - 4*a*c)**(1./2))/(2*a)
return x1, x2
print quadratic(1,5,4)
and returns (-1.0, -4.0).
To get your parentheses, put the negative of the roots in an appropriate string:
def quadratic(a,b,c):
x1 = (-b+(b**2 - 4*a*c)**(1./2))/(2*a)
x2 = (-b-(b**2 - 4*a*c)**(1./2))/(2*a)
return '(x{:+f})(x{:+f})'.format(-x1,-x2)
print quadratic(1,5,4)
Returns:
(x+1.000000)(x+4.000000)
This will help you:
from __future__ import division
def quadratic(a,b,c):
x = (-b+((b**2)-(4*a*c))**(1/2))/(2*a)
y = (-b-((b**2)-(4*a*c))**(1/2))/(2*a)
return x,y
m,n = quadratic(1,5,4)
sign_of_m = '-' if m > 0 else '+'
sign_of_n = '-' if n > 0 else '+'
print '(x'+sign_of_m+str(abs(m))+')(x'+sign_of_n+str(abs(n))+')'
Output
(x+1.0)(x+4.0)
Let me know if it helps.