Возможная комбинация скобок в матричном приложении - PullRequest
0 голосов
/ 27 сентября 2018

Я изучил умножение цепочки матриц, в которой при заданной последовательности матриц цель состоит в том, чтобы найти наиболее эффективный способ умножения матриц.Проблема на самом деле не в том, чтобы выполнить умножения, а просто в том, чтобы решить последовательность задействованных умножений матриц.По этой причине мне поручено составить программу, которая выводит все возможные комбинации матриц в матричном умножении, используя n в качестве числа матриц в качестве входных данных.Например,

 n == 1     (A)

 n == 2     (AB)

 n == 3     (AB)C ,  A(BC)

 n== 4      ((AB)C)D,   (A(BC))D, A((BC)D), A(B(CD)), (AB)(CD)

Мой начальный код был ниже, он вызывается как

 possible_groupings(4) #4 matrices

def possible_groupings(n):
    print("Possible Groupings : ")
    total  = 0
    if(n==1):
        print('A')
        total = total + 1
    elif(n==2):
       print('(AB)')
       total = total + 1
    else:
       a = 2
       while(a <= n-1):
           b = 0
           while((b+a) <= (n )):
               c = b

               d = 0
               substr = ''
               while (d < c):                    
                   substr = substr + chr(65 + d)                    
                   d = d + 1

               if substr != '':
                   if len(substr) == 1:
                      print( substr, end = '')
                   else:
                      print('(' + substr + ')', end = '')

            print('(', end = '')
            while (c < (b +a)):                    
                print(chr(65 + c), end = '');
                c = c + 1
            print(')', end = '')

            e = b+a

            substr = ''
            while (e < n):
                substr = substr + chr(65 + e) 
                e = e + 1
            if substr != '':
                if len(substr) == 1:
                    print( substr, end = '')
                else:
                    print('(' + substr + ')', end = '')
            print('')

            total = total + 1

            b = b + 1
        a = a + 1
print('Total : ' + str(total))

Вывод кода выше, когда мой входной файл равен 4 матрицам:

(AB)(CD)
A(BC)D
(AB)(CD)
(ABC)D
A(BCD)

Как я могу пересмотреть мой код.Количество матриц должно быть в диапазоне 1-26.Моя голова сейчас болит.Пожалуйста, помогите.

Ответы [ 3 ]

0 голосов
/ 27 сентября 2018

Существует Catalan(nmatrices-1) комбинаций, и мы можем использовать простой алгоритм сбалансированных скобок для генерации предварительных комбинаций.Вот код для получения скобок (для сравнения) и матричных предварительных комбинаций.

Но я пока не нашел краткого метода установки закрывающих скобок (аргумент cx - это моя попытка подсчитать умножения и вывести число закрывающих скобок в данной точке).

Возможно, кто-то может увидеть простую формулу/ закон, чтобы получить окончательный результат.

def genparens(s, maxlen, l, r):
    if l + r == maxlen * 2:
        print(s)
        return
    if l < maxlen:
        genparens(s + '(', maxlen, l + 1, r)
    if r < l:
        genparens(s + ')', maxlen, l, r + 1)

alpha = "ABCDEFGHIJK"

def genmatparens(s, n, l, r, ci, cx):
    if l + r == n * 2:
        s = s + alpha[ci] # + ")" * cx
        print(s)
        return
    if l < n:
        genmatparens(s + '(', n, l + 1, r, ci, cx + 1)
    if r < l:
        s += alpha[ci]
        #s += ")" * cx
        s += "x"
        genmatparens(s, n, l, r + 1, ci + 1, 1)


genparens("", 3, 0, 0)
print()
genmatparens("", 3, 0, 0, 0, 0)

