From ea27f7d09fc8c7e3b284e0e248c37a126583faf9 Mon Sep 17 00:00:00 2001 From: "Steinar H. Gunderson" Date: Thu, 11 Oct 2007 19:06:25 +0200 Subject: [PATCH] Switch to more accurate double score calculation. --- foosball.pm | 12 ++++++++ foosrank.cpp | 62 +++++++++++++++++++++++++++++++++++++--- recalc-double-result.pl | 19 +++--------- www/add-double-result.pl | 20 +++---------- www/index.pl | 29 +++++++++++++++---- 5 files changed, 102 insertions(+), 40 deletions(-) diff --git a/foosball.pm b/foosball.pm index dc5ff22..a2b0d55 100644 --- a/foosball.pm +++ b/foosball.pm @@ -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; diff --git a/foosrank.cpp b/foosrank.cpp index fc968cd..6991061 100644 --- a/foosrank.cpp +++ b/foosrank.cpp @@ -6,8 +6,8 @@ #include // 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 > 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; diff --git a/recalc-double-result.pl b/recalc-double-result.pl index 2ccb6a7..b606b5a 100755 --- a/recalc-double-result.pl +++ b/recalc-double-result.pl @@ -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'}, diff --git a/www/add-double-result.pl b/www/add-double-result.pl index 9b65aff..8efd9b5 100755 --- a/www/add-double-result.pl +++ b/www/add-double-result.pl @@ -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); diff --git a/www/index.pl b/www/index.pl index 6f77c33..c31200a 100755 --- a/www/index.pl +++ b/www/index.pl @@ -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; } -- 2.39.2