How can I implement this point in polygon code in Python? - python

So, for my Computer Graphics class I was tasked with doing a Polygon Filler, my software renderer is currently being coded in Python. Right now, I want to test this pointInPolygon code I found at: How can I determine whether a 2D Point is within a Polygon? so I can make my own method later on basing myself on that one.
The code is:
int pnpoly(int nvert, float *vertx, float *verty, float testx, float testy)
{
int i, j, c = 0;
for (i = 0, j = nvert-1; i < nvert; j = i++) {
if ( ((verty[i]>testy) != (verty[j]>testy)) &&
(testx < (vertx[j]-vertx[i]) * (testy-verty[i]) / (verty[j]-verty[i]) + vertx[i]) )
c = !c;
}
return c;
}
And my attempt to recreate it in Python is as following:
def pointInPolygon(self, nvert, vertx, verty, testx, testy):
c = 0
j = nvert-1
for i in range(nvert):
if(((verty[i]>testy) != (verty[j]>testy)) and (testx < (vertx[j]-vertx[i]) * (testy-verty[i]) / (verty[j]-verty[i] + vertx[i]))):
c = not c
j += 1
return c
But this obviously will return a index out of range in the second iteration because j = nvert and it will crash.
Thanks in advance.

You're reading the tricky C code incorrectly. The point of j = i++ is to both increment i by one and assign the old value to j. Similar python code would do j = i at the end of the loop:
j = nvert - 1
for i in range(nvert):
...
j = i
The idea is that for nvert == 3, the values would go
j | i
---+---
2 | 0
0 | 1
1 | 2
Another way to achieve this is that j equals (i - 1) % nvert,
for i in range(nvert):
j = (i - 1) % nvert
...
i.e. it is lagging one behind, and the indices form a ring (like the vertices do)
More pythonic code would use itertools and iterate over the coordinates themselves. You'd have a list of pairs (tuples) called vertices, and two iterators, one of which is one vertex ahead the other, and cycling back to the beginning because of itertools.cycle, something like:
# make one iterator that goes one ahead and wraps around at the end
next_ones = itertools.cycle(vertices)
next(next_ones)
for ((x1, y1), (x2, y2)) in zip(vertices, next_ones):
# unchecked...
if (((y1 > testy) != (y2 > testy))
and (testx < (x2 - x1) * (testy - y1) / (y2-y1 + x1))):
c = not c

Related

Hairpin structure easy algorithm

