mirror of
				https://github.com/furyfire/trueskill.git
				synced 2025-11-04 10:12:28 +01:00 
			
		
		
		
	General cleanup and removal of all unnecessary references
This commit is contained in:
		@@ -1,5 +1,7 @@
 | 
			
		||||
<?php namespace Moserware\Skills\Elo;
 | 
			
		||||
 | 
			
		||||
use Moserware\Skills\GameInfo;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Including Elo's scheme as a simple comparison.
 | 
			
		||||
 * See http://en.wikipedia.org/wiki/Elo_rating_system#Theory
 | 
			
		||||
@@ -22,7 +24,7 @@ class FideEloCalculator extends TwoPlayerEloCalculator
 | 
			
		||||
        return new FideEloCalculator(new ProvisionalFideKFactor());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getPlayerWinProbability($gameInfo, $playerRating, $opponentRating)
 | 
			
		||||
    public function getPlayerWinProbability(GameInfo $gameInfo, $playerRating, $opponentRating)
 | 
			
		||||
    {
 | 
			
		||||
        $ratingDifference = $opponentRating - $playerRating;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
<?php namespace Moserware\Skills\Elo;
 | 
			
		||||
 | 
			
		||||
use Moserware\Skills\GameInfo;
 | 
			
		||||
use Moserware\Numerics\GaussianDistribution;
 | 
			
		||||
use Moserware\Skills\Numerics\GaussianDistribution;
 | 
			
		||||
 | 
			
		||||
class GaussianEloCalculator extends TwoPlayerEloCalculator
 | 
			
		||||
{
 | 
			
		||||
@@ -21,6 +21,7 @@ class GaussianEloCalculator extends TwoPlayerEloCalculator
 | 
			
		||||
        return GaussianDistribution::cumulativeTo(
 | 
			
		||||
            $ratingDifference
 | 
			
		||||
            /
 | 
			
		||||
            (sqrt(2) * $gameInfo->getBeta()));
 | 
			
		||||
            (sqrt(2) * $gameInfo->getBeta())
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -6,7 +6,6 @@ use Moserware\Skills\PairwiseComparison;
 | 
			
		||||
use Moserware\Skills\RankSorter;
 | 
			
		||||
use Moserware\Skills\SkillCalculator;
 | 
			
		||||
use Moserware\Skills\SkillCalculatorSupportedOptions;
 | 
			
		||||
 | 
			
		||||
use Moserware\Skills\PlayersRange;
 | 
			
		||||
use Moserware\Skills\TeamsRange;
 | 
			
		||||
 | 
			
		||||
@@ -20,10 +19,8 @@ abstract class TwoPlayerEloCalculator extends SkillCalculator
 | 
			
		||||
        $this->_kFactor = $kFactor;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function calculateNewRatings(GameInfo $gameInfo,
 | 
			
		||||
                                        array $teamsOfPlayerToRatings,
 | 
			
		||||
                                        array $teamRanks)
 | 
			
		||||
    {   
 | 
			
		||||
    public function calculateNewRatings(GameInfo $gameInfo, array $teamsOfPlayerToRatings, array $teamRanks)
 | 
			
		||||
    {
 | 
			
		||||
        $this->validateTeamCountAndPlayersCountPerTeam($teamsOfPlayerToRatings);
 | 
			
		||||
        RankSorter::sort($teamsOfPlayerToRatings, $teamRanks);
 | 
			
		||||
        
 | 
			
		||||
@@ -71,9 +68,9 @@ abstract class TwoPlayerEloCalculator extends SkillCalculator
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public abstract function getPlayerWinProbability($gameInfo, $playerRating, $opponentRating);
 | 
			
		||||
    public abstract function getPlayerWinProbability(GameInfo $gameInfo, $playerRating, $opponentRating);
 | 
			
		||||
 | 
			
		||||
    public function calculateMatchQuality(GameInfo $gameInfo, array &$teamsOfPlayerToRatings)
 | 
			
		||||
    public function calculateMatchQuality(GameInfo $gameInfo, array $teamsOfPlayerToRatings)
 | 
			
		||||
    {
 | 
			
		||||
        $this->validateTeamCountAndPlayersCountPerTeam($teamsOfPlayerToRatings);
 | 
			
		||||
        $team1 = $teamsOfPlayerToRatings[0];
 | 
			
		||||
 
 | 
			
		||||
@@ -2,6 +2,7 @@
 | 
			
		||||
 | 
			
		||||
use Exception;
 | 
			
		||||
 | 
			
		||||
// XXX: This class is not used anywhere
 | 
			
		||||
class DefaultVariable extends Variable
 | 
			
		||||
{
 | 
			
		||||
    public function __construct()
 | 
			
		||||
@@ -9,12 +10,12 @@ class DefaultVariable extends Variable
 | 
			
		||||
        parent::__construct("Default", null);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function &getValue()
 | 
			
		||||
    public function getValue()
 | 
			
		||||
    {
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function setValue(&$value)
 | 
			
		||||
    public function setValue($value)
 | 
			
		||||
    {
 | 
			
		||||
        throw new Exception();
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -34,24 +34,26 @@ abstract class Factor
 | 
			
		||||
        return count($this->_messages);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected function &getVariables()
 | 
			
		||||
    protected function getVariables()
 | 
			
		||||
    {
 | 
			
		||||
        return $this->_variables;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected function &getMessages()
 | 
			
		||||
    protected function getMessages()
 | 
			
		||||
    {
 | 
			
		||||
        return $this->_messages;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Update the message and marginal of the i-th variable that the factor is connected to
 | 
			
		||||
     * @param $messageIndex
 | 
			
		||||
     * @throws Exception
 | 
			
		||||
     */
 | 
			
		||||
    public function updateMessageIndex($messageIndex)
 | 
			
		||||
    {
 | 
			
		||||
        Guard::argumentIsValidIndex($messageIndex, count($this->_messages), "messageIndex");
 | 
			
		||||
        $message = &$this->_messages[$messageIndex];
 | 
			
		||||
        $variable = &$this->_messageToVariableBinding->getValue($message);
 | 
			
		||||
        $message = $this->_messages[$messageIndex];
 | 
			
		||||
        $variable = $this->_messageToVariableBinding->getValue($message);
 | 
			
		||||
        return $this->updateMessageVariable($message, $variable);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -65,41 +67,41 @@ abstract class Factor
 | 
			
		||||
     */
 | 
			
		||||
    public function resetMarginals()
 | 
			
		||||
    {
 | 
			
		||||
        $allValues = &$this->_messageToVariableBinding->getAllValues();
 | 
			
		||||
        foreach ($allValues as &$currentVariable) {
 | 
			
		||||
        $allValues = $this->_messageToVariableBinding->getAllValues();
 | 
			
		||||
        foreach ($allValues as $currentVariable) {
 | 
			
		||||
            $currentVariable->resetToPrior();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sends the ith message to the marginal and returns the log-normalization constant
 | 
			
		||||
     * @param $messageIndex
 | 
			
		||||
     * @return
 | 
			
		||||
     * @throws Exception
 | 
			
		||||
     */
 | 
			
		||||
    public function sendMessageIndex($messageIndex)
 | 
			
		||||
    {
 | 
			
		||||
        Guard::argumentIsValidIndex($messageIndex, count($this->_messages), "messageIndex");
 | 
			
		||||
 | 
			
		||||
        $message = &$this->_messages[$messageIndex];
 | 
			
		||||
        $variable = &$this->_messageToVariableBinding->getValue($message);
 | 
			
		||||
        $message = $this->_messages[$messageIndex];
 | 
			
		||||
        $variable = $this->_messageToVariableBinding->getValue($message);
 | 
			
		||||
        return $this->sendMessageVariable($message, $variable);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected abstract function sendMessageVariable(Message &$message, Variable &$variable);
 | 
			
		||||
    protected abstract function sendMessageVariable(Message $message, Variable $variable);
 | 
			
		||||
 | 
			
		||||
    public abstract function &createVariableToMessageBinding(Variable &$variable);
 | 
			
		||||
    public abstract function createVariableToMessageBinding(Variable $variable);
 | 
			
		||||
 | 
			
		||||
    protected function &createVariableToMessageBindingWithMessage(Variable &$variable, Message &$message)
 | 
			
		||||
    protected function createVariableToMessageBindingWithMessage(Variable $variable, Message $message)
 | 
			
		||||
    {
 | 
			
		||||
        $index = count($this->_messages);
 | 
			
		||||
        $localMessages = &$this->_messages;
 | 
			
		||||
        $localMessages[] = &$message;
 | 
			
		||||
        $this->_messageToVariableBinding->setValue($message, $variable);
 | 
			
		||||
        $localVariables = &$this->_variables;
 | 
			
		||||
        $localVariables[] = &$variable;
 | 
			
		||||
        $this->_messages[] = $message;
 | 
			
		||||
        $this->_variables[] = $variable;
 | 
			
		||||
        return $message;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function __toString()
 | 
			
		||||
    {
 | 
			
		||||
        return ($this->_name != null) ? $this->_name : base::__toString();
 | 
			
		||||
        return ($this->_name != null) ? $this->_name : null;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -4,14 +4,13 @@ class FactorGraph
 | 
			
		||||
{
 | 
			
		||||
    private $_variableFactory;
 | 
			
		||||
 | 
			
		||||
    public function &getVariableFactory()
 | 
			
		||||
    public function getVariableFactory()
 | 
			
		||||
    {
 | 
			
		||||
        $factory = &$this->_variableFactory;
 | 
			
		||||
        return $factory;
 | 
			
		||||
        return $this->_variableFactory;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function setVariableFactory(VariableFactory &$factory)
 | 
			
		||||
    public function setVariableFactory(VariableFactory $factory)
 | 
			
		||||
    {
 | 
			
		||||
        $this->_variableFactory = &$factory;
 | 
			
		||||
        $this->_variableFactory = $factory;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
<?php namespace Moserware\Skills\FactorGraphs;
 | 
			
		||||
 | 
			
		||||
// edit this
 | 
			
		||||
abstract class FactorGraphLayer
 | 
			
		||||
{
 | 
			
		||||
    private $_localFactors = array();
 | 
			
		||||
@@ -7,38 +7,39 @@ abstract class FactorGraphLayer
 | 
			
		||||
    private $_inputVariablesGroups = array();
 | 
			
		||||
    private $_parentFactorGraph;
 | 
			
		||||
 | 
			
		||||
    protected function __construct(FactorGraph &$parentGraph)
 | 
			
		||||
    protected function __construct(FactorGraph $parentGraph)
 | 
			
		||||
    {
 | 
			
		||||
        $this->_parentFactorGraph = &$parentGraph;
 | 
			
		||||
        $this->_parentFactorGraph = $parentGraph;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected function &getInputVariablesGroups()
 | 
			
		||||
    protected function getInputVariablesGroups()
 | 
			
		||||
    {
 | 
			
		||||
        $inputVariablesGroups = &$this->_inputVariablesGroups;
 | 
			
		||||
        return $inputVariablesGroups;
 | 
			
		||||
        return $this->_inputVariablesGroups;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // HACK
 | 
			
		||||
 | 
			
		||||
    public function &getParentFactorGraph()
 | 
			
		||||
    public function getParentFactorGraph()
 | 
			
		||||
    {
 | 
			
		||||
        $parentFactorGraph = &$this->_parentFactorGraph;
 | 
			
		||||
        return $parentFactorGraph;
 | 
			
		||||
        return $this->_parentFactorGraph;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * This reference is still needed
 | 
			
		||||
     *
 | 
			
		||||
     * @return array
 | 
			
		||||
     */
 | 
			
		||||
    public function &getOutputVariablesGroups()
 | 
			
		||||
    {
 | 
			
		||||
        $outputVariablesGroups = &$this->_outputVariablesGroups;
 | 
			
		||||
        return $outputVariablesGroups;
 | 
			
		||||
        return $this->_outputVariablesGroups;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function &getLocalFactors()
 | 
			
		||||
    public function getLocalFactors()
 | 
			
		||||
    {
 | 
			
		||||
        $localFactors = &$this->_localFactors;
 | 
			
		||||
        return $localFactors;
 | 
			
		||||
        return $this->_localFactors;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function setInputVariablesGroups(&$value)
 | 
			
		||||
    public function setInputVariablesGroups($value)
 | 
			
		||||
    {
 | 
			
		||||
        $this->_inputVariablesGroups = $value;
 | 
			
		||||
    }
 | 
			
		||||
@@ -48,7 +49,7 @@ abstract class FactorGraphLayer
 | 
			
		||||
        return new ScheduleSequence($name, $itemsToSequence);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected function addLayerFactor(Factor &$factor)
 | 
			
		||||
    protected function addLayerFactor(Factor $factor)
 | 
			
		||||
    {
 | 
			
		||||
        $this->_localFactors[] = $factor;
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -9,7 +9,7 @@ class FactorList
 | 
			
		||||
 | 
			
		||||
    public function getLogNormalization()
 | 
			
		||||
    {
 | 
			
		||||
        $list = &$this->_list;
 | 
			
		||||
        $list = $this->_list;
 | 
			
		||||
        foreach ($list as &$currentFactor) {
 | 
			
		||||
            $currentFactor->resetMarginals();
 | 
			
		||||
        }
 | 
			
		||||
@@ -42,7 +42,7 @@ class FactorList
 | 
			
		||||
        return count($this->_list);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function &addFactor(Factor &$factor)
 | 
			
		||||
    public function addFactor(Factor $factor)
 | 
			
		||||
    {
 | 
			
		||||
        $this->_list[] = $factor;
 | 
			
		||||
        return $factor;
 | 
			
		||||
 
 | 
			
		||||
@@ -4,15 +4,14 @@ class KeyedVariable extends Variable
 | 
			
		||||
{
 | 
			
		||||
    private $_key;
 | 
			
		||||
 | 
			
		||||
    public function __construct(&$key, $name, &$prior)
 | 
			
		||||
    public function __construct($key, $name, $prior)
 | 
			
		||||
    {
 | 
			
		||||
        parent::__construct($name, $prior);
 | 
			
		||||
        $this->_key = &$key;
 | 
			
		||||
        $this->_key = $key;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function &getKey()
 | 
			
		||||
    public function getKey()
 | 
			
		||||
    {
 | 
			
		||||
        $key = &$this->_key;
 | 
			
		||||
        return $key;
 | 
			
		||||
        return $this->_key;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -5,21 +5,20 @@ class Message
 | 
			
		||||
    private $_name;
 | 
			
		||||
    private $_value;
 | 
			
		||||
 | 
			
		||||
    public function __construct(&$value = null, $name = null)
 | 
			
		||||
    public function __construct($value = null, $name = null)
 | 
			
		||||
    {
 | 
			
		||||
        $this->_name = $name;
 | 
			
		||||
        $this->_value = $value;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function& getValue()
 | 
			
		||||
    public function getValue()
 | 
			
		||||
    {
 | 
			
		||||
        $value = &$this->_value;
 | 
			
		||||
        return $value;
 | 
			
		||||
        return $this->_value;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function setValue(&$value)
 | 
			
		||||
    public function setValue($value)
 | 
			
		||||
    {
 | 
			
		||||
        $this->_value = &$value;
 | 
			
		||||
        $this->_value = $value;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function __toString()
 | 
			
		||||
 
 | 
			
		||||
@@ -5,7 +5,7 @@ class ScheduleLoop extends Schedule
 | 
			
		||||
    private $_maxDelta;
 | 
			
		||||
    private $_scheduleToLoop;
 | 
			
		||||
 | 
			
		||||
    public function __construct($name, Schedule &$scheduleToLoop, $maxDelta)
 | 
			
		||||
    public function __construct($name, Schedule $scheduleToLoop, $maxDelta)
 | 
			
		||||
    {
 | 
			
		||||
        parent::__construct($name);
 | 
			
		||||
        $this->_scheduleToLoop = $scheduleToLoop;
 | 
			
		||||
 
 | 
			
		||||
@@ -14,8 +14,8 @@ class ScheduleSequence extends Schedule
 | 
			
		||||
    {
 | 
			
		||||
        $maxDelta = 0;
 | 
			
		||||
 | 
			
		||||
        $schedules = &$this->_schedules;
 | 
			
		||||
        foreach ($schedules as &$currentSchedule) {
 | 
			
		||||
        $schedules = $this->_schedules;
 | 
			
		||||
        foreach ($schedules as $currentSchedule) {
 | 
			
		||||
            $currentVisit = $currentSchedule->visit($depth + 1, $maxDepth);
 | 
			
		||||
            $maxDelta = max($currentVisit, $maxDelta);
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -5,7 +5,7 @@ class ScheduleStep extends Schedule
 | 
			
		||||
    private $_factor;
 | 
			
		||||
    private $_index;
 | 
			
		||||
 | 
			
		||||
    public function __construct($name, Factor &$factor, $index)
 | 
			
		||||
    public function __construct($name, Factor $factor, $index)
 | 
			
		||||
    {
 | 
			
		||||
        parent::__construct($name);
 | 
			
		||||
        $this->_factor = $factor;
 | 
			
		||||
@@ -14,7 +14,7 @@ class ScheduleStep extends Schedule
 | 
			
		||||
 | 
			
		||||
    public function visit($depth = -1, $maxDepth = 0)
 | 
			
		||||
    {
 | 
			
		||||
        $currentFactor = &$this->_factor;
 | 
			
		||||
        $currentFactor = $this->_factor;
 | 
			
		||||
        $delta = $currentFactor->updateMessageIndex($this->_index);
 | 
			
		||||
        return $delta;
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -7,22 +7,21 @@ class Variable
 | 
			
		||||
    private $_prior;
 | 
			
		||||
    private $_value;
 | 
			
		||||
 | 
			
		||||
    public function __construct($name, &$prior)
 | 
			
		||||
    public function __construct($name, $prior)
 | 
			
		||||
    {
 | 
			
		||||
        $this->_name = "Variable[" . $name . "]";
 | 
			
		||||
        $this->_prior = $prior;
 | 
			
		||||
        $this->resetToPrior();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function &getValue()
 | 
			
		||||
    public function getValue()
 | 
			
		||||
    {
 | 
			
		||||
        $value = &$this->_value;
 | 
			
		||||
        return $value;
 | 
			
		||||
        return $this->_value;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function setValue(&$value)
 | 
			
		||||
    public function setValue($value)
 | 
			
		||||
    {
 | 
			
		||||
        $this->_value = &$value;
 | 
			
		||||
        $this->_value = $value;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function resetToPrior()
 | 
			
		||||
 
 | 
			
		||||
@@ -7,17 +7,17 @@ class VariableFactory
 | 
			
		||||
 | 
			
		||||
    public function __construct($variablePriorInitializer)
 | 
			
		||||
    {
 | 
			
		||||
        $this->_variablePriorInitializer = &$variablePriorInitializer;
 | 
			
		||||
        $this->_variablePriorInitializer = $variablePriorInitializer;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function &createBasicVariable($name)
 | 
			
		||||
    public function createBasicVariable($name)
 | 
			
		||||
    {
 | 
			
		||||
        $initializer = $this->_variablePriorInitializer;
 | 
			
		||||
        $newVar = new Variable($name, $initializer());
 | 
			
		||||
        return $newVar;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function &createKeyedVariable(&$key, $name)
 | 
			
		||||
    public function createKeyedVariable($key, $name)
 | 
			
		||||
    {
 | 
			
		||||
        $initializer = $this->_variablePriorInitializer;
 | 
			
		||||
        $newVar = new KeyedVariable($key, $name, $initializer());
 | 
			
		||||
 
 | 
			
		||||
@@ -8,30 +8,30 @@ class HashMap
 | 
			
		||||
    private $_hashToValue = array();
 | 
			
		||||
    private $_hashToKey = array();
 | 
			
		||||
 | 
			
		||||
    public function &getValue(&$key)
 | 
			
		||||
    public function getValue($key)
 | 
			
		||||
    {
 | 
			
		||||
        $hash = self::getHash($key);
 | 
			
		||||
        $hashValue = &$this->_hashToValue[$hash];
 | 
			
		||||
        $hashValue = $this->_hashToValue[$hash];
 | 
			
		||||
        return $hashValue;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function setValue(&$key, &$value)
 | 
			
		||||
    public function setValue($key, $value)
 | 
			
		||||
    {
 | 
			
		||||
        $hash = self::getHash($key);
 | 
			
		||||
        $this->_hashToKey[$hash] = &$key;
 | 
			
		||||
        $this->_hashToValue[$hash] = &$value;
 | 
			
		||||
        $this->_hashToKey[$hash] = $key;
 | 
			
		||||
        $this->_hashToValue[$hash] = $value;
 | 
			
		||||
        return $this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function &getAllKeys()
 | 
			
		||||
    public function getAllKeys()
 | 
			
		||||
    {
 | 
			
		||||
        $keys = &array_values($this->_hashToKey);
 | 
			
		||||
        $keys = array_values($this->_hashToKey);
 | 
			
		||||
        return $keys;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getAllValues()
 | 
			
		||||
    {
 | 
			
		||||
        $values = &array_values($this->_hashToValue);
 | 
			
		||||
        $values = array_values($this->_hashToValue);
 | 
			
		||||
        return $values;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -40,7 +40,7 @@ class HashMap
 | 
			
		||||
        return count($this->_hashToKey);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static function getHash(&$key)
 | 
			
		||||
    private static function getHash($key)
 | 
			
		||||
    {
 | 
			
		||||
        if (is_object($key)) {
 | 
			
		||||
            return spl_object_hash($key);
 | 
			
		||||
 
 | 
			
		||||
@@ -109,7 +109,8 @@ class GaussianDistribution
 | 
			
		||||
    {
 | 
			
		||||
        return max(
 | 
			
		||||
            abs($left->_precisionMean - $right->_precisionMean),
 | 
			
		||||
            sqrt(abs($left->_precision - $right->_precision)));
 | 
			
		||||
            sqrt(abs($left->_precision - $right->_precision))
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Computes the absolute difference between two Gaussians
 | 
			
		||||
@@ -133,8 +134,10 @@ class GaussianDistribution
 | 
			
		||||
 | 
			
		||||
    public static function divide(GaussianDistribution $numerator, GaussianDistribution $denominator)
 | 
			
		||||
    {
 | 
			
		||||
        return GaussianDistribution::fromPrecisionMean($numerator->_precisionMean - $denominator->_precisionMean,
 | 
			
		||||
            $numerator->_precision - $denominator->_precision);
 | 
			
		||||
        return GaussianDistribution::fromPrecisionMean(
 | 
			
		||||
            $numerator->_precisionMean - $denominator->_precisionMean,
 | 
			
		||||
            $numerator->_precision - $denominator->_precision
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static function logRatioNormalization(GaussianDistribution $numerator, GaussianDistribution $denominator)
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,7 @@
 | 
			
		||||
<?php namespace Moserware\Skills\Numerics;
 | 
			
		||||
 | 
			
		||||
use Exception;
 | 
			
		||||
 | 
			
		||||
class Matrix
 | 
			
		||||
{
 | 
			
		||||
    const ERROR_TOLERANCE = 0.0000000001;
 | 
			
		||||
@@ -20,12 +22,10 @@ class Matrix
 | 
			
		||||
        $data = array();
 | 
			
		||||
        $result = new Matrix($rows, $columns, $data);
 | 
			
		||||
 | 
			
		||||
        for($currentColumn = 0; $currentColumn < $columns; $currentColumn++)
 | 
			
		||||
        {
 | 
			
		||||
        for ($currentColumn = 0; $currentColumn < $columns; $currentColumn++) {
 | 
			
		||||
            $currentColumnData = $columnValues[$currentColumn];
 | 
			
		||||
 | 
			
		||||
            for($currentRow = 0; $currentRow < $rows; $currentRow++)
 | 
			
		||||
            {
 | 
			
		||||
            for ($currentRow = 0; $currentRow < $rows; $currentRow++) {
 | 
			
		||||
                $result->setValue($currentRow, $currentColumn, $currentColumnData[$currentRow]);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
@@ -41,10 +41,8 @@ class Matrix
 | 
			
		||||
        $result = new Matrix($rows, $cols);
 | 
			
		||||
        $currentIndex = 2;
 | 
			
		||||
 | 
			
		||||
        for($currentRow = 0; $currentRow < $rows; $currentRow++)
 | 
			
		||||
        {
 | 
			
		||||
            for($currentCol = 0; $currentCol < $cols; $currentCol++)
 | 
			
		||||
            {
 | 
			
		||||
        for ($currentRow = 0; $currentRow < $rows; $currentRow++) {
 | 
			
		||||
            for ($currentCol = 0; $currentCol < $cols; $currentCol++) {
 | 
			
		||||
                $result->setValue($currentRow, $currentCol, $args[$currentIndex++]);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
@@ -80,12 +78,10 @@ class Matrix
 | 
			
		||||
        $rowMatrixData = $this->_matrixRowData;
 | 
			
		||||
        for ($currentRowTransposeMatrix = 0;
 | 
			
		||||
             $currentRowTransposeMatrix < $this->_columnCount;
 | 
			
		||||
             $currentRowTransposeMatrix++)
 | 
			
		||||
        {
 | 
			
		||||
             $currentRowTransposeMatrix++) {
 | 
			
		||||
            for ($currentColumnTransposeMatrix = 0;
 | 
			
		||||
                 $currentColumnTransposeMatrix < $this->_rowCount;
 | 
			
		||||
                 $currentColumnTransposeMatrix++)
 | 
			
		||||
            {
 | 
			
		||||
                 $currentColumnTransposeMatrix++) {
 | 
			
		||||
                $transposeMatrix[$currentRowTransposeMatrix][$currentColumnTransposeMatrix] =
 | 
			
		||||
                    $rowMatrixData[$currentColumnTransposeMatrix][$currentRowTransposeMatrix];
 | 
			
		||||
            }
 | 
			
		||||
@@ -102,19 +98,16 @@ class Matrix
 | 
			
		||||
    public function getDeterminant()
 | 
			
		||||
    {
 | 
			
		||||
        // Basic argument checking
 | 
			
		||||
        if (!$this->isSquare())
 | 
			
		||||
        {
 | 
			
		||||
        if (!$this->isSquare()) {
 | 
			
		||||
            throw new Exception("Matrix must be square!");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if ($this->_rowCount == 1)
 | 
			
		||||
        {
 | 
			
		||||
        if ($this->_rowCount == 1) {
 | 
			
		||||
            // Really happy path :)
 | 
			
		||||
            return $this->_matrixRowData[0][0];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if ($this->_rowCount == 2)
 | 
			
		||||
        {
 | 
			
		||||
        if ($this->_rowCount == 2) {
 | 
			
		||||
            // Happy path!
 | 
			
		||||
            // Given:
 | 
			
		||||
            // | a b |
 | 
			
		||||
@@ -124,7 +117,7 @@ class Matrix
 | 
			
		||||
            $b = $this->_matrixRowData[0][1];
 | 
			
		||||
            $c = $this->_matrixRowData[1][0];
 | 
			
		||||
            $d = $this->_matrixRowData[1][1];
 | 
			
		||||
            return $a*$d - $b*$c;
 | 
			
		||||
            return $a * $d - $b * $c;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // I use the Laplace expansion here since it's straightforward to implement.
 | 
			
		||||
@@ -136,11 +129,10 @@ class Matrix
 | 
			
		||||
        $result = 0.0;
 | 
			
		||||
 | 
			
		||||
        // I expand along the first row
 | 
			
		||||
        for ($currentColumn = 0; $currentColumn < $this->_columnCount; $currentColumn++)
 | 
			
		||||
        {
 | 
			
		||||
        for ($currentColumn = 0; $currentColumn < $this->_columnCount; $currentColumn++) {
 | 
			
		||||
            $firstRowColValue = $this->_matrixRowData[0][$currentColumn];
 | 
			
		||||
            $cofactor = $this->getCofactor(0, $currentColumn);
 | 
			
		||||
            $itemToAdd = $firstRowColValue*$cofactor;
 | 
			
		||||
            $itemToAdd = $firstRowColValue * $cofactor;
 | 
			
		||||
            $result = $result + $itemToAdd;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -149,14 +141,12 @@ class Matrix
 | 
			
		||||
 | 
			
		||||
    public function getAdjugate()
 | 
			
		||||
    {
 | 
			
		||||
        if (!$this->isSquare())
 | 
			
		||||
        {
 | 
			
		||||
        if (!$this->isSquare()) {
 | 
			
		||||
            throw new Exception("Matrix must be square!");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // See http://en.wikipedia.org/wiki/Adjugate_matrix
 | 
			
		||||
        if ($this->_rowCount == 2)
 | 
			
		||||
        {
 | 
			
		||||
        if ($this->_rowCount == 2) {
 | 
			
		||||
            // Happy path!
 | 
			
		||||
            // Adjugate of:
 | 
			
		||||
            // | a b |
 | 
			
		||||
@@ -170,17 +160,15 @@ class Matrix
 | 
			
		||||
            $c = $this->_matrixRowData[1][0];
 | 
			
		||||
            $d = $this->_matrixRowData[1][1];
 | 
			
		||||
 | 
			
		||||
            return new SquareMatrix( $d, -$b,
 | 
			
		||||
                                    -$c,  $a);
 | 
			
		||||
            return new SquareMatrix($d, -$b,
 | 
			
		||||
                -$c, $a);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // The idea is that it's the transpose of the cofactors
 | 
			
		||||
        $result = array();
 | 
			
		||||
 | 
			
		||||
        for ($currentColumn = 0; $currentColumn < $this->_columnCount; $currentColumn++)
 | 
			
		||||
        {
 | 
			
		||||
            for ($currentRow = 0; $currentRow < $this->_rowCount; $currentRow++)
 | 
			
		||||
            {
 | 
			
		||||
        for ($currentColumn = 0; $currentColumn < $this->_columnCount; $currentColumn++) {
 | 
			
		||||
            for ($currentRow = 0; $currentRow < $this->_rowCount; $currentRow++) {
 | 
			
		||||
                $result[$currentColumn][$currentRow] = $this->getCofactor($currentRow, $currentColumn);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
@@ -190,9 +178,8 @@ class Matrix
 | 
			
		||||
 | 
			
		||||
    public function getInverse()
 | 
			
		||||
    {
 | 
			
		||||
        if (($this->_rowCount == 1) && ($this->_columnCount == 1))
 | 
			
		||||
        {
 | 
			
		||||
            return new SquareMatrix(1.0/$this->_matrixRowData[0][0]);
 | 
			
		||||
        if (($this->_rowCount == 1) && ($this->_columnCount == 1)) {
 | 
			
		||||
            return new SquareMatrix(1.0 / $this->_matrixRowData[0][0]);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Take the simple approach:
 | 
			
		||||
@@ -209,11 +196,9 @@ class Matrix
 | 
			
		||||
        $columns = $matrix->getColumnCount();
 | 
			
		||||
        $newValues = array();
 | 
			
		||||
 | 
			
		||||
        for ($currentRow = 0; $currentRow < $rows; $currentRow++)
 | 
			
		||||
        {
 | 
			
		||||
            for ($currentColumn = 0; $currentColumn < $columns; $currentColumn++)
 | 
			
		||||
            {
 | 
			
		||||
                $newValues[$currentRow][$currentColumn] = $scalarValue*$matrix->getValue($currentRow, $currentColumn);
 | 
			
		||||
        for ($currentRow = 0; $currentRow < $rows; $currentRow++) {
 | 
			
		||||
            for ($currentColumn = 0; $currentColumn < $columns; $currentColumn++) {
 | 
			
		||||
                $newValues[$currentRow][$currentColumn] = $scalarValue * $matrix->getValue($currentRow, $currentColumn);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -223,11 +208,10 @@ class Matrix
 | 
			
		||||
    public static function add($left, $right)
 | 
			
		||||
    {
 | 
			
		||||
        if (
 | 
			
		||||
                ($left->getRowCount() != $right->getRowCount())
 | 
			
		||||
                ||
 | 
			
		||||
                ($left->getColumnCount() != $right->getColumnCount())
 | 
			
		||||
           )
 | 
			
		||||
        {
 | 
			
		||||
            ($left->getRowCount() != $right->getRowCount())
 | 
			
		||||
            ||
 | 
			
		||||
            ($left->getColumnCount() != $right->getColumnCount())
 | 
			
		||||
        ) {
 | 
			
		||||
            throw new Exception("Matrices must be of the same size");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -235,14 +219,12 @@ class Matrix
 | 
			
		||||
 | 
			
		||||
        $resultMatrix = array();
 | 
			
		||||
 | 
			
		||||
        for ($currentRow = 0; $currentRow < $left->getRowCount(); $currentRow++)
 | 
			
		||||
        {
 | 
			
		||||
            for ($currentColumn = 0; $currentColumn < $right->getColumnCount(); $currentColumn++)
 | 
			
		||||
            {
 | 
			
		||||
        for ($currentRow = 0; $currentRow < $left->getRowCount(); $currentRow++) {
 | 
			
		||||
            for ($currentColumn = 0; $currentColumn < $right->getColumnCount(); $currentColumn++) {
 | 
			
		||||
                $resultMatrix[$currentRow][$currentColumn] =
 | 
			
		||||
                   $left->getValue($currentRow, $currentColumn)
 | 
			
		||||
                   +
 | 
			
		||||
                   $right->getValue($currentRow, $currentColumn);
 | 
			
		||||
                    $left->getValue($currentRow, $currentColumn)
 | 
			
		||||
                    +
 | 
			
		||||
                    $right->getValue($currentRow, $currentColumn);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -254,8 +236,7 @@ class Matrix
 | 
			
		||||
        // Just your standard matrix multiplication.
 | 
			
		||||
        // See http://en.wikipedia.org/wiki/Matrix_multiplication for details
 | 
			
		||||
 | 
			
		||||
        if ($left->getColumnCount() != $right->getRowCount())
 | 
			
		||||
        {
 | 
			
		||||
        if ($left->getColumnCount() != $right->getRowCount()) {
 | 
			
		||||
            throw new Exception("The width of the left matrix must match the height of the right matrix");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -264,17 +245,14 @@ class Matrix
 | 
			
		||||
 | 
			
		||||
        $resultMatrix = array();
 | 
			
		||||
 | 
			
		||||
        for ($currentRow = 0; $currentRow < $resultRows; $currentRow++)
 | 
			
		||||
        {            
 | 
			
		||||
            for ($currentColumn = 0; $currentColumn < $resultColumns; $currentColumn++)
 | 
			
		||||
            {
 | 
			
		||||
        for ($currentRow = 0; $currentRow < $resultRows; $currentRow++) {
 | 
			
		||||
            for ($currentColumn = 0; $currentColumn < $resultColumns; $currentColumn++) {
 | 
			
		||||
                $productValue = 0;
 | 
			
		||||
 | 
			
		||||
                for ($vectorIndex = 0; $vectorIndex < $left->getColumnCount(); $vectorIndex++)
 | 
			
		||||
                {
 | 
			
		||||
                for ($vectorIndex = 0; $vectorIndex < $left->getColumnCount(); $vectorIndex++) {
 | 
			
		||||
                    $leftValue = $left->getValue($currentRow, $vectorIndex);
 | 
			
		||||
                    $rightValue = $right->getValue($vectorIndex, $currentColumn);
 | 
			
		||||
                    $vectorIndexProduct = $leftValue*$rightValue;
 | 
			
		||||
                    $vectorIndexProduct = $leftValue * $rightValue;
 | 
			
		||||
                    $productValue = $productValue + $vectorIndexProduct;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
@@ -283,7 +261,7 @@ class Matrix
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return new Matrix($resultRows, $resultColumns, $resultMatrix);
 | 
			
		||||
    }   
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private function getMinorMatrix($rowToRemove, $columnToRemove)
 | 
			
		||||
    {
 | 
			
		||||
@@ -294,19 +272,15 @@ class Matrix
 | 
			
		||||
 | 
			
		||||
        $actualRow = 0;
 | 
			
		||||
 | 
			
		||||
        for ($currentRow = 0; $currentRow < $this->_rowCount; $currentRow++)
 | 
			
		||||
        {
 | 
			
		||||
            if ($currentRow == $rowToRemove)
 | 
			
		||||
            {
 | 
			
		||||
        for ($currentRow = 0; $currentRow < $this->_rowCount; $currentRow++) {
 | 
			
		||||
            if ($currentRow == $rowToRemove) {
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            $actualCol = 0;
 | 
			
		||||
 | 
			
		||||
            for ($currentColumn = 0; $currentColumn < $this->_columnCount; $currentColumn++)
 | 
			
		||||
            {
 | 
			
		||||
                if ($currentColumn == $columnToRemove)
 | 
			
		||||
                {
 | 
			
		||||
            for ($currentColumn = 0; $currentColumn < $this->_columnCount; $currentColumn++) {
 | 
			
		||||
                if ($currentColumn == $columnToRemove) {
 | 
			
		||||
                    continue;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
@@ -326,41 +300,33 @@ class Matrix
 | 
			
		||||
        // See http://en.wikipedia.org/wiki/Cofactor_(linear_algebra) for details
 | 
			
		||||
        // REVIEW: should things be reversed since I'm 0 indexed?
 | 
			
		||||
        $sum = $rowToRemove + $columnToRemove;
 | 
			
		||||
        $isEven = ($sum%2 == 0);
 | 
			
		||||
        $isEven = ($sum % 2 == 0);
 | 
			
		||||
 | 
			
		||||
        if ($isEven)
 | 
			
		||||
        {
 | 
			
		||||
        if ($isEven) {
 | 
			
		||||
            return $this->getMinorMatrix($rowToRemove, $columnToRemove)->getDeterminant();
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            return -1.0*$this->getMinorMatrix($rowToRemove, $columnToRemove)->getDeterminant();
 | 
			
		||||
        } else {
 | 
			
		||||
            return -1.0 * $this->getMinorMatrix($rowToRemove, $columnToRemove)->getDeterminant();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function equals($otherMatrix)
 | 
			
		||||
    {
 | 
			
		||||
        // If one is null, but not both, return false.
 | 
			
		||||
        if ($otherMatrix == null)
 | 
			
		||||
        {
 | 
			
		||||
        if ($otherMatrix == null) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (($this->_rowCount != $otherMatrix->getRowCount()) || ($this->_columnCount != $otherMatrix->getColumnCount()))
 | 
			
		||||
        {
 | 
			
		||||
        if (($this->_rowCount != $otherMatrix->getRowCount()) || ($this->_columnCount != $otherMatrix->getColumnCount())) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        for ($currentRow = 0; $currentRow < $this->_rowCount; $currentRow++)
 | 
			
		||||
        {
 | 
			
		||||
            for ($currentColumn = 0; $currentColumn < $this->_columnCount; $currentColumn++)
 | 
			
		||||
            {
 | 
			
		||||
        for ($currentRow = 0; $currentRow < $this->_rowCount; $currentRow++) {
 | 
			
		||||
            for ($currentColumn = 0; $currentColumn < $this->_columnCount; $currentColumn++) {
 | 
			
		||||
                $delta =
 | 
			
		||||
                    abs($this->_matrixRowData[$currentRow][$currentColumn] -
 | 
			
		||||
                        $otherMatrix->getValue($currentRow, $currentColumn));
 | 
			
		||||
 | 
			
		||||
                if ($delta > self::ERROR_TOLERANCE)
 | 
			
		||||
                {
 | 
			
		||||
                if ($delta > self::ERROR_TOLERANCE) {
 | 
			
		||||
                    return false;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 
 | 
			
		||||
@@ -5,8 +5,7 @@ class Vector extends Matrix
 | 
			
		||||
    public function __construct(array $vectorValues)
 | 
			
		||||
    {
 | 
			
		||||
        $columnValues = array();
 | 
			
		||||
        foreach($vectorValues as $currentVectorValue)
 | 
			
		||||
        {
 | 
			
		||||
        foreach ($vectorValues as $currentVectorValue) {
 | 
			
		||||
            $columnValues[] = array($currentVectorValue);
 | 
			
		||||
        }
 | 
			
		||||
        parent::__construct(count($vectorValues), 1, $columnValues);
 | 
			
		||||
 
 | 
			
		||||
@@ -34,9 +34,8 @@ class Player implements ISupportPartialPlay, ISupportPartialUpdate
 | 
			
		||||
    /**
 | 
			
		||||
     * The identifier for the player, such as a name.
 | 
			
		||||
     */
 | 
			
		||||
    public function &getId()
 | 
			
		||||
    public function getId()
 | 
			
		||||
    {
 | 
			
		||||
        $id = &$this->_Id;
 | 
			
		||||
        return $this->_Id;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -9,27 +9,24 @@ class RatingContainer
 | 
			
		||||
        $this->_playerToRating = new HashMap();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function &getRating(Player &$player)
 | 
			
		||||
    public function getRating(Player $player)
 | 
			
		||||
    {
 | 
			
		||||
        $rating = &$this->_playerToRating->getValue($player);
 | 
			
		||||
        return $rating;
 | 
			
		||||
        return $this->_playerToRating->getValue($player);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function setRating(Player &$player, Rating $rating)
 | 
			
		||||
    public function setRating(Player $player, Rating $rating)
 | 
			
		||||
    {
 | 
			
		||||
        return $this->_playerToRating->setValue($player, $rating);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function &getAllPlayers()
 | 
			
		||||
    public function getAllPlayers()
 | 
			
		||||
    {
 | 
			
		||||
        $allPlayers = &$this->_playerToRating->getAllKeys();
 | 
			
		||||
        return $allPlayers;
 | 
			
		||||
        return $this->_playerToRating->getAllKeys();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function &getAllRatings()
 | 
			
		||||
    public function getAllRatings()
 | 
			
		||||
    {
 | 
			
		||||
        $allRatings = &$this->_playerToRating->getAllValues();
 | 
			
		||||
        return $allRatings;
 | 
			
		||||
        return $this->_playerToRating->getAllValues();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function count()
 | 
			
		||||
 
 | 
			
		||||
@@ -37,23 +37,21 @@ abstract class SkillCalculator
 | 
			
		||||
     * @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 abstract function calculateMatchQuality(GameInfo $gameInfo, array $teamsOfPlayerToRatings);
 | 
			
		||||
 | 
			
		||||
    public function isSupported($option)
 | 
			
		||||
    {
 | 
			
		||||
        return ($this->_supportedOptions & $option) == $option;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected function validateTeamCountAndPlayersCountPerTeam(array &$teamsOfPlayerToRatings)
 | 
			
		||||
    protected function validateTeamCountAndPlayersCountPerTeam(array $teamsOfPlayerToRatings)
 | 
			
		||||
    {
 | 
			
		||||
        self::validateTeamCountAndPlayersCountPerTeamWithRanges($teamsOfPlayerToRatings, $this->_totalTeamsAllowed, $this->_playersPerTeamAllowed);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static function validateTeamCountAndPlayersCountPerTeamWithRanges(
 | 
			
		||||
        array &$teams,
 | 
			
		||||
        TeamsRange &$totalTeams,
 | 
			
		||||
        PlayersRange &$playersPerTeam)
 | 
			
		||||
    private static function validateTeamCountAndPlayersCountPerTeamWithRanges(array $teams,
 | 
			
		||||
                                                                              TeamsRange $totalTeams,
 | 
			
		||||
                                                                              PlayersRange $playersPerTeam)
 | 
			
		||||
    {
 | 
			
		||||
        $countOfTeams = 0;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,7 @@
 | 
			
		||||
 | 
			
		||||
class Team extends RatingContainer
 | 
			
		||||
{
 | 
			
		||||
    public function __construct(Player &$player = null, Rating $rating = null)
 | 
			
		||||
    public function __construct(Player $player = null, Rating $rating = null)
 | 
			
		||||
    {
 | 
			
		||||
        parent::__construct();
 | 
			
		||||
        
 | 
			
		||||
@@ -12,7 +12,7 @@ class Team extends RatingContainer
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function addPlayer(Player &$player, Rating $rating)
 | 
			
		||||
    public function addPlayer(Player $player, Rating $rating)
 | 
			
		||||
    {
 | 
			
		||||
        $this->setRating($player, $rating);
 | 
			
		||||
        return $this;
 | 
			
		||||
 
 | 
			
		||||
@@ -7,8 +7,8 @@ class Teams
 | 
			
		||||
        $args = func_get_args();
 | 
			
		||||
        $result = array();
 | 
			
		||||
 | 
			
		||||
        foreach ($args as &$currentTeam) {
 | 
			
		||||
            $localCurrentTeam = &$currentTeam;
 | 
			
		||||
        foreach ($args as $currentTeam) {
 | 
			
		||||
            $localCurrentTeam = $currentTeam;
 | 
			
		||||
            $result[] = $localCurrentTeam;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -43,8 +43,7 @@ class FactorGraphTrueSkillCalculator extends SkillCalculator
 | 
			
		||||
        return $factorGraph->getUpdatedRatings();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function calculateMatchQuality(GameInfo $gameInfo,
 | 
			
		||||
                                          array &$teams)
 | 
			
		||||
    public function calculateMatchQuality(GameInfo $gameInfo, array $teams)
 | 
			
		||||
    {
 | 
			
		||||
        // We need to create the A matrix which is the player team assigments.
 | 
			
		||||
        $teamAssignmentsList = $teams;
 | 
			
		||||
@@ -87,7 +86,7 @@ class FactorGraphTrueSkillCalculator extends SkillCalculator
 | 
			
		||||
        return $result;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static function getPlayerMeansVector(array &$teamAssignmentsList)
 | 
			
		||||
    private static function getPlayerMeansVector(array $teamAssignmentsList)
 | 
			
		||||
    {
 | 
			
		||||
        // A simple vector of all the player means.
 | 
			
		||||
        return new Vector(self::getPlayerRatingValues($teamAssignmentsList,
 | 
			
		||||
@@ -96,7 +95,7 @@ class FactorGraphTrueSkillCalculator extends SkillCalculator
 | 
			
		||||
            }));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static function getPlayerCovarianceMatrix(array &$teamAssignmentsList)
 | 
			
		||||
    private static function getPlayerCovarianceMatrix(array $teamAssignmentsList)
 | 
			
		||||
    {
 | 
			
		||||
        // This is a square matrix whose diagonal values represent the variance (square of standard deviation) of all
 | 
			
		||||
        // players.
 | 
			
		||||
@@ -108,8 +107,7 @@ class FactorGraphTrueSkillCalculator extends SkillCalculator
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Helper function that gets a list of values for all player ratings
 | 
			
		||||
    private static function getPlayerRatingValues(array &$teamAssignmentsList,
 | 
			
		||||
                                                  $playerRatingFunction)
 | 
			
		||||
    private static function getPlayerRatingValues(array $teamAssignmentsList, $playerRatingFunction)
 | 
			
		||||
    {
 | 
			
		||||
        $playerRatingValues = array();
 | 
			
		||||
 | 
			
		||||
@@ -122,7 +120,7 @@ class FactorGraphTrueSkillCalculator extends SkillCalculator
 | 
			
		||||
        return $playerRatingValues;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static function createPlayerTeamAssignmentMatrix(&$teamAssignmentsList, $totalPlayers)
 | 
			
		||||
    private static function createPlayerTeamAssignmentMatrix($teamAssignmentsList, $totalPlayers)
 | 
			
		||||
    {
 | 
			
		||||
        // The team assignment matrix is often referred to as the "A" matrix. It's a matrix whose rows represent the players
 | 
			
		||||
        // and the columns represent teams. At Matrix[row, column] represents that player[row] is on team[col]
 | 
			
		||||
 
 | 
			
		||||
@@ -18,19 +18,19 @@ abstract class GaussianFactor extends Factor
 | 
			
		||||
     * @param Variable $variable
 | 
			
		||||
     * @return float|int
 | 
			
		||||
     */
 | 
			
		||||
    protected function sendMessageVariable(Message &$message, Variable &$variable)
 | 
			
		||||
    protected function sendMessageVariable(Message $message, Variable $variable)
 | 
			
		||||
    {
 | 
			
		||||
        $marginal = &$variable->getValue();
 | 
			
		||||
        $messageValue = &$message->getValue();
 | 
			
		||||
        $marginal = $variable->getValue();
 | 
			
		||||
        $messageValue = $message->getValue();
 | 
			
		||||
        $logZ = GaussianDistribution::logProductNormalization($marginal, $messageValue);
 | 
			
		||||
        $variable->setValue(GaussianDistribution::multiply($marginal, $messageValue));
 | 
			
		||||
        return $logZ;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function &createVariableToMessageBinding(Variable &$variable)
 | 
			
		||||
    public function createVariableToMessageBinding(Variable $variable)
 | 
			
		||||
    {
 | 
			
		||||
        $newDistribution = GaussianDistribution::fromPrecisionMean(0, 0);
 | 
			
		||||
        $binding = &parent::createVariableToMessageBindingWithMessage($variable,
 | 
			
		||||
        $binding = parent::createVariableToMessageBindingWithMessage($variable,
 | 
			
		||||
            new Message(
 | 
			
		||||
                $newDistribution,
 | 
			
		||||
                sprintf("message from %s to %s", $this, $variable)));
 | 
			
		||||
 
 | 
			
		||||
@@ -14,7 +14,7 @@ class GaussianGreaterThanFactor extends GaussianFactor
 | 
			
		||||
{
 | 
			
		||||
    private $_epsilon;
 | 
			
		||||
 | 
			
		||||
    public function __construct($epsilon, Variable &$variable)
 | 
			
		||||
    public function __construct($epsilon, Variable $variable)
 | 
			
		||||
    {
 | 
			
		||||
        parent::__construct(\sprintf("%s > %.2f", $variable, $epsilon));
 | 
			
		||||
        $this->_epsilon = $epsilon;
 | 
			
		||||
@@ -23,20 +23,26 @@ class GaussianGreaterThanFactor extends GaussianFactor
 | 
			
		||||
 | 
			
		||||
    public function getLogNormalization()
 | 
			
		||||
    {
 | 
			
		||||
        $vars = &$this->getVariables();
 | 
			
		||||
        $marginal = &$vars[0]->getValue();
 | 
			
		||||
        $messages = &$this->getMessages();
 | 
			
		||||
        $message = &$messages[0]->getValue();
 | 
			
		||||
        /** @var Variable[] $vars */
 | 
			
		||||
        $vars = $this->getVariables();
 | 
			
		||||
        $marginal = $vars[0]->getValue();
 | 
			
		||||
 | 
			
		||||
        /** @var Message[] $messages */
 | 
			
		||||
        $messages = $this->getMessages();
 | 
			
		||||
        $message = $messages[0]->getValue();
 | 
			
		||||
        $messageFromVariable = GaussianDistribution::divide($marginal, $message);
 | 
			
		||||
        return -GaussianDistribution::logProductNormalization($messageFromVariable, $message)
 | 
			
		||||
        +
 | 
			
		||||
        log(
 | 
			
		||||
            GaussianDistribution::cumulativeTo(($messageFromVariable->getMean() - $this->_epsilon) /
 | 
			
		||||
                $messageFromVariable->getStandardDeviation()));
 | 
			
		||||
            GaussianDistribution::cumulativeTo(
 | 
			
		||||
                ($messageFromVariable->getMean() - $this->_epsilon) /
 | 
			
		||||
                $messageFromVariable->getStandardDeviation()
 | 
			
		||||
            )
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected function updateMessageVariable(Message &$message, Variable &$variable)
 | 
			
		||||
    protected function updateMessageVariable(Message $message, Variable $variable)
 | 
			
		||||
    {
 | 
			
		||||
        $oldMarginal = clone $variable->getValue();
 | 
			
		||||
        $oldMessage = clone $message->getValue();
 | 
			
		||||
@@ -55,16 +61,18 @@ class GaussianGreaterThanFactor extends GaussianFactor
 | 
			
		||||
        $denom = 1.0 - TruncatedGaussianCorrectionFunctions::wExceedsMargin($dOnSqrtC, $epsilsonTimesSqrtC);
 | 
			
		||||
 | 
			
		||||
        $newPrecision = $c / $denom;
 | 
			
		||||
        $newPrecisionMean = ($d +
 | 
			
		||||
        $newPrecisionMean = (
 | 
			
		||||
                $d +
 | 
			
		||||
                $sqrtC *
 | 
			
		||||
                TruncatedGaussianCorrectionFunctions::vExceedsMargin($dOnSqrtC, $epsilsonTimesSqrtC)) /
 | 
			
		||||
            $denom;
 | 
			
		||||
                TruncatedGaussianCorrectionFunctions::vExceedsMargin($dOnSqrtC, $epsilsonTimesSqrtC)
 | 
			
		||||
            ) / $denom;
 | 
			
		||||
 | 
			
		||||
        $newMarginal = GaussianDistribution::fromPrecisionMean($newPrecisionMean, $newPrecision);
 | 
			
		||||
 | 
			
		||||
        $newMessage = GaussianDistribution::divide(
 | 
			
		||||
            GaussianDistribution::multiply($oldMessage, $newMarginal),
 | 
			
		||||
            $oldMarginal);
 | 
			
		||||
            $oldMarginal
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Update the message and marginal
 | 
			
		||||
        $message->setValue($newMessage);
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
<?php namespace Moserware\Skills\TrueSkill\Factors;
 | 
			
		||||
 | 
			
		||||
use Exception;
 | 
			
		||||
use Moserware\Skills\FactorGraphs\KeyedVariable;
 | 
			
		||||
use Moserware\Skills\FactorGraphs\Message;
 | 
			
		||||
use Moserware\Skills\FactorGraphs\Variable;
 | 
			
		||||
use Moserware\Skills\Numerics\GaussianDistribution;
 | 
			
		||||
@@ -14,7 +15,7 @@ class GaussianLikelihoodFactor extends GaussianFactor
 | 
			
		||||
{
 | 
			
		||||
    private $_precision;
 | 
			
		||||
 | 
			
		||||
    public function __construct($betaSquared, Variable &$variable1, Variable &$variable2)
 | 
			
		||||
    public function __construct($betaSquared, Variable $variable1, Variable $variable2)
 | 
			
		||||
    {
 | 
			
		||||
        parent::__construct(sprintf("Likelihood of %s going to %s", $variable2, $variable1));
 | 
			
		||||
        $this->_precision = 1.0 / $betaSquared;
 | 
			
		||||
@@ -24,16 +25,18 @@ class GaussianLikelihoodFactor extends GaussianFactor
 | 
			
		||||
 | 
			
		||||
    public function getLogNormalization()
 | 
			
		||||
    {
 | 
			
		||||
        $vars = &$this->getVariables();
 | 
			
		||||
        $messages = &$this->getMessages();
 | 
			
		||||
        /** @var KeyedVariable[]|mixed $vars */
 | 
			
		||||
        $vars = $this->getVariables();
 | 
			
		||||
        /** @var Message[] $messages */
 | 
			
		||||
        $messages = $this->getMessages();
 | 
			
		||||
 | 
			
		||||
        return GaussianDistribution::logRatioNormalization(
 | 
			
		||||
            $vars[0]->getValue(),
 | 
			
		||||
            $messages[0]->getValue());
 | 
			
		||||
            $messages[0]->getValue()
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private function updateHelper(Message &$message1, Message &$message2,
 | 
			
		||||
                                  Variable &$variable1, Variable &$variable2)
 | 
			
		||||
    private function updateHelper(Message $message1, Message $message2, Variable $variable1, Variable $variable2)
 | 
			
		||||
    {
 | 
			
		||||
        $message1Value = clone $message1->getValue();
 | 
			
		||||
        $message2Value = clone $message2->getValue();
 | 
			
		||||
@@ -45,7 +48,8 @@ class GaussianLikelihoodFactor extends GaussianFactor
 | 
			
		||||
 | 
			
		||||
        $newMessage = GaussianDistribution::fromPrecisionMean(
 | 
			
		||||
            $a * ($marginal2->getPrecisionMean() - $message2Value->getPrecisionMean()),
 | 
			
		||||
            $a * ($marginal2->getPrecision() - $message2Value->getPrecision()));
 | 
			
		||||
            $a * ($marginal2->getPrecision() - $message2Value->getPrecision())
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        $oldMarginalWithoutMessage = GaussianDistribution::divide($marginal1, $message1Value);
 | 
			
		||||
 | 
			
		||||
@@ -62,8 +66,8 @@ class GaussianLikelihoodFactor extends GaussianFactor
 | 
			
		||||
 | 
			
		||||
    public function updateMessageIndex($messageIndex)
 | 
			
		||||
    {
 | 
			
		||||
        $messages = &$this->getMessages();
 | 
			
		||||
        $vars = &$this->getVariables();
 | 
			
		||||
        $messages = $this->getMessages();
 | 
			
		||||
        $vars = $this->getVariables();
 | 
			
		||||
 | 
			
		||||
        switch ($messageIndex) {
 | 
			
		||||
            case 0:
 | 
			
		||||
 
 | 
			
		||||
@@ -13,7 +13,7 @@ class GaussianPriorFactor extends GaussianFactor
 | 
			
		||||
{
 | 
			
		||||
    private $_newMessage;
 | 
			
		||||
 | 
			
		||||
    public function __construct($mean, $variance, Variable &$variable)
 | 
			
		||||
    public function __construct($mean, $variance, Variable $variable)
 | 
			
		||||
    {
 | 
			
		||||
        parent::__construct(sprintf("Prior value going to %s", $variable));
 | 
			
		||||
        $this->_newMessage = new GaussianDistribution($mean, sqrt($variance));
 | 
			
		||||
@@ -23,18 +23,17 @@ class GaussianPriorFactor extends GaussianFactor
 | 
			
		||||
        $this->createVariableToMessageBindingWithMessage($variable, $newMessage);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected function updateMessageVariable(Message &$message, Variable &$variable)
 | 
			
		||||
    protected function updateMessageVariable(Message $message, Variable $variable)
 | 
			
		||||
    {
 | 
			
		||||
        $oldMarginal = clone $variable->getValue();
 | 
			
		||||
        $oldMessage = $message;
 | 
			
		||||
        $newMarginal =
 | 
			
		||||
            GaussianDistribution::fromPrecisionMean(
 | 
			
		||||
                $oldMarginal->getPrecisionMean() + $this->_newMessage->getPrecisionMean() - $oldMessage->getValue()->getPrecisionMean(),
 | 
			
		||||
                $oldMarginal->getPrecision() + $this->_newMessage->getPrecision() - $oldMessage->getValue()->getPrecision());
 | 
			
		||||
        $newMarginal = GaussianDistribution::fromPrecisionMean(
 | 
			
		||||
            $oldMarginal->getPrecisionMean() + $this->_newMessage->getPrecisionMean() - $oldMessage->getValue()->getPrecisionMean(),
 | 
			
		||||
            $oldMarginal->getPrecision() + $this->_newMessage->getPrecision() - $oldMessage->getValue()->getPrecision()
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        $variable->setValue($newMarginal);
 | 
			
		||||
        $newMessage = &$this->_newMessage;
 | 
			
		||||
        $message->setValue($newMessage);
 | 
			
		||||
        $message->setValue($this->_newMessage);
 | 
			
		||||
        return GaussianDistribution::subtract($oldMarginal, $newMarginal);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -20,7 +20,7 @@ class GaussianWeightedSumFactor extends GaussianFactor
 | 
			
		||||
    private $_weights;
 | 
			
		||||
    private $_weightsSquared;
 | 
			
		||||
 | 
			
		||||
    public function __construct(Variable &$sumVariable, array &$variablesToSum, array &$variableWeights = null)
 | 
			
		||||
    public function __construct(Variable $sumVariable, array $variablesToSum, array $variableWeights = null)
 | 
			
		||||
    {
 | 
			
		||||
        parent::__construct(self::createName($sumVariable, $variablesToSum, $variableWeights));
 | 
			
		||||
        $this->_weights = array();
 | 
			
		||||
@@ -29,7 +29,7 @@ class GaussianWeightedSumFactor extends GaussianFactor
 | 
			
		||||
        // The first weights are a straightforward copy
 | 
			
		||||
        // v_0 = a_1*v_1 + a_2*v_2 + ... + a_n * v_n
 | 
			
		||||
        $variableWeightsLength = count($variableWeights);
 | 
			
		||||
        $this->_weights[0] = \array_fill(0, count($variableWeights), 0);
 | 
			
		||||
        $this->_weights[0] = array_fill(0, count($variableWeights), 0);
 | 
			
		||||
 | 
			
		||||
        for ($i = 0; $i < $variableWeightsLength; $i++) {
 | 
			
		||||
            $weight = &$variableWeights[$i];
 | 
			
		||||
@@ -104,16 +104,16 @@ class GaussianWeightedSumFactor extends GaussianFactor
 | 
			
		||||
 | 
			
		||||
        $this->createVariableToMessageBinding($sumVariable);
 | 
			
		||||
 | 
			
		||||
        foreach ($variablesToSum as &$currentVariable) {
 | 
			
		||||
            $localCurrentVariable = &$currentVariable;
 | 
			
		||||
        foreach ($variablesToSum as $currentVariable) {
 | 
			
		||||
            $localCurrentVariable = $currentVariable;
 | 
			
		||||
            $this->createVariableToMessageBinding($localCurrentVariable);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getLogNormalization()
 | 
			
		||||
    {
 | 
			
		||||
        $vars = &$this->getVariables();
 | 
			
		||||
        $messages = &$this->getMessages();
 | 
			
		||||
        $vars = $this->getVariables();
 | 
			
		||||
        $messages = $this->getMessages();
 | 
			
		||||
 | 
			
		||||
        $result = 0.0;
 | 
			
		||||
 | 
			
		||||
@@ -126,9 +126,7 @@ class GaussianWeightedSumFactor extends GaussianFactor
 | 
			
		||||
        return $result;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private function updateHelper(array &$weights, array &$weightsSquared,
 | 
			
		||||
                                  array &$messages,
 | 
			
		||||
                                  array &$variables)
 | 
			
		||||
    private function updateHelper(array $weights, array $weightsSquared, array $messages, array $variables)
 | 
			
		||||
    {
 | 
			
		||||
        // Potentially look at http://mathworld.wolfram.com/NormalSumDistribution.html for clues as
 | 
			
		||||
        // to what it's doing
 | 
			
		||||
@@ -185,23 +183,23 @@ class GaussianWeightedSumFactor extends GaussianFactor
 | 
			
		||||
 | 
			
		||||
    public function updateMessageIndex($messageIndex)
 | 
			
		||||
    {
 | 
			
		||||
        $allMessages = &$this->getMessages();
 | 
			
		||||
        $allVariables = &$this->getVariables();
 | 
			
		||||
        $allMessages = $this->getMessages();
 | 
			
		||||
        $allVariables = $this->getVariables();
 | 
			
		||||
 | 
			
		||||
        Guard::argumentIsValidIndex($messageIndex, count($allMessages), "messageIndex");
 | 
			
		||||
 | 
			
		||||
        $updatedMessages = array();
 | 
			
		||||
        $updatedVariables = array();
 | 
			
		||||
 | 
			
		||||
        $indicesToUse = &$this->_variableIndexOrdersForWeights[$messageIndex];
 | 
			
		||||
        $indicesToUse = $this->_variableIndexOrdersForWeights[$messageIndex];
 | 
			
		||||
 | 
			
		||||
        // The tricky part here is that we have to put the messages and variables in the same
 | 
			
		||||
        // 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++) {
 | 
			
		||||
            $updatedMessages[] = &$allMessages[$indicesToUse[$i]];
 | 
			
		||||
            $updatedVariables[] = &$allVariables[$indicesToUse[$i]];
 | 
			
		||||
            $updatedMessages[] = $allMessages[$indicesToUse[$i]];
 | 
			
		||||
            $updatedVariables[] = $allVariables[$indicesToUse[$i]];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return $this->updateHelper($this->_weights[$messageIndex],
 | 
			
		||||
 
 | 
			
		||||
@@ -14,7 +14,7 @@ class GaussianWithinFactor extends GaussianFactor
 | 
			
		||||
{
 | 
			
		||||
    private $_epsilon;
 | 
			
		||||
 | 
			
		||||
    public function __construct($epsilon, Variable &$variable)
 | 
			
		||||
    public function __construct($epsilon, Variable $variable)
 | 
			
		||||
    {
 | 
			
		||||
        parent::__construct(sprintf("%s <= %.2f", $variable, $epsilon));
 | 
			
		||||
        $this->_epsilon = $epsilon;
 | 
			
		||||
@@ -23,11 +23,13 @@ class GaussianWithinFactor extends GaussianFactor
 | 
			
		||||
 | 
			
		||||
    public function getLogNormalization()
 | 
			
		||||
    {
 | 
			
		||||
        $variables = &$this->getVariables();
 | 
			
		||||
        $marginal = &$variables[0]->getValue();
 | 
			
		||||
        /** @var Variable[] $variables */
 | 
			
		||||
        $variables = $this->getVariables();
 | 
			
		||||
        $marginal = $variables[0]->getValue();
 | 
			
		||||
 | 
			
		||||
        $messages = &$this->getMessages();
 | 
			
		||||
        $message = &$messages[0]->getValue();
 | 
			
		||||
        /** @var Message[] $messages */
 | 
			
		||||
        $messages = $this->getMessages();
 | 
			
		||||
        $message = $messages[0]->getValue();
 | 
			
		||||
        $messageFromVariable = GaussianDistribution::divide($marginal, $message);
 | 
			
		||||
        $mean = $messageFromVariable->getMean();
 | 
			
		||||
        $std = $messageFromVariable->getStandardDeviation();
 | 
			
		||||
@@ -38,7 +40,7 @@ class GaussianWithinFactor extends GaussianFactor
 | 
			
		||||
        return -GaussianDistribution::logProductNormalization($messageFromVariable, $message) + log($z);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected function updateMessageVariable(Message &$message, Variable &$variable)
 | 
			
		||||
    protected function updateMessageVariable(Message $message, Variable $variable)
 | 
			
		||||
    {
 | 
			
		||||
        $oldMarginal = clone $variable->getValue();
 | 
			
		||||
        $oldMessage = clone $message->getValue();
 | 
			
		||||
@@ -55,15 +57,16 @@ class GaussianWithinFactor extends GaussianFactor
 | 
			
		||||
 | 
			
		||||
        $denominator = 1.0 - TruncatedGaussianCorrectionFunctions::wWithinMargin($dOnSqrtC, $epsilonTimesSqrtC);
 | 
			
		||||
        $newPrecision = $c / $denominator;
 | 
			
		||||
        $newPrecisionMean = ($d +
 | 
			
		||||
                $sqrtC *
 | 
			
		||||
                TruncatedGaussianCorrectionFunctions::vWithinMargin($dOnSqrtC, $epsilonTimesSqrtC)) /
 | 
			
		||||
            $denominator;
 | 
			
		||||
        $newPrecisionMean = (   $d +
 | 
			
		||||
                                $sqrtC *
 | 
			
		||||
                                TruncatedGaussianCorrectionFunctions::vWithinMargin($dOnSqrtC, $epsilonTimesSqrtC)
 | 
			
		||||
                            ) / $denominator;
 | 
			
		||||
 | 
			
		||||
        $newMarginal = GaussianDistribution::fromPrecisionMean($newPrecisionMean, $newPrecision);
 | 
			
		||||
        $newMessage = GaussianDistribution::divide(
 | 
			
		||||
            GaussianDistribution::multiply($oldMessage, $newMarginal),
 | 
			
		||||
            $oldMarginal);
 | 
			
		||||
            $oldMarginal
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Update the message and marginal
 | 
			
		||||
        $message->setValue($newMessage);
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,6 @@
 | 
			
		||||
<?php namespace Moserware\Skills\TrueSkill\Layers;
 | 
			
		||||
 | 
			
		||||
use Exception;
 | 
			
		||||
use Moserware\Skills\FactorGraphs\ScheduleLoop;
 | 
			
		||||
use Moserware\Skills\FactorGraphs\ScheduleSequence;
 | 
			
		||||
use Moserware\Skills\FactorGraphs\ScheduleStep;
 | 
			
		||||
@@ -11,30 +12,31 @@ class IteratedTeamDifferencesInnerLayer extends TrueSkillFactorGraphLayer
 | 
			
		||||
    private $_TeamDifferencesComparisonLayer;
 | 
			
		||||
    private $_TeamPerformancesToTeamPerformanceDifferencesLayer;
 | 
			
		||||
 | 
			
		||||
    public function __construct(TrueSkillFactorGraph &$parentGraph,
 | 
			
		||||
                                TeamPerformancesToTeamPerformanceDifferencesLayer &$teamPerformancesToPerformanceDifferences,
 | 
			
		||||
                                TeamDifferencesComparisonLayer &$teamDifferencesComparisonLayer)
 | 
			
		||||
    public function __construct(TrueSkillFactorGraph $parentGraph,
 | 
			
		||||
                                TeamPerformancesToTeamPerformanceDifferencesLayer $teamPerformancesToPerformanceDifferences,
 | 
			
		||||
                                TeamDifferencesComparisonLayer $teamDifferencesComparisonLayer)
 | 
			
		||||
    {
 | 
			
		||||
        parent::__construct($parentGraph);
 | 
			
		||||
        $this->_TeamPerformancesToTeamPerformanceDifferencesLayer = $teamPerformancesToPerformanceDifferences;
 | 
			
		||||
        $this->_TeamDifferencesComparisonLayer = $teamDifferencesComparisonLayer;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function &getLocalFactors()
 | 
			
		||||
    public function getLocalFactors()
 | 
			
		||||
    {
 | 
			
		||||
        $localFactors =
 | 
			
		||||
            array_merge($this->_TeamPerformancesToTeamPerformanceDifferencesLayer->getLocalFactors(),
 | 
			
		||||
                $this->_TeamDifferencesComparisonLayer->getLocalFactors());
 | 
			
		||||
        $localFactors = array_merge($this->_TeamPerformancesToTeamPerformanceDifferencesLayer->getLocalFactors(),
 | 
			
		||||
            $this->_TeamDifferencesComparisonLayer->getLocalFactors()
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        return $localFactors;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function buildLayer()
 | 
			
		||||
    {
 | 
			
		||||
        $inputVariablesGroups = &$this->getInputVariablesGroups();
 | 
			
		||||
        $inputVariablesGroups = $this->getInputVariablesGroups();
 | 
			
		||||
        $this->_TeamPerformancesToTeamPerformanceDifferencesLayer->setInputVariablesGroups($inputVariablesGroups);
 | 
			
		||||
        $this->_TeamPerformancesToTeamPerformanceDifferencesLayer->buildLayer();
 | 
			
		||||
 | 
			
		||||
        $teamDifferencesOutputVariablesGroups = &$this->_TeamPerformancesToTeamPerformanceDifferencesLayer->getOutputVariablesGroups();
 | 
			
		||||
        $teamDifferencesOutputVariablesGroups = $this->_TeamPerformancesToTeamPerformanceDifferencesLayer->getOutputVariablesGroups();
 | 
			
		||||
        $this->_TeamDifferencesComparisonLayer->setInputVariablesGroups($teamDifferencesOutputVariablesGroups);
 | 
			
		||||
        $this->_TeamDifferencesComparisonLayer->buildLayer();
 | 
			
		||||
    }
 | 
			
		||||
@@ -44,7 +46,7 @@ class IteratedTeamDifferencesInnerLayer extends TrueSkillFactorGraphLayer
 | 
			
		||||
        switch (count($this->getInputVariablesGroups())) {
 | 
			
		||||
            case 0:
 | 
			
		||||
            case 1:
 | 
			
		||||
                throw new InvalidOperationException();
 | 
			
		||||
                throw new Exception('InvalidOperation');
 | 
			
		||||
            case 2:
 | 
			
		||||
                $loop = $this->createTwoTeamInnerPriorLoopSchedule();
 | 
			
		||||
                break;
 | 
			
		||||
@@ -57,10 +59,11 @@ class IteratedTeamDifferencesInnerLayer extends TrueSkillFactorGraphLayer
 | 
			
		||||
        $totalTeamDifferences = count($this->_TeamPerformancesToTeamPerformanceDifferencesLayer->getLocalFactors());
 | 
			
		||||
        $totalTeams = $totalTeamDifferences + 1;
 | 
			
		||||
 | 
			
		||||
        $localFactors = &$this->_TeamPerformancesToTeamPerformanceDifferencesLayer->getLocalFactors();
 | 
			
		||||
        $localFactors = $this->_TeamPerformancesToTeamPerformanceDifferencesLayer->getLocalFactors();
 | 
			
		||||
 | 
			
		||||
        $firstDifferencesFactor = $localFactors[0];
 | 
			
		||||
        $lastDifferencesFactor = $localFactors[$totalTeamDifferences - 1];
 | 
			
		||||
 | 
			
		||||
        $firstDifferencesFactor = &$localFactors[0];
 | 
			
		||||
        $lastDifferencesFactor = &$localFactors[$totalTeamDifferences - 1];
 | 
			
		||||
        $innerSchedule = new ScheduleSequence(
 | 
			
		||||
            "inner schedule",
 | 
			
		||||
            array(
 | 
			
		||||
@@ -79,11 +82,11 @@ class IteratedTeamDifferencesInnerLayer extends TrueSkillFactorGraphLayer
 | 
			
		||||
 | 
			
		||||
    private function createTwoTeamInnerPriorLoopSchedule()
 | 
			
		||||
    {
 | 
			
		||||
        $teamPerformancesToTeamPerformanceDifferencesLayerLocalFactors = &$this->_TeamPerformancesToTeamPerformanceDifferencesLayer->getLocalFactors();
 | 
			
		||||
        $teamDifferencesComparisonLayerLocalFactors = &$this->_TeamDifferencesComparisonLayer->getLocalFactors();
 | 
			
		||||
        $teamPerformancesToTeamPerformanceDifferencesLayerLocalFactors = $this->_TeamPerformancesToTeamPerformanceDifferencesLayer->getLocalFactors();
 | 
			
		||||
        $teamDifferencesComparisonLayerLocalFactors = $this->_TeamDifferencesComparisonLayer->getLocalFactors();
 | 
			
		||||
 | 
			
		||||
        $firstPerfToTeamDiff = &$teamPerformancesToTeamPerformanceDifferencesLayerLocalFactors[0];
 | 
			
		||||
        $firstTeamDiffComparison = &$teamDifferencesComparisonLayerLocalFactors[0];
 | 
			
		||||
        $firstPerfToTeamDiff = $teamPerformancesToTeamPerformanceDifferencesLayerLocalFactors[0];
 | 
			
		||||
        $firstTeamDiffComparison = $teamDifferencesComparisonLayerLocalFactors[0];
 | 
			
		||||
        $itemsToSequence = array(
 | 
			
		||||
            new ScheduleStep(
 | 
			
		||||
                "send team perf to perf differences",
 | 
			
		||||
@@ -107,11 +110,11 @@ class IteratedTeamDifferencesInnerLayer extends TrueSkillFactorGraphLayer
 | 
			
		||||
        $forwardScheduleList = array();
 | 
			
		||||
 | 
			
		||||
        for ($i = 0; $i < $totalTeamDifferences - 1; $i++) {
 | 
			
		||||
            $teamPerformancesToTeamPerformanceDifferencesLayerLocalFactors = &$this->_TeamPerformancesToTeamPerformanceDifferencesLayer->getLocalFactors();
 | 
			
		||||
            $teamDifferencesComparisonLayerLocalFactors = &$this->_TeamDifferencesComparisonLayer->getLocalFactors();
 | 
			
		||||
            $teamPerformancesToTeamPerformanceDifferencesLayerLocalFactors = $this->_TeamPerformancesToTeamPerformanceDifferencesLayer->getLocalFactors();
 | 
			
		||||
            $teamDifferencesComparisonLayerLocalFactors = $this->_TeamDifferencesComparisonLayer->getLocalFactors();
 | 
			
		||||
 | 
			
		||||
            $currentTeamPerfToTeamPerfDiff = &$teamPerformancesToTeamPerformanceDifferencesLayerLocalFactors[$i];
 | 
			
		||||
            $currentTeamDiffComparison = &$teamDifferencesComparisonLayerLocalFactors[$i];
 | 
			
		||||
            $currentTeamPerfToTeamPerfDiff = $teamPerformancesToTeamPerformanceDifferencesLayerLocalFactors[$i];
 | 
			
		||||
            $currentTeamDiffComparison = $teamDifferencesComparisonLayerLocalFactors[$i];
 | 
			
		||||
 | 
			
		||||
            $currentForwardSchedulePiece =
 | 
			
		||||
                $this->scheduleSequence(
 | 
			
		||||
@@ -135,12 +138,12 @@ class IteratedTeamDifferencesInnerLayer extends TrueSkillFactorGraphLayer
 | 
			
		||||
        $backwardScheduleList = array();
 | 
			
		||||
 | 
			
		||||
        for ($i = 0; $i < $totalTeamDifferences - 1; $i++) {
 | 
			
		||||
            $teamPerformancesToTeamPerformanceDifferencesLayerLocalFactors = &$this->_TeamPerformancesToTeamPerformanceDifferencesLayer->getLocalFactors();
 | 
			
		||||
            $teamDifferencesComparisonLayerLocalFactors = &$this->_TeamDifferencesComparisonLayer->getLocalFactors();
 | 
			
		||||
            $teamPerformancesToTeamPerformanceDifferencesLayerLocalFactors = $this->_TeamPerformancesToTeamPerformanceDifferencesLayer->getLocalFactors();
 | 
			
		||||
            $teamDifferencesComparisonLayerLocalFactors = $this->_TeamDifferencesComparisonLayer->getLocalFactors();
 | 
			
		||||
 | 
			
		||||
            $differencesFactor = &$teamPerformancesToTeamPerformanceDifferencesLayerLocalFactors[$totalTeamDifferences - 1 - $i];
 | 
			
		||||
            $comparisonFactor = &$teamDifferencesComparisonLayerLocalFactors[$totalTeamDifferences - 1 - $i];
 | 
			
		||||
            $performancesToDifferencesFactor = &$teamPerformancesToTeamPerformanceDifferencesLayerLocalFactors[$totalTeamDifferences - 1 - $i];
 | 
			
		||||
            $differencesFactor = $teamPerformancesToTeamPerformanceDifferencesLayerLocalFactors[$totalTeamDifferences - 1 - $i];
 | 
			
		||||
            $comparisonFactor = $teamDifferencesComparisonLayerLocalFactors[$totalTeamDifferences - 1 - $i];
 | 
			
		||||
            $performancesToDifferencesFactor = $teamPerformancesToTeamPerformanceDifferencesLayerLocalFactors[$totalTeamDifferences - 1 - $i];
 | 
			
		||||
 | 
			
		||||
            $currentBackwardSchedulePiece = new ScheduleSequence(
 | 
			
		||||
                "current backward schedule piece",
 | 
			
		||||
 
 | 
			
		||||
@@ -9,17 +9,17 @@ use Moserware\Skills\TrueSkill\TrueSkillFactorGraph;
 | 
			
		||||
 | 
			
		||||
class PlayerPerformancesToTeamPerformancesLayer extends TrueSkillFactorGraphLayer
 | 
			
		||||
{
 | 
			
		||||
    public function __construct(TrueSkillFactorGraph &$parentGraph)
 | 
			
		||||
    public function __construct(TrueSkillFactorGraph $parentGraph)
 | 
			
		||||
    {
 | 
			
		||||
        parent::__construct($parentGraph);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function buildLayer()
 | 
			
		||||
    {
 | 
			
		||||
        $inputVariablesGroups = &$this->getInputVariablesGroups();
 | 
			
		||||
        foreach ($inputVariablesGroups as &$currentTeam) {
 | 
			
		||||
            $localCurrentTeam = &$currentTeam;
 | 
			
		||||
            $teamPerformance = &$this->createOutputVariable($localCurrentTeam);
 | 
			
		||||
        $inputVariablesGroups = $this->getInputVariablesGroups();
 | 
			
		||||
        foreach ($inputVariablesGroups as $currentTeam) {
 | 
			
		||||
            $localCurrentTeam = $currentTeam;
 | 
			
		||||
            $teamPerformance = $this->createOutputVariable($localCurrentTeam);
 | 
			
		||||
            $newSumFactor = $this->createPlayerToTeamSumFactor($localCurrentTeam, $teamPerformance);
 | 
			
		||||
 | 
			
		||||
            $this->addLayerFactor($newSumFactor);
 | 
			
		||||
@@ -32,9 +32,9 @@ class PlayerPerformancesToTeamPerformancesLayer extends TrueSkillFactorGraphLaye
 | 
			
		||||
 | 
			
		||||
    public function createPriorSchedule()
 | 
			
		||||
    {
 | 
			
		||||
        $localFactors = &$this->getLocalFactors();
 | 
			
		||||
        $localFactors = $this->getLocalFactors();
 | 
			
		||||
 | 
			
		||||
        $sequence = &$this->scheduleSequence(
 | 
			
		||||
        $sequence = $this->scheduleSequence(
 | 
			
		||||
            array_map(
 | 
			
		||||
                function ($weightedSumFactor) {
 | 
			
		||||
                    return new ScheduleStep("Perf to Team Perf Step", $weightedSumFactor, 0);
 | 
			
		||||
@@ -44,11 +44,11 @@ class PlayerPerformancesToTeamPerformancesLayer extends TrueSkillFactorGraphLaye
 | 
			
		||||
        return $sequence;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected function createPlayerToTeamSumFactor(&$teamMembers, &$sumVariable)
 | 
			
		||||
    protected function createPlayerToTeamSumFactor($teamMembers, $sumVariable)
 | 
			
		||||
    {
 | 
			
		||||
        $weights = array_map(
 | 
			
		||||
            function ($v) {
 | 
			
		||||
                $player = &$v->getKey();
 | 
			
		||||
                $player = $v->getKey();
 | 
			
		||||
                return PartialPlay::getPartialPlayPercentage($player);
 | 
			
		||||
            },
 | 
			
		||||
            $teamMembers);
 | 
			
		||||
@@ -63,9 +63,9 @@ class PlayerPerformancesToTeamPerformancesLayer extends TrueSkillFactorGraphLaye
 | 
			
		||||
    public function createPosteriorSchedule()
 | 
			
		||||
    {
 | 
			
		||||
        $allFactors = array();
 | 
			
		||||
        $localFactors = &$this->getLocalFactors();
 | 
			
		||||
        foreach ($localFactors as &$currentFactor) {
 | 
			
		||||
            $localCurrentFactor = &$currentFactor;
 | 
			
		||||
        $localFactors = $this->getLocalFactors();
 | 
			
		||||
        foreach ($localFactors as $currentFactor) {
 | 
			
		||||
            $localCurrentFactor = $currentFactor;
 | 
			
		||||
            $numberOfMessages = $localCurrentFactor->getNumberOfMessages();
 | 
			
		||||
            for ($currentIteration = 1; $currentIteration < $numberOfMessages; $currentIteration++) {
 | 
			
		||||
                $allFactors[] = new ScheduleStep("team sum perf @" . $currentIteration,
 | 
			
		||||
@@ -75,15 +75,14 @@ class PlayerPerformancesToTeamPerformancesLayer extends TrueSkillFactorGraphLaye
 | 
			
		||||
        return $this->scheduleSequence($allFactors, "all of the team's sum iterations");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private function &createOutputVariable(&$team)
 | 
			
		||||
    private function createOutputVariable($team)
 | 
			
		||||
    {
 | 
			
		||||
        $memberNames = \array_map(function ($currentPlayer) {
 | 
			
		||||
        $memberNames = array_map(function ($currentPlayer) {
 | 
			
		||||
            return (string)($currentPlayer->getKey());
 | 
			
		||||
        },
 | 
			
		||||
            $team);
 | 
			
		||||
        }, $team);
 | 
			
		||||
 | 
			
		||||
        $teamMemberNames = \join(", ", $memberNames);
 | 
			
		||||
        $outputVariable = &$this->getParentFactorGraph()->getVariableFactory()->createBasicVariable("Team[" . $teamMemberNames . "]'s performance");
 | 
			
		||||
        $outputVariable = $this->getParentFactorGraph()->getVariableFactory()->createBasicVariable("Team[" . $teamMemberNames . "]'s performance");
 | 
			
		||||
        return $outputVariable;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -13,7 +13,7 @@ class PlayerPriorValuesToSkillsLayer extends TrueSkillFactorGraphLayer
 | 
			
		||||
{
 | 
			
		||||
    private $_teams;
 | 
			
		||||
 | 
			
		||||
    public function __construct(TrueSkillFactorGraph &$parentGraph, array &$teams)
 | 
			
		||||
    public function __construct(TrueSkillFactorGraph $parentGraph, array $teams)
 | 
			
		||||
    {
 | 
			
		||||
        parent::__construct($parentGraph);
 | 
			
		||||
        $this->_teams = $teams;
 | 
			
		||||
@@ -21,17 +21,17 @@ class PlayerPriorValuesToSkillsLayer extends TrueSkillFactorGraphLayer
 | 
			
		||||
 | 
			
		||||
    public function buildLayer()
 | 
			
		||||
    {
 | 
			
		||||
        $teams = &$this->_teams;
 | 
			
		||||
        foreach ($teams as &$currentTeam) {
 | 
			
		||||
            $localCurrentTeam = &$currentTeam;
 | 
			
		||||
        $teams = $this->_teams;
 | 
			
		||||
        foreach ($teams as $currentTeam) {
 | 
			
		||||
            $localCurrentTeam = $currentTeam;
 | 
			
		||||
            $currentTeamSkills = array();
 | 
			
		||||
 | 
			
		||||
            $currentTeamAllPlayers = $localCurrentTeam->getAllPlayers();
 | 
			
		||||
            foreach ($currentTeamAllPlayers as &$currentTeamPlayer) {
 | 
			
		||||
                $localCurrentTeamPlayer = &$currentTeamPlayer;
 | 
			
		||||
            foreach ($currentTeamAllPlayers as $currentTeamPlayer) {
 | 
			
		||||
                $localCurrentTeamPlayer = $currentTeamPlayer;
 | 
			
		||||
                $currentTeamPlayerRating = $currentTeam->getRating($localCurrentTeamPlayer);
 | 
			
		||||
                $playerSkill = &$this->createSkillOutputVariable($localCurrentTeamPlayer);
 | 
			
		||||
                $priorFactor = &$this->createPriorFactor($localCurrentTeamPlayer, $currentTeamPlayerRating, $playerSkill);
 | 
			
		||||
                $playerSkill = $this->createSkillOutputVariable($localCurrentTeamPlayer);
 | 
			
		||||
                $priorFactor = $this->createPriorFactor($localCurrentTeamPlayer, $currentTeamPlayerRating, $playerSkill);
 | 
			
		||||
                $this->addLayerFactor($priorFactor);
 | 
			
		||||
                $currentTeamSkills[] = $playerSkill;
 | 
			
		||||
            }
 | 
			
		||||
@@ -43,17 +43,17 @@ class PlayerPriorValuesToSkillsLayer extends TrueSkillFactorGraphLayer
 | 
			
		||||
 | 
			
		||||
    public function createPriorSchedule()
 | 
			
		||||
    {
 | 
			
		||||
        $localFactors = &$this->getLocalFactors();
 | 
			
		||||
        $localFactors = $this->getLocalFactors();
 | 
			
		||||
        return $this->scheduleSequence(
 | 
			
		||||
            array_map(
 | 
			
		||||
                function (&$prior) {
 | 
			
		||||
                function ($prior) {
 | 
			
		||||
                    return new ScheduleStep("Prior to Skill Step", $prior, 0);
 | 
			
		||||
                },
 | 
			
		||||
                $localFactors),
 | 
			
		||||
            "All priors");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private function createPriorFactor(&$player, Rating &$priorRating, Variable &$skillsVariable)
 | 
			
		||||
    private function createPriorFactor($player, Rating $priorRating, Variable $skillsVariable)
 | 
			
		||||
    {
 | 
			
		||||
        return new GaussianPriorFactor(
 | 
			
		||||
            $priorRating->getMean(),
 | 
			
		||||
@@ -63,11 +63,11 @@ class PlayerPriorValuesToSkillsLayer extends TrueSkillFactorGraphLayer
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private function &createSkillOutputVariable(&$key)
 | 
			
		||||
    private function createSkillOutputVariable($key)
 | 
			
		||||
    {
 | 
			
		||||
        $parentFactorGraph = &$this->getParentFactorGraph();
 | 
			
		||||
        $variableFactory = &$parentFactorGraph->getVariableFactory();
 | 
			
		||||
        $skillOutputVariable = &$variableFactory->createKeyedVariable($key, $key . "'s skill");
 | 
			
		||||
        $parentFactorGraph = $this->getParentFactorGraph();
 | 
			
		||||
        $variableFactory = $parentFactorGraph->getVariableFactory();
 | 
			
		||||
        $skillOutputVariable = $variableFactory->createKeyedVariable($key, $key . "'s skill");
 | 
			
		||||
        return $skillOutputVariable;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -8,23 +8,23 @@ use Moserware\Skills\TrueSkill\Factors\GaussianLikelihoodFactor;
 | 
			
		||||
 | 
			
		||||
class PlayerSkillsToPerformancesLayer extends TrueSkillFactorGraphLayer
 | 
			
		||||
{
 | 
			
		||||
    public function __construct(TrueSkillFactorGraph &$parentGraph)
 | 
			
		||||
    public function __construct(TrueSkillFactorGraph $parentGraph)
 | 
			
		||||
    {
 | 
			
		||||
        parent::__construct($parentGraph);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function buildLayer()
 | 
			
		||||
    {
 | 
			
		||||
        $inputVariablesGroups = &$this->getInputVariablesGroups();
 | 
			
		||||
        $inputVariablesGroups = $this->getInputVariablesGroups();
 | 
			
		||||
        $outputVariablesGroups = &$this->getOutputVariablesGroups();
 | 
			
		||||
 | 
			
		||||
        foreach ($inputVariablesGroups as &$currentTeam) {
 | 
			
		||||
        foreach ($inputVariablesGroups as $currentTeam) {
 | 
			
		||||
            $currentTeamPlayerPerformances = array();
 | 
			
		||||
 | 
			
		||||
            foreach ($currentTeam as &$playerSkillVariable) {
 | 
			
		||||
                $localPlayerSkillVariable = &$playerSkillVariable;
 | 
			
		||||
                $currentPlayer = &$localPlayerSkillVariable->getKey();
 | 
			
		||||
                $playerPerformance = &$this->createOutputVariable($currentPlayer);
 | 
			
		||||
            foreach ($currentTeam as $playerSkillVariable) {
 | 
			
		||||
                $localPlayerSkillVariable = $playerSkillVariable;
 | 
			
		||||
                $currentPlayer = $localPlayerSkillVariable->getKey();
 | 
			
		||||
                $playerPerformance = $this->createOutputVariable($currentPlayer);
 | 
			
		||||
                $newLikelihoodFactor = $this->createLikelihood($localPlayerSkillVariable, $playerPerformance);
 | 
			
		||||
                $this->addLayerFactor($newLikelihoodFactor);
 | 
			
		||||
                $currentTeamPlayerPerformances[] = $playerPerformance;
 | 
			
		||||
@@ -34,7 +34,7 @@ class PlayerSkillsToPerformancesLayer extends TrueSkillFactorGraphLayer
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private function createLikelihood(KeyedVariable &$playerSkill, KeyedVariable &$playerPerformance)
 | 
			
		||||
    private function createLikelihood(KeyedVariable $playerSkill, KeyedVariable $playerPerformance)
 | 
			
		||||
    {
 | 
			
		||||
        return new GaussianLikelihoodFactor(
 | 
			
		||||
            BasicMath::square($this->getParentFactorGraph()->getGameInfo()->getBeta()),
 | 
			
		||||
@@ -43,15 +43,15 @@ class PlayerSkillsToPerformancesLayer extends TrueSkillFactorGraphLayer
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private function &createOutputVariable(&$key)
 | 
			
		||||
    private function createOutputVariable($key)
 | 
			
		||||
    {
 | 
			
		||||
        $outputVariable = &$this->getParentFactorGraph()->getVariableFactory()->createKeyedVariable($key, $key . "'s performance");
 | 
			
		||||
        $outputVariable = $this->getParentFactorGraph()->getVariableFactory()->createKeyedVariable($key, $key . "'s performance");
 | 
			
		||||
        return $outputVariable;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function createPriorSchedule()
 | 
			
		||||
    {
 | 
			
		||||
        $localFactors = &$this->getLocalFactors();
 | 
			
		||||
        $localFactors = $this->getLocalFactors();
 | 
			
		||||
        return $this->scheduleSequence(
 | 
			
		||||
            array_map(
 | 
			
		||||
                function ($likelihood) {
 | 
			
		||||
@@ -63,7 +63,7 @@ class PlayerSkillsToPerformancesLayer extends TrueSkillFactorGraphLayer
 | 
			
		||||
 | 
			
		||||
    public function createPosteriorSchedule()
 | 
			
		||||
    {
 | 
			
		||||
        $localFactors = &$this->getLocalFactors();
 | 
			
		||||
        $localFactors = $this->getLocalFactors();
 | 
			
		||||
        return $this->scheduleSequence(
 | 
			
		||||
            array_map(
 | 
			
		||||
                function ($likelihood) {
 | 
			
		||||
 
 | 
			
		||||
@@ -10,22 +10,22 @@ class TeamDifferencesComparisonLayer extends TrueSkillFactorGraphLayer
 | 
			
		||||
    private $_epsilon;
 | 
			
		||||
    private $_teamRanks;
 | 
			
		||||
 | 
			
		||||
    public function __construct(TrueSkillFactorGraph &$parentGraph, array &$teamRanks)
 | 
			
		||||
    public function __construct(TrueSkillFactorGraph $parentGraph, array $teamRanks)
 | 
			
		||||
    {
 | 
			
		||||
        parent::__construct($parentGraph);
 | 
			
		||||
        $this->_teamRanks = $teamRanks;
 | 
			
		||||
        $gameInfo = &$this->getParentFactorGraph()->getGameInfo();
 | 
			
		||||
        $gameInfo = $this->getParentFactorGraph()->getGameInfo();
 | 
			
		||||
        $this->_epsilon = DrawMargin::getDrawMarginFromDrawProbability($gameInfo->getDrawProbability(), $gameInfo->getBeta());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function buildLayer()
 | 
			
		||||
    {
 | 
			
		||||
        $inputVarGroups = &$this->getInputVariablesGroups();
 | 
			
		||||
        $inputVarGroups = $this->getInputVariablesGroups();
 | 
			
		||||
        $inputVarGroupsCount = count($inputVarGroups);
 | 
			
		||||
 | 
			
		||||
        for ($i = 0; $i < $inputVarGroupsCount; $i++) {
 | 
			
		||||
            $isDraw = ($this->_teamRanks[$i] == $this->_teamRanks[$i + 1]);
 | 
			
		||||
            $teamDifference = &$inputVarGroups[$i][0];
 | 
			
		||||
            $teamDifference = $inputVarGroups[$i][0];
 | 
			
		||||
 | 
			
		||||
            $factor =
 | 
			
		||||
                $isDraw
 | 
			
		||||
 
 | 
			
		||||
@@ -6,23 +6,23 @@ use Moserware\Skills\TrueSkill\Factors\GaussianWeightedSumFactor;
 | 
			
		||||
 | 
			
		||||
class TeamPerformancesToTeamPerformanceDifferencesLayer extends TrueSkillFactorGraphLayer
 | 
			
		||||
{
 | 
			
		||||
    public function __construct(TrueSkillFactorGraph &$parentGraph)
 | 
			
		||||
    public function __construct(TrueSkillFactorGraph $parentGraph)
 | 
			
		||||
    {
 | 
			
		||||
        parent::__construct($parentGraph);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function buildLayer()
 | 
			
		||||
    {
 | 
			
		||||
        $inputVariablesGroups = &$this->getInputVariablesGroups();
 | 
			
		||||
        $inputVariablesGroups = $this->getInputVariablesGroups();
 | 
			
		||||
        $inputVariablesGroupsCount = count($inputVariablesGroups);
 | 
			
		||||
        $outputVariablesGroup = &$this->getOutputVariablesGroups();
 | 
			
		||||
 | 
			
		||||
        for ($i = 0; $i < $inputVariablesGroupsCount - 1; $i++)
 | 
			
		||||
        {
 | 
			
		||||
            $strongerTeam = &$inputVariablesGroups[$i][0];
 | 
			
		||||
            $weakerTeam = &$inputVariablesGroups[$i + 1][0];
 | 
			
		||||
            $strongerTeam = $inputVariablesGroups[$i][0];
 | 
			
		||||
            $weakerTeam = $inputVariablesGroups[$i + 1][0];
 | 
			
		||||
 | 
			
		||||
            $currentDifference = &$this->createOutputVariable();
 | 
			
		||||
            $currentDifference = $this->createOutputVariable();
 | 
			
		||||
            $newDifferencesFactor = $this->createTeamPerformanceToDifferenceFactor($strongerTeam, $weakerTeam, $currentDifference);
 | 
			
		||||
            $this->addLayerFactor($newDifferencesFactor);
 | 
			
		||||
 | 
			
		||||
@@ -31,17 +31,18 @@ class TeamPerformancesToTeamPerformanceDifferencesLayer extends TrueSkillFactorG
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private function createTeamPerformanceToDifferenceFactor(
 | 
			
		||||
        Variable &$strongerTeam, Variable &$weakerTeam, Variable &$output)
 | 
			
		||||
    private function createTeamPerformanceToDifferenceFactor(Variable $strongerTeam,
 | 
			
		||||
                                                             Variable $weakerTeam,
 | 
			
		||||
                                                             Variable $output)
 | 
			
		||||
    {
 | 
			
		||||
        $teams = array($strongerTeam, $weakerTeam);
 | 
			
		||||
        $weights = array(1.0, -1.0);
 | 
			
		||||
        return new GaussianWeightedSumFactor($output, $teams, $weights);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private function &createOutputVariable()
 | 
			
		||||
    private function createOutputVariable()
 | 
			
		||||
    {
 | 
			
		||||
        $outputVariable = &$this->getParentFactorGraph()->getVariableFactory()->createBasicVariable("Team performance difference");
 | 
			
		||||
        $outputVariable = $this->getParentFactorGraph()->getVariableFactory()->createBasicVariable("Team performance difference");
 | 
			
		||||
        return $outputVariable;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -5,7 +5,7 @@ use Moserware\Skills\TrueSkill\TrueSkillFactorGraph;
 | 
			
		||||
 | 
			
		||||
abstract class TrueSkillFactorGraphLayer extends FactorGraphLayer
 | 
			
		||||
{
 | 
			
		||||
    public function __construct(TrueSkillFactorGraph &$parentGraph)
 | 
			
		||||
    public function __construct(TrueSkillFactorGraph $parentGraph)
 | 
			
		||||
    {
 | 
			
		||||
        parent::__construct($parentGraph);
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
<?php namespace Moserware\Skills\TrueSkill;
 | 
			
		||||
 | 
			
		||||
use Moserware\Skills\GameInfo;
 | 
			
		||||
use Moserware\Skills\Numerics\GaussianDistribution;
 | 
			
		||||
use Moserware\Skills\Rating;
 | 
			
		||||
use Moserware\Skills\RatingContainer;
 | 
			
		||||
use Moserware\Skills\FactorGraphs\FactorGraph;
 | 
			
		||||
@@ -20,7 +21,7 @@ class TrueSkillFactorGraph extends FactorGraph
 | 
			
		||||
    private $_layers;
 | 
			
		||||
    private $_priorLayer;
 | 
			
		||||
 | 
			
		||||
    public function __construct(GameInfo &$gameInfo, array &$teams, array $teamRanks)
 | 
			
		||||
    public function __construct(GameInfo $gameInfo, array $teams, array $teamRanks)
 | 
			
		||||
    {
 | 
			
		||||
        $this->_priorLayer = new PlayerPriorValuesToSkillsLayer($this, $teams);
 | 
			
		||||
        $this->_gameInfo = $gameInfo;
 | 
			
		||||
@@ -50,15 +51,15 @@ class TrueSkillFactorGraph extends FactorGraph
 | 
			
		||||
    {
 | 
			
		||||
        $lastOutput = null;
 | 
			
		||||
 | 
			
		||||
        $layers = &$this->_layers;
 | 
			
		||||
        foreach ($layers as &$currentLayer) {
 | 
			
		||||
        $layers = $this->_layers;
 | 
			
		||||
        foreach ($layers as $currentLayer) {
 | 
			
		||||
            if ($lastOutput != null) {
 | 
			
		||||
                $currentLayer->setInputVariablesGroups($lastOutput);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            $currentLayer->buildLayer();
 | 
			
		||||
 | 
			
		||||
            $lastOutput = &$currentLayer->getOutputVariablesGroups();
 | 
			
		||||
            $lastOutput = $currentLayer->getOutputVariablesGroups();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -72,11 +73,11 @@ class TrueSkillFactorGraph extends FactorGraph
 | 
			
		||||
    {
 | 
			
		||||
        $factorList = new FactorList();
 | 
			
		||||
 | 
			
		||||
        $layers = &$this->_layers;
 | 
			
		||||
        foreach ($layers as &$currentLayer) {
 | 
			
		||||
            $localFactors = &$currentLayer->getLocalFactors();
 | 
			
		||||
            foreach ($localFactors as &$currentFactor) {
 | 
			
		||||
                $localCurrentFactor = &$currentFactor;
 | 
			
		||||
        $layers = $this->_layers;
 | 
			
		||||
        foreach ($layers as $currentLayer) {
 | 
			
		||||
            $localFactors = $currentLayer->getLocalFactors();
 | 
			
		||||
            foreach ($localFactors as $currentFactor) {
 | 
			
		||||
                $localCurrentFactor = $currentFactor;
 | 
			
		||||
                $factorList->addFactor($localCurrentFactor);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
@@ -89,17 +90,17 @@ class TrueSkillFactorGraph extends FactorGraph
 | 
			
		||||
    {
 | 
			
		||||
        $fullSchedule = array();
 | 
			
		||||
 | 
			
		||||
        $layers = &$this->_layers;
 | 
			
		||||
        foreach ($layers as &$currentLayer) {
 | 
			
		||||
        $layers = $this->_layers;
 | 
			
		||||
        foreach ($layers as $currentLayer) {
 | 
			
		||||
            $currentPriorSchedule = $currentLayer->createPriorSchedule();
 | 
			
		||||
            if ($currentPriorSchedule != null) {
 | 
			
		||||
                $fullSchedule[] = $currentPriorSchedule;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $allLayersReverse = \array_reverse($this->_layers);
 | 
			
		||||
        $allLayersReverse = array_reverse($this->_layers);
 | 
			
		||||
 | 
			
		||||
        foreach ($allLayersReverse as &$currentLayer) {
 | 
			
		||||
        foreach ($allLayersReverse as $currentLayer) {
 | 
			
		||||
            $currentPosteriorSchedule = $currentLayer->createPosteriorSchedule();
 | 
			
		||||
            if ($currentPosteriorSchedule != null) {
 | 
			
		||||
                $fullSchedule[] = $currentPosteriorSchedule;
 | 
			
		||||
@@ -113,10 +114,10 @@ class TrueSkillFactorGraph extends FactorGraph
 | 
			
		||||
    {
 | 
			
		||||
        $result = new RatingContainer();
 | 
			
		||||
 | 
			
		||||
        $priorLayerOutputVariablesGroups = &$this->_priorLayer->getOutputVariablesGroups();
 | 
			
		||||
        foreach ($priorLayerOutputVariablesGroups as &$currentTeam) {
 | 
			
		||||
            foreach ($currentTeam as &$currentPlayer) {
 | 
			
		||||
                $localCurrentPlayer = &$currentPlayer->getKey();
 | 
			
		||||
        $priorLayerOutputVariablesGroups = $this->_priorLayer->getOutputVariablesGroups();
 | 
			
		||||
        foreach ($priorLayerOutputVariablesGroups as $currentTeam) {
 | 
			
		||||
            foreach ($currentTeam as $currentPlayer) {
 | 
			
		||||
                $localCurrentPlayer = $currentPlayer->getKey();
 | 
			
		||||
                $newRating = new Rating($currentPlayer->getValue()->getMean(),
 | 
			
		||||
                    $currentPlayer->getValue()->getStandardDeviation());
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -38,8 +38,12 @@ class TruncatedGaussianCorrectionFunctions
 | 
			
		||||
     *
 | 
			
		||||
     * In the reference F# implementation, this is referred to as "the multiplicative
 | 
			
		||||
     * correction of a single-sided truncated Gaussian with unit variance."
 | 
			
		||||
     *
 | 
			
		||||
     * @param $teamPerformanceDifference
 | 
			
		||||
     * @param $drawMargin
 | 
			
		||||
     * @param $c
 | 
			
		||||
     * @return float
 | 
			
		||||
     */
 | 
			
		||||
 | 
			
		||||
    public static function wExceedsMarginScaled($teamPerformanceDifference, $drawMargin, $c)
 | 
			
		||||
    {
 | 
			
		||||
        return self::wExceedsMargin($teamPerformanceDifference / $c, $drawMargin / $c);
 | 
			
		||||
 
 | 
			
		||||
@@ -9,7 +9,6 @@ use Moserware\Skills\Rating;
 | 
			
		||||
use Moserware\Skills\RatingContainer;
 | 
			
		||||
use Moserware\Skills\SkillCalculator;
 | 
			
		||||
use Moserware\Skills\SkillCalculatorSupportedOptions;
 | 
			
		||||
 | 
			
		||||
use Moserware\Skills\PlayersRange;
 | 
			
		||||
use Moserware\Skills\TeamsRange;
 | 
			
		||||
 | 
			
		||||
@@ -126,7 +125,7 @@ class TwoPlayerTrueSkillCalculator extends SkillCalculator
 | 
			
		||||
    /**
 | 
			
		||||
     * {@inheritdoc }
 | 
			
		||||
     */
 | 
			
		||||
    public function calculateMatchQuality(GameInfo $gameInfo, array &$teams)
 | 
			
		||||
    public function calculateMatchQuality(GameInfo $gameInfo, array $teams)
 | 
			
		||||
    {
 | 
			
		||||
        Guard::argumentNotNull($gameInfo, "gameInfo");
 | 
			
		||||
        $this->validateTeamCountAndPlayersCountPerTeam($teams);
 | 
			
		||||
@@ -146,18 +145,18 @@ class TwoPlayerTrueSkillCalculator extends SkillCalculator
 | 
			
		||||
        $player2SigmaSquared = BasicMath::square($player2Rating->getStandardDeviation());
 | 
			
		||||
 | 
			
		||||
        // This is the square root part of the equation:
 | 
			
		||||
        $sqrtPart =
 | 
			
		||||
            sqrt(
 | 
			
		||||
                (2*$betaSquared)
 | 
			
		||||
                /
 | 
			
		||||
                (2*$betaSquared + $player1SigmaSquared + $player2SigmaSquared));
 | 
			
		||||
        $sqrtPart = sqrt(
 | 
			
		||||
            (2*$betaSquared)
 | 
			
		||||
            /
 | 
			
		||||
            (2*$betaSquared + $player1SigmaSquared + $player2SigmaSquared)
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // This is the exponent part of the equation:
 | 
			
		||||
        $expPart =
 | 
			
		||||
            exp(
 | 
			
		||||
                (-1*BasicMath::square($player1Rating->getMean() - $player2Rating->getMean()))
 | 
			
		||||
                /
 | 
			
		||||
                (2*(2*$betaSquared + $player1SigmaSquared + $player2SigmaSquared)));
 | 
			
		||||
        $expPart = exp(
 | 
			
		||||
            (-1*BasicMath::square($player1Rating->getMean() - $player2Rating->getMean()))
 | 
			
		||||
            /
 | 
			
		||||
            (2*(2*$betaSquared + $player1SigmaSquared + $player2SigmaSquared))
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        return $sqrtPart*$expPart;
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -57,7 +57,7 @@ class TwoTeamTrueSkillCalculator extends SkillCalculator
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static function updatePlayerRatings(GameInfo $gameInfo,
 | 
			
		||||
                                                RatingContainer &$newPlayerRatings,
 | 
			
		||||
                                                RatingContainer $newPlayerRatings,
 | 
			
		||||
                                                Team $selfTeam,
 | 
			
		||||
                                                Team $otherTeam,
 | 
			
		||||
                                                $selfToOtherTeamComparison)
 | 
			
		||||
@@ -119,9 +119,9 @@ class TwoTeamTrueSkillCalculator extends SkillCalculator
 | 
			
		||||
            $rankMultiplier = 1;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $selfTeamAllPlayers = &$selfTeam->getAllPlayers();
 | 
			
		||||
        foreach ($selfTeamAllPlayers as &$selfTeamCurrentPlayer) {
 | 
			
		||||
            $localSelfTeamCurrentPlayer = &$selfTeamCurrentPlayer;
 | 
			
		||||
        $selfTeamAllPlayers = $selfTeam->getAllPlayers();
 | 
			
		||||
        foreach ($selfTeamAllPlayers as $selfTeamCurrentPlayer) {
 | 
			
		||||
            $localSelfTeamCurrentPlayer = $selfTeamCurrentPlayer;
 | 
			
		||||
            $previousPlayerRating = $selfTeam->getRating($localSelfTeamCurrentPlayer);
 | 
			
		||||
 | 
			
		||||
            $meanMultiplier = (BasicMath::square($previousPlayerRating->getStandardDeviation()) + $tauSquared) / $c;
 | 
			
		||||
@@ -141,7 +141,7 @@ class TwoTeamTrueSkillCalculator extends SkillCalculator
 | 
			
		||||
    /**
 | 
			
		||||
     * {@inheritdoc}
 | 
			
		||||
     */
 | 
			
		||||
    public function calculateMatchQuality(GameInfo $gameInfo, array &$teams)
 | 
			
		||||
    public function calculateMatchQuality(GameInfo $gameInfo, array $teams)
 | 
			
		||||
    {
 | 
			
		||||
        Guard::argumentNotNull($gameInfo, "gameInfo");
 | 
			
		||||
        $this->validateTeamCountAndPlayersCountPerTeam($teams);
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user