Если я правильно понимаю, это должно дать вам то, что вы хотите:
import numpy as np
from itertools import permutations
def fluboxing_permutations(a, n):
return [p for p in permutations(range(n))
if all(a[i, j] > a[j, i] for i, j in zip(p, p[1:]))]
n = 3
a = np.random.random([n, n])
fluboxing_permutations(a, n)
itertools.permutations
приведет к перестановкам в лексикографическом порядке, соответствующем вашему дереву; затем мы проверяем, что для каждой последовательной пары индексов в перестановке элемент в матрице больше, чем элемент при поменяемых индексах. Если это так, мы сохраняем перестановку.
(Понятия не имею, как описать, что делает функция, поэтому я сделал новое имя. Надеюсь, вам понравится. Если кто-нибудь знает лучший способ описать это, пожалуйста, отредактируйте!: P)
РЕДАКТИРОВАТЬ: Вот рекурсивная функция, которая должна делать то же самое, но с сокращением:
def fluboxing_permutations_r(a, n):
nset = set(range(n))
def inner(p):
l = len(p)
if l > 1 and a[p[-2]][p[-1]] <= a[p[-1]][p[-2]]:
return []
if l == n:
return [p]
return [r for i in nset - set(p)
for r in inner(p + (i,))]
return inner(())
p
начинается как пустой кортеж, но растет в рекурсии. Если в частичной перестановке есть хотя бы два элемента, мы можем проверить последние два элемента и проверить, не прошел ли он тест, и отклонить его, если это произойдет (удалив его поддерево из пространства поиска). Если это полная перестановка, которая не была отклонена, мы ее возвращаем. Если он еще не заполнен, мы добавляем к нему все возможные индексы, которых там еще нет, и возвращаемся.
tinyEDIT: Кстати, параметр n
является своего рода избыточным, потому что n = len(a)
в верхней части функции должен заботиться об этом.