I have this method which returns the max sum of the path from top left to bottom right (can move only to the right or bottom).
def max_path(grid):
N = len(grid)
M = len(grid[0])
sum = [[0 for i in range(M + 1)] for i in range(N + 1)]
for i in range(1, N + 1):
for j in range(1, M + 1):
sum[i][j] = (max(sum[i - 1][j], sum[i][j - 1]) + grid[i - 1][j - 1])
return sum[N][M]
matrix = [[1, 2, 3], [3, 4, 5]]
print(max_path(matrix))
output : 1 + 3 + 4 + 5 = 13
But what I want to get is also the coordinates of the points of the path:
[(0,0) (1,0) (1,1) (1,2)]
You can try the below code to get your job done.
from itertools import permutations, product
def get_max_sum(table):
height, width = len(table), len(table[0])
sum_, *pos = max((sum(table[x][y] for x, y in zip(*pairs)), *zip(*pairs))
for pairs in product(
permutations(range(height)),
([*range(i, width), *range(i)] for i in range(width))))
return (sum_, *sorted(pos))
sum_, *pos = get_max_sum(
[[1, 2, 3],
[2, 3, 5],
[4, 9, 16]]
)
Output:
20 #maximum sum
(0, 1) (1, 0) (2, 2) #co -ordinates
The variable sum after the nested-for loops (as written in your code) is
[0, 0, 0, 0],
[0, 1, 3, 6],
[0, 4, 8, 13]
You can work out the coordinates of the max sum by having a initial "pointer" at the bottom right corner (i=1, j =2, ignoring the zeros), and comparing the values that is on the top (i=0, i=2) and on the left (i=1, j=1). Since 8 is larger than 6, we move the "pointer" to the left, and now i=1, j=1.
4 is larger than 3, so we move the pointer to 4 (i=1, j=0)
1 is larger than 0, so we move the pointer to 1 (i=0, j=0)
A basic (untested) implementation of the algorithm is as follows:
def max_path(grid):
N = len(grid)
M = len(grid[0])
sum = [[0 for i in range(M + 1)] for i in range(N + 1)]
for i in range(1, N + 1):
for j in range(1, M + 1):
sum[i][j] = (max(sum[i - 1][j], sum[i][j - 1]) + grid[i - 1][j - 1])
j = M
i = N
path = []
while i > 0 and j > 0:
path.append((i-1,j-1))
if sum[i-1][j] <= sum[i][j-1]:
j -= 1
else:
i -= 1
path.reverse()
return sum[N][M],path
matrix = [[1, 2, 3], [3, 4, 5]]
print(max_path(matrix))
Related
Let's say i have this matrix: (doesn't have to be squared)
a b c
d e f
g h i
I want to return a list, or a generator, of all it's pairwise-neighbors.
Meaning:
[[a,b], [b,c], [d,e], [e,f], [g,h], [h,i], [a,d], [b,e], [c,f], [d,g], [e,h], [f,i]]
AND(!) to add an option to return only the sum of: a*b + b*c + d*e + e*f + g*h + ... + f*i
If this is not explained clearly enough from the example, two elements are pairwise-neighbors if they both stand next to each other, from left to right or from the bottom up (NOT diagonally!).
Here's what I did so far:
def neighbors(X, returnSet=False):
'''
:param X: The matrix
:param returnSet: False[DEFAULT] = Return sum of Xi*Xj (when Xi and Xj are pairwise-neighbors)
True = Return the set of all neighbors.
:return: Depends on returnSet
'''
sum, neighbors = 0, []
for i in range(0, X.shape[0]):
for j in range(0, X.shape[1]):
if j + 1 < X.shape[1]:
neighbors.append([X[i][j], X[i][j + 1]]) if returnSet else None
sum += X[i][j] * X[i][j + 1]
if i + 1 < X.shape[0]:
neighbors.append([X[i][j], X[i + 1][j]]) if returnSet else None
sum += X[i][j] * X[i + 1][j]
return neighbors if returnSet else sum
This code works, but I don't really like how it looks. Can you come up with some "cooler" algorithm than that? Or maybe more efficient? I like when a python code are short and simple.
Basically same as your last question, just doing it over two axes and with a double dot product (which isn't as pretty).
a = np.arange(9).reshape(3,3)
np.einsum('ij, ij->', a[1:], a[:-1]) + np.einsum('ij, ij->', a[:, 1:], a[:, :-1])
Out[]: 232
neighbors(a)
Out[]: 232
If you just want the pairs:
h = np.stack([a[:, 1:], a[:, :-1]]).transpose(1,2,0).reshape(-1, 2)
v = np.stack([a[1:], a[:-1]]).transpose(1,2,0).reshape(-1, 2)
np.vstack([h, v])
Out[]:
array([[1, 0],
[2, 1],
[4, 3],
[5, 4],
[7, 6],
[8, 7],
[3, 0],
[4, 1],
[5, 2],
[6, 3],
[7, 4],
[8, 5]])
I need to return the vector solution x of Ux = b for an upper triangular matrix U and vector b using back substitution, but I'm unable to actually access an element of the matrix U.
def BackSub(U, b):
n = len(U)
x = [0 for i in range(n)]
for i in range(n - 1, -1, -1):
s = 0
for j in range(n - 1, i, -1):
s += (U[i][j])*b[j]
b[i] = (b[i] - s)/(U[i][i])
return b
b = [5, 6, 3, 2]
U = [[ 1, 2, 1, 0],
[ 0, 3, -5, 9],
[ 0, 0, 0.5, 1],
[ 0, 0, 0, 7]]
N = GaussElim(U, b)
x = BackSub(N, b)
It returns
TypeError: 'float' object is not subscriptable for U[i][i]
The GaussElim function is this
import numpy as np
def GaussElim(A, b):
n = len(b) #n is matrix size
#Elimination phase
for k in range(0 , n - 1): #k is matrix row
for i in range(k + 1, n): #i is matrix col
if A[i][k] != 0:
factor = A[i][k]/ A[k][k]
A[i][k + 1 : n] = A[i][k + 1 : n] - np.multiply(factor, A[k][k + 1 : n])
b[i] = b[i] - np.multiply(factor, b[k])
#Back substitution
for k in range(n - 1, -1, -1):
b[k] = (b[k] - dot(A[k][k + 1 : n], b[k + 1 : n]))/A[k][k]
return b
Assume you have a grid, where each node contains a weight that represents the cost of taking that square.
You start at (0,0) at the top left of the 2D array and you want to get to (X-1, Y-1) where X is the number of columns and Y rows at the bottom right. You can go right 1 square, or you can go down 1 square at a time. You are also given an int array of "jumps", where each value $d_i$ represents the number of squares you can skip over going right or down on the ith jump. The jumps array specifies the order you have to take for jumps, meaning, for instance, you can't take jump[2] of a skip if you haven't used a single one. You can only take len(jump) number of jumps.
We are trying to solve this with dynamic programming. This is what I have thus far:
def helper(grid, jumps):
dCount = 0
dp = [[[0 for k in range(len(jumps)+1)] for j in range(len(grid[0]))] for i in range(len(grid))]
for row in range(len(grid)):
for col in range(len(grid[0])):
if row == 0 and col == 0:
dp[row][col][dCount] += grid[row][col]
jumpRight = float('infinity')
jumpUp = float('infinity')
goUp = float('infinity')
goRight = float('infinity')
if(row > 0):
goUp = dp[row-1][col][dCount]
if(col > 0):
goRight = dp[row][col-1][dCount]
if (dCount < len(jumps)):
jumpRight = dp[row-jumps[dCount]][col][dCount]
jumpUp = dp[row][col-jumps[dCount]][dCount]
res = grid[row][col] + min(goRight, goUp, jumpRight, jumpUp)
if(res == jumpRight or res==jumpUp):
dCount+=1
dp[row][col][dCount] = res
return dp[len(grid)-1][len(grid[0])-1]
grid = [[1, 0, 3, 7, 2, 5], [8, 3, 7, 6, 9, 8], [9, 7, 8, 2, 1, 1], [3, 2, 9, 1, 7, 8]]
jumps = [1, 1]
print(helper(grid,jumps)) #should be 16
However, the code doesn't seem to be working.
The above is just printing out [0 0 15], when I think it should be [0 0 16]
The following is an implementation:
def shortest(grid, jumps, x=0, y=0, jumped=0):
# grid: whole grid
# jumps: jumps to be exhuasted
# x, y: current position
# jumped: number of jumps that have been used
# output: a tuple (cost, path)
# cost: minimum cost from this position to the final position
# path: a list of tuples, each element the position along the minimum-cost path
rows = len(grid) - x; cols = len(grid[0]) - y # remaining num of rows and cols
if (rows, cols) == (1, 1): # if arrived at the southeast corner
return (float('inf'), [(x, y)]) if jumps[jumped:] else (grid[x][y], [(x, y)]) # return inf if jumps are not exhausted
candidates = [] # store results from deeper calls
if rows > 1: # if possible to move down
candidates.append(shortest(grid, jumps, x+1, y, jumped)) # down by one
if jumped < len(jumps) and rows > jumps[jumped] + 1: # if possible to jump
candidates.append(shortest(grid, jumps, x+jumps[jumped]+1, y, jumped+1)) # jump down
if cols > 1: # if possible to move right
candidates.append(shortest(grid, jumps, x, y+1, jumped)) # right by one
if jumped < len(jumps) and cols > jumps[jumped] + 1: # if possible to jump
candidates.append(shortest(grid, jumps, x, y+jumps[jumped]+1, jumped+1)) # jump right
temp = min(candidates, key=lambda x: x[0]) # recall: temp[0]: min_cost, temp[1]: min_path
return (temp[0] + grid[x][y], [(x, y), *temp[1]])
grid = [[1, 0, 3, 7, 2, 5], [8, 3, 7, 6, 9, 8], [9, 7, 8, 2, 1, 1], [3, 2, 9, 1, 7, 8]]
jumps = [1, 1]
print(shortest(grid, jumps)) # (16, [(0, 0), (0, 1), (0, 2), (0, 4), (2, 4), (2, 5), (3, 5)])
The state variables are x, y and jumps; x and y remember where the current position is in the given grid. jumps remembers how many jumps have been used so far.
The end state of the recursion occurs when the position is at the final destination, i.e., [-1, -1]. If the jumps have not been exhausted, then it is a failure; so return the infinity as the cost. Otherwise, return the value at the point as the cost.
Actually, the return is a tuple; the first element is the cost, and the second element is the current position. The second element is used for obtaining the cost-minimization path in the end.
In other states, the recursion is defined in a natural way; the function recurses into (up to) four possible movements: up by one, right by one, jump up, jump right. It compares the resulting costs, and selects the minimum-cost direction.
Note: this uses generalized unpack, introduced in python 3.5. But this is not essential.
Here's an example of a bottom up approach that seems to return correct results for this example and the one in a similar question. I'm not sure the code is foolproof, though.
Python:
def f(grid, jumps):
m, n = len(grid), len(grid[0])
dp = [None] * m
for i in range(m):
dp[i] = [[float('inf')] * (len(jumps) + 1) for j in range(n)]
dp[0][0][0] = grid[0][0]
for y in range(m):
for x in range(n):
for j in range(len(jumps) + 1):
if (y, x, j) == (0, 0, 0):
continue
dp[y][x][j] = grid[y][x] + min(
dp[y - 1][x][j] if y > 0 else float('inf'),
dp[y][x - 1][j] if x > 0 else float('inf'),
dp[y - jumps[j-1] - 1][x][j-1] if (j > 0 and y - jumps[j-1] - 1 >= 0) else float('inf'),
dp[y][x - jumps[j-1] - 1][j-1] if (j > 0 and x - jumps[j-1] - 1 >= 0) else float('inf')
)
return min(dp[m-1][n-1])
grid = [
[1, 0, 3, 7, 2, 5],
[8, 3, 7, 6, 9, 8],
[9, 7, 8, 2, 1, 1],
[3, 2, 9, 1, 7, 8]]
jumps = [1, 1]
print(f(grid, jumps)) # 16
grid = [
[3, 9, 1],
[9, 9, 1],
[9, 9, 1]
]
jumps = [1, 1]
print(f(grid, jumps)) # 5
I am finding the longest path with my data and my code is collecting the longest path in each node.
def dfs(node, adj, dp, vis):
vis[node] = True
for i in range(0, len(adj[node])):
if not vis[adj[node][i]]:
dfs(adj[node][i], adj, dp, vis)
dp[node] = max(dp[node], [node] + dp[adj[node][i]], key=lambda x: len(x))
def findLongestPathFromEachNode(adj, n):
dp = [[x] for x in range(n)]
vis = [False] * (n + 1)
for i in range(1, n + 1):
if not vis[i]:
dfs(i, adj, dp, vis)
return dp[1:]
n = 6
adj = [[] for i in range(n + 1)]
addEdge(adj, 1, 2)
addEdge(adj, 1, 3)
addEdge(adj, 3, 2)
addEdge(adj, 2, 4)
addEdge(adj, 2, 5)
addEdge(adj, 3, 4)
addEdge(adj, 3, 5)
and I got this results
In[29]:
paths = findLongestPathFromEachNode(adj, n)
paths
Out[29]:
[[1, 3, 2, 4], [2, 4], [3, 2, 4], [4], [5]]
while I expect to see the results as
[[1, 3, 2, 4], [1, 3, 2, 5], [2, 4], [2, 5], [3, 2, 4], [3, 2, 5], [4], [5]]
due to longest paths in each node are reached to node 5 too.
any suggestion?
The core idea to your question is to store not the single path in dp but the array of paths: dp = [[[x]] for x in range(n)].
Then in your dfs we will compare our new possibly longer paths with any instance from dp[node]. For example with zero index because we can guarantee that it will always exist: if len(dp[node][0]) < 1 + len(dp[adj[node][i]][0]): and elif len(dp[node][0]) == 1 + len(dp[adj[node][i]][0]):.
Also, we will need to append a node to every new path in the dp:
if len(dp[node][0]) < 1 + len(dp[adj[node][i]][0]):
dp[node] = []
for path in dp[adj[node][i]]:
dp[node].append([node] + path)
elif len(dp[node][0]) == 1 + len(dp[adj[node][i]][0]):
for path in dp[adj[node][i]]:
dp[node].append([node] + path)
All in all, it will be:
def dfs(node, adj, dp, vis):
vis[node] = True
for i in range(0, len(adj[node])):
if not vis[adj[node][i]]:
dfs(adj[node][i], adj, dp, vis)
if len(dp[node][0]) < 1 + len(dp[adj[node][i]][0]):
dp[node] = []
for path in dp[adj[node][i]]:
dp[node].append([node] + path)
elif len(dp[node][0]) == 1 + len(dp[adj[node][i]][0]):
for path in dp[adj[node][i]]:
dp[node].append([node] + path)
def findLongestPathFromEachNode(adj, n):
dp = [[[x]] for x in range(n)]
vis = [False] * (n + 1)
for i in range(1, n + 1):
if not vis[i]:
dfs(i, adj, dp, vis)
return dp[1:]
n = 6
adj = [[] for i in range(n + 1)]
addEdge(adj, 1, 2)
addEdge(adj, 1, 3)
addEdge(adj, 3, 2)
addEdge(adj, 2, 4)
addEdge(adj, 2, 5)
addEdge(adj, 3, 4)
addEdge(adj, 3, 5)
I'm working on A star algorithm and as my code below shown the gird is written manually and I'm thinking to make a grid with 100* 100 size. So, it will be so awful to write them manually. I need to put my starting point at (0,0) location and my goal point at (99,99) location.
I'm trying to make the grid with this line below
grid1 = [[0 for i in range(100)]for j in range(100)]
But how could I assign obstacles to this grid randomly or not randomly without touching the location of starting point and goal point?
This is below my code:
from __future__ import print_function
import random
grid = [[0, 1, 0, 0, 0, 0],
[0, 1, 0, 0, 0, 0],#0 are free path whereas 1's are obstacles
[0, 1, 0, 0, 0, 0],
[0, 1, 0, 0, 1, 0],
[0, 0, 0, 0, 1, 0]]
'''
heuristic = [[9, 8, 7, 6, 5, 4],
[8, 7, 6, 5, 4, 3],
[7, 6, 5, 4, 3, 2],
[6, 5, 4, 3, 2, 1],
[5, 4, 3, 2, 1, 0]]'''
init = [0, 0]
goal = [len(grid)-1, len(grid[0])-1] #all coordinates are given in format [y,x]
cost = 1
drone_h = 60
#the cost map which pushes the path closer to the goal
heuristic = [[0 for row in range(len(grid[0]))] for col in range(len(grid))]
for i in range(len(grid)):
for j in range(len(grid[0])):
heuristic[i][j] = abs(i - goal[0]) + abs(j - goal[1])
#if grid[i][j] == 1:
#heuristic[i][j] = 99 #added extra penalty in the heuristic map
print(heuristic)
elevation = [[0 for row in range(len(grid[0]))] for col in range(len(grid))]
for i in range(len(grid)):
for j in range(len(grid[0])):
if grid[i][j] == 1:
elevation[i][j] = random.randint(1,100)
else:
elevation[i][j] = 0
#the actions we can take
delta = [[-1, 0 ], # go up
[ 0, -1], # go left
[ 1, 0 ], # go down
[ 0, 1 ]] # go right
#function to search the path
def search(grid,init,goal,cost,heuristic):
closed = [[0 for col in range(len(grid[0]))] for row in range(len(grid))]# the referrence grid
closed[init[0]][init[1]] = 1
action = [[0 for col in range(len(grid[0]))] for row in range(len(grid))]#the action grid
x = init[0]
y = init[1]
g = 0
f = g + heuristic[init[0]][init[0]] + elevation[init[0]][init[0]]
cell = [[f, g, x, y]]
found = False # flag that is set when search is complete
resign = False # flag set if we can't find expand
while not found and not resign:
if len(cell) == 0:
resign = True
return "FAIL"
else:
cell.sort()#to choose the least costliest action so as to move closer to the goal
cell.reverse()
next = cell.pop()
x = next[2]
y = next[3]
g = next[1]
f = next[0]
if x == goal[0] and y == goal[1]:
found = True
else:
for i in range(len(delta)):#to try out different valid actions
x2 = x + delta[i][0]
y2 = y + delta[i][1]
if x2 >= 0 and x2 < len(grid) and y2 >=0 and y2 < len(grid[0]):
if closed[x2][y2] == 0 and grid[x2][y2] == 0 and elevation[x2][y2] < drone_h :
g2 = g + cost
f2 = g2 + heuristic[x2][y2] + elevation[x2][y2]
cell.append([f2, g2, x2, y2])
closed[x2][y2] = 1
action[x2][y2] = i
invpath = []
x = goal[0]
y = goal[1]
invpath.append([x, y])#we get the reverse path from here
while x != init[0] or y != init[1]:
x2 = x - delta[action[x][y]][0]
y2 = y - delta[action[x][y]][1]
x = x2
y = y2
invpath.append([x, y])
path = []
for i in range(len(invpath)):
path.append(invpath[len(invpath) - 1 - i])
print("ACTION MAP")
for i in range(len(action)):
print(action[i])
return path
a = search(grid,init,goal,cost,heuristic)
for i in range(len(a)):
print(a[i])
You could assign the grid randomly and afterwards make sure both starting and end point don't contain obstacles. For neighboring fields you could just do the same as for those two.
import random
grid1 = [[random.randint(0,1) for i in range(100)]for j in range(100)]
# clear starting and end point of potential obstacles
grid1[0][0] = 0
grid1[99][99] = 0