Check for pattern recursively - python

*Note i refer to thing as a matrix but it is not, it is just a collection of 1's and zeros
Suppose you have a matrix that is always square (n x n). Is it possible to determine if there exists a single column/row/diagonal such that each item is a 1.
Take the matrix below for instance (True):
1 0 0
1 1 0
0 0 1
Another example (True):
1 1 1
0 0 0
0 1 0
And finally one without a solution (False):
0 1 1
1 0 0
0 0 0
Notice how there is a diagonal filled with 1's. The rule is there is either there is a solution or there is no solution. There can be any number of 1's or zeros within the matrix. All i really need to do is, if you have (n x n) then there should be a row/column/diagonal with n elements the same.
If this is not possible with recursions, please let me know what is the best and most efficient method. Thanks a lot, i have been stuck on this for hours so any help is appreciated (if you could post samples that would be great).
EDIT
This is one solution that i came up with but it gets really complex after a while.
Take the first example i gave and string all the rows together so you get:
1 0 0, 1 1 0, 0 0 1
Then add zeros between the rows to get:
1 0 0 0, 1 1 0 0, 0 0 1 0
Now if you look closely, you will see that the distances between the 1's that form a solution are equal. I dont know how this can be implemented though.

In search for an elegant solution I came up with this:
class LineOfOnesChecker(object):
_DIAG_INDICES = (lambda i: i, lambda i: -i - 1)
def __init__(self, matrix):
self._matrix = matrix
self._len_range = range(len(self._matrix))
def has_any(self):
return self.has_row() or self.has_col() or self.has_diag()
def has_row(self):
return any(all(elem == 1 for elem in row)
for row in self._matrix)
def has_col(self):
return any(all(self._matrix[i][j] == 1 for i in self._len_range)
for j in self._len_range)
def has_diag(self):
return any(all(self._matrix[transf(i)][i] == 1 for i in self._len_range)
for transf in self._DIAG_INDICES)
Usage:
print LineOfOnesChecker(matrix).has_any()

You can have a list of n 1's and do an 'AND' for your sets of diagonal elements, row elements and column elements and if any of those AND operation results in a TRUE, then you have your valid pattern.
import sys
matrix = [[1,0,1],[1,0,1],[1,0,1]]
transpose = zip(*matrix)
diagonal1 = []
for n,elem in enumerate(matrix):
diagonal1.append(elem[n])
diagonal2 = []
for n,elem in enumerate(transpose):
diagonal2.append(elem[n])
for row in matrix:
if reduce(lambda x,y: x and y, row):
print True
sys.exit()
for row in transpose:
if reduce(lambda x,y: x and y, row):
print True
sys.exit()
if (reduce(lambda x,y: x and y, diagonal1) or reduce(lambda x, y: x and y, diagonal2)):
print True
sys.exit()

From what I understand of the problem, you just need to check whether any row, coloumn or diagonal consists entirely of '1's. This can be done very easily using all in Python, so I don't get why you want to do this recursively.
The more obvious solution (in my mind) is something like this:
#! /usr/bin/env python
boards=[
((0,1,0),(1,0,1),(0,1,0)),
((1,1,1),(0,0,0),(0,0,0)),
((0,0,0),(1,1,1),(0,0,0)),
((0,0,0),(0,0,0),(1,1,1)),
((1,0,0),(1,0,0),(1,0,0)),
((0,1,0),(0,1,0),(0,1,0)),
((0,0,1),(0,0,1),(0,0,1)),
((1,0,0),(0,1,0),(0,0,1)),
((0,0,1),(0,1,0),(1,0,0)),
((0,0,0),(0,0,0),(0,0,0))
]
def check(board):
for row in board:
if all(row):
return True
for col in xrange(len(board)):
vector=[board[row][col] for row in xrange(len(board))]
if all(vector):
return True
diag1=[board[i][i] for i in xrange(len(board))]
if all(diag1):
return True
diag2=[board[i][i] for i in xrange(len(board)-1,-1,-1)]
if all(diag2):
return True
return False
if __name__=='__main__':
for board in boards:
if check(board):
print "Yes"
else:
print "No"

Related

List of binary numbers: How many positions have a one and zero

