Zaimplementuj interfejs API dla rozkładów prawdopodobieństwa

9

Wprowadzenie

W tym wyzwaniu Twoim zadaniem jest zaimplementowanie zbioru prostych funkcji, które razem tworzą użyteczną minibibliotekę dla prostych rozkładów prawdopodobieństwa. Aby dostosować się do niektórych bardziej ezoterycznych języków, których ludzie lubią tutaj używać, dopuszczalne są następujące implementacje:

  1. Fragment kodu definiujący zbiór nazwanych funkcji (lub najbliższych odpowiedników).
  2. Zbiór wyrażeń, które oceniają na nazwane lub anonimowe funkcje (lub najbliższe odpowiedniki).
  3. Pojedyncze wyrażenie, które ocenia do kilku nazwanych lub anonimowych funkcji (lub najbliższych odpowiedników).
  4. Zbiór niezależnych programów, które pobierają dane wejściowe z wiersza poleceń, STDIN lub najbliższego odpowiednika i wysyłają dane do STDOUT lub najbliższego odpowiednika.

Funkcje

Wdrożysz następujące funkcje, w razie potrzeby używając krótszych nazw.

  1. uniformprzyjmuje jako wejście dwóch liczb zmiennoprzecinkowych ai b, i zwraca rozkład jednolity na [a,b]. Możesz założyć, że a < b; sprawa a ≥ bjest niezdefiniowana.
  2. blendprzyjmuje jako dane wejściowe trzy rozkłady prawdopodobieństwa P, Qoraz R. Zwraca rozkład prawdopodobieństwa S, który opiera się wartość x, yi zz P, Qi R, odpowiednio, ulega y, gdy x ≥ 0i zjeżeli x < 0.
  3. overprzyjmuje jako dane wejściowe liczbę zmiennoprzecinkową fi rozkład prawdopodobieństwa Pi zwraca prawdopodobieństwo, które obowiązuje x ≥ fdla losowej liczby xwyciągniętej z P.

W celach informacyjnych overmożna zdefiniować w następujący sposób (w pseudokodzie):

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)

Możesz założyć, że wszystkie podane rozkłady prawdopodobieństwa oversą konstruowane przy użyciu uniformi blend, i że jedyną rzeczą, którą użytkownik zrobi z rozkładem prawdopodobieństwa, jest karmienie go do blendlub over. Możesz użyć dowolnego wygodnego typu danych do przedstawienia dystrybucji: list liczb, ciągów znaków, obiektów niestandardowych itp. Jedyną ważną rzeczą jest to, że interfejs API działa poprawnie. Ponadto twoja implementacja musi być deterministyczna w tym sensie, że zawsze zwraca ten sam wynik dla tych samych danych wejściowych.

Przypadki testowe

Twoje wartości wyjściowe powinny być poprawne do co najmniej dwóch cyfr po przecinku w tych przypadkach testowych.

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
źródło
2
Czy możemy korzystać z wbudowanych funkcji, aby je tworzyć?
Mutador
@ AndréMuta Zapomniałem, że Mathematica prawdopodobnie ma wbudowane w to wszystko ... ale pozwolę im, o ile będą przestrzegać zasad.
Zgarb
Jaka jest twoja sugestia, jak reprezentować dane zmiennoprzecinkowe w BrainFuck?
flawr
@flawr W przypadku języków, które nie mają natywnych liczb zmiennoprzecinkowych, można użyć dowolnego wygodnego kodowania dla liczb zmiennoprzecinkowych od -10,0 do 10,0 (wyłącznie), które mają najwyżej 0,001 różnicy między kolejnymi wartościami. Dane wyjściowe powinny być dokładne z dokładnością do 0,01 dla przypadków testowych.
Zgarb

Odpowiedzi:

1

CJam, 58 bajtów

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

Są to operatory Postfix, które działają na stosie: 2.0 1.0 3.0 U Ois over(2, uniform(1, 3)).

Liczba punktów

{[\]}jest samą funkcją, :U;przypisuje ją do nazwy Ui wyskakuje. Zasadniczo nie jest to częścią funkcji, więc zgodnie z zasadą liczenia punktów 2 musiałbym tylko liczyć {[\]}. Bjest zdefiniowany podobnie.

