Building an upper triangular matrix recursively - python

Ive been breaking my head over trying to come up with a recursive way to build the following matrix in python. It is quite a challenge without pointers. Could anyone maybe help me out?
The recursion is the following:
T0 = 1,
Tn+1 = [[Tn, Tn],
[ 0, Tn]]
I have tried many iterations of some recursive function, but I cannot wrap my head around it.
def T(n, arr):
n=int(n)
if n == 0:
return 1
else:
c = 2**(n-1)
Tn = np.zeros((c,c))
Tn[np.triu_indices(n=c)] = self.T(n=n-1, arr=arr)
return Tn
arr = np.zeros((8,8))
T(arr=arr, n=3)

It's not hard to do this, but you need to be careful about the meaning of the zero in the recursion. This isn't really precise for larger values of n:
Tn+1 = [[Tn, Tn],
[ 0, Tn]]
Because that zero can represent a block of zeros for example on the second iteration you have this:
[1, 1, 1, 1],
[0, 1, 0, 1],
[0, 0, 1, 1],
[0, 0, 0, 1]
Those four zeros in the bottom-left are all represented by the one zero in the formula. The block of zeros needs to be the same shape as the blocks around it.
After that it's a matter of making Numpy put thing in the right order and shape for you. numpy.block is really handy for this and makes it pretty simple:
import numpy as np
def makegasket(n):
if n == 0:
return np.array([1], dtype=int)
else:
node = makegasket(n-1)
return np.block([[node, node], [np.zeros(node.shape, dtype=int), node]])
makegasket(3)
Result:
array([[1, 1, 1, 1, 1, 1, 1, 1],
[0, 1, 0, 1, 0, 1, 0, 1],
[0, 0, 1, 1, 0, 0, 1, 1],
[0, 0, 0, 1, 0, 0, 0, 1],
[0, 0, 0, 0, 1, 1, 1, 1],
[0, 0, 0, 0, 0, 1, 0, 1],
[0, 0, 0, 0, 0, 0, 1, 1],
[0, 0, 0, 0, 0, 0, 0, 1]])
If you use larger n you might enjoy matplotlib.pyplot.imshow for display:
from matplotlib.pyplot import imshow
# ....
imshow(makegasket(7))

You don't really need a recursive function to implement this recursion. The idea is to start with the UR corner and build outward. You can even start with the UL corner to avoid some of the book-keeping and flip the matrix along either axis, but this won't be as efficient in the long run.
def build_matrix(n):
size = 2**n
# Depending on the application, even dtype=np.bool might work
matrix = np.zeros((size, size), dtype=np.int)
# This is t[0]
matrix[0, -1] = 1
for i in range(n):
k = 2**i
matrix[:k, -2 * k:-k] = matrix[k:2 * k, -k:] = matrix[:k, -k:]
return matrix
Just for fun, here is a plot of timing results for this implementation vs #Mark Meyer's answer. It shows the slight timing advantage (also memory) of using a looping approach in this case:
Both algorithms run out of memory around n=15 on my machine, which is not too surprising.

Related

python function to count nonzero patches in array

For a given array (1 or 2-dimensional) I would like to know, how many "patches" there are of nonzero elements. For example, in the array [0, 0, 1, 1, 0, 1, 0, 0] there are two patches.
I came up with a function for the 1-dimensional case, where I first assume the maximal number of patches and then decrease that number if a neighbor of a nonzero element is nonzero, too.
def count_patches_1D(array):
patches = np.count_nonzero(array)
for i in np.nonzero(array)[0][:-1]:
if (array[i+1] != 0):
patches -= 1
return patches
I'm not sure if that method works for two dimensions as well. I haven't come up with a function for that case and I need some help for that.
Edit for clarification:
I would like to count connected patches in the 2-dimensional case, including diagonals. So an array [[1, 0], [1, 1]] would have one patch as well as [[1, 0], [0, 1]].
Also, I am wondering if there is a build-in python function for this.
The following should work:
import numpy as np
import copy
# create an array
A = np.array(
[
[0, 1, 1, 1, 0, 1],
[0, 0, 1, 0, 0, 0],
[1, 0, 0, 1, 0, 1],
[1, 0, 0, 0, 0, 1],
[0, 0, 1, 0, 0, 1]
]
)
def isadjacent(pos, newpos):
"""
Check whether two coordinates are adjacent
"""
# check for adjacent columns and rows
return np.all(np.abs(np.array(newpos) - np.array(pos)) < 2):
def count_patches(A):
"""
Count the number of non-zero patches in an array.
"""
# get non-zero coordinates
coords = np.nonzero(A)
# add them to a list
inipatches = list(zip(*coords))
# list to contain all patches
allpatches = []
while len(inipatches) > 0:
patch = [inipatches.pop(0)]
i = 0
# check for all points adjacent to the points within the current patch
while True:
plen = len(patch)
curpatch = patch[i]
remaining = copy.deepcopy(inipatches)
for j in range(len(remaining)):
if isadjacent(curpatch, remaining[j]):
patch.append(remaining[j])
inipatches.remove(remaining[j])
if len(inipatches) == 0:
break
if len(inipatches) == 0 or plen == len(patch):
# nothing added to patch or no points remaining
break
i += 1
allpatches.append(patch)
return len(allpatches)
print(f"Number of patches is {count_patches(A)}")
Number of patches is 5
This should work for arrays with any number of dimensions.

