Distance between point to list of points - python

I'm trying to calculate the distance from point p to each of the points in list s.
import math
s= [(1,4),(4,2),(6,3)]
p= (3,7)
p0,p1=p
dist=[]
for s0,s1 in s:
dist=math.sqrt((p0[0] - p1[0])**2 + (s0[1] - s1[1])**2)
dist= dist+1
print(dist)
TypeError Traceback (most recent call last)
<ipython-input-7-77e000c3374a> in <module>
3 dist=[]
4 for s0,s1 in s:
----> 5 dist=math.sqrt((p0[0] - p1[0])**2 + (s0[1] - s1[1])**2)
6
7
TypeError: 'int' object is not subscriptable
I see that accessing the location is ceased as p0,p1 are ints. but in this scenario I'm not getting an idea how to address this.

You are accidentally using indexing on your data even though you already separated your points into x, y. In addition, you are overwriting your list and not saving the data. Also the distance formula is incorrect it should be a subtraction between points not addition. Try this:
import math
s= [(1,4),(4,2),(6,3)]
p= (3,7)
p0,p1=p
dist=[]
for s0,s1 in s:
dist_=math.sqrt((p0 - s0)**2 + (p1 - s1)**2) #Edit this line to [0]s and [1]s
dist_= dist_+1 #Also change name and/or delete
# print(dist)
dist.append(dist_) #Save data to list

dist=math.sqrt((p0[0] - p1[0])**2 + (s0[1] - s1[1])**2)
Here, you are indexing integer.
Moreover, you've made mistake in calculation. It should be:
dist=math.sqrt((p0 - s0)**2 + (p1 - s1)**2)

If what is desired is a list of the distances, that can be done in a single line of code with a list comprehension:
import math
import pprint
s = [(1,2),(3,4),(-1,1),(6,-7),(0, 6),(-5,-8),(-1,-1),(6,0),(1,-1)]
p = (3,-4)
dists = [math.sqrt((p[0]-s0)**2 + (p[1]-s1)**2) for s0, s1 in s]
pprint.pprint(dists)
The other thing here is that I've removed the dist = dist + 1 from the OPs code. I don't see that being correct...why add 1 to each computed distance?
Result:
[6.324555320336759,
8.0,
6.4031242374328485,
4.242640687119285,
10.44030650891055,
8.94427190999916,
5.0,
5.0,
3.605551275463989]

Maybe try to change this line:
dist=math.sqrt((p0[0] - p1[0])**2 + (s0[1] - s1[1])**2)
To:
dist=math.sqrt((p0 - p1)**2 + (s0 - s1)**2)

If you would like the Euclidean distance, you could do something like this (even without import math)
s = [(1, 4), (4, 2), (6, 3)]
p = (3, 7)
for point in s:
sum_ = sum((p[i] - point[i]) ** 2 for i in range(len(p)))
distance = sum_ ** (1 / 2) # take the square root, the same thing as math.sqrt()
print(p, point, round(distance, 1))
Results:
(3, 7) (1, 4) 3.6
(3, 7) (4, 2) 5.1
(3, 7) (6, 3) 5.0
The error you get in your code is because you used indexing on an integer. Just like doing this:
>>> a = 3
>>> a[0]
Traceback (most recent call last):
File "<input>", line 1, in <module>
a[0]
TypeError: 'int' object is not subscriptable

In case you are not constrained by the packages you can use. An implementation using NumPy would be more swift.
import numpy as np
s = np.array([(1,4),(4,2),(6,3)])
p = np.array((3,7))
dist = np.linalg.norm(p - s, axis=1)
Result:
array([3.60555128, 5.09901951, 5.])

Related

Converting Maple to Sage

