Find connected components in list of triangle vertices - python

Consider two graphs, G1 = (V1, E1), G2 = (V2, E2)
V1 = {1,2,3,4,5,6}
V2 = {7,8,9,10,11,12}
In space, these vertices are connected by triangles faces (each with three vertices)
F1 = [[ 2, 1, 0], [ 0, 3, 2], [ 1, 4, 0], [ 0, 4, 3], [ 5, 1, 2], [ 3, 5, 2], [ 5, 4, 1], [ 4, 5, 3]]
F2 = [[ 8, 7, 6], [ 6, 9, 8], [ 7, 10, 6], [ 6, 10, 9], [11, 7, 8], [ 9, 11, 8], [11, 10, 7], [10, 11, 9]]
The above is what I am trying to find. If we are given the entire array of faces:
faces = [[ 2, 1, 0], [ 0, 3, 2], [ 1, 4, 0], [ 0, 4, 3], [ 5, 1, 2], [ 3, 5, 2],
[ 5, 4, 1], [ 4, 5, 3], [ 8, 7, 6], [ 6, 9, 8], [ 7, 10, 6], [ 6, 10, 9],
[11, 7, 8], [ 9, 11, 8], [11, 10, 7], [10, 11, 9]]
can we find the connected components, and separate into F1 and F2?
A version of this problem has been solved in Mathematica, but I cannot translate.
My work is found in this post.

Making a graph from your faces is pretty straightforward: each triplet yields 3 edges corresponding to all combinations of the triplet's members. Then it is just a matter of instantiating the networkx Graph object and calling networkx.algorithms.components.connected_components.
#!/usr/bin/env python
"""
Given a list of triangles, find the connected components.
https://stackoverflow.com/q/61584283/2912349
"""
import itertools
import networkx as nx
faces = [[ 2, 1, 0], [ 0, 3, 2], [ 1, 4, 0], [ 0, 4, 3], [ 5, 1, 2], [ 3, 5, 2],
[ 5, 4, 1], [ 4, 5, 3], [ 8, 7, 6], [ 6, 9, 8], [ 7, 10, 6], [ 6, 10, 9],
[11, 7, 8], [ 9, 11, 8], [11, 10, 7], [10, 11, 9]]
#create graph
edges = []
for face in faces:
edges.extend(list(itertools.combinations(face, 2)))
g = nx.from_edgelist(edges)
# compute connected components and print results
components = list(nx.algorithms.components.connected_components(g))
for component in components:
print(component)
# {0, 1, 2, 3, 4, 5}
# {6, 7, 8, 9, 10, 11}
# separate faces by component
component_to_faces = dict()
for component in components:
component_to_faces[tuple(component)] = [face for face in faces if set(face) <= component] # <= operator tests for subset relation
for component, component_faces in component_to_faces.items():
print(component, component_faces)
# (0, 1, 2, 3, 4, 5) [[2, 1, 0], [0, 3, 2], [1, 4, 0], [0, 4, 3], [5, 1, 2], [3, 5, 2], [5, 4, 1], [4, 5, 3]]
# (6, 7, 8, 9, 10, 11) [[8, 7, 6], [6, 9, 8], [7, 10, 6], [6, 10, 9], [11, 7, 8], [9, 11, 8], [11, 10, 7], [10, 11, 9]]

Related

reduce even array in half by merging columns

