Suppose I have an array, namely Map. Map[i][j] means the distance between area i and area j. Under this definition, we get:
a) Map[i][i] always equals 0.
b) Map[i][k] <= Map[i][j] + Map[j][k] for all i,j,k
I want to build a function func(Map,k) returning a metric D, while D[i][j] is the shortest distance of a route from area i to area j, and this route should pass through at least k different area.
This is my python code to do so:
def func(Map,k):
n=len(Map)
D_temp = [list(x) for x in Map]
D = [list(x) for x in Map]
for m in range(k - 1):
for i in range(n):
for j in range(n):
tmp = [D[i][x] + Map[x][j] for x in range(n) if x != i and x != j]
D_temp[i][j] = min(tmp)
D = [list(x) for x in D_temp]
return D
func([[0, 2, 3], [2, 0, 1], [3, 1, 0]],2)
return a distance metric D which equals [[4, 4, 3], [4, 2, 5], [3, 5, 2]]
D[0][0] equals 4, because the shortest route from area0 to area0 which pass through at least 2 area is {area0-->area1-->area0}, and the distance of the route is Map[0][1]+Map[1][0]=2+2=4
Wanted to know what would be the best way to do that?
You can use the A* algorithm for this, using Map[i][j] as the heuristic for the minimum remaining distance to the target node (assuming that, as you said, Map[i][j] <= Map[i][x] + Map[x][j] for all i,j,x). The only difference to a regular A* would be that you only accept paths if they have a minimum length of k.
import heapq
def min_path(Map, k, i, j):
heap = [(0, 0, i, [])]
while heap:
_, cost, cur, path = heapq.heappop(heap)
if cur == j and len(path) >= k:
return cost
for other in range(len(Map)):
if other != cur:
c = cost + Map[cur][other]
heapq.heappush(heap, (c + Map[other][j], c, other, path + [other]))
Change your func to return a list comprehension using this min_path accordingly.
def func(Map, k):
n = len(Map)
return [[min_path(Map, k, i, j) for i in range(n)] for j in range(n)]
res = func([[0, 2, 3], [2, 0, 1], [3, 1, 0]], 2)
This gives me the result [[4, 4, 3], [4, 2, 3], [3, 3, 2]] for len(path) >= k, or [[4, 4, 3], [4, 2, 5], [3, 5, 2]] for len(path) == k.
Related
Given a 1d vecotr x of size n, how can we construct an n-by-n matrix X consisting of all the rolled vectors of x in PyTorch?
For example
x = torch.tensor([1,2,3,4])
The expected output is
tensor([[1, 2, 3, 4],
[2, 3, 4, 1],
[3, 4, 1, 2],
[4, 1, 2, 3]])
Is there any better way than this?
N = x.shape[0]
A = torch.zeros(N, N)
for i in range(N):
A[i] = torch.roll(x, -i)
Here are two related SO questions 1 2 that helped me formulate my preliminary solution.
The reason for wanting to do this is to feed permutations by edit distance into a Damerau-Levenshtein NFA; the number of permutations grows fast, so it's a good idea to delay (N-C) cycle N permutations candidates until (N-C) iterations of the NFA.
I've only studied engineering math up to Differential Equations and Discrete Mathematics, so I lack the foundation to approach this task from a formal perspective. If anyone can provide reference materials to help me understand this problem properly, I would appreciate that!
Through brief empirical analysis, I've noticed that I can generate the swaps for all C cycle N permutations with this procedure:
Generate all 2-combinations of N elements (combs)
Subdivide combs into arrays where the smallest element of each 2-combination is the same (ncombs)
Generate the cartesian products of the (N-C)-combinations of ncombs (pcombs)
Sum pcombs to get a list of the swaps that will generate all C cycle N permutations (swaps)
The code is here.
My Python is a bit rusty, so helpful advice about the code is appreciated (I have the feeling that lines 17, 20, and 21 should be combined. I'm not sure if I should be making lists of the results of itertools.(combinations|product). I don't know why line 10 can't be ncombs += ... instead of ncombs.append(...)).
My primary question is how to solve this question properly. I did the rounds on my own due diligence by finding a solution, but I am sure there's a better way. I've also only verified my solution for N=3 and N=4, is it really correct?
The ideal solution would be functionally identical to heap's algorithm, except it would generate the permutations in decreasing cycle order (by the minimum number of swaps to generate the permutation, increasing).
This is far from Heap's efficiency, but it does produce only the necessary cycle combinations restricted by the desired number of cycles, k, in the permutation. We use the partitions of k to create all combinations of cycles for each partition. Enumerating the actual permutations is just a cartesian product of applying each cycle n-1 times, where n is the cycle length.
Recursive Python 3 code:
from math import ceil
def partitions(N, K, high=float('inf')):
if K == 1:
return [[N]]
result = []
low = ceil(N / K)
high = min(high, N-K+1)
for k in range(high, low - 1, -1):
for sfx in partitions(N-k, K - 1, k):
result.append([k] + sfx)
return result
print("partitions(10, 3):\n%s\n" % partitions(10, 3))
def combs(ns, subs):
def g(i, _subs):
if i == len(ns):
return [tuple(tuple(x) for x in _subs)]
res = []
cardinalities = set()
def h(j):
temp = [x[:] for x in _subs]
temp[j].append(ns[i])
res.extend(g(i + 1, temp))
for j in range(len(subs)):
if not _subs[j] and not subs[j] in cardinalities:
h(j)
cardinalities.add(subs[j])
elif _subs[j] and len(_subs[j]) < subs[j]:
h(j)
return res
_subs = [[] for x in subs]
return g(0, _subs)
A = [1,2,3,4]
ns = [2, 2]
print("combs(%s, %s):\n%s\n" % (A, ns, combs(A, ns)))
A = [0,1,2,3,4,5,6,7,8,9,10,11]
ns = [3, 3, 3, 3]
print("num combs(%s, %s):\n%s\n" % (A, ns, len(combs(A, ns))))
def apply_cycle(A, cycle):
n = len(cycle)
last = A[ cycle[n-1] ]
for i in range(n-1, 0, -1):
A[ cycle[i] ] = A[ cycle[i-1] ]
A[ cycle[0] ] = last
def permutations_by_cycle_count(n, num_cycles):
arr = [x for x in range(n)]
cycle_combs = []
for partition in partitions(n, num_cycles):
cycle_combs.extend(combs(arr, partition))
result = {}
def f(A, cycle_comb, i):
if i == len(cycle_comb):
result[cycle_comb].append(A)
return
if len(cycle_comb[i]) == 1:
f(A[:], cycle_comb, i+1)
for k in range(1, len(cycle_comb[i])):
apply_cycle(A, cycle_comb[i])
f(A[:], cycle_comb, i+1)
apply_cycle(A, cycle_comb[i])
for cycle_comb in cycle_combs:
result[cycle_comb] = []
f(arr, cycle_comb, 0)
return result
result = permutations_by_cycle_count(4, 2)
print("permutations_by_cycle_count(4, 2):\n")
for e in result:
print("%s: %s\n" % (e, result[e]))
Output:
partitions(10, 3):
[[8, 1, 1], [7, 2, 1], [6, 3, 1], [6, 2, 2], [5, 4, 1], [5, 3, 2], [4, 4, 2], [4, 3, 3]]
# These are the cycle combinations
combs([1, 2, 3, 4], [2, 2]):
[((1, 2), (3, 4)), ((1, 3), (2, 4)), ((1, 4), (2, 3))]
num combs([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], [3, 3, 3, 3]):
15400
permutations_by_cycle_count(4, 2):
((0, 1, 2), (3,)): [[2, 0, 1, 3], [1, 2, 0, 3]]
((0, 1, 3), (2,)): [[3, 0, 2, 1], [1, 3, 2, 0]]
((0, 2, 3), (1,)): [[3, 1, 0, 2], [2, 1, 3, 0]]
((1, 2, 3), (0,)): [[0, 3, 1, 2], [0, 2, 3, 1]]
((0, 1), (2, 3)): [[1, 0, 3, 2]]
((0, 2), (1, 3)): [[2, 3, 0, 1]]
((0, 3), (1, 2)): [[3, 2, 1, 0]]
We are given a directed graph, with nodes labeled 0, 1, ..., n-1 and each edge is either red or blue, and there could be self-edges or parallel edges.
Each [i, j] in red_edges denotes a red directed edge from node i to node j. Similarly, for blue_edges.
Return an array 'answer' of length n, where each answer[X] is the length of the shortest path from node 0 to node X such that the edge colors alternate along the path (or -1 if such a path doesn't exist).
I'm not getting where's the problem in the code.
n = 3, red_edges = [[0,1],[1,2]], blue_edges = []
n = 3, red_edges = [[0,1]], blue_edges = [[2,1]]
n = 3, red_edges = [[0,1]], blue_edges = [[1,2]]
n = 3, red_edges = [[1,0]], blue_edges = [[2,1]]
d={}
result=[-1]*(n)
for i in red_edges:
if i[0] not in d:
d[i[0]]=[i[1]]
else:
d[i[0]].append(i[1])
if i[0]==0:
result[i[1]]=1
#print(d)
for j in blue_edges:
if j[0] not in d:
d[j[0]]=[j[1]]
else:
d[j[0]].append(j[1])
if j[0]==0:
result[j[1]]=1
elif j[0]!=0:
if j[0] in d[0]: #This is Line 24 which is throwing error.
result[j[1]]=2
else:
pass
if 0 in d[0]:
result[0]=1
else:
result[0]=0
#print(d)
print(result)
Key in 'd' is equal to the starting node and value in a key-value pair has a list in which all the endpoints corresponding to that key are inserted.
Moreover, in each for loop, I'm also preparing my result array if any edge is present between node zero and node equal to the index of the result array. e.g, I'll insert 1 in result array for index 1 if it has a direct link with node zero else I'll keep it as -1. And if any index has indirect link( as in test case 2: blue_edges =[[2,1]]) then I'll check in d[0] if first element of blue_edges is present. If it is present then I'll insert 2 else -1.
expected=actual=[0,1,-1]
expected=actual=[0,1,-1]
expected=actual=[0,1,1]
expected=[0,-1,-1] but in 4th case it is throwing an error.
Line 24: KeyError: 0
I switched to using defaultdict(list) so that if d is empty for some value, you'll just get an empty list.
In your case - it eliminates the error and logically matches the if.
it also help clean up many if/elses.
try this:
from collections import defaultdict
cases = [
(3, [[0, 1], [1, 2]], []),
(3, [[0, 1]], [[2, 1]]),
(3, [[0, 1]], [[1, 2]]),
(3, [[1, 0]], [[2, 1]]),
]
for n, red_edges, blue_edges in cases:
d = defaultdict(list)
result = [-1] * n
result[0] = 0
for src, dst in red_edges:
d[src].append(dst)
if src == 0:
result[dst] = 1
for src, dst in blue_edges:
d[src].append(dst)
if src == 0:
result[dst] = 1
else:
if src in d[0]:
result[dst] = 2
print(result)
Output:
[0, 1, -1]
[0, 1, -1]
[0, 1, 2]
[0, -1, -1]
I have a list of 262144 elements in a list created through "itertools.product". Now I have to loop over these elements and multiply it with all other elements, which is taking too much time. (I don't have any issue of memory / cpu)
elements = []
for e in itertools.product(range(4), repeat=9):
elements.append(e)
for row in elements:
for col in elements:
do_calculations(row, col)
def do_calculations(ro, co):
t = {}
t[0] = [multiply(c=ro[0], r=co[0])]
for i in range(1, len(ro)):
_t = []
for j in range(i+1):
_t.append(multiply(c=ro[j], r=co[i-j]))
t[i] = _t
for vals in t.values():
nx = len(vals)
_co = ro[nx:]
_ro = co[nx:]
for k in range(len(_ro)):
vals.append(multiply(c=_co[k], r=_ro[k]))
_t = []
for k in t.values():
s = k[0]
for j in range(1, len(k)):
s = addition(c=s, r=k[j])
_t.append(s)
return _t
def addition(c, r) -> int:
__a = [[0, 3, 1, 2],
[3, 2, 0, 1],
[0, 3, 2, 1],
[1, 0, 2, 3]]
return __a[c][r]
def multiply(c, r) -> int:
__m = [[0, 0, 0, 0],
[0, 1, 2, 3],
[0, 3, 1, 2],
[0, 2, 3, 1]]
return __m[c][r]
it is taking too much time to process single col with rows....
can any one help me in this?
regards
Not much of a python guy but
make sure col is a higher number than row (small optimization, but optimization nevertheless)
use a multiprocessing library (alink). that should cut the calculation time.
(as noted in comment by #Skam, multithreading does not increase performance in such case)
also, you might consider some optimizations in the calculation itself.
I am trying to append permutations of a list of integers to a local variable in python but end of appending a single permutation several times. The code will print all the results correctly but not sure why my class variable will not be updated correctly.
Any help would be extremely appreciated!!
I am working on a leetCode problem but can't output the right results. I am trying to update my array, myVals, within a backtracking loop but and storing the just one permutation.
I can print all the results however when
class Solution:
def __init__(self):
self.myVals = []
def add(self, x):
self.myVals.append(x)
def permuteArray(self, nums, l, r):
if l == r:
print(nums)
self.add(nums)
else:
for i in range(l, r + 1):
nums[l], nums[i] = nums[i], nums[l]
self.permuteArray(nums, 1+l, r)
nums[l], nums[i] = nums[i], nums[l]
def permute(self, nums):
"""
:type nums: List[int]
:rtype: List[List[int]]
"""
numCount = len(nums)
start = 0
self.permuteArray(nums, start, numCount - 1)
print(self.myVals)
nums = [1,2,3]
driver = Solution()
result = driver.permute(nums)
Expected Results:
[[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 2, 1], [3, 1, 2]]
Actual Results:
[[1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3]]