Implementieren Sie eine API für Wahrscheinlichkeitsverteilungen

9

Einführung

Bei dieser Herausforderung besteht Ihre Aufgabe darin, eine Sammlung einfacher Funktionen zu implementieren, die zusammen eine verwendbare Minibibliothek für einfache Wahrscheinlichkeitsverteilungen bilden. Die folgenden Implementierungen sind akzeptabel, um einige der esoterischeren Sprachen aufzunehmen, die hier gerne verwendet werden:

  1. Ein Codefragment, das eine Sammlung benannter Funktionen (oder nächstgelegener Entsprechungen) definiert.
  2. Eine Sammlung von Ausdrücken, die benannte oder anonyme Funktionen (oder nächstgelegene Entsprechungen) ergeben.
  3. Ein einzelner Ausdruck, der mehrere benannte oder anonyme Funktionen (oder nächstgelegene Entsprechungen) ergibt.
  4. Eine Sammlung unabhängiger Programme, die Eingaben von der Befehlszeile STDIN oder dem nächstgelegenen Äquivalent und die Ausgabe an STDOUT oder das nächstgelegene Äquivalent übernehmen.

Die Funktionen

Sie müssen die folgenden Funktionen implementieren und bei Bedarf kürzere Namen verwenden.

  1. uniformNimmt als Eingabe zwei Gleitkommazahlen aund bund gibt die Gleichverteilung auf zurück [a,b]. Sie können davon ausgehen a < b; Der Fall a ≥ bist undefiniert.
  2. blendnimmt als Eingaben drei Wahrscheinlichkeitsverteilungen P, Qund R. Sie gibt eine Wahrscheinlichkeitsverteilung S, die Werte zieht x, yund zaus P, Qund R, bzw., und Ausbeuten , ywenn x ≥ 0, und zwenn x < 0.
  3. overNimmt als Eingabe eine Gleitkommazahl fund eine Wahrscheinlichkeitsverteilung Pund gibt die Wahrscheinlichkeit zurück, x ≥ fdie für eine Zufallszahl gilt x, aus der gezogen wird P.

Als Referenz overkann wie folgt definiert werden (im Pseudocode):

over(f, uniform(a, b)):
    if f <= a: return 1.0
    else if f >= b: return 0.0
    else: return (b - f)/(b - a)

over(f, blend(P, Q, R)):
    p = over(0.0, P)
    return p*over(f, Q) + (1-p)*over(f, R)

Sie können davon ausgehen, dass alle angegebenen Wahrscheinlichkeitsverteilungen overmit uniformund erstellt blendwerden und dass das einzige, was ein Benutzer mit einer Wahrscheinlichkeitsverteilung tun wird, darin besteht, sie an blendoder weiterzuleiten over. Sie können einen beliebigen Datentyp verwenden, um die Verteilungen darzustellen: Listen mit Zahlen, Zeichenfolgen, benutzerdefinierten Objekten usw. Das einzig Wichtige ist, dass die API ordnungsgemäß funktioniert. Auch Ihre Implementierung muss deterministisch sein, im Sinne der immer die gleiche Leistung für die gleichen Eingaben zurück.

Testfälle

Ihre Ausgabewerte sollten in diesen Testfällen mindestens zwei Stellen nach dem Dezimalpunkt korrekt sein.

