2009-07-22 25 views
11

Jeneratör oluşturmak için Mathematica'da Python'un getiri beyanı gibi bir şey yapabilir misiniz? Bakınız örn. Konsept için here.Mathematica'da Verim

Burada ne demek istediğimi bir örnek Güncelleme, sadece O (n) alanı kullanarak, tüm permütasyon yineleme için: (Algoritması Sedgewick'e en Algoritmalar kitabında olduğu gibi):

gen[f_, n_] := Module[{id = -1, val = Table[Null, {n}], visit}, 
    visit[k_] := Module[{t}, 
    id++; If[k != 0, val[[k]] = id]; 
    If[id == n, f[val]]; 
    Do[If[val[[t]] == Null, visit[t]], {t, 1, n}]; 
    id--; val[[k]] = Null;]; 
    visit[0]; 
    ] 

Sonra bunu diyoruz gibi: uzunlukta 6 permütasyon baskı

gen[Print,3], 3.

+0

FWIW, Python'un yineleyici/üreteç yapma şekli oldukça sıradışı. Devlet üzerinde bir çeşit soyutlama (kapaklar, sınıflar) olduğu sürece, bunları herhangi bir dubada uygulayabilirsiniz. – jrockway

+0

Ah, güzel. Belki de bunu kendi sorunuza bir cevap olarak ekleyelim (bunu yapmak için oldukça koşucu sayılır). Yoksa burada hala cevaplanmamış bir soru var mı? – dreeves

+0

Python, sizin için bir şey ifade ediyor ve bu çerçeveye uygun hale getirirken, işlevlerinizi açık bir şekilde iletmeniz gerekiyor. Yani, bu mükemmel değil. Ama yeterince iyi, aslında, şimdi kullanıyorum. – nes1983

cevap

5

Daha önce belirttiğim gibi, Compile kullanarak daha hızlı kod verilecektir.

ClearAll[cfNextPartition]; 
cfNextPartition[target : "MVM" | "C"] := 
    cfNextPartition[target] = 
    Compile[{{n, _Integer}, {this, _Integer, 1}}, 
    Module[{i = n, j = n, ni, next = this, r, s}, 
    While[Part[next, --i] > Part[next, i + 1], 
     If[i == 1, i = 0; Break[]]]; 
    If[i == 0, {-1}, ni = Part[next, i]; 
     While[ni > Part[next, j], --j]; 
     next[[i]] = Part[next, j]; next[[j]] = ni; 
     r = n; s = i + 1; 
     While[r > s, ni = Part[next, r]; next[[r]] = Part[next, s]; 
     next[[s]] = ni; --r; ++s]; 
     next 
     ]], RuntimeOptions -> "Speed", CompilationTarget -> target 
    ]; 

Sonra

In[75]:= Reap[PermutationIterator[Sow, 4, cfNextPartition["C"]]][[2, 
    1]] === Permutations[Range[4]] 

Out[75]= True 

budur:

Aşağıdaki kod varsayar
PermutationIterator[f_, n_Integer?Positive, nextFunc_] := 
Module[{this = Range[n]}, 
    While[this =!= {-1}, f[this]; this = nextFunc[n, this]];] 

biz sürüm 8 çalıştırın: fxtbook gelen bir algoritma kullanarak, aşağıdaki kod lexicographic sıralamada bir sonraki bölümü oluşturur Orijinal gen işlevinden açıkça daha iyi performans. Mathematica adlı sanal makine kullanma

In[83]:= gen[dummy, 9] // Timing 

Out[83]= {26.067, Null} 

In[84]:= PermutationIterator[dummy, 9, cfNextPartition["C"]] // Timing 

Out[84]= {1.03, Null} 

çok daha yavaş değil:

In[85]:= PermutationIterator[dummy, 9, 
    cfNextPartition["MVM"]] // Timing 

Out[85]= {1.154, Null} 

Tabii bu, hiçbir yerde C kodu uygulaması yakındır henüz saf üst düzey kodu üzerinde önemli bir hız-up sağlar.

+0

Sen bu yazı açığa edildi hile kullanarak C hızını alabilirsiniz: http://stackoverflow.com/questions/5246330/delete-repeating- list-elementler-koruyarak dereceden-of-görünüm/5251034 # 5251034. "PermutationIterator" derlenmiş bir işlev için bir jeneratör oluşturursanız, şöyle ki: 'PermutationIteratorGen [f_, nextFunc_]: = Derleme [{{n, _Integer}}, Modülü [{this = Aralık [n]}, [bu =! = {-1}, f [bu]; this = nextFunc [n, this]];], RuntimeOptions -> "Speed", CompilationTarget -> "C", Derleme Seçenekleri -> {"InlineCompiledFunctions" -> Doğru, "InlineExternalDefinitions" -> Doğru}] ', devamı .. –

+0

Devam ediyor .. Sonra, * kukla * işlevinizin "Derlendi" olduğu varsayılarak, başka bir büyüklük hızlandırma sırası alırsınız: 'fn = PermutationIteratorGen [# &, cfNextPartition [" C "]]; fn [9] // Zamanlama '. Yukarıdaki hile etkili bir şekilde derlenmiş kodun içerdiği değişkenlerin derlenmiş kodda yaşamalarına izin verir ve arayanın derlenmiş işlevi tarafından değiştirilir, çünkü sonunda satır içi ve sadece büyük bir Derlenmiş işlevi alırız, ama bizim için daha modüler görünüyor . Ancak 'Sow' veya diğer komplike olmayan fonksiyonlar, performansı büyük ölçüde bozar, böylece C ve MVM arasında neredeyse hiçbir fark olmaz. –

+0

@Leonid Evet, bu iyi bir nokta ve yineleyici, önceden belirlenmiş bazı işlemleri gerçekleştirmek için özel olarak yazılabilir, böylece işlevi tamamen geçmeye devam eder. C-speed ile kastettiğim şey, fxtbook'ta yapılan ikinci alıntı başına üretilen 130 milyon permütasyondan uzak olmasıdır. 'fn [11]' makinemde saniyede 4 milyon permütasyona 9.86 saniye sürer. CompilePrint [fn] 'ye bir bakış öğreticidir ve bunun neden olduğunu gösterecektir. – Sasha

2

muhtemelen soru daha genel olarak ama yinelemek örneğini permutatio demek Bağlamak sayfasında verildiği gibi ns için Matematica inşa edilecek olur:

Scan[Print, Permutations[{1, 2, 3}]] 

Print herhangi fonksiyonu ile orada değiştirilebilir.

+2

Eh, bir jeneratör tarafından ne demek istediğim, O (n) hafızasında çalışan, O (n!) 'Ye ihtiyacınız olan aşağıdaki gibidir. gen [f_, n_]: = Modül [{id = -1, val = Tablo [Boş, {n}], ziyaret edin}, ziyareti [k_]: = Modül [{t}, id ++; Eğer [k!= 0, val [[k]] = id]; [id == n, f [val]]; Do [val [[t]] == Boşsa, [t]], {t, 1, n} sayfasını ziyaret edin; id--; val [[k]] = Boş;); ziyareti [0]; ] Böyle çalıştırmak: gen [Baskı, 3] – nes1983