I have a structure with letters A, Z, F, G.
A have a pair with Z, and F with G.
I have for example AAAFFZZGGFFGGAAAAZZZZ. And I need to "curve" structure and that fold will make a pairs
A A A F F Z Z G G F F -
* * * * * * |
Z Z Z Z A A A A G G -
6 pairs in upper example.
But we can create structure like this:
A A A F F Z Z G G -
* * * |
Z Z Z Z A A A A G G F F -
And head is a fragment of structure where pairs cannot exists. For example head 2:
rozmiar. Na przykład head = 2:
F F
A A A F F Z Z G G / \
* * * * |
Z Z Z Z A A A A \ /
G G
I don't know how to find maximal number of pairs that can be created in this structure
To make the matching go faster you can prepare a second string (R) with the letters flipped to their corresponding values. This will allow direct comparisons of paired positions instead of going through an indirection n^2 times:
S = "AAAFFZZGGFFGGAAAAZZZZ"
match = str.maketrans("AZFG","ZAGF")
R = S.translate(match) # flipped matching letters
mid = len(S)//2
maxCount,maxPos = 0,0
for d in range(mid+1): # moving away from middle
for p in {mid+d,mid-d}: # right them left
pairs = sum(a==b for a,b in zip(S[p-1::-1],R[p:])) # match fold
if pairs>maxCount:
maxCount,maxPos = pairs,p # track best so far and fold position
if p <= maxCount: break # stop when impossible to improve
print(maxCount) # 6 matches
print(maxPos) # folding at 11
print(S[:maxPos].rjust(len(S))) # AAAFFZZGGFF
print(S[maxPos:][::-1].rjust(len(S))) # ZZZZAAAAGG
# ** ** **
You could start with testing the folding point in the center, and then fan out (in zig-zag manner) putting the folding point further from the center.
Then for a given folding point, count the allowed pairs. You can use slicing to create the two strips, one in reversed order, and then zip those to get the pairs.
The outer iteration (determining the folding point) can stop when the size of the shortest strip is shorter than the size of the best answer found so far.
Here is a solution, which also returns the actual fold, so it can be printed for verification:
def best_fold(chain):
allowed = set(("AZ","ZA","FG","GF"))
revchain = chain[::-1]
maxnumpairs = 0
fold = chain # This represents "no solution"
n = len(chain)
head = n // 2
for diff in range(n):
head += diff if diff % 2 else -diff
if head - 2 < maxnumpairs or n - head - 2 < maxnumpairs:
break
numpairs = sum(a+b in allowed
for a, b in zip(revchain[-head+2:], chain[head+2:])
)
if numpairs > maxnumpairs:
maxnumpairs = numpairs
fold = chain[:head].rjust(n) + "\n" + revchain[:-head].rjust(n)
return maxnumpairs, fold
Here is how to run it on the example string:
numpairs, fold = best_fold("AAAFFZZGGFFGGAAAAZZZZ")
print(numpairs) # 5
print(fold) # AAAFFZZGGF
# ZZZZAAAAGGF
I would first start with a suitable data type to implement your creasable string. Now first things first, as you mention in your comment we can use list of characters which is better than a string. Then perhaps a tuple of arrays like [[Char],[Char]] would be sufficient.
Also creasing from left or right shouldn't matter so for simplicity we start with;
[ ["A","A","F","F","Z","Z","G","G","F","F","G","G","A","A","A","A","Z","Z","Z","Z"]
, ["A"]
]
then in every step;
Then in every step we can map our list of characters into a a tuple of creases like
chars.map((_,i,a) => [a.slice(i+1),a.slice(0,i+1).reverse()]
Compare and count for pairs.
In order to make an efficient comparison of corresponding items being a valid pair, a simple look up table as below can be used
{ "A": "Z"
, "Z": "A"
, "G": "F"
, "F": "G"
}
Finally we can filter the longest one(s)
An implementation of creases could be like;
function pairs(cs){
var lut = { "A": "Z"
, "Z": "A"
, "G": "F"
, "F": "G"
};
return cs.map(function(_,i,a){
var crs = [a.slice(i+1),a.slice(0,i+1).reverse()]; // console.log(crs) to see all creases)
return crs[0].reduce( (ps,c,j) => lut[c] === crs[1][j] ? ( ps.res.push([c,crs[1][j],j])
, ps.crs ??= crs.concat(i+1)
, ps
)
: ps
, { res: []
, crs: null
}
);
})
.reduce( (r,d) => r.length ? r[r.length-1].res.length > d.res.length ? r :
r[r.length-1].res.length < d.res.length ? [d] : r.concat(d)
: [d]
, []
);
}
var chars = ["A","A","A","F","F","Z","Z","G","G","F","F","G","G","A","A","A","A","Z","Z","Z","Z"],
result = pairs(chars);
console.log(result);
.as-console-wrapper{
max-height: 100% !important;
}
Now this is a straightforward algorithm and possibly not the most efficient one. It can be made more faster by using complex modular arithmetic on testing pairs without using any additional arrays however i believe it would be an overkill and very hard to explain.

Extracting contiguous rows in an array

The following code in python
df['tag'] = df['Value'] < 1.0
df['mask'] = np.where(df['tag'],1,0)
first = df.index[df['tag'] & ~ df['tag'].shift(1).fillna(False)]
last = df.index[df['tag'] & ~ df['tag'].shift(-1).fillna(False)]
pr = [(i, j) for i, j in zip(first, last) if j > i + 1]
returns an array, pr, that contains tuples of contiguous rows lesser than the Value of 1. I have tried to translate this Julia to a partial extent as follows:
df[:tag]=df[:Value] .< 1.0
df[:mask]=zeros(length(df[:tag]))
df[:mask][df[:tag].==true] .= 1
df[:mask][df[:tag].==false] .= 0
How can I replicate the values for first, last, pr in Julia?
I will give you two possible approaches to this problem. The first is faster, but requires a bit more code. The second is slower, but shorter.
function getblocks1(vs)
blocks = Tuple{Int, Int}[]
inblock, start = false, 0, 0
for (i, v) in enumerate(vs)
if inblock
if v >= 1.0
push!(blocks, (start, i-1))
inblock = false
end
else
if v < 1.0
start = i
inblock = true
end
end
end
inblock && push!(blocks, (start, length(vs)))
blocks
end
function getblocks2(vs)
t = [false; vs .< 1.0; false]
dt = diff(t)
f = findall(==(1), dt)
l = findall(==(-1), dt) .- 1
collect(zip(f, l))
end
The crucial thing to know, that in Julia getblocks1 will be fast because loops in Julia are fast and the function tries to minimize the number of allocations and does everything in one pass. The second implementation is more Python-like, but allocates more and does several passes through the whole vector.

Strange behaviour of simple pycuda kernel

I'm quite new to cuda and pycuda.
I need a kernel that creates a matrix (of dimension n x d) out of an array (1 x d), by simply "repeating" the same array n times:
for example, suppose we have n = 4 and d = 3, then if the array is [1 2 3]
the result of my kernel should be:
[1 2 3
1 2 3
1 2 3
1 2 3]
(a matrix 4x3).
Basically, it's the same as doing numpy.tile(array, (n, 1))
I've written the code below:
kernel_code_template = """
__global__ void TileKernel(float *in, float *out)
{
// Each thread computes one element of out
int y = blockIdx.y * blockDim.y + threadIdx.y;
int x = blockIdx.x * blockDim.x + threadIdx.x;
if (y > %(n)s || x > %(d)s) return;
out[y * %(d)s + x] = in[x];
}
"""
d = 64
n = 512
blockSizex = 16
blockSizey = 16
gridSizex = (d + blockSizex - 1) / blockSizex
gridSizey = (n + blockSizey - 1) / blockSizey
# get the kernel code from the template
kernel_code = kernel_code_template % {
'd': d,
'n': n
}
mod = SourceModule(kernel_code)
TileKernel = mod.get_function("TileKernel")
vec_cpu = np.arange(d).astype(np.float32) # just as an example
vec_gpu = gpuarray.to_gpu(vec_cpu)
out_gpu = gpuarray.empty((n, d), np.float32)
TileKernel.prepare("PP")
TileKernel.prepared_call((gridSizex, gridSizey), (blockSizex, blockSizey, 1), vec_gpu.gpudata, out_gpu.gpudata)
out_cpu = out_gpu.get()
Now, if I run this code with d equals a power of 2 >= 16 I get the right result (just like numpy.tile(vec_cpu, (n, 1)) );
but if I set d equals to anything else (let's say for example 88) I get that every element of the output matrix has the
correct value, except the first column: some entries are right but others have another value, apparently random, same for every wrong element, but different every run,
and also the entries of the first column that have the wrong value are different every run.
Example:
[0 1 2
0 1 2
6 1 2
0 1 2
6 1 2
...]
I really can't figure out what is causing this problem, but maybe it's just something simple that I'm missing...
Any help will be appreciated, thanks in advance!
The bounds checking within your kernel code is incorrect. This
if (y > n || x > d) return;
out[y * d + x] = in[x];
should be:
if (y >= n || x >= d) return;
out[y * d + x] = in[x];
or better still:
if ((y < n) && (x < d))
out[y * d + x] = in[x];
All array valid indexing in the array lies on 0 < x < d and 0 < y < n. By allowing x=d you have undefined behaviour, allowing the first entry in the next row of the output array to be overwritten with an unknown value. This explains why sometimes the results were correct and other times not.

NeedlemanWunsch algorithm

I'm trying to understand the Hirschberg algorithm and I came across this piece of algorithm from Wikipedia. I do not understand how the NeedlemanWunsch() function works.
function Hirschberg(X,Y)
Z = ""
W = ""
if length(X) == 0 or length(Y) == 0
if length(X) == 0
for i=1 to length(Y)
Z = Z + '-'
W = W + Yi
end
else if length(Y) == 0
for i=1 to length(X)
Z = Z + Xi
W = W + '-'
end
end
else if length(X) == 1 or length(Y) == 1
(Z,W) = NeedlemanWunsch(X,Y)
else
xlen = length(X)
xmid = length(X)/2
ylen = length(Y)
ScoreL = NWScore(X1:xmid, Y)
ScoreR = NWScore(rev(Xxmid+1:xlen), rev(Y))
ymid = PartitionY(ScoreL, ScoreR)
(Z,W) = Hirschberg(X1:xmid, y1:ymid) + Hirschberg(Xxmid+1:xlen, Yymid+1:ylen)
end
return (Z,W)
Can someone explain about the NeedlemanWunsch algorithm and how can it be implemented through Python? Thank you very much!
This looks like a homework/coursework question so I won't give you the full solution. However, I will guide you into producing a working solution.
Needleman-Wunsch Algorithm
The Needleman-Wunsch algorithm is a method used to align sequences. It is essentially made up of two components:
A similarity matrix, F.
A linear penalty gap, d.
When aligning sequences, there can be many possibilities. What this matrix allows you to do is to find the most optimal one and discard all the other sequences.
What you will have to do is:
Create a 2-dimensional array to hold the matrix, F.
A method to initialise matrix F with the scores.
A method to compute the optimal sequence.
Creating a 2-dimensional array to hold the matrix, F
You can either use numpy for this, or you could just generate the matrix as follows. Assume you have two sequences A and B:
F = [[0 for x in xrange(len(A)] for x in xrange(len(B))]
A method to initialise matrix F with the scores.
Create a method which takes a parameters the length of each sequence, the linear penalty gap, and the matrix F:
def createSimilarityMatrix(lengthOfA, lengthOfB, penalityGap, F):
You then need to implement the following pseudo-code:
for i=0 to length(A)
F(i,0) ← d*i
for j=0 to length(B)
F(0,j) ← d*j
for i=1 to length(A)
for j=1 to length(B)
{
Match ← F(i-1,j-1) + S(Ai, Bj)
Delete ← F(i-1, j) + d
Insert ← F(i, j-1) + d
F(i,j) ← max(Match, Insert, Delete)
}
Hint: Research optimal ways to write this algorithm in idiomatic Python. Also note that in the double for-loop at the bottom, you can collapse in a one-liner.
A method to compute the optimal sequence
Once you have the similarity matrix done, then you can implement the main algorithm to compute the optimal sequence. For this, create a method which takes your two sequences A and B as parameters:
def needlemanWunsch (a, b):
You will then need to implement this method using the following pseudocode:
AlignmentA ← ""
AlignmentB ← ""
i ← length(A)
j ← length(B)
while (i > 0 or j > 0)
{
if (i > 0 and j > 0 and F(i,j) == F(i-1,j-1) + S(Ai, Bj))
{
AlignmentA ← Ai + AlignmentA
AlignmentB ← Bj + AlignmentB
i ← i - 1
j ← j - 1
}
else if (i > 0 and F(i,j) == F(i-1,j) + d)
{
AlignmentA ← Ai + AlignmentA
AlignmentB ← "-" + AlignmentB
i ← i - 1
}
else (j > 0 and F(i,j) == F(i,j-1) + d)
{
AlignmentA ← "-" + AlignmentA
AlignmentB ← Bj + AlignmentB
j ← j - 1
}
}
The psuedo-code has been taken from this page on Wikipedia. For more information on the Needleman-Wunsch algorithm, please have a look at this presentation.

Pulling data from a numpy array

I have a numpy ndarray that I made using numpy.loadtxt. I want to pull an entire row from it based on a condition in the third column. Something like : if array[2][i] is meeting my conditions, then get array[0][i] and array [1][i] as well. I'm new to python, and all of the numpy features, so I'm looking for the best way to do this. Ideally, I'd like to pull 2 rows at a time, but I wont always have an even number of rows, so I imagine that is a problem
import numpy as np
'''
Created on Jan 27, 2013
#author:
'''
class Volume:
f ='/Users/Documents/workspace/findMinMax/crapc.txt'
m = np.loadtxt(f, unpack=True, usecols=(1,2,3), ndmin = 2)
maxZ = max(m[2])
minZ = min(m[2])
print("Maximum Z value: " + str(maxZ))
print("Minimum Z value: " + str(minZ))
zIncrement = .5
steps = maxZ/zIncrement
currentStep = .5
b = []
for i in m[2]:#here is my problem
while currentStep < steps:
if m[2][i] < currentStep and m[2][i] > currentStep - zIncrement:
b.append(m[2][i])
if len(b) < 2:
currentStep + zIncrement
print(b)
Here is some code that I did in java that is the general idea of what I want:
while( e < a.length - 1){
for(int i = 0; i < a.length - 1; i++){
if(a[i][2] < stepSize && a[i][2] > stepSize - 2){
x.add(a[i][0]);
y.add(a[i][1]);
z.add(a[i][2]);
}
if(x.size() < 1){
stepSize += 1;
}
}
}
First of all, you probably don't want to put your code in that class definition...
import numpy as np
def main():
m = np.random.random((3, 4))
mask = (m[2] > 0.5) & (m[2] < 0.8) # put your conditions here
# instead of 0.5 and 0.8 you can use
# an array if you like
m[:, mask]
if __name__ == '__main__':
main()
mask is a boolean array, m[:, mask] is the array you want
m[2] is the third row of m. If you type m[2] + 2 you get a new array with the old values + 2. m[2] > 0.5 creates an array with boolean values. It is best to try this stuff out with ipython (www.ipython.org)
In the expression m[:, mask] the : means "take all rows", mask describes which columns should be included.
Update
Next try :-)
for i in range(0, len(m), 2):
two_rows = m[i:i+2]
If you can write your condition as a simple function
def condition(value):
# return True or False depending on value
then you could select your subarrays like this:
cond = condition(a[2])
subarray0 = a[0,cond]
subarray1 = a[1,cond]

Categories

Resources