over(4.356, uniform(-4.873, 2.441)) -> 0.0
over(2.226, uniform(-1.922, 2.664)) -> 0.09550806803314438
over(-4.353, uniform(-7.929, -0.823)) -> 0.49676329862088375
over(-2.491, uniform(-0.340, 6.453)) -> 1.0
over(0.738, blend(uniform(-5.233, 3.384), uniform(2.767, 8.329), uniform(-2.769, 6.497))) -> 0.7701533851999125
over(-3.577, blend(uniform(-3.159, 0.070), blend(blend(uniform(-4.996, 4.851), uniform(-7.516, 1.455), uniform(-0.931, 7.292)), blend(uniform(-5.437, -0.738), uniform(-8.272, -2.316), uniform(-3.225, 1.201)), uniform(3.097, 6.792)), uniform(-8.215, 0.817))) -> 0.4976245638164541
over(3.243, blend(blend(uniform(-4.909, 2.003), uniform(-4.158, 4.622), blend(uniform(0.572, 5.874), uniform(-0.573, 4.716), blend(uniform(-5.279, 3.702), uniform(-6.564, 1.373), uniform(-6.585, 2.802)))), uniform(-3.148, 2.015), blend(uniform(-6.235, -5.629), uniform(-4.647, -1.056), uniform(-0.384, 2.050)))) -> 0.0
over(-3.020, blend(blend(uniform(-0.080, 6.148), blend(uniform(1.691, 6.439), uniform(-7.086, 2.158), uniform(3.423, 6.773)), uniform(-1.780, 2.381)), blend(uniform(-1.754, 1.943), uniform(-0.046, 6.327), blend(uniform(-6.667, 2.543), uniform(0.656, 7.903), blend(uniform(-8.673, 3.639), uniform(-7.606, 1.435), uniform(-5.138, -2.409)))), uniform(-8.008, -0.317))) -> 0.4487803553043079
Zgarb
quelle
2
Können wir integrierte Funktionen verwenden, um sie zu erstellen?
Mutador
@ AndréMuta Ich habe vergessen, dass Mathematica wahrscheinlich Einbauten für all das hat ... aber ich werde es ihnen erlauben, solange sie den Regeln folgen.
Zgarb
Was ist Ihr Vorschlag zur Darstellung von Gleitkommadaten in BrainFuck?
Fehler
@flawr Für Sprachen ohne native Gleitkommazahlen können Sie eine beliebige bequeme Codierung für Gleitkommazahlen zwischen -10,0 und 10,0 (exklusiv) verwenden, die höchstens 0,001 Unterschiede zwischen aufeinanderfolgenden Werten aufweisen. Die Ausgabe sollte für die Testfälle auf 0,01 Differenz genau sein.
Zgarb

Antworten:

1

CJam, 58 Bytes

{[\]}:U;
{[@]}:B;
{_,2={~1$-@@-\/0e>1e<}{6Yb@f*\.{O})[_1@-].*:+}?}:O;

Dies sind Postfix-Operatoren, die auf dem Stack arbeiten: 2.0 1.0 3.0 U Ois over(2, uniform(1, 3)).

Punktzahl zählen

{[\]}ist die Funktion selbst, :U;weist sie dem Namen zu Uund öffnet sie. Im Wesentlichen ist dies nicht Teil der Funktion. Wenn ich also Regel 2 zähle, muss ich nur zählen {[\]}. Bist ähnlich definiert.

Allerdings Oist rekursiv, und wenn ich keinen Namen angeben, gibt es keine Möglichkeit Rekursion. Hier würde ich also gerne den :O;Teil zählen. Dann ist meine Punktzahl 5+5+48=58insgesamt Bytes.

Erläuterung

UEs werden zwei Argumente angezeigt und ein Paar in umgekehrter Reihenfolge erstellt : a b => [b a].

Bwirft drei Argumente auf und macht ein Dreifach in gedrehter Reihenfolge : a b c => [b c a].

ODie Struktur ist wie folgt:

{             }:O;   Define O as this function:
 _,2=        ?       If the argument list's length is 2:
     {~Γ}            Append the list to the stack and execute subprogram Γ.
         {~Δ}        Else, do the same, but execute subprogram Δ.

Unterprogramm Γ behandelt gleichmäßige Verteilungen:

Executed ops      Explanation   Stack contents
============      ===========   ==============
                  Initial       f; b; a
1$                Copy b        f; b; a; b
  -               Difference    f; b; (a-b)
   @@             Rotate x2     (a-b); f, b
     -            Difference    (a-b); (f-b)
      \/          Flip divide   (f-b)/(a-b)
        0e>       Clamp low     max(0, (f-b)/(a-b))
           1e<    Clamp high    min(1, max(0, (f-b)/(a-b)))

