Adding values to a matrix with a for loop in python - python

My intention with this program was to get a 4x4 matrix with certain values, but for some reason the loop is putting everything into the same row/column... What is off about my code?
def matrixH0(k):
H0=[]
print H0
for m in range (0,k):
for n in range (0,k):
if abs(m-n)==1:
H0.append(math.sqrt(n+m+1)/2.)
else:
H0.append(0)
print H0
This is my output:
[0,
0.7071067811865476,
0,
0,
0.7071067811865476,
0,
1.0,
0,
0,
1.0,
0,
1.224744871391589,
0,
0,
1.224744871391589,
0]

Append rows to H0, append values to rows:
import math
import pprint
def matrixH0(k):
H0 = []
for m in range(k):
# create a new row
row = []
for n in range(k):
if abs(m-n)==1:
row.append(math.sqrt(n+m+1)/2.)
else:
row.append(0)
H0.append(row)
return H0
pprint.pprint(matrixH0(4))
yields
[[0, 0.7071067811865476, 0, 0],
[0.7071067811865476, 0, 1.0, 0],
[0, 1.0, 0, 1.224744871391589],
[0, 0, 1.224744871391589, 0]]
By the way, matrixH0 could also be written using nested list comprehensions:
def matrixH0(k):
return [[math.sqrt(n+m+1)/2. if abs(m-n)==1 else 0 for n in range(k)]
for m in range(k)]

You never create a multidimensional array in your code, you just append to a single list. Here is a solution:
def matrixH0(k):
H0=[]
print H0
for m in range (0,k):
H0.append([])
for n in range (0,k):
if abs(m-n)==1:
H0[m].append(math.sqrt(n+m+1)/2.)
else:
H0[m].append(0)
print H0

Init the rows at on the first loop and append the numbers to the array under the first loop index
def matrixH0(k):
H0=[]
print H0
for m in range (0,k):
H0.append([])
for n in range (0,k):
if abs(m-n)==1:
H0[m].append(math.sqrt(n+m+1)/2.)
else:
H0[m].append(0)
print H0

you find the correct Function
def matrixH0(k):
H1=[]
k=4
print H1
for m in range (0,k):
H0=[]
for n in range (0,k):
if abs(m-n)==1:
H0.append(math.sqrt(n+m+1)/2.)
else:
H0.append(0)
H1.append(H0)
return H1
[[0, 0.7071067811865476, 0, 0], [0.7071067811865476, 0, 1.0, 0], [0, 1.0, 0, 1.224744871391589], [0, 0, 1.224744871391589, 0]]

I think Raulucco's answer will work. But you if you work with number and matrix, numpy is certainly the module you want.
Your code will look like
import numpy
H0 = numpy.diag([math.sqrt(n + 1) for n in xrange(k - 1)], 1) + \
numpy.diag([math.sqrt(n) for n in xrange(k - 1)], -1)

Related

How to solve partial Knight's Tour with special constraints