How can "self" update original variable correctly? Recursion/Backtracking in the N-queens problem (Python)

This is my python program to solve the 8-queens problem. Everything is working except the final step of printing the solved board. I use recursion/backtracking to fill the board with queens until a solution is found. The board object that holds the solution is self, which is a reference to b1, so I assume that b1, the original board I initialized, would be updated to contain the final solved board, and would print the solution using printBoard. However, b1 is not being updated and is holding a failed board when I print it for some unknown reason.
edit: added placeQueen in solve
EMPTY = 0
QUEEN = 1
RESTRICTED = 2
class Board:
# initializes a 8x8 array
def __init__ (self):
self.board = [[EMPTY for x in range(8)] for y in range(8)]
# pretty prints board
def printBoard(self):
for row in self.board:
print(row)
# places a queen on a board
def placeQueen(self, x, y):
# restricts row
self.board[y] = [RESTRICTED for i in range(8)]
# restricts column
for row in self.board:
row[x] = RESTRICTED
# places queen
self.board[y][x] = QUEEN
self.fillDiagonal(x, y, 0, 0, -1, -1) # restricts top left diagonal
self.fillDiagonal(x, y, 7, 0, 1, -1) # restructs top right diagonal
self.fillDiagonal(x, y, 0, 7, -1, 1) # restricts bottom left diagonal
self.fillDiagonal(x, y, 7, 7, 1, 1) # restricts bottom right diagonal
# restricts a diagonal in a specified direction
def fillDiagonal(self, x, y, xlim, ylim, xadd, yadd):
if x != xlim and y != ylim:
self.board[y + yadd][x + xadd] = RESTRICTED
self.fillDiagonal(x + xadd, y + yadd, xlim, ylim, xadd, yadd)
# recursively places queens such that no queen shares a row or
# column with another queen, or in other words, no queen sits on a
# restricted square. Should solve by backtracking until solution is found.
def solve(self, col):
if col == -1:
return True
for i in range(8):
if self.board[i][col] == EMPTY:
temp = self.copy()
self.placeQueen(col, i)
if self.solve(col - 1):
return True
temp.board[i][col] = RESTRICTED
self = temp.copy()
return False
# deep copies a board onto another board
def copy(self):
copy = Board()
for i in range(8):
for j in range (8):
copy.board[j][i] = self.board[j][i]
return copy
b1 = Board()
b1.solve(7)
b1.printBoard()
I know that my actual solver is working, because when I add a printBoard like so:
if col == -1:
self.printBoard()
return True
in the solve method, a solved board is printed. In short, why is the self instance of a board not updating b1?
I believe your problem is related to redefining self in the solve method, andi'm not even sure why you're doing that.
See this question for more details: Is it safe to replace a self object by another object of the same type in a method?
Reassigning self like you're doing is not reassigning the "b1" reference. So when you reference b1 again and do printBoard, you're referencing a different object than what "self.printBoard()" will be referencing by the time solve is done.
I would step back and ask yourself why you're replacing self to begin with, and what this gains you. You likely don't need too and shouldn't be doing it either.
I'm not sure how this works since placeQueen is never called. As such, I don't see that adding a print as suggested presents a finished board (I see it as empty). [note: the latest update fixes this]
Using the restricted squares idea could work, but the way it's implemented here (without an undo option) is inefficient; copying a whole new Board object for every inner loop is very expensive. For all the trouble, we could just as well perform an iterative conflict check per move which at least saves the allocation and garbage collection costs of a new heap object.
As far as returning the completed board result, use a return value of self or self.board and None on failure rather than True and False.
A few other points:
Since solving a puzzle doesn't require state and we can (hopefully) agree that copying the board is inefficient, I'm not sure if there's much point in allowing an __init__ method. The class is nice as an encapsulation construct and we should hide static variables like EMPTY, QUEEN, etc inside the Board class regardless of whether the class is static or instantiated.
If you do decide to keep the class stateful, printBoard should not produce side effects--override __str__ instead.
Don't hardcode size literals such as 8 throughout the code; this makes the class rigid, difficult to maintain and prone to typos and off-by-one errors. Use len(self.board) instead and provide parameters liberally.
fillDiagonal doesn't need to be recursive. Consider using list comprehensions or numpy to simplify this matrix traversal logic.
Use snake_case variable names and docstrings instead of hashtag comments per PEP-8. If you feel compelled to write a comment like # restricts column, consider moving the relevant chunk to a function called restrict_column(...) and skip the comment.
Here's an initial rewrite that implements a few of these points:
class Board:
EMPTY = 0
QUEEN = 1
DIRS = [(x, y) for x in range(-1, 2) for y in range(-1, 2) if x]
def __init__ (self, size=8):
self.board = [[Board.EMPTY] * size for _ in range(size)]
def __str__(self):
return "\n".join(map(str, self.board))
def legal_from(self, row, col, dr, dc):
while row >= 0 and row < len(self.board) and \
col >= 0 and col < len(self.board[row]):
if self.board[row][col] != Board.EMPTY:
return False
row += dr; col += dc
return True
def legal_move(self, row, col):
return all([self.legal_from(row, col, *d) for d in Board.DIRS])
def solve(self, row=0):
if row >= len(self.board):
return self
for col in range(len(self.board[row])):
if self.legal_move(row, col):
self.board[row][col] = Board.QUEEN
if self.solve(row + 1):
return self
self.board[row][col] = Board.EMPTY
if __name__ == "__main__":
for result in [Board(i).solve() for i in range(9)]:
print(result, "\n")
Output:
[1]
None
None
[0, 1, 0, 0]
[0, 0, 0, 1]
[1, 0, 0, 0]
[0, 0, 1, 0]
[1, 0, 0, 0, 0]
[0, 0, 1, 0, 0]
[0, 0, 0, 0, 1]
[0, 1, 0, 0, 0]
[0, 0, 0, 1, 0]
[0, 1, 0, 0, 0, 0]
[0, 0, 0, 1, 0, 0]
[0, 0, 0, 0, 0, 1]
[1, 0, 0, 0, 0, 0]
[0, 0, 1, 0, 0, 0]
[0, 0, 0, 0, 1, 0]
[1, 0, 0, 0, 0, 0, 0]
[0, 0, 1, 0, 0, 0, 0]
[0, 0, 0, 0, 1, 0, 0]
[0, 0, 0, 0, 0, 0, 1]
[0, 1, 0, 0, 0, 0, 0]
[0, 0, 0, 1, 0, 0, 0]
[0, 0, 0, 0, 0, 1, 0]
[1, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 1, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 1]
[0, 0, 0, 0, 0, 1, 0, 0]
[0, 0, 1, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 1, 0]
[0, 1, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 1, 0, 0, 0, 0]