I have a list of integers, e.g. i=[1,7,3,1,5] which I first transform to a list of the respective binary representations of length L, e.g. b=["001","111","011","001","101"] with L=3.
Now I want to compute at how many of the L positions in the binary representation there is a 1 as well as a zero 0. In my example the result would be return=2 since there is always a 1 in the third (last) position for these entries. I would be happy for any comment. I think, ideally I should do many Xor operations at the same time. However, I'm not sure how I can do this efficiently.
Edit: Thanks for the many answers!! I have to check which one is the fastest.
One observation is that if you take the AND of all numbers, and also the OR of all numbers, then the XOR of those two results will have a 1 where the condition is fulfilled.
So:
from functools import reduce
from operator import and_, or_
def count_mixed_bits(lst):
xor = reduce(and_, lst) ^ reduce(or_, lst)
return bin(xor).count("1")
count_mixed_bits([1,7,3,1,5]) # 2
There's a numpy.binary_repr method that accepts length. Unfortunately, it can't handle arrays. But you can apply a functionality of np.unravel_index instead:
def check(arr, lenght):
positions = np.array(np.unravel_index(i, (2,)*lenght))
return positions, np.sum(np.sum(positions, axis=1) != len(arr))
>>> positions, output = check(i, 3)
>>> print(positions)
>>> print(output)
[[0 1 0 0 1]
[0 1 1 0 0]
[1 1 1 1 1]]
2
Here is a solution, I suspect it is not very efficient, but it is easy to understand.
I loop over the digits and find the unique set, then I count the number of entries with a set length of two:
# create a binary list of 3 elements from input list of integers
i=[1,7,3,1,5]
b=['{0:03b}'.format(x) for x in i]
# loop over the digit position (1,2,3)
cnt=[]
for pos in range(3):
cnt.append(len(set([c[pos] for c in b])))
# cnt now contains a list of either 2(=both 1 and 0 present) or 1 (unique)
# so now we count the number of entries with "2"
result=cnt.count(2)
print (result)
answer:
2
First of all your question is tagged with numpy but your array is not a numpy array.
Here is a solution that uses numpy:
import numpy as np
def has_zeroes_and_ones_at_index(arr, index_from_right):
shifted_arr = np.right_shift(arr, index_from_right)
has_one_at_index = shifted_arr % 2 == 1
return(True in has_one_at_index and False in has_one_at_index)
arr = np.array([1, 7, 3, 1, 5])
res= has_zeroes_and_ones_at_index(arr, 1)
print(res)
Because the numbers are stored in binary we can use bit shifting to move all bits of the numbers to the right and then look at the last bit. We dont have to cast them to a binary format before.
5 (101) right shift by one -> 2 (010)
We then create a mask to see which numbers have a one in the last bit and return True when in the mask there is at least one True element and one false element.
You can use python bitwise operators for this task.
def find(aList, nn):
return sum(
filter(
lambda bb: bb > 0 ,
(
( 1 <= (sum( (aa & 1<<kk) > 0 for aa in aList)) < len(aList) )
for kk in range(nn)
)
)
)
>>> find([1,7,3,1,5],3)
2
>>> find([],3)
0
>>> find([7],3)
0
>>> find([7,1],3)
2
>>> find([7,1,7],3)
2

Giving positional arguments for Co-ordinates and Clustering them together

