Terapkan API untuk distribusi probabilitas

9

pengantar

Dalam tantangan ini, tugas Anda adalah mengimplementasikan kumpulan fungsi sederhana yang bersama-sama membentuk perpustakaan mini yang dapat digunakan untuk distribusi probabilitas sederhana. Untuk mengakomodasi beberapa bahasa yang lebih esoteris yang orang suka gunakan di sini, implementasi berikut dapat diterima:

  1. Cuplikan kode yang mendefinisikan kumpulan fungsi bernama (atau setara terdekat).
  2. Kumpulan ekspresi yang mengevaluasi fungsi bernama atau anonim (atau setara terdekat).
  3. Ekspresi tunggal yang mengevaluasi beberapa fungsi yang disebut atau anonim (atau setara terdekat).
  4. Kumpulan program independen yang mengambil input dari baris perintah, STDIN atau setara terdekat, dan output ke STDOUT atau setara terdekat.

Fungsinya

Anda harus menerapkan fungsi-fungsi berikut, menggunakan nama yang lebih pendek jika diinginkan.

  1. uniformmengambil input dua nomor floating point adan b, dan mengembalikan distribusi seragam aktif [a,b]. Anda dapat mengasumsikan itu a < b; case a ≥ btidak terdefinisi.
  2. blendmengambil input tiga distribusi probabilitas P, Qdan R. Ini mengembalikan distribusi probabilitas S, yang menarik nilai x, ydan zdari P, Qdan R, masing-masing, dan menghasilkan yjika x ≥ 0, dan zjika x < 0.
  3. overmengambil sebagai input angka floating point fdan distribusi probabilitas P, dan mengembalikan probabilitas yang x ≥ fberlaku untuk nomor acak yang xdiambil P.

Untuk referensi, overdapat didefinisikan sebagai berikut (dalam 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)

Anda dapat mengasumsikan bahwa semua distribusi probabilitas yang diberikan overdibangun menggunakan uniformdan blend, dan bahwa satu-satunya hal yang akan dilakukan pengguna dengan distribusi probabilitas adalah memberi makan kepada blendatau over. Anda dapat menggunakan tipe data yang mudah untuk mewakili distribusi: daftar angka, string, objek khusus, dll. Satu-satunya hal yang penting adalah API bekerja dengan benar. Juga, implementasi Anda harus deterministik, dalam arti selalu mengembalikan output yang sama untuk input yang sama.

Uji kasus

Nilai output Anda harus benar setidaknya dua digit setelah titik desimal pada kasus uji ini.

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
sumber
2
Bisakah kita menggunakan fungsi bawaan untuk membuatnya?
Mutador
@ AndréMuta Saya lupa bahwa Mathematica mungkin memiliki built-in untuk semua ini ... tapi saya akan mengizinkannya, selama mereka mengikuti aturan.
Zgarb
Apa saran Anda tentang cara merepresentasikan data titik apung di BrainFuck?
flawr
@ flawr Untuk bahasa yang tidak memiliki angka floating point asli, Anda dapat menggunakan pengkodean apa pun yang nyaman untuk float antara -10.0 dan 10.0 (eksklusif) yang memiliki paling banyak selisih 0,001 antara nilai berturut-turut. Output harus akurat hingga selisih 0,01 untuk kasus uji.
Zgarb

Jawaban:

1

CJam, 58 byte

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

Ini adalah operator postfix yang bekerja pada stack: 2.0 1.0 3.0 U Ois over(2, uniform(1, 3)).

Jumlah skor

{[\]}adalah fungsi itu sendiri, :U;menugaskannya ke nama Udan muncul. Pada dasarnya ini bukan bagian dari fungsi, jadi dengan aturan penghitungan skor 2, saya hanya perlu menghitung {[\]}. Bdidefinisikan dengan cara yang sama.

Namun, Obersifat rekursif, dan jika saya tidak menentukan nama, tidak ada cara untuk mengulang. Jadi di sini, saya cenderung menghitung :O;bagian. Maka skor saya adalah 5+5+48=58total byte.