Coefficients of Charpoly using Sympy in Python

I am new to using the library Sympy. I am need to extract all coefficients of the characteristic polynomial to be used later.
For example, my code is:
import sympy as sp
M = sp.Matrix([[0, 0, 0, 1, 0, 1], [0, 0, 0, 0, 1, 0], [0, 1, 0, 1, 0, -1], [1, 0, -1, 0, 1, 0], [0, 0, 0, 1, 0, 0], [-1, 0, 1, 0, 0, 0]])
lamda = symbols('lamda')
p = M.charpoly(lamda)
print(p)
print(p.coeffs())
which gives output:
PurePoly(lamda**6 + lamda**4 - lamda**2, lamda, domain='ZZ')
[1, 1, -1]
However, I need [1, 0, 1, 0, 1, 0, 0], which includes the zero coefficients of the lamda too the exponents 4, 3, 1, and 0, terms. I would normally use a for loop to iterate over the equation to see which terms are missing so a zero can be inserted into the appropriate spot in the array of coefficients. However, when I attempted to do so, I received an error saying PurePoly type doesn't support indexing. So, I was wondering if anyone knows how to make sympy include the zeros or a way to do it myself? I need will eventually have to incorporate this code into a loop for lots of matrices so I can't manually do it.
Thanks.
When I have questions like this I hope for some sort of intelligent naming of methods for objects and look through the directory of the object:
>>> print([w for w in dir(p) if 'coeff' in w])
['all_coeffs', 'as_coeff_Add', 'as_coeff_Mul', ...]
That all_coeffs is the one you want:
>>> help(p.all_coeffs)
Help on method all_coeffs in module sympy.polys.polytools:
all_coeffs(f) method of sympy.polys.polytools.PurePoly instance
Returns all coefficients from a univariate polynomial ``f``.
>>> p.all_coeffs()
[1,0,1,0,−1,0,0]