Das Unterprogramm Δ behandelt gemischte Verteilungen:

Executed ops              Explanation    Stack contents
============              ===========    ==============
                          Initial        f; [Q R P]
6Yb                       Push [1,1,0]   f; [Q R P]; [1 1 0]
   @                      Rotate         [Q R P]; [1 1 0]; f
    f*                    Multiply each  [Q R P]; [f f 0]
      \                   Swap           [f f 0]; [Q R P]
       .{O}               Pairwise O     [q r p]
           )              Uncons         [q r] p
            [_1@-]        [p, 1-p]       [q r] [p 1-p]
                  .*:+    Dot product    q*p+r*(1-p)
Lynn
quelle
2

Ruby, 103

u=b=->*a{a}
o=->f,d{d[2]?(p=o[0,d[0]])*o[f,d[1]]+(1-p)*o[f,d[2]]:(f<a=d[0])?1:(f>b=d[1])?0:(b-f)/(b-a)}

Definiert drei lambdas, u, b, und o. uund berstellen Sie einfach Arrays mit zwei Elementen bzw. drei Elementen. oEs wird davon ausgegangen, dass ein Array mit zwei Elementen eine gleichmäßige Verteilung und ein Array mit drei Elementen eine Mischung aus drei Verteilungen ist. Im letzteren Fall ruft es sich rekursiv auf.

Histokrat
quelle
2

MATLAB, 73

Zeit für eine kleine "funktionale Programmierung" in MATLAB. Dies sind 3 anonyme Funktionen. Uniform und Blend werden wie die Beispiele bezeichnet, sollten jedoch für overdie Argumente ausgetauscht werden. Ich brauche nicht wirklich eine overseit den ersten beiden Rückgabefunktionen, aber als Formalität fevalist eine Funktion, die eine Funktion aufrufen kann.

%uniform
@(a,b)@(x)(x<b)*min(1,(b-x)/(b-a))
%blend
@(P,Q,R)@(x)P(0)*(Q(x)-R(x))+R(x)
%over
@feval

Jetzt ist das Parsing- und Bewertungssystem von MATLAB, gelinde gesagt, ein wenig wackelig. Sie können eine Funktion, die von einer Funktion zurückgegeben wurde, nicht direkt aufrufen. Stattdessen muss man zuerst das Ergebnis in einer Variablen speichern. Das 4. Beispiel könnte wie folgt gemacht werden:

x=uniform(-5.233,3.384);y=uniform(2.767,8.329);z=uniform(-2.769,6.497);over(blend(x,y,z),0.738)

Es ist jedoch möglich, dies zu umgehen, indem Sie fevalalle Funktionen aufrufen. Wenn die folgenden Definitionen verwendet werden, können die Beispiele genau so ausgewertet werden, wie sie geschrieben wurden.

uniform=@(a,b)@(x)(x<b)*min(1,(b-x)/(b-a))
blend=@(P,Q,R)@(x)feval(P,0)*(feval(Q,x)-feval(R,x))+feval(R,x)
over=@(x,f)feval(f,x)
Feersum
quelle
Funktionen machen Funktionen ... wie pervers!
Luis Mendo
1

Mathematica, 129 116 Bytes

