SVM: problems with SMO algorithm - python

I'm currently trying to code a non linear SVM for handwritten digits recognition using the MNIST data base.
I chose to use the SMO algorithm (based on Platt's paper and other books), but I have some trouble implementing it.
When I run the code over the training set, the bias goes higher and higher, sometimes until "Inf" value, leading the SVM to "classify" every example in the same class.
Here is my code:
import numpy
import gzip
import struct
import matplotlib
from sklearn import datasets
from copy import copy
class SVM:
def __init__(self, constant, data_set, label_set):
self._N = len(data_set)
if self._N != len(label_set):
raise Exception("Data size and label size don't match.")
self._C = constant
self._epsilon = 0.001
self._tol = 0.001
self._data = [numpy.ndarray.flatten((1/255)*elt) for elt in data_set]
self._dimension = len(self._data[0])
self._label = label_set
self._alphas = numpy.zeros((1, self._N))
self._b = 0
self._errors = numpy.ndarray((2, 0))
def kernel(self, x1, x2):
x1 = x1.reshape(1,self._dimension)
result = numpy.power(numpy.dot(x1, x2), 3)
return result
def evaluate(self, x):
result = 0
i = 0
while i < self._N:
result += self._alphas[0, i]*self._label[i]*self.kernel(x, self._data[i])
i += 1
result += self._b
return result
def update(self, i1, i2, E2):
i1 = int(i1)
i2 = int(i2)
if i1 == i2:
return 0
y1 = self._label[i1]
y2 = self._label[i2]
alpha1 = self._alphas[0, i1]
alpha2 = self._alphas[0, i2]
#If alpha1 is non-bound, its error is in the cache.
#So we check its position to extract its error.
#Else, we compute it.
if alpha1 > 0 and alpha1 < self._C :
position = 0
for i, elt in enumerate(self._errors[0, :]):
if elt == i1:
position = i
E1 = self._errors[1, position]
else:
E1 = self.evaluate(self._data[i1]) - y1
s = y1*y2
H = L = 0
if y1 != y2:
L = max(0, alpha2 - alpha1)
H = min(self._C, self._C + alpha2 - alpha1)
else:
L = max(0, alpha2 + alpha1 - self._C)
H = min(self._C, alpha2 + alpha1)
if H == L:
return 0
K11 = self.kernel(self._data[i1], self._data[i1])
K12 = self.kernel(self._data[i1], self._data[i2])
K22 = self.kernel(self._data[i2], self._data[i2])
eta = K11 + K22 - 2*K12
if eta > 0:
alpha2_new = alpha2 + (y2*(E1 - E2)/eta)
if alpha2_new < L:
alpha2_new = L
elif alpha2_new > H:
alpha2_new = H
else:
f1 = y1*(E1 + self._b) - alpha1*K11 - s*alpha2*K12
f2 = y2*(E2 + self._b) - alpha2*K22 - s*alpha1*K12
L1 = alpha1 + s*(alpha2 - L)
H1 = alpha1 + s*(alpha2 - H)
FuncL = L1*f1 + L*f2 + (1/2)*numpy.square(L1)*K11 + (1/2)*numpy.square(L)*K22 + s*L1*L*K12
FuncH = H1*f1 + H*f2 + (1/2)*numpy.square(H1)*K11 + (1/2)*numpy.square(H)*K22 + s*H1*H*K12
if FuncL < FuncH - self._epsilon:
alpha2_new = L
elif FuncL > FuncH + self._epsilon:
alpha2_new = H
else:
alpha2_new = alpha2
if numpy.abs(alpha2_new - alpha2) < self._epsilon*(alpha2_new+alpha2+ self._epsilon):
return 0
alpha1_new = alpha1 + s*(alpha2 - alpha2_new)
#Update of the threshold.
b1 = E1 + y1*(alpha1_new - alpha1)*K11 + y2*(alpha2_new - alpha2)*K12 + self._b
b2 = E2 + y1*(alpha1_new - alpha1)*K12 + y2*(alpha2_new - alpha2)*K22 + self._b
if L < alpha1_new < H:
b_new = b1
elif L < alpha2_new < H:
b_new = b2
else:
b_new = (b1+b2)/2
#Update the cache error
#If alpha2 was bound and its new value is non-bound, we add its index and its error to the cache.
#If alpha2 was unbound and its new value is bound, we delete it from the cache.
if (alpha2 == 0 or alpha2 == self._C) and (alpha2_new > 0 and alpha2_new < self._C):
vector_alpha2_new = numpy.array([i2, E2])
vector_alpha2_new = vector_alpha2_new.reshape((2, 1))
self._errors = numpy.concatenate((self._errors, vector_alpha2_new), 1)
if (alpha2 > 0 and alpha2 < self._C) and (alpha2_new == 0 or alpha2_new == self._C):
l = 0
position = 0
while l < len(self._errors[0, :]):
if self._errors[0, l] == i2:
position = l
l += 1
self._errors = numpy.delete(self._errors, position, 1)
#We do the exact same thing with alpha1.
if (alpha1 == 0 or alpha1 == self._C) and (alpha1_new > 0 and alpha1_new < self._C):
vector_alpha1_new = numpy.array([i1, E1])
vector_alpha1_new = vector_alpha1_new.reshape((2, 1))
self._errors = numpy.concatenate((self._errors, vector_alpha1_new), 1)
if (alpha1 > 0 and alpha1 < self._C) and (alpha1_new == 0 or alpha1_new == self._C):
l = 0
position = 0
while l < len(self._errors[0, :]):
if self._errors[0, l] == i1:
position = l
l += 1
self._errors = numpy.delete(self._errors, position, 1)
#Then we update the error for each non bound point using the new values for alpha1 and alpha2.
for i,error in enumerate(self._errors[1, :]):
self._errors[1, i] = error + (alpha2_new - alpha2)*y2*self.kernel(self._data[i2], self._data[int(self._errors[0, i])]) + (alpha1_new - alpha1)*y1*self.kernel(self._data[i1], self._data[int(self._errors[0, i])]) - self._b + b_new
#Storing the new values of alpha1 and alpha2:
self._alphas[0, i1] = alpha1_new
self._alphas[0, i2] = alpha2_new
self._b = b_new
print(self._errors)
return 1
def examineExample(self, i2):
i2 = int(i2)
y2 = self._label[i2]
alpha2 = self._alphas[0, i2]
if alpha2 > 0 and alpha2 < self._C:
position = 0
for i, elt in enumerate(self._errors[0, :]):
if elt == i2:
position = i
E2 = self._errors[1, position]
else:
E2 = self.evaluate(self._data[i2]) - y2
r2 = E2*y2
if (r2< -self._tol and alpha2 < self._C) or (r2 > self._tol and alpha2 > 0):
n = numpy.shape(self._errors)[1]
if n > 1:
i1 = 0
if E2 > 0:
min = self._errors[1, 0]
position = 0
for l, elt in enumerate(self._errors[1, :]):
if elt < min:
min = elt
position = l
i1 = self._errors[0, position]
else:
max = self._errors[1, 0]
position = 0
for l, elt in enumerate(self._errors[1, :]):
if elt > max:
max = elt
position = l
i1 = self._errors[0, position]
if self.update(i1, i2, E2):
return 1
#loop over all non bound examples starting at a random point.
list_index = [i for i in range(n)]
numpy.random.shuffle(list_index)
for i in list_index:
i1 = self._errors[0, i]
if self.update(i1, i2, E2):
return 1
#Loop over all the training examples, starting at a random point.
list_bound = [i for i in range(self._N) if not numpy.any(self._errors[0, :] == i)]
numpy.random.shuffle(list_bound)
for i in list_bound:
i1 = i
if self.update(i1, i2, E2):
return 1
return 0
def SMO(self):
numChanged = 0
examineAll = 1
cpt = 1
while(numChanged > 0 or examineAll):
numChanged = 0
if examineAll == 1:
for i in range(self._N):
numChanged += self.examineExample(i)
else:
for i in self._errors[0, :]:
numChanged += self.examineExample(i)
if examineAll == 1:
examineAll = 0
elif numChanged == 0:
examineAll = 1
cpt += 1
def load_training_data(a, b):
train = gzip.open("train-images-idx3-ubyte.gz", "rb")
labels = gzip.open("train-labels-idx1-ubyte.gz", "rb")
train.read(4)
labels.read(4)
number_images = train.read(4)
number_images = struct.unpack(">I", number_images)[0]
rows = train.read(4)
rows = struct.unpack(">I", rows)[0]
cols = train.read(4)
cols = struct.unpack(">I", cols)[0]
number_labels = labels.read(4)
number_labels = struct.unpack(">I", number_labels)[0]
image_list = []
label_list = []
if number_images != number_labels:
raise Exception("The number of labels doesn't match with the number of images")
else:
for l in range(number_labels):
if l % 1000 == 0:
print("l:{}".format(l))
mat = numpy.zeros((rows, cols), dtype = numpy.uint8)
for i in range(rows):
for j in range(cols):
pixel = train.read(1)
pixel = struct.unpack(">B", pixel)[0]
mat[i][j] = pixel
image_list += [mat]
lab = labels.read(1)
lab = struct.unpack(">B", lab)[0]
label_list += [lab]
train.close()
labels.close()
i = 0
index_a = []
index_b = []
while i < number_labels:
if label_list[i] == a:
index_a += [i]
elif label_list[i] == b:
index_b += [i]
i += 1
image_list = [m for i,m in enumerate(image_list) if (i in index_a) | (i in index_b)]
mean = (a+b)/2
label_list = [ numpy.sign(m - mean) for l,m in enumerate(label_list) if l in index_a+index_b]
return ([image_list, label_list])
def load_test_data():
test = gzip.open("t10k-images-idx3-ubyte.gz", "rb")
labels = gzip.open("t10k-labels-idx1-ubyte.gz", "rb")
test.read(4)
labels.read(4)
number_images = test.read(4)
number_images = struct.unpack(">I", number_images)[0]
rows = test.read(4)
rows = struct.unpack(">I", rows)[0]
cols = test.read(4)
cols = struct.unpack(">I", cols)[0]
number_labels = labels.read(4)
number_labels = struct.unpack(">I", number_labels)[0]
image_list = []
label_list = []
if number_images != number_labels:
raise Exception("The number of labels doesn't match with the number of images")
else:
for l in range(number_labels):
if l % 1000 == 0:
print("l:{}".format(l))
mat = numpy.zeros((rows, cols), dtype = numpy.uint8)
for i in range(rows):
for j in range(cols):
pixel = test.read(1)
pixel = struct.unpack(">B", pixel)[0]
mat[i][j] = pixel
image_list += [mat]
lab = labels.read(1)
lab = struct.unpack(">B", lab)[0]
label_list += [lab]
test.close()
labels.close()
return ([image_list, label_list])
data = load_training_data(0, 7)
images_training = data[0]
labels_training = data[1]
svm = SVM(0.1, images_training[0:200], labels_training[0:200])
svm.SMO()
def view(image, label=""):
print("Number : {}".format(label))
pylab.imshow(image, cmap = pylab.cm.gray)
pylab.show()

First, SMO is a fairly complicated algorithm - it is not one easy to debug in this kind of format.
Second, you are starting too high up in your testing. Some advice to help you debug your problems.
1) First, switch to using the linear kernel. Its much easier for you to compute the exact linear solution with another algorithm and compare what you are getting with the exact solution. This way its only the weight vectors and bias term. If you stay in the dual space, you'll have to compare all the coefficients and make sure things stay in the same order.
2) Start with a much simpler 2D problem where you know what the general solution should look like. You can then visualize the solution, and watch as it changes at each step - this can be a visual tool to help you find where something goes wrong.

