Ein in der Künstlichen Intelligenz lange verfolgtes Ziel ist die natürlichsprachliche Kommunikation zwischen Mensch und Maschine. Bislang ist kein Computer-Programm bekannt, mit dem eine Kommunikation auf höherem Niveau durchgeführt werden könnte.
Gegeben sei eine Sequenz von n Symbolen vor, in der Symbol A mit der Zahl nA und Symbol B mit der Zahl nB und die Kombination AB mit der Zahl nAB auftritt. Die Wahrscheinlichkeit, dass dies zufällig passiert ist genau hypergeom(n, nA, nB, nAB).
public static double hypergeometricF(int n, int nA, int nB, int nAB) { double p = 0; for (int i = 0; i <= nAB; ++i) { p += hypergeometric(n, nA, nB, i); } return p; } public static double hypergeometric(int n, int nA, int nB, int nAB) { return binomial(nA, nAB) * binomial(n - nA, nB - nAB) / (double)binomial(n, nB); } public static long binomial(int n, int k) { return factorial(n) / (factorial(k) * factorial(n - k)); } public static long factorial(int n) { long z = 1; for (int i = 2; i <= n; ++i) z *= i; return z; }
Die hier gezeigte Implementierung der hypergeometrischen Verteilungsfunktion haben wir nicht besonders optimiert, dafür ist der Algorithmus mathematisch sehr leicht durchschaubar. In der Praxis nutzen wir diese Implementierung sowieso nicht, da die Approximierung durch die Gauß-Verteilung in konstanter Komplexität berechnet werden kann und nicht den Integer-Einschränkungen im Wertebereich unterliegt:
public static double normalF(int n, int nA, int nB, int nAB) { double pA = (double)nA / n; double mu = nB * pA; double c = (n - nB) / (double)(n - 1); double sigma = Math.sqrt(mu * (1 - pA) * c); return normalF(mu, sigma, nAB + 0.5 /* avg */); } public static double normalF(double mu, double sigma, double x) { return normalF((x - mu) / sigma); } public static double normalF(double x) { double t = 1.0 / (1.0 + 0.33267 * Math.abs(x)); double u = t * (0.3480242 + t * (-0.0958798 + t * 0.7478556)); double z = 0.5 * u * Math.exp(-0.5 * x * x); return x < 0 ? z : 1 - z; }
Ein Vergleich der hypergeometrischen Werte mit der Gauß-Approximation bringt folgendes Ergebnis:
p(14, 6, 7, 0) = 0.002331002331002331 ~ 0.004642135984499961 p(14, 6, 7, 1) = 0.05128205128205128 ~ 0.059229045502362444 p(14, 6, 7, 2) = 0.29603729603729606 ~ 0.30139821320402993 p(14, 6, 7, 3) = 0.703962703962704 ~ 0.6986017867959701 p(14, 6, 7, 4) = 0.9487179487179488 ~ 0.9407709544976376 p(14, 6, 7, 5) = 0.9976689976689977 ~ 0.9953578640155001 p(14, 6, 7, 6) = 1.0 ~ 0.999864197750926 p(15, 6, 3, 0) = 0.18461538461538463 ~ 0.1864473739109894 p(15, 6, 3, 1) = 0.6593406593406593 ~ 0.6487176975729911 p(15, 6, 3, 2) = 0.956043956043956 ~ 0.9510197540962199 p(15, 6, 3, 3) = 0.9999999999999999 ~ 0.9982871868198867
Das Ergebnis ist für die Praxis zunächst völlig ausreichend. Die eigentliche Herausforderung liegt nicht in der Präzision der Berechnung, sondern in der strukturellen Vorgehensweise bei der Aufstellung des semantischen Gebildes.