2009-07-22 41 views
11

Bạn có thể làm điều gì đó giống như tuyên bố lợi nhuận của Python trong Mathematica, để tạo ra máy phát điện không? Xem ví dụ here cho khái niệm.Năng suất trong Mathematica

Cập nhật Dưới đây là một ví dụ về những gì tôi có nghĩa là, để lặp qua tất cả các hoán vị, chỉ sử dụng O (n) không gian: (Thuật toán như trong cuốn sách Thuật toán Sedgewick):

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]; 
    ] 

Sau đó gọi nó là nó như:

gen[Print,3], in tất cả 6 hoán vị của chiều dài 3.

+0

FWIW, cách tạo lặp/tạo của Python là khá bất thường. Miễn là bạn có một số loại trừu tượng trên trạng thái (bao đóng, các lớp), bạn có thể thực hiện chúng trong bất kỳ ngôn ngữ nào. – jrockway

+0

Ah, hay. Có thể thêm rằng như là một câu trả lời cho câu hỏi của riêng bạn (nó được coi là khá kosher để làm điều đó). Hay vẫn còn một câu hỏi chưa được trả lời ở đây? – dreeves

+0

Vâng, bạn cần phải thông minh một cách rõ ràng các chức năng của bạn xung quanh, trong khi các loại năng suất Python loại con số nó ra cho bạn, và làm cho nó phù hợp với khuôn khổ. Vì vậy, nó không phải là khá hoàn hảo. Nhưng đủ tốt, thực sự, tôi sử dụng nó ngay bây giờ. – nes1983

Trả lời

5

Như tôi đã nêu trước đây, việc sử dụng Compile sẽ đưa ra mã nhanh hơn. Sử dụng một thuật toán từ fxtbook, đoạn code sau tạo ra một phân vùng tiếp theo trong trật tự tự từ điển:

PermutationIterator[f_, n_Integer?Positive, nextFunc_] := 
Module[{this = Range[n]}, 
    While[this =!= {-1}, f[this]; this = nextFunc[n, this]];] 

Các mã sau đây giả định chúng tôi chạy phiên bản 8:

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 
    ]; 

Sau đó

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

Out[75]= True 

Đây là rõ ràng hơn về hiệu suất so với chức năng gốc gen.

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

Out[83]= {26.067, Null} 

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

Out[84]= {1.03, Null} 

Sử dụng máy ảo Mathematica không phải là chậm hơn nhiều:

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

Out[85]= {1.154, Null} 

Tất nhiên đây là nơi nào gần thi mã C, tuy nhiên cung cấp một tốc độ đáng kể-up trên tinh khiết đang cấp cao nhất.

+0

Bạn có thể nhận được tốc độ C bằng cách sử dụng mẹo tôi đã phơi bày trong bài đăng này: http://stackoverflow.com/questions/5246330/delete-repeating- list-elements-preserving-order-of-appearance/5251034 # 5251034. Nếu bạn tạo một trình tạo cho một hàm được biên dịch 'PermutationIterator', như sau:' PermutationIteratorGen [f_, nextFunc_]: = Biên dịch [{{n, _Integer}}, Module [{this = Range [n]}, [this =! = {-1}, f [điều này]; this = nextFunc [n, this]];], RuntimeOptions -> "Speed", CompilationTarget -> "C", CompilationOptions -> {"InlineCompiledFunctions" -> True, "InlineExternalDefinitions" -> True}] ', contd .. –

+0

Tiếp tục .. Sau đó, giả sử rằng hàm * giả * của bạn có thể là 'Biên dịch', bạn nhận được một thứ tự tăng cường độ lớn khác:' fn = PermutationIteratorGen [# &, cfNextPartition ["C"]]; fn [9] // Thời gian '. Thủ thuật trên cho phép các biến của hàm Compiled kèm theo sống trong mã được biên dịch và được sửa đổi bởi hàm được biên dịch bởi người gọi, vì cuối cùng chúng ta thực hiện nội tuyến và chỉ nhận được một hàm biên dịch lớn. . Nhưng sử dụng 'Sow' hoặc chức năng không thể giải mã khác sẽ làm giảm đáng kể hiệu suất, do đó hầu như không có sự khác biệt giữa C và MVM. –

+0

@Leonid Có điều này là một điểm tốt, và iterator cũng có thể được tùy chỉnh bằng văn bản để thực hiện một số hoạt động định trước, do đó forgoing đi qua các chức năng hoàn toàn. Những gì tôi có nghĩa là không phải tốc độ C là nó là xa 130 triệu hoán vị được tạo ra cho mỗi trích dẫn thứ hai được thực hiện trong fxtbook. 'fn [11]' mất 9,86 giây trên máy tính của tôi lên đến 4 triệu hoán vị mỗi giây. Một cái nhìn tại 'CompilePrint [fn]' là hướng dẫn và sẽ cho biết tại sao điều đó lại xảy ra. – Sasha

2

Bạn có thể có nghĩa là câu hỏi được tổng quát hơn nhưng ví dụ về iterating trên permutatio ns như được đưa ra trên trang mà bạn liên kết đến xảy ra cho được tích hợp sẵn trong Mathematica:

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

Các Print có thể được thay thế bằng bất kỳ chức năng.

+2

Vâng, những gì tôi có nghĩa là bởi một máy phát điện là điều này giống như sau, mà làm việc trong O (n) bộ nhớ, nơi bạn cần O (n!). gen [f_, n_]: = Mô-đun [{id = -1, val = Bảng [Null, {n}], truy cập}, truy cập [k_]: = Mô-đun [{t}, id ++; Nếu [k!= 0, val [[k]] = id]; Nếu [id == n, f [val]]; Thực hiện [Nếu [val [[t]] == Null, truy cập [t]], {t, 1, n}]; id--; val [[k]] = Null;]; truy cập [0]; ] Bạn chạy nó như thế này: gen [In, 3] – nes1983

Các vấn đề liên quan