mirror of
https://github.com/furyfire/trueskill.git
synced 2025-01-16 01:47:39 +00:00
136 lines
5.2 KiB
PHP
136 lines
5.2 KiB
PHP
<?php
|
|
namespace Moserware\Skills\TrueSkill;
|
|
|
|
require_once(dirname(__FILE__) . '/../Numerics/GaussianDistribution.php');
|
|
|
|
use Moserware\Numerics\GaussianDistribution;
|
|
|
|
class TruncatedGaussianCorrectionFunctions
|
|
{
|
|
// These functions from the bottom of page 4 of the TrueSkill paper.
|
|
|
|
/// <summary>
|
|
/// The "V" function where the team performance difference is greater than the draw margin.
|
|
/// </summary>
|
|
/// <remarks>In the reference F# implementation, this is referred to as "the additive
|
|
/// correction of a single-sided truncated Gaussian with unit variance."</remarks>
|
|
/// <param name="teamPerformanceDifference"></param>
|
|
/// <param name="drawMargin">In the paper, it's referred to as just "ε".</param>
|
|
/// <returns></returns>
|
|
public static function vExceedsMarginScaled($teamPerformanceDifference, $drawMargin, $c)
|
|
{
|
|
return self::vExceedsMargin($teamPerformanceDifference/$c, $drawMargin/$c);
|
|
}
|
|
|
|
public static function vExceedsMargin($teamPerformanceDifference, $drawMargin)
|
|
{
|
|
$denominator = GaussianDistribution::cumulativeTo($teamPerformanceDifference - $drawMargin);
|
|
|
|
if ($denominator < 2.222758749e-162)
|
|
{
|
|
return -$teamPerformanceDifference + $drawMargin;
|
|
}
|
|
|
|
return GaussianDistribution::at($teamPerformanceDifference - $drawMargin)/$denominator;
|
|
}
|
|
|
|
/// <summary>
|
|
/// The "W" function where the team performance difference is greater than the draw margin.
|
|
/// </summary>
|
|
/// <remarks>In the reference F# implementation, this is referred to as "the multiplicative
|
|
/// correction of a single-sided truncated Gaussian with unit variance."</remarks>
|
|
/// <param name="teamPerformanceDifference"></param>
|
|
/// <param name="drawMargin"></param>
|
|
/// <param name="c"></param>
|
|
/// <returns></returns>
|
|
public static function wExceedsMarginScaled($teamPerformanceDifference, $drawMargin, $c)
|
|
{
|
|
return self::wExceedsMargin($teamPerformanceDifference/$c, $drawMargin/$c);
|
|
}
|
|
|
|
public static function wExceedsMargin($teamPerformanceDifference, $drawMargin)
|
|
{
|
|
$denominator = GaussianDistribution::cumulativeTo($teamPerformanceDifference - $drawMargin);
|
|
|
|
if ($denominator < 2.222758749e-162)
|
|
{
|
|
if ($teamPerformanceDifference < 0.0)
|
|
{
|
|
return 1.0;
|
|
}
|
|
return 0.0;
|
|
}
|
|
|
|
$vWin = self::vExceedsMargin($teamPerformanceDifference, $drawMargin);
|
|
return $vWin*($vWin + $teamPerformanceDifference - $drawMargin);
|
|
}
|
|
|
|
// the additive correction of a double-sided truncated Gaussian with unit variance
|
|
public static function vWithinMarginScaled($teamPerformanceDifference, $drawMargin, $c)
|
|
{
|
|
return self::vWithinMargin($teamPerformanceDifference/$c, $drawMargin/$c);
|
|
}
|
|
|
|
// from F#:
|
|
public static function vWithinMargin($teamPerformanceDifference, $drawMargin)
|
|
{
|
|
$teamPerformanceDifferenceAbsoluteValue = abs($teamPerformanceDifference);
|
|
$denominator =
|
|
GaussianDistribution::cumulativeTo($drawMargin - $teamPerformanceDifferenceAbsoluteValue) -
|
|
GaussianDistribution::cumulativeTo(-$drawMargin - $teamPerformanceDifferenceAbsoluteValue);
|
|
|
|
if ($denominator < 2.222758749e-162)
|
|
{
|
|
if ($teamPerformanceDifference < 0.0)
|
|
{
|
|
return -$teamPerformanceDifference - $drawMargin;
|
|
}
|
|
|
|
return -$teamPerformanceDifference + $drawMargin;
|
|
}
|
|
|
|
$numerator = GaussianDistribution::at(-$drawMargin - $teamPerformanceDifferenceAbsoluteValue) -
|
|
GaussianDistribution::at($drawMargin - $teamPerformanceDifferenceAbsoluteValue);
|
|
|
|
if ($teamPerformanceDifference < 0.0)
|
|
{
|
|
return -$numerator/$denominator;
|
|
}
|
|
|
|
return $numerator/$denominator;
|
|
}
|
|
|
|
// the multiplicative correction of a double-sided truncated Gaussian with unit variance
|
|
public static function wWithinMarginScaled($teamPerformanceDifference, $drawMargin, $c)
|
|
{
|
|
return self::wWithinMargin($teamPerformanceDifference/$c, $drawMargin/$c);
|
|
}
|
|
|
|
// From F#:
|
|
public static function wWithinMargin($teamPerformanceDifference, $drawMargin)
|
|
{
|
|
$teamPerformanceDifferenceAbsoluteValue = abs($teamPerformanceDifference);
|
|
$denominator = GaussianDistribution::cumulativeTo($drawMargin - $teamPerformanceDifferenceAbsoluteValue)
|
|
-
|
|
GaussianDistribution::cumulativeTo(-$drawMargin - $teamPerformanceDifferenceAbsoluteValue);
|
|
|
|
if ($denominator < 2.222758749e-162)
|
|
{
|
|
return 1.0;
|
|
}
|
|
|
|
$vt = self::vWithinMargin($teamPerformanceDifferenceAbsoluteValue, $drawMargin);
|
|
|
|
return $vt*$vt +
|
|
(
|
|
($drawMargin - $teamPerformanceDifferenceAbsoluteValue)
|
|
*
|
|
GaussianDistribution::at(
|
|
$drawMargin - $teamPerformanceDifferenceAbsoluteValue)
|
|
- (-$drawMargin - $teamPerformanceDifferenceAbsoluteValue)
|
|
*
|
|
GaussianDistribution::at(-$drawMargin - $teamPerformanceDifferenceAbsoluteValue))/$denominator;
|
|
}
|
|
}
|
|
?>
|