Why does SymPy give me the wrong answer when I row-reduce a symbolic matrix?

If I ask SymPy to row-reduce the singular matrix
nu = Symbol('nu')
lamb = Symbol('lambda')
A3 = Matrix([[-3*nu, 1, 0, 0],
[3*nu, -2*nu-1, 2, 0],
[0, 2*nu, (-1 * nu) - lamb - 2, 3],
[0, 0, nu + lamb, -3]])
print A3.rref()
then it returns the identity matrix
(Matrix([
[1, 0, 0, 0],
[0, 1, 0, 0],
[0, 0, 1, 0],
[0, 0, 0, 1]]), [0, 1, 2, 3])
which it shouldn't do, since the matrix is singular. Why is SymPy giving me the wrong answer and how can I get it to give me the right answer?
I know SymPy knows the matrix is singular, because when I ask for A3.inv(), it gives
raise ValueError("Matrix det == 0; not invertible.")
Furthermore, when I remove lamb from the matrix (equivalent to setting lamb = 0), SymPy gives the correct answer:
(Matrix([
[1, 0, 0, -1/nu**3],
[0, 1, 0, -3/nu**2],
[0, 0, 1, -3/nu],
[0, 0, 0, 0]]), [0, 1, 2])
which leads me to believe that this problem only happens with more than one variable.
EDIT: Interestingly, I just got the correct answer when I pass rref() the argument "simplify=True". I still have no idea why that is though.
The rref algorithm fundamentally requires the ability to tell if the elements of the matrix are identically zero. In SymPy, the simplify=True option instructs SymPy to simplify the entries first at the relevant stage of the algorithm. With symbolic entries, this is necessary, as you can easily have symbolic expressions that are identically zero but which don't simplify to such automatically, like x*(x - 1) - x**2 + x. The option is off by default because in general such simplification can be expensive, through this can be controlled by passing in a less general simplify function than simplify (for rational functions, use cancel). The defaults here could probably be smarter.

Is there a "bounding box" function (slice with non-zero values) for a ndarray in NumPy?

I am dealing with arrays created via numpy.array(), and I need to draw points on a canvas simulating an image. Since there is a lot of zero values around the central part of the array which contains the meaningful data, I would like to "trim" the array, erasing columns that only contain zeros and rows that only contain zeros.
So, I would like to know of some native numpy function or even a code snippet to "trim" or find a "bounding box" to slice only the data-containing part of the array.
(since it is a conceptual question, I did not put any code, sorry if I should, I'm very fresh to posting at SO.)
Thanks for reading
This should do it:
from numpy import array, argwhere
A = array([[0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0],
[0, 0, 1, 0, 0, 0, 0],
[0, 0, 1, 1, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0],
[0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0]])
B = argwhere(A)
(ystart, xstart), (ystop, xstop) = B.min(0), B.max(0) + 1
Atrim = A[ystart:ystop, xstart:xstop]
The code below, from this answer runs fastest in my tests:
def bbox2(img):
rows = np.any(img, axis=1)
cols = np.any(img, axis=0)
ymin, ymax = np.where(rows)[0][[0, -1]]
xmin, xmax = np.where(cols)[0][[0, -1]]
return img[ymin:ymax+1, xmin:xmax+1]
The accepted answer using argwhere worked but ran slower. My guess is, it's because argwhere allocates a giant output array of indices. I tested on a large 2D array (a 1024 x 1024 image, with roughly a 50x100 nonzero region).
Something like:
empty_cols = sp.all(array == 0, axis=0)
empty_rows = sp.all(array == 0, axis=1)
The resulting arrays will be 1D boolian arrays. Loop on them from both ends to find the 'bounding box'.

Categories

Resources