Knight's tour problem described in the image here, with diagram.
A knight was initially located in a square labeled 1. It then proceeded to make a
series of moves, never re-visiting a square, and labeled the visited squares in
order. When the knight was finished, the labeled squares in each region of connected
squares had the same sum.
A short while later, many of the labels were erased. The remaining labels can be seen
above.
Complete the grid by re-entering the missing labels. The answer to this puzzle is
the sum of the squares of the largest label in each row of the completed grid, as in
the example.
[1]: E.g. the 14 and 33 are in different regions.
The picture explains it a lot more clearly, but in summary a Knight has gone around a 10 x 10 grid. The picture shows a 10 x 10 board that shows some positions in has been in, and at what point of its journey. You do not know which position the Knight started in, or how many movements it made.
The coloured groups on the board need to all sum to the same amount.
I’ve built a python solver, but it runs for ages - uses recursion. I’ve noted that the maximum sum of a group is 197, based on there being 100 squares and the smallest group is 2 adjacent squares.
My code at this link: https://pastebin.com/UMQn1HZa
import sys, numpy as np
fixedLocationsArray = [[ 12, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[ 0, 0, 0, 0, 0, 0, 5, 0, 23, 0],
[ 0, 0, 0, 0, 0, 0, 8, 0, 0, 0],
[ 0, 0, 0, 14, 0, 0, 0, 0, 0, 0],
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[ 0, 2, 0, 0, 0, 0, 0, 0, 0, 0],
[ 0, 0, 0, 0, 20, 0, 0, 0, 0, 0],
[ 0, 0, 0, 0, 33, 0, 0, 0, 0, 0],
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 28]]
groupsArray = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 1, 0, 0, 0, 0,10, 0],
[0, 0, 0, 1, 0, 0, 0, 0,10, 0],
[0, 0, 1, 1, 1, 1, 9,10,10,10],
[2, 0, 1, 0, 0,11, 9, 9, 9, 9],
[2, 0, 0, 0,11,11,11,15,15, 9],
[2, 4, 4,14,11,12,12,15,15, 8],
[2, 3, 4,14,14,13,13,13,15, 8],
[2, 3, 5,14,16,16,16, 7, 7, 8],
[3, 3, 5, 6, 6, 6, 6, 6, 7, 8]]
'''
Solver
- Noted that the maximum sum of a group is 197 since the group of only 2 can have the 100 filled and then 97 on return
'''
class KnightsTour:
def __init__(self, width, height, fixedLocations, groupsArray):
self.w = width
self.h = height
self.fixedLocationsArray = fixedLocations
self.groupsArray = groupsArray
self.npfixedLocationsArray = np.array(fixedLocations)
self.npgroupsArray = np.array(groupsArray)
self.board = [] # Contains the solution
self.generate_board()
def generate_board(self):
"""
Creates a nested list to represent the game board
"""
for i in range(self.h):
self.board.append([0]*self.w)
def print_board(self): # Prints out the final board solution
print(" ")
print("------")
for elem in self.board:
print(elem)
print("------")
print(" ")
def generate_legal_moves(self, cur_pos, n):
"""
Generates a list of legal moves for the knight to take next
"""
possible_pos = []
move_offsets = [(1, 2), (1, -2), (-1, 2), (-1, -2),
(2, 1), (2, -1), (-2, 1), (-2, -1)]
locationOfNumberInFixed = [(ix,iy) for ix, row in enumerate(self.fixedLocationsArray) for iy, i in enumerate(row) if i == n+1]
groupsizeIsNotExcessive = self.groupsNotExcessiveSize(self.board, self.groupsArray)
for move in move_offsets:
new_x = cur_pos[0] + move[0]
new_y = cur_pos[1] + move[1]
new_pos = (new_x, new_y)
if groupsizeIsNotExcessive:
if locationOfNumberInFixed:
print(f"This number {n+1} exists in the fixed grid at {locationOfNumberInFixed[0]}")
if locationOfNumberInFixed[0] == new_pos:
print(f"Next position is {new_pos} and matches location in fixed")
possible_pos.append((new_x, new_y))
else:
continue
elif not locationOfNumberInFixed: # if the current index of move is not in table, then evaluate if it is a legal move
if (new_x >= self.h): # if it is out of height of the board, continue, don't app onto the list of possible moves
continue
elif (new_x < 0):
continue
elif (new_y >= self.w):
continue
elif (new_y < 0):
continue
else:
possible_pos.append((new_x, new_y))
else:
continue
print(f"The legal moves for index {n} are {possible_pos}")
print(f"The current board looks like:")
self.print_board()
return possible_pos
def sort_lonely_neighbors(self, to_visit, n):
"""
It is more efficient to visit the lonely neighbors first,
since these are at the edges of the chessboard and cannot
be reached easily if done later in the traversal
"""
neighbor_list = self.generate_legal_moves(to_visit, n)
empty_neighbours = []
for neighbor in neighbor_list:
np_value = self.board[neighbor[0]][neighbor[1]]
if np_value == 0:
empty_neighbours.append(neighbor)
scores = []
for empty in empty_neighbours:
score = [empty, 0]
moves = self.generate_legal_moves(empty, n)
for m in moves:
if self.board[m[0]][m[1]] == 0:
score[1] += 1
scores.append(score)
scores_sort = sorted(scores, key = lambda s: s[1])
sorted_neighbours = [s[0] for s in scores_sort]
return sorted_neighbours
def groupby_perID_and_sum(self, board, groups):
# Convert into numpy arrays
npboard = np.array(board)
npgroups = np.array(groups)
# Get argsort indices, to be used to sort a and b in the next steps
board_flattened = npboard.ravel()
groups_flattened = npgroups.ravel()
sidx = groups_flattened.argsort(kind='mergesort')
board_sorted = board_flattened[sidx]
groups_sorted = groups_flattened[sidx]
# Get the group limit indices (start, stop of groups)
cut_idx = np.flatnonzero(np.r_[True,groups_sorted[1:] != groups_sorted[:-1],True])
# Create cut indices for all unique IDs in b
n = groups_sorted[-1]+2
cut_idxe = np.full(n, cut_idx[-1], dtype=int)
insert_idx = groups_sorted[cut_idx[:-1]]
cut_idxe[insert_idx] = cut_idx[:-1]
cut_idxe = np.minimum.accumulate(cut_idxe[::-1])[::-1]
# Split input array with those start, stop ones
arrayGroups = [board_sorted[i:j] for i,j in zip(cut_idxe[:-1],cut_idxe[1:])]
arraySum = [np.sum(a) for a in arrayGroups]
sumsInListSame = arraySum.count(arraySum[0]) == len(arraySum)
return sumsInListSame
def groupsNotExcessiveSize(self, board, groups):
# Convert into numpy arrays
npboard = np.array(board)
npgroups = np.array(groups)
# Get argsort indices, to be used to sort a and b in the next steps
board_flattened = npboard.ravel()
groups_flattened = npgroups.ravel()
sidx = groups_flattened.argsort(kind='mergesort')
board_sorted = board_flattened[sidx]
groups_sorted = groups_flattened[sidx]
# Get the group limit indices (start, stop of groups)
cut_idx = np.flatnonzero(np.r_[True,groups_sorted[1:] != groups_sorted[:-1],True])
# Create cut indices for all unique IDs in b
n = groups_sorted[-1]+2
cut_idxe = np.full(n, cut_idx[-1], dtype=int)
insert_idx = groups_sorted[cut_idx[:-1]]
cut_idxe[insert_idx] = cut_idx[:-1]
cut_idxe = np.minimum.accumulate(cut_idxe[::-1])[::-1]
# Split input array with those start, stop ones
arrayGroups = [board_sorted[i:j] for i,j in zip(cut_idxe[:-1],cut_idxe[1:])]
arraySum = [np.sum(a) for a in arrayGroups]
print(arraySum)
# Check if either groups aren't too large
groupSizeNotExcessive = all(sum <= 197 for sum in arraySum)
return groupSizeNotExcessive
def tour(self, n, path, to_visit):
"""
Recursive definition of knights tour. Inputs are as follows:
n = current depth of search tree
path = current path taken
to_visit = node to visit, i.e. the coordinate
"""
self.board[to_visit[0]][to_visit[1]] = n # This writes the number on the grid
path.append(to_visit) #append the newest vertex to the current point
print(f"Added {n}")
print(f"For {n+1} visiting: ", to_visit)
if self.groupby_perID_and_sum(self.board, self.npgroupsArray): #if all areas sum
self.print_board()
print(path)
print("Done! All areas sum equal")
sys.exit(1)
else:
sorted_neighbours = self.sort_lonely_neighbors(to_visit, n)
for neighbor in sorted_neighbours:
self.tour(n+1, path, neighbor)
#If we exit this loop, all neighbours failed so we reset
self.board[to_visit[0]][to_visit[1]] = 0
try:
path.pop()
print("Going back to: ", path[-1])
except IndexError:
print("No path found")
sys.exit(1)
if __name__ == '__main__':
#Define the size of grid. We are currently solving for an 8x8 grid
kt0 = KnightsTour(10, 10, fixedLocationsArray, groupsArray)
kt0.tour(1, [], (3, 0))
# kt0.tour(1, [], (7, 0))
# kt0.tour(1, [], (7,2))
# kt0.tour(1, [], (6,3))
# kt0.tour(1, [], (4,3))
# kt0.tour(1, [], (3,2))
# startingPositions = [(3, 0), (7, 0), (7,2), (6,3), (4,3), (3,2)]
kt0.print_board()
Here are some observations that you could include to be able to stop more early in your backtracking.
First of all remember that for n steps the total sum in all areas can be computed with the formula n(n+1)/2. This number has to be divisible evenly into the groups i.e. it has to be divisible by 17 which is the amount of groups.
Furthermore if we look at the 12 we can conclude that the 11 and 13 must have been in the same area so we get a lower bound on the number for each area as 2+5+8+11+12+13=51.
And lastly we have groups of size two so the largest two step numbers must make up the total sum for one group.
Using those conditions we can calculate the remaining possible amount of steps with
# the total sum is divisible by 17:
# n*(n+1)/2 % 17 == 0
# the sum for each group is at least the predictable sum for
# the biggest given group 2+5+8+11+12+13=51:
# n*(n+1)/(2*17) >= 51
# since there are groups of two elements the sum of the biggest
# two numbers must be as least as big as the sum for each group
# n+n-1 >= n*(n+1)/(2*17)
[n for n in range(101) if n*(n+1)/2 % 17 == 0 and n*(n+1)/(2*17) >= 51 and n+n-1 >= n*(n+1)/(2*17)]
giving us
[50,51].
So the knight must have taken either 50 or 51 steps and the sum for each area must be either 75 or 78.