I have some Maple code below that I'm trying to convert to Sage (which is some kind of Python) code.
This is the Maple code
restart:
m:=15:
a:=array(1..m):
eqn:=array(1..m):
expr:=sum(a['i']*u^('i'-1),'i'=1..m)-
product((1-u^'i')^(-a['i']),'i'=1..m):
for i from 1 to m do eqn[i]:=coeff(series(expr,u=0,m+2),u,i-1);
od:
sols:=solve({seq(eqn[i],i=1..m)},{seq(a[i],i=1..m)}):
assign(sols):
print(a);
This is the output for this code:
[1, 1, 2, 4, 9, 20, 48, 115, 286, 719, 1842, 4766, 12486, 32973, 87811]
This is the Sage code I have already:
u = var('u')
m = 15
a = [var(f"a_{i}") for i in range(1,m+1)]
eqn = [var(f"e_{i}") for i in range(1,m+1)]
expr = sum(a[i]*u^(i-1) for i in range(1,m)) - product((1-u^i)^(-a[i]) for i in range(1,m))
print(expr)
for i in range(0,m):
# eqn[i] = taylor(expr,u,0,m+2).coefficients(sparse=False)[i]
When I uncomment the code in the for-loop, I get IndexError: list index out of range.
I tried the CodeGeneration tool:
CodeGeneration:-Python(i -> coeff(series(expr, u = 0, m + 2), u, i - 1), output = embed);
CodeGeneration:-Python(sols -> assign(sols), output = embed);
This however gives me
Warning, the function names {coeff, series} are not recognized in the target language
Warning, the function names {assign} are not recognized in the target language
And it gives as output thus no useful code, since coeff and series don't exist:
cg0 = lambda i: coeff(series(expr, u == 0, m + 2), u, i - 1)
cg2 = lambda sols: assign(sols)
The question is now: what are the equivalent expressions for coeff, series and assign?
To give an answer, one has to understand first what happens behind the maple code, the solve the problem more or less in an optimal manner in sage. Here is what can be done in sage, to look as close as possible to the maple way.
m = 15
r = [1..m] # range to be used in the sequel
u = var('u');
a = dict(zip(r, var('a', n=m+1, latex_name='a')[1:]))
expr = sum ( a[j]*u^(j-1) for j in r ) \
- prod( (1 - u^j)^(-a[j]) for j in r )
expr = taylor(expr, u, 0, m)
sols = solve( [ diff(expr, u, j-1).subs(u == 0) for j in r ]
, list(a.values())
, solution_dict=True)
for sol in sols:
print(sol)
And there is only one solution, and the one print is:
{a1: 1, a2: 1, a3: 2, a4: 4, a5: 9, a6: 20, a7: 48, a8: 115, a9: 286
, a10: 719, a11: 1842, a12: 4766, a13: 12486, a14: 32973, a15: 87811}
Here are some words about the decision to use the "range" list (which is a list object, not a range object)... In the maple code, a was something that accepted a[1] and a[2] and so on. These "symbols" are variables, if not specified in a different way. But there is no a[0]. My choice was to use
var('a', n=m+1, latex_name='a')
which is a list of "variables", well it is the list starting with a0, so i am taking it from a1 to the end via (slicing)
var('a', n=m+1, latex_name='a')[1:]
and then, in order to have something like a[1] pointing to a1 i am using a dictionary in sage. So i am zipping / pairing the list r with the above sliced part of the var's. Then is want the dictionary that solidifies this pairing.
Then in order to have the u-coefficients, i am using the poor man's coefficient extraction, obtained by differentiation w.r.t. u, as many times as needed, then setting the u variable to zero.
Why is the above not working "somehow" by directly "taking coefficients"? Because in sage, expr is an expression.
sage: type(expr)
<class 'sage.symbolic.expression.Expression'>
And there is no way in general to get the coefficients of such an "expression".
Instead, if we arrange to work in polynomial rings, then there is still a chance to proceed using the wanted method. Please compare the above with:
m = 15
r = [1..m] # range to be used in the sequel
R.<a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15> = \
PolynomialRing(QQ)
a = dict(zip(r, R.gens()))
S.<u> = PowerSeriesRing(R, default_prec=m)
expr = sum ( a[j]*u^(j-1) for j in r ) \
- exp( sum( -a[j]*log(1 - u^j) for j in r ) )
J = R.ideal(expr.coefficients())
J.variety() # solution(s) to the R-coefficient equations from above over QQ, base ring of R
And that J.variety() delivers...
sage: J.variety()
[{a15: 87811, a14: 32973, a13: 12486, a12: 4766, a11: 1842, a10: 719
, a9: 286, a8: 115, a7: 48, a6: 20, a5: 9, a4: 4, a3: 2, a2: 1, a1: 1}]
(Results were manually adjusted.)
You are trying to solve algebraic equations, right?
There is a module for that:
https://docs.sympy.org/latest/modules/solvers/solvers.html
Your python code doesn't work. Is there a module, I have to import first?
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'var' is not defined
Apology: This should be a comment, not an answer, I know. I don't have enough reputation yet. But I used to love Maple and would like to help.

Simple 1D Array Iteration Error (TypeError: 'int' object is not iterable)

