From c80e3970733546d1ee0a0e75b92d234bddb3ce38 Mon Sep 17 00:00:00 2001 From: avitex Date: Thu, 16 Nov 2017 13:37:56 +1100 Subject: [PATCH] Improve opts and test --- lib/glicko.ex | 23 +++++++++++++---------- test/glicko_test.exs | 16 +++++++++------- 2 files changed, 22 insertions(+), 17 deletions(-) diff --git a/lib/glicko.ex b/lib/glicko.ex index 28a553a..ebd4269 100644 --- a/lib/glicko.ex +++ b/lib/glicko.ex @@ -5,26 +5,28 @@ defmodule Glicko do GameResult, } - @epsilon 0.0000001 @default_system_constant 0.8 + @default_convergence_tolerance 1.0e-7 + + @type new_rating_opts_t :: [system_constant: float, convergence_tolerance: float] @doc """ Generate a new Rating from an existing rating and a series of results. """ - @spec new_rating(player :: Player.t, results :: list(GameResult.t), sys_constant :: float) :: Player.t - def new_rating(player, results, sys_constant \\ @default_system_constant) - def new_rating(player = %Player{version: :v1}, results, sys_constant) do + @spec new_rating(player :: Player.t, results :: list(GameResult.t), opts :: new_rating_opts_t) :: Player.t + def new_rating(player, results, opts \\ []) + def new_rating(player = %Player{version: :v1}, results, opts) do player |> Player.to_v2 - |> do_new_rating(results, sys_constant) + |> do_new_rating(results, opts) |> Player.to_v1 end - def new_rating(player = %Player{version: :v2}, results, sys_constant) do - do_new_rating(player, results, sys_constant) + def new_rating(player = %Player{version: :v2}, results, opts) do + do_new_rating(player, results, opts) end - defp do_new_rating(player = %Player{version: :v2}, results, sys_constant) do + defp do_new_rating(player = %Player{version: :v2}, results, opts) do results = Enum.map(results, fn result -> result = Map.new @@ -38,7 +40,8 @@ defmodule Glicko do ctx = Map.new - |> Map.put(:system_constant, sys_constant) + |> Map.put(:system_constant, Keyword.get(opts, :system_constant, @default_system_constant)) + |> Map.put(:convergence_tolerance, Keyword.get(opts, :convergence_tolerance, @default_convergence_tolerance)) |> Map.put(:results, results) |> Map.put(:player, player) |> Map.put(:player_rating_deviation_squared, :math.pow(player.rating_deviation, 2)) @@ -134,7 +137,7 @@ defmodule Glicko do end defp iterative_algorithm_body(ctx, a, b, fa, fb) do - if abs(b - a) > @epsilon do + if abs(b - a) > ctx.convergence_tolerance do c = a + (a - b) * fa / (fb - fa) fc = calc_f(ctx, c) {a, fa} = diff --git a/test/glicko_test.exs b/test/glicko_test.exs index 0e62307..5b5c7bf 100644 --- a/test/glicko_test.exs +++ b/test/glicko_test.exs @@ -8,7 +8,7 @@ defmodule GlickoTest do doctest Glicko - @player Player.new_v1([rating: 1500, rating_deviation: 200]) + @player Player.new_v1([rating: 1500, rating_deviation: 200]) |> Player.to_v2 @results [ GameResult.new(Player.new_v1([rating: 1400, rating_deviation: 30]), :win), @@ -16,14 +16,16 @@ defmodule GlickoTest do GameResult.new(Player.new_v1([rating: 1700, rating_deviation: 300]), :loss), ] - @valid_player_rating_after_results 1464.06 - @valid_player_rating_deviation_after_results 151.52 + @valid_player_rating_after_results 1464.06 |> Player.scale_rating_to(:v2) + @valid_player_rating_deviation_after_results 151.52 |> Player.scale_rating_deviation_to(:v2) + @valid_player_volatility_after_results 0.05999 test "new rating" do - %Player{rating: new_rating, rating_deviation: new_rating_deviation} = - Glicko.new_rating(@player, @results, 0.5) + %Player{rating: new_rating, rating_deviation: new_rating_deviation, volatility: new_volatility} = + Glicko.new_rating(@player, @results, [system_constant: 0.5]) - assert_in_delta new_rating, @valid_player_rating_after_results, 0.1 - assert_in_delta new_rating_deviation, @valid_player_rating_deviation_after_results, 0.1 + assert_in_delta new_rating, @valid_player_rating_after_results, 1.0e-4 + assert_in_delta new_rating_deviation, @valid_player_rating_deviation_after_results, 1.0e-4 + assert_in_delta new_volatility, @valid_player_volatility_after_results, 1.0e-5 end end