((()))
(()())
(())()
()(())
()()()
current           should be
(((AxBxCxD        (((AxB)xC)xD)
((Ax(BxCxD        ((Ax(BxC))xD)
((AxBx(CxD        ((AxB)x(CxD))
(Ax((BxCxD        (Ax((BxC)xD))
(Ax(Bx(CxD        (Ax(Bx(CxD)))
0 голосов
/ 01 октября 2018

Вот рекурсивная схема, которая работает задом наперед.

Она реализована в виде генератора part, который начинается с умножения last .Это последнее умножение должно быть между двумя факторами, левый из которых является произведением по первым j (переменная cut в коде ниже) матриц («левый блок») и правым из которых является произведениеповерх оставшихся матриц («правый блок»). j может быть любым значением от 1 до N -1, где N - количество матриц в цепочке.

Поэтому для перечисления всехгруппировки мы должны перебрать j .Для каждого j мы должны объединить каждую группировку левого блока с каждой группировкой правого блока.Для перечисления группировок блоков мы используем part, то есть рекурсию.

def part(names, top=True):
    lr = ('', '') if top else '()'
    if len(names) <= 1:
        yield names
    elif len(names)==2:
        yield names.join(lr)
    else:
        for cut in range(1, len(names)):
            for left in part(names[:cut], False):
                for right in part(names[cut:], False):
                    yield (left+right).join(lr)

Та же логика может быть использована для минимизатора.Для этого можно использовать памятку в соответствии с functools.lru_cache:

from functools import lru_cache
from string import ascii_uppercase

@lru_cache(None)
def _min_no_mult(dims):
    if len(dims) == 2:
        return 0, 'x'
    elif len(dims)==3:
        return dims[0]*dims[1]*dims[2], 'xx'.join('()')
    cuts = ((cut, *_min_no_mult(dims[:cut+1]), *_min_no_mult(dims[cut:]))
            for cut in range(1, len(dims)-1))
    return min((mnl + mnr + dims[0]*dims[-1]*dims[cut], (nml+nmr).join('()'))
                for cut, mnl, nml, mnr, nmr in cuts)

def min_no_mult(dims, names=None):
    mn, argmn = _min_no_mult(tuple(dims))
    names = iter(ascii_uppercase if names is None else names)
    argmn = argmn[1:-1] if len(dims) > 2 else argmn
    argmn = ''.join(next(names) if a=='x' else a for a in argmn)
    return mn, argmn

Демо:

>>> for i, j in enumerate(part(ascii_uppercase[:6])):
...     print(i, j)
... 
0 A(B(C(D(EF))))
1 A(B(C((DE)F)))
2 A(B((CD)(EF)))
3 A(B((C(DE))F))
4 A(B(((CD)E)F))

...

38 ((A((BC)D))E)F
39 (((AB)(CD))E)F
40 (((A(BC))D)E)F
41 ((((AB)C)D)E)F

Благодаря памятке минимизатор может легко обрабатывать большое количество измерений:

>>> import numpy as np
>>> dims = np.clip(np.arange(-1, 26), 1, None)
>>> np.random.shuffle(dims)
>>> dims
array([ 5, 25,  1,  4, 14, 24,  7, 15,  2, 12, 11,  9, 18,  8, 19, 13, 23,
       17,  1, 22, 21,  1, 16,  6,  3, 20, 10])

>>> min_no_mult(dims)
(3383, '(AB)((((((((((CD)E)F)G)H)(I(J(K(L(M(N(O(P(QR))))))))))((ST)U))((VW)X))Y)Z)')

Мы можем запросить некоторую базовую статистику кэша:

>>> _min_no_mult.cache_info()
CacheInfo(hits=5450, misses=351, maxsize=None, currsize=351)

Это может показаться не впечатляющим, но имейте в виду, что каждое попадание обрезает целое поддерево.

Действительно, мы можем еще раз переработатьсхема повторения и подсчета количества скобок:

@lru_cache(None)
def count(n):
    if n <= 2:
        return 1
    else:
        return sum(count(cut) * count(n-cut) for cut in range(1, n))

Для 26 матриц существует несколько способов заключить их в скобки:

>>> print(f"{count(26):,d}")
4,861,946,401,452
0 голосов
/ 27 сентября 2018

Похоже, что вы хотите разделить набор символов на все возможные подмножества, хотя вы, похоже, не учли несмежные группировки (такие как (AC) (DB)).Если это так, то это известная проблема, для которой существуют известные решения.См. Например Как найти все разделы набора .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...