Python iterate through an 2dDarray

I have a 2D array like
grid = [[1, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0]]
Now based on the point where there is 1, I wanna create a new array and save the distance to all the points from it. Example
dp = [[1, 2, 3, 4, 5],
[2, 3, 4, 5, 6],
[3, 4, 5, 6, 7]]
I get RuntimeError: maximum recursion depth exceeded not sure what I'm missing.
def minTotalDistance(grid):
dp = [[0]*len(grid[0]) for _ in range(len(grid))]
for i in range(len(grid)):
for j in range(len(grid[0])):
if grid[i][j] == 1:
dfs(i, j, dp, 1)
print dp
def dfs(i, j, dp, val):
if i < 0 or i >= len(dp) or j < 0 or j >= len(dp[0]):
return 0
dp[i][j] = val
dfs(i - 1, j, dp, val+1)
dfs(i + 1, j, dp, val+1)
dfs(i, j - 1, dp, val+1)
dfs(i, j + 1, dp, val+1)
grid = [[1, 0, 0, 0, 1], [0, 0, 0, 0, 0], [0, 0, 1, 0, 0]]
minTotalDistance(grid)
I think the problem here is with your recursive calls. For example when you call the dfs(0, 0, dp, val) will call dfs(0-1, 0, dp, val) which returns but then it will call dfs(1, 0, dp, val) which then calls dfs(1 - 1, 0, dp, val). Here dp and val are irrelevant in terms of the recursion as they don't terminate the function in any way. Note that the last call is equivalent to the first call in terms of i and j which just repeat the cycle until the call stack exceeds the memory boundary and you get the error.
You need some condition to stop the recursion. For instance, only process cells if they are unprocessed or if the current path constitutes an improvement.
def dfs(i, j, dp, val):
if not (0 <= i < len(dp) and 0 <= j < len(dp[0])):
return 0
# only process if improvement or unprocessed
if dp[i][j] == 0 or val < dp[i][j]:
dp[i][j] = val
dfs(i - 1, j, dp, val+1)
dfs(i + 1, j, dp, val+1)
dfs(i, j - 1, dp, val+1)
dfs(i, j + 1, dp, val+1)
When you are using recursion, you must make sure to never enter a recursion loop where a recursive function call itself with some parameters and inside that call, call again itself with the original parameter.
Here when computing df(i, j, ...) you call dfs(i-1, j, ...) and in that call you have dfs(i+1, j, ...) which gives the original point => infinite loop!
You should either make sure to always increase indices, or to have a distinctive value for uninitialized points and break the recursion as soon as a point has already received a value.

