]> git.sesse.net Git - foosball/commitdiff
Switch to more accurate double score calculation.
authorSteinar H. Gunderson <sesse@debian.org>
Thu, 11 Oct 2007 17:06:25 +0000 (19:06 +0200)
committerSteinar H. Gunderson <sesse@debian.org>
Thu, 11 Oct 2007 17:06:25 +0000 (19:06 +0200)
foosball.pm
foosrank.cpp
recalc-double-result.pl
www/add-double-result.pl
www/index.pl

index dc5ff223d4c70b82493dbd2a067b3f62d8b930e7..a2b0d55b041ab4d8f6084f523dc8d680a31c4ecc 100644 (file)
@@ -81,4 +81,16 @@ sub calc_rating {
        return ($newr1, $newrd1);
 }
 
+sub calc_rating_double {
+       my ($rating1, $rd1, $rating2, $rd2, $rating3, $rd3, $rating4, $rd4, $score1, $score2) = @_;
+       my $result = `/srv/foosball.sesse.net/foosrank $rating1 $rd1 $rating2 $rd2 $rating3 $rd3 $rating4 $rd4 $score1 $score2`;
+       chomp $result;
+       my ($newr1, $newrd1) = split / /, $result;
+
+       $newrd1 = 30.0 if ($newrd1 < 30.0);
+
+       return ($newr1, $newrd1);
+}
+
+
 1;
index fc968cd647b86baa5591205f6bd2b47d9507544c..6991061fae2973d063d9d879aef7abe70dcf3133 100644 (file)
@@ -6,8 +6,8 @@
 #include <algorithm>
 
 // step sizes
-static const double int_step_size = 50.0;
-static const double pdf_step_size = 10.0;
+static const double int_step_size = 75.0;
+static const double pdf_step_size = 15.0;
 
 // rating constant (see below)
 static const double rating_constant = 455.0;
@@ -128,7 +128,7 @@ double opponent_rating_pdf(int k, double a, double r1, double mu2, double sigma2
        double binomial_precompute = prodai(k, a) / fac(k-1);
        winfac /= rating_constant;
 
-       return simpson_integrate(ProbScoreEvaluator(k, a, binomial_precompute, r1, mu2, sigma2, winfac), 0.0, 3000.0, int_step_size);
+       return simpson_integrate(ProbScoreEvaluator(k, a, binomial_precompute, r1, mu2, sigma2, winfac), 0.0, 6000.0, int_step_size);
 }
 
 // normalize the curve so we know that A ~= 1
@@ -393,6 +393,50 @@ void compute_new_rating(double mu1, double sigma1, double mu2, double sigma2, in
        least_squares(curve, mu_est, sigma_est, mu, sigma);
 }
 
