Implémenter une API pour les distributions de probabilités

9

introduction

Dans ce défi, votre tâche consiste à implémenter une collection de fonctions simples qui forment ensemble une mini-bibliothèque utilisable pour des distributions de probabilités simples. Pour prendre en charge certains des langages les plus ésotériques que les gens aiment utiliser ici, les implémentations suivantes sont acceptables:

  1. Un extrait de code définissant une collection de fonctions nommées (ou équivalents les plus proches).
  2. Collection d'expressions évaluant des fonctions nommées ou anonymes (ou leurs équivalents les plus proches).
  3. Expression unique qui évalue plusieurs fonctions nommées ou anonymes (ou équivalents les plus proches).
  4. Une collection de programmes indépendants qui prennent les entrées de la ligne de commande, STDIN ou l'équivalent le plus proche, et la sortie vers STDOUT ou l'équivalent le plus proche.

Les fonctions

Vous devez implémenter les fonctions suivantes, en utilisant des noms plus courts si vous le souhaitez.

  1. uniformprend en entrée deux nombres à virgule flottante aet b, et renvoie la distribution uniforme [a,b]. Vous pouvez supposer cela a < b; l'affaire a ≥ bn'est pas définie.
  2. blendprend en entrée trois distributions de probabilité P, Qet R. Il renvoie une distribution de probabilité S, qui tire des valeurs x, yet zde P, Qet R, respectivement, et produit ysi x ≥ 0, et zsi x < 0.
  3. overprend en entrée un nombre à virgule flottante fet une distribution de probabilité P, et retourne la probabilité qui x ≥ fvaut pour un nombre aléatoire xtiré de P.

Pour référence, overpeut être défini comme suit (en 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)

Vous pouvez supposer que toutes les distributions de probabilité données à oversont construites à l'aide de uniformet blend, et que la seule chose qu'un utilisateur va faire avec une distribution de probabilité est de l'alimenter en blendou over. Vous pouvez utiliser n'importe quel type de données pratique pour représenter les distributions: listes de nombres, chaînes, objets personnalisés, etc. La seule chose importante est que l'API fonctionne correctement. De plus, votre implémentation doit être déterministe, dans le sens de toujours renvoyer la même sortie pour les mêmes entrées.

Cas de test

Vos valeurs de sortie doivent être correctes à au moins deux chiffres après la virgule décimale sur ces cas de test.

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
la source
2
Pouvons-nous utiliser des fonctions intégrées pour les créer?
Mutador
@ AndréMuta J'ai oublié que Mathematica a probablement des modules intégrés pour tout cela ... mais je vais leur permettre, tant qu'ils respectent les règles.
Zgarb
Quelle est votre suggestion sur la façon de représenter les données à virgule flottante dans BrainFuck?
flawr
@flawr Pour les langues qui n'ont pas de nombres à virgule flottante natifs, vous pouvez utiliser n'importe quel encodage pratique pour les flottants entre -10,0 et 10,0 (exclusif) qui a au plus 0,001 différence entre les valeurs consécutives. La sortie doit être précise à une différence près de 0,01 pour les cas de test.
Zgarb

Réponses:

1

CJam, 58 octets

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

Ce sont des opérateurs postfix qui travaillent sur la pile: 2.0 1.0 3.0 U Ois over(2, uniform(1, 3)).

Nombre de points

{[\]}est la fonction elle-même, l' :U;affecte au nom Uet l'affiche. Essentiellement, cela ne fait pas partie de la fonction, donc en comptant la règle de comptage 2, je n'aurais qu'à compter {[\]}. Best défini de manière similaire.

Cependant, Oest récursif, et si je ne spécifie pas de nom, il n'y a aucun moyen de recurse. Alors là, je serais enclin à compter la :O;pièce. Ensuite, mon score est en 5+5+48=58octets au total.

Explication

Usaute deux arguments et fait une paire dans l' ordre inverse: a b => [b a].

Bsaute trois arguments et fait une triple rotation afin: a b c => [b c a].

OLa structure de est la suivante:

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

Le sous-programme Γ gère des distributions uniformes:

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

Le sous-programme Δ gère les distributions mixtes:

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
la source
2

Rubis, 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)}

Définit trois lambdas, u, bet o. uet il bsuffit de créer des tableaux à deux et trois éléments respectivement. osuppose qu'un tableau à deux éléments est une distribution uniforme et un tableau à trois éléments est un mélange de trois distributions. Dans ce dernier cas, il s'appelle récursivement.

histocrate
la source
2

MATLAB, 73

Temps pour une petite "programmation fonctionnelle" dans MATLAB. Ce sont 3 fonctions anonymes. Uniform et blend sont appelés de la même manière que les exemples, mais overles arguments doivent être échangés. Je n'ai pas vraiment besoin d'un overdepuis les deux premières fonctions de retour, mais comme une formalité fevalest une fonction qui peut appeler une fonction.

%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

Maintenant, le système d'analyse et d'évaluation de MATLAB est pour le moins un peu bancal. Il ne vous permet pas d'appeler directement une fonction renvoyée par une fonction. Au lieu de cela, il faut d'abord enregistrer le résultat dans une variable. Le 4ème exemple pourrait se faire comme suit:

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)

Cependant, il est possible de contourner ce problème en utilisant fevalpour appeler toutes les fonctions. Si les définitions suivantes sont utilisées, les exemples peuvent être évalués exactement tels qu'ils sont écrits.

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
la source
Des fonctions qui font des fonctions ... comme c'est pervers!
Luis Mendo
1

Mathematica, 129 116 octets

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

u, b Et osont uniform, blendet overrespectively.Wrapper les fonctions standard. Remplacez le \uF3D2s par le caractère à 3 octets. Renvoie simplement 0et 1pour les cas 1, 4 et 7.

LegionMammal978
la source
1

Python, 146 octets

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)

Même stratégie que la réponse Ruby de l'histocrate, mais en Python. Faire une récursivité sans Z-combinateur (ce qui serait coûteux), xety sont définis comme des fonctions d'assistance qui évaluent les overtuples d'argument de 2 et 3 longueurs ( uniformet les blendarguments, respectivement).

Cas de test sur ideone

Mego
la source
0

Matlab, 104 octets

J'espère que cela est toujours valable, car cela ne fonctionne que pour les distributions avec prise en charge dans [-10,10] qui est l'exigence pour les langues qui ne prennent pas en charge la virgule flottante. Le vecteur de support et la précision peuvent être facilement ajustés en modifiant simplement les nombres correspondants. u,o,best pour uniform,blend,over. Le pdf est simplement représenté comme un vecteur discret. Je pense que cette approche peut facilement être transférée dans d'autres langues.

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;

Vous pouvez les tester si vous définissez d'abord ces fonctions, puis collez simplement ce code:

[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]
flawr
la source
Matlab a un support FP, donc je pense que ce serait invalide.
LegionMammal978
J'hésite à le permettre, car Matlab prend en charge les nombres à virgule flottante en natif. Si vous pouvez remplacer Xet Dpar MIN_FLOATet MAX_FLOAT(ou quel que soit l'appeler Matlab), alors c'est une approche valide.
Zgarb
Oui, vous pourriez supprimer realmax/ realmin, vous pourriez même créer un vecteur qui va à travers tous les nombres à virgule flottante si vous avez suffisamment de mémoire.
flawr