so I have a data file and I'm wanting to find two things:
Whether the coordinates I give are inside or outside an area and returning if its true or not
Put each coordinates of "1" together in each line in its own list. This should return it in a dictionary.
The file has the following:
1 1 0 1 0 1
0 0 1 1 1 0
1 1 1 1 1 0
1 0 0 0 0 1
0 0 1 1 0 1
1 0 0 0 0 1
I've put the above into a list and each with the code:
lines = []
with open('area.dat', 'r') as a:
for line in a:
line = line.strip()
if not line:
continue
lines.append(list(map(int, line.split())))
data.extend(map(int, line.split()))
print(lines)
My attempts at code to get the coordinates and whether it's outside or inside the area (for both x and y)
area is the list of lists
x = int(input('enter x: '))
y = int(input('enter y: '))
def cords(x, y, area):
if x > 6 or y > 6:
print('Outside Area')
return(False)
else:
print('Inside Area')
return(True)
I want to get a coordinate x and y within the list "area" and return whether it is in or out this.
So for example if I put in cords(0,4,area) it will return "True" and if I put cords(3,7,area) it will return "False".
After this I then want to put them together in groups of 1's by each line.
so for example line 1 and 2 would give:
{1: [(0,4), (0,5)], 2: [(1,0), (1,1)]}
All help is appreciated thanks.
For the first part you have two options:
def cords(x, y):
return x >= 0 and x < 6 and y >= 0 and y < 6
This first option is static for an area size of 6x6, note that array indexing starts at 0 so 6 would already be out of bounds.
def cords(x, y, area):
return x >= 0 and x < len(area) and y >= 0 and y < len(area[0])
This second option dynamically checks whether the coordinates are in bounds of the given nested list. You might have to adjust it based on whether x and y relate to rows and columns or vice versa.
Now for your second part, you're creating a dictionary with redundant information, since the index (1 and 2 in your example) directly relates to the first axis (0 and 1 in your example), you might want to reconsider what you actually want to achieve here.
d = {}
for i,row in enumerate(lines):
n = []
for j,v in enumerate(row):
if v == 1:
n.append([i,j])
d[i+1] = n

Optimization problem of connection between nodes