Penjelasan

Umuncul dua argumen dan membuat sepasang dalam urutan terbalik: a b => [b a].

Bmuncul tiga argumen dan membuat triple agar diputar: a b c => [b c a].

OStrukturnya adalah sebagai berikut:

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

Subprogram Γ menangani distribusi seragam:

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

Subprogram Δ menangani distribusi campuran:

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

Mendefinisikan tiga lambdas, u, b, dan o. udan masing-masing bhanya membuat array dua elemen dan tiga elemen. omengasumsikan array dua elemen adalah distribusi yang seragam dan satu elemen tiga adalah campuran dari tiga distribusi. Dalam kasus terakhir ini menyebut dirinya secara rekursif.

histokrat
sumber
2

MATLAB, 73

Saatnya untuk sedikit "pemrograman fungsional" di MATLAB. Ini adalah 3 fungsi anonim. Seragam dan campuran disebut dengan cara yang sama seperti contoh, tetapi untuk overargumen harus ditukar. Saya tidak benar-benar membutuhkan oversejak dua fungsi kembali yang pertama, tetapi sebagai formalitas fevaladalah fungsi yang dapat memanggil fungsi.

%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

Sekarang sistem parsing dan evaluasi MATLAB sedikit sulit untuk sedikitnya. Itu tidak memungkinkan Anda untuk langsung memanggil fungsi yang dikembalikan dari suatu fungsi. Sebagai gantinya, seseorang harus terlebih dahulu menyimpan hasilnya ke variabel. Contoh ke-4 dapat dilakukan sebagai berikut:

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)

Namun, dimungkinkan untuk menyiasatinya dengan menggunakan fevaluntuk memanggil semua fungsi. Jika definisi berikut digunakan, maka contoh-contohnya dapat dievaluasi persis seperti yang tertulis.

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
sumber
Fungsi membuat fungsi ... betapa buruknya!
Luis Mendo
1

Mathematica, 129 116 byte

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

u, bDan oyang uniform, blend, dan overrespectively.Wrapper alih fungsi standar. Ganti \uF3D2s dengan karakter 3-byte. Hanya mengembalikan 0dan 1untuk kasus 1, 4, dan 7.

LegionMammal978
sumber
1

Python, 146 byte

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)

Strategi yang sama dengan jawaban Ruby histokrat, tetapi dengan Python. Untuk melakukan rekursi tanpa Z-combinator (yang akan mahal), xdan ydidefinisikan sebagai fungsi pembantu yang mengevaluasi overuntuk tuple argumen 2 dan 3 panjang ( uniformdan blendargumen, masing-masing).

Uji kasus pada ideone

Mego
sumber
0

Matlab, 104 byte

Saya harap ini masih valid, karena ini hanya berfungsi untuk distribusi dengan dukungan di [-10,10] yang merupakan persyaratan untuk bahasa yang tidak memiliki dukungan floating point. Vektor dukungan dan akurasi dapat dengan mudah disesuaikan dengan hanya mengubah angka yang sesuai. u,o,badalah untuk uniform,blend,over. PDF hanya direpresentasikan sebagai vektor diskrit. Saya pikir pendekatan ini dapat dengan mudah ditransfer ke bahasa lain.

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;

Anda dapat mengujinya jika Anda mendefinisikan fungsi-fungsi itu terlebih dahulu dan kemudian tempelkan kode ini:

[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]
cacat
sumber
Matlab memiliki dukungan FP, jadi saya pikir ini tidak valid.
LegionMammal978
Saya ragu untuk mengizinkan ini, karena Matlab mendukung angka floating point secara asli. Jika Anda dapat mengganti Xdan Ddengan MIN_FLOATdan MAX_FLOAT(atau apa pun Matlab memanggil mereka), maka ini adalah pendekatan yang valid.
Zgarb
Ya, Anda bisa menggunakan realmax/ realmin, Anda bahkan bisa membuat vektor yang masuk ke semua nomor floating point jika Anda memiliki cukup memori.
flawr