'Lossy' cumsum in numpy

I have an array a of length N and need to implement the following operation:
With p in [0..1]. This equation is a lossy sum, where the first indexes in the sum are weighted by a greater loss (p^{n-i}) than the last ones. The last index (i=n) is always weigthed by 1. if p = 1, then the operation is a simple cumsum.
b = np.cumsum(a)
If if p != 1, I can implement this operation in a cpu-inefficient way:
b = np.empty(np.shape(a))
# I'm using the (-1,-1,-1) idiom for reversed ranges
p_vec = np.power(p, np.arange(N-1, 0-1, -1))
# p_vec[0] = p^{N-1}, p_vec[-1] = 1
for n in range(N):
b[n] = np.sum(a[:n+1]*p_vec[-(n+1):])
Or in a memory-inefficient but vectorized way (IMO is cpu inefficient too, since a lot of work is wasted):
a_idx = np.reshape(np.arange(N+1), (1, N+1)) - np.reshape(np.arange(N-1, 0-1, -1), (N, 1))
a_idx = np.maximum(0, a_idx)
# For N=4, a_idx looks like this:
# [[0, 0, 0, 0, 1],
# [0, 0, 0, 1, 2],
# [0, 0, 1, 2, 3],
# [0, 1, 2, 3, 4]]
a_ext = np.concatenate(([0], a,), axis=0) # len(a_ext) = N + 1
p_vec = np.power(p, np.arange(N, 0-1, -1)) # len(p_vec) = N + 1
b = np.dot(a_ext[a_idx], p_vec)
Is there a better way to achieve this 'lossy' cumsum?
What you want is a IIR filter, you can use scipy.signal.lfilter(), here is the code:
Your code:
import numpy as np
N = 10
p = 0.8
np.random.seed(0)
x = np.random.randn(N)
y = np.empty_like(x)
p_vec = np.power(p, np.arange(N-1, 0-1, -1))
for n in range(N):
y[n] = np.sum(x[:n+1]*p_vec[-(n+1):])
y
the output:
array([1.76405235, 1.81139909, 2.42785725, 4.183179 , 5.21410119,
3.19400307, 3.50529088, 2.65287549, 2.01908154, 2.02586374])
By using lfilter():
from scipy import signal
y = signal.lfilter([1], [1, -p], x)
print(y)
the output:
array([1.76405235, 1.81139909, 2.42785725, 4.183179 , 5.21410119,
3.19400307, 3.50529088, 2.65287549, 2.01908154, 2.02586374])