I have a problem that I am struggling to solve efficiently. I have 2 sets of nodes, A_1, ... A_m and B_1,... B_m. Each node from one set can be connected to a node from the other set with a given constant probability p. Then, what I want is to have the maximum links between the set A and the set B under the condition that there is one and only one node remaining between each single node of A and B.
For example if A_i is connected to B_j and B_j', then we have either to remove the link with either B_j or B_j'.
The successful link between A_i and B_j can be stored in a matrix where M_{ij} = 1 if there is a link between A_i and B_j, 0 if not.
This matrix can for example be simulated by the given code for a matrix dimension 5 and a probability 0.7 of successful link (in python):
import numpy as np
m = 5
proba = 0.7
M = np.random.choice([0, 1], size=(m, m), p=[1 - proba, proba])
This can give for example the matrix:
M =
[[0 1 0 1 0]
[1 1 1 0 1]
[1 1 1 0 0]
[0 0 0 1 0]
[1 1 1 1 1]]
What I want is to implement the transformation on this matrix that satisfies the condition of maximum one link between nodes while maximizing the number of links. This transformation convert M into M_2.
Here's the condition on M_2:
In the end, there is k<= m links between the set A and the set B as each node of A can in fine connect to only one single node (or zero) of the the set of B.
This translate in terms of matrix into a transformation from M to M_2 where M_2_{ij} is equal either to M_{ij} or 0. If M_2_{i0,j0} = 1 then M_2_{i, j0} = 0 and M'_{i0, j} = 0 for all i, j != i0, j0. It means that there is only one (or zero) non zero term per row and per column.
It is easy to remove any terms in a row if one is already equal to one. The hard part of what I want my code to do is to maximize the number of non-zero terms of the matrix M_2 while respecting the conditions on the matrix M_2.
I've managed to do painfully the "automatic reduction part" where if you find a row with only one non-zero term, you remove the non-zero terms of the associated column and conversely. I've done it recursively, until the transformed matrix stays the same (The code is at the end, and is quite complicated to understand, because I think that I've not found the elegant way to do it...)
With this code there is some improvements:
M_2' =
[[0 1 0 0 0]
[1 0 1 0 1]
[1 0 1 0 0]
[0 0 0 1 0]
[1 0 1 0 1]]
There are less non-zero terms compared to M in this matrix but still, it does not respect the conditions.
What I want is to automatically do the final step to find the matrix M_2 which by hand should look like this:
M_2 =
[[0 1 0 0 0]
[1 0 0 0 0]
[0 0 1 0 0]
[0 0 0 1 0]
[0 0 0 0 1]]
But I have no idea how to automatically and efficiently do such optimization... Anyone have ideas how to realize that?
Thank you in advance.
Paul
The code for the straightforward transformation that gave me M_2' is the following (if you have any improvement for a more pythonic or efficient way to write it, I'd be happy to see it):
def remove_straightforward_terms(M):
"""Transform the matrix M by removing a maximum of non-zero terms."""
# Index of the non-zero (=1) terms:
ind_i, ind_j = np.where(M == 1)
# Remove automatically some terms:
new_ind_i, new_ind_j = automatic_remove_straightforward(ind_i, ind_j)
# Rebuild the matrix using this terms
return build_matrix_non_zero(M, new_ind_i, new_ind_j)
def build_matrix_non_zero(M, ind_i, ind_j):
"""Rebuild the matrix using non-zero terms indices."""
M_2 = np.zeros(M.shape, dtype=int)
for ind, val in np.ndenumerate(ind_i):
M_2[ind_i[ind], ind_j[ind]] = 1
return M_2
def automatic_remove_straightforward(ind_i, ind_j):
"""Recursively remove the terms from ind_i and ind_j."""
ind_j_int_2 = []
ind_i_int_2 = []
while len(ind_i) != len(ind_i_int_2) and len(ind_j) != len(ind_j_int_2):
if len(ind_i_int_2) != 0:
# Necessary for entering the while loop...
ind_i = ind_i_int_2
ind_j = ind_j_int_2
# If there is only one non zero term for a given row, remove the other corresponding terms from the column.
ind_i_int_2, ind_j_int_2 = remove_indices_straightforward(ind_i, ind_j)
# If there is only one non zero term for a given column, remove the other corresponding terms from the row.
ind_j_int_2, ind_i_int_2 = remove_indices_straightforward(
ind_j_int_2, ind_i_int_2)
return ind_i, ind_j
def remove_indices_straightforward(ind_i, ind_j):
"""Remove the non-zero terms automatically.
Let's consider i is the column and j the row"""
unique_i, counts_i = np.unique(ind_i, return_counts=True)
# Record all the indices that will be removed (it correspond to removing non-zero terms)
remove_ind = []
for ind, val_counts in np.ndenumerate(counts_i):
if val_counts == 1:
# If a term is in ind_i is only here once (it is alone on its line).
val_i = unique_i[ind]
# We find its position in the list ind_i
index_ind_i = np.where(ind_i == val_i)[0]
# We find the correspond row of the list ind_j
val_j = ind_j[index_ind_i]
# We find the indices of all the non-zero terms share the same row.
indices_ind_j = np.where(ind_j == val_j)[0]
# We record all but the one that was found in the first place
indices_ind_j = indices_ind_j[indices_ind_j != index_ind_i]
# and put them in the remove_ind
remove_ind = np.concatenate((remove_ind, indices_ind_j))
# We remove the indices that we don't want anymore
new_ind_j = np.delete(ind_j, remove_ind)
new_ind_i = np.delete(ind_i, remove_ind)
return new_ind_i, new_ind_j
M_2 = remove_straightforward_terms(M)
EDIT:
Using the solution proposed by btilly, here is how to obtain the desired matrix:
import numpy as np
import networkx as nx
from networkx.algorithms import bipartite
m = 5
p = 0.7
def connecting(m, p):
G_1 = nx.bipartite.random_graph(m, m, p)
top_nodes = {n for n, d in G_1.nodes(data=True) if d['bipartite'] == 0}
A = nx.bipartite.hopcroft_karp_matching(G_1, top_nodes)
M = np.zeros((m, m), dtype=int)
for node_1, node_2 in A.items():
if node_1 < m:
M[node_1, node_2 - m] = 1
return M

Basic Sudoku checker