One important thing is you said this:
b1 = E1 + y1*(alpha1_new - alpha1)*K11 + y2*(alpha2_new - alpha2)*K12 + self._b
b2 = E2 + y1*(alpha1_new - alpha1)*K12 + y2*(alpha2_new - alpha2)*K22 + self._b
Basically you're just adding to b every time with this code. Your b's should look more like this:
b1 = smo.b - E1 - y1 * (a1 - alpha1) * smo.K[i1, i1] - y2 * (a2 - alpha2) * smo.K[i1, i2]
b2 = smo.b - E2 - y1 * (a1 - alpha1) * smo.K[i1, i2] - y2 * (a2 - alpha2) * smo.K[i2, i2]
This version is not perfect, but I recommend checking apex51's version on Github for pointers:
SVM-and-sequential-minimal-optimization
The mathematical basis in the notes are very strong (despite some minor discrepancies with Platt's paper) and the code is not perfect, but a good direction for you. I would also suggest looking at other, completed SMOs and trying to tweak that code to math your needs instead of writing from scratch.

Related

k means algorithm python

Whenever k = 2, the code runs in a loop
if k > 2 it sets all, but one of the centroids location to 0,0
I've reviewed it a couple of times , and it doesn't seem like there are any errors probably some sort of logic flaw. The code starts by having a class and its methods which initiate the centroids, calculate the Euclidean distance, and reassign centroids to the average positions of the points that are in the cluster. It then runs a loop that consists of reassigning and calculating distance until a list of the assignments are equal and then plots it.
class Kmeans:
def __init__(self, K, dataset, centroids, sorting):
self.K = K
self.dataset = dataset
self.centroids = centroids
self.sorting = sorting
#sets starting position of centroids
def initializeCentroids(self):
bigX = 0
bigY = 0
self.centroids = []
for i in self.dataset:
if i[0] > bigX:
bigX = i[0]
if i[1] > bigY:
bigY = i[1]
for q in range(self.K):
self.centroids.append([random.randint(0, bigX), random.randint(0, bigY)])
plt.scatter((self.centroids[0][0], self.centroids[1][0]), (self.centroids[0][1], self.centroids[1][1]))
return self.centroids
#calculates euclidean distance
def calcDistance(self):
self.sorting = []
for w in self.dataset:
print(w)
distances = []
counter = 0
for centr in self.centroids:
distances.append(math.sqrt(abs((centr[0] - w[0] * centr[0] - w[0]) + (centr[1] - w[1] * centr[1] - w[1]))))
counter += 1
if counter > 0:
try:
if distances[0] > distances[1]:
distances.pop(0)
if distances[1] > distances[0]:
distances.pop(1)
counter -= 1
except IndexError:
pass
self.sorting.append([w, counter, distances[0]])
return self.sorting
def reassignCentroids(self):
counter3 = 1
for r in range(len(self.centroids)):
positionsX = []
positionsY = []
for t in self.sorting:
if t[1] == counter3:
positionsX.append(t[0][0])
positionsY.append(t[0][1])
population = len(positionsY)
if population == 0:
population = 1
self.centroids.append([sum(positionsX) / population, sum(positionsY) / population])
counter3 += 1
self.centroids.pop(0)
return
k = 4
dataSetSize = input("Enter the amount of tuples you want generated: ")
data_set = []
for o in range(int(dataSetSize)):
data_set.append((random.randint(0, 1000), random.randint(0, 1000)))
attempt = Kmeans(k, data_set, 0, 0)
attempt.initializeCentroids()
xvals = []
yvals = []
sortCompare = []
# plots
for p in data_set:
xvals.append(p[0])
yvals.append(p[1])
running = True
while running:
if len(sortCompare) > 1:
centroidChoice0 = []
centroidChoice1 = []
for p in sortCompare[0]:
centroidChoice0.append(p[1])
for d in sortCompare[1]:
centroidChoice1.append(d[1])
print(centroidChoice1)
print(attempt.centroids)
if centroidChoice1 == centroidChoice0:
running = False
for m in attempt.centroids:
plt.scatter((attempt.centroids[0][0], attempt.centroids[1][0]), (attempt.centroids[0][1], attempt.centroids[1][1]))
running = False
sortCompare.pop(0)
attempt.calcDistance()
sortCompare.append(attempt.sorting)
attempt.reassignCentroids()

IndexError: list index out of range error while enter value like 1 2 3 in Python

I am generating a graph/drawing using pyhton.
When I am entering value from backward like 6 5 4 3 it's working fine but When I am giving input like 1 2 3 it's throwing list index out of range error.
I am new to python. Please help me to fix this.
**EDIT : ** it's only accepting when first value is greater than second value for example it's working with 7 6 but not with 6 7.
here is my python code:
HUMAN_HEIGHT = 3
HUMAN_WIDTH = 3
HUMAN_LEG_OFFSET = 1
def print_2d_array(arr):
"""Print the 2D Array"""
print(f"Height = {len(arr)}, Width = {len(arr[0])}")
for row in arr:
for item in row:
print(f"{item}", end="")
print()
def increasing_slope(index):
"""Returns if the slope is increasing which is the even number"""
return index % 2 == 0
def get_indicator(index):
"""Returns the indicator for increasing or decreasing slope"""
return "/" if increasing_slope(index) else "\\"
def add_human_at(new_arr, human_location, height):
"""Adds Human to the Array"""
human_x = human_location[0]
human_y = human_location[1]
new_arr[height - human_y - 1][human_x - 1] = " "
new_arr[height - human_y - 1][human_x] = "○"
new_arr[height - human_y - 1][human_x + 1] = " "
new_arr[height - human_y][human_x - 1] = "/"
new_arr[height - human_y][human_x] = "|"
new_arr[height - human_y][human_x + 1] = "\\"
new_arr[height - human_y + 1][human_x - 1] = "<"
new_arr[height - human_y + 1][human_x] = " "
new_arr[height - human_y + 1][human_x + 1] = ">"
def create_line(y0, x0, y1, x1, index):
"""Generator that Returns the diagonal line from x,y to x1,y1"""
yield y0, x0
while y0 != y1 and x0 != x1:
y0 = y0 + (-1 if increasing_slope(index) else 1)
x0 += 1
yield y0, x0
def get_2d_mountains_from_1d_sum(arr, height, width, human_location):
new_arr = []
for i in range(height + HUMAN_HEIGHT):
mountain_row = []
for j in range(width + HUMAN_LEG_OFFSET):
mountain_row.append(" ")
new_arr.append(mountain_row)
ground = height + HUMAN_HEIGHT
prev_x, prev_y = 0, 0
for index, [x, y] in enumerate(arr):
indicator = get_indicator(index)
if prev_x >= human_location[0]:
start_x, start_y = ground - prev_y - 1, prev_x + HUMAN_LEG_OFFSET
end_x, end_y = ground - y - 1, x - 1 + HUMAN_LEG_OFFSET
else:
start_x, start_y = ground - prev_y - 1, prev_x
end_x, end_y = ground - y - 1, x - 1
for (point_y, point_x) in create_line(start_x, start_y, end_x, end_y, index):
new_arr[point_y][point_x] = indicator
prev_y = y
prev_x = x
add_human_at(new_arr, human_location, height)
print_2d_array(new_arr)
def generate_mountains(nums):
sum_nums = []
sum_at_position = 0
previous_sum = 0
total_width = 0
max_height = 0
human_location = []
for index, item in enumerate(nums):
# + or - numbers to get prefix list
if index % 2 == 0:
sum_at_position += (item - 1)
else:
sum_at_position -= (item - 1)
total_width += abs(sum_at_position - previous_sum) + 1
if sum_at_position > max_height:
max_height = sum_at_position
human_location = [total_width, max_height]
previous_sum = sum_at_position
sum_nums.append([total_width, sum_at_position])
get_2d_mountains_from_1d_sum(sum_nums, max_height + 1, total_width, human_location)
def print_mountains_human_from_input(nums):
generate_mountains(nums)
print("Enter the inputs")
a = [int(x) for x in input().split()]
print_mountains_human_from_input(a)
I added the screenshot of error..
thanks in advance.
You can add a sorting to your function to avoid a wrong input error but it will not fix the actual error:
def print_mountains_human_from_input(nums):
nums.sort(reverse=True)
generate_mountains(nums)

Dijkstra's shortest path

I'm VERY new to Python (self learning) and am writing some code, and have read as much as possible (both on this website and youtube) to figure it out, and I'm perplexed as to why it's not working for me
I've generated this dictionary of dictionaries (may not be most efficient, please let me know how to improve, been doing this a couple weeks only):
graphx = []
all_locs = []
def graph(width, height):
for r in range(height):
row = []
for c in range(width):
t = (r, c)
row.append(t)
all_locs.append(t)
graphx.append(row)
graph(width, height)
# # Builds a dictionary of all nodes, and their weight
weighted_grid = {}
for node in graphx:
for c in node:
n = {}
s = {}
e = {}
w = {}
if (c[0] < height) and (c[0] > 0):
n[c[0] + 1, c[1]] = 1
s[c[0] - 1, c[1]] = 1
elif c[0] == 0:
n[c[0] + 1, c[1]] = 1
elif c[0] == height:
s[c[0] - 1, c[1]] = 1
if c[1] < width and c[1] > 0:
e[c[0], c[1] + 1] = 1
w[c[0], c[1] - 1] = 1
elif c[1] == 0:
e[c[0], c[1] + 1] = 1
elif c[1] == height:
w[c[0], c[1] - 1] = 1
temp = {}
blank = {}
if n != blank:
temp[c[0] + 1, c[1]] = 1
if e != blank:
temp[c[0], c[1] + 1] = 1
if s != blank:
temp[c[0] - 1, c[1]] = 1
if w != blank:
temp[c[0], c[1] - 1] = 1
weighted_grid[c[0],c[1]] = temp
When I run dijikstras, using the the tuples as start and destination, I get an error. Here's the version of dijkstras I'm running:
def dijkstra(graph, start, goal):
shortest_distance = {} # records the current cost to reach that node.
track_predecessor = {} # keeps track of the path that led to this node.
unseen_nodes = graph # Iterate through the graph to check all nodes.
infinity = 99999 # Make it any large number,greater than possible path weights.
track_path = [] # gives us the trace-back path of the optimal route
for node in unseen_nodes:
shortest_distance[node] = infinity
shortest_distance[start] = 0
while unseen_nodes:
min_distance_node = None
for node in unseen_nodes:
if min_distance_node is None:
min_distance_node = node
elif shortest_distance[node] < shortest_distance[min_distance_node]:
min_distance_node = node
path_options = graph[min_distance_node].items()
for child_node, weight in path_options:
if weight + shortest_distance[min_distance_node] < shortest_distance[child_node]:
shortest_distance[child_node] = weight + shortest_distance[min_distance_node]
track_predecessor[child_node] = min_distance_node
unseen_nodes.pop(min_distance_node)
current_node = goal
while current_node != start:
try:
track_path.insert(0, current_node)
current_node = track_predecessor[current_node]
except KeyError:
break
track_path.insert(0, start)
if shortest_distance[goal] != infinity:
pass
The error I get is:
Traceback (most recent call last):
File "C:/Users/Dave/Desktop/Important/PycharmProjects/DMT2/dungeonmasterstome/Main.py", line 318, in <module>
dijkstra(weighted_grid, (0, 0), (0,1))
File "C:/Users/Dave/Desktop/Important/PycharmProjects/DMT2/dungeonmasterstome/Main.py", line 300, in dijkstra
if weight + shortest_distance[min_distance_node] < shortest_distance[child_node]:
KeyError: (0, 30)
Thoughts and thanks for any help and constructive criticism.

Python: Point in polygon, boundary and vertex check (ray casting)

So I have written some code to check whether a point [(x,y)] lies within a polygon [(x,y), (x,y), (x,y), (x,y)] but the code fails if the point lies on a boundary or a vertex, I need this to be classed as lying within the polygon. This is the code:
def areasign(poly):
sumarea = 0
for i in range(0, len(poly)-1):
xi = poly[i][0]
yi = poly[i][1]
xj = poly[i+1][0]
yj = poly[i+1][1]
sumarea = sumarea + ((xi*yj)-(yi*xj))
if sumarea == 0: return 0
if sumarea < 0: return -1
if sumarea > 0: return 1
def lineintersection(xy, ij):
xyi = []
xyj = []
ijx = []
ijy = []
xyi.extend(xy)
xyj.extend(xy)
xyi.append(ij[0])
xyj.append(ij[1])
xyi.append(xy[0])
xyj.append(xy[0])
ijx.extend(ij)
ijy.extend(ij)
ijx.append(xy[0])
ijy.append(xy[1])
ijx.append(ij[0])
ijy.append(ij[0])
a = areasign(xyi)
b = areasign(xyj)
c = areasign(ijx)
d = areasign(ijy)
if (a!= b) and (c!=d):
return True
else:
return False
def openpointfile(fname):
p = []
f = open(fname)
for line in f:
line = line.replace('POINT(', '')
line = line.replace(')', '')
vals = line.split(' ')
res = map(float, vals)
ctuple = tuple(res)
p.append(ctuple)
print ctuple
f.close()
return p
points = openpointfile('C:/Users/Dan/Documents/Informatics/Data/Point_On_Line.txt')
def openpolygonfile(fname):
p = []
f = open(fname)
for line in f:
line = line.replace('POLYGON((', '')
line = line.replace('))', '')
s = line.split(',')
poly = []
for coord in s:
vals = coord.split(' ')
res = map(float, vals)
ctuple = tuple(res)
poly.append(ctuple)
p.append(poly)
f.close()
return p
polys = openpolygonfile('C:/Users/Dan/Documents/Informatics/Data/Polygon_On_Line.txt')
def pointinpoly(points, polys):
infinity = tuple([100000000.0, 100000010.0])
sum = 0
testline = (points, infinity)
for i in range(0, len(poly)-1):
start = poly[i]
end = poly[i+1]
line = (start, end)
l = lineintersection(line, testline)
if l == True:
sum = sum + 1
if sum % 2 == 0:
return False
else:
return True
pointcount = 0
for point in points:
pointcount = pointcount + 1
polycount = 0
for poly in polys:
polycount = polycount + 1
l = pointinpoly(point, poly)
res = 'Point ' + str(pointcount) + ' lies within Polygon ' + str(polycount) + ' = ' + str(l)
print l
print (res)
Like i said before this doesnt work if the point lies on a boundary or a vertex, i have this function that i found on here that seems to work but i can't find a way to get it my files into the correct format for the function and to get it to iterate oer a list of polygons.
def point_in_poly(x,y,poly):
# check if point is a vertex
if (x,y) in poly: return "IN"
# check if point is on a boundary
for i in range(len(poly)):
p1 = None
p2 = None
if i==0:
p1 = poly[0]
p2 = poly[1]
else:
p1 = poly[i-1]
p2 = poly[i]
if p1[1] == p2[1] and p1[1] == y and x > min(p1[0], p2[0]) and x < max(p1[0], p2[0]):
return "IN"
n = len(poly)
inside = False
p1x,p1y = poly[0]
for i in range(n+1):
p2x,p2y = poly[i % n]
if y > min(p1y,p2y):
if y <= max(p1y,p2y):
if x <= max(p1x,p2x):
if p1y != p2y:
xints = (y-p1y)*(p2x-p1x)/(p2y-p1y)+p1x
if p1x == p2x or x <= xints:
inside = not inside
p1x,p1y = p2x,p2y
if inside: return "IN"
else: return "OUT"
Any help on how to build that function into my existing code or any help on a new function that could be used to check if the point lies on the boundary of a polygon or on a vertex

how can I use a function I define in a new function I define?

My first function I defined that works
def chainPoints(aa,DIS,SEG,H):
#xtuple
n=0
xterms = []
xterm = -DIS
while n<=SEG:
xterms.append(xterm)
n+=1
xterm = -DIS + n*SEGL
#
#ytuple
k=0
yterms = []
while k<=SEG:
yterm = H + aa*m.cosh(xterms[k]/aa) - aa*m.cosh(DIS/aa)
yterms.append(yterm)
k+=1
But now I need a second function that depends on my first function, speciffically the lists xterms and yterms.
def chainLength(aa,DIS,SEG,H):
chainPoints(aa,DIS,SEG,H)
#length of chain
ff=1
Lterm=0.
totallength=0.
while ff<=SEG:
Lterm = m.sqrt((xterms[ff]-xterms[ff-1])**2 + (yterms[ff]-yterms[ff-1])**2)
totallength += Lterm
ff+=1
return(totallength)
I had it all done without defined functions, but now I need to have defined functions for each part.
You need to return results from your chainPoints() function, then assign the return value to local name(s) in your chainLength() function:
def chainPoints(aa, DIS, SEG, H):
#xtuple
n = 0
xterms = []
xterm = -DIS
while n <= SEG:
xterms.append(xterm)
n += 1
xterm = -DIS + n * SEGL
#
#ytuple
k = 0
yterms = []
while k <= SEG:
yterm = H + aa * m.cosh(xterms[k] / aa) - aa * m.cosh(DIS / aa)
yterms.append(yterm)
k += 1
return xterms, yterms
def chainLength(aa, DIS, SEG, H):
xterms, yterms = chainPoints(aa, DIS, SEG, H)
ff = 1
Lterm = 0.
totallength = 0.
while ff <= SEG:
Lterm = m.sqrt((xterms[ff] - xterms[ff-1]) ** 2 +
(yterms[ff] - yterms[ff - 1]) ** 2)
totallength += Lterm
ff += 1
return totallength
I used the same names in chainLength here, but that is not a requirement.

Categories