2012-06-27 10 views
86

In meiner letzten work mit Gibbs sampling habe ich die RVar, die aus meiner Sicht eine nahezu ideale Schnittstelle zur Generierung von Zufallszahlen bietet. Leider konnte ich Repa aufgrund der Unfähigkeit, monadische Aktionen in Karten zu verwenden, nicht nutzen.Parallele mapM auf Repa-Arrays

Während eindeutig monadische Karten im Allgemeinen nicht parallelisiert werden können, scheint mir, dass RVar mindestens ein Beispiel für eine Monade sein kann, in der Effekte sicher parallelisiert werden können (zumindest im Prinzip; ich bin nicht besonders vertraut mit das Innenleben von RVar). Und zwar möchte ich etwas wie die folgenden schreiben,

drawClass :: Sample -> RVar Class 
drawClass = ... 

drawClasses :: Array U DIM1 Sample -> RVar (Array U DIM1 Class) 
drawClasses samples = A.mapM drawClass samples 

wo A.mapM etwas aussehen würde,

mapM :: ParallelMonad m => (a -> m b) -> Array r sh a -> m (Array r sh b) 

Während klar, wie dies funktionieren würde entscheidend von der Umsetzung der RVar und die ihr zugrunde liegenden RandomSource abhängt, im Prinzip würde man denken, dass dies das Zeichnen eines neuen zufälligen Samens für jeden Thread beinhalten würde, der wie gewohnt erzeugt wird.

Intuitiv scheint es, dass diese Idee auf einige andere Monaden verallgemeinern könnte.

Also meine Frage ist: Könnte man eine Klasse ParallelMonad von Monaden konstruieren, für die Effekte sicher parallelisiert werden können (vermutlich von mindestens RVar bewohnt)?

Wie könnte es aussehen? Welche anderen Monaden könnten diese Klasse bewohnen? Haben andere die Möglichkeit in Betracht gezogen, wie dies in Repa funktionieren könnte?

Schließlich, wenn dieser Begriff der parallelen monadischen Aktionen nicht verallgemeinert werden kann, sieht jemand einen schönen Weg, um dies im speziellen Fall von RVar (wo es sehr nützlich wäre) zu arbeiten? Aufgeben von RVar für die Parallelität ist ein sehr schwieriger Kompromiss.

+1

Ich denke, der Knackpunkt ist "Zeichnen eines neuen Zufallssaat für jeden erzeugten Thread" - wie sollte dieser Schritt funktionieren, und wie sollten die Seeds wieder zusammengeführt werden, sobald alle Threads zurückkehren? –

+1

Die RVar-Schnittstelle würde mit ziemlicher Sicherheit einige Ergänzungen benötigen, um einen neuen Generator mit einem bestimmten Seed hervorzubringen. Zugegeben, es ist unklar, wie die Mechanik dieser Arbeit aussieht und es scheint ganz "RandomSource" spezifisch zu sein. Mein naive Versuch, einen Samen zu zeichnen, wäre, etwas Einfaches und wahrscheinlich sehr Falsches zu tun, wie einen Vektor von Elementen zu zeichnen (im Falle von "mwc-random") und jedem Element 1 hinzuzufügen, um einen Samen für den ersten Arbeiter zu erzeugen. fügen Sie 2 für den zweiten Arbeiter usw. hinzu. Völlig inadäquat, wenn Sie Entropie in kryptographischer Qualität benötigen; Hoffentlich in Ordnung, wenn Sie nur einen zufälligen Spaziergang brauchen. – bgamari

+0

Ich konnte etwas tun, was Sie mit 'fillChunkedIOP' ähnlich machen. – kosmikus

Antwort

4

Es ist wahrscheinlich keine gute Idee, dies aufgrund der inhärent sequentiellen Natur von PRNGs zu tun. Stattdessen sollten Sie Ihren Code zu übergehen, wie folgt:

  1. Deklarieren Sie eine IO-Funktion (main, oder was Sie haben).
  2. Lesen Sie so viele Zufallszahlen, wie Sie benötigen.
  3. Übergeben Sie die (jetzt reinen) Zahlen an Ihre Repa-Funktionen.
+0

Ist es möglich, jeden PRNG in jedem parallelen Thread zu brennen, um statistische Unabhängigkeit zu schaffen? –