Files
trueskill/src/TrueSkill/Factors/GaussianWithinFactor.php

86 lines
2.9 KiB
PHP
Raw Normal View History

2022-07-05 15:55:47 +02:00
<?php
declare(strict_types=1);
2022-07-05 15:55:47 +02:00
namespace DNW\Skills\TrueSkill\Factors;
2022-07-05 15:33:34 +02:00
use DNW\Skills\FactorGraphs\Message;
use DNW\Skills\FactorGraphs\Variable;
2022-07-05 15:55:47 +02:00
use DNW\Skills\Numerics\GaussianDistribution;
use DNW\Skills\TrueSkill\TruncatedGaussianCorrectionFunctions;
/**
* Factor representing a team difference that has not exceeded the draw margin.
*
* See the accompanying math paper for more details.
*/
class GaussianWithinFactor extends GaussianFactor
{
public function __construct(private readonly float $epsilon, Variable $variable)
{
2024-03-19 15:56:57 +00:00
//$epsilon <= $variable
parent::__construct();
$this->createVariableToMessageBinding($variable);
}
2025-01-28 09:20:03 +00:00
#[\Override]
2023-08-02 09:36:44 +00:00
public function getLogNormalization(): float
{
2023-08-01 13:53:19 +00:00
/**
* @var Variable[] $variables
*/
$variables = $this->getVariables();
$marginal = $variables[0]->getValue();
2023-08-01 13:53:19 +00:00
/**
* @var Message[] $messages
*/
$messages = $this->getMessages();
$message = $messages[0]->getValue();
$messageFromVariable = GaussianDistribution::divide($marginal, $message);
$mean = $messageFromVariable->getMean();
$std = $messageFromVariable->getStandardDeviation();
2023-08-01 13:53:19 +00:00
$z = GaussianDistribution::cumulativeTo(($this->epsilon - $mean) / $std)
-
2023-08-01 13:53:19 +00:00
GaussianDistribution::cumulativeTo((-$this->epsilon - $mean) / $std);
return -GaussianDistribution::logProductNormalization($messageFromVariable, $message) + log($z);
}
2025-01-28 09:20:03 +00:00
#[\Override]
2023-08-02 09:36:44 +00:00
protected function updateMessageVariable(Message $message, Variable $variable): float
{
$oldMarginal = clone $variable->getValue();
$oldMessage = clone $message->getValue();
$messageFromVariable = GaussianDistribution::divide($oldMarginal, $oldMessage);
$c = $messageFromVariable->getPrecision();
$d = $messageFromVariable->getPrecisionMean();
$sqrtC = sqrt($c);
$dOnSqrtC = $d / $sqrtC;
2023-08-01 13:53:19 +00:00
$epsilonTimesSqrtC = $this->epsilon * $sqrtC;
$d = $messageFromVariable->getPrecisionMean();
$denominator = 1.0 - TruncatedGaussianCorrectionFunctions::wWithinMargin($dOnSqrtC, $epsilonTimesSqrtC);
$newPrecision = $c / $denominator;
2022-07-05 15:55:47 +02:00
$newPrecisionMean = ($d +
$sqrtC *
TruncatedGaussianCorrectionFunctions::vWithinMargin($dOnSqrtC, $epsilonTimesSqrtC)) / $denominator;
$newMarginal = GaussianDistribution::fromPrecisionMean($newPrecisionMean, $newPrecision);
$newMessage = GaussianDistribution::divide(
GaussianDistribution::multiply($oldMessage, $newMarginal),
$oldMarginal
);
// Update the message and marginal
$message->setValue($newMessage);
$variable->setValue($newMarginal);
// Return the difference in the new marginal
return GaussianDistribution::subtract($newMarginal, $oldMarginal);
}
2022-07-05 15:55:47 +02:00
}