diff --git a/src/Elo/EloRating.php b/src/Elo/EloRating.php index ec9c027..844f8e6 100644 --- a/src/Elo/EloRating.php +++ b/src/Elo/EloRating.php @@ -1,7 +1,4 @@ - \ No newline at end of file +} \ No newline at end of file diff --git a/src/Elo/FideEloCalculator.php b/src/Elo/FideEloCalculator.php index e7349cb..5a5263d 100644 --- a/src/Elo/FideEloCalculator.php +++ b/src/Elo/FideEloCalculator.php @@ -1,17 +1,13 @@ -getBeta())) - ); - } -} - -?> \ No newline at end of file + / + ( + 1.0 + pow(10.0, $ratingDifference / (2 * $gameInfo->getBeta())) + ); + } +} \ No newline at end of file diff --git a/src/Elo/FideKFactor.php b/src/Elo/FideKFactor.php index 405a198..6b40b93 100644 --- a/src/Elo/FideKFactor.php +++ b/src/Elo/FideKFactor.php @@ -1,30 +1,14 @@ - \ No newline at end of file +} \ No newline at end of file diff --git a/src/Elo/GaussianEloCalculator.php b/src/Elo/GaussianEloCalculator.php index 717e3e3..de22b1c 100644 --- a/src/Elo/GaussianEloCalculator.php +++ b/src/Elo/GaussianEloCalculator.php @@ -1,10 +1,4 @@ -getBeta())); } -} - -?> \ No newline at end of file +} \ No newline at end of file diff --git a/src/Elo/KFactor.php b/src/Elo/KFactor.php index 995d052..a3105ec 100644 --- a/src/Elo/KFactor.php +++ b/src/Elo/KFactor.php @@ -1,11 +1,9 @@ -_value; } -} - -?> \ No newline at end of file +} \ No newline at end of file diff --git a/src/Elo/ProvisionalFideKFactor.php b/src/Elo/ProvisionalFideKFactor.php new file mode 100644 index 0000000..57ea7b3 --- /dev/null +++ b/src/Elo/ProvisionalFideKFactor.php @@ -0,0 +1,12 @@ + \ No newline at end of file +} \ No newline at end of file diff --git a/src/FactorGraphs/DefaultVariable.php b/src/FactorGraphs/DefaultVariable.php new file mode 100644 index 0000000..8dd5cc3 --- /dev/null +++ b/src/FactorGraphs/DefaultVariable.php @@ -0,0 +1,21 @@ +_messages); } - + protected function &getVariables() { return $this->_variables; } - + protected function &getMessages() { return $this->_messages; @@ -56,7 +51,7 @@ abstract class Factor { Guard::argumentIsValidIndex($messageIndex, count($this->_messages), "messageIndex"); $message = &$this->_messages[$messageIndex]; - $variable = &$this->_messageToVariableBinding->getValue($message); + $variable = &$this->_messageToVariableBinding->getValue($message); return $this->updateMessageVariable($message, $variable); } @@ -71,8 +66,7 @@ abstract class Factor public function resetMarginals() { $allValues = &$this->_messageToVariableBinding->getAllValues(); - foreach ($allValues as &$currentVariable) - { + foreach ($allValues as &$currentVariable) { $currentVariable->resetToPrior(); } } @@ -108,6 +102,4 @@ abstract class Factor { return ($this->_name != null) ? $this->_name : base::__toString(); } -} - -?> +} \ No newline at end of file diff --git a/src/FactorGraphs/FactorGraph.php b/src/FactorGraphs/FactorGraph.php index 3685f1f..7eea953 100644 --- a/src/FactorGraphs/FactorGraph.php +++ b/src/FactorGraphs/FactorGraph.php @@ -1,7 +1,4 @@ -_variableFactory = &$factory; } -} -?> +} \ No newline at end of file diff --git a/src/FactorGraphs/FactorGraphLayer.php b/src/FactorGraphs/FactorGraphLayer.php index 74036b6..1984015 100644 --- a/src/FactorGraphs/FactorGraphLayer.php +++ b/src/FactorGraphs/FactorGraphLayer.php @@ -1,9 +1,4 @@ - +} \ No newline at end of file diff --git a/src/FactorGraphs/FactorList.php b/src/FactorGraphs/FactorList.php index feac65b..fa95baa 100644 --- a/src/FactorGraphs/FactorList.php +++ b/src/FactorGraphs/FactorList.php @@ -1,8 +1,4 @@ -_list; - foreach($list as &$currentFactor) - { + foreach ($list as &$currentFactor) { $currentFactor->resetMarginals(); } @@ -23,22 +18,19 @@ class FactorList $listCount = count($this->_list); - for ($i = 0; $i < $listCount; $i++) - { + for ($i = 0; $i < $listCount; $i++) { $f = $this->_list[$i]; $numberOfMessages = $f->getNumberOfMessages(); - for ($j = 0; $j < $numberOfMessages; $j++) - { + for ($j = 0; $j < $numberOfMessages; $j++) { $sumLogZ += $f->sendMessageIndex($j); } } $sumLogS = 0; - foreach($list as &$currentFactor) - { + foreach ($list as &$currentFactor) { $sumLogS = $sumLogS + $currentFactor->getLogNormalization(); } @@ -55,6 +47,4 @@ class FactorList $this->_list[] = $factor; return $factor; } -} - -?> +} \ No newline at end of file diff --git a/src/FactorGraphs/KeyedVariable.php b/src/FactorGraphs/KeyedVariable.php new file mode 100644 index 0000000..b85a88d --- /dev/null +++ b/src/FactorGraphs/KeyedVariable.php @@ -0,0 +1,18 @@ +_key = &$key; + } + + public function &getKey() + { + $key = &$this->_key; + return $key; + } +} \ No newline at end of file diff --git a/src/FactorGraphs/Message.php b/src/FactorGraphs/Message.php index 6768a8b..98f07f9 100644 --- a/src/FactorGraphs/Message.php +++ b/src/FactorGraphs/Message.php @@ -1,14 +1,13 @@ -_name = $name; + $this->_name = $name; $this->_value = $value; } @@ -19,14 +18,12 @@ class Message } public function setValue(&$value) - { + { $this->_value = &$value; } public function __toString() { - return $this->_name; + return (string)$this->_name; } -} - -?> +} \ No newline at end of file diff --git a/src/FactorGraphs/Schedule.php b/src/FactorGraphs/Schedule.php index 34b64ee..ac766db 100644 --- a/src/FactorGraphs/Schedule.php +++ b/src/FactorGraphs/Schedule.php @@ -1,7 +1,4 @@ -_name; } -} - -class ScheduleStep extends Schedule -{ - private $_factor; - private $_index; - - public function __construct($name, Factor &$factor, $index) - { - parent::__construct($name); - $this->_factor = $factor; - $this->_index = $index; - } - - public function visit($depth = -1, $maxDepth = 0) - { - $currentFactor = &$this->_factor; - $delta = $currentFactor->updateMessageIndex($this->_index); - return $delta; - } -} - -class ScheduleSequence extends Schedule -{ - private $_schedules; - - public function __construct($name, array $schedules) - { - parent::__construct($name); - $this->_schedules = $schedules; - } - - public function visit($depth = -1, $maxDepth = 0) - { - $maxDelta = 0; - - $schedules = &$this->_schedules; - foreach ($schedules as &$currentSchedule) - { - $currentVisit = $currentSchedule->visit($depth + 1, $maxDepth); - $maxDelta = max($currentVisit, $maxDelta); - } - - return $maxDelta; - } -} - -class ScheduleLoop extends Schedule -{ - private $_maxDelta; - private $_scheduleToLoop; - - public function __construct($name, Schedule &$scheduleToLoop, $maxDelta) - { - parent::__construct($name); - $this->_scheduleToLoop = $scheduleToLoop; - $this->_maxDelta = $maxDelta; - } - - public function visit($depth = -1, $maxDepth = 0) - { - $totalIterations = 1; - $delta = $this->_scheduleToLoop->visit($depth + 1, $maxDepth); - while ($delta > $this->_maxDelta) - { - $delta = $this->_scheduleToLoop->visit($depth + 1, $maxDepth); - $totalIterations++; - } - - return $delta; - } -} - -?> +} \ No newline at end of file diff --git a/src/FactorGraphs/ScheduleLoop.php b/src/FactorGraphs/ScheduleLoop.php new file mode 100644 index 0000000..962be55 --- /dev/null +++ b/src/FactorGraphs/ScheduleLoop.php @@ -0,0 +1,26 @@ +_scheduleToLoop = $scheduleToLoop; + $this->_maxDelta = $maxDelta; + } + + public function visit($depth = -1, $maxDepth = 0) + { + $totalIterations = 1; + $delta = $this->_scheduleToLoop->visit($depth + 1, $maxDepth); + while ($delta > $this->_maxDelta) { + $delta = $this->_scheduleToLoop->visit($depth + 1, $maxDepth); + $totalIterations++; + } + + return $delta; + } +} \ No newline at end of file diff --git a/src/FactorGraphs/ScheduleSequence.php b/src/FactorGraphs/ScheduleSequence.php new file mode 100644 index 0000000..fc66b8b --- /dev/null +++ b/src/FactorGraphs/ScheduleSequence.php @@ -0,0 +1,25 @@ +_schedules = $schedules; + } + + public function visit($depth = -1, $maxDepth = 0) + { + $maxDelta = 0; + + $schedules = &$this->_schedules; + foreach ($schedules as &$currentSchedule) { + $currentVisit = $currentSchedule->visit($depth + 1, $maxDepth); + $maxDelta = max($currentVisit, $maxDelta); + } + + return $maxDelta; + } +} \ No newline at end of file diff --git a/src/FactorGraphs/ScheduleStep.php b/src/FactorGraphs/ScheduleStep.php new file mode 100644 index 0000000..1ea75ed --- /dev/null +++ b/src/FactorGraphs/ScheduleStep.php @@ -0,0 +1,21 @@ +_factor = $factor; + $this->_index = $index; + } + + public function visit($depth = -1, $maxDepth = 0) + { + $currentFactor = &$this->_factor; + $delta = $currentFactor->updateMessageIndex($this->_index); + return $delta; + } +} \ No newline at end of file diff --git a/src/FactorGraphs/Variable.php b/src/FactorGraphs/Variable.php index 5f464ad..f1ad077 100644 --- a/src/FactorGraphs/Variable.php +++ b/src/FactorGraphs/Variable.php @@ -16,12 +16,12 @@ class Variable public function &getValue() { - $value = &$this->_value; + $value = &$this->_value; return $value; } public function setValue(&$value) - { + { $this->_value = &$value; } @@ -34,40 +34,4 @@ class Variable { return $this->_name; } -} - -class DefaultVariable extends Variable -{ - public function __construct() - { - parent::__construct("Default", null); - } - - public function &getValue() - { - return null; - } - - public function setValue(&$value) - { - throw new Exception(); - } -} - -class KeyedVariable extends Variable -{ - private $_key; - public function __construct(&$key, $name, &$prior) - { - parent::__construct($name, $prior); - $this->_key = &$key; - } - - public function &getKey() - { - $key = &$this->_key; - return $key; - } -} - -?> +} \ No newline at end of file diff --git a/src/FactorGraphs/VariableFactory.php b/src/FactorGraphs/VariableFactory.php index 12061f2..fd86263 100644 --- a/src/FactorGraphs/VariableFactory.php +++ b/src/FactorGraphs/VariableFactory.php @@ -1,8 +1,4 @@ - diff --git a/src/GameInfo.php b/src/GameInfo.php index 47b6b43..f0c6f2d 100644 --- a/src/GameInfo.php +++ b/src/GameInfo.php @@ -1,9 +1,4 @@ -_initialMean = $initialMean; @@ -33,19 +28,19 @@ class GameInfo $this->_beta = $beta; $this->_dynamicsFactor = $dynamicsFactor; $this->_drawProbability = $drawProbability; - } - + } + public function getInitialMean() - { + { return $this->_initialMean; } - + public function getInitialStandardDeviation() { return $this->_initialStandardDeviation; } - + public function getBeta() { return $this->_beta; @@ -55,7 +50,7 @@ class GameInfo { return $this->_dynamicsFactor; } - + public function getDrawProbability() { return $this->_drawProbability; @@ -65,6 +60,4 @@ class GameInfo { return new Rating($this->_initialMean, $this->_initialStandardDeviation); } -} - -?> \ No newline at end of file +} \ No newline at end of file diff --git a/src/Guard.php b/src/Guard.php index 17dc653..9bb22f3 100644 --- a/src/Guard.php +++ b/src/Guard.php @@ -1,35 +1,32 @@ -= $count)) - { + if (($index < 0) || ($index >= $count)) { throw new Exception($parameterName . " is an invalid index"); } } public static function argumentInRangeInclusive($value, $min, $max, $parameterName) { - if (($value < $min) || ($value > $max)) - { + if (($value < $min) || ($value > $max)) { throw new Exception($parameterName . " is not in the valid range [" . $min . ", " . $max . "]"); } } -} -?> +} \ No newline at end of file diff --git a/src/HashMap.php b/src/HashMap.php index ac35a10..9b72f94 100644 --- a/src/HashMap.php +++ b/src/HashMap.php @@ -1,6 +1,4 @@ -_hashToKey); + $keys = &array_values($this->_hashToKey); return $keys; } public function getAllValues() { - $values = &\array_values($this->_hashToValue); + $values = &array_values($this->_hashToValue); return $values; } public function count() - { - return \count($this->_hashToKey); + { + return count($this->_hashToKey); } private static function getHash(&$key) { - if(\is_object($key)) - { - return \spl_object_hash($key); + if (is_object($key)) { + return spl_object_hash($key); } return $key; } -} -?> +} \ No newline at end of file diff --git a/src/ISupportPartialPlay.php b/src/ISupportPartialPlay.php index 31fa0e3..e8d7022 100644 --- a/src/ISupportPartialPlay.php +++ b/src/ISupportPartialPlay.php @@ -1,16 +1,12 @@ - \ No newline at end of file +} \ No newline at end of file diff --git a/src/ISupportPartialUpdate.php b/src/ISupportPartialUpdate.php index 5e0f5c9..5dadfa5 100644 --- a/src/ISupportPartialUpdate.php +++ b/src/ISupportPartialUpdate.php @@ -1,5 +1,4 @@ - \ No newline at end of file +} \ No newline at end of file diff --git a/src/Numerics/BasicMath.php b/src/Numerics/BasicMath.php index 59dccb3..2929cdf 100644 --- a/src/Numerics/BasicMath.php +++ b/src/Numerics/BasicMath.php @@ -1,31 +1,30 @@ - * @copyright 2010 Jeff Moser */ +class BasicMatch { -/** - * Squares the input (x^2 = x * x) - * @param number $x Value to square (x) - * @return number The squared value (x^2) - */ -function square($x) -{ - return $x * $x; -} + /** + * Squares the input (x^2 = x * x) + * @param number $x Value to square (x) + * @return number The squared value (x^2) + */ + public static function square($x) { + return $x * $x; + } -/** - * Sums the items in $itemsToSum - * @param array $itemsToSum The items to sum, - * @param callback $callback The function to apply to each array element before summing. - * @return number The sum. - */ -function sum(array $itemsToSum, $callback ) -{ - $mappedItems = array_map($callback, $itemsToSum); - return array_sum($mappedItems); -} - -?> \ No newline at end of file + /** + * Sums the items in $itemsToSum + * @param array $itemsToSum The items to sum, + * @param callback $callback The function to apply to each array element before summing. + * @return number The sum. + */ + public static function sum(array $itemsToSum, $callback) { + $mappedItems = array_map($callback, $itemsToSum); + return array_sum($mappedItems); + } +} \ No newline at end of file diff --git a/src/Numerics/DiagonalMatrix.php b/src/Numerics/DiagonalMatrix.php new file mode 100644 index 0000000..8dec57d --- /dev/null +++ b/src/Numerics/DiagonalMatrix.php @@ -0,0 +1,23 @@ +setValue($currentRow, $currentCol, $diagonalValues[$currentRow]); + } else { + $this->setValue($currentRow, $currentCol, 0); + } + } + } + } +} \ No newline at end of file diff --git a/src/Numerics/GaussianDistribution.php b/src/Numerics/GaussianDistribution.php index 6229302..2b176ba 100644 --- a/src/Numerics/GaussianDistribution.php +++ b/src/Numerics/GaussianDistribution.php @@ -1,8 +1,4 @@ -_mean = $mean; + public function __construct($mean = 0.0, $standardDeviation = 1.0) + { + $this->_mean = $mean; $this->_standardDeviation = $standardDeviation; - $this->_variance = square($standardDeviation); + $this->_variance = BasicMatch::square($standardDeviation); - if($this->_variance != 0) - { - $this->_precision = 1.0/$this->_variance; - $this->_precisionMean = $this->_precision*$this->_mean; - } - else - { + if ($this->_variance != 0) { + $this->_precision = 1.0 / $this->_variance; + $this->_precisionMean = $this->_precision * $this->_mean; + } else { $this->_precision = \INF; - if($this->_mean == 0) - { + if ($this->_mean == 0) { $this->_precisionMean = 0; - } - else - { + } else { $this->_precisionMean = \INF; } } - } - + } + public function getMean() { return $this->_mean; } - + public function getVariance() { return $this->_variance; } - + public function getStandardDeviation() { return $this->_standardDeviation; @@ -71,13 +61,13 @@ class GaussianDistribution { return $this->_precisionMean; } - + public function getNormalizationConstant() - { + { // Great derivation of this is at http://www.astro.psu.edu/~mce/A451_2/A451/downloads/notes0.pdf - return 1.0/(sqrt(2*M_PI)*$this->_standardDeviation); + return 1.0 / (sqrt(2 * M_PI) * $this->_standardDeviation); } - + public function __clone() { $result = new GaussianDistribution(); @@ -88,35 +78,32 @@ class GaussianDistribution $result->_precisionMean = $this->_precisionMean; return $result; } - + public static function fromPrecisionMean($precisionMean, $precision) { $result = new GaussianDistribution(); $result->_precision = $precision; $result->_precisionMean = $precisionMean; - if($precision != 0) - { - $result->_variance = 1.0/$precision; + if ($precision != 0) { + $result->_variance = 1.0 / $precision; $result->_standardDeviation = sqrt($result->_variance); - $result->_mean = $result->_precisionMean/$result->_precision; - } - else - { + $result->_mean = $result->_precisionMean / $result->_precision; + } else { $result->_variance = \INF; $result->_standardDeviation = \INF; $result->_mean = \NAN; } return $result; } - + // For details, see http://www.tina-vision.net/tina-knoppix/tina-memo/2003-003.pdf // for multiplication, the precision mean ones are easier to write :) public static function multiply(GaussianDistribution $left, GaussianDistribution $right) { return GaussianDistribution::fromPrecisionMean($left->_precisionMean + $right->_precisionMean, $left->_precision + $right->_precision); } - + // Computes the absolute difference between two Gaussians public static function absoluteDifference(GaussianDistribution $left, GaussianDistribution $right) { @@ -130,43 +117,41 @@ class GaussianDistribution { return GaussianDistribution::absoluteDifference($left, $right); } - + public static function logProductNormalization(GaussianDistribution $left, GaussianDistribution $right) { - if (($left->_precision == 0) || ($right->_precision == 0)) - { + if (($left->_precision == 0) || ($right->_precision == 0)) { return 0; } $varianceSum = $left->_variance + $right->_variance; $meanDifference = $left->_mean - $right->_mean; - $logSqrt2Pi = log(sqrt(2*M_PI)); - return -$logSqrt2Pi - (log($varianceSum)/2.0) - (square($meanDifference)/(2.0*$varianceSum)); + $logSqrt2Pi = log(sqrt(2 * M_PI)); + return -$logSqrt2Pi - (log($varianceSum) / 2.0) - (BasicMatch::square($meanDifference) / (2.0 * $varianceSum)); } - + public static function divide(GaussianDistribution $numerator, GaussianDistribution $denominator) { return GaussianDistribution::fromPrecisionMean($numerator->_precisionMean - $denominator->_precisionMean, - $numerator->_precision - $denominator->_precision); + $numerator->_precision - $denominator->_precision); } public static function logRatioNormalization(GaussianDistribution $numerator, GaussianDistribution $denominator) { - if (($numerator->_precision == 0) || ($denominator->_precision == 0)) - { + if (($numerator->_precision == 0) || ($denominator->_precision == 0)) { return 0; } $varianceDifference = $denominator->_variance - $numerator->_variance; $meanDifference = $numerator->_mean - $denominator->_mean; - $logSqrt2Pi = log(sqrt(2*M_PI)); + $logSqrt2Pi = log(sqrt(2 * M_PI)); - return log($denominator->_variance) + $logSqrt2Pi - log($varianceDifference)/2.0 + - square($meanDifference)/(2*$varianceDifference); + return log($denominator->_variance) + $logSqrt2Pi - log($varianceDifference) / 2.0 + + BasicMatch::square($meanDifference) / (2 * $varianceDifference); } - + public static function at($x, $mean = 0.0, $standardDeviation = 1.0) { // See http://mathworld.wolfram.com/NormalDistribution.html @@ -174,93 +159,89 @@ class GaussianDistribution // P(x) = ------------------- * e // stdDev * sqrt(2*pi) - $multiplier = 1.0/($standardDeviation*sqrt(2*M_PI)); - $expPart = exp((-1.0*square($x - $mean))/(2*square($standardDeviation))); - $result = $multiplier*$expPart; + $multiplier = 1.0 / ($standardDeviation * sqrt(2 * M_PI)); + $expPart = exp((-1.0 * BasicMatch::square($x - $mean)) / (2 * BasicMatch::square($standardDeviation))); + $result = $multiplier * $expPart; return $result; } public static function cumulativeTo($x, $mean = 0.0, $standardDeviation = 1.0) { $invsqrt2 = -0.707106781186547524400844362104; - $result = GaussianDistribution::errorFunctionCumulativeTo($invsqrt2*$x); - return 0.5*$result; + $result = GaussianDistribution::errorFunctionCumulativeTo($invsqrt2 * $x); + return 0.5 * $result; } - + private static function errorFunctionCumulativeTo($x) { // Derived from page 265 of Numerical Recipes 3rd Edition $z = abs($x); - $t = 2.0/(2.0 + $z); - $ty = 4*$t - 2; + $t = 2.0 / (2.0 + $z); + $ty = 4 * $t - 2; $coefficients = array( - -1.3026537197817094, - 6.4196979235649026e-1, - 1.9476473204185836e-2, - -9.561514786808631e-3, - -9.46595344482036e-4, - 3.66839497852761e-4, - 4.2523324806907e-5, - -2.0278578112534e-5, - -1.624290004647e-6, - 1.303655835580e-6, - 1.5626441722e-8, - -8.5238095915e-8, - 6.529054439e-9, - 5.059343495e-9, - -9.91364156e-10, - -2.27365122e-10, - 9.6467911e-11, - 2.394038e-12, - -6.886027e-12, - 8.94487e-13, - 3.13092e-13, - -1.12708e-13, - 3.81e-16, - 7.106e-15, - -1.523e-15, - -9.4e-17, - 1.21e-16, - -2.8e-17 ); + -1.3026537197817094, + 6.4196979235649026e-1, + 1.9476473204185836e-2, + -9.561514786808631e-3, + -9.46595344482036e-4, + 3.66839497852761e-4, + 4.2523324806907e-5, + -2.0278578112534e-5, + -1.624290004647e-6, + 1.303655835580e-6, + 1.5626441722e-8, + -8.5238095915e-8, + 6.529054439e-9, + 5.059343495e-9, + -9.91364156e-10, + -2.27365122e-10, + 9.6467911e-11, + 2.394038e-12, + -6.886027e-12, + 8.94487e-13, + 3.13092e-13, + -1.12708e-13, + 3.81e-16, + 7.106e-15, + -1.523e-15, + -9.4e-17, + 1.21e-16, + -2.8e-17); $ncof = count($coefficients); $d = 0.0; $dd = 0.0; - for ($j = $ncof - 1; $j > 0; $j--) - { + for ($j = $ncof - 1; $j > 0; $j--) { $tmp = $d; - $d = $ty*$d - $dd + $coefficients[$j]; + $d = $ty * $d - $dd + $coefficients[$j]; $dd = $tmp; } - $ans = $t*exp(-$z*$z + 0.5*($coefficients[0] + $ty*$d) - $dd); + $ans = $t * exp(-$z * $z + 0.5 * ($coefficients[0] + $ty * $d) - $dd); return ($x >= 0.0) ? $ans : (2.0 - $ans); } - + private static function inverseErrorFunctionCumulativeTo($p) { // From page 265 of numerical recipes - if ($p >= 2.0) - { + if ($p >= 2.0) { return -100; } - if ($p <= 0.0) - { + if ($p <= 0.0) { return 100; } $pp = ($p < 1.0) ? $p : 2 - $p; - $t = sqrt(-2*log($pp/2.0)); // Initial guess - $x = -0.70711*((2.30753 + $t*0.27061)/(1.0 + $t*(0.99229 + $t*0.04481)) - $t); + $t = sqrt(-2 * log($pp / 2.0)); // Initial guess + $x = -0.70711 * ((2.30753 + $t * 0.27061) / (1.0 + $t * (0.99229 + $t * 0.04481)) - $t); - for ($j = 0; $j < 2; $j++) - { + for ($j = 0; $j < 2; $j++) { $err = GaussianDistribution::errorFunctionCumulativeTo($x) - $pp; - $x += $err/(1.12837916709551257*exp(-square($x)) - $x*$err); // Halley + $x += $err / (1.12837916709551257 * exp(-BasicMatch::square($x)) - $x * $err); // Halley } return ($p < 1.0) ? $x : -$x; @@ -269,12 +250,11 @@ class GaussianDistribution public static function inverseCumulativeTo($x, $mean = 0.0, $standardDeviation = 1.0) { // From numerical recipes, page 320 - return $mean - sqrt(2)*$standardDeviation*GaussianDistribution::inverseErrorFunctionCumulativeTo(2*$x); + return $mean - sqrt(2) * $standardDeviation * GaussianDistribution::inverseErrorFunctionCumulativeTo(2 * $x); } - + public function __toString() { return sprintf("mean=%.4f standardDeviation=%.4f", $this->_mean, $this->_standardDeviation); - } -} -?> \ No newline at end of file + } +} \ No newline at end of file diff --git a/src/Numerics/IdentityMatrix.php b/src/Numerics/IdentityMatrix.php new file mode 100644 index 0000000..65d2596 --- /dev/null +++ b/src/Numerics/IdentityMatrix.php @@ -0,0 +1,9 @@ +setValue($currentRow, $currentCol, $diagonalValues[$currentRow]); - } - else - { - $this->setValue($currentRow, $currentCol, 0); - } - } - } - } -} - -class IdentityMatrix extends DiagonalMatrix -{ - public function __construct($rows) - { - parent::__construct(\array_fill(0, $rows, 1)); - } -} -?> +} \ No newline at end of file diff --git a/src/Numerics/Range.php b/src/Numerics/Range.php index 544c57c..73452c6 100644 --- a/src/Numerics/Range.php +++ b/src/Numerics/Range.php @@ -1,10 +1,10 @@ -_min <= $value) && ($value <= $this->_max); } -} - -?> +} \ No newline at end of file diff --git a/src/Numerics/SquareMatrix.php b/src/Numerics/SquareMatrix.php new file mode 100644 index 0000000..d27cb46 --- /dev/null +++ b/src/Numerics/SquareMatrix.php @@ -0,0 +1,22 @@ + \ No newline at end of file +} \ No newline at end of file diff --git a/src/PartialPlay.php b/src/PartialPlay.php index 4d193e7..868290e 100644 --- a/src/PartialPlay.php +++ b/src/PartialPlay.php @@ -1,7 +1,4 @@ - +} \ No newline at end of file diff --git a/src/Player.php b/src/Player.php index b83fb97..5af87e5 100644 --- a/src/Player.php +++ b/src/Player.php @@ -1,9 +1,4 @@ -_Id; return $this->_Id; } - + /** * Indicates the percent of the time the player should be weighted where 0.0 indicates the player didn't play and 1.0 indicates the player played 100% of the time. */ @@ -52,7 +47,7 @@ class Player implements ISupportPartialPlay, ISupportPartialUpdate { return $this->_PartialPlayPercentage; } - + /** * Indicated how much of a skill update a player should receive where 0.0 represents no update and 1.0 represents 100% of the update. */ @@ -60,15 +55,13 @@ class Player implements ISupportPartialPlay, ISupportPartialUpdate { return $this->_PartialUpdatePercentage; } - + public function __toString() { - if ($this->_Id != null) - { + if ($this->_Id != null) { return (string)$this->_Id; } return parent::__toString(); } -} -?> +} \ No newline at end of file diff --git a/src/PlayersRange.php b/src/PlayersRange.php index 7186ce7..6efa4d9 100644 --- a/src/PlayersRange.php +++ b/src/PlayersRange.php @@ -1,9 +1,6 @@ - \ No newline at end of file +} \ No newline at end of file diff --git a/src/RankSorter.php b/src/RankSorter.php index cba00f9..13aa0d9 100644 --- a/src/RankSorter.php +++ b/src/RankSorter.php @@ -1,6 +1,4 @@ - \ No newline at end of file +} \ No newline at end of file diff --git a/src/Rating.php b/src/Rating.php index 99f1791..72f9e58 100644 --- a/src/Rating.php +++ b/src/Rating.php @@ -1,12 +1,12 @@ -_mean; + return $this->_mean; } /** @@ -45,27 +45,28 @@ class Rating */ public function getConservativeRating() { - return $this->_mean - $this->_conservativeStandardDeviationMultiplier*$this->_standardDeviation; + return $this->_mean - $this->_conservativeStandardDeviationMultiplier * $this->_standardDeviation; } public function getPartialUpdate(Rating $prior, Rating $fullPosterior, $updatePercentage) { $priorGaussian = new GaussianDistribution($prior->getMean(), $prior->getStandardDeviation()); - $posteriorGaussian = new GaussianDistribution($fullPosterior->getMean(), $fullPosterior.getStandardDeviation()); + $posteriorGaussian = new GaussianDistribution($fullPosterior->getMean(), $fullPosterior . getStandardDeviation()); // From a clarification email from Ralf Herbrich: // "the idea is to compute a linear interpolation between the prior and posterior skills of each player // ... in the canonical space of parameters" $precisionDifference = $posteriorGaussian->getPrecision() - $priorGaussian->getPrecision(); - $partialPrecisionDifference = $updatePercentage*$precisionDifference; + $partialPrecisionDifference = $updatePercentage * $precisionDifference; - $precisionMeanDifference = $posteriorGaussian->getPrecisionMean() - $priorGaussian.getPrecisionMean(); - $partialPrecisionMeanDifference = $updatePercentage*$precisionMeanDifference; + $precisionMeanDifference = $posteriorGaussian->getPrecisionMean() - $priorGaussian . getPrecisionMean(); + $partialPrecisionMeanDifference = $updatePercentage * $precisionMeanDifference; $partialPosteriorGaussion = GaussianDistribution::fromPrecisionMean( $priorGaussian->getPrecisionMean() + $partialPrecisionMeanDifference, - $priorGaussian->getPrecision() + $partialPrecisionDifference); + $priorGaussian->getPrecision() + $partialPrecisionDifference + ); return new Rating($partialPosteriorGaussion->getMean(), $partialPosteriorGaussion->getStandardDeviation(), $prior->_conservativeStandardDeviationMultiplier); } @@ -73,7 +74,5 @@ class Rating public function __toString() { return sprintf("mean=%.4f, standardDeviation=%.4f", $this->_mean, $this->_standardDeviation); - } -} - -?> \ No newline at end of file + } +} \ No newline at end of file diff --git a/src/RatingContainer.php b/src/RatingContainer.php index 95ddf31..1977309 100644 --- a/src/RatingContainer.php +++ b/src/RatingContainer.php @@ -1,9 +1,4 @@ -_playerToRating->setValue($player, $rating); } - + public function &getAllPlayers() { $allPlayers = &$this->_playerToRating->getAllKeys(); return $allPlayers; } - + public function &getAllRatings() { $allRatings = &$this->_playerToRating->getAllValues(); @@ -40,6 +35,5 @@ class RatingContainer public function count() { return $this->_playerToRating->count(); - } -} -?> + } +} \ No newline at end of file diff --git a/src/SkillCalculator.php b/src/SkillCalculator.php index d7a40f9..a526cdf 100644 --- a/src/SkillCalculator.php +++ b/src/SkillCalculator.php @@ -1,11 +1,8 @@ -_supportedOptions = $supportedOptions; @@ -23,9 +20,10 @@ abstract class SkillCalculator /** * Calculates new ratings based on the prior ratings and team ranks. - * @param $gameInfo Parameters for the game. - * @param $teams A mapping of team players and their ratings. - * @param $teamRanks The ranks of the teams where 1 is first place. For a tie, repeat the number (e.g. 1, 2, 2). + * @param GameInfo $gameInfo Parameters for the game. + * @param array $teamsOfPlayerToRatings A mapping of team players and their ratings. + * @param array $teamRanks The ranks of the teams where 1 is first place. For a tie, repeat the number (e.g. 1, 2, 2). + * * @return All the players and their new ratings. */ public abstract function calculateNewRatings(GameInfo &$gameInfo, @@ -34,18 +32,18 @@ abstract class SkillCalculator /** * Calculates the match quality as the likelihood of all teams drawing. - * - * @param $gameInfo Parameters for the game. - * @param $teams A mapping of team players and their ratings. + * + * @param GameInfo $gameInfo Parameters for the game. + * @param array $teamsOfPlayerToRatings A mapping of team players and their ratings. * @return The quality of the match between the teams as a percentage (0% = bad, 100% = well matched). */ public abstract function calculateMatchQuality(GameInfo &$gameInfo, array &$teamsOfPlayerToRatings); public function isSupported($option) - { - return ($this->_supportedOptions & $option) == $option; - } + { + return ($this->_supportedOptions & $option) == $option; + } protected function validateTeamCountAndPlayersCountPerTeam(array &$teamsOfPlayerToRatings) { @@ -56,20 +54,17 @@ abstract class SkillCalculator array &$teams, TeamsRange &$totalTeams, PlayersRange &$playersPerTeam) - { + { $countOfTeams = 0; - - foreach ($teams as $currentTeam) - { - if (!$playersPerTeam->isInRange($currentTeam->count())) - { - throw new \Exception("Player count is not in range"); + + foreach ($teams as $currentTeam) { + if (!$playersPerTeam->isInRange($currentTeam->count())) { + throw new Exception("Player count is not in range"); } $countOfTeams++; } - if (!$totalTeams->isInRange($countOfTeams)) - { + if (!$totalTeams->isInRange($countOfTeams)) { throw new Exception("Team range is not in range"); } } @@ -80,5 +75,4 @@ class SkillCalculatorSupportedOptions const NONE = 0x00; const PARTIAL_PLAY = 0x01; const PARTIAL_UPDATE = 0x02; -} -?> \ No newline at end of file +} \ No newline at end of file diff --git a/src/Team.php b/src/Team.php index 8b5f80e..83e93f1 100644 --- a/src/Team.php +++ b/src/Team.php @@ -1,9 +1,4 @@ -addPlayer($player, $rating); } @@ -22,6 +17,4 @@ class Team extends RatingContainer $this->setRating($player, $rating); return $this; } -} - -?> +} \ No newline at end of file diff --git a/src/Teams.php b/src/Teams.php index 35784ca..cfa3551 100644 --- a/src/Teams.php +++ b/src/Teams.php @@ -1,11 +1,10 @@ - +} \ No newline at end of file diff --git a/src/TeamsRange.php b/src/TeamsRange.php index d895a3f..a9f1e62 100644 --- a/src/TeamsRange.php +++ b/src/TeamsRange.php @@ -1,9 +1,6 @@ - \ No newline at end of file +} \ No newline at end of file diff --git a/src/TrueSkill/DrawMargin.php b/src/TrueSkill/DrawMargin.php index 12eb777..4b1f968 100644 --- a/src/TrueSkill/DrawMargin.php +++ b/src/TrueSkill/DrawMargin.php @@ -1,9 +1,6 @@ - \ No newline at end of file +} \ No newline at end of file diff --git a/src/TrueSkill/FactorGraphTrueSkillCalculator.php b/src/TrueSkill/FactorGraphTrueSkillCalculator.php index c10b8ca..6a23fa5 100644 --- a/src/TrueSkill/FactorGraphTrueSkillCalculator.php +++ b/src/TrueSkill/FactorGraphTrueSkillCalculator.php @@ -1,28 +1,13 @@ -buildGraph(); $factorGraph->runSchedule(); - + $probabilityOfOutcome = $factorGraph->getProbabilityOfRanking(); return $factorGraph->getUpdatedRatings(); @@ -70,17 +55,19 @@ class FactorGraphTrueSkillCalculator extends SkillCalculator $playerTeamAssignmentsMatrix = $this->createPlayerTeamAssignmentMatrix($teamAssignmentsList, $meanVector->getRowCount()); $playerTeamAssignmentsMatrixTranspose = $playerTeamAssignmentsMatrix->getTranspose(); - $betaSquared = square($gameInfo->getBeta()); + $betaSquared = BasicMatch::square($gameInfo->getBeta()); $start = Matrix::multiply($meanVectorTranspose, $playerTeamAssignmentsMatrix); + $aTa = Matrix::multiply( - Matrix::scalarMultiply($betaSquared, - $playerTeamAssignmentsMatrixTranspose), - $playerTeamAssignmentsMatrix); + Matrix::scalarMultiply($betaSquared, $playerTeamAssignmentsMatrixTranspose), + $playerTeamAssignmentsMatrix + ); $aTSA = Matrix::multiply( - Matrix::multiply($playerTeamAssignmentsMatrixTranspose, $skillsMatrix), - $playerTeamAssignmentsMatrix); + Matrix::multiply($playerTeamAssignmentsMatrixTranspose, $skillsMatrix), + $playerTeamAssignmentsMatrix + ); $middle = Matrix::add($aTa, $aTSA); @@ -104,10 +91,9 @@ class FactorGraphTrueSkillCalculator extends SkillCalculator { // A simple vector of all the player means. return new Vector(self::getPlayerRatingValues($teamAssignmentsList, - function($rating) - { - return $rating->getMean(); - })); + function ($rating) { + return $rating->getMean(); + })); } private static function getPlayerCovarianceMatrix(array &$teamAssignmentsList) @@ -115,11 +101,10 @@ class FactorGraphTrueSkillCalculator extends SkillCalculator // This is a square matrix whose diagonal values represent the variance (square of standard deviation) of all // players. return new DiagonalMatrix( - self::getPlayerRatingValues($teamAssignmentsList, - function($rating) - { - return square($rating->getStandardDeviation()); - })); + self::getPlayerRatingValues($teamAssignmentsList, + function ($rating) { + return BasicMatch::square($rating->getStandardDeviation()); + })); } // Helper function that gets a list of values for all player ratings @@ -128,10 +113,8 @@ class FactorGraphTrueSkillCalculator extends SkillCalculator { $playerRatingValues = array(); - foreach ($teamAssignmentsList as $currentTeam) - { - foreach ($currentTeam->getAllRatings() as $currentRating) - { + foreach ($teamAssignmentsList as $currentTeam) { + foreach ($currentTeam->getAllRatings() as $currentRating) { $playerRatingValues[] = $playerRatingFunction($currentRating); } } @@ -164,16 +147,14 @@ class FactorGraphTrueSkillCalculator extends SkillCalculator $currentColumn = 0; - for ($i = 0; $i < $teamAssignmentsListCount - 1; $i++) - { + for ($i = 0; $i < $teamAssignmentsListCount - 1; $i++) { $currentTeam = $teamAssignmentsList[$i]; // Need to add in 0's for all the previous players, since they're not // on this team $playerAssignments[$currentColumn] = ($totalPreviousPlayers > 0) ? \array_fill(0, $totalPreviousPlayers, 0) : array(); - foreach ($currentTeam->getAllPlayers() as $currentPlayer) - { + foreach ($currentTeam->getAllPlayers() as $currentPlayer) { $playerAssignments[$currentColumn][] = PartialPlay::getPartialPlayPercentage($currentPlayer); // indicates the player is on the team $totalPreviousPlayers++; @@ -182,15 +163,13 @@ class FactorGraphTrueSkillCalculator extends SkillCalculator $rowsRemaining = $totalPlayers - $totalPreviousPlayers; $nextTeam = $teamAssignmentsList[$i + 1]; - foreach ($nextTeam->getAllPlayers() as $nextTeamPlayer) - { + foreach ($nextTeam->getAllPlayers() as $nextTeamPlayer) { // Add a -1 * playing time to represent the difference $playerAssignments[$currentColumn][] = -1 * PartialPlay::getPartialPlayPercentage($nextTeamPlayer); $rowsRemaining--; } - for ($ixAdditionalRow = 0; $ixAdditionalRow < $rowsRemaining; $ixAdditionalRow++) - { + for ($ixAdditionalRow = 0; $ixAdditionalRow < $rowsRemaining; $ixAdditionalRow++) { // Pad with zeros $playerAssignments[$currentColumn][] = 0; } @@ -202,6 +181,4 @@ class FactorGraphTrueSkillCalculator extends SkillCalculator return $playerTeamAssignmentsMatrix; } -} - -?> +} \ No newline at end of file diff --git a/src/TrueSkill/Factors/GaussianFactor.php b/src/TrueSkill/Factors/GaussianFactor.php index ec3a98e..4032f68 100644 --- a/src/TrueSkill/Factors/GaussianFactor.php +++ b/src/TrueSkill/Factors/GaussianFactor.php @@ -1,16 +1,9 @@ - +} \ No newline at end of file diff --git a/src/TrueSkill/Factors/GaussianGreaterThanFactor.php b/src/TrueSkill/Factors/GaussianGreaterThanFactor.php index f97c96d..db96a59 100644 --- a/src/TrueSkill/Factors/GaussianGreaterThanFactor.php +++ b/src/TrueSkill/Factors/GaussianGreaterThanFactor.php @@ -1,13 +1,6 @@ -getValue(); $messageFromVariable = GaussianDistribution::divide($marginal, $message); return -GaussianDistribution::logProductNormalization($messageFromVariable, $message) - + - log( - GaussianDistribution::cumulativeTo(($messageFromVariable->getMean() - $this->_epsilon)/ - $messageFromVariable->getStandardDeviation())); + + + log( + GaussianDistribution::cumulativeTo(($messageFromVariable->getMean() - $this->_epsilon) / + $messageFromVariable->getStandardDeviation())); } @@ -54,24 +47,24 @@ class GaussianGreaterThanFactor extends GaussianFactor $sqrtC = sqrt($c); - $dOnSqrtC = $d/$sqrtC; + $dOnSqrtC = $d / $sqrtC; - $epsilsonTimesSqrtC = $this->_epsilon*$sqrtC; + $epsilsonTimesSqrtC = $this->_epsilon * $sqrtC; $d = $messageFromVar->getPrecisionMean(); $denom = 1.0 - TruncatedGaussianCorrectionFunctions::wExceedsMargin($dOnSqrtC, $epsilsonTimesSqrtC); - $newPrecision = $c/$denom; + $newPrecision = $c / $denom; $newPrecisionMean = ($d + - $sqrtC* - TruncatedGaussianCorrectionFunctions::vExceedsMargin($dOnSqrtC, $epsilsonTimesSqrtC))/ - $denom; + $sqrtC * + TruncatedGaussianCorrectionFunctions::vExceedsMargin($dOnSqrtC, $epsilsonTimesSqrtC)) / + $denom; $newMarginal = GaussianDistribution::fromPrecisionMean($newPrecisionMean, $newPrecision); $newMessage = GaussianDistribution::divide( - GaussianDistribution::multiply($oldMessage, $newMarginal), - $oldMarginal); + GaussianDistribution::multiply($oldMessage, $newMarginal), + $oldMarginal); // Update the message and marginal $message->setValue($newMessage); @@ -81,5 +74,4 @@ class GaussianGreaterThanFactor extends GaussianFactor // Return the difference in the new marginal return GaussianDistribution::subtract($newMarginal, $oldMarginal); } -} -?> +} \ No newline at end of file diff --git a/src/TrueSkill/Factors/GaussianLikelihoodFactor.php b/src/TrueSkill/Factors/GaussianLikelihoodFactor.php index 5a1b393..a917d74 100644 --- a/src/TrueSkill/Factors/GaussianLikelihoodFactor.php +++ b/src/TrueSkill/Factors/GaussianLikelihoodFactor.php @@ -1,18 +1,13 @@ -_precision = 1.0/$betaSquared; + $this->_precision = 1.0 / $betaSquared; $this->createVariableToMessageBinding($variable1); $this->createVariableToMessageBinding($variable2); } @@ -33,24 +28,24 @@ class GaussianLikelihoodFactor extends GaussianFactor $messages = &$this->getMessages(); return GaussianDistribution::logRatioNormalization( - $vars[0]->getValue(), - $messages[0]->getValue()); + $vars[0]->getValue(), + $messages[0]->getValue()); } private function updateHelper(Message &$message1, Message &$message2, Variable &$variable1, Variable &$variable2) - { + { $message1Value = clone $message1->getValue(); - $message2Value = clone $message2->getValue(); - + $message2Value = clone $message2->getValue(); + $marginal1 = clone $variable1->getValue(); $marginal2 = clone $variable2->getValue(); - $a = $this->_precision/($this->_precision + $marginal2->getPrecision() - $message2Value->getPrecision()); + $a = $this->_precision / ($this->_precision + $marginal2->getPrecision() - $message2Value->getPrecision()); $newMessage = GaussianDistribution::fromPrecisionMean( - $a*($marginal2->getPrecisionMean() - $message2Value->getPrecisionMean()), - $a*($marginal2->getPrecision() - $message2Value->getPrecision())); + $a * ($marginal2->getPrecisionMean() - $message2Value->getPrecisionMean()), + $a * ($marginal2->getPrecision() - $message2Value->getPrecision())); $oldMarginalWithoutMessage = GaussianDistribution::divide($marginal1, $message1Value); @@ -68,20 +63,17 @@ class GaussianLikelihoodFactor extends GaussianFactor public function updateMessageIndex($messageIndex) { $messages = &$this->getMessages(); - $vars = &$this->getVariables(); + $vars = &$this->getVariables(); - switch ($messageIndex) - { + switch ($messageIndex) { case 0: return $this->updateHelper($messages[0], $messages[1], - $vars[0], $vars[1]); + $vars[0], $vars[1]); case 1: return $this->updateHelper($messages[1], $messages[0], - $vars[1], $vars[0]); + $vars[1], $vars[0]); default: throw new Exception(); } } -} - -?> +} \ No newline at end of file diff --git a/src/TrueSkill/Factors/GaussianPriorFactor.php b/src/TrueSkill/Factors/GaussianPriorFactor.php index cf278fe..22c6d99 100644 --- a/src/TrueSkill/Factors/GaussianPriorFactor.php +++ b/src/TrueSkill/Factors/GaussianPriorFactor.php @@ -1,14 +1,8 @@ -_newMessage = new GaussianDistribution($mean, sqrt($variance)); $newMessage = new Message(GaussianDistribution::fromPrecisionMean(0, 0), - sprintf("message from %s to %s", $this, $variable)); + sprintf("message from %s to %s", $this, $variable)); $this->createVariableToMessageBindingWithMessage($variable, $newMessage); } @@ -43,6 +37,4 @@ class GaussianPriorFactor extends GaussianFactor $message->setValue($newMessage); return GaussianDistribution::subtract($oldMarginal, $newMarginal); } -} - -?> +} \ No newline at end of file diff --git a/src/TrueSkill/Factors/GaussianWeightedSumFactor.php b/src/TrueSkill/Factors/GaussianWeightedSumFactor.php index d2a941e..4173019 100644 --- a/src/TrueSkill/Factors/GaussianWeightedSumFactor.php +++ b/src/TrueSkill/Factors/GaussianWeightedSumFactor.php @@ -1,21 +1,14 @@ -_weights[0] = \array_fill(0, count($variableWeights), 0); - - for($i = 0; $i < $variableWeightsLength; $i++) - { + + for ($i = 0; $i < $variableWeightsLength; $i++) { $weight = &$variableWeights[$i]; $this->_weights[0][$i] = $weight; - $this->_weightsSquared[0][$i] = square($weight); + $this->_weightsSquared[0][$i] = BasicMatch::square($weight); } $variablesToSumLength = count($variablesToSum); // 0..n-1 $this->_variableIndexOrdersForWeights[0] = array(); - for($i = 0; $i < ($variablesToSumLength + 1); $i++) - { + for ($i = 0; $i < ($variablesToSumLength + 1); $i++) { $this->_variableIndexOrdersForWeights[0][] = $i; } @@ -62,10 +53,9 @@ class GaussianWeightedSumFactor extends GaussianFactor // By convention, we'll put the v_0 term at the end $weightsLength = $variableWeightsLength + 1; - for ($weightsIndex = 1; $weightsIndex < $weightsLength; $weightsIndex++) - { + for ($weightsIndex = 1; $weightsIndex < $weightsLength; $weightsIndex++) { $currentWeights = \array_fill(0, $variableWeightsLength, 0); - + $variableIndices = \array_fill(0, $variableWeightsLength + 1, 0); $variableIndices[0] = $weightsIndex; @@ -73,42 +63,38 @@ class GaussianWeightedSumFactor extends GaussianFactor // keep a single variable to keep track of where we are in the array. // This is helpful since we skip over one of the spots - $currentDestinationWeightIndex = 0; + $currentDestinationWeightIndex = 0; for ($currentWeightSourceIndex = 0; $currentWeightSourceIndex < $variableWeightsLength; - $currentWeightSourceIndex++) - { - if ($currentWeightSourceIndex == ($weightsIndex - 1)) - { + $currentWeightSourceIndex++) { + if ($currentWeightSourceIndex == ($weightsIndex - 1)) { continue; } - $currentWeight = (-$variableWeights[$currentWeightSourceIndex]/$variableWeights[$weightsIndex - 1]); + $currentWeight = (-$variableWeights[$currentWeightSourceIndex] / $variableWeights[$weightsIndex - 1]); - if ($variableWeights[$weightsIndex - 1] == 0) - { + if ($variableWeights[$weightsIndex - 1] == 0) { // HACK: Getting around division by zero $currentWeight = 0; } $currentWeights[$currentDestinationWeightIndex] = $currentWeight; - $currentWeightsSquared[$currentDestinationWeightIndex] = $currentWeight*$currentWeight; + $currentWeightsSquared[$currentDestinationWeightIndex] = $currentWeight * $currentWeight; $variableIndices[$currentDestinationWeightIndex + 1] = $currentWeightSourceIndex + 1; $currentDestinationWeightIndex++; } // And the final one - $finalWeight = 1.0/$variableWeights[$weightsIndex - 1]; + $finalWeight = 1.0 / $variableWeights[$weightsIndex - 1]; - if ($variableWeights[$weightsIndex - 1] == 0) - { + if ($variableWeights[$weightsIndex - 1] == 0) { // HACK: Getting around division by zero $finalWeight = 0; } $currentWeights[$currentDestinationWeightIndex] = $finalWeight; - $currentWeightsSquared[$currentDestinationWeightIndex] = square($finalWeight); + $currentWeightsSquared[$currentDestinationWeightIndex] = BasicMatch::square($finalWeight); $variableIndices[count($variableWeights)] = 0; $this->_variableIndexOrdersForWeights[] = $variableIndices; @@ -118,11 +104,10 @@ class GaussianWeightedSumFactor extends GaussianFactor $this->createVariableToMessageBinding($sumVariable); - foreach ($variablesToSum as &$currentVariable) - { + foreach ($variablesToSum as &$currentVariable) { $localCurrentVariable = &$currentVariable; $this->createVariableToMessageBinding($localCurrentVariable); - } + } } public function getLogNormalization() @@ -134,8 +119,7 @@ class GaussianWeightedSumFactor extends GaussianFactor // We start at 1 since offset 0 has the sum $varCount = count($vars); - for ($i = 1; $i < $varCount; $i++) - { + for ($i = 1; $i < $varCount; $i++) { $result += GaussianDistribution::logRatioNormalization($vars[$i]->getValue(), $messages[$i]->getValue()); } @@ -160,30 +144,29 @@ class GaussianWeightedSumFactor extends GaussianFactor $weightsSquaredLength = count($weightsSquared); - for ($i = 0; $i < $weightsSquaredLength; $i++) - { + for ($i = 0; $i < $weightsSquaredLength; $i++) { // These flow directly from the paper - $inverseOfNewPrecisionSum += $weightsSquared[$i]/ - ($variables[$i + 1]->getValue()->getPrecision() - $messages[$i + 1]->getValue()->getPrecision()); + $inverseOfNewPrecisionSum += $weightsSquared[$i] / + ($variables[$i + 1]->getValue()->getPrecision() - $messages[$i + 1]->getValue()->getPrecision()); $diff = GaussianDistribution::divide($variables[$i + 1]->getValue(), $messages[$i + 1]->getValue()); - $anotherInverseOfNewPrecisionSum += $weightsSquared[$i]/$diff->getPrecision(); + $anotherInverseOfNewPrecisionSum += $weightsSquared[$i] / $diff->getPrecision(); $weightedMeanSum += $weights[$i] - * - ($variables[$i + 1]->getValue()->getPrecisionMean() - $messages[$i + 1]->getValue()->getPrecisionMean()) - / - ($variables[$i + 1]->getValue()->getPrecision() - $messages[$i + 1]->getValue()->getPrecision()); + * + ($variables[$i + 1]->getValue()->getPrecisionMean() - $messages[$i + 1]->getValue()->getPrecisionMean()) + / + ($variables[$i + 1]->getValue()->getPrecision() - $messages[$i + 1]->getValue()->getPrecision()); - $anotherWeightedMeanSum += $weights[$i]*$diff->getPrecisionMean()/$diff->getPrecision(); + $anotherWeightedMeanSum += $weights[$i] * $diff->getPrecisionMean() / $diff->getPrecision(); } - $newPrecision = 1.0/$inverseOfNewPrecisionSum; - $anotherNewPrecision = 1.0/$anotherInverseOfNewPrecisionSum; + $newPrecision = 1.0 / $inverseOfNewPrecisionSum; + $anotherNewPrecision = 1.0 / $anotherInverseOfNewPrecisionSum; - $newPrecisionMean = $newPrecision*$weightedMeanSum; - $anotherNewPrecisionMean = $anotherNewPrecision*$anotherWeightedMeanSum; + $newPrecisionMean = $newPrecision * $weightedMeanSum; + $anotherNewPrecisionMean = $anotherNewPrecision * $anotherWeightedMeanSum; $newMessage = GaussianDistribution::fromPrecisionMean($newPrecisionMean, $newPrecision); $oldMarginalWithoutMessage = GaussianDistribution::divide($marginal0, $message0); @@ -201,7 +184,7 @@ class GaussianWeightedSumFactor extends GaussianFactor } public function updateMessageIndex($messageIndex) - { + { $allMessages = &$this->getMessages(); $allVariables = &$this->getVariables(); @@ -216,16 +199,15 @@ class GaussianWeightedSumFactor extends GaussianFactor // order as the weights. Thankfully, the weights and messages share the same index numbers, // so we just need to make sure they're consistent $allMessagesCount = count($allMessages); - for ($i = 0; $i < $allMessagesCount; $i++) - { + for ($i = 0; $i < $allMessagesCount; $i++) { $updatedMessages[] = &$allMessages[$indicesToUse[$i]]; $updatedVariables[] = &$allVariables[$indicesToUse[$i]]; } - + return $this->updateHelper($this->_weights[$messageIndex], - $this->_weightsSquared[$messageIndex], - $updatedMessages, - $updatedVariables); + $this->_weightsSquared[$messageIndex], + $updatedMessages, + $updatedVariables); } private static function createName($sumVariable, $variablesToSum, $weights) @@ -233,14 +215,12 @@ class GaussianWeightedSumFactor extends GaussianFactor // TODO: Perf? Use PHP equivalent of StringBuilder? implode on arrays? $result = (string)$sumVariable; $result .= ' = '; - + $totalVars = count($variablesToSum); - for($i = 0; $i < $totalVars; $i++) - { + for ($i = 0; $i < $totalVars; $i++) { $isFirst = ($i == 0); - - if($isFirst && ($weights[$i] < 0)) - { + + if ($isFirst && ($weights[$i] < 0)) { $result .= '-'; } @@ -249,24 +229,18 @@ class GaussianWeightedSumFactor extends GaussianFactor $result .= "*["; $result .= (string)$variablesToSum[$i]; $result .= ']'; - + $isLast = ($i == ($totalVars - 1)); - - if(!$isLast) - { - if($weights[$i + 1] >= 0) - { + + if (!$isLast) { + if ($weights[$i + 1] >= 0) { $result .= ' + '; - } - else - { + } else { $result .= ' - '; } - } + } } - + return $result; } -} - -?> +} \ No newline at end of file diff --git a/src/TrueSkill/Factors/GaussianWithinFactor.php b/src/TrueSkill/Factors/GaussianWithinFactor.php index 075afd4..e7c1956 100644 --- a/src/TrueSkill/Factors/GaussianWithinFactor.php +++ b/src/TrueSkill/Factors/GaussianWithinFactor.php @@ -1,13 +1,6 @@ -getMean(); $std = $messageFromVariable->getStandardDeviation(); - $z = GaussianDistribution::cumulativeTo(($this->_epsilon - $mean)/$std) - - - GaussianDistribution::cumulativeTo((-$this->_epsilon - $mean)/$std); + $z = GaussianDistribution::cumulativeTo(($this->_epsilon - $mean) / $std) + - + GaussianDistribution::cumulativeTo((-$this->_epsilon - $mean) / $std); return -GaussianDistribution::logProductNormalization($messageFromVariable, $message) + log($z); } @@ -55,22 +48,22 @@ class GaussianWithinFactor extends GaussianFactor $d = $messageFromVariable->getPrecisionMean(); $sqrtC = sqrt($c); - $dOnSqrtC = $d/$sqrtC; + $dOnSqrtC = $d / $sqrtC; - $epsilonTimesSqrtC = $this->_epsilon*$sqrtC; + $epsilonTimesSqrtC = $this->_epsilon * $sqrtC; $d = $messageFromVariable->getPrecisionMean(); $denominator = 1.0 - TruncatedGaussianCorrectionFunctions::wWithinMargin($dOnSqrtC, $epsilonTimesSqrtC); - $newPrecision = $c/$denominator; + $newPrecision = $c / $denominator; $newPrecisionMean = ($d + - $sqrtC* - TruncatedGaussianCorrectionFunctions::vWithinMargin($dOnSqrtC, $epsilonTimesSqrtC))/ - $denominator; + $sqrtC * + TruncatedGaussianCorrectionFunctions::vWithinMargin($dOnSqrtC, $epsilonTimesSqrtC)) / + $denominator; $newMarginal = GaussianDistribution::fromPrecisionMean($newPrecisionMean, $newPrecision); $newMessage = GaussianDistribution::divide( - GaussianDistribution::multiply($oldMessage, $newMarginal), - $oldMarginal); + GaussianDistribution::multiply($oldMessage, $newMarginal), + $oldMarginal); // Update the message and marginal $message->setValue($newMessage); @@ -79,6 +72,4 @@ class GaussianWithinFactor extends GaussianFactor // Return the difference in the new marginal return GaussianDistribution::subtract($newMarginal, $oldMarginal); } -} - -?> +} \ No newline at end of file diff --git a/src/TrueSkill/Layers/IteratedTeamDifferencesInnerLayer.php b/src/TrueSkill/Layers/IteratedTeamDifferencesInnerLayer.php index 50113d9..d66c412 100644 --- a/src/TrueSkill/Layers/IteratedTeamDifferencesInnerLayer.php +++ b/src/TrueSkill/Layers/IteratedTeamDifferencesInnerLayer.php @@ -1,11 +1,4 @@ -_TeamPerformancesToTeamPerformanceDifferencesLayer->getLocalFactors(), - $this->_TeamDifferencesComparisonLayer->getLocalFactors()); + array_merge($this->_TeamPerformancesToTeamPerformanceDifferencesLayer->getLocalFactors(), + $this->_TeamDifferencesComparisonLayer->getLocalFactors()); return $localFactors; } @@ -47,9 +40,8 @@ class IteratedTeamDifferencesInnerLayer extends TrueSkillFactorGraphLayer } public function createPriorSchedule() - { - switch (count($this->getInputVariablesGroups())) - { + { + switch (count($this->getInputVariablesGroups())) { case 0: case 1: throw new InvalidOperationException(); @@ -72,15 +64,15 @@ class IteratedTeamDifferencesInnerLayer extends TrueSkillFactorGraphLayer $innerSchedule = new ScheduleSequence( "inner schedule", array( - $loop, - new ScheduleStep( - "teamPerformanceToPerformanceDifferenceFactors[0] @ 1", - $firstDifferencesFactor, 1), - new ScheduleStep( - sprintf("teamPerformanceToPerformanceDifferenceFactors[teamTeamDifferences = %d - 1] @ 2", $totalTeamDifferences), - $lastDifferencesFactor, 2) - ) - ); + $loop, + new ScheduleStep( + "teamPerformanceToPerformanceDifferenceFactors[0] @ 1", + $firstDifferencesFactor, 1), + new ScheduleStep( + sprintf("teamPerformanceToPerformanceDifferenceFactors[teamTeamDifferences = %d - 1] @ 2", $totalTeamDifferences), + $lastDifferencesFactor, 2) + ) + ); return $innerSchedule; } @@ -93,15 +85,15 @@ class IteratedTeamDifferencesInnerLayer extends TrueSkillFactorGraphLayer $firstPerfToTeamDiff = &$teamPerformancesToTeamPerformanceDifferencesLayerLocalFactors[0]; $firstTeamDiffComparison = &$teamDifferencesComparisonLayerLocalFactors[0]; $itemsToSequence = array( - new ScheduleStep( - "send team perf to perf differences", - $firstPerfToTeamDiff, - 0), - new ScheduleStep( - "send to greater than or within factor", - $firstTeamDiffComparison, - 0) - ); + new ScheduleStep( + "send team perf to perf differences", + $firstPerfToTeamDiff, + 0), + new ScheduleStep( + "send to greater than or within factor", + $firstTeamDiffComparison, + 0) + ); return $this->scheduleSequence( $itemsToSequence, @@ -114,8 +106,7 @@ class IteratedTeamDifferencesInnerLayer extends TrueSkillFactorGraphLayer $forwardScheduleList = array(); - for ($i = 0; $i < $totalTeamDifferences - 1; $i++) - { + for ($i = 0; $i < $totalTeamDifferences - 1; $i++) { $teamPerformancesToTeamPerformanceDifferencesLayerLocalFactors = &$this->_TeamPerformancesToTeamPerformanceDifferencesLayer->getLocalFactors(); $teamDifferencesComparisonLayerLocalFactors = &$this->_TeamDifferencesComparisonLayer->getLocalFactors(); @@ -125,16 +116,16 @@ class IteratedTeamDifferencesInnerLayer extends TrueSkillFactorGraphLayer $currentForwardSchedulePiece = $this->scheduleSequence( array( - new ScheduleStep( - sprintf("team perf to perf diff %d", $i), - $currentTeamPerfToTeamPerfDiff, 0), - new ScheduleStep( - sprintf("greater than or within result factor %d", $i), - $currentTeamDiffComparison, 0), - new ScheduleStep( - sprintf("team perf to perf diff factors [%d], 2", $i), - $currentTeamPerfToTeamPerfDiff, 2) - ), sprintf("current forward schedule piece %d", $i)); + new ScheduleStep( + sprintf("team perf to perf diff %d", $i), + $currentTeamPerfToTeamPerfDiff, 0), + new ScheduleStep( + sprintf("greater than or within result factor %d", $i), + $currentTeamDiffComparison, 0), + new ScheduleStep( + sprintf("team perf to perf diff factors [%d], 2", $i), + $currentTeamPerfToTeamPerfDiff, 2) + ), sprintf("current forward schedule piece %d", $i)); $forwardScheduleList[] = $currentForwardSchedulePiece; } @@ -143,8 +134,7 @@ class IteratedTeamDifferencesInnerLayer extends TrueSkillFactorGraphLayer $backwardScheduleList = array(); - for ($i = 0; $i < $totalTeamDifferences - 1; $i++) - { + for ($i = 0; $i < $totalTeamDifferences - 1; $i++) { $teamPerformancesToTeamPerformanceDifferencesLayerLocalFactors = &$this->_TeamPerformancesToTeamPerformanceDifferencesLayer->getLocalFactors(); $teamDifferencesComparisonLayerLocalFactors = &$this->_TeamDifferencesComparisonLayer->getLocalFactors(); @@ -155,15 +145,15 @@ class IteratedTeamDifferencesInnerLayer extends TrueSkillFactorGraphLayer $currentBackwardSchedulePiece = new ScheduleSequence( "current backward schedule piece", array( - new ScheduleStep( - sprintf("teamPerformanceToPerformanceDifferenceFactors[totalTeamDifferences - 1 - %d] @ 0", $i), - $differencesFactor, 0), - new ScheduleStep( - sprintf("greaterThanOrWithinResultFactors[totalTeamDifferences - 1 - %d] @ 0", $i), - $comparisonFactor, 0), - new ScheduleStep( - sprintf("teamPerformanceToPerformanceDifferenceFactors[totalTeamDifferences - 1 - %d] @ 1", $i), - $performancesToDifferencesFactor, 1) + new ScheduleStep( + sprintf("teamPerformanceToPerformanceDifferenceFactors[totalTeamDifferences - 1 - %d] @ 0", $i), + $differencesFactor, 0), + new ScheduleStep( + sprintf("greaterThanOrWithinResultFactors[totalTeamDifferences - 1 - %d] @ 0", $i), + $comparisonFactor, 0), + new ScheduleStep( + sprintf("teamPerformanceToPerformanceDifferenceFactors[totalTeamDifferences - 1 - %d] @ 1", $i), + $performancesToDifferencesFactor, 1) )); $backwardScheduleList[] = $currentBackwardSchedulePiece; } @@ -184,6 +174,4 @@ class IteratedTeamDifferencesInnerLayer extends TrueSkillFactorGraphLayer return $loop; } -} - -?> +} \ No newline at end of file diff --git a/src/TrueSkill/Layers/PlayerPerformancesToTeamPerformancesLayer.php b/src/TrueSkill/Layers/PlayerPerformancesToTeamPerformancesLayer.php index b546374..4767a6e 100644 --- a/src/TrueSkill/Layers/PlayerPerformancesToTeamPerformancesLayer.php +++ b/src/TrueSkill/Layers/PlayerPerformancesToTeamPerformancesLayer.php @@ -1,13 +1,4 @@ -getInputVariablesGroups(); - foreach ($inputVariablesGroups as &$currentTeam) - { + foreach ($inputVariablesGroups as &$currentTeam) { $localCurrentTeam = &$currentTeam; $teamPerformance = &$this->createOutputVariable($localCurrentTeam); $newSumFactor = $this->createPlayerToTeamSumFactor($localCurrentTeam, $teamPerformance); - + $this->addLayerFactor($newSumFactor); // REVIEW: Does it make sense to have groups of one? $outputVariablesGroups = &$this->getOutputVariablesGroups(); $outputVariablesGroups[] = array($teamPerformance); - } + } } public function createPriorSchedule() @@ -45,45 +35,41 @@ class PlayerPerformancesToTeamPerformancesLayer extends TrueSkillFactorGraphLaye $localFactors = &$this->getLocalFactors(); $sequence = &$this->scheduleSequence( - array_map( - function($weightedSumFactor) - { - return new ScheduleStep("Perf to Team Perf Step", $weightedSumFactor, 0); - }, - $localFactors), - "all player perf to team perf schedule"); + array_map( + function ($weightedSumFactor) { + return new ScheduleStep("Perf to Team Perf Step", $weightedSumFactor, 0); + }, + $localFactors), + "all player perf to team perf schedule"); return $sequence; } protected function createPlayerToTeamSumFactor(&$teamMembers, &$sumVariable) { $weights = array_map( - function($v) - { - $player = &$v->getKey(); - return PartialPlay::getPartialPlayPercentage($player); - }, - $teamMembers); + function ($v) { + $player = &$v->getKey(); + return PartialPlay::getPartialPlayPercentage($player); + }, + $teamMembers); return new GaussianWeightedSumFactor( - $sumVariable, - $teamMembers, - $weights); - + $sumVariable, + $teamMembers, + $weights); + } public function createPosteriorSchedule() - { + { $allFactors = array(); $localFactors = &$this->getLocalFactors(); - foreach($localFactors as &$currentFactor) - { + foreach ($localFactors as &$currentFactor) { $localCurrentFactor = &$currentFactor; $numberOfMessages = $localCurrentFactor->getNumberOfMessages(); - for($currentIteration = 1; $currentIteration < $numberOfMessages; $currentIteration++) - { + for ($currentIteration = 1; $currentIteration < $numberOfMessages; $currentIteration++) { $allFactors[] = new ScheduleStep("team sum perf @" . $currentIteration, - $localCurrentFactor, $currentIteration); + $localCurrentFactor, $currentIteration); } } return $this->scheduleSequence($allFactors, "all of the team's sum iterations"); @@ -91,16 +77,13 @@ class PlayerPerformancesToTeamPerformancesLayer extends TrueSkillFactorGraphLaye private function &createOutputVariable(&$team) { - $memberNames = \array_map(function ($currentPlayer) - { - return (string)($currentPlayer->getKey()); - }, - $team); + $memberNames = \array_map(function ($currentPlayer) { + return (string)($currentPlayer->getKey()); + }, + $team); $teamMemberNames = \join(", ", $memberNames); $outputVariable = &$this->getParentFactorGraph()->getVariableFactory()->createBasicVariable("Team[" . $teamMemberNames . "]'s performance"); return $outputVariable; } -} - -?> +} \ No newline at end of file diff --git a/src/TrueSkill/Layers/PlayerPriorValuesToSkillsLayer.php b/src/TrueSkill/Layers/PlayerPriorValuesToSkillsLayer.php index 08487eb..d87f9b2 100644 --- a/src/TrueSkill/Layers/PlayerPriorValuesToSkillsLayer.php +++ b/src/TrueSkill/Layers/PlayerPriorValuesToSkillsLayer.php @@ -1,20 +1,9 @@ -_teams; - foreach ($teams as &$currentTeam) - { + foreach ($teams as &$currentTeam) { $localCurrentTeam = &$currentTeam; $currentTeamSkills = array(); $currentTeamAllPlayers = $localCurrentTeam->getAllPlayers(); - foreach ($currentTeamAllPlayers as &$currentTeamPlayer) - { + foreach ($currentTeamAllPlayers as &$currentTeamPlayer) { $localCurrentTeamPlayer = &$currentTeamPlayer; $currentTeamPlayerRating = $currentTeam->getRating($localCurrentTeamPlayer); $playerSkill = &$this->createSkillOutputVariable($localCurrentTeamPlayer); @@ -58,21 +45,22 @@ class PlayerPriorValuesToSkillsLayer extends TrueSkillFactorGraphLayer { $localFactors = &$this->getLocalFactors(); return $this->scheduleSequence( - array_map( - function(&$prior) - { - return new ScheduleStep("Prior to Skill Step", $prior, 0); - }, - $localFactors), - "All priors"); + array_map( + function (&$prior) { + return new ScheduleStep("Prior to Skill Step", $prior, 0); + }, + $localFactors), + "All priors"); } private function createPriorFactor(&$player, Rating &$priorRating, Variable &$skillsVariable) { - return new GaussianPriorFactor($priorRating->getMean(), - square($priorRating->getStandardDeviation()) + - square($this->getParentFactorGraph()->getGameInfo()->getDynamicsFactor()), - $skillsVariable); + return new GaussianPriorFactor( + $priorRating->getMean(), + BasicMatch::square($priorRating->getStandardDeviation()) + + BasicMatch::square($this->getParentFactorGraph()->getGameInfo()->getDynamicsFactor()), + $skillsVariable + ); } private function &createSkillOutputVariable(&$key) @@ -82,6 +70,4 @@ class PlayerPriorValuesToSkillsLayer extends TrueSkillFactorGraphLayer $skillOutputVariable = &$variableFactory->createKeyedVariable($key, $key . "'s skill"); return $skillOutputVariable; } -} - -?> +} \ No newline at end of file diff --git a/src/TrueSkill/Layers/PlayerSkillsToPerformancesLayer.php b/src/TrueSkill/Layers/PlayerSkillsToPerformancesLayer.php index bd4df4f..38602a8 100644 --- a/src/TrueSkill/Layers/PlayerSkillsToPerformancesLayer.php +++ b/src/TrueSkill/Layers/PlayerSkillsToPerformancesLayer.php @@ -1,15 +1,8 @@ -getInputVariablesGroups(); $outputVariablesGroups = &$this->getOutputVariablesGroups(); - foreach ($inputVariablesGroups as &$currentTeam) - { + foreach ($inputVariablesGroups as &$currentTeam) { $currentTeamPlayerPerformances = array(); - foreach ($currentTeam as &$playerSkillVariable) - { + foreach ($currentTeam as &$playerSkillVariable) { $localPlayerSkillVariable = &$playerSkillVariable; $currentPlayer = &$localPlayerSkillVariable->getKey(); $playerPerformance = &$this->createOutputVariable($currentPlayer); $newLikelihoodFactor = $this->createLikelihood($localPlayerSkillVariable, $playerPerformance); $this->addLayerFactor($newLikelihoodFactor); $currentTeamPlayerPerformances[] = $playerPerformance; - } - + } + $outputVariablesGroups[] = $currentTeamPlayerPerformances; } } private function createLikelihood(KeyedVariable &$playerSkill, KeyedVariable &$playerPerformance) { - return new GaussianLikelihoodFactor(square($this->getParentFactorGraph()->getGameInfo()->getBeta()), $playerPerformance, $playerSkill); + return new GaussianLikelihoodFactor( + BasicMatch::square($this->getParentFactorGraph()->getGameInfo()->getBeta()), + $playerPerformance, + $playerSkill + ); } private function &createOutputVariable(&$key) @@ -58,27 +53,23 @@ class PlayerSkillsToPerformancesLayer extends TrueSkillFactorGraphLayer { $localFactors = &$this->getLocalFactors(); return $this->scheduleSequence( - array_map( - function($likelihood) - { - return new ScheduleStep("Skill to Perf step", $likelihood, 0); - }, - $localFactors), - "All skill to performance sending"); + array_map( + function ($likelihood) { + return new ScheduleStep("Skill to Perf step", $likelihood, 0); + }, + $localFactors), + "All skill to performance sending"); } public function createPosteriorSchedule() { $localFactors = &$this->getLocalFactors(); return $this->scheduleSequence( - array_map( - function($likelihood) - { - return new ScheduleStep("name", $likelihood, 1); - }, - $localFactors), - "All skill to performance sending"); + array_map( + function ($likelihood) { + return new ScheduleStep("name", $likelihood, 1); + }, + $localFactors), + "All skill to performance sending"); } } - -?> diff --git a/src/TrueSkill/Layers/TeamDifferencesComparisonLayer.php b/src/TrueSkill/Layers/TeamDifferencesComparisonLayer.php index c66bb67..f8762ed 100644 --- a/src/TrueSkill/Layers/TeamDifferencesComparisonLayer.php +++ b/src/TrueSkill/Layers/TeamDifferencesComparisonLayer.php @@ -1,11 +1,4 @@ -getInputVariablesGroups(); $inputVarGroupsCount = count($inputVarGroups); - for ($i = 0; $i < $inputVarGroupsCount; $i++) - { + for ($i = 0; $i < $inputVarGroupsCount; $i++) { $isDraw = ($this->_teamRanks[$i] == $this->_teamRanks[$i + 1]); $teamDifference = &$inputVarGroups[$i][0]; @@ -43,6 +35,4 @@ class TeamDifferencesComparisonLayer extends TrueSkillFactorGraphLayer $this->addLayerFactor($factor); } } -} - -?> +} \ No newline at end of file diff --git a/src/TrueSkill/Layers/TeamPerformancesToTeamPerformanceDifferencesLayer.php b/src/TrueSkill/Layers/TeamPerformancesToTeamPerformanceDifferencesLayer.php index a8a8405..9a6998e 100644 --- a/src/TrueSkill/Layers/TeamPerformancesToTeamPerformanceDifferencesLayer.php +++ b/src/TrueSkill/Layers/TeamPerformancesToTeamPerformanceDifferencesLayer.php @@ -1,13 +1,6 @@ -getParentFactorGraph()->getVariableFactory()->createBasicVariable("Team performance difference"); return $outputVariable; } -} - -?> +} \ No newline at end of file diff --git a/src/TrueSkill/Layers/TrueSkillFactorGraphLayer.php b/src/TrueSkill/Layers/TrueSkillFactorGraphLayer.php index ea5754d..cdf6ebe 100644 --- a/src/TrueSkill/Layers/TrueSkillFactorGraphLayer.php +++ b/src/TrueSkill/Layers/TrueSkillFactorGraphLayer.php @@ -1,8 +1,4 @@ - +} \ No newline at end of file diff --git a/src/TrueSkill/TrueSkillFactorGraph.php b/src/TrueSkill/TrueSkillFactorGraph.php index 9f81015..a0ee373 100644 --- a/src/TrueSkill/TrueSkillFactorGraph.php +++ b/src/TrueSkill/TrueSkillFactorGraph.php @@ -1,22 +1,5 @@ -_priorLayer = new PlayerPriorValuesToSkillsLayer($this, $teams); $this->_gameInfo = $gameInfo; $newFactory = new VariableFactory( - function() - { - return GaussianDistribution::fromPrecisionMean(0, 0); - }); - + function () { + return GaussianDistribution::fromPrecisionMean(0, 0); + }); + $this->setVariableFactory($newFactory); $this->_layers = array( - $this->_priorLayer, - new PlayerSkillsToPerformancesLayer($this), - new PlayerPerformancesToTeamPerformancesLayer($this), - new IteratedTeamDifferencesInnerLayer( - $this, - new TeamPerformancesToTeamPerformanceDifferencesLayer($this), - new TeamDifferencesComparisonLayer($this, $teamRanks)) - ); + $this->_priorLayer, + new PlayerSkillsToPerformancesLayer($this), + new PlayerPerformancesToTeamPerformancesLayer($this), + new IteratedTeamDifferencesInnerLayer( + $this, + new TeamPerformancesToTeamPerformanceDifferencesLayer($this), + new TeamDifferencesComparisonLayer($this, $teamRanks)) + ); } public function getGameInfo() @@ -69,16 +51,14 @@ class TrueSkillFactorGraph extends FactorGraph $lastOutput = null; $layers = &$this->_layers; - foreach ($layers as &$currentLayer) - { - if ($lastOutput != null) - { + foreach ($layers as &$currentLayer) { + if ($lastOutput != null) { $currentLayer->setInputVariablesGroups($lastOutput); } $currentLayer->buildLayer(); - $lastOutput = &$currentLayer->getOutputVariablesGroups(); + $lastOutput = &$currentLayer->getOutputVariablesGroups(); } } @@ -93,11 +73,9 @@ class TrueSkillFactorGraph extends FactorGraph $factorList = new FactorList(); $layers = &$this->_layers; - foreach ($layers as &$currentLayer) - { + foreach ($layers as &$currentLayer) { $localFactors = &$currentLayer->getLocalFactors(); - foreach ($localFactors as &$currentFactor) - { + foreach ($localFactors as &$currentFactor) { $localCurrentFactor = &$currentFactor; $factorList->addFactor($localCurrentFactor); } @@ -112,22 +90,18 @@ class TrueSkillFactorGraph extends FactorGraph $fullSchedule = array(); $layers = &$this->_layers; - foreach ($layers as &$currentLayer) - { + foreach ($layers as &$currentLayer) { $currentPriorSchedule = $currentLayer->createPriorSchedule(); - if ($currentPriorSchedule != null) - { + if ($currentPriorSchedule != null) { $fullSchedule[] = $currentPriorSchedule; } } - + $allLayersReverse = \array_reverse($this->_layers); - foreach ($allLayersReverse as &$currentLayer) - { + foreach ($allLayersReverse as &$currentLayer) { $currentPosteriorSchedule = $currentLayer->createPosteriorSchedule(); - if ($currentPosteriorSchedule != null) - { + if ($currentPosteriorSchedule != null) { $fullSchedule[] = $currentPosteriorSchedule; } } @@ -140,13 +114,11 @@ class TrueSkillFactorGraph extends FactorGraph $result = new RatingContainer(); $priorLayerOutputVariablesGroups = &$this->_priorLayer->getOutputVariablesGroups(); - foreach ($priorLayerOutputVariablesGroups as &$currentTeam) - { - foreach ($currentTeam as &$currentPlayer) - { - $localCurrentPlayer = &$currentPlayer->getKey(); + foreach ($priorLayerOutputVariablesGroups as &$currentTeam) { + foreach ($currentTeam as &$currentPlayer) { + $localCurrentPlayer = &$currentPlayer->getKey(); $newRating = new Rating($currentPlayer->getValue()->getMean(), - $currentPlayer->getValue()->getStandardDeviation()); + $currentPlayer->getValue()->getStandardDeviation()); $result->setRating($localCurrentPlayer, $newRating); } @@ -154,6 +126,4 @@ class TrueSkillFactorGraph extends FactorGraph return $result; } -} - -?> +} \ No newline at end of file diff --git a/src/TrueSkill/TruncatedGaussianCorrectionFunctions.php b/src/TrueSkill/TruncatedGaussianCorrectionFunctions.php index 702043f..548e3c5 100644 --- a/src/TrueSkill/TruncatedGaussianCorrectionFunctions.php +++ b/src/TrueSkill/TruncatedGaussianCorrectionFunctions.php @@ -1,9 +1,6 @@ - +} \ No newline at end of file diff --git a/src/TrueSkill/TwoPlayerTrueSkillCalculator.php b/src/TrueSkill/TwoPlayerTrueSkillCalculator.php index fb5e57e..93a315c 100644 --- a/src/TrueSkill/TwoPlayerTrueSkillCalculator.php +++ b/src/TrueSkill/TwoPlayerTrueSkillCalculator.php @@ -1,25 +1,8 @@ -getDrawProbability(), - $gameInfo->getBeta()); + $drawMargin = DrawMargin::getDrawMarginFromDrawProbability( + $gameInfo->getDrawProbability(), + $gameInfo->getBeta() + ); - $c = - sqrt( - square($selfRating->getStandardDeviation()) - + - square($opponentRating->getStandardDeviation()) - + - 2*square($gameInfo->getBeta())); + $c = sqrt( + BasicMatch::square($selfRating->getStandardDeviation()) + + + BasicMatch::square($opponentRating->getStandardDeviation()) + + + 2 * BasicMatch::square($gameInfo->getBeta()) + ); $winningMean = $selfRating->getMean(); $losingMean = $opponentRating->getMean(); @@ -128,10 +112,10 @@ class TwoPlayerTrueSkillCalculator extends SkillCalculator $rankMultiplier = 1; } - $meanMultiplier = (square($selfRating->getStandardDeviation()) + square($gameInfo->getDynamicsFactor()))/$c; + $meanMultiplier = (BasicMatch::square($selfRating->getStandardDeviation()) + BasicMatch::square($gameInfo->getDynamicsFactor()))/$c; - $varianceWithDynamics = square($selfRating->getStandardDeviation()) + square($gameInfo->getDynamicsFactor()); - $stdDevMultiplier = $varianceWithDynamics/square($c); + $varianceWithDynamics = BasicMatch::square($selfRating->getStandardDeviation()) + BasicMatch::square($gameInfo->getDynamicsFactor()); + $stdDevMultiplier = $varianceWithDynamics/BasicMatch::square($c); $newMean = $selfRating->getMean() + ($rankMultiplier*$meanMultiplier*$v); $newStdDev = sqrt($varianceWithDynamics*(1 - $w*$stdDevMultiplier)); @@ -157,9 +141,9 @@ class TwoPlayerTrueSkillCalculator extends SkillCalculator $player2Rating = $team2Ratings[0]; // We just use equation 4.1 found on page 8 of the TrueSkill 2006 paper: - $betaSquared = square($gameInfo->getBeta()); - $player1SigmaSquared = square($player1Rating->getStandardDeviation()); - $player2SigmaSquared = square($player2Rating->getStandardDeviation()); + $betaSquared = BasicMatch::square($gameInfo->getBeta()); + $player1SigmaSquared = BasicMatch::square($player1Rating->getStandardDeviation()); + $player2SigmaSquared = BasicMatch::square($player2Rating->getStandardDeviation()); // This is the square root part of the equation: $sqrtPart = @@ -171,11 +155,10 @@ class TwoPlayerTrueSkillCalculator extends SkillCalculator // This is the exponent part of the equation: $expPart = exp( - (-1*square($player1Rating->getMean() - $player2Rating->getMean())) + (-1*BasicMatch::square($player1Rating->getMean() - $player2Rating->getMean())) / (2*(2*$betaSquared + $player1SigmaSquared + $player2SigmaSquared))); return $sqrtPart*$expPart; } -} -?> +} \ No newline at end of file diff --git a/src/TrueSkill/TwoTeamTrueSkillCalculator.php b/src/TrueSkill/TwoTeamTrueSkillCalculator.php index a62517b..826b344 100644 --- a/src/TrueSkill/TwoTeamTrueSkillCalculator.php +++ b/src/TrueSkill/TwoTeamTrueSkillCalculator.php @@ -1,27 +1,8 @@ -getDrawProbability(), - $gameInfo->getBeta()); + $drawMargin = DrawMargin::getDrawMarginFromDrawProbability( + $gameInfo->getDrawProbability(), + $gameInfo->getBeta() + ); - $betaSquared = square($gameInfo->getBeta()); - $tauSquared = square($gameInfo->getDynamicsFactor()); + $betaSquared = BasicMatch::square($gameInfo->getBeta()); + $tauSquared = BasicMatch::square($gameInfo->getDynamicsFactor()); $totalPlayers = $selfTeam->count() + $otherTeam->count(); - $meanGetter = - function($currentRating) - { - return $currentRating->getMean(); - }; + $meanGetter = function ($currentRating) { + return $currentRating->getMean(); + }; - $selfMeanSum = sum($selfTeam->getAllRatings(), $meanGetter); - $otherTeamMeanSum = sum($otherTeam->getAllRatings(), $meanGetter); + $selfMeanSum = BasicMatch::sum($selfTeam->getAllRatings(), $meanGetter); + $otherTeamMeanSum = BasicMatch::sum($otherTeam->getAllRatings(), $meanGetter); - $varianceGetter = - function($currentRating) - { - return square($currentRating->getStandardDeviation()); - }; + $varianceGetter = function ($currentRating) { + return BasicMatch::square($currentRating->getStandardDeviation()); + }; $c = sqrt( - sum($selfTeam->getAllRatings(), $varianceGetter) - + - sum($otherTeam->getAllRatings(), $varianceGetter) - + - $totalPlayers*$betaSquared); + BasicMatch::sum($selfTeam->getAllRatings(), $varianceGetter) + + + BasicMatch::sum($otherTeam->getAllRatings(), $varianceGetter) + + + $totalPlayers * $betaSquared + ); $winningMean = $selfMeanSum; $losingMean = $otherTeamMeanSum; - switch ($selfToOtherTeamComparison) - { + switch ($selfToOtherTeamComparison) { case PairwiseComparison::WIN: case PairwiseComparison::DRAW: // NOP @@ -130,15 +109,12 @@ class TwoTeamTrueSkillCalculator extends SkillCalculator $meanDelta = $winningMean - $losingMean; - if ($selfToOtherTeamComparison != PairwiseComparison::DRAW) - { + if ($selfToOtherTeamComparison != PairwiseComparison::DRAW) { // non-draw case $v = TruncatedGaussianCorrectionFunctions::vExceedsMarginScaled($meanDelta, $drawMargin, $c); $w = TruncatedGaussianCorrectionFunctions::wExceedsMarginScaled($meanDelta, $drawMargin, $c); - $rankMultiplier = (int) $selfToOtherTeamComparison; - } - else - { + $rankMultiplier = (int)$selfToOtherTeamComparison; + } else { // assume draw $v = TruncatedGaussianCorrectionFunctions::vWithinMarginScaled($meanDelta, $drawMargin, $c); $w = TruncatedGaussianCorrectionFunctions::wWithinMarginScaled($meanDelta, $drawMargin, $c); @@ -146,19 +122,18 @@ class TwoTeamTrueSkillCalculator extends SkillCalculator } $selfTeamAllPlayers = &$selfTeam->getAllPlayers(); - foreach ($selfTeamAllPlayers as &$selfTeamCurrentPlayer) - { + foreach ($selfTeamAllPlayers as &$selfTeamCurrentPlayer) { $localSelfTeamCurrentPlayer = &$selfTeamCurrentPlayer; $previousPlayerRating = $selfTeam->getRating($localSelfTeamCurrentPlayer); - $meanMultiplier = (square($previousPlayerRating->getStandardDeviation()) + $tauSquared)/$c; - $stdDevMultiplier = (square($previousPlayerRating->getStandardDeviation()) + $tauSquared)/square($c); + $meanMultiplier = (BasicMatch::square($previousPlayerRating->getStandardDeviation()) + $tauSquared) / $c; + $stdDevMultiplier = (BasicMatch::square($previousPlayerRating->getStandardDeviation()) + $tauSquared) / BasicMatch::square($c); - $playerMeanDelta = ($rankMultiplier*$meanMultiplier*$v); + $playerMeanDelta = ($rankMultiplier * $meanMultiplier * $v); $newMean = $previousPlayerRating->getMean() + $playerMeanDelta; $newStdDev = - sqrt((square($previousPlayerRating->getStandardDeviation()) + $tauSquared)*(1 - $w*$stdDevMultiplier)); + sqrt((BasicMatch::square($previousPlayerRating->getStandardDeviation()) + $tauSquared) * (1 - $w * $stdDevMultiplier)); $newPlayerRatings->setRating($localSelfTeamCurrentPlayer, new Rating($newMean, $newStdDev)); } @@ -182,45 +157,38 @@ class TwoTeamTrueSkillCalculator extends SkillCalculator $totalPlayers = $team1Count + $team2Count; - $betaSquared = square($gameInfo->getBeta()); + $betaSquared = BasicMatch::square($gameInfo->getBeta()); - $meanGetter = - function($currentRating) - { - return $currentRating->getMean(); - }; + $meanGetter = function ($currentRating) { + return $currentRating->getMean(); + }; - $varianceGetter = - function($currentRating) - { - return square($currentRating->getStandardDeviation()); - }; + $varianceGetter = function ($currentRating) { + return BasicMatch::square($currentRating->getStandardDeviation()); + }; - $team1MeanSum = sum($team1Ratings, $meanGetter); - $team1StdDevSquared = sum($team1Ratings, $varianceGetter); + $team1MeanSum = BasicMatch::sum($team1Ratings, $meanGetter); + $team1StdDevSquared = BasicMatch::sum($team1Ratings, $varianceGetter); - $team2MeanSum = sum($team2Ratings, $meanGetter); - $team2SigmaSquared = sum($team2Ratings, $varianceGetter); + $team2MeanSum = BasicMatch::sum($team2Ratings, $meanGetter); + $team2SigmaSquared = BasicMatch::sum($team2Ratings, $varianceGetter); // This comes from equation 4.1 in the TrueSkill paper on page 8 // The equation was broken up into the part under the square root sign and // the exponential part to make the code easier to read. - $sqrtPart - = sqrt( - ($totalPlayers*$betaSquared) - / - ($totalPlayers*$betaSquared + $team1StdDevSquared + $team2SigmaSquared) - ); + $sqrtPart = sqrt( + ($totalPlayers * $betaSquared) + / + ($totalPlayers * $betaSquared + $team1StdDevSquared + $team2SigmaSquared) + ); - $expPart - = exp( - (-1*square($team1MeanSum - $team2MeanSum)) - / - (2*($totalPlayers*$betaSquared + $team1StdDevSquared + $team2SigmaSquared)) - ); + $expPart = exp( + (-1 * BasicMatch::square($team1MeanSum - $team2MeanSum)) + / + (2 * ($totalPlayers * $betaSquared + $team1StdDevSquared + $team2SigmaSquared)) + ); - return $expPart*$sqrtPart; + return $expPart * $sqrtPart; } -} -?> +} \ No newline at end of file diff --git a/tests/Numerics/GaussianDistributionTest.php b/tests/Numerics/GaussianDistributionTest.php index 3b37cc5..44601e5 100644 --- a/tests/Numerics/GaussianDistributionTest.php +++ b/tests/Numerics/GaussianDistributionTest.php @@ -1,6 +1,5 @@ assertEquals($expectedMean, $product2->getMean(), '', GaussianDistributionTest::ERROR_TOLERANCE); - $expectedSigma = sqrt(((square(5) * square(7)) / (square(5) + square(7)))); + $expectedSigma = sqrt(((BasicMatch::square(5) * BasicMatch::square(7)) / (BasicMatch::square(5) + BasicMatch::square(7)))); $this->assertEquals($expectedSigma, $product2->getStandardDeviation(), '', GaussianDistributionTest::ERROR_TOLERANCE); } @@ -54,7 +53,7 @@ class GaussianDistributionTest extends TestCase $this->assertEquals(2.0, $productDividedByStandardNormal->getMean(), '', GaussianDistributionTest::ERROR_TOLERANCE); $this->assertEquals(3.0, $productDividedByStandardNormal->getStandardDeviation(),'', GaussianDistributionTest::ERROR_TOLERANCE); - $product2 = new GaussianDistribution((4 * square(7) + 6 * square(5)) / (square(5) + square(7)), sqrt(((square(5) * square(7)) / (square(5) + square(7))))); + $product2 = new GaussianDistribution((4 * BasicMatch::square(7) + 6 * BasicMatch::square(5)) / (BasicMatch::square(5) + BasicMatch::square(7)), sqrt(((BasicMatch::square(5) * BasicMatch::square(7)) / (BasicMatch::square(5) + BasicMatch::square(7))))); $m4s5 = new GaussianDistribution(4,5); $product2DividedByM4S5 = GaussianDistribution::divide($product2, $m4s5); $this->assertEquals(6.0, $product2DividedByM4S5->getMean(), '', GaussianDistributionTest::ERROR_TOLERANCE);