33

operasyonların sırası Verilen:Dize analizi

a * b * a * b * a * a * b * a * b

optimal alt bölümü almanın bir yolu yoktur alt dizinin yeniden kullanılmasını sağlar.

a * b yapmak * a * b * a * a * b * a * b * => C * A * C, burada c = a * b * a * b

görme

ve daha sonra bu

a * b * a * b * => d x d, d = a * b th 8 içine ilk redüksiyon işlemleri tüm

tüm e 4 burada açıklanan?

(c = (d = a * b) * d) * A * C

tabii amacı bir suffixtree düşünüyorum işlemleri

sayısını

en aza indirmek için çeşitler.

Özellikle lineer zaman keşifleri veya çözümleri ile ilgileniyorum. '*' işlemleri aslında matris çarpımlarıdır.

+0

Kısa soru (n log n) - Sadece (mutiplication kullanmakta olduğunuz a * b durumda = b * a) veya * keyfi bir işlem olup, ilgilendiğiniz alt dizelerdir? –

+0

, operatörler aslında matris çarpımlarıdır –

+1

Bunları değişmez yapan yapar. Ama yine de ilişkisel veya bu soru mantıklı olmaz. – phkahler

cevap

19

Bu sorun, "Common Subexpression Elimination" or CSE olarak bilinir. İşlevsel programlama dilleri için derleyicilerin uyguladığı "Graph Reduction" adlı sorunun biraz daha küçük bir versiyonudur. Googling “Common Subexpression eliminasyon algoritması”, özellikle matris çarpımının verdiği kısıtlamalar için göremediğim bir çok çözüm sunar.

Bağlantı verilen sayfalar çok sayıda referans veriyor.

Eski yanıtım aşağıda. Ancak, biraz daha fazla araştırdıktan sonra, çözüm sadece bir suffix tree yapıyor. Bu O (N) zamanında yapılabilir (wikipedia sayfasındaki birçok referans). Bunu yaptıktan sonra, alt ifadeler (sorunuzdaki c, d vb.) Sonek ağacındaki sadece düğümlerdir - sadece onları dışarı çekin.


Ancak, grafik azaltma öncelik burada izin verilebilir optimizasyon izin vermeyebilir olarak Marcos, Longest repeating Substring önerisi ile bir şey için olduğunu düşünüyorum. algoritmanın

kroki:

optimise(s): 
    let sub = longestRepeatingSubstring(s). 
    optimisedSub = optimise(sub) 
    return s with sub replaced by optimisedSub 

en uzun yinelenen alt dize her çalışma gereken süre N. Muhtemelen suffix tree sen itibaren zaman N.

+0

Kod minimizasyonu gibi göründüğünü düşünüyordum ;-) –

+0

Merhaba @nick, Steven S. Muchnick'in derleyici Tasarım Uygulamalarına dair kitabına baktım ve haklısınız, CSE problemine çok benziyor. Tek şey, bir dizi atomik işlem için tasarlanan CSE algoritmasına benzediğidir - ve bu, simülaritenin durduğu yerdir. Sorunumu bir dizi işlem içine yeniden yazdığımdan, ister doğrusal isterse bir treefashion, çözüme yönelik kısıtlamalar getirecektir. Ama sanırım senin ameliyatın hakkında fikirler var. –

+0

CSE ayrıca C derleyiciler tarafından yapılır. – phkahler

14

düzenleme: Bu cevap siparişler-of-büyüme, bir sıkıştırma algoritması istediğini olabilir

İlginç CSE veya matris zincir çarpma çalıştırmak için kabul edilen yanıt ek olarak ihtiyaç vardır: Bir sıkıştırma algoritması sıkıştırdığı şeyin boyutunu küçültmeyi amaçlamaktadır ve eğer bunu yapabilmesinin tek yolu ikame olması durumunda, onu izleyebilir ve algoritmanız için gerekli alt bileşenleri elde edebilirsiniz. Bu küçük girdiler için güzel sonuçlar vermeyebilir.

Bu tür bir algoritmanın seçiminde, işlemlerin hangi alt kümelerinin değişmeli olduğu önemli bir husustur. Açgözlü olmadığı sorusu vardır

input: [some product of matrices to compute] 

given that multiplying two NxN matrices is O(N^2.376) 
given we can visualize the product as follows: 
    [[AxB][BxC][CxD][DxE]...] 
we must for example perform O(max(A,B,C)^2.376) or so operations in order to combine 
    [AxB][BxC] -> [AxC] 

The max(...) is an estimate based on how fast it is to multiply two square matrices; 
a better estimate of cost(A,B,C) for multiplying an AxB * BxC matrix can be gotten 
from actually looking at the algorithm, or running benchmarks if you don't know the 
algorithm used. 