u=UniformDistribution@{##}&;b=If[x<0,z,y]~TransformedDistribution~{x\uF3D2#,y\uF3D2#2,z\uF3D2#3}&;o=Probability[x>=#,x\uF3D2#2]&

u, bUnd osind uniform, blendund overrespectively.Wrapper über die Standardfunktionen. Ersetzen Sie das \uF3D2s durch das 3-Byte-Zeichen. Kommt gerade zurück 0und 1für die Fälle 1, 4 und 7.

LegionMammal978
quelle
1

Python, 146 Bytes

u=lambda*a:a
b=u
x=lambda f,a,b:[int(f<=a),(b-f)/(b-a)][a<f<b]
y=lambda f,p,q,r:o(0,p)*o(f,q)+(1-o(0,p))*o(f,r)
o=lambda f,p:[x,y][len(p)-2](f,*p)

Gleiche Strategie wie die Ruby-Antwort des Histokraten, jedoch in Python. Rekursion ohne Z-Kombinator durchführen (was kostspielig wäre) xund yals Hilfsfunktionen definiert sind, die overfür Argumenttupel mit 2 bzw. 3 Längen ( uniformbzw. blendArgumente) ausgewertet werden .

Testfälle auf ideone

Mego
quelle
0

Matlab, 104 Bytes

Ich hoffe, dass dies weiterhin gültig ist, da dies nur für Distributionen mit Unterstützung in [-10,10] funktioniert. Dies ist die Voraussetzung für Sprachen ohne Gleitkomma-Unterstützung. Der Unterstützungsvektor und die Genauigkeit können einfach durch Ändern der entsprechenden Zahlen angepasst werden. u,o,bist für uniform,blend,over. Das PDF wird nur als diskreter Vektor dargestellt. Ich denke, dieser Ansatz kann leicht auf andere Sprachen übertragen werden.

D=1e-4;X=-10:D:10;
u=@(a,b)(1/(b-a))*(a<X&X<b);
o=@(x,d)sum(d.*(X>x))*D;
b=@(p,q,r)o(0,p).*q+(1-o(0,p)).*r;

Sie können sie testen, wenn Sie diese Funktionen zuerst definieren und dann einfach diesen Code einfügen:

[o(4.356, u(-4.873, 2.441)) , 0.0;
o(2.226, u(-1.922, 2.664)) , 0.09550806803314438;
o(-4.353, u(-7.929, -0.823)) , 0.49676329862088375;
o(-2.491, u(-0.340, 6.453)) , 1.0;
o(0.738, b(u(-5.233, 3.384), u(2.767, 8.329), u(-2.769, 6.497))) , 0.7701533851999125;
o(-3.577, b(u(-3.159, 0.070), b(b(u(-4.996, 4.851), u(-7.516, 1.455), u(-0.931, 7.292)), b(u(-5.437, -0.738), u(-8.272, -2.316), u(-3.225, 1.201)), u(3.097, 6.792)), u(-8.215, 0.817))) , 0.4976245638164541;
o(3.243, b(b(u(-4.909, 2.003), u(-4.158, 4.622), b(u(0.572, 5.874), u(-0.573, 4.716), b(u(-5.279, 3.702), u(-6.564, 1.373), u(-6.585, 2.802)))), u(-3.148, 2.015), b(u(-6.235, -5.629), u(-4.647, -1.056), u(-0.384, 2.050)))) , 0.0;
o(-3.020, b(b(u(-0.080, 6.148), b(u(1.691, 6.439), u(-7.086, 2.158), u(3.423, 6.773)), u(-1.780, 2.381)), b(u(-1.754, 1.943), u(-0.046, 6.327), b(u(-6.667, 2.543), u(0.656, 7.903), b(u(-8.673, 3.639), u(-7.606, 1.435), u(-5.138, -2.409)))), u(-8.008, -0.317))) , 0.4487803553043079]
fehlerhaft
quelle
Matlab hat FP-Unterstützung, daher denke ich, dass dies ungültig wäre.
LegionMammal978
Ich zögere, dies zuzulassen, da Matlab Gleitkommazahlen nativ unterstützt. Wenn Sie Xund Ddurch MIN_FLOATund MAX_FLOAT(oder wie auch immer Matlab sie nennt) ersetzen können, ist dies ein gültiger Ansatz.
Zgarb
Ja, Sie könnten realmax/ verwenden realmin, Sie könnten sogar einen Vektor erstellen , der durch alle Gleitkommazahlen geht, wenn Sie über genügend Speicher verfügen.
Fehler