mirror of
https://github.com/furyfire/trueskill.git
synced 2025-01-15 17:37:39 +00: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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
<?php
|
||||
<?php
|
||||
|
||||
namespace DNW\Skills;
|
||||
|
||||
|
@ -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,11 +32,13 @@ 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
|
||||
protected function createPlayerToTeamSumFactor($teamMembers, $sumVariable): GaussianWeightedSumFactor
|
||||
{
|
||||
$weights = array_map(
|
||||
function ($v) {
|
||||
@ -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