However note that multiplying the same matrix with itself, i.e. calculating 
a power, can be much more efficient, and we also need to take that into account. 
At worst, it takes log_2(power) multiplies each of O(N^2.376), but this could be 
made more efficient by diagonalizing the matrix first. 

: biz böyle önbelleğe alma gibi efektleri göz ardı edersek,

Biz de optimal çözüm tanımlayabilirsiniz: [değiştir OP hiçbir işlem onun/onu durumda değişmeli diyor] Yaklaşım mümkün değildir: Her adımda tekrarlayan alt dizileri sıkıştırmanız gerekip gerekmediği. Bu durum söz konusu olmayabilir, örn.

aaaaabaab 
compressing 'aa' results in ccabcb and compressing 'aab' is now impossible 

Ancak biz sıkıştırarak alt dizeleri tüm siparişler denerseniz, muhtemelen çok sık bu sorunla yayınlanmaz, bu bir his var.

Böylece (maliyetler) istediğini yazılı olan ve sorunları, biz bunu zaten yapabilir bir kaba kuvvet algoritması var ve bu matrisin çok az sayıda aday olacak muhtemelen kabul:

# pseudocode 

def compress(problem, substring) 
    x = new Problem(problem) 
    x.string.replaceall(substring, newsymbol) 
    x.subcomputations += Subcomputation(newsymbol=substring) 

def bestCompression(problem) 
    candidateCompressions = [compress(problem,substring) for each substring in problem.string] 
    # etc., recursively return problem with minimum cost 
    # dynamic programming may help make this more efficient, but one must watch 
    # out for the note above, how it may be hard to be greedy 

Not: Asgeir'in bir başka cevabına göre, bu Matris Zinciri Çarpımı optimizasyon problemi olarak bilinir. Nick Fortescue, daha genel olarak http://en.wikipedia.org/wiki/Common_subexpression_elimination olarak da bilinir - bu nedenle literatürden herhangi bir jenerik CSE veya Matrix-Chain-Çarpma algoritması/kitaplığı bulabilir ve fişi daha önce belirtmiş olduğum maliyet siparişleri büyüklüğünde (siz hangi adayı kullanacağınıza karar vermelisiniz. Yukarıdaki hesaplamaların maliyetinin (çarpma, üs alma, vb.), Son teknoloji ürünü algoritmalar ile verimli bir şekilde yapıldığını varsaydığını unutmayın. Bu durumda değilse, üslerin operasyonların gerçekleştirilme şekline uygun uygun değerlerle değiştirin.

+0

işlemlerim matris çarpımıdır ve bu nedenle değişmez değildir. –

7
+0

sadece bir indirgeme yapmakla ilgiliysem olurdu, ancak tüm indirgeme serisini bilmek istediğimden, aynı sorun olduğunu düşünmüyorum. Sorunun en iyi çözümünde yer alan en uzun yinelenen alt dizgenin olduğundan emin olabileceğinizden bile emin değilim. –

+0

@Martin Kristiansen: true. Bununla birlikte, yinelenen en uzun alt dizeyi bulmak için algoritmayı yinelemeli olarak uygulayabileceğinizi düşünüyorum: Eğer orijinal dizginizle başlıyorsanız, "a * b * a * b * a * a * b * a * b" sonra a * b olsun * a * b'; Şimdi içinde en uzun tekrarlanan alt dizeyi bulabilirsiniz, bu bir "b", sonra tekrar ararsanız bir şey bulamazsınız ve işiniz biter. – MarcoS

8

içinde her şey çözmek için inşa yeniden kullanabilirsiniz Başın tepesinde sorun benim için NP'de görünüyor. Diğer alt katmanlardaki değişikliklere bağlı olarak, örneğin d*e*a*b*c*d*e*a*b*c*d*e*a dizesi için çeşitli olasılıklar olabilir. f = d*e*a*b*c ve sonunda üç çoğaltmaları ve dört ara olanlar (toplam yedi) ile bırakarak f*f*e*a yerine olabilir: Eğer en uzun ortak dize alırsak

öyle olacak.

bunun yerine aşağıdaki şekilde yerine ise: f = d*e*a Eğer başka altı çarpma olmak üzere toplam g = f*b*cg*g*f kullanarak yerini alabilir f*b*c*f*b*c*f olsun.

Bu sorunla ilgili olası başka alternatifler de vardır, ancak şu anda bunları hesaba katma zamanım yok.Ben tam bir asgari ikame için tahmin ediyorum

muhtemelen şimdiye kadar tüm değiştirmelerin izlemek zorunda ve geri izleme yok demektir sadece en uzun ortak alt dize değil, aynı zamanda bazen her alt dize tekrarlar, sayısını anlamaya gereklidir. Yine de gerçek çarpımlardan daha hızlı olabilir. Eğer o zaman O indirgenebilir matrix chain multiplication bakmak gerekir en az aritmetik işlemlerini kullanmak istiyorsanız