Assuming i have the following array:
a = array([[[4, 8, 7, 3, 1, 2],
[3, 1, 8, 7, 1, 9],
[0, 0, 3, 0, 7, 6],
[1, 1, 5, 0, 5, 1],
[1, 6, 7, 0, 6, 2]],
[[8, 1, 1, 0, 0, 0],
[2, 8, 1, 6, 4, 9],
[1, 8, 7, 2, 2, 2],
[6, 6, 2, 6, 0, 5],
[3, 2, 2, 0, 6, 8]],
[[4, 6, 3, 2, 1, 4],
[0, 4, 3, 5, 9, 4],
[1, 4, 6, 7, 2, 4],
[6, 3, 5, 7, 7, 8],
[1, 0, 3, 9, 2, 5]],
[[7, 7, 3, 9, 7, 0],
[8, 5, 1, 4, 3, 9],
[9, 7, 9, 5, 4, 9],
[2, 0, 6, 0, 8, 5],
[4, 4, 4, 7, 5, 2]],
[[4, 0, 8, 2, 1, 0],
[2, 4, 0, 7, 3, 7],
[4, 6, 8, 7, 9, 6],
[3, 2, 7, 5, 2, 3],
[7, 6, 3, 0, 1, 5]]])
Is there an easy way to reduce the column values by summing to get the following array:
b = array([[[12, 10, 3],
[4, 15, 10],
[0, 3, 13],
[2, 5, 6],
[7, 7, 8]],
...])
The first row is achieved by:[4+8, 7+3, 1+2]. I know we can use np.sum to merge columns but I am lost on how to select the right columns to add together. Help is greatly appreciated!
You can do simply this:
a.reshape((5,5,3,2)).sum(axis=-1)
reshape((5,5,3,2)) will 'split' the last dimension into groups of 2, the sum(axis=-1) will sum over that last freshly created dimension.
In the general case (if the dimensions of a change) you can also use
a.reshape(a.shape[:-1]+(-1,2)).sum(axis=-1)
We can do this with simple numpy slicing.
b = a[:,:,::2] + a[:,:,1::2]
This tells us to select the whole array, and at the last dimension select the even columns, then the odd columns, and add them together elementwise.

Is there an alternate way to do the same without for loop?