Assign values to a matrix in Python

I have wrote this piece of code and need to generate a matrix and save it. But, when assigning the matrix values, it says "KeyError: 0"!! Anybody has an idea what is the reason? thanks
import numpy as np
l=5; x=0; z=5; y=np.arange(0,5,0.5)
positions = { (i,j):0 for i in range(l) for j in range(2)}
for i in range(l):
positions[i][0]=x
positions[i][1]=y[i]
positions[i][2]=z
I am not sure what is the shape of matrix you need but assuming something like:
[[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]]
then code:
import numpy as np
l=5; x=0; z=5; y=np.arange(0,5,0.5)
positions = [[0 for j in range(3)] for i in range(l)]
print(positions)
for i in range(l):
positions[i][0]=x
positions[i][1]=y[i]
positions[i][2]=z
It's how you structured your keys, it should be a tuple instead of something array like
import numpy as np
l=5; x=0; z=5; y=np.arange(0,5,0.5)
positions = { (i,j):0 for i in range(l) for j in range(2)}
for i in range(l):
positions[(i, 0)] = x
positions[(i, 1)] = y[i]
positions[(i, 2)] = z

How to simplify very small number to 0 in SymPy?

I am doing some matrix computation with sympy 0.7.6 in python 2.7.10. For example,
M =
[cos(q1), -6.12323399573677e-17*sin(q1), -1.0*sin(q1), 150*sin(q1)]
[sin(q1), 6.12323399573677e-17*cos(q1), 1.0*cos(q1), 150*sin(q1)]
[ 0, -1.0, 6.12323399573677e-17, 445]
[ 0, 0, 0, 1]
Then I apply simplify to M and it results in:
M =
[cos(q1), 0, -1.0*sin(q1), 150*sin(q1)]
[sin(q1), 0, 1.0*cos(q1), 150*sin(q1)]
[ 0, -1.0, 6.12323399573677e-17, 445]
[ 0, 0, 0, 1]
It's clear that -6.12323399573677e-17*sin(q1) is simplified to 0 but 6.12323399573677e-17 is not. Is it possible to simplify the pure number item with simplify?
Sympy’s nsimplify function with the rational=True argument converts floats within an expression to rational numbers (within a given tolerance). Something like 6.12323399573677e-17 will be converted to 0 if below the threshold. So, in your case:
from sympy import Symbol, Matrix, sin, cos, nsimplify
q1 = Symbol("q1")
M = Matrix([
[cos(q1), -6.12323e-17*sin(q1), 1.0*sin(q1), 150*sin(q1)],
[sin(q1), 6.12323e-17*cos(q1), 1.0*cos(q1), 150*sin(q1)],
[ 0, -1.0, 6.123233e-17, 445],
[ 0, 0, 0, 1],
])
nsimplify(M,tolerance=1e-10,rational=True)
# Matrix([
# [cos(q1), 0, -sin(q1), 150*sin(q1)],
# [sin(q1), 0, cos(q1), 150*sin(q1)],
# [ 0, -1, 0, 445],
# [ 0, 0, 0, 1]])
Note how this also converted -1.0 to -1.
If you are using a Matrix (sympy.matrices.dense.MutableDenseMatrix), including one with sybolic elements, the conversion can be done with the following function:
def round2zero(m, e):
for i in range(m.shape[0]):
for j in range(m.shape[1]):
if (isinstance(m[i,j], Float) and m[i,j] < e):
m[i,j] = 0
For example:
from sympy import *
e = .0000001 # change according to your definition of small
x, y, z = symbols('x y z')
mlist = [[0.0, 1.0*cos(z)], [x*y, 1.05000000000000], [0, 6.12323399573677e-17]]
m = Matrix(mlist)
m
Out[4]:
Matrix([
[0.0, 1.0*cos(z)],
[x*y, 1.05],
[ 0, 6.12323399573677e-17]])
round2zero(m,e)
m
Matrix([
[ 0, 1.0*cos(z)],
[x*y, 1.05],
[ 0, 0]])
Some fuzzing can help detect more values that can be set to zero:
import sympy
import random
def fuzz_simplify(matrix, min=-1.0, max=1.0, iterations=1000, tolerance=0.005):
m = sympy.Matrix(matrix)
free_sym = range(len(J.free_symbols))
f = sympy.lambdify(m.free_symbols,m)
sum = f(*[0 for i in free_sym])
for i in range(0, iterations):
rand_params = [random.uniform(min,max) for i in free_sym]
sum += f(*rand_params)
for i in range(0, J.shape[0]):
for j in range(0, J.shape[1]):
if sum[i,j] < tolerance:
m[i,j] *= 0
return m

Categories