mirror of
https://github.com/furyfire/trueskill.git
synced 2025-04-18 20:04:28 +00:00
CodeBeautifier for PSR-12 standard.
This commit is contained in:
@ -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