I have two numpy arrays A and l. The dimension of A is (n, x, y) and the dimension of l is (n,1). I get the result as follows:
res = []
for i in range(n):
res.append(A[i, x, l[i])
This way of getting the result is very time consuming for a larger value of n. Is there an alternative to get the same result quickly?
If 0<=l[i]<y for all values of i:
>>> n,x,y = 4,5,6
>>> A = np.random.randint(0,10,(n,x,y))
array([[[3, 3, 3, 8, 7, 0],
[8, 1, 1, 5, 3, 8],
[0, 1, 0, 4, 1, 3],
[2, 2, 1, 8, 6, 5],
[2, 5, 9, 2, 6, 3]],
[[9, 7, 4, 6, 7, 7],
[1, 7, 0, 4, 9, 6],
[8, 0, 8, 6, 7, 8],
[1, 9, 7, 8, 7, 6],
[2, 4, 6, 3, 6, 8]],
[[2, 8, 5, 7, 9, 4],
[7, 2, 2, 5, 2, 1],
[0, 8, 6, 4, 1, 2],
[6, 9, 9, 0, 2, 4],
[9, 9, 1, 6, 7, 0]],
[[3, 8, 4, 3, 5, 6],
[5, 3, 7, 7, 4, 6],
[9, 0, 7, 9, 2, 1],
[1, 6, 2, 2, 9, 5],
[5, 0, 9, 0, 5, 2]]])
>>> l = np.random.randint(low=0, high=y-1, size=(n,1))
array([[0],
[1],
[3],
[1]])
>>> x0 = 2
>>> res = []
>>> for i in range(n):
res.append(A[i, x0, l[i])
>>> res
[array([0]), array([0]), array([4]), array([0])]
numpy:
>>> A[range(n), 2, l.flatten()]
array([0, 0, 4, 0])
what about list comprehension?
res=[A[i, x, l[i] for i in range(n)]

Elementwise operations in numpy

I have a 4000 x 16 matrix A. I have 256 x 1 vector B. I need to get the elementwise addition for each element in A with every element of B and get a 3D array of size 4000 x 16 x 256. What is the most efficient way to achieve this without loops with numpy?
You can first reshape A to a 4000×16×1 matrix, and B to 1×1×256 matrix. Then you can perform addition:
A[:,:,None] + B.reshape(1, 1, -1)
For A a 4×5 matrix, and B a 3×1 matrix, for example, we get:
>>> A
array([[1, 2, 2, 2, 2],
[2, 1, 0, 3, 2],
[4, 1, 2, 1, 3],
[3, 2, 3, 2, 2]])
>>> B
array([[0],
[3],
[3],
[6],
[4],
[3]])
>>> A[:,:,None] + B.reshape(1, 1, -1)
array([[[ 1, 4, 4, 7, 5, 4],
[ 2, 5, 5, 8, 6, 5],
[ 2, 5, 5, 8, 6, 5],
[ 2, 5, 5, 8, 6, 5],
[ 2, 5, 5, 8, 6, 5]],
[[ 2, 5, 5, 8, 6, 5],
[ 1, 4, 4, 7, 5, 4],
[ 0, 3, 3, 6, 4, 3],
[ 3, 6, 6, 9, 7, 6],
[ 2, 5, 5, 8, 6, 5]],
[[ 4, 7, 7, 10, 8, 7],
[ 1, 4, 4, 7, 5, 4],
[ 2, 5, 5, 8, 6, 5],
[ 1, 4, 4, 7, 5, 4],
[ 3, 6, 6, 9, 7, 6]],
[[ 3, 6, 6, 9, 7, 6],
[ 2, 5, 5, 8, 6, 5],
[ 3, 6, 6, 9, 7, 6],
[ 2, 5, 5, 8, 6, 5],
[ 2, 5, 5, 8, 6, 5]]])
Performance: If I run the above 100 times with A a 4000×16 matrix, and B a 256×1 matrix of floating points, I get the following results:
>>> timeit(lambda: A[:,:,None] + B.reshape(1, 1, -1), number=100)
5.949456596048549
It thus takes roughly 59.49457ms for a single run. This looks reasonable to calculate 16'384'000 elements.
This is where numpy's broadcasting and np.transpose() features really shine!
A[:,:, np.newaxis] + B[np.newaxis,:,:].transpose(2,0,1)

How can I make this triple Sudoku for loop work

I am having some trouble with this algorithm. I am only able to grab one sub grid. I've only included the sub grid part here as I've done checkRows and checkColumns on my own. How can I connect this code to capture the rest? Your help is greatly appreciated. Thanks.
class Sudoku_Checker:
def __init__(self,board):
self.board = board
def board_validater(self,board):
self.checkSquares(board)
return self.checkSquares(board) == True
def checkSquares(self,board):
compare = [1,2,3,4,5,6,7,8,9]
hold = []
row = 0
column = 0
square = 0
for p in range(square, square+3):
for i in range(row, row + 3):
for j in range(column, column + 3):
hold.append(board[i][j])
if len(hold)==9:
if sorted(hold) == compare:
hold =[]
continue
else:
return False
square +=3
row += 3
return True
board = [ [5, 3, 4, 6, 7, 8, 9, 1, 2],
[6, 7, 2, 1, 9, 5, 3, 4, 8],
[1, 9, 8, 3, 4, 2, 5, 6, 0],
[8, 5, 9, 7, 6, 1, 4, 2, 3],
[4, 2, 6, 8, 5, 3, 7, 9, 1],
[7, 1, 3, 9, 2, 4, 8, 5, 6],
[9, 6, 1, 5, 3, 7, 2, 8, 4],
[2, 8, 7, 4, 1, 9, 6, 3, 5],
[3, 4, 5, 2, 8, 6, 1, 7, 9]]
s = Sudoku_Checker(board)
s.board_validater(board)
So in my exemple with line and column variable i get the upper left corner of eaxh 3x3 matrix and then i iterate from there to construct the square.
Please let me know if this is what you are looking for.
board = [
[5, 3, 4, 6, 7, 8, 9, 1, 2],
[6, 7, 2, 1, 9, 5, 3, 4, 8],
[1, 9, 8, 3, 4, 2, 5, 6, 0],
[8, 5, 9, 7, 6, 1, 4, 2, 3],
[4, 2, 6, 8, 5, 3, 7, 9, 1],
[7, 1, 3, 9, 2, 4, 8, 5, 6],
[9, 6, 1, 5, 3, 7, 2, 8, 4],
[2, 8, 7, 4, 1, 9, 6, 3, 5],
[3, 4, 5, 2, 8, 6, 1, 7, 9]
]
for line in range(0, 9, 3):
for column in range(0, 9, 3):
square = [[board[l][c] for c in range(column, column + 3)] for l in range(line, line + 3)]
print(square)
Result:
[[5, 3, 4], [6, 7, 2], [1, 9, 8]]
[[6, 7, 8], [1, 9, 5], [3, 4, 2]]
[[9, 1, 2], [3, 4, 8], [5, 6, 0]]
[[8, 5, 9], [4, 2, 6], [7, 1, 3]]
[[7, 6, 1], [8, 5, 3], [9, 2, 4]]
[[4, 2, 3], [7, 9, 1], [8, 5, 6]]
[[9, 6, 1], [2, 8, 7], [3, 4, 5]]
[[5, 3, 7], [4, 1, 9], [2, 8, 6]]
[[2, 8, 4], [6, 3, 5], [1, 7, 9]]
Hopefully someone finds this useful. I prefer this implementation because it is more readable and understandable to me. The other commentor also has a good solution except for the list comprehension which is too much of a loop.
class Sudoku_Checker:
def __init__(self,board):
self.board = board
def board_validater(self,board):
return self.checkSquares(board) == True
def checkSquares(self,board):
compare = range(1,10)
for i in range(0, 9, 3):
for j in range(0, 9, 3):
nums = board[i][j:j+3] + board[i+1][j:j+3] + board[i+2][j:j+3]
if sorted(nums) == compare:
continue
else:
return False
return True
board = [ [5, 3, 4, 6, 7, 8, 9, 1, 2],
[6, 7, 2, 1, 9, 5, 3, 4, 8],
[1, 9, 8, 3, 4, 2, 5, 6, 0],
[8, 5, 9, 7, 6, 1, 4, 2, 3],
[4, 2, 6, 8, 5, 3, 7, 9, 1],
[7, 1, 3, 9, 2, 4, 8, 5, 6],
[9, 6, 1, 5, 3, 7, 2, 8, 4],
[2, 8, 7, 4, 1, 9, 6, 3, 5],
[3, 4, 5, 2, 8, 6, 1, 7, 9]]
s = Sudoku_Checker(board)
s.board_validater(board)

How to get all submatrices of given size in numpy?

For example, x = np.random.randint(low=0, high=10, shape=(6,6)) gives me a 6x6 numpy array:
array([[3, 1, 0, 1, 5, 4],
[2, 9, 9, 4, 8, 8],
[2, 3, 4, 3, 2, 9],
[5, 8, 4, 5, 7, 6],
[3, 0, 8, 1, 8, 0],
[6, 7, 1, 9, 0, 5]])
How can I get a list of, say, all 2x3 submatrices? What about non-overlapping ones?
I could code this in myself, but I'm sure this is a common enough operation that it already exists in numpy, I just can't find it.
Listed in this post is a generic approach to get a list of submatrices with given shape. Based on the order of submatrices being row (C-style) or column major (fortran-way), you would have two choices. Here's the implementation with np.reshape , np.transpose and np.array_split -
def split_submatrix(x,submat_shape,order='C'):
p,q = submat_shape # Store submatrix shape
m,n = x.shape
if np.any(np.mod(x.shape,np.array(submat_shape))!=0):
raise Exception('Input array shape is not divisible by submatrix shape!')
if order == 'C':
x4D = x.reshape(-1,p,n/q,q).transpose(0,2,1,3).reshape(-1,p,q)
return np.array_split(x4D,x.size/(p*q),axis=0)
elif order == 'F':
x2D = x.reshape(-1,n/q,q).transpose(1,0,2).reshape(-1,q)
return np.array_split(x2D,x.size/(p*q),axis=0)
else:
print "Invalid output order."
return x
Sample run with a modified sample input -
In [201]: x
Out[201]:
array([[5, 2, 5, 6, 5, 6, 1, 5],
[1, 1, 8, 4, 4, 5, 2, 5],
[4, 1, 6, 5, 6, 4, 6, 1],
[5, 3, 7, 0, 5, 8, 6, 5],
[7, 7, 0, 6, 5, 2, 5, 4],
[3, 4, 2, 5, 0, 7, 5, 0]])
In [202]: split_submatrix(x,(3,4))
Out[202]:
[array([[[5, 2, 5, 6],
[1, 1, 8, 4],
[4, 1, 6, 5]]]), array([[[5, 6, 1, 5],
[4, 5, 2, 5],
[6, 4, 6, 1]]]), array([[[5, 3, 7, 0],
[7, 7, 0, 6],
[3, 4, 2, 5]]]), array([[[5, 8, 6, 5],
[5, 2, 5, 4],
[0, 7, 5, 0]]])]
In [203]: split_submatrix(x,(3,4),order='F')
Out[203]:
[array([[5, 2, 5, 6],
[1, 1, 8, 4],
[4, 1, 6, 5]]), array([[5, 3, 7, 0],
[7, 7, 0, 6],
[3, 4, 2, 5]]), array([[5, 6, 1, 5],
[4, 5, 2, 5],
[6, 4, 6, 1]]), array([[5, 8, 6, 5],
[5, 2, 5, 4],
[0, 7, 5, 0]])]

Categories