Python Trig Functions Return Complex Numbers? - python

I am writing code that accepts the degree by which a motor turns and uses that data to calculate the distance covered by the wheels (using distance = no. of rotations * distance covered per rotation).
It then makes an error adjustment (taking into consideration environmental factors such as friction).
Finally, using trigonometry, it calculates the distance moved along the x-axis and y-axis.
All the above is done by the function straight contained within the class CoordinateManager. This function is called by an instance of another class.
class CoordinateManager:
goalcord = [20, 0]
def __init__(self):
self.curcord = [0, 0]
self.theta = 0
def get_compass_angle(self):
compass = Sensor(address='in2')
return compass.value(0)
def turn(self, iangle, fangle):
self.theta = self.theta + (fangle-iangle)
def straight(self, turnangle):
d = turnangle*2*3.14*2/360
d = 1.8120132*(d**0.8938054)
thetarad = radians(self.theta)
dx = d*sin(thetarad)
dy = d*cos(thetarad)
self.curcord[0] += dx
self.curcord[1] += dy
Printing both d and self.theta shows that they contain correct values.
This must mean that the array self.curcord has valid values too. However, this has not been the case. Printing the two elements of self.curcord outputs complex numbers (some big float + another big floatj).
I can think of no logical explanation for this other than that the trigonometric functions must be returning complex numbers. However, I think the chances that a python built-in lib function returns wrong values are extraordinarily slim.
Is there any logical error that I may be overlooking?
Edit: I just tried changing the last two lines to:
self.curcord[0] += dx
self.curcord[1] += dy
I just tried using .real when displaying the values. Even though the values are real now, they are still wrong. I will look further into whether this is caused by some calculation error.

Since you said in the comments above that turnangle can be any integer, the problem can be directly traced to this line:
d = 1.8120132*(d**0.8938054)
Since turnangle can be negative, the value of d before this line is executed can also be negative; a negative value raised to an arbitrary decimal power is in general complex.
Therefore the problem does not lie with the trig functions at all. The above also leads me to believe that when you said
Printing both d and self.theta shows that they contain correct values
... you only did so after this line:
d = turnangle*2*3.14*2/360
This would explain why you wrongly thought the problem must lie elsewhere.
UPDATE:
It is a very bad habit to set a variable to some function of itself like you did. Try to use a different variable name to avoid confusion - as you saw above I had to refer to "this line" rather than by their variable names.
Perhaps something like this would work, assuming that the behaviour of the motor is the same regardless of the sign of turnangle?
d = sign(d) * 1.8120132 * (abs(d) ** 0.8938054)

Related

What is the best way to display numeric and symbolic expressions in python?

I need to produce calculation reports that detail step by step calculations, showing the formulas that are used and then showing how the results are achieved.
I have looked at using sympy to display symbolic equations. The problem is that a sympy symbol is stored as a variable, and therefore I cannot also store the numerical value of that symbol.
For example, for the formula σ=My/I , I need to show the value of each symbol, then the symbolic formula, then the formula with values substituted in, and finally the resolution of the formula.
M=100
y= 25
I=5
σ=My/I
σ=100*25/5
σ=5000
I’m new to programming and this is something I’m struggling with. I’ve thought of perhaps building my own class but not sure how to make the distinction the different forms. In the example above, σ is at one point a numerical value, one half of an symbolic expression, and also one half of a numerical expression.
Hopefully the following helps. This produces more or less what you want. You cannot get your fifth line of workings easily as you'll see in the code.
from sympy import *
# define all variables needed
# trying to keep things clear that symbols are different from their numeric values
M_label, y_label, l_label = ("M", "y", "l")
M_symbol, y_symbol, l_symbol = symbols(f"{M_label} {y_label} {l_label}", real=True)
M_value, y_value, l_value = (100, 25, 5)
# define the dictionary whose keys are string names
# and whose values are a tuple of symbols and numerical values
symbols_values = {M_label: (M_symbol, M_value),
y_label: (y_symbol, y_value),
l_label: (l_symbol, l_value)}
for name, symbol_value in symbols_values.items():
print(f"{name} = {symbol_value[1]}") # an f-string or formatted string
sigma = M_symbol * y_symbol / l_symbol
print(f"sigma = {sigma}")
# option 1
# changes `/5` to 5**(-1) since this is exactly how sympy views division
# credit for UnevaluatedExpr
# https://stackoverflow.com/questions/49842196/substitute-in-sympy-wihout-evaluating-or-simplifying-the-expression
sigma_substituted = sigma\
.subs(M_symbol, UnevaluatedExpr(M_value))\
.subs(y_symbol, UnevaluatedExpr(y_value))\
.subs(l_symbol, UnevaluatedExpr(l_value))
print(f"sigma = {sigma_substituted}")
# option 2
# using string substitution
# note this could replace words like `log`, `cos` or `exp` to something completely different
# this is why it is unadvised. The code above is far better for that purpose
sigma_substituted = str(sigma)\
.replace(M_label, str(M_value))\
.replace(y_label, str(y_value))\
.replace(l_label, str(l_value))
print(f"sigma = {sigma_substituted}")
sigma_simplified = sigma\
.subs(M_symbol, M_value)\
.subs(y_symbol, y_value)\
.subs(l_symbol, l_value)
print(f"sigma = {sigma_simplified}")
Also note that if you wanted to change the symbols_values dictionary to keys being the symbols and values being the numerical values, you will have a hard time or seemingly buggy experience using the keys. That is because if you have x1 = Symbol("x") and x2 = Symbol("x"), SymPy sometimes treats the above as 2 completely different variables even though they are defined the same way. It is far easier to use strings as keys.
If you begin to use more variables and choose to work this way, I suggest using lists and for loops instead of writing the same code over and over.