I am creating a basic sudoku checker with the help of Python.
However, the result is always displayed as 'False'.
The code is as follows:
list = [[1,2,3,4],
[2,4,1,3],
[3,1,4,2],
[4,3,2,1]]
def sudoku_check(list):
n = len(list)
digit = 1
while digit <= n:
row_count = 0
col_count = 0
v = 0
while v < n:
x = 0
while x < n:
print ("Check")
if digit == list[v][x]:
row_count = row_count + 1
if digit == list[x][v]:
col_count = col_count + 1
x = x + 1
v = v + 1
if col_count != 1 or row_count != 1:
return False
digit = digit + 1
return True
print (sudoku_check(list))
I am new to programming. Would appreciate your help on this.
Thanks
Alright, have a solution for you/can explain your problem #ShreyashKarnik!
The Problem:
The issue in code comes from the chunk below:
while digit <= n:
row_count = 0
col_count = 0
v = 0
while v < n:
x = 0
while x < n:
print ("Check")
if digit == sudo_board[v][x]:
row_count = row_count + 1
if digit == sudo_board[x][v]:
col_count = col_count + 1
x = x + 1
v = v + 1
if col_count != 1 or row_count != 1:
return False
So what exactly is this code doing? It's going through every cell in your sudoku board and looking for a digit. For the sake of explanation, let's say it's looking for the digit 1. It checks every cell in the entire board, and since 1 appears 4 times total, col_count and row_count will be 4 every time. You can verify this with a print statement if you'd like!
Since your false check is checking against the number 1, it's going to fail every time. So let's start looking for a fix!
Making Things Pythonic
"Pythonic means code that doesn't just get the syntax right but that follows the conventions of the Python community". You say you're new to programming, so learning the proper style of how to write python is important. You have a couple of issues in the code above:
Confusing variable names
Using while loops instead of for loops
Lack of code modularity
Let's start with the last comment, lack of modularity and fix the other things along the way. Determining if a Sudoku grid is valid is actually surprisingly complex -- it has three components.
1. Do all of the rows have the right number of digits?
2. Do all of the columns have the right number of digits?
3. Does the grid as a whole have the right number of digits?
3 is actually a factor of 1 and 2, which you figured out in your code -- nice! But it might make things easier to read if we broke the first and second bit of things into their own functions. How might those look? Let's do rows first. For our function, we'll check each row and confirm that it has the right number of digits.
Let's start with the row checker. All we have to do for that is the following:
def has_correct_number_rows(sudo_board):
# the set we create below is an unordered grouping of the numbers
# 1-4.
correct_set = set(range(1, len(sudo_board)))
for row in sudo_board:
# this if statement checks if our row contains values 1-4
if (correct_set != set(row)):
return False
return True
This will return True if the rows all contain the correct number of items, otherwise it will give false.
Next, the checking the correct number of columns. This is slightly more complicated, but still fairly simple:
def has_correct_number_cols(sudo_board):
correct_set = set(range(1, len(sudo_board) + 1))
for col_num in range(0, len(sudo_board)):
# col_set creates a set of the elements in a given column
col_set = set([row[col_num] for row in sudo_board])
if (correct_set != set(row)):
return False
return True
Same return values here.
Putting it all together
Now that you have these two functions, your final check is actually very easy. It's below:
def sudoku_check_peter(sudo_board):
correct_rows = has_correct_number_rows(sudo_board)
correct_cols = has_correct_number_cols(sudo_board)
# This last line returns True if both are true, otherwise
# False.
return correct_rows and correct_cols
This ended up being quite wordy which I apologize for -- happy to answer follow up questions or explain anything more! hope this helps.

How to create a numpy matrix, whose values meet several conditions?

I want to create a matrix, that meets this condition at first:
e.g. if a value m[2][1] == 0 <-> m[1][2] in {0,1}
For this one I use an upper triangular matrix like:
m = np.ones((6, 6), int)
m = np.triu(m, 1)
And I change some random values of the remaining to zero, until a certain percentage is achieved:
MaxPer = 0.75
i, e = np.count_nonzero(m), np.count_nonzero(m)
MAX = np.round(MaxPre*e)
while i > MAX:
m[np.random.randint(len(m[0][:]))][np.random.randint(len(m[0][:]))] = 0
i = np.count_nonzero(m)
Now the second criteria is the one I am struggling with:
if m[1][2] == 1 & m[1][3] == 0 <-> m[2][3] == 0
I want to check, if all values in m satisfy this condition (indices 1,2,3 are examples). If not, I want to change the value of m[2][3] to zero. I tried the following code with for-loops, but it overwrites all the values to zero.
for k in range(len(m[0][:])):
for l in range(k, len(m[0][:])):
for j in range(l,len(m[0][:])):
if matrix[k][l] == 1 & matrix[k][j] == 0:
matrix[l][j] = 0
Is there a simple way to this without the loops?
I think imposing your second condition indeed causes zeroing of the matrix.
Are you sure you want
m[i][j] == 1 & m[i][k] == 0 <-> m[j][k] == 0
without any dependencies between i, j, and k?
Maybe you want something like this (which would require a few changes in the fors)?
m[i][i+1] == 1 & m[i][i+2] == 0 <-> m[i+1][i+2] == 0

Categories