mirror of
				https://github.com/furyfire/trueskill.git
				synced 2025-11-04 10:12:28 +01:00 
			
		
		
		
	CodeBeautifier for PSR-12 standard.
This commit is contained in:
		@@ -8,18 +8,18 @@ use Exception;
 | 
			
		||||
 | 
			
		||||
abstract class Factor implements \Stringable
 | 
			
		||||
{
 | 
			
		||||
    private array $_messages = [];
 | 
			
		||||
    private array $messages = [];
 | 
			
		||||
 | 
			
		||||
    private $_messageToVariableBinding;
 | 
			
		||||
    private $messageToVariableBinding;
 | 
			
		||||
 | 
			
		||||
    private string $_name;
 | 
			
		||||
    private string $name;
 | 
			
		||||
 | 
			
		||||
    private array $_variables = [];
 | 
			
		||||
    private array $variables = [];
 | 
			
		||||
 | 
			
		||||
    protected function __construct(string $name)
 | 
			
		||||
    {
 | 
			
		||||
        $this->_name = 'Factor['.$name.']';
 | 
			
		||||
        $this->_messageToVariableBinding = new HashMap();
 | 
			
		||||
        $this->name = 'Factor[' . $name . ']';
 | 
			
		||||
        $this->messageToVariableBinding = new HashMap();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -35,17 +35,17 @@ abstract class Factor implements \Stringable
 | 
			
		||||
     */
 | 
			
		||||
    public function getNumberOfMessages(): int
 | 
			
		||||
    {
 | 
			
		||||
        return count($this->_messages);
 | 
			
		||||
        return count($this->messages);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected function getVariables(): array
 | 
			
		||||
    {
 | 
			
		||||
        return $this->_variables;
 | 
			
		||||
        return $this->variables;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected function getMessages(): array
 | 
			
		||||
    {
 | 
			
		||||
        return $this->_messages;
 | 
			
		||||
        return $this->messages;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -57,9 +57,9 @@ abstract class Factor implements \Stringable
 | 
			
		||||
     */
 | 
			
		||||
    public function updateMessageIndex(int $messageIndex)
 | 
			
		||||
    {
 | 
			
		||||
        Guard::argumentIsValidIndex($messageIndex, count($this->_messages), 'messageIndex');
 | 
			
		||||
        $message = $this->_messages[$messageIndex];
 | 
			
		||||
        $variable = $this->_messageToVariableBinding->getValue($message);
 | 
			
		||||
        Guard::argumentIsValidIndex($messageIndex, count($this->messages), 'messageIndex');
 | 
			
		||||
        $message = $this->messages[$messageIndex];
 | 
			
		||||
        $variable = $this->messageToVariableBinding->getValue($message);
 | 
			
		||||
 | 
			
		||||
        return $this->updateMessageVariable($message, $variable);
 | 
			
		||||
    }
 | 
			
		||||
@@ -74,7 +74,7 @@ abstract class Factor implements \Stringable
 | 
			
		||||
     */
 | 
			
		||||
    public function resetMarginals()
 | 
			
		||||
    {
 | 
			
		||||
        $allValues = $this->_messageToVariableBinding->getAllValues();
 | 
			
		||||
        $allValues = $this->messageToVariableBinding->getAllValues();
 | 
			
		||||
        foreach ($allValues as $currentVariable) {
 | 
			
		||||
            $currentVariable->resetToPrior();
 | 
			
		||||
        }
 | 
			
		||||
@@ -83,17 +83,17 @@ abstract class Factor implements \Stringable
 | 
			
		||||
    /**
 | 
			
		||||
     * Sends the ith message to the marginal and returns the log-normalization constant
 | 
			
		||||
     *
 | 
			
		||||
     * @param $messageIndex
 | 
			
		||||
     * @param  $messageIndex
 | 
			
		||||
     * @return
 | 
			
		||||
     *
 | 
			
		||||
     * @throws Exception
 | 
			
		||||
     */
 | 
			
		||||
    public function sendMessageIndex($messageIndex)
 | 
			
		||||
    {
 | 
			
		||||
        Guard::argumentIsValidIndex($messageIndex, count($this->_messages), '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);
 | 
			
		||||
    }
 | 
			
		||||
@@ -104,15 +104,15 @@ abstract class Factor implements \Stringable
 | 
			
		||||
 | 
			
		||||
    protected function createVariableToMessageBindingWithMessage(Variable $variable, Message $message): Message
 | 
			
		||||
    {
 | 
			
		||||
        $this->_messageToVariableBinding->setValue($message, $variable);
 | 
			
		||||
        $this->_messages[] = $message;
 | 
			
		||||
        $this->_variables[] = $variable;
 | 
			
		||||
        $this->messageToVariableBinding->setValue($message, $variable);
 | 
			
		||||
        $this->messages[] = $message;
 | 
			
		||||
        $this->variables[] = $variable;
 | 
			
		||||
 | 
			
		||||
        return $message;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function __toString(): string
 | 
			
		||||
    {
 | 
			
		||||
        return $this->_name;
 | 
			
		||||
        return $this->name;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -4,15 +4,15 @@ namespace DNW\Skills\FactorGraphs;
 | 
			
		||||
 | 
			
		||||
class FactorGraph
 | 
			
		||||
{
 | 
			
		||||
    private $_variableFactory;
 | 
			
		||||
    private $variableFactory;
 | 
			
		||||
 | 
			
		||||
    public function getVariableFactory()
 | 
			
		||||
    {
 | 
			
		||||
        return $this->_variableFactory;
 | 
			
		||||
        return $this->variableFactory;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function setVariableFactory(VariableFactory $factory)
 | 
			
		||||
    {
 | 
			
		||||
        $this->_variableFactory = $factory;
 | 
			
		||||
        $this->variableFactory = $factory;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -4,33 +4,33 @@ namespace DNW\Skills\FactorGraphs;
 | 
			
		||||
 | 
			
		||||
class Variable implements \Stringable
 | 
			
		||||
{
 | 
			
		||||
    private string $_name;
 | 
			
		||||
    private string $name;
 | 
			
		||||
 | 
			
		||||
    private mixed $_value;
 | 
			
		||||
    private mixed $value;
 | 
			
		||||
 | 
			
		||||
    public function __construct(string $name, private mixed $_prior)
 | 
			
		||||
    public function __construct(string $name, private mixed $prior)
 | 
			
		||||
    {
 | 
			
		||||
        $this->_name = 'Variable['.$name.']';
 | 
			
		||||
        $this->name = 'Variable[' . $name . ']';
 | 
			
		||||
        $this->resetToPrior();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getValue(): mixed
 | 
			
		||||
    {
 | 
			
		||||
        return $this->_value;
 | 
			
		||||
        return $this->value;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function setValue(mixed $value): void
 | 
			
		||||
    {
 | 
			
		||||
        $this->_value = $value;
 | 
			
		||||
        $this->value = $value;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function resetToPrior(): void
 | 
			
		||||
    {
 | 
			
		||||
        $this->_value = $this->_prior;
 | 
			
		||||
        $this->value = $this->prior;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function __toString(): string
 | 
			
		||||
    {
 | 
			
		||||
        return $this->_name;
 | 
			
		||||
        return $this->name;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -5,15 +5,15 @@ namespace DNW\Skills\Numerics;
 | 
			
		||||
/**
 | 
			
		||||
 * Basic math functions.
 | 
			
		||||
 *
 | 
			
		||||
 * @author     Jeff Moser <jeff@moserware.com>
 | 
			
		||||
 * @copyright  2010 Jeff Moser
 | 
			
		||||
 * @author    Jeff Moser <jeff@moserware.com>
 | 
			
		||||
 * @copyright 2010 Jeff Moser
 | 
			
		||||
 */
 | 
			
		||||
class BasicMath
 | 
			
		||||
{
 | 
			
		||||
    /**
 | 
			
		||||
     * Squares the input (x^2 = x * x)
 | 
			
		||||
     *
 | 
			
		||||
     * @param  number  $x Value to square (x)
 | 
			
		||||
     * @param  number $x Value to square (x)
 | 
			
		||||
     * @return number The squared value (x^2)
 | 
			
		||||
     */
 | 
			
		||||
    public static function square($x): float|int
 | 
			
		||||
@@ -24,8 +24,8 @@ class BasicMath
 | 
			
		||||
    /**
 | 
			
		||||
     * Sums the items in $itemsToSum
 | 
			
		||||
     *
 | 
			
		||||
     * @param  array  $itemsToSum The items to sum,
 | 
			
		||||
     * @param  callable  $callback The function to apply to each array element before summing.
 | 
			
		||||
     * @param  array    $itemsToSum The items to sum,
 | 
			
		||||
     * @param  callable $callback   The function to apply to each array element before summing.
 | 
			
		||||
     * @return number The sum.
 | 
			
		||||
     */
 | 
			
		||||
    public static function sum(array $itemsToSum, \Closure $callback): float|int
 | 
			
		||||
 
 | 
			
		||||
@@ -5,8 +5,8 @@ namespace DNW\Skills\Numerics;
 | 
			
		||||
/**
 | 
			
		||||
 * Computes Gaussian (bell curve) values.
 | 
			
		||||
 *
 | 
			
		||||
 * @author     Jeff Moser <jeff@moserware.com>
 | 
			
		||||
 * @copyright  2010 Jeff Moser
 | 
			
		||||
 * @author    Jeff Moser <jeff@moserware.com>
 | 
			
		||||
 * @copyright 2010 Jeff Moser
 | 
			
		||||
 */
 | 
			
		||||
class GaussianDistribution implements \Stringable
 | 
			
		||||
{
 | 
			
		||||
 
 | 
			
		||||
@@ -70,12 +70,16 @@ class Matrix
 | 
			
		||||
        $transposeMatrix = [];
 | 
			
		||||
 | 
			
		||||
        $rowMatrixData = $this->_matrixRowData;
 | 
			
		||||
        for ($currentRowTransposeMatrix = 0;
 | 
			
		||||
        for (
 | 
			
		||||
            $currentRowTransposeMatrix = 0;
 | 
			
		||||
             $currentRowTransposeMatrix < $this->_columnCount;
 | 
			
		||||
             $currentRowTransposeMatrix++) {
 | 
			
		||||
            for ($currentColumnTransposeMatrix = 0;
 | 
			
		||||
             $currentRowTransposeMatrix++
 | 
			
		||||
        ) {
 | 
			
		||||
            for (
 | 
			
		||||
                $currentColumnTransposeMatrix = 0;
 | 
			
		||||
                 $currentColumnTransposeMatrix < $this->_rowCount;
 | 
			
		||||
                 $currentColumnTransposeMatrix++) {
 | 
			
		||||
                 $currentColumnTransposeMatrix++
 | 
			
		||||
            ) {
 | 
			
		||||
                $transposeMatrix[$currentRowTransposeMatrix][$currentColumnTransposeMatrix] =
 | 
			
		||||
                    $rowMatrixData[$currentColumnTransposeMatrix][$currentRowTransposeMatrix];
 | 
			
		||||
            }
 | 
			
		||||
@@ -155,8 +159,12 @@ 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
 | 
			
		||||
@@ -204,8 +212,8 @@ class Matrix
 | 
			
		||||
    {
 | 
			
		||||
        if (
 | 
			
		||||
            ($left->getRowCount() != $right->getRowCount())
 | 
			
		||||
            ||
 | 
			
		||||
            ($left->getColumnCount() != $right->getColumnCount())
 | 
			
		||||
 | 
			
		||||
            || ($left->getColumnCount() != $right->getColumnCount())
 | 
			
		||||
        ) {
 | 
			
		||||
            throw new Exception('Matrices must be of the same size');
 | 
			
		||||
        }
 | 
			
		||||
@@ -318,8 +326,10 @@ class Matrix
 | 
			
		||||
        for ($currentRow = 0; $currentRow < $this->_rowCount; $currentRow++) {
 | 
			
		||||
            for ($currentColumn = 0; $currentColumn < $this->_columnCount; $currentColumn++) {
 | 
			
		||||
                $delta =
 | 
			
		||||
                    abs($this->_matrixRowData[$currentRow][$currentColumn] -
 | 
			
		||||
                        $otherMatrix->getValue($currentRow, $currentColumn));
 | 
			
		||||
                    abs(
 | 
			
		||||
                        $this->_matrixRowData[$currentRow][$currentColumn] -
 | 
			
		||||
                        $otherMatrix->getValue($currentRow, $currentColumn)
 | 
			
		||||
                    );
 | 
			
		||||
 | 
			
		||||
                if ($delta > self::ERROR_TOLERANCE) {
 | 
			
		||||
                    return false;
 | 
			
		||||
 
 | 
			
		||||
@@ -18,14 +18,15 @@ class Player implements ISupportPartialPlay, ISupportPartialUpdate, \Stringable
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs a player.
 | 
			
		||||
     *
 | 
			
		||||
     * @param  mixed  $_Id The identifier for the player, such as a name.
 | 
			
		||||
     * @param  number  $partialPlayPercentage The weight percentage to give this player when calculating a new rank.
 | 
			
		||||
     * @param  number  $partialUpdatePercentage Indicated how much of a skill update a player should receive where 0 represents no update and 1.0 represents 100% of the update.
 | 
			
		||||
     * @param mixed  $_Id                     The identifier for the player, such as a name.
 | 
			
		||||
     * @param number $partialPlayPercentage   The weight percentage to give this player when calculating a new rank.
 | 
			
		||||
     * @param number $partialUpdatePercentage Indicated how much of a skill update a player should receive where 0 represents no update and 1.0 represents 100% of the update.
 | 
			
		||||
     */
 | 
			
		||||
    public function __construct(private $_Id,
 | 
			
		||||
                                $partialPlayPercentage = self::DEFAULT_PARTIAL_PLAY_PERCENTAGE,
 | 
			
		||||
                                $partialUpdatePercentage = self::DEFAULT_PARTIAL_UPDATE_PERCENTAGE)
 | 
			
		||||
    {
 | 
			
		||||
    public function __construct(
 | 
			
		||||
        private $_Id,
 | 
			
		||||
        $partialPlayPercentage = self::DEFAULT_PARTIAL_PLAY_PERCENTAGE,
 | 
			
		||||
        $partialUpdatePercentage = self::DEFAULT_PARTIAL_UPDATE_PERCENTAGE
 | 
			
		||||
    ) {
 | 
			
		||||
        // If they don't want to give a player an id, that's ok...
 | 
			
		||||
        Guard::argumentInRangeInclusive($partialPlayPercentage, 0.0, 1.0, 'partialPlayPercentage');
 | 
			
		||||
        Guard::argumentInRangeInclusive($partialUpdatePercentage, 0, 1.0, 'partialUpdatePercentage');
 | 
			
		||||
 
 | 
			
		||||
@@ -10,8 +10,8 @@ class RankSorter
 | 
			
		||||
    /**
 | 
			
		||||
     * Performs an in-place sort of the items in according to the ranks in non-decreasing order.
 | 
			
		||||
     *
 | 
			
		||||
     * @param  array  $teams The items to sort according to the order specified by ranks.
 | 
			
		||||
     * @param  array  $teamRanks The ranks for each item where 1 is first place.
 | 
			
		||||
     * @param  array $teams     The items to sort according to the order specified by ranks.
 | 
			
		||||
     * @param  array $teamRanks The ranks for each item where 1 is first place.
 | 
			
		||||
     * @return array
 | 
			
		||||
     */
 | 
			
		||||
    public static function sort(array &$teams, array &$teamRanks)
 | 
			
		||||
 
 | 
			
		||||
@@ -12,9 +12,9 @@ class Rating implements \Stringable
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs a rating.
 | 
			
		||||
     *
 | 
			
		||||
     * @param  float  $_mean The statistical mean value of the rating (also known as mu).
 | 
			
		||||
     * @param  float  $_standardDeviation The standard deviation of the rating (also known as s).
 | 
			
		||||
     * @param  float|int  $_conservativeStandardDeviationMultiplier optional The number of standardDeviations to subtract from the mean to achieve a conservative rating.
 | 
			
		||||
     * @param float     $_mean                                    The statistical mean value of the rating (also known as mu).
 | 
			
		||||
     * @param float     $_standardDeviation                       The standard deviation of the rating (also known as s).
 | 
			
		||||
     * @param float|int $_conservativeStandardDeviationMultiplier optional The number of standardDeviations to subtract from the mean to achieve a conservative rating.
 | 
			
		||||
     */
 | 
			
		||||
    public function __construct(private $_mean, private $_standardDeviation, private $_conservativeStandardDeviationMultiplier = self::CONSERVATIVE_STANDARD_DEVIATION_MULTIPLIER)
 | 
			
		||||
    {
 | 
			
		||||
@@ -47,7 +47,7 @@ class Rating implements \Stringable
 | 
			
		||||
    public function getPartialUpdate(Rating $prior, Rating $fullPosterior, $updatePercentage)
 | 
			
		||||
    {
 | 
			
		||||
        $priorGaussian = new GaussianDistribution($prior->getMean(), $prior->getStandardDeviation());
 | 
			
		||||
        $posteriorGaussian = new GaussianDistribution($fullPosterior->getMean(), $fullPosterior.getStandardDeviation());
 | 
			
		||||
        $posteriorGaussian = new GaussianDistribution($fullPosterior->getMean(), $fullPosterior . getStandardDeviation());
 | 
			
		||||
 | 
			
		||||
        // From a clarification email from Ralf Herbrich:
 | 
			
		||||
        // "the idea is to compute a linear interpolation between the prior and posterior skills of each player
 | 
			
		||||
@@ -56,7 +56,7 @@ class Rating implements \Stringable
 | 
			
		||||
        $precisionDifference = $posteriorGaussian->getPrecision() - $priorGaussian->getPrecision();
 | 
			
		||||
        $partialPrecisionDifference = $updatePercentage * $precisionDifference;
 | 
			
		||||
 | 
			
		||||
        $precisionMeanDifference = $posteriorGaussian->getPrecisionMean() - $priorGaussian.getPrecisionMean();
 | 
			
		||||
        $precisionMeanDifference = $posteriorGaussian->getPrecisionMean() - $priorGaussian . getPrecisionMean();
 | 
			
		||||
        $partialPrecisionMeanDifference = $updatePercentage * $precisionMeanDifference;
 | 
			
		||||
 | 
			
		||||
        $partialPosteriorGaussion = GaussianDistribution::fromPrecisionMean(
 | 
			
		||||
 
 | 
			
		||||
@@ -19,21 +19,22 @@ abstract class SkillCalculator
 | 
			
		||||
    /**
 | 
			
		||||
     * Calculates new ratings based on the prior ratings and team ranks.
 | 
			
		||||
     *
 | 
			
		||||
     * @param GameInfo $gameInfo Parameters for the game.
 | 
			
		||||
     * @param array $teamsOfPlayerToRatings A mapping of team players and their ratings.
 | 
			
		||||
     * @param array $teamRanks The ranks of the teams where 1 is first place. For a tie, repeat the number (e.g. 1, 2, 2).
 | 
			
		||||
     * @param  GameInfo $gameInfo               Parameters for the game.
 | 
			
		||||
     * @param  array    $teamsOfPlayerToRatings A mapping of team players and their ratings.
 | 
			
		||||
     * @param  array    $teamRanks              The ranks of the teams where 1 is first place. For a tie, repeat the number (e.g. 1, 2, 2).
 | 
			
		||||
     * @return All the players and their new ratings.
 | 
			
		||||
     */
 | 
			
		||||
    abstract public function calculateNewRatings(
 | 
			
		||||
        GameInfo $gameInfo,
 | 
			
		||||
        array $teamsOfPlayerToRatings,
 | 
			
		||||
        array $teamRanks);
 | 
			
		||||
        array $teamRanks
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Calculates the match quality as the likelihood of all teams drawing.
 | 
			
		||||
     *
 | 
			
		||||
     * @param  GameInfo  $gameInfo Parameters for the game.
 | 
			
		||||
     * @param  array  $teamsOfPlayerToRatings A mapping of team players and their ratings.
 | 
			
		||||
     * @param  GameInfo $gameInfo               Parameters for the game.
 | 
			
		||||
     * @param  array    $teamsOfPlayerToRatings A mapping of team players and their ratings.
 | 
			
		||||
     * @return float The quality of the match between the teams as a percentage (0% = bad, 100% = well matched).
 | 
			
		||||
     */
 | 
			
		||||
    abstract public function calculateMatchQuality(GameInfo $gameInfo, array $teamsOfPlayerToRatings): float;
 | 
			
		||||
@@ -49,7 +50,7 @@ abstract class SkillCalculator
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @param  array<\DNW\Skills\Team>  $teams
 | 
			
		||||
     * @param array<\DNW\Skills\Team> $teams
 | 
			
		||||
     *
 | 
			
		||||
     * @throws \Exception
 | 
			
		||||
     */
 | 
			
		||||
@@ -69,4 +70,3 @@ abstract class SkillCalculator
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -26,10 +26,11 @@ class FactorGraphTrueSkillCalculator extends SkillCalculator
 | 
			
		||||
        parent::__construct(SkillCalculatorSupportedOptions::PARTIAL_PLAY | SkillCalculatorSupportedOptions::PARTIAL_UPDATE, TeamsRange::atLeast(2), PlayersRange::atLeast(1));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function calculateNewRatings(GameInfo $gameInfo,
 | 
			
		||||
                                        array $teams,
 | 
			
		||||
                                        array $teamRanks): RatingContainer
 | 
			
		||||
    {
 | 
			
		||||
    public function calculateNewRatings(
 | 
			
		||||
        GameInfo $gameInfo,
 | 
			
		||||
        array $teams,
 | 
			
		||||
        array $teamRanks
 | 
			
		||||
    ): RatingContainer {
 | 
			
		||||
        Guard::argumentNotNull($gameInfo, 'gameInfo');
 | 
			
		||||
        $this->validateTeamCountAndPlayersCountPerTeam($teams);
 | 
			
		||||
 | 
			
		||||
@@ -88,8 +89,12 @@ class FactorGraphTrueSkillCalculator extends SkillCalculator
 | 
			
		||||
    private static function getPlayerMeansVector(array $teamAssignmentsList)
 | 
			
		||||
    {
 | 
			
		||||
        // A simple vector of all the player means.
 | 
			
		||||
        return new Vector(self::getPlayerRatingValues($teamAssignmentsList,
 | 
			
		||||
            fn ($rating) => $rating->getMean()));
 | 
			
		||||
        return new Vector(
 | 
			
		||||
            self::getPlayerRatingValues(
 | 
			
		||||
                $teamAssignmentsList,
 | 
			
		||||
                fn ($rating) => $rating->getMean()
 | 
			
		||||
            )
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static function getPlayerCovarianceMatrix(array $teamAssignmentsList)
 | 
			
		||||
@@ -97,8 +102,11 @@ class FactorGraphTrueSkillCalculator extends SkillCalculator
 | 
			
		||||
        // This is a square matrix whose diagonal values represent the variance (square of standard deviation) of all
 | 
			
		||||
        // players.
 | 
			
		||||
        return new DiagonalMatrix(
 | 
			
		||||
            self::getPlayerRatingValues($teamAssignmentsList,
 | 
			
		||||
                fn ($rating) => BasicMath::square($rating->getStandardDeviation())));
 | 
			
		||||
            self::getPlayerRatingValues(
 | 
			
		||||
                $teamAssignmentsList,
 | 
			
		||||
                fn ($rating) => BasicMath::square($rating->getStandardDeviation())
 | 
			
		||||
            )
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Helper function that gets a list of values for all player ratings
 | 
			
		||||
 
 | 
			
		||||
@@ -26,9 +26,12 @@ abstract class GaussianFactor extends Factor
 | 
			
		||||
    {
 | 
			
		||||
        $newDistribution = GaussianDistribution::fromPrecisionMean(0, 0);
 | 
			
		||||
 | 
			
		||||
        return parent::createVariableToMessageBindingWithMessage($variable,
 | 
			
		||||
        return parent::createVariableToMessageBindingWithMessage(
 | 
			
		||||
            $variable,
 | 
			
		||||
            new Message(
 | 
			
		||||
                $newDistribution,
 | 
			
		||||
                sprintf('message from %s to %s', $this, $variable)));
 | 
			
		||||
                sprintf('message from %s to %s', $this, $variable)
 | 
			
		||||
            )
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -14,22 +14,26 @@ use DNW\Skills\TrueSkill\TruncatedGaussianCorrectionFunctions;
 | 
			
		||||
 */
 | 
			
		||||
class GaussianGreaterThanFactor extends GaussianFactor
 | 
			
		||||
{
 | 
			
		||||
    private $_epsilon;
 | 
			
		||||
    private $epsilon;
 | 
			
		||||
 | 
			
		||||
    public function __construct($epsilon, Variable $variable)
 | 
			
		||||
    {
 | 
			
		||||
        parent::__construct(\sprintf('%s > %.2f', $variable, $epsilon));
 | 
			
		||||
        $this->_epsilon = $epsilon;
 | 
			
		||||
        $this->epsilon = $epsilon;
 | 
			
		||||
        $this->createVariableToMessageBinding($variable);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getLogNormalization()
 | 
			
		||||
    {
 | 
			
		||||
        /** @var Variable[] $vars */
 | 
			
		||||
        /**
 | 
			
		||||
 * @var Variable[] $vars
 | 
			
		||||
*/
 | 
			
		||||
        $vars = $this->getVariables();
 | 
			
		||||
        $marginal = $vars[0]->getValue();
 | 
			
		||||
 | 
			
		||||
        /** @var Message[] $messages */
 | 
			
		||||
        /**
 | 
			
		||||
 * @var Message[] $messages
 | 
			
		||||
*/
 | 
			
		||||
        $messages = $this->getMessages();
 | 
			
		||||
        $message = $messages[0]->getValue();
 | 
			
		||||
        $messageFromVariable = GaussianDistribution::divide($marginal, $message);
 | 
			
		||||
@@ -38,7 +42,7 @@ class GaussianGreaterThanFactor extends GaussianFactor
 | 
			
		||||
        +
 | 
			
		||||
        log(
 | 
			
		||||
            GaussianDistribution::cumulativeTo(
 | 
			
		||||
                ($messageFromVariable->getMean() - $this->_epsilon) /
 | 
			
		||||
                ($messageFromVariable->getMean() - $this->epsilon) /
 | 
			
		||||
                $messageFromVariable->getStandardDeviation()
 | 
			
		||||
            )
 | 
			
		||||
        );
 | 
			
		||||
@@ -57,7 +61,7 @@ class GaussianGreaterThanFactor extends GaussianFactor
 | 
			
		||||
 | 
			
		||||
        $dOnSqrtC = $d / $sqrtC;
 | 
			
		||||
 | 
			
		||||
        $epsilsonTimesSqrtC = $this->_epsilon * $sqrtC;
 | 
			
		||||
        $epsilsonTimesSqrtC = $this->epsilon * $sqrtC;
 | 
			
		||||
        $d = $messageFromVar->getPrecisionMean();
 | 
			
		||||
 | 
			
		||||
        $denom = 1.0 - TruncatedGaussianCorrectionFunctions::wExceedsMargin($dOnSqrtC, $epsilsonTimesSqrtC);
 | 
			
		||||
 
 | 
			
		||||
@@ -15,21 +15,25 @@ use Exception;
 | 
			
		||||
 */
 | 
			
		||||
class GaussianLikelihoodFactor extends GaussianFactor
 | 
			
		||||
{
 | 
			
		||||
    private $_precision;
 | 
			
		||||
    private $precision;
 | 
			
		||||
 | 
			
		||||
    public function __construct($betaSquared, Variable $variable1, Variable $variable2)
 | 
			
		||||
    {
 | 
			
		||||
        parent::__construct(sprintf('Likelihood of %s going to %s', $variable2, $variable1));
 | 
			
		||||
        $this->_precision = 1.0 / $betaSquared;
 | 
			
		||||
        $this->precision = 1.0 / $betaSquared;
 | 
			
		||||
        $this->createVariableToMessageBinding($variable1);
 | 
			
		||||
        $this->createVariableToMessageBinding($variable2);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getLogNormalization(): float
 | 
			
		||||
    {
 | 
			
		||||
        /** @var KeyedVariable[]|mixed $vars */
 | 
			
		||||
        /**
 | 
			
		||||
 * @var KeyedVariable[]|mixed $vars
 | 
			
		||||
*/
 | 
			
		||||
        $vars = $this->getVariables();
 | 
			
		||||
        /** @var Message[] $messages */
 | 
			
		||||
        /**
 | 
			
		||||
 * @var Message[] $messages
 | 
			
		||||
*/
 | 
			
		||||
        $messages = $this->getMessages();
 | 
			
		||||
 | 
			
		||||
        return GaussianDistribution::logRatioNormalization(
 | 
			
		||||
@@ -46,7 +50,7 @@ class GaussianLikelihoodFactor extends GaussianFactor
 | 
			
		||||
        $marginal1 = clone $variable1->getValue();
 | 
			
		||||
        $marginal2 = clone $variable2->getValue();
 | 
			
		||||
 | 
			
		||||
        $a = $this->_precision / ($this->_precision + $marginal2->getPrecision() - $message2Value->getPrecision());
 | 
			
		||||
        $a = $this->precision / ($this->precision + $marginal2->getPrecision() - $message2Value->getPrecision());
 | 
			
		||||
 | 
			
		||||
        $newMessage = GaussianDistribution::fromPrecisionMean(
 | 
			
		||||
            $a * ($marginal2->getPrecisionMean() - $message2Value->getPrecisionMean()),
 | 
			
		||||
@@ -72,10 +76,16 @@ class GaussianLikelihoodFactor extends GaussianFactor
 | 
			
		||||
        $vars = $this->getVariables();
 | 
			
		||||
 | 
			
		||||
        return match ($messageIndex) {
 | 
			
		||||
            0 => $this->updateHelper($messages[0], $messages[1],
 | 
			
		||||
                $vars[0], $vars[1]),
 | 
			
		||||
            1 => $this->updateHelper($messages[1], $messages[0],
 | 
			
		||||
                $vars[1], $vars[0]),
 | 
			
		||||
            0 => $this->updateHelper(
 | 
			
		||||
                $messages[0],
 | 
			
		||||
                $messages[1],
 | 
			
		||||
                $vars[0], $vars[1]
 | 
			
		||||
            ),
 | 
			
		||||
            1 => $this->updateHelper(
 | 
			
		||||
                $messages[1],
 | 
			
		||||
                $messages[0],
 | 
			
		||||
                $vars[1], $vars[0]
 | 
			
		||||
            ),
 | 
			
		||||
            default => throw new Exception(),
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -19,8 +19,10 @@ class GaussianPriorFactor extends GaussianFactor
 | 
			
		||||
    {
 | 
			
		||||
        parent::__construct(sprintf('Prior value going to %s', $variable));
 | 
			
		||||
        $this->_newMessage = new GaussianDistribution($mean, sqrt($variance));
 | 
			
		||||
        $newMessage = new Message(GaussianDistribution::fromPrecisionMean(0, 0),
 | 
			
		||||
            sprintf('message from %s to %s', $this, $variable));
 | 
			
		||||
        $newMessage = new Message(
 | 
			
		||||
            GaussianDistribution::fromPrecisionMean(0, 0),
 | 
			
		||||
            sprintf('message from %s to %s', $this, $variable)
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        $this->createVariableToMessageBindingWithMessage($variable, $newMessage);
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -15,13 +15,13 @@ use DNW\Skills\Numerics\GaussianDistribution;
 | 
			
		||||
 */
 | 
			
		||||
class GaussianWeightedSumFactor extends GaussianFactor
 | 
			
		||||
{
 | 
			
		||||
    private array $_variableIndexOrdersForWeights = [];
 | 
			
		||||
    private array $variableIndexOrdersForWeights = [];
 | 
			
		||||
 | 
			
		||||
    // This following is used for convenience, for example, the first entry is [0, 1, 2]
 | 
			
		||||
    // corresponding to v[0] = a1*v[1] + a2*v[2]
 | 
			
		||||
    private array $_weights = [];
 | 
			
		||||
    private array $weights = [];
 | 
			
		||||
 | 
			
		||||
    private array $_weightsSquared = [];
 | 
			
		||||
    private array $weightsSquared = [];
 | 
			
		||||
 | 
			
		||||
    public function __construct(Variable $sumVariable, array $variablesToSum, array $variableWeights = null)
 | 
			
		||||
    {
 | 
			
		||||
@@ -30,20 +30,20 @@ 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((array) $variableWeights);
 | 
			
		||||
        $this->_weights[0] = array_fill(0, count((array) $variableWeights), 0);
 | 
			
		||||
        $this->weights[0] = array_fill(0, count((array) $variableWeights), 0);
 | 
			
		||||
 | 
			
		||||
        for ($i = 0; $i < $variableWeightsLength; $i++) {
 | 
			
		||||
            $weight = &$variableWeights[$i];
 | 
			
		||||
            $this->_weights[0][$i] = $weight;
 | 
			
		||||
            $this->_weightsSquared[0][$i] = BasicMath::square($weight);
 | 
			
		||||
            $this->weights[0][$i] = $weight;
 | 
			
		||||
            $this->weightsSquared[0][$i] = BasicMath::square($weight);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $variablesToSumLength = count($variablesToSum);
 | 
			
		||||
 | 
			
		||||
        // 0..n-1
 | 
			
		||||
        $this->_variableIndexOrdersForWeights[0] = [];
 | 
			
		||||
        $this->variableIndexOrdersForWeights[0] = [];
 | 
			
		||||
        for ($i = 0; $i < ($variablesToSumLength + 1); $i++) {
 | 
			
		||||
            $this->_variableIndexOrdersForWeights[0][] = $i;
 | 
			
		||||
            $this->variableIndexOrdersForWeights[0][] = $i;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $variableWeightsLength = count((array) $variableWeights);
 | 
			
		||||
@@ -66,9 +66,11 @@ class GaussianWeightedSumFactor extends GaussianFactor
 | 
			
		||||
            // This is helpful since we skip over one of the spots
 | 
			
		||||
            $currentDestinationWeightIndex = 0;
 | 
			
		||||
 | 
			
		||||
            for ($currentWeightSourceIndex = 0;
 | 
			
		||||
            for (
 | 
			
		||||
                $currentWeightSourceIndex = 0;
 | 
			
		||||
                 $currentWeightSourceIndex < $variableWeightsLength;
 | 
			
		||||
                 $currentWeightSourceIndex++) {
 | 
			
		||||
                 $currentWeightSourceIndex++
 | 
			
		||||
            ) {
 | 
			
		||||
                if ($currentWeightSourceIndex === $weightsIndex - 1) {
 | 
			
		||||
                    continue;
 | 
			
		||||
                }
 | 
			
		||||
@@ -97,10 +99,10 @@ class GaussianWeightedSumFactor extends GaussianFactor
 | 
			
		||||
            $currentWeights[$currentDestinationWeightIndex] = $finalWeight;
 | 
			
		||||
            $currentWeightsSquared[$currentDestinationWeightIndex] = BasicMath::square($finalWeight);
 | 
			
		||||
            $variableIndices[count((array) $variableWeights)] = 0;
 | 
			
		||||
            $this->_variableIndexOrdersForWeights[] = $variableIndices;
 | 
			
		||||
            $this->variableIndexOrdersForWeights[] = $variableIndices;
 | 
			
		||||
 | 
			
		||||
            $this->_weights[$weightsIndex] = $currentWeights;
 | 
			
		||||
            $this->_weightsSquared[$weightsIndex] = $currentWeightsSquared;
 | 
			
		||||
            $this->weights[$weightsIndex] = $currentWeights;
 | 
			
		||||
            $this->weightsSquared[$weightsIndex] = $currentWeightsSquared;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $this->createVariableToMessageBinding($sumVariable);
 | 
			
		||||
@@ -192,7 +194,7 @@ class GaussianWeightedSumFactor extends GaussianFactor
 | 
			
		||||
        $updatedMessages = [];
 | 
			
		||||
        $updatedVariables = [];
 | 
			
		||||
 | 
			
		||||
        $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,
 | 
			
		||||
@@ -203,10 +205,12 @@ class GaussianWeightedSumFactor extends GaussianFactor
 | 
			
		||||
            $updatedVariables[] = $allVariables[$indicesToUse[$i]];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return $this->updateHelper($this->_weights[$messageIndex],
 | 
			
		||||
            $this->_weightsSquared[$messageIndex],
 | 
			
		||||
        return $this->updateHelper(
 | 
			
		||||
            $this->weights[$messageIndex],
 | 
			
		||||
            $this->weightsSquared[$messageIndex],
 | 
			
		||||
            $updatedMessages,
 | 
			
		||||
            $updatedVariables);
 | 
			
		||||
            $updatedVariables
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static function createName($sumVariable, $variablesToSum, $weights)
 | 
			
		||||
 
 | 
			
		||||
@@ -14,30 +14,34 @@ use DNW\Skills\TrueSkill\TruncatedGaussianCorrectionFunctions;
 | 
			
		||||
 */
 | 
			
		||||
class GaussianWithinFactor extends GaussianFactor
 | 
			
		||||
{
 | 
			
		||||
    private $_epsilon;
 | 
			
		||||
    private $epsilon;
 | 
			
		||||
 | 
			
		||||
    public function __construct($epsilon, Variable $variable)
 | 
			
		||||
    {
 | 
			
		||||
        parent::__construct(sprintf('%s <= %.2f', $variable, $epsilon));
 | 
			
		||||
        $this->_epsilon = $epsilon;
 | 
			
		||||
        $this->epsilon = $epsilon;
 | 
			
		||||
        $this->createVariableToMessageBinding($variable);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getLogNormalization()
 | 
			
		||||
    {
 | 
			
		||||
        /** @var Variable[] $variables */
 | 
			
		||||
        /**
 | 
			
		||||
 * @var Variable[] $variables
 | 
			
		||||
*/
 | 
			
		||||
        $variables = $this->getVariables();
 | 
			
		||||
        $marginal = $variables[0]->getValue();
 | 
			
		||||
 | 
			
		||||
        /** @var Message[] $messages */
 | 
			
		||||
        /**
 | 
			
		||||
 * @var Message[] $messages
 | 
			
		||||
*/
 | 
			
		||||
        $messages = $this->getMessages();
 | 
			
		||||
        $message = $messages[0]->getValue();
 | 
			
		||||
        $messageFromVariable = GaussianDistribution::divide($marginal, $message);
 | 
			
		||||
        $mean = $messageFromVariable->getMean();
 | 
			
		||||
        $std = $messageFromVariable->getStandardDeviation();
 | 
			
		||||
        $z = GaussianDistribution::cumulativeTo(($this->_epsilon - $mean) / $std)
 | 
			
		||||
        $z = GaussianDistribution::cumulativeTo(($this->epsilon - $mean) / $std)
 | 
			
		||||
            -
 | 
			
		||||
            GaussianDistribution::cumulativeTo((-$this->_epsilon - $mean) / $std);
 | 
			
		||||
            GaussianDistribution::cumulativeTo((-$this->epsilon - $mean) / $std);
 | 
			
		||||
 | 
			
		||||
        return -GaussianDistribution::logProductNormalization($messageFromVariable, $message) + log($z);
 | 
			
		||||
    }
 | 
			
		||||
@@ -54,7 +58,7 @@ class GaussianWithinFactor extends GaussianFactor
 | 
			
		||||
        $sqrtC = sqrt($c);
 | 
			
		||||
        $dOnSqrtC = $d / $sqrtC;
 | 
			
		||||
 | 
			
		||||
        $epsilonTimesSqrtC = $this->_epsilon * $sqrtC;
 | 
			
		||||
        $epsilonTimesSqrtC = $this->epsilon * $sqrtC;
 | 
			
		||||
        $d = $messageFromVariable->getPrecisionMean();
 | 
			
		||||
 | 
			
		||||
        $denominator = 1.0 - TruncatedGaussianCorrectionFunctions::wWithinMargin($dOnSqrtC, $epsilonTimesSqrtC);
 | 
			
		||||
 
 | 
			
		||||
@@ -13,28 +13,29 @@ class IteratedTeamDifferencesInnerLayer extends TrueSkillFactorGraphLayer
 | 
			
		||||
{
 | 
			
		||||
    public function __construct(
 | 
			
		||||
        TrueSkillFactorGraph $parentGraph,
 | 
			
		||||
        private readonly TeamPerformancesToTeamPerformanceDifferencesLayer $_TeamPerformancesToTeamPerformanceDifferencesLayer,
 | 
			
		||||
        private readonly TeamDifferencesComparisonLayer $_TeamDifferencesComparisonLayer
 | 
			
		||||
        private readonly TeamPerformancesToTeamPerformanceDifferencesLayer $TeamPerformancesToTeamPerformanceDifferencesLayer,
 | 
			
		||||
        private readonly TeamDifferencesComparisonLayer $TeamDifferencesComparisonLayer
 | 
			
		||||
    ) {
 | 
			
		||||
        parent::__construct($parentGraph);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getLocalFactors(): array
 | 
			
		||||
    {
 | 
			
		||||
        return array_merge($this->_TeamPerformancesToTeamPerformanceDifferencesLayer->getLocalFactors(),
 | 
			
		||||
            $this->_TeamDifferencesComparisonLayer->getLocalFactors()
 | 
			
		||||
        return array_merge(
 | 
			
		||||
            $this->TeamPerformancesToTeamPerformanceDifferencesLayer->getLocalFactors(),
 | 
			
		||||
            $this->TeamDifferencesComparisonLayer->getLocalFactors()
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function buildLayer()
 | 
			
		||||
    {
 | 
			
		||||
        $inputVariablesGroups = $this->getInputVariablesGroups();
 | 
			
		||||
        $this->_TeamPerformancesToTeamPerformanceDifferencesLayer->setInputVariablesGroups($inputVariablesGroups);
 | 
			
		||||
        $this->_TeamPerformancesToTeamPerformanceDifferencesLayer->buildLayer();
 | 
			
		||||
        $this->TeamPerformancesToTeamPerformanceDifferencesLayer->setInputVariablesGroups($inputVariablesGroups);
 | 
			
		||||
        $this->TeamPerformancesToTeamPerformanceDifferencesLayer->buildLayer();
 | 
			
		||||
 | 
			
		||||
        $teamDifferencesOutputVariablesGroups = $this->_TeamPerformancesToTeamPerformanceDifferencesLayer->getOutputVariablesGroups();
 | 
			
		||||
        $this->_TeamDifferencesComparisonLayer->setInputVariablesGroups($teamDifferencesOutputVariablesGroups);
 | 
			
		||||
        $this->_TeamDifferencesComparisonLayer->buildLayer();
 | 
			
		||||
        $teamDifferencesOutputVariablesGroups = $this->TeamPerformancesToTeamPerformanceDifferencesLayer->getOutputVariablesGroups();
 | 
			
		||||
        $this->TeamDifferencesComparisonLayer->setInputVariablesGroups($teamDifferencesOutputVariablesGroups);
 | 
			
		||||
        $this->TeamDifferencesComparisonLayer->buildLayer();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function createPriorSchedule(): ScheduleSequence
 | 
			
		||||
@@ -52,9 +53,9 @@ class IteratedTeamDifferencesInnerLayer extends TrueSkillFactorGraphLayer
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // When dealing with differences, there are always (n-1) differences, so add in the 1
 | 
			
		||||
        $totalTeamDifferences = is_countable($this->_TeamPerformancesToTeamPerformanceDifferencesLayer->getLocalFactors()) ? count($this->_TeamPerformancesToTeamPerformanceDifferencesLayer->getLocalFactors()) : 0;
 | 
			
		||||
        $totalTeamDifferences = is_countable($this->TeamPerformancesToTeamPerformanceDifferencesLayer->getLocalFactors()) ? count($this->TeamPerformancesToTeamPerformanceDifferencesLayer->getLocalFactors()) : 0;
 | 
			
		||||
 | 
			
		||||
        $localFactors = $this->_TeamPerformancesToTeamPerformanceDifferencesLayer->getLocalFactors();
 | 
			
		||||
        $localFactors = $this->TeamPerformancesToTeamPerformanceDifferencesLayer->getLocalFactors();
 | 
			
		||||
 | 
			
		||||
        $firstDifferencesFactor = $localFactors[0];
 | 
			
		||||
        $lastDifferencesFactor = $localFactors[$totalTeamDifferences - 1];
 | 
			
		||||
@@ -65,18 +66,22 @@ class IteratedTeamDifferencesInnerLayer extends TrueSkillFactorGraphLayer
 | 
			
		||||
                $loop,
 | 
			
		||||
                new ScheduleStep(
 | 
			
		||||
                    'teamPerformanceToPerformanceDifferenceFactors[0] @ 1',
 | 
			
		||||
                    $firstDifferencesFactor, 1),
 | 
			
		||||
                    $firstDifferencesFactor,
 | 
			
		||||
                    1
 | 
			
		||||
                ),
 | 
			
		||||
                new ScheduleStep(
 | 
			
		||||
                    sprintf('teamPerformanceToPerformanceDifferenceFactors[teamTeamDifferences = %d - 1] @ 2', $totalTeamDifferences),
 | 
			
		||||
                    $lastDifferencesFactor, 2),
 | 
			
		||||
                    $lastDifferencesFactor,
 | 
			
		||||
                    2
 | 
			
		||||
                ),
 | 
			
		||||
            ]
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    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];
 | 
			
		||||
@@ -84,27 +89,30 @@ class IteratedTeamDifferencesInnerLayer extends TrueSkillFactorGraphLayer
 | 
			
		||||
            new ScheduleStep(
 | 
			
		||||
                'send team perf to perf differences',
 | 
			
		||||
                $firstPerfToTeamDiff,
 | 
			
		||||
                0),
 | 
			
		||||
                0
 | 
			
		||||
            ),
 | 
			
		||||
            new ScheduleStep(
 | 
			
		||||
                'send to greater than or within factor',
 | 
			
		||||
                $firstTeamDiffComparison,
 | 
			
		||||
                0),
 | 
			
		||||
                0
 | 
			
		||||
            ),
 | 
			
		||||
        ];
 | 
			
		||||
 | 
			
		||||
        return $this->scheduleSequence(
 | 
			
		||||
            $itemsToSequence,
 | 
			
		||||
            'loop of just two teams inner sequence');
 | 
			
		||||
            'loop of just two teams inner sequence'
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private function createMultipleTeamInnerPriorLoopSchedule()
 | 
			
		||||
    {
 | 
			
		||||
        $totalTeamDifferences = is_countable($this->_TeamPerformancesToTeamPerformanceDifferencesLayer->getLocalFactors()) ? count($this->_TeamPerformancesToTeamPerformanceDifferencesLayer->getLocalFactors()) : 0;
 | 
			
		||||
        $totalTeamDifferences = is_countable($this->TeamPerformancesToTeamPerformanceDifferencesLayer->getLocalFactors()) ? count($this->TeamPerformancesToTeamPerformanceDifferencesLayer->getLocalFactors()) : 0;
 | 
			
		||||
 | 
			
		||||
        $forwardScheduleList = [];
 | 
			
		||||
 | 
			
		||||
        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];
 | 
			
		||||
@@ -114,14 +122,22 @@ class IteratedTeamDifferencesInnerLayer extends TrueSkillFactorGraphLayer
 | 
			
		||||
                    [
 | 
			
		||||
                        new ScheduleStep(
 | 
			
		||||
                            sprintf('team perf to perf diff %d', $i),
 | 
			
		||||
                            $currentTeamPerfToTeamPerfDiff, 0),
 | 
			
		||||
                            $currentTeamPerfToTeamPerfDiff,
 | 
			
		||||
                            0
 | 
			
		||||
                        ),
 | 
			
		||||
                        new ScheduleStep(
 | 
			
		||||
                            sprintf('greater than or within result factor %d', $i),
 | 
			
		||||
                            $currentTeamDiffComparison, 0),
 | 
			
		||||
                            $currentTeamDiffComparison,
 | 
			
		||||
                            0
 | 
			
		||||
                        ),
 | 
			
		||||
                        new ScheduleStep(
 | 
			
		||||
                            sprintf('team perf to perf diff factors [%d], 2', $i),
 | 
			
		||||
                            $currentTeamPerfToTeamPerfDiff, 2),
 | 
			
		||||
                    ], sprintf('current forward schedule piece %d', $i));
 | 
			
		||||
                            $currentTeamPerfToTeamPerfDiff,
 | 
			
		||||
                            2
 | 
			
		||||
                        ),
 | 
			
		||||
                    ],
 | 
			
		||||
                    sprintf('current forward schedule piece %d', $i)
 | 
			
		||||
                );
 | 
			
		||||
 | 
			
		||||
            $forwardScheduleList[] = $currentForwardSchedulePiece;
 | 
			
		||||
        }
 | 
			
		||||
@@ -131,8 +147,8 @@ class IteratedTeamDifferencesInnerLayer extends TrueSkillFactorGraphLayer
 | 
			
		||||
        $backwardScheduleList = [];
 | 
			
		||||
 | 
			
		||||
        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];
 | 
			
		||||
@@ -143,17 +159,21 @@ class IteratedTeamDifferencesInnerLayer extends TrueSkillFactorGraphLayer
 | 
			
		||||
                [
 | 
			
		||||
                    new ScheduleStep(
 | 
			
		||||
                        sprintf('teamPerformanceToPerformanceDifferenceFactors[totalTeamDifferences - 1 - %d] @ 0', $i),
 | 
			
		||||
                        $differencesFactor, 0
 | 
			
		||||
                        $differencesFactor,
 | 
			
		||||
                        0
 | 
			
		||||
                    ),
 | 
			
		||||
                    new ScheduleStep(
 | 
			
		||||
                        sprintf('greaterThanOrWithinResultFactors[totalTeamDifferences - 1 - %d] @ 0', $i),
 | 
			
		||||
                        $comparisonFactor, 0
 | 
			
		||||
                        $comparisonFactor,
 | 
			
		||||
                        0
 | 
			
		||||
                    ),
 | 
			
		||||
                    new ScheduleStep(
 | 
			
		||||
                        sprintf('teamPerformanceToPerformanceDifferenceFactors[totalTeamDifferences - 1 - %d] @ 1', $i),
 | 
			
		||||
                        $performancesToDifferencesFactor, 1
 | 
			
		||||
                        $performancesToDifferencesFactor,
 | 
			
		||||
                        1
 | 
			
		||||
                    ),
 | 
			
		||||
                ]);
 | 
			
		||||
                ]
 | 
			
		||||
            );
 | 
			
		||||
            $backwardScheduleList[] = $currentBackwardSchedulePiece;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -32,8 +32,10 @@ class PlayerPerformancesToTeamPerformancesLayer extends TrueSkillFactorGraphLaye
 | 
			
		||||
        return $this->scheduleSequence(
 | 
			
		||||
            array_map(
 | 
			
		||||
                fn ($weightedSumFactor) => new ScheduleStep('Perf to Team Perf Step', $weightedSumFactor, 0),
 | 
			
		||||
                $localFactors),
 | 
			
		||||
            'all player perf to team perf schedule');
 | 
			
		||||
                $localFactors
 | 
			
		||||
            ),
 | 
			
		||||
            'all player perf to team perf schedule'
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected function createPlayerToTeamSumFactor($teamMembers, $sumVariable): GaussianWeightedSumFactor
 | 
			
		||||
@@ -44,12 +46,14 @@ class PlayerPerformancesToTeamPerformancesLayer extends TrueSkillFactorGraphLaye
 | 
			
		||||
 | 
			
		||||
                return PartialPlay::getPartialPlayPercentage($player);
 | 
			
		||||
            },
 | 
			
		||||
            $teamMembers);
 | 
			
		||||
            $teamMembers
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        return new GaussianWeightedSumFactor(
 | 
			
		||||
            $sumVariable,
 | 
			
		||||
            $teamMembers,
 | 
			
		||||
            $weights);
 | 
			
		||||
            $weights
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function createPosteriorSchedule(): ScheduleSequence
 | 
			
		||||
@@ -60,8 +64,11 @@ class PlayerPerformancesToTeamPerformancesLayer extends TrueSkillFactorGraphLaye
 | 
			
		||||
            $localCurrentFactor = $currentFactor;
 | 
			
		||||
            $numberOfMessages = $localCurrentFactor->getNumberOfMessages();
 | 
			
		||||
            for ($currentIteration = 1; $currentIteration < $numberOfMessages; $currentIteration++) {
 | 
			
		||||
                $allFactors[] = new ScheduleStep('team sum perf @'.$currentIteration,
 | 
			
		||||
                    $localCurrentFactor, $currentIteration);
 | 
			
		||||
                $allFactors[] = new ScheduleStep(
 | 
			
		||||
                    'team sum perf @' . $currentIteration,
 | 
			
		||||
                    $localCurrentFactor,
 | 
			
		||||
                    $currentIteration
 | 
			
		||||
                );
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -74,6 +81,6 @@ class PlayerPerformancesToTeamPerformancesLayer extends TrueSkillFactorGraphLaye
 | 
			
		||||
 | 
			
		||||
        $teamMemberNames = \implode(', ', $memberNames);
 | 
			
		||||
 | 
			
		||||
        return $this->getParentFactorGraph()->getVariableFactory()->createBasicVariable('Team['.$teamMemberNames."]'s performance");
 | 
			
		||||
        return $this->getParentFactorGraph()->getVariableFactory()->createBasicVariable('Team[' . $teamMemberNames . "]'s performance");
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -47,8 +47,10 @@ class PlayerPriorValuesToSkillsLayer extends TrueSkillFactorGraphLayer
 | 
			
		||||
        return $this->scheduleSequence(
 | 
			
		||||
            array_map(
 | 
			
		||||
                fn ($prior) => new ScheduleStep('Prior to Skill Step', $prior, 0),
 | 
			
		||||
                $localFactors),
 | 
			
		||||
            'All priors');
 | 
			
		||||
                $localFactors
 | 
			
		||||
            ),
 | 
			
		||||
            'All priors'
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private function createPriorFactor(Rating $priorRating, Variable $skillsVariable)
 | 
			
		||||
@@ -66,6 +68,6 @@ class PlayerPriorValuesToSkillsLayer extends TrueSkillFactorGraphLayer
 | 
			
		||||
        $parentFactorGraph = $this->getParentFactorGraph();
 | 
			
		||||
        $variableFactory = $parentFactorGraph->getVariableFactory();
 | 
			
		||||
 | 
			
		||||
        return $variableFactory->createKeyedVariable($key, $key."'s skill");
 | 
			
		||||
        return $variableFactory->createKeyedVariable($key, $key . "'s skill");
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -9,13 +9,13 @@ use DNW\Skills\TrueSkill\TrueSkillFactorGraph;
 | 
			
		||||
 | 
			
		||||
class TeamDifferencesComparisonLayer extends TrueSkillFactorGraphLayer
 | 
			
		||||
{
 | 
			
		||||
    private $_epsilon;
 | 
			
		||||
    private $epsilon;
 | 
			
		||||
 | 
			
		||||
    public function __construct(TrueSkillFactorGraph $parentGraph, private readonly array $_teamRanks)
 | 
			
		||||
    public function __construct(TrueSkillFactorGraph $parentGraph, private readonly array $teamRanks)
 | 
			
		||||
    {
 | 
			
		||||
        parent::__construct($parentGraph);
 | 
			
		||||
        $gameInfo = $this->getParentFactorGraph()->getGameInfo();
 | 
			
		||||
        $this->_epsilon = DrawMargin::getDrawMarginFromDrawProbability($gameInfo->getDrawProbability(), $gameInfo->getBeta());
 | 
			
		||||
        $this->epsilon = DrawMargin::getDrawMarginFromDrawProbability($gameInfo->getDrawProbability(), $gameInfo->getBeta());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function buildLayer()
 | 
			
		||||
@@ -24,13 +24,13 @@ class TeamDifferencesComparisonLayer extends TrueSkillFactorGraphLayer
 | 
			
		||||
        $inputVarGroupsCount = is_countable($inputVarGroups) ? count($inputVarGroups) : 0;
 | 
			
		||||
 | 
			
		||||
        for ($i = 0; $i < $inputVarGroupsCount; $i++) {
 | 
			
		||||
            $isDraw = ($this->_teamRanks[$i] == $this->_teamRanks[$i + 1]);
 | 
			
		||||
            $isDraw = ($this->teamRanks[$i] == $this->teamRanks[$i + 1]);
 | 
			
		||||
            $teamDifference = $inputVarGroups[$i][0];
 | 
			
		||||
 | 
			
		||||
            $factor =
 | 
			
		||||
                $isDraw
 | 
			
		||||
                    ? new GaussianWithinFactor($this->_epsilon, $teamDifference)
 | 
			
		||||
                    : new GaussianGreaterThanFactor($this->_epsilon, $teamDifference);
 | 
			
		||||
                    ? new GaussianWithinFactor($this->epsilon, $teamDifference)
 | 
			
		||||
                    : new GaussianGreaterThanFactor($this->epsilon, $teamDifference);
 | 
			
		||||
 | 
			
		||||
            $this->addLayerFactor($factor);
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -26,10 +26,11 @@ class TeamPerformancesToTeamPerformanceDifferencesLayer extends TrueSkillFactorG
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private function createTeamPerformanceToDifferenceFactor(Variable $strongerTeam,
 | 
			
		||||
                                                             Variable $weakerTeam,
 | 
			
		||||
                                                             Variable $output)
 | 
			
		||||
    {
 | 
			
		||||
    private function createTeamPerformanceToDifferenceFactor(
 | 
			
		||||
        Variable $strongerTeam,
 | 
			
		||||
        Variable $weakerTeam,
 | 
			
		||||
        Variable $output
 | 
			
		||||
    ) {
 | 
			
		||||
        $teams = [$strongerTeam, $weakerTeam];
 | 
			
		||||
        $weights = [1.0, -1.0];
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -19,38 +19,40 @@ use DNW\Skills\TrueSkill\Layers\TeamPerformancesToTeamPerformanceDifferencesLaye
 | 
			
		||||
 | 
			
		||||
class TrueSkillFactorGraph extends FactorGraph
 | 
			
		||||
{
 | 
			
		||||
    private $_layers;
 | 
			
		||||
    private $layers;
 | 
			
		||||
 | 
			
		||||
    private $_priorLayer;
 | 
			
		||||
    private $priorLayer;
 | 
			
		||||
 | 
			
		||||
    public function __construct(private readonly GameInfo $_gameInfo, array $teams, array $teamRanks)
 | 
			
		||||
    public function __construct(private readonly GameInfo $gameInfo, array $teams, array $teamRanks)
 | 
			
		||||
    {
 | 
			
		||||
        $this->_priorLayer = new PlayerPriorValuesToSkillsLayer($this, $teams);
 | 
			
		||||
        $this->priorLayer = new PlayerPriorValuesToSkillsLayer($this, $teams);
 | 
			
		||||
        $newFactory = new VariableFactory(
 | 
			
		||||
            fn () => GaussianDistribution::fromPrecisionMean(0, 0));
 | 
			
		||||
            fn () => GaussianDistribution::fromPrecisionMean(0, 0)
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        $this->setVariableFactory($newFactory);
 | 
			
		||||
        $this->_layers = [
 | 
			
		||||
            $this->_priorLayer,
 | 
			
		||||
        $this->layers = [
 | 
			
		||||
            $this->priorLayer,
 | 
			
		||||
            new PlayerSkillsToPerformancesLayer($this),
 | 
			
		||||
            new PlayerPerformancesToTeamPerformancesLayer($this),
 | 
			
		||||
            new IteratedTeamDifferencesInnerLayer(
 | 
			
		||||
                $this,
 | 
			
		||||
                new TeamPerformancesToTeamPerformanceDifferencesLayer($this),
 | 
			
		||||
                new TeamDifferencesComparisonLayer($this, $teamRanks)),
 | 
			
		||||
                new TeamDifferencesComparisonLayer($this, $teamRanks)
 | 
			
		||||
            ),
 | 
			
		||||
        ];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getGameInfo()
 | 
			
		||||
    {
 | 
			
		||||
        return $this->_gameInfo;
 | 
			
		||||
        return $this->gameInfo;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function buildGraph(): void
 | 
			
		||||
    {
 | 
			
		||||
        $lastOutput = null;
 | 
			
		||||
 | 
			
		||||
        $layers = $this->_layers;
 | 
			
		||||
        $layers = $this->layers;
 | 
			
		||||
        foreach ($layers as $currentLayer) {
 | 
			
		||||
            if ($lastOutput != null) {
 | 
			
		||||
                $currentLayer->setInputVariablesGroups($lastOutput);
 | 
			
		||||
@@ -72,7 +74,7 @@ class TrueSkillFactorGraph extends FactorGraph
 | 
			
		||||
    {
 | 
			
		||||
        $factorList = new FactorList();
 | 
			
		||||
 | 
			
		||||
        $layers = $this->_layers;
 | 
			
		||||
        $layers = $this->layers;
 | 
			
		||||
        foreach ($layers as $currentLayer) {
 | 
			
		||||
            $localFactors = $currentLayer->getLocalFactors();
 | 
			
		||||
            foreach ($localFactors as $currentFactor) {
 | 
			
		||||
@@ -90,7 +92,7 @@ class TrueSkillFactorGraph extends FactorGraph
 | 
			
		||||
    {
 | 
			
		||||
        $fullSchedule = [];
 | 
			
		||||
 | 
			
		||||
        $layers = $this->_layers;
 | 
			
		||||
        $layers = $this->layers;
 | 
			
		||||
        foreach ($layers as $currentLayer) {
 | 
			
		||||
            $currentPriorSchedule = $currentLayer->createPriorSchedule();
 | 
			
		||||
            if ($currentPriorSchedule != null) {
 | 
			
		||||
@@ -98,7 +100,7 @@ class TrueSkillFactorGraph extends FactorGraph
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $allLayersReverse = array_reverse($this->_layers);
 | 
			
		||||
        $allLayersReverse = array_reverse($this->layers);
 | 
			
		||||
 | 
			
		||||
        foreach ($allLayersReverse as $currentLayer) {
 | 
			
		||||
            $currentPosteriorSchedule = $currentLayer->createPosteriorSchedule();
 | 
			
		||||
@@ -114,12 +116,14 @@ class TrueSkillFactorGraph extends FactorGraph
 | 
			
		||||
    {
 | 
			
		||||
        $result = new RatingContainer();
 | 
			
		||||
 | 
			
		||||
        $priorLayerOutputVariablesGroups = $this->_priorLayer->getOutputVariablesGroups();
 | 
			
		||||
        $priorLayerOutputVariablesGroups = $this->priorLayer->getOutputVariablesGroups();
 | 
			
		||||
        foreach ($priorLayerOutputVariablesGroups as $currentTeam) {
 | 
			
		||||
            foreach ($currentTeam as $currentPlayer) {
 | 
			
		||||
                $localCurrentPlayer = $currentPlayer->getKey();
 | 
			
		||||
                $newRating = new Rating($currentPlayer->getValue()->getMean(),
 | 
			
		||||
                    $currentPlayer->getValue()->getStandardDeviation());
 | 
			
		||||
                $newRating = new Rating(
 | 
			
		||||
                    $currentPlayer->getValue()->getMean(),
 | 
			
		||||
                    $currentPlayer->getValue()->getStandardDeviation()
 | 
			
		||||
                );
 | 
			
		||||
 | 
			
		||||
                $result->setRating($localCurrentPlayer, $newRating);
 | 
			
		||||
            }
 | 
			
		||||
 
 | 
			
		||||
@@ -15,7 +15,8 @@ class TruncatedGaussianCorrectionFunctions
 | 
			
		||||
     * correction of a single-sided truncated Gaussian with unit variance."
 | 
			
		||||
     *
 | 
			
		||||
     * @param $teamPerformanceDifference
 | 
			
		||||
     * @param $drawMargin In the paper, it's referred to as just "ε".
 | 
			
		||||
     * @param $drawMargin                In the paper, it's referred to as just
 | 
			
		||||
     *                                   "ε".
 | 
			
		||||
     * @param $c
 | 
			
		||||
     */
 | 
			
		||||
    public static function vExceedsMarginScaled(float $teamPerformanceDifference, float $drawMargin, float $c): float
 | 
			
		||||
@@ -123,7 +124,8 @@ class TruncatedGaussianCorrectionFunctions
 | 
			
		||||
            ($drawMargin - $teamPerformanceDifferenceAbsoluteValue)
 | 
			
		||||
            *
 | 
			
		||||
            GaussianDistribution::at(
 | 
			
		||||
                $drawMargin - $teamPerformanceDifferenceAbsoluteValue)
 | 
			
		||||
                $drawMargin - $teamPerformanceDifferenceAbsoluteValue
 | 
			
		||||
            )
 | 
			
		||||
            - (-$drawMargin - $teamPerformanceDifferenceAbsoluteValue)
 | 
			
		||||
            *
 | 
			
		||||
            GaussianDistribution::at(-$drawMargin - $teamPerformanceDifferenceAbsoluteValue)) / $denominator;
 | 
			
		||||
 
 | 
			
		||||
@@ -27,10 +27,11 @@ class TwoPlayerTrueSkillCalculator extends SkillCalculator
 | 
			
		||||
        parent::__construct(SkillCalculatorSupportedOptions::NONE, TeamsRange::exactly(2), PlayersRange::exactly(1));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function calculateNewRatings(GameInfo $gameInfo,
 | 
			
		||||
                                        array $teams,
 | 
			
		||||
                                        array $teamRanks): RatingContainer
 | 
			
		||||
    {
 | 
			
		||||
    public function calculateNewRatings(
 | 
			
		||||
        GameInfo $gameInfo,
 | 
			
		||||
        array $teams,
 | 
			
		||||
        array $teamRanks
 | 
			
		||||
    ): RatingContainer {
 | 
			
		||||
        // Basic argument checking
 | 
			
		||||
        Guard::argumentNotNull($gameInfo, 'gameInfo');
 | 
			
		||||
        $this->validateTeamCountAndPlayersCountPerTeam($teams);
 | 
			
		||||
@@ -51,17 +52,27 @@ class TwoPlayerTrueSkillCalculator extends SkillCalculator
 | 
			
		||||
 | 
			
		||||
        $results = new RatingContainer();
 | 
			
		||||
 | 
			
		||||
        $results->setRating($winner, self::calculateNewRating($gameInfo,
 | 
			
		||||
                                                              $winnerPreviousRating,
 | 
			
		||||
                                                              $loserPreviousRating,
 | 
			
		||||
                                                              $wasDraw ? PairwiseComparison::DRAW
 | 
			
		||||
                                                                       : PairwiseComparison::WIN));
 | 
			
		||||
        $results->setRating(
 | 
			
		||||
            $winner,
 | 
			
		||||
            self::calculateNewRating(
 | 
			
		||||
                $gameInfo,
 | 
			
		||||
                $winnerPreviousRating,
 | 
			
		||||
                $loserPreviousRating,
 | 
			
		||||
                $wasDraw ? PairwiseComparison::DRAW
 | 
			
		||||
                : PairwiseComparison::WIN
 | 
			
		||||
            )
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        $results->setRating($loser, self::calculateNewRating($gameInfo,
 | 
			
		||||
                                                             $loserPreviousRating,
 | 
			
		||||
                                                             $winnerPreviousRating,
 | 
			
		||||
                                                             $wasDraw ? PairwiseComparison::DRAW
 | 
			
		||||
                                                                      : PairwiseComparison::LOSE));
 | 
			
		||||
        $results->setRating(
 | 
			
		||||
            $loser,
 | 
			
		||||
            self::calculateNewRating(
 | 
			
		||||
                $gameInfo,
 | 
			
		||||
                $loserPreviousRating,
 | 
			
		||||
                $winnerPreviousRating,
 | 
			
		||||
                $wasDraw ? PairwiseComparison::DRAW
 | 
			
		||||
                : PairwiseComparison::LOSE
 | 
			
		||||
            )
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // And we're done!
 | 
			
		||||
        return $results;
 | 
			
		||||
 
 | 
			
		||||
@@ -60,12 +60,13 @@ class TwoTeamTrueSkillCalculator extends SkillCalculator
 | 
			
		||||
        return $results;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static function updatePlayerRatings(GameInfo $gameInfo,
 | 
			
		||||
                                                RatingContainer $newPlayerRatings,
 | 
			
		||||
                                                Team $selfTeam,
 | 
			
		||||
                                                Team $otherTeam,
 | 
			
		||||
                                                PairwiseComparison $selfToOtherTeamComparison): void
 | 
			
		||||
    {
 | 
			
		||||
    private static function updatePlayerRatings(
 | 
			
		||||
        GameInfo $gameInfo,
 | 
			
		||||
        RatingContainer $newPlayerRatings,
 | 
			
		||||
        Team $selfTeam,
 | 
			
		||||
        Team $otherTeam,
 | 
			
		||||
        PairwiseComparison $selfToOtherTeamComparison
 | 
			
		||||
    ): void {
 | 
			
		||||
        $drawMargin = DrawMargin::getDrawMarginFromDrawProbability(
 | 
			
		||||
            $gameInfo->getDrawProbability(),
 | 
			
		||||
            $gameInfo->getBeta()
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user