+// int(normpdf[mu2, sigma2](t2) * ..., t2=0..3000);
+class OuterIntegralEvaluator {
+private:
+       double theta1, mu2, sigma2, mu_t, sigma_t;
+       int score1, score2;
+       double winfac;
+
+public:
+       OuterIntegralEvaluator(double theta1, double mu2, double sigma2, double mu3, double sigma3, double mu4, double sigma4, int score1, int score2, double winfac)
+               : theta1(theta1), mu2(mu2), sigma2(sigma2), mu_t(mu3 + mu4), sigma_t(sqrt(sigma3*sigma3 + sigma4*sigma4)), score1(score1), score2(score2), winfac(winfac) {}
+
+       double operator() (double theta2) const
+       {
+               double z = (theta2 - mu2) / sigma2;
+               double gaussian = exp(-(z*z/2.0));
+               double r1 = theta1 + theta2;
+               return gaussian * opponent_rating_pdf(score1, score2, r1, mu_t, sigma_t, winfac);
+       }
+};
+
+void compute_new_double_rating(double mu1, double sigma1, double mu2, double sigma2, double mu3, double sigma3, double mu4, double sigma4, int score1, int score2, double &mu, double &sigma)
+{
+       vector<pair<double, double> > curve;
+
+       if (score1 > score2) {
+               for (double r1 = 0.0; r1 < 3000.0; r1 += pdf_step_size) {
+                       double z = (r1 - mu1) / sigma1;
+                       double gaussian = exp(-(z*z/2.0));
+                       curve.push_back(make_pair(r1, gaussian * simpson_integrate(OuterIntegralEvaluator(r1,mu2,sigma2,mu3,sigma3,mu4,sigma4,score1,score2,0.5), 0.0, 3000.0, int_step_size)));
+               }
+       } else {
+               for (double r1 = 0.0; r1 < 3000.0; r1 += pdf_step_size) {
+                       double z = (r1 - mu1) / sigma1;
+                       double gaussian = exp(-(z*z/2.0));
+                       curve.push_back(make_pair(r1, gaussian * simpson_integrate(OuterIntegralEvaluator(r1,mu2,sigma2,mu3,sigma3,mu4,sigma4,score2,score1,-0.5), 0.0, 3000.0, int_step_size)));
+               }
+       }
+
+       double mu_est, sigma_est;
+       normalize(curve);
+       estimate_musigma(curve, mu_est, sigma_est);
+       least_squares(curve, mu_est, sigma_est, mu, sigma);
+}
+
 int main(int argc, char **argv)
 {
        double mu1 = atof(argv[1]);
@@ -400,7 +444,17 @@ int main(int argc, char **argv)
        double mu2 = atof(argv[3]);
        double sigma2 = atof(argv[4]);
 
-       if (argc > 6) {
+       if (argc > 8) {
+               double mu3 = atof(argv[5]);
+               double sigma3 = atof(argv[6]);
+               double mu4 = atof(argv[7]);
+               double sigma4 = atof(argv[8]);
+               int score1 = atoi(argv[9]);
+               int score2 = atoi(argv[10]);
+               double mu, sigma;
+               compute_new_double_rating(mu1, sigma1, mu2, sigma2, mu3, sigma3, mu4, sigma4, score1, score2, mu, sigma);
+               printf("%f %f\n", mu, sigma);
+       } else if (argc > 6) {
                int score1 = atoi(argv[5]);
                int score2 = atoi(argv[6]);
                double mu, sigma;
index 2ccb6a7428430db97079ca1f25d96f7ba487292f..b606b5adc426374000bec16a75c16426d3d19280 100755 (executable)
@@ -47,21 +47,10 @@ while (my $ref = $q->fetchrow_hashref) {
        my $score1 = $ref->{'score1'};
        my $score2 = $ref->{'score2'};
 
-       # make virtual "team players"
-       my ($rating_team1, $rd_team1) = foosball::combine_ratings($rating1_1, $rd1_1, $rating1_2, $rd1_2);
-       my ($rating_team2, $rd_team2) = foosball::combine_ratings($rating2_1, $rd2_1, $rating2_2, $rd2_2);
-
-       my ($new_t1r, undef) =  foosball::calc_rating($rating_team1, $rd_team1, $rating_team2, $rd_team2, $score1, $score2);
-       my ($new_t2r, undef) =  foosball::calc_rating($rating_team2, $rd_team2, $rating_team1, $rd_team1, $score2, $score1);
-       my $newr1_1 = $rating1_1 + ($new_t1r - $rating_team1);
-       my $newr1_2 = $rating1_2 + ($new_t1r - $rating_team1);
-       my $newr2_1 = $rating2_1 + ($new_t2r - $rating_team2);
-       my $newr2_2 = $rating2_2 + ($new_t2r - $rating_team2);
-
-       my (undef, $newrd1_1) = foosball::calc_rating($rating1_1, $rd1_1, $rating_team2, $rd_team2, $score1, $score2);
-       my (undef, $newrd1_2) = foosball::calc_rating($rating1_2, $rd1_2, $rating_team2, $rd_team2, $score1, $score2);
-       my (undef, $newrd2_1) = foosball::calc_rating($rating2_1, $rd2_1, $rating_team1, $rd_team1, $score2, $score1);
-       my (undef, $newrd2_2) = foosball::calc_rating($rating2_2, $rd2_2, $rating_team1, $rd_team1, $score2, $score1);
+       my ($newr1_1, $newrd1_1) = foosball::calc_rating_double($rating1_1, $rd1_1, $rating1_2, $rd1_2, $rating2_1, $rd2_1, $rating2_2, $rd2_2, $score1, $score2);
+       my ($newr1_2, $newrd1_2) = foosball::calc_rating_double($rating1_2, $rd1_2, $rating1_1, $rd1_1, $rating2_1, $rd2_1, $rating2_2, $rd2_2, $score1, $score2);
+       my ($newr2_1, $newrd2_1) = foosball::calc_rating_double($rating2_1, $rd2_1, $rating2_2, $rd2_2, $rating1_1, $rd1_1, $rating1_2, $rd1_2, $score2, $score1);
+       my ($newr2_2, $newrd2_2) = foosball::calc_rating_double($rating2_2, $rd2_2, $rating2_1, $rd2_1, $rating1_1, $rd1_1, $rating1_2, $rd1_2, $score2, $score1);
 
        printf("%-10s/%-10s - %-10s/%-10s: %u - %u, new ratings %u/%u %u/%u   %u/%u %u/%u\n",
                $ref->{'team1_username1'}, $ref->{'team1_username2'},
index 9b65aff120b5f34738d64e61a4dd23cd954362f3..8efd9b53c477c69c57a3ca414c97be2333485a2f 100755 (executable)
@@ -47,23 +47,11 @@ my ($rating1_2, $rd1_2) = foosball::find_double_rating($dbh, $team1_username2);
 my ($rating2_1, $rd2_1) = foosball::find_double_rating($dbh, $team2_username1);
 my ($rating2_2, $rd2_2) = foosball::find_double_rating($dbh, $team2_username2);
 
+my ($newr1_1, $newrd1_1) = foosball::calc_rating_double($rating1_1, $rd1_1, $rating1_2, $rd1_2, $rating2_1, $rd2_1, $rating2_2, $rd2_2, $score1, $score2);
+my ($newr1_2, $newrd1_2) = foosball::calc_rating_double($rating1_2, $rd1_2, $rating1_1, $rd1_1, $rating2_1, $rd2_1, $rating2_2, $rd2_2, $score1, $score2);
+my ($newr2_1, $newrd2_1) = foosball::calc_rating_double($rating2_1, $rd2_1, $rating2_2, $rd2_2, $rating1_1, $rd1_1, $rating1_2, $rd1_2, $score2, $score1);
+my ($newr2_2, $newrd2_2) = foosball::calc_rating_double($rating2_2, $rd2_2, $rating2_1, $rd2_1, $rating1_1, $rd1_1, $rating1_2, $rd1_2, $score2, $score1);
 # make virtual "team players"
-my ($rating_team1, $rd_team1) = foosball::combine_ratings($rating1_1, $rd1_1, $rating1_2, $rd1_2);
-my ($rating_team2, $rd_team2) = foosball::combine_ratings($rating2_1, $rd2_1, $rating2_2, $rd2_2);
-
-my $q = $foosball::q;
-
-my ($new_t1r, undef) =  foosball::calc_rating($rating_team1, $rd_team1, $rating_team2, $rd_team2, $score1, $score2);
-my ($new_t2r, undef) =  foosball::calc_rating($rating_team2, $rd_team2, $rating_team1, $rd_team1, $score2, $score1);
-my $newr1_1 = $rating1_1 + ($new_t1r - $rating_team1);
-my $newr1_2 = $rating1_2 + ($new_t1r - $rating_team1);
-my $newr2_1 = $rating2_1 + ($new_t2r - $rating_team2);
-my $newr2_2 = $rating2_2 + ($new_t2r - $rating_team2);
-
-my (undef, $newrd1_1) = foosball::calc_rating($rating1_1, $rd1_1, $rating_team2, $rd_team2, $score1, $score2);
-my (undef, $newrd1_2) = foosball::calc_rating($rating1_2, $rd1_2, $rating_team2, $rd_team2, $score1, $score2);
-my (undef, $newrd2_1) = foosball::calc_rating($rating2_1, $rd2_1, $rating_team1, $rd_team1, $score2, $score1);
-my (undef, $newrd2_2) = foosball::calc_rating($rating2_2, $rd2_2, $rating_team1, $rd_team1, $score2, $score1);
 
 $dbh->do('INSERT INTO double_results (gametime,team1_username1,team1_username2,team2_username1,team2_username2,score1,score2) VALUES (CURRENT_TIMESTAMP,?,?,?,?,?,?)',
        undef, $team1_username1, $team1_username2, $team2_username1, $team2_username2, $score1, $score2);
index 6f77c3323de3117a4bdae5d32a0c8ff734472029..c31200a59586c5260fbadb8533cebdca7b95af64 100755 (executable)
@@ -72,7 +72,9 @@ select * from (
        score1,
        score2,
        ra1.rating_diff as diff1, 
-       ra2.rating_diff as diff2
+       ra2.rating_diff as diff2, 
+       ra3.rating_diff as diff3, 
+       ra4.rating_diff as diff4 
     from
         double_results re
         join double_rating ra1
@@ -80,7 +82,13 @@ select * from (
            and re.team1_username1=ra1.username
        join double_rating ra2
            on re.gametime=ra2.ratetime
-           and re.team2_username1=ra2.username
+           and re.team1_username2=ra2.username
+       join double_rating ra3
+           on re.gametime=ra3.ratetime
+           and re.team2_username1=ra3.username
+       join double_rating ra4
+           on re.gametime=ra4.ratetime
+           and re.team2_username2=ra4.username
     union all
     select
         to_char(gametime, \'IYYY-MM-DD HH24:MI\') as gametime,
@@ -90,7 +98,9 @@ select * from (
        score1,
        score2,
        ra1.rating_diff as diff1, 
-       ra2.rating_diff as diff2
+       null as diff2, 
+       ra2.rating_diff as diff3,
+       null as diff4 
     from
         single_results re
         join single_rating ra1
@@ -103,8 +113,17 @@ select * from (
 order by gametime desc limit 10');
 $q->execute();
 while (my $ref = $q->fetchrow_hashref) {
-       $ref->{'diff1'} = sprintf "%+d", int($ref->{'diff1'} + 0.5);
-       $ref->{'diff2'} = sprintf "%+d", int($ref->{'diff2'} + 0.5);
+       if (defined($ref->{'diff2'})) {
+               $ref->{'diff1'} = sprintf "%+d / %+d",
+                       int($ref->{'diff1'} + 0.5),
+                       int($ref->{'diff2'} + 0.5);
+               $ref->{'diff2'} = sprintf "%+d / %+d",
+                       int($ref->{'diff3'} + 0.5),
+                       int($ref->{'diff4'} + 0.5);
+       } else {
+               $ref->{'diff1'} = sprintf "%+d", int($ref->{'diff1'} + 0.5);
+               $ref->{'diff2'} = sprintf "%+d", int($ref->{'diff3'} + 0.5);
+       }
        push @last_games, $ref;
 }