Finding a abstraction for repetitive code: Bootstrap analysis

Intro
There is a pattern that I use all the time in my Python code which analyzes
numerical data. All implementations seem overly redundant or very cumbersome or
just do not play nicely with NumPy functions. I'd like to find a better way to
abstract this pattern.
The Problem / Current State
A method of statistical error propagation is the bootstrap method. It works by
running the same analysis many times with slightly different inputs and look at
the distribution of final results.
To compute the actual value of ams_phys, I have the following equation:
ams_phys = (amk_phys**2 - 0.5 * ampi_phys**2) / aB - amcr
All the values that go into that equation have a statistical error associated
with it. These values are also computed from other equations. For instance
amk_phys is computed from this equation, where both numbers also have
uncertainties:
amk_phys_dist = mk_phys / a_inv
The value of mk_phys is given as (494.2 ± 0.3) in a paper. What I now do is
parametric bootstrap and generate R samples from a Gaussian distribution
with mean 494.2 and standard deviation 0.3. This is what I store in
mk_phys_dist:
mk_phys_dist = bootstrap.make_dist(494.2, 0.3, R)
The same is done for a_inv which is also quoted with an error in the
literature. Above equation is then converted into a list comprehension to yield
a new distribution:
amk_phys_dist = [mk_phys / a_inv
for a_inv, mk_phys in zip(a_inv_dist, mk_phys_dist)]
The first equation is then also converted into a list comprehension:
ams_phys_dist = [
(amk_phys**2 - 0.5 * ampi_phys**2) / aB - amcr
for ampi_phys, amk_phys, aB, amcr
in zip(ampi_phys_dist, amk_phys_dist, aB_dist, amcr_dist)]
To get the end result in terms of (Value ± Error), I then take the average and
standard deviation of this distribution of numbers:
ams_phys_val, ams_phys_avg, ams_phys_err \
= bootstrap.average_and_std_arrays(ams_phys_dist)
The actual value is supposed to be computed with the actual value coming in,
not the mean of this bootstrap distribution. Before I had the code replicated
for that, now I have the original value at the 0th position in the _dist
arrays. The arrays now contain 1 + R elements and the
bootstrap.average_and_std_arrays function will separate that element.
This kind of line occurs for every number that I might want to quote in my
writing. I got annoyed by the writing and created a snippet for it:
$1_val, $1_avg, $1_err = bootstrap.average_and_std_arrays($1_dist)
The need for the snippet strongly told me that I need to do some refactoring.
Also the list comprehensions are always of the following pattern:
foo_dist = [ ... bar ...
for bar in bar_dist]
It feels bad to write bar three times there.
The Class Approach
I have tried to make those _dist things a Boot class such that I would not
write ampi_dist and ampi_val but could just use ampi.val without having
to explicitly call this average_and_std_arrays functions and type a bunch of
names for it.
class Boot(object):
def __init__(self, dist):
self.dist = dist
def __str__(self):
return str(self.dist)
#property
def cen(self):
return self.dist[0]
#property
def val(self):
x = np.array(self.dist)
return np.mean(x[1:,], axis=0)
#property
def err(self):
x = np.array(self.dist)
return np.std(x[1:,], axis=0)
However, this still does not solve the problem of the list comprehensions. I
fear that I still have to repeat myself there three times. I could make the
Boot object inherit from list, such that I could at least write it like
this (without the _dist):
bar = Boot([... foo ... for foo in foo])
Magic Approach
Ideally all those list comprehensions would be gone such that I could just
write
bar = ... foo ...
where the dots mean some non-trivial operation. Those can be simple arithmetic
as above, but that could also be a function call to something that does not
support being called with multiple values (like NumPy function do support).
For instance the scipy.optimize.curve_fit function needs to be called a bunch of times:
popt_dist = [op.curve_fit(linear, mpi, diff)[0]
for mpi, diff in zip(mpi_dist, diff_dist)]
One would have to write a wrapper for that because it does not automatically loops over list of arrays.
Question
Do you see a way to abstract this process of running every transformation with
1 + R sets of data? I would like to get rid of those patterns and the huge
number of variables in each namespace (_dist, _val, _avg, ...) as this
makes passing it to function rather tedious.
Still I need to have a lot of freedom in the ... foo ... part where I need to
call arbitrary functions.