I'm currently trying to iterate arrays for Random Walks, and I am able to use a for loop when there are multiple numbers per element of the array. I seem to be having trouble applying a math.dist function to a 1-dimensional array with one number per element.
Here is the problematic code:
origin = 0
all_walks1 = []
W = 100
N = 10
list_points = []
for i in range(W):
x = 2*np.random.randint(0,2,size=N)-1
xs = cumsum(x)
all_walks1.append(xs)
list_points.append(xs[-1])
list_dist = []
for i in list_points:
d = math.dist(origin, i)
list_dist.append(d)
If I try to append the distances to a new array, I am getting a TypeError: 'int' object is not iterable error.
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
~\AppData\Local\Temp/ipykernel_1808/1512057642.py in <module>
16
17 for i in list_points:
---> 18 d = math.dist(origin, i)
19 list_dist.append(d)
20
TypeError: 'int' object is not iterable
However, if the array I am parsing through in the for loop is has multiple numbers per element, as it is in the following code, everything works fine:
origin = (0, 0, 0)
all_walks_x = []
all_walks_y = []
all_walks_z = []
W = 100
N = 10
list_points = []
for i in range(W):
x = 2*np.random.randint(0,2,size=N)-1
y = 2*np.random.randint(0,2,size=N)-1
z = 2*np.random.randint(0,2,size=N)-1
xs = cumsum(x)
ys = cumsum(y)
zs = cumsum(z)
all_walks_x.append(xs)
all_walks_y.append(ys)
all_walks_z.append(zs)
list_points.append((xs[-1], ys[-1], zs[-1]))
list_dist = []
for i in list_points:
d = math.dist(origin, i)
list_dist.append(d)
I have tried using for i in range(len(list_points): and for key, value in enumerate(list_points): to no success. The only difference between the first and and the second list_points arrays would appear to be the elements enclosed in parentheses when there are multiple numbers per element. It would seem to be a simple solution that in whatever way is eluding me. Thanks for reading, and any help would be appreciated.
EDIT: I may be using the terms 1D and 3D arrays incorrectly, The first array is a list of numbers such as [6, 4, -1, 5 ... ] and the second array is a list of multiple numbers per element such as [(-10, -2, 14), (12, 2, 8), (-4, 8, 24), (10, 10, 0), (2, 8, 10) ... ]
It seems you are passing integers to math.dist. math.dist finds the Euclidean distance between one and two dimensional points. Therefore you have to provide a list, even if its just a single integer.
Example:
# not valid
math.dist(1, 2)
# valid
math.dist([1], [2])

Rewriting R's density() (not really)

In response to this question, I took upon the challenge to make my understanding on R's density() function.
Since I'm pretty much very new to R, I have no ideas about vectors regarding the c() function, which made me use a list as the closest form.
I would make this function:
def density(x, bw, adjust):
bw2 = None
result = 0
if bw == "nrd0":
bw2 = 31.39367
else:
print("No such bandwidth.")
for i in range[len(x)]:
x[i] = x[i] * bw2
for i in range[len(x)]:
result = result + x[i]
return result * adjust
And I wanted to test it:
x = [1, 3, 5]
kern = density(x, "nrd0", 1)
print(kern)
And I gained 2 errors, the main one being a TypeError.
If you want to look into it further, here's the whole terminal message:
Traceback (most recent call last):
File "density.py", line 15, in <module>
kern = density(x, "nrd0", 1)
File "density.py", line 8, in density
for i in range[len(x)]:
TypeError: 'type' object is not subscriptable
How do I fix the TypeError?
for i in range[len(x)]:
x[i] = x[i] * bw2
You have range with [] while it should be (). Try to change it.
Below is an example:
l = [10, 20, 30, 40]
for i in range(len(l)):
print(l[i], end =" ")
print()

Fraction Value Problem in Ctypes to PARI/GP

I have written a code to compare the solution of sympy and PARI/GP, but when I give a fraction value D=13/12, I get error, TypeError: int expected instead of float.
So I changed p1[i] = pari.stoi(c_long(numbers[i - 1])) to p1[i] = pari.stoi(c_float(numbers[i - 1])), but then nfroots gives no output, note that I have to use fraction in A, B, C, D which might take $10^10$ digits after decimal point.
How can I solve this problem?
The code is given below to download the libpari.dll file, click here -
from ctypes import *
from sympy.solvers import solve
from sympy import Symbol
pari = cdll.LoadLibrary("libpari.dll")
pari.stoi.restype = POINTER(c_long)
pari.cgetg.restype = POINTER(POINTER(c_long))
pari.gtopoly.restype = POINTER(c_long)
pari.nfroots.restype = POINTER(POINTER(c_long))
(t_VEC, t_COL, t_MAT) = (17, 18, 19) # incomplete
pari.pari_init(2 ** 19, 0)
def t_vec(numbers):
l = len(numbers) + 1
p1 = pari.cgetg(c_long(l), c_long(t_VEC))
for i in range(1, l):
#Changed c_long to c_float, but got no output
p1[i] = pari.stoi(c_long(numbers[i - 1]))
return p1
def Quartic_Comparison():
x = Symbol('x')
a=0;A=0;B=1;C=-7;D=13/12 #PROBLEM 1
solution=solve(a*x**4+A*x**3+B*x**2+ C*x + D, x)
print(solution)
V=(A,B,C,D)
P = pari.gtopoly(t_vec(V), c_long(-1))
res = pari.nfroots(None, P)
print("elements as long (only if of type t_INT): ")
for i in range(1, pari.glength(res) + 1):
print(pari.itos(res[i]))
return res #PROBLEM 2
f=Quartic_Comparison()
print(f)
The error is -
[0.158343724039430, 6.84165627596057]
Traceback (most recent call last):
File "C:\Users\Desktop\PARI Function ellisdivisible - Copy.py", line 40, in <module>
f=Quartic_Comparison()
File "C:\Users\Desktop\PARI Function ellisdivisible - Copy.py", line 32, in Quartic_Comparison
P = pari.gtopoly(t_vec(V), c_long(-1))
File "C:\Users\Desktop\PARI Function ellisdivisible - Copy.py", line 20, in t_vec
p1[i] = pari.stoi(c_long(numbers[i - 1]))
TypeError: int expected instead of float
The PARI/C type system is very powerful and can also work with user-defined precision. Therefore PARI/C needs to use its own types system, see e.g. Implementation of the PARI types https://pari.math.u-bordeaux.fr/pub/pari/manuals/2.7.6/libpari.pdf.
All these internal types are handled as pointer to long in the PARI/C world. Don't be fooled by this, but the type has nothing to do with long. It is perhaps best thought of as an index or handle, representing a variable whose internal representation is hidden from the caller.
So whenever switching between PARI/C world and Python you need to convert types.
Conversion are described e.g. in section 4.4.6 in the above mentioned PDF file.
To convert a double to the corresponding PARI type (= t_REAL) one would therefore call the conversion function dbltor.
With the definition of
pari.dbltor.restype = POINTER(c_long)
pari.dbltor.argtypes = (c_double,)
one could get a PARI vector (t_VEC) like this:
def t_vec(numbers):
l = len(numbers) + 1
p1 = pari.cgetg(c_long(l), c_long(t_VEC))
for i in range(1, l):
p1[i] = pari.dbltor(numbers[i - 1])
return p1
User-defined Precision
But the type Python type double has limited precision (search e.g. for floating point precision on stackoverflow).
Therefore if you want to work with defined precision I would recommend to use gdiv.
Define it e.g. like so:
V = (pari.stoi(A), pari.stoi(B), pari.stoi(C), pari.gdiv(pari.stoi(13), pari.stoi(12)))
and adjust t_vec accordingly, to get a vector of these PARI numbers:
def t_vec(numbers):
l = len(numbers) + 1
p1 = pari.cgetg(c_long(l), c_long(t_VEC))
for i in range(1, l):
p1[i] = numbers[i - 1]
return p1
You then need to use realroots to calculate the roots in this case, see https://pari.math.u-bordeaux.fr/dochtml/html-stable/Polynomials_and_power_series.html#polrootsreal.
You could likewise use rtodbl to convert a PARI type t_REAL back to a double. But the same applies, since with using a floating point number you would loose precision. One solution here could be to convert the result to a string and display the list with the strings in the output.
Python Program
A self-contained Python program that considers the above points might look like this:
from ctypes import *
from sympy.solvers import solve
from sympy import Symbol
pari = cdll.LoadLibrary("libpari.so")
pari.stoi.restype = POINTER(c_long)
pari.stoi.argtypes = (c_long,)
pari.cgetg.restype = POINTER(POINTER(c_long))
pari.cgetg.argtypes = (c_long, c_long)
pari.gtopoly.restype = POINTER(c_long)
pari.gtopoly.argtypes = (POINTER(POINTER(c_long)), c_long)
pari.dbltor.restype = POINTER(c_long)
pari.dbltor.argtypes = (c_double,)
pari.rtodbl.restype = c_double
pari.rtodbl.argtypes = (POINTER(c_long),)
pari.realroots.restype = POINTER(POINTER(c_long))
pari.realroots.argtypes = (POINTER(c_long), POINTER(POINTER(c_long)), c_long)
pari.GENtostr.restype = c_char_p
pari.GENtostr.argtypes = (POINTER(c_long),)
pari.gdiv.restype = POINTER(c_long)
pari.gdiv.argtypes = (POINTER(c_long), POINTER(c_long))
(t_VEC, t_COL, t_MAT) = (17, 18, 19) # incomplete
precision = c_long(38)
pari.pari_init(2 ** 19, 0)
def t_vec(numbers):
l = len(numbers) + 1
p1 = pari.cgetg(c_long(l), c_long(t_VEC))
for i in range(1, l):
p1[i] = numbers[i - 1]
return p1
def quartic_comparison():
x = Symbol('x')
a = 0
A = 0
B = 1
C = -7
D = 13 / 12
solution = solve(a * x ** 4 + A * x ** 3 + B * x ** 2 + C * x + D, x)
print(f"sympy: {solution}")
V = (pari.stoi(A), pari.stoi(B), pari.stoi(C), pari.gdiv(pari.stoi(13), pari.stoi(12)))
P = pari.gtopoly(t_vec(V), -1)
roots = pari.realroots(P, None, precision)
res = []
for i in range(1, pari.glength(roots) + 1):
res.append(pari.GENtostr(roots[i]).decode("utf-8")) #res.append(pari.rtodbl(roots[i]))
return res
f = quartic_comparison()
print(f"PARI: {f}")
Test
The output on the console would look like:
sympy: [0.158343724039430, 6.84165627596057]
PARI: ['0.15834372403942977487354358292473161327', '6.8416562759605702251264564170752683867']
Side Note
Not really asked in the question, but just in case you want to avoid 13/12 you could transform your formula from
to

Fix a method to convert list of integers to NumPy matrix

I want to create random integers and convert them in binary format via NumPy matrix. I wrote the following code:
def toBinary(C):
l = []
for x in C:
b = [int(i) for i in bin(x)[2:]]
l = np.vstack((l, np.array(b)))
return l
list_vectors = [random.randint(0, 2 ** 64) for _ in range(2)]
print(toBinary(list_vectors))
But I still don't know how to solve this error:
Traceback (most recent call last):
File "test.py", line 31, in <module>
print(toBinary(list_vectors))
File "test.py", line 27, in toBinary
l = np.vstack((l, np.array(b)))
File "/anaconda3/lib/python3.6/site-packages/numpy/core/shape_base.py", line 234, in vstack
return _nx.concatenate([atleast_2d(_m) for _m in tup], 0)
ValueError: all the input array dimensions except for the concatenation axis must match exactly
Any suggestion is highly appreciated.
The issue here is that the conversion to binary does not always return a binary number of same length.
If the first integer in C is, let's say 3, it'll give '0b11'. Stack this in the array, then try to convert 17. Oops, you're trying to concatenate '11' and '1001' together, it won't work.
What I did here then, is forcing the converted binary number length to 10 using the format() function (Convert to binary and keep leading zeros in Python).
import numpy as np
import numpy.random as random
def toBinary(C):
binaries_length = 10
bin_format = f'#0{binaries_length+2}b'
array_rows = len(C)
l = np.empty((array_rows, binaries_length))
for i, x in enumerate(C):
l[i,:] = np.array([int(i) for i in format(x, bin_format)[2:]])
return l
list_vectors = [random.randint(0, 2 * 64) for _ in range(10)]
print(toBinary(list_vectors))
Also, the returned array is pre-allocated, since you now perfectly know what size it will be :
binaries_length = 10
bin_format = f'#0{10+2}b'
array_rows = len(C)
l = np.empty((array_rows, binaries_length))
By the way, the call random.randint(0, 2 ** 64) also triggers an exception because 2 ** 64 is insanely too high so I changed it to 2*64 here.
To go further, you can find the optimal binary length by finding the maximum of C.
Try this, it will return a list instead of array, so make the necessary adjustments if you like:
def toBinary(C):
l = []
for x in C:
b = [i for i in bin(x)[2:]]
a="".join(b)
a=int(a)
l.append(a)
return l

Categories