Jest jednak Orekurencyjne, a jeśli nie podam nazwy, nie ma możliwości ponownego wystąpienia. Więc tutaj chciałbym policzyć tę :O;część. Zatem mój wynik to 5+5+48=58w sumie bajty.

Wyjaśnienie

Upojawia dwa argumenty i sprawia, że pary w odwrotnej kolejności: a b => [b a].

Bwyskakuje trzy argumenty i sprawia, że potrójna w obróconym kolejności: a b c => [b c a].

OStruktura jest następująca:

{             }: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 Δ.

Podprogram Γ obsługuje jednolite rozkłady:

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)))

Podprogram Δ obsługuje mieszane rozkłady:

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
źródło
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)}

Definiuje trzy lambdas, u, b, i o. ui bpo prostu utwórz odpowiednio dwu- i trzyelementowe tablice. ozakłada, że ​​tablica dwuelementowa jest rozkładem jednolitym, a trzyelementowa jest mieszanką trzech rozkładów. W tym drugim przypadku nazywa się rekurencyjnie.

histocrat
źródło
2

MATLAB, 73

Czas na trochę „programowania funkcjonalnego” w MATLAB. Są to 3 anonimowe funkcje. Jednolite i mieszane są nazywane tak samo jak w przykładach, ale overargumenty powinny zostać zamienione. Tak naprawdę nie potrzebuję, overodkąd dwie pierwsze funkcje zwracają, ale jako formalność fevaljest funkcją, która może wywoływać funkcję.

%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

Teraz system parsowania i oceny MATLAB jest co najmniej trochę chwiejny. Nie pozwala na bezpośrednie wywołanie funkcji, która została zwrócona z funkcji. Zamiast tego należy najpierw zapisać wynik w zmiennej. Czwarty przykład można wykonać w następujący sposób:

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)

Można jednak obejść ten problem, fevalwywołując wszystkie funkcje. Jeśli zastosowane zostaną następujące definicje, przykłady można ocenić dokładnie tak, jak zostały zapisane.

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
źródło
Funkcje tworzące funkcje ... jak przewrotne!
Luis Mendo
1

Mathematica, 129 116 bajtów

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

u, bI oto uniform, blendi overrespectively.Wrapper nad standardowymi funkcjami. Zamień \uF3D2s na znak 3-bajtowy. Po prostu wraca 0i 1dla przypadków 1, 4 i 7.

LegionMammal978
źródło
1

Python, 146 bajtów

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)

Ta sama strategia, co odpowiedź Ruby u histokraty, ale w Pythonie. Wykonanie rekurencji bez kombinatora Z (co byłoby kosztowne) xi ysą zdefiniowane jako funkcje pomocnicze, które oceniają overkrotki argumentów o długości 2 i 3 ( uniformi blendargumenty odpowiednio).

Testuj przypadki na ideone

Mego
źródło
0

Matlab, 104 bajty

Mam nadzieję, że jest to nadal aktualne, ponieważ działa to tylko w przypadku dystrybucji z obsługą w [-10,10], co jest wymagane dla języków, które nie mają obsługi zmiennoprzecinkowej. Wektor podparcia i dokładność można łatwo regulować, po prostu zmieniając odpowiednie liczby. u,o,bjest dla uniform,blend,over. Plik pdf jest po prostu reprezentowany jako dyskretny wektor. Myślę, że to podejście można łatwo przenieść na inne języki.

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;

Możesz je przetestować, jeśli najpierw zdefiniujesz te funkcje, a następnie wkleisz ten kod:

[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]
wada
źródło
Matlab ma wsparcie FP, więc myślę, że byłoby to nieprawidłowe.
LegionMammal978
Waham się na to pozwolić, ponieważ Matlab obsługuje natywnie liczby zmiennoprzecinkowe. Jeśli możesz zastąpić Xi Dprzy pomocy MIN_FLOATi MAX_FLOAT(lub jakkolwiek to nazywa Matlab), jest to prawidłowe podejście.
Zgarb
Tak, możesz ouse realmax/ realmin, możesz nawet stworzyć wektor przechodzący przez liczbę zmiennoprzecinkową, jeśli masz wystarczającą ilość pamięci.
flawr