scipy.optimize.minimize chi squared python

So i am doing this assignment, where i am supposed to minimize the chi squared function. I saw someone doing this on the internet so i just copied it:
Multiple variables in SciPy's optimize.minimize
I made a chi-squared function which is a function in 3 variables (x,y,sigma) where sigma is random gaussian fluctuation random.gauss(0,sigma). I did not print that code here because on first sight it might be confusing (I used a lot of recursion). But i can assure you that this function is correct.
now this code just makes a list of the calculated minimization(Which are different every time because of the random gaussian fluctuation). But here comes the main problem. If i did my calculation correctly, we should get a list with a mean of 2 (since i have 2 degrees of freedom as you can see in this link: https://en.wikipedia.org/wiki/Chi-squared_test).
def Chi2(pos):
return Chi(pos[0],pos[1],1)
x_list= []
y_list= []
chi_list = []
for i in range(1000):
result = scipy.optimize.minimize(Chi2,[5,5]).x
x_list.append(result[0])
y_list.append(result[1])
chi_list.append(Chi2(result))
But when i use this code i get a list of mean 4, however if i add the method "Powell" i get a mean of 9!!
So my main question is, how is it possible these means are so different and how do i know which method to use to get the best optimization?
Because i think the error might be in my chisquare function i will show this one as well. The story behind this assignment is that we need to find the position of a mobile device and we have routers on the positions (0,0),(20,0),(0,20) and (20,20). We used a lot of recursion, and the graph of the chi_squared looked fine(it has a minimum on (5,5)
def perfectsignal(x_m,y_m,x_r,y_r):
return 20*np.log10(c / (4 * np.pi * f)) - 10 * np.log((x_m-x_r)**2 + (y_m-y_r)**2 + 2**2)
def signal(x_m,y_m,x_r,y_r,sigma):
return perfectsignal(x_m,y_m,x_r,y_r) + random.gauss(0,sigma)
def res(x_m,y_m,x_r,y_r,sigma,sigma2):
x = (signal(x_m,y_m,x_r,y_r,sigma) - perfectsignal(x_m,y_m,x_r,y_r))/float(sigma2);
return x
def Chi(x,y,sigma):
return(res(x,y,0,0,sigma,1)**2+res(x,y,20,0,sigma,1)**2+res(x,y,0,20,sigma,1)**2+res(x,y,20,20,sigma,1)**2)
Kees

Recursion not breaking

I am trying to solve Euler problem 18 where I am required to find out the maximum total from top to bottom. I am trying to use recursion, but am stuck with this.
I guess I didn't state my problem earlier. What I am trying to achieve by recursion is to find the sum of the maximum number path. I start from the top of the triangle, and then check the condition is 7 + findsum() bigger or 4 + findsum() bigger. findsum() is supposed to find the sum of numbers beneath it. I am storing the sum in variable 'result'
The problem is I don't know the breaking case of this recursion function. I know it should break when it has reached the child elements, but I don't know how to write this logic in the program.
pyramid=[[0,0,0,3,0,0,0,],
[0,0,7,0,4,0,0],
[0,2,0,4,0,6,0],
[8,0,5,0,9,0,3]]
pos=[0,3]
def downleft(pyramid,pos):#returns down left child
try:
return(pyramid[pos[0]+1][pos[1]-1])
except:return(0)
def downright(pyramid,pos):#returns down right child
try:
return(pyramid[pos[0]+1][pos[1]+1])
except:
return(0)
result=0
def find_max(pyramid,pos):
global result
if downleft(pyramid,pos)+find_max(pyramid,[pos[0]+1,pos[1]-1]) > downright(pyramid,pos)+find_max(pyramid,[pos[0]+1,pos[1]+1]):
new_pos=[pos[0]+1,pos[1]-1]
result+=downleft(pyramid,pos)+find_max(pyramid,[pos[0]+1,pos[1]-1])
elif downright(pyramid,pos)+find_max(pyramid,[pos[0]+1,pos[1]+1]) > downleft(pyramid,pos)+find_max(pyramid,[pos[0]+1,pos[1]-1]):
new_pos=[pos[0]+1,pos[1]+1]
result+=downright(pyramid,pos)+find_max(pyramid,[pos[0]+1,pos[1]+1])
else :
return(result)
find_max(pyramid,pos)
A big part of your problem is that you're recursing a lot more than you need to. You should really only ever call find_max twice recursively, and you need some base-case logic to stop after the last row.
Try this code:
def find_max(pyramid, x, y):
if y >= len(pyramid): # base case, we're off the bottom of the pyramid
return 0 # so, return 0 immediately, without recursing
left_value = find_max(pyramid, x - 1, y + 1) # first recursive call
right_value = find_max(pyramid, x + 1, y + 1) # second recursive call
if left_value > right_value:
return left_value + pyramid[y][x]
else:
return right_value + pyramid[y][x]
I changed the call signature to have separate values for the coordinates rather than using a tuple, as this made the indexing much easier to write. Call it with find_max(pyramid, 3, 0), and get rid of the global pos list. I also got rid of the result global (the function returns the result).
This algorithm could benefit greatly from memoization, as on bigger pyramids you'll calculate the values of the lower-middle areas many times. Without memoization, the code may be impractically slow for large pyramid sizes.
Edit: I see that you are having trouble with the logic of the code. So let's have a look at that.
At each position in the tree you want to make a choice of selecting
the path from this point on that has the highest value. So what
you do is, you calculate the score of the left path and the score of
the right path. I see this is something you try in your current code,
only there are some inefficiencies. You calculate everything
twice (first in the if, then in the elif), which is very expensive. You should only calculate the values of the children once.
You ask for the stopping condition. Well, if you reach the bottom of the tree, what is the score of the path starting at this point? It's just the value in the tree. And that is what you should return at that point.
So the structure should look something like this:
function getScoreAt(x, y):
if at the end: return valueInTree(x, y)
valueLeft = getScoreAt(x - 1, y + 1)
valueRight = getScoreAt(x + 1, y + 1)
valueHere = min(valueLeft, valueRight) + valueInTree(x, y)
return valueHere
Extra hint:
Are you aware that in Python negative indices wrap around to the back of the array? So if you do pyramid[pos[0]+1][pos[1]-1] you may actually get to elements like pyramid[1][-1], which is at the other side of the row of the pyramid. What you probably expect is that this raises an error, but it does not.
To fix your problem, you should add explicit bound checks and not rely on try blocks (try blocks for this is also not a nice programming style).

Tips on improving this function?

This may be quite a green question, but I hope you understand – just started on python and trying to improve. Anyways, wrote a little function to do the "Shoelace Method" of finding the area of a polygon in a Cartesian plane (see this for a refresher).
I want to know how can I improve my method, so I can try out fancy new ways of doing the same old things.
def shoelace(list):
r_p = 0 # Positive Values
r_n = 0 # Negative Values
x, y = [i[0] for i in list], [i[1] for i in list]
x.append(x[0]), y.append(y[0])
print(x, y)
for i in range(len(x)):
if (i+1) < len(x):
r_p += (x[i] * y[i+1])
r_n += (x[i+1] * y[i])
else:
break
return ((abs(r_p - r_n))/2)
Don't use short variable names that need to be commented; use names that indicate the function.
list is the name of the built-in list type, so while Python will let you replace that name, it's a bad idea stylistically.
, should not be used to separate what are supposed to be statements. You can use ;, but it's generally better to just put things on separate lines. In your case, it happens to work because you are using .append for the side effect, but basically what you are doing is constructing the 2-tuple (None, None) (the return values from .append) and throwing it away.
Use built-in functions where possible for standard list transformations. See the documentation for zip, for example. Except you don't really need to perform this transformation; you want to consider pairs of adjacent points, so do that - and take apart their coordinates inside the loop.
However, you can use zip to transform the list of points into a list of pairs-of-adjacent-points :) which lets you write a much cleaner loop. The idea is simple: first, we make a list of all the "next" points relative to the originals, and then we zip the two point-lists together.
return is not a function, so the thing you're returning does not need surrounding parentheses.
Instead of tallying up separate positive and negative values, perform signed arithmetic on a single value.
def shoelace(points):
signed_double_area = 0
next_points = points[1:] + points[:1]
for begin, end in zip(points, next_points):
begin_x, begin_y = begin
end_x, end_y = end
signed_double_area += begin_x * end_y
signed_double_area -= end_x * begin_y
return abs(signed_double_area) / 2
Functionally, your program is quite good. One minor remark is to replace range(len(x)) with xrange(len(x)). It makes the program slightly more efficient. Generally, you should use range only in cases where you actually need the full list of values it creates. If all you need is to loop over those values, use xrange.
Also, you don't need the parenthesis in the return statement, nor in the r_p += and r_n += statements.
Regarding style, in Python variable assignments shouldn't be done like you did, but rather with a single space on each side of the = symbol:
r_p = 0
r_n = 0

Categories

Resources