Upgrade with rector

This commit is contained in:
Alex Wulf 2022-07-05 16:21:06 +02:00
parent fd5d276359
commit 689e3b75fe
38 changed files with 144 additions and 355 deletions

@ -17,7 +17,7 @@ class DefaultVariable extends Variable
return null; return null;
} }
public function setValue($value) public function setValue($value): never
{ {
throw new Exception(); throw new Exception();
} }

@ -6,15 +6,15 @@ use DNW\Skills\Guard;
use DNW\Skills\HashMap; use DNW\Skills\HashMap;
use Exception; use Exception;
abstract class Factor abstract class Factor implements \Stringable
{ {
private $_messages = []; private array $_messages = [];
private $_messageToVariableBinding; private $_messageToVariableBinding;
private $_name; private $_name;
private $_variables = []; private array $_variables = [];
protected function __construct($name) protected function __construct($name)
{ {
@ -111,7 +111,7 @@ abstract class Factor
return $message; return $message;
} }
public function __toString() public function __toString(): string
{ {
return $this->_name; return $this->_name;
} }

@ -5,17 +5,14 @@ namespace DNW\Skills\FactorGraphs;
// edit this // edit this
abstract class FactorGraphLayer abstract class FactorGraphLayer
{ {
private $_localFactors = []; private array $_localFactors = [];
private $_outputVariablesGroups = []; private array $_outputVariablesGroups = [];
private $_inputVariablesGroups = []; private $_inputVariablesGroups = [];
private $_parentFactorGraph; protected function __construct(private readonly FactorGraph $_parentFactorGraph)
protected function __construct(FactorGraph $parentGraph)
{ {
$this->_parentFactorGraph = $parentGraph;
} }
protected function getInputVariablesGroups() protected function getInputVariablesGroups()

@ -7,7 +7,7 @@ namespace DNW\Skills\FactorGraphs;
*/ */
class FactorList class FactorList
{ {
private $_list = []; private array $_list = [];
public function getLogNormalization() public function getLogNormalization()
{ {
@ -33,7 +33,7 @@ class FactorList
$sumLogS = 0; $sumLogS = 0;
foreach ($list as &$currentFactor) { foreach ($list as &$currentFactor) {
$sumLogS = $sumLogS + $currentFactor->getLogNormalization(); $sumLogS += $currentFactor->getLogNormalization();
} }
return $sumLogZ + $sumLogS; return $sumLogZ + $sumLogS;

@ -4,12 +4,9 @@ namespace DNW\Skills\FactorGraphs;
class KeyedVariable extends Variable class KeyedVariable extends Variable
{ {
private $_key; public function __construct(private $_key, $name, $prior)
public function __construct($key, $name, $prior)
{ {
parent::__construct($name, $prior); parent::__construct($name, $prior);
$this->_key = $key;
} }
public function getKey() public function getKey()

@ -2,16 +2,10 @@
namespace DNW\Skills\FactorGraphs; namespace DNW\Skills\FactorGraphs;
class Message class Message implements \Stringable
{ {
private $_name; public function __construct(private $_value = null, private $_name = null)
private $_value;
public function __construct($value = null, $name = null)
{ {
$this->_name = $name;
$this->_value = $value;
} }
public function getValue() public function getValue()
@ -24,7 +18,7 @@ class Message
$this->_value = $value; $this->_value = $value;
} }
public function __toString() public function __toString(): string
{ {
return (string) $this->_name; return (string) $this->_name;
} }

@ -2,19 +2,16 @@
namespace DNW\Skills\FactorGraphs; namespace DNW\Skills\FactorGraphs;
abstract class Schedule abstract class Schedule implements \Stringable
{ {
private $_name; protected function __construct(private $_name)
protected function __construct($name)
{ {
$this->_name = $name;
} }
abstract public function visit($depth = -1, $maxDepth = 0); abstract public function visit($depth = -1, $maxDepth = 0);
public function __toString() public function __toString(): string
{ {
return $this->_name; return (string) $this->_name;
} }
} }

@ -4,15 +4,9 @@ namespace DNW\Skills\FactorGraphs;
class ScheduleLoop extends Schedule class ScheduleLoop extends Schedule
{ {
private $_maxDelta; public function __construct($name, private readonly Schedule $_scheduleToLoop, private $_maxDelta)
private $_scheduleToLoop;
public function __construct($name, Schedule $scheduleToLoop, $maxDelta)
{ {
parent::__construct($name); parent::__construct($name);
$this->_scheduleToLoop = $scheduleToLoop;
$this->_maxDelta = $maxDelta;
} }
public function visit($depth = -1, $maxDepth = 0) public function visit($depth = -1, $maxDepth = 0)

@ -4,12 +4,9 @@ namespace DNW\Skills\FactorGraphs;
class ScheduleSequence extends Schedule class ScheduleSequence extends Schedule
{ {
private $_schedules; public function __construct($name, private readonly array $_schedules)
public function __construct($name, array $schedules)
{ {
parent::__construct($name); parent::__construct($name);
$this->_schedules = $schedules;
} }
public function visit($depth = -1, $maxDepth = 0) public function visit($depth = -1, $maxDepth = 0)

@ -4,22 +4,15 @@ namespace DNW\Skills\FactorGraphs;
class ScheduleStep extends Schedule class ScheduleStep extends Schedule
{ {
private $_factor; public function __construct($name, private readonly Factor $_factor, private $_index)
private $_index;
public function __construct($name, Factor $factor, $index)
{ {
parent::__construct($name); parent::__construct($name);
$this->_factor = $factor;
$this->_index = $index;
} }
public function visit($depth = -1, $maxDepth = 0) public function visit($depth = -1, $maxDepth = 0)
{ {
$currentFactor = $this->_factor; $currentFactor = $this->_factor;
$delta = $currentFactor->updateMessageIndex($this->_index);
return $delta; return $currentFactor->updateMessageIndex($this->_index);
} }
} }

@ -2,18 +2,15 @@
namespace DNW\Skills\FactorGraphs; namespace DNW\Skills\FactorGraphs;
class Variable class Variable implements \Stringable
{ {
private $_name; private $_name;
private $_prior;
private $_value; private $_value;
public function __construct($name, $prior) public function __construct($name, private $_prior)
{ {
$this->_name = 'Variable['.$name.']'; $this->_name = 'Variable['.$name.']';
$this->_prior = $prior;
$this->resetToPrior(); $this->resetToPrior();
} }
@ -32,7 +29,7 @@ class Variable
$this->_value = $this->_prior; $this->_value = $this->_prior;
} }
public function __toString() public function __toString(): string
{ {
return $this->_name; return $this->_name;
} }

@ -4,27 +4,21 @@ namespace DNW\Skills\FactorGraphs;
class VariableFactory class VariableFactory
{ {
// using a Func<TValue> to encourage fresh copies in case it's overwritten public function __construct(private $_variablePriorInitializer)
private $_variablePriorInitializer;
public function __construct($variablePriorInitializer)
{ {
$this->_variablePriorInitializer = $variablePriorInitializer;
} }
public function createBasicVariable($name) public function createBasicVariable($name)
{ {
$initializer = $this->_variablePriorInitializer; $initializer = $this->_variablePriorInitializer;
$newVar = new Variable($name, $initializer());
return $newVar; return new Variable($name, $initializer());
} }
public function createKeyedVariable($key, $name) public function createKeyedVariable($key, $name)
{ {
$initializer = $this->_variablePriorInitializer; $initializer = $this->_variablePriorInitializer;
$newVar = new KeyedVariable($key, $name, $initializer());
return $newVar; return new KeyedVariable($key, $name, $initializer());
} }
} }

@ -7,37 +7,18 @@ namespace DNW\Skills;
*/ */
class GameInfo class GameInfo
{ {
const DEFAULT_BETA = 4.1666666666666666666666666666667; // Default initial mean / 6 final const DEFAULT_BETA = 4.1666666666666666666666666666667; // Default initial mean / 6
const DEFAULT_DRAW_PROBABILITY = 0.10; final const DEFAULT_DRAW_PROBABILITY = 0.10;
const DEFAULT_DYNAMICS_FACTOR = 0.083333333333333333333333333333333; // Default initial mean / 300 final const DEFAULT_DYNAMICS_FACTOR = 0.083333333333333333333333333333333; // Default initial mean / 300
const DEFAULT_INITIAL_MEAN = 25.0; final const DEFAULT_INITIAL_MEAN = 25.0;
const DEFAULT_INITIAL_STANDARD_DEVIATION = 8.3333333333333333333333333333333; // Default initial mean / 3 final const DEFAULT_INITIAL_STANDARD_DEVIATION = 8.3333333333333333333333333333333;
private $_initialMean; public function __construct(private $_initialMean = self::DEFAULT_INITIAL_MEAN, private $_initialStandardDeviation = self::DEFAULT_INITIAL_STANDARD_DEVIATION, private $_beta = self::DEFAULT_BETA, private $_dynamicsFactor = self::DEFAULT_DYNAMICS_FACTOR, private $_drawProbability = self::DEFAULT_DRAW_PROBABILITY)
private $_initialStandardDeviation;
private $_beta;
private $_dynamicsFactor;
private $_drawProbability;
public function __construct($initialMean = self::DEFAULT_INITIAL_MEAN,
$initialStandardDeviation = self::DEFAULT_INITIAL_STANDARD_DEVIATION,
$beta = self::DEFAULT_BETA,
$dynamicsFactor = self::DEFAULT_DYNAMICS_FACTOR,
$drawProbability = self::DEFAULT_DRAW_PROBABILITY)
{ {
$this->_initialMean = $initialMean;
$this->_initialStandardDeviation = $initialStandardDeviation;
$this->_beta = $beta;
$this->_dynamicsFactor = $dynamicsFactor;
$this->_drawProbability = $drawProbability;
} }
public function getInitialMean() public function getInitialMean()

@ -7,16 +7,15 @@ namespace DNW\Skills;
*/ */
class HashMap class HashMap
{ {
private $_hashToValue = []; private array $_hashToValue = [];
private $_hashToKey = []; private array $_hashToKey = [];
public function getValue($key) public function getValue($key)
{ {
$hash = self::getHash($key); $hash = self::getHash($key);
$hashValue = $this->_hashToValue[$hash];
return $hashValue; return $this->_hashToValue[$hash];
} }
public function setValue($key, $value) public function setValue($key, $value)
@ -30,16 +29,12 @@ class HashMap
public function getAllKeys() public function getAllKeys()
{ {
$keys = array_values($this->_hashToKey); return array_values($this->_hashToKey);
return $keys;
} }
public function getAllValues() public function getAllValues()
{ {
$values = array_values($this->_hashToValue); return array_values($this->_hashToValue);
return $values;
} }
public function count() public function count()

@ -14,7 +14,7 @@ class DiagonalMatrix extends Matrix
for ($currentRow = 0; $currentRow < $rowCount; $currentRow++) { for ($currentRow = 0; $currentRow < $rowCount; $currentRow++) {
for ($currentCol = 0; $currentCol < $colCount; $currentCol++) { for ($currentCol = 0; $currentCol < $colCount; $currentCol++) {
if ($currentRow == $currentCol) { if ($currentRow === $currentCol) {
$this->setValue($currentRow, $currentCol, $diagonalValues[$currentRow]); $this->setValue($currentRow, $currentCol, $diagonalValues[$currentRow]);
} else { } else {
$this->setValue($currentRow, $currentCol, 0); $this->setValue($currentRow, $currentCol, 0);

@ -8,12 +8,8 @@ namespace DNW\Skills\Numerics;
* @author Jeff Moser <jeff@moserware.com> * @author Jeff Moser <jeff@moserware.com>
* @copyright 2010 Jeff Moser * @copyright 2010 Jeff Moser
*/ */
class GaussianDistribution class GaussianDistribution implements \Stringable
{ {
private $_mean;
private $_standardDeviation;
// precision and precisionMean are used because they make multiplying and dividing simpler // precision and precisionMean are used because they make multiplying and dividing simpler
// (the the accompanying math paper for more details) // (the the accompanying math paper for more details)
private $_precision; private $_precision;
@ -22,11 +18,9 @@ class GaussianDistribution
private $_variance; private $_variance;
public function __construct($mean = 0.0, $standardDeviation = 1.0) public function __construct(private $_mean = 0.0, private $_standardDeviation = 1.0)
{ {
$this->_mean = $mean; $this->_variance = BasicMath::square($_standardDeviation);
$this->_standardDeviation = $standardDeviation;
$this->_variance = BasicMath::square($standardDeviation);
if ($this->_variance != 0) { if ($this->_variance != 0) {
$this->_precision = 1.0 / $this->_variance; $this->_precision = 1.0 / $this->_variance;
@ -34,11 +28,7 @@ class GaussianDistribution
} else { } else {
$this->_precision = \INF; $this->_precision = \INF;
if ($this->_mean == 0) { $this->_precisionMean = $this->_mean == 0 ? 0 : \INF;
$this->_precisionMean = 0;
} else {
$this->_precisionMean = \INF;
}
} }
} }
@ -172,9 +162,8 @@ class GaussianDistribution
$multiplier = 1.0 / ($standardDeviation * sqrt(2 * M_PI)); $multiplier = 1.0 / ($standardDeviation * sqrt(2 * M_PI));
$expPart = exp((-1.0 * BasicMath::square($x - $mean)) / (2 * BasicMath::square($standardDeviation))); $expPart = exp((-1.0 * BasicMath::square($x - $mean)) / (2 * BasicMath::square($standardDeviation)));
$result = $multiplier * $expPart;
return $result; return $multiplier * $expPart;
} }
public static function cumulativeTo($x, $mean = 0.0, $standardDeviation = 1.0) public static function cumulativeTo($x, $mean = 0.0, $standardDeviation = 1.0)
@ -267,7 +256,7 @@ class GaussianDistribution
return $mean - sqrt(2) * $standardDeviation * GaussianDistribution::inverseErrorFunctionCumulativeTo(2 * $x); return $mean - sqrt(2) * $standardDeviation * GaussianDistribution::inverseErrorFunctionCumulativeTo(2 * $x);
} }
public function __toString() public function __toString(): string
{ {
return sprintf('mean=%.4f standardDeviation=%.4f', $this->_mean, $this->_standardDeviation); return sprintf('mean=%.4f standardDeviation=%.4f', $this->_mean, $this->_standardDeviation);
} }

@ -6,19 +6,10 @@ use Exception;
class Matrix class Matrix
{ {
const ERROR_TOLERANCE = 0.0000000001; public const ERROR_TOLERANCE = 0.0000000001;
private $_matrixRowData; public function __construct(private $_rowCount = 0, private $_columnCount = 0, private $_matrixRowData = null)
private $_rowCount;
private $_columnCount;
public function __construct($rows = 0, $columns = 0, $matrixData = null)
{ {
$this->_rowCount = $rows;
$this->_columnCount = $columns;
$this->_matrixRowData = $matrixData;
} }
public static function fromColumnValues($rows, $columns, $columnValues) public static function fromColumnValues($rows, $columns, $columnValues)
@ -37,9 +28,8 @@ class Matrix
return $result; return $result;
} }
public static function fromRowsColumns() public static function fromRowsColumns(...$args)
{ {
$args = \func_get_args();
$rows = $args[0]; $rows = $args[0];
$cols = $args[1]; $cols = $args[1];
$result = new Matrix($rows, $cols); $result = new Matrix($rows, $cols);
@ -138,7 +128,7 @@ class Matrix
$firstRowColValue = $this->_matrixRowData[0][$currentColumn]; $firstRowColValue = $this->_matrixRowData[0][$currentColumn];
$cofactor = $this->getCofactor(0, $currentColumn); $cofactor = $this->getCofactor(0, $currentColumn);
$itemToAdd = $firstRowColValue * $cofactor; $itemToAdd = $firstRowColValue * $cofactor;
$result = $result + $itemToAdd; $result += $itemToAdd;
} }
return $result; return $result;
@ -258,7 +248,7 @@ class Matrix
$leftValue = $left->getValue($currentRow, $vectorIndex); $leftValue = $left->getValue($currentRow, $vectorIndex);
$rightValue = $right->getValue($vectorIndex, $currentColumn); $rightValue = $right->getValue($vectorIndex, $currentColumn);
$vectorIndexProduct = $leftValue * $rightValue; $vectorIndexProduct = $leftValue * $rightValue;
$productValue = $productValue + $vectorIndexProduct; $productValue += $vectorIndexProduct;
} }
$resultMatrix[$currentRow][$currentColumn] = $productValue; $resultMatrix[$currentRow][$currentColumn] = $productValue;

@ -4,9 +4,8 @@ namespace DNW\Skills\Numerics;
class SquareMatrix extends Matrix class SquareMatrix extends Matrix
{ {
public function __construct() public function __construct(...$allValues)
{ {
$allValues = func_get_args();
$rows = (int) sqrt(count($allValues)); $rows = (int) sqrt(count($allValues));
$cols = $rows; $cols = $rows;

@ -9,21 +9,18 @@ namespace DNW\Skills;
*/ */
class PairwiseComparison class PairwiseComparison
{ {
const WIN = 1; final const WIN = 1;
const DRAW = 0; final const DRAW = 0;
const LOSE = -1; final const LOSE = -1;
public static function getRankFromComparison($comparison) public static function getRankFromComparison($comparison)
{ {
switch ($comparison) { return match ($comparison) {
case PairwiseComparison::WIN: PairwiseComparison::WIN => [1, 2],
return [1, 2]; PairwiseComparison::LOSE => [2, 1],
case PairwiseComparison::LOSE: default => [1, 1],
return [2, 1]; };
default:
return [1, 1];
}
} }
} }

@ -5,13 +5,11 @@ namespace DNW\Skills;
/** /**
* Represents a player who has a Rating. * Represents a player who has a Rating.
*/ */
class Player implements ISupportPartialPlay, ISupportPartialUpdate class Player implements ISupportPartialPlay, ISupportPartialUpdate, \Stringable
{ {
const DEFAULT_PARTIAL_PLAY_PERCENTAGE = 1.0; // = 100% play time final const DEFAULT_PARTIAL_PLAY_PERCENTAGE = 1.0; // = 100% play time
const DEFAULT_PARTIAL_UPDATE_PERCENTAGE = 1.0; // = receive 100% update final const DEFAULT_PARTIAL_UPDATE_PERCENTAGE = 1.0;
private $_Id;
private $_PartialPlayPercentage; private $_PartialPlayPercentage;
@ -20,18 +18,17 @@ class Player implements ISupportPartialPlay, ISupportPartialUpdate
/** /**
* Constructs a player. * Constructs a player.
* *
* @param mixed $id The identifier for the player, such as a name. * @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 $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 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($id, public function __construct(private $_Id,
$partialPlayPercentage = self::DEFAULT_PARTIAL_PLAY_PERCENTAGE, $partialPlayPercentage = self::DEFAULT_PARTIAL_PLAY_PERCENTAGE,
$partialUpdatePercentage = self::DEFAULT_PARTIAL_UPDATE_PERCENTAGE) $partialUpdatePercentage = self::DEFAULT_PARTIAL_UPDATE_PERCENTAGE)
{ {
// If they don't want to give a player an id, that's ok... // If they don't want to give a player an id, that's ok...
Guard::argumentInRangeInclusive($partialPlayPercentage, 0.0, 1.0, 'partialPlayPercentage'); Guard::argumentInRangeInclusive($partialPlayPercentage, 0.0, 1.0, 'partialPlayPercentage');
Guard::argumentInRangeInclusive($partialUpdatePercentage, 0, 1.0, 'partialUpdatePercentage'); Guard::argumentInRangeInclusive($partialUpdatePercentage, 0, 1.0, 'partialUpdatePercentage');
$this->_Id = $id;
$this->_PartialPlayPercentage = $partialPlayPercentage; $this->_PartialPlayPercentage = $partialPlayPercentage;
$this->_PartialUpdatePercentage = $partialUpdatePercentage; $this->_PartialUpdatePercentage = $partialUpdatePercentage;
} }
@ -60,7 +57,7 @@ class Player implements ISupportPartialPlay, ISupportPartialUpdate
return $this->_PartialUpdatePercentage; return $this->_PartialUpdatePercentage;
} }
public function __toString() public function __toString(): string
{ {
return (string) $this->_Id; return (string) $this->_Id;
} }

@ -6,11 +6,6 @@ use DNW\Skills\Numerics\Range;
class PlayersRange extends Range class PlayersRange extends Range
{ {
public function __construct($min, $max)
{
parent::__construct($min, $max);
}
protected static function create($min, $max) protected static function create($min, $max)
{ {
return new PlayersRange($min, $max); return new PlayersRange($min, $max);

@ -5,28 +5,19 @@ namespace DNW\Skills;
// Container for a player's rating. // Container for a player's rating.
use DNW\Skills\Numerics\GaussianDistribution; use DNW\Skills\Numerics\GaussianDistribution;
class Rating class Rating implements \Stringable
{ {
const CONSERVATIVE_STANDARD_DEVIATION_MULTIPLIER = 3; final const CONSERVATIVE_STANDARD_DEVIATION_MULTIPLIER = 3;
private $_conservativeStandardDeviationMultiplier;
private $_mean;
private $_standardDeviation;
/** /**
* Constructs a rating. * Constructs a rating.
* *
* @param float $mean The statistical mean value of the rating (also known as mu). * @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 $_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|int $_conservativeStandardDeviationMultiplier optional The number of standardDeviations to subtract from the mean to achieve a conservative rating.
*/ */
public function __construct($mean, $standardDeviation, $conservativeStandardDeviationMultiplier = self::CONSERVATIVE_STANDARD_DEVIATION_MULTIPLIER) public function __construct(private $_mean, private $_standardDeviation, private $_conservativeStandardDeviationMultiplier = self::CONSERVATIVE_STANDARD_DEVIATION_MULTIPLIER)
{ {
$this->_mean = $mean;
$this->_standardDeviation = $standardDeviation;
$this->_conservativeStandardDeviationMultiplier = $conservativeStandardDeviationMultiplier;
} }
/** /**
@ -76,7 +67,7 @@ class Rating
return new Rating($partialPosteriorGaussion->getMean(), $partialPosteriorGaussion->getStandardDeviation(), $prior->_conservativeStandardDeviationMultiplier); return new Rating($partialPosteriorGaussion->getMean(), $partialPosteriorGaussion->getStandardDeviation(), $prior->_conservativeStandardDeviationMultiplier);
} }
public function __toString() public function __toString(): string
{ {
return sprintf('mean=%.4f, standardDeviation=%.4f', $this->_mean, $this->_standardDeviation); return sprintf('mean=%.4f, standardDeviation=%.4f', $this->_mean, $this->_standardDeviation);
} }

@ -9,17 +9,8 @@ use Exception;
*/ */
abstract class SkillCalculator abstract class SkillCalculator
{ {
private $_supportedOptions; protected function __construct(private $_supportedOptions, private readonly TeamsRange $_totalTeamsAllowed, private readonly PlayersRange $_playersPerTeamAllowed)
private $_playersPerTeamAllowed;
private $_totalTeamsAllowed;
protected function __construct($supportedOptions, TeamsRange $totalTeamsAllowed, PlayersRange $playerPerTeamAllowed)
{ {
$this->_supportedOptions = $supportedOptions;
$this->_totalTeamsAllowed = $totalTeamsAllowed;
$this->_playersPerTeamAllowed = $playerPerTeamAllowed;
} }
/** /**
@ -55,8 +46,6 @@ abstract class SkillCalculator
/** /**
* @param array<\DNW\Skills\Team> $teams * @param array<\DNW\Skills\Team> $teams
* @param \DNW\Skills\TeamsRange $totalTeams
* @param \DNW\Skills\PlayersRange $playersPerTeam
* @return void * @return void
* @throws \Exception * @throws \Exception
*/ */
@ -79,9 +68,9 @@ abstract class SkillCalculator
class SkillCalculatorSupportedOptions class SkillCalculatorSupportedOptions
{ {
const NONE = 0x00; final const NONE = 0x00;
const PARTIAL_PLAY = 0x01; final const PARTIAL_PLAY = 0x01;
const PARTIAL_UPDATE = 0x02; final const PARTIAL_UPDATE = 0x02;
} }

@ -4,9 +4,8 @@ namespace DNW\Skills;
class Teams class Teams
{ {
public static function concat(/*variable arguments*/) public static function concat(...$args/*variable arguments*/)
{ {
$args = func_get_args();
$result = []; $result = [];
foreach ($args as $currentTeam) { foreach ($args as $currentTeam) {

@ -6,11 +6,6 @@ use DNW\Skills\Numerics\Range;
class TeamsRange extends Range class TeamsRange extends Range
{ {
public function __construct($min, $max)
{
parent::__construct($min, $max);
}
protected static function create($min, $max) protected static function create($min, $max)
{ {
return new TeamsRange($min, $max); return new TeamsRange($min, $max);

@ -38,7 +38,7 @@ class FactorGraphTrueSkillCalculator extends SkillCalculator
$factorGraph->buildGraph(); $factorGraph->buildGraph();
$factorGraph->runSchedule(); $factorGraph->runSchedule();
$probabilityOfOutcome = $factorGraph->getProbabilityOfRanking(); $factorGraph->getProbabilityOfRanking();
return $factorGraph->getUpdatedRatings(); return $factorGraph->getUpdatedRatings();
} }
@ -47,11 +47,11 @@ class FactorGraphTrueSkillCalculator extends SkillCalculator
{ {
// We need to create the A matrix which is the player team assigments. // We need to create the A matrix which is the player team assigments.
$teamAssignmentsList = $teams; $teamAssignmentsList = $teams;
$skillsMatrix = $this->getPlayerCovarianceMatrix($teamAssignmentsList); $skillsMatrix = self::getPlayerCovarianceMatrix($teamAssignmentsList);
$meanVector = $this->getPlayerMeansVector($teamAssignmentsList); $meanVector = self::getPlayerMeansVector($teamAssignmentsList);
$meanVectorTranspose = $meanVector->getTranspose(); $meanVectorTranspose = $meanVector->getTranspose();
$playerTeamAssignmentsMatrix = $this->createPlayerTeamAssignmentMatrix($teamAssignmentsList, $meanVector->getRowCount()); $playerTeamAssignmentsMatrix = self::createPlayerTeamAssignmentMatrix($teamAssignmentsList, $meanVector->getRowCount());
$playerTeamAssignmentsMatrixTranspose = $playerTeamAssignmentsMatrix->getTranspose(); $playerTeamAssignmentsMatrixTranspose = $playerTeamAssignmentsMatrix->getTranspose();
$betaSquared = BasicMath::square($gameInfo->getBeta()); $betaSquared = BasicMath::square($gameInfo->getBeta());
@ -81,18 +81,14 @@ class FactorGraphTrueSkillCalculator extends SkillCalculator
$sqrtPartDenominator = $middle->getDeterminant(); $sqrtPartDenominator = $middle->getDeterminant();
$sqrtPart = $sqrtPartNumerator / $sqrtPartDenominator; $sqrtPart = $sqrtPartNumerator / $sqrtPartDenominator;
$result = exp($expPart) * sqrt($sqrtPart); return exp($expPart) * sqrt($sqrtPart);
return $result;
} }
private static function getPlayerMeansVector(array $teamAssignmentsList) private static function getPlayerMeansVector(array $teamAssignmentsList)
{ {
// A simple vector of all the player means. // A simple vector of all the player means.
return new Vector(self::getPlayerRatingValues($teamAssignmentsList, return new Vector(self::getPlayerRatingValues($teamAssignmentsList,
function ($rating) { fn($rating) => $rating->getMean()));
return $rating->getMean();
}));
} }
private static function getPlayerCovarianceMatrix(array $teamAssignmentsList) private static function getPlayerCovarianceMatrix(array $teamAssignmentsList)
@ -101,9 +97,7 @@ class FactorGraphTrueSkillCalculator extends SkillCalculator
// players. // players.
return new DiagonalMatrix( return new DiagonalMatrix(
self::getPlayerRatingValues($teamAssignmentsList, self::getPlayerRatingValues($teamAssignmentsList,
function ($rating) { fn($rating) => BasicMath::square($rating->getStandardDeviation())));
return BasicMath::square($rating->getStandardDeviation());
}));
} }
// Helper function that gets a list of values for all player ratings // Helper function that gets a list of values for all player ratings
@ -141,7 +135,7 @@ class FactorGraphTrueSkillCalculator extends SkillCalculator
$playerAssignments = []; $playerAssignments = [];
$totalPreviousPlayers = 0; $totalPreviousPlayers = 0;
$teamAssignmentsListCount = count($teamAssignmentsList); $teamAssignmentsListCount = is_countable($teamAssignmentsList) ? count($teamAssignmentsList) : 0;
$currentColumn = 0; $currentColumn = 0;
@ -175,8 +169,6 @@ class FactorGraphTrueSkillCalculator extends SkillCalculator
$currentColumn++; $currentColumn++;
} }
$playerTeamAssignmentsMatrix = Matrix::fromColumnValues($totalPlayers, $teamAssignmentsListCount - 1, $playerAssignments); return Matrix::fromColumnValues($totalPlayers, $teamAssignmentsListCount - 1, $playerAssignments);
return $playerTeamAssignmentsMatrix;
} }
} }

@ -9,19 +9,10 @@ use DNW\Skills\Numerics\GaussianDistribution;
abstract class GaussianFactor extends Factor abstract class GaussianFactor extends Factor
{ {
protected function __construct($name)
{
parent::__construct($name);
}
/** /**
* Sends the factor-graph message with and returns the log-normalization constant. * Sends the factor-graph message with and returns the log-normalization constant.
*
* @param Message $message
* @param Variable $variable
* @return float|int
*/ */
protected function sendMessageVariable(Message $message, Variable $variable) protected function sendMessageVariable(Message $message, Variable $variable): float|int
{ {
$marginal = $variable->getValue(); $marginal = $variable->getValue();
$messageValue = $message->getValue(); $messageValue = $message->getValue();
@ -34,11 +25,10 @@ abstract class GaussianFactor extends Factor
public function createVariableToMessageBinding(Variable $variable) public function createVariableToMessageBinding(Variable $variable)
{ {
$newDistribution = GaussianDistribution::fromPrecisionMean(0, 0); $newDistribution = GaussianDistribution::fromPrecisionMean(0, 0);
$binding = parent::createVariableToMessageBindingWithMessage($variable,
return parent::createVariableToMessageBindingWithMessage($variable,
new Message( new Message(
$newDistribution, $newDistribution,
sprintf('message from %s to %s', $this, $variable))); sprintf('message from %s to %s', $this, $variable)));
return $binding;
} }
} }

@ -71,15 +71,12 @@ class GaussianLikelihoodFactor extends GaussianFactor
$messages = $this->getMessages(); $messages = $this->getMessages();
$vars = $this->getVariables(); $vars = $this->getVariables();
switch ($messageIndex) { return match ($messageIndex) {
case 0: 0 => $this->updateHelper($messages[0], $messages[1],
return $this->updateHelper($messages[0], $messages[1], $vars[0], $vars[1]),
$vars[0], $vars[1]); 1 => $this->updateHelper($messages[1], $messages[0],
case 1: $vars[1], $vars[0]),
return $this->updateHelper($messages[1], $messages[0], default => throw new Exception(),
$vars[1], $vars[0]); };
default:
throw new Exception();
}
} }
} }

@ -38,5 +38,6 @@ class GaussianPriorFactor extends GaussianFactor
$message->setValue($this->_newMessage); $message->setValue($this->_newMessage);
return GaussianDistribution::subtract($oldMarginal, $newMarginal); return GaussianDistribution::subtract($oldMarginal, $newMarginal);
} }
} }

@ -15,24 +15,22 @@ use DNW\Skills\Numerics\GaussianDistribution;
*/ */
class GaussianWeightedSumFactor extends GaussianFactor class GaussianWeightedSumFactor extends GaussianFactor
{ {
private $_variableIndexOrdersForWeights = []; private array $_variableIndexOrdersForWeights = [];
// This following is used for convenience, for example, the first entry is [0, 1, 2] // 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] // corresponding to v[0] = a1*v[1] + a2*v[2]
private $_weights; private array $_weights = [];
private $_weightsSquared; private array $_weightsSquared = [];
public function __construct(Variable $sumVariable, array $variablesToSum, array $variableWeights = null) public function __construct(Variable $sumVariable, array $variablesToSum, array $variableWeights = null)
{ {
parent::__construct(self::createName($sumVariable, $variablesToSum, $variableWeights)); parent::__construct(self::createName($sumVariable, $variablesToSum, $variableWeights));
$this->_weights = [];
$this->_weightsSquared = [];
// The first weights are a straightforward copy // The first weights are a straightforward copy
// v_0 = a_1*v_1 + a_2*v_2 + ... + a_n * v_n // v_0 = a_1*v_1 + a_2*v_2 + ... + a_n * v_n
$variableWeightsLength = count($variableWeights); $variableWeightsLength = count((array) $variableWeights);
$this->_weights[0] = array_fill(0, count($variableWeights), 0); $this->_weights[0] = array_fill(0, count((array) $variableWeights), 0);
for ($i = 0; $i < $variableWeightsLength; $i++) { for ($i = 0; $i < $variableWeightsLength; $i++) {
$weight = &$variableWeights[$i]; $weight = &$variableWeights[$i];
@ -48,7 +46,7 @@ class GaussianWeightedSumFactor extends GaussianFactor
$this->_variableIndexOrdersForWeights[0][] = $i; $this->_variableIndexOrdersForWeights[0][] = $i;
} }
$variableWeightsLength = count($variableWeights); $variableWeightsLength = count((array) $variableWeights);
// The rest move the variables around and divide out the constant. // The rest move the variables around and divide out the constant.
// For example: // For example:
@ -71,7 +69,7 @@ class GaussianWeightedSumFactor extends GaussianFactor
for ($currentWeightSourceIndex = 0; for ($currentWeightSourceIndex = 0;
$currentWeightSourceIndex < $variableWeightsLength; $currentWeightSourceIndex < $variableWeightsLength;
$currentWeightSourceIndex++) { $currentWeightSourceIndex++) {
if ($currentWeightSourceIndex == ($weightsIndex - 1)) { if ($currentWeightSourceIndex === $weightsIndex - 1) {
continue; continue;
} }
@ -98,7 +96,7 @@ class GaussianWeightedSumFactor extends GaussianFactor
} }
$currentWeights[$currentDestinationWeightIndex] = $finalWeight; $currentWeights[$currentDestinationWeightIndex] = $finalWeight;
$currentWeightsSquared[$currentDestinationWeightIndex] = BasicMath::square($finalWeight); $currentWeightsSquared[$currentDestinationWeightIndex] = BasicMath::square($finalWeight);
$variableIndices[count($variableWeights)] = 0; $variableIndices[count((array) $variableWeights)] = 0;
$this->_variableIndexOrdersForWeights[] = $variableIndices; $this->_variableIndexOrdersForWeights[] = $variableIndices;
$this->_weights[$weightsIndex] = $currentWeights; $this->_weights[$weightsIndex] = $currentWeights;
@ -121,7 +119,7 @@ class GaussianWeightedSumFactor extends GaussianFactor
$result = 0.0; $result = 0.0;
// We start at 1 since offset 0 has the sum // We start at 1 since offset 0 has the sum
$varCount = count($vars); $varCount = is_countable($vars) ? count($vars) : 0;
for ($i = 1; $i < $varCount; $i++) { for ($i = 1; $i < $varCount; $i++) {
$result += GaussianDistribution::logRatioNormalization($vars[$i]->getValue(), $messages[$i]->getValue()); $result += GaussianDistribution::logRatioNormalization($vars[$i]->getValue(), $messages[$i]->getValue());
} }
@ -167,7 +165,6 @@ class GaussianWeightedSumFactor extends GaussianFactor
$anotherNewPrecision = 1.0 / $anotherInverseOfNewPrecisionSum; $anotherNewPrecision = 1.0 / $anotherInverseOfNewPrecisionSum;
$newPrecisionMean = $newPrecision * $weightedMeanSum; $newPrecisionMean = $newPrecision * $weightedMeanSum;
$anotherNewPrecisionMean = $anotherNewPrecision * $anotherWeightedMeanSum;
$newMessage = GaussianDistribution::fromPrecisionMean($newPrecisionMean, $newPrecision); $newMessage = GaussianDistribution::fromPrecisionMean($newPrecisionMean, $newPrecision);
$oldMarginalWithoutMessage = GaussianDistribution::divide($marginal0, $message0); $oldMarginalWithoutMessage = GaussianDistribution::divide($marginal0, $message0);
@ -190,7 +187,7 @@ class GaussianWeightedSumFactor extends GaussianFactor
$allMessages = $this->getMessages(); $allMessages = $this->getMessages();
$allVariables = $this->getVariables(); $allVariables = $this->getVariables();
Guard::argumentIsValidIndex($messageIndex, count($allMessages), 'messageIndex'); Guard::argumentIsValidIndex($messageIndex, is_countable($allMessages) ? count($allMessages) : 0, 'messageIndex');
$updatedMessages = []; $updatedMessages = [];
$updatedVariables = []; $updatedVariables = [];
@ -200,7 +197,7 @@ class GaussianWeightedSumFactor extends GaussianFactor
// The tricky part here is that we have to put the messages and variables in the same // 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, // order as the weights. Thankfully, the weights and messages share the same index numbers,
// so we just need to make sure they're consistent // so we just need to make sure they're consistent
$allMessagesCount = count($allMessages); $allMessagesCount = is_countable($allMessages) ? count($allMessages) : 0;
for ($i = 0; $i < $allMessagesCount; $i++) { for ($i = 0; $i < $allMessagesCount; $i++) {
$updatedMessages[] = $allMessages[$indicesToUse[$i]]; $updatedMessages[] = $allMessages[$indicesToUse[$i]];
$updatedVariables[] = $allVariables[$indicesToUse[$i]]; $updatedVariables[] = $allVariables[$indicesToUse[$i]];
@ -218,7 +215,7 @@ class GaussianWeightedSumFactor extends GaussianFactor
$result = (string) $sumVariable; $result = (string) $sumVariable;
$result .= ' = '; $result .= ' = ';
$totalVars = count($variablesToSum); $totalVars = is_countable($variablesToSum) ? count($variablesToSum) : 0;
for ($i = 0; $i < $totalVars; $i++) { for ($i = 0; $i < $totalVars; $i++) {
$isFirst = ($i == 0); $isFirst = ($i == 0);
@ -232,7 +229,7 @@ class GaussianWeightedSumFactor extends GaussianFactor
$result .= (string) $variablesToSum[$i]; $result .= (string) $variablesToSum[$i];
$result .= ']'; $result .= ']';
$isLast = ($i == ($totalVars - 1)); $isLast = ($i === $totalVars - 1);
if (! $isLast) { if (! $isLast) {
if ($weights[$i + 1] >= 0) { if ($weights[$i + 1] >= 0) {

@ -11,26 +11,18 @@ use Exception;
// The whole purpose of this is to do a loop on the bottom // The whole purpose of this is to do a loop on the bottom
class IteratedTeamDifferencesInnerLayer extends TrueSkillFactorGraphLayer class IteratedTeamDifferencesInnerLayer extends TrueSkillFactorGraphLayer
{ {
private $_TeamDifferencesComparisonLayer;
private $_TeamPerformancesToTeamPerformanceDifferencesLayer;
public function __construct(TrueSkillFactorGraph $parentGraph, public function __construct(TrueSkillFactorGraph $parentGraph,
TeamPerformancesToTeamPerformanceDifferencesLayer $teamPerformancesToPerformanceDifferences, private readonly TeamPerformancesToTeamPerformanceDifferencesLayer $_TeamPerformancesToTeamPerformanceDifferencesLayer,
TeamDifferencesComparisonLayer $teamDifferencesComparisonLayer) private readonly TeamDifferencesComparisonLayer $_TeamDifferencesComparisonLayer)
{ {
parent::__construct($parentGraph); parent::__construct($parentGraph);
$this->_TeamPerformancesToTeamPerformanceDifferencesLayer = $teamPerformancesToPerformanceDifferences;
$this->_TeamDifferencesComparisonLayer = $teamDifferencesComparisonLayer;
} }
public function getLocalFactors() public function getLocalFactors()
{ {
$localFactors = array_merge($this->_TeamPerformancesToTeamPerformanceDifferencesLayer->getLocalFactors(), return array_merge($this->_TeamPerformancesToTeamPerformanceDifferencesLayer->getLocalFactors(),
$this->_TeamDifferencesComparisonLayer->getLocalFactors() $this->_TeamDifferencesComparisonLayer->getLocalFactors()
); );
return $localFactors;
} }
public function buildLayer() public function buildLayer()
@ -46,7 +38,7 @@ class IteratedTeamDifferencesInnerLayer extends TrueSkillFactorGraphLayer
public function createPriorSchedule() public function createPriorSchedule()
{ {
switch (count($this->getInputVariablesGroups())) { switch (is_countable($this->getInputVariablesGroups()) ? count($this->getInputVariablesGroups()) : 0) {
case 0: case 0:
case 1: case 1:
throw new Exception('InvalidOperation'); throw new Exception('InvalidOperation');
@ -59,15 +51,14 @@ class IteratedTeamDifferencesInnerLayer extends TrueSkillFactorGraphLayer
} }
// When dealing with differences, there are always (n-1) differences, so add in the 1 // When dealing with differences, there are always (n-1) differences, so add in the 1
$totalTeamDifferences = count($this->_TeamPerformancesToTeamPerformanceDifferencesLayer->getLocalFactors()); $totalTeamDifferences = is_countable($this->_TeamPerformancesToTeamPerformanceDifferencesLayer->getLocalFactors()) ? count($this->_TeamPerformancesToTeamPerformanceDifferencesLayer->getLocalFactors()) : 0;
$totalTeams = $totalTeamDifferences + 1;
$localFactors = $this->_TeamPerformancesToTeamPerformanceDifferencesLayer->getLocalFactors(); $localFactors = $this->_TeamPerformancesToTeamPerformanceDifferencesLayer->getLocalFactors();
$firstDifferencesFactor = $localFactors[0]; $firstDifferencesFactor = $localFactors[0];
$lastDifferencesFactor = $localFactors[$totalTeamDifferences - 1]; $lastDifferencesFactor = $localFactors[$totalTeamDifferences - 1];
$innerSchedule = new ScheduleSequence( return new ScheduleSequence(
'inner schedule', 'inner schedule',
[ [
$loop, $loop,
@ -79,8 +70,6 @@ class IteratedTeamDifferencesInnerLayer extends TrueSkillFactorGraphLayer
$lastDifferencesFactor, 2), $lastDifferencesFactor, 2),
] ]
); );
return $innerSchedule;
} }
private function createTwoTeamInnerPriorLoopSchedule() private function createTwoTeamInnerPriorLoopSchedule()
@ -108,7 +97,7 @@ class IteratedTeamDifferencesInnerLayer extends TrueSkillFactorGraphLayer
private function createMultipleTeamInnerPriorLoopSchedule() private function createMultipleTeamInnerPriorLoopSchedule()
{ {
$totalTeamDifferences = count($this->_TeamPerformancesToTeamPerformanceDifferencesLayer->getLocalFactors()); $totalTeamDifferences = is_countable($this->_TeamPerformancesToTeamPerformanceDifferencesLayer->getLocalFactors()) ? count($this->_TeamPerformancesToTeamPerformanceDifferencesLayer->getLocalFactors()) : 0;
$forwardScheduleList = []; $forwardScheduleList = [];
@ -173,11 +162,9 @@ class IteratedTeamDifferencesInnerLayer extends TrueSkillFactorGraphLayer
$initialMaxDelta = 0.0001; $initialMaxDelta = 0.0001;
$loop = new ScheduleLoop( return new ScheduleLoop(
sprintf('loop with max delta of %f', $initialMaxDelta), sprintf('loop with max delta of %f', $initialMaxDelta),
$forwardBackwardScheduleToLoop, $forwardBackwardScheduleToLoop,
$initialMaxDelta); $initialMaxDelta);
return $loop;
} }
} }

@ -9,11 +9,6 @@ use DNW\Skills\TrueSkill\TrueSkillFactorGraph;
class PlayerPerformancesToTeamPerformancesLayer extends TrueSkillFactorGraphLayer class PlayerPerformancesToTeamPerformancesLayer extends TrueSkillFactorGraphLayer
{ {
public function __construct(TrueSkillFactorGraph $parentGraph)
{
parent::__construct($parentGraph);
}
public function buildLayer() public function buildLayer()
{ {
$inputVariablesGroups = $this->getInputVariablesGroups(); $inputVariablesGroups = $this->getInputVariablesGroups();
@ -34,15 +29,11 @@ class PlayerPerformancesToTeamPerformancesLayer extends TrueSkillFactorGraphLaye
{ {
$localFactors = $this->getLocalFactors(); $localFactors = $this->getLocalFactors();
$sequence = $this->scheduleSequence( return $this->scheduleSequence(
array_map( array_map(
function ($weightedSumFactor) { fn($weightedSumFactor) => new ScheduleStep('Perf to Team Perf Step', $weightedSumFactor, 0),
return new ScheduleStep('Perf to Team Perf Step', $weightedSumFactor, 0);
},
$localFactors), $localFactors),
'all player perf to team perf schedule'); 'all player perf to team perf schedule');
return $sequence;
} }
protected function createPlayerToTeamSumFactor($teamMembers, $sumVariable) protected function createPlayerToTeamSumFactor($teamMembers, $sumVariable)
@ -79,13 +70,10 @@ class PlayerPerformancesToTeamPerformancesLayer extends TrueSkillFactorGraphLaye
private function createOutputVariable($team) private function createOutputVariable($team)
{ {
$memberNames = array_map(function ($currentPlayer) { $memberNames = array_map(fn($currentPlayer) => (string) ($currentPlayer->getKey()), $team);
return (string) ($currentPlayer->getKey());
}, $team);
$teamMemberNames = \implode(', ', $memberNames); $teamMemberNames = \implode(', ', $memberNames);
$outputVariable = $this->getParentFactorGraph()->getVariableFactory()->createBasicVariable('Team['.$teamMemberNames."]'s performance");
return $outputVariable; return $this->getParentFactorGraph()->getVariableFactory()->createBasicVariable('Team['.$teamMemberNames."]'s performance");
} }
} }

@ -13,12 +13,9 @@ use DNW\Skills\TrueSkill\TrueSkillFactorGraph;
// start the process. // start the process.
class PlayerPriorValuesToSkillsLayer extends TrueSkillFactorGraphLayer class PlayerPriorValuesToSkillsLayer extends TrueSkillFactorGraphLayer
{ {
private $_teams; public function __construct(TrueSkillFactorGraph $parentGraph, private readonly array $_teams)
public function __construct(TrueSkillFactorGraph $parentGraph, array $teams)
{ {
parent::__construct($parentGraph); parent::__construct($parentGraph);
$this->_teams = $teams;
} }
public function buildLayer() public function buildLayer()
@ -33,7 +30,7 @@ class PlayerPriorValuesToSkillsLayer extends TrueSkillFactorGraphLayer
$localCurrentTeamPlayer = $currentTeamPlayer; $localCurrentTeamPlayer = $currentTeamPlayer;
$currentTeamPlayerRating = $currentTeam->getRating($localCurrentTeamPlayer); $currentTeamPlayerRating = $currentTeam->getRating($localCurrentTeamPlayer);
$playerSkill = $this->createSkillOutputVariable($localCurrentTeamPlayer); $playerSkill = $this->createSkillOutputVariable($localCurrentTeamPlayer);
$priorFactor = $this->createPriorFactor($localCurrentTeamPlayer, $currentTeamPlayerRating, $playerSkill); $priorFactor = $this->createPriorFactor($currentTeamPlayerRating, $playerSkill);
$this->addLayerFactor($priorFactor); $this->addLayerFactor($priorFactor);
$currentTeamSkills[] = $playerSkill; $currentTeamSkills[] = $playerSkill;
} }
@ -49,14 +46,12 @@ class PlayerPriorValuesToSkillsLayer extends TrueSkillFactorGraphLayer
return $this->scheduleSequence( return $this->scheduleSequence(
array_map( array_map(
function ($prior) { fn($prior) => new ScheduleStep('Prior to Skill Step', $prior, 0),
return new ScheduleStep('Prior to Skill Step', $prior, 0);
},
$localFactors), $localFactors),
'All priors'); 'All priors');
} }
private function createPriorFactor($player, Rating $priorRating, Variable $skillsVariable) private function createPriorFactor(Rating $priorRating, Variable $skillsVariable)
{ {
return new GaussianPriorFactor( return new GaussianPriorFactor(
$priorRating->getMean(), $priorRating->getMean(),
@ -70,8 +65,7 @@ class PlayerPriorValuesToSkillsLayer extends TrueSkillFactorGraphLayer
{ {
$parentFactorGraph = $this->getParentFactorGraph(); $parentFactorGraph = $this->getParentFactorGraph();
$variableFactory = $parentFactorGraph->getVariableFactory(); $variableFactory = $parentFactorGraph->getVariableFactory();
$skillOutputVariable = $variableFactory->createKeyedVariable($key, $key."'s skill");
return $skillOutputVariable; return $variableFactory->createKeyedVariable($key, $key."'s skill");
} }
} }

@ -10,11 +10,6 @@ use DNW\Skills\TrueSkill\TrueSkillFactorGraph;
class PlayerSkillsToPerformancesLayer extends TrueSkillFactorGraphLayer class PlayerSkillsToPerformancesLayer extends TrueSkillFactorGraphLayer
{ {
public function __construct(TrueSkillFactorGraph $parentGraph)
{
parent::__construct($parentGraph);
}
public function buildLayer() public function buildLayer()
{ {
$inputVariablesGroups = $this->getInputVariablesGroups(); $inputVariablesGroups = $this->getInputVariablesGroups();
@ -47,9 +42,7 @@ class PlayerSkillsToPerformancesLayer extends TrueSkillFactorGraphLayer
private function createOutputVariable($key) private function createOutputVariable($key)
{ {
$outputVariable = $this->getParentFactorGraph()->getVariableFactory()->createKeyedVariable($key, $key."'s performance"); return $this->getParentFactorGraph()->getVariableFactory()->createKeyedVariable($key, $key."'s performance");
return $outputVariable;
} }
public function createPriorSchedule() public function createPriorSchedule()
@ -58,9 +51,7 @@ class PlayerSkillsToPerformancesLayer extends TrueSkillFactorGraphLayer
return $this->scheduleSequence( return $this->scheduleSequence(
array_map( array_map(
function ($likelihood) { fn($likelihood) => new ScheduleStep('Skill to Perf step', $likelihood, 0),
return new ScheduleStep('Skill to Perf step', $likelihood, 0);
},
$localFactors), $localFactors),
'All skill to performance sending'); 'All skill to performance sending');
} }
@ -71,9 +62,7 @@ class PlayerSkillsToPerformancesLayer extends TrueSkillFactorGraphLayer
return $this->scheduleSequence( return $this->scheduleSequence(
array_map( array_map(
function ($likelihood) { fn($likelihood) => new ScheduleStep('name', $likelihood, 1),
return new ScheduleStep('name', $likelihood, 1);
},
$localFactors), $localFactors),
'All skill to performance sending'); 'All skill to performance sending');
} }

@ -11,12 +11,9 @@ class TeamDifferencesComparisonLayer extends TrueSkillFactorGraphLayer
{ {
private $_epsilon; private $_epsilon;
private $_teamRanks; public function __construct(TrueSkillFactorGraph $parentGraph, private readonly array $_teamRanks)
public function __construct(TrueSkillFactorGraph $parentGraph, array $teamRanks)
{ {
parent::__construct($parentGraph); parent::__construct($parentGraph);
$this->_teamRanks = $teamRanks;
$gameInfo = $this->getParentFactorGraph()->getGameInfo(); $gameInfo = $this->getParentFactorGraph()->getGameInfo();
$this->_epsilon = DrawMargin::getDrawMarginFromDrawProbability($gameInfo->getDrawProbability(), $gameInfo->getBeta()); $this->_epsilon = DrawMargin::getDrawMarginFromDrawProbability($gameInfo->getDrawProbability(), $gameInfo->getBeta());
} }
@ -24,7 +21,7 @@ class TeamDifferencesComparisonLayer extends TrueSkillFactorGraphLayer
public function buildLayer() public function buildLayer()
{ {
$inputVarGroups = $this->getInputVariablesGroups(); $inputVarGroups = $this->getInputVariablesGroups();
$inputVarGroupsCount = count($inputVarGroups); $inputVarGroupsCount = is_countable($inputVarGroups) ? count($inputVarGroups) : 0;
for ($i = 0; $i < $inputVarGroupsCount; $i++) { for ($i = 0; $i < $inputVarGroupsCount; $i++) {
$isDraw = ($this->_teamRanks[$i] == $this->_teamRanks[$i + 1]); $isDraw = ($this->_teamRanks[$i] == $this->_teamRanks[$i + 1]);

@ -8,15 +8,10 @@ use DNW\Skills\TrueSkill\TrueSkillFactorGraph;
class TeamPerformancesToTeamPerformanceDifferencesLayer extends TrueSkillFactorGraphLayer class TeamPerformancesToTeamPerformanceDifferencesLayer extends TrueSkillFactorGraphLayer
{ {
public function __construct(TrueSkillFactorGraph $parentGraph)
{
parent::__construct($parentGraph);
}
public function buildLayer() public function buildLayer()
{ {
$inputVariablesGroups = $this->getInputVariablesGroups(); $inputVariablesGroups = $this->getInputVariablesGroups();
$inputVariablesGroupsCount = count($inputVariablesGroups); $inputVariablesGroupsCount = is_countable($inputVariablesGroups) ? count($inputVariablesGroups) : 0;
$outputVariablesGroup = &$this->getOutputVariablesGroups(); $outputVariablesGroup = &$this->getOutputVariablesGroups();
for ($i = 0; $i < $inputVariablesGroupsCount - 1; $i++) { for ($i = 0; $i < $inputVariablesGroupsCount - 1; $i++) {
@ -44,8 +39,6 @@ class TeamPerformancesToTeamPerformanceDifferencesLayer extends TrueSkillFactorG
private function createOutputVariable() private function createOutputVariable()
{ {
$outputVariable = $this->getParentFactorGraph()->getVariableFactory()->createBasicVariable('Team performance difference'); return $this->getParentFactorGraph()->getVariableFactory()->createBasicVariable('Team performance difference');
return $outputVariable;
} }
} }

@ -19,20 +19,15 @@ use DNW\Skills\TrueSkill\Layers\TeamPerformancesToTeamPerformanceDifferencesLaye
class TrueSkillFactorGraph extends FactorGraph class TrueSkillFactorGraph extends FactorGraph
{ {
private $_gameInfo;
private $_layers; private $_layers;
private $_priorLayer; private $_priorLayer;
public function __construct(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);
$this->_gameInfo = $gameInfo;
$newFactory = new VariableFactory( $newFactory = new VariableFactory(
function () { fn() => GaussianDistribution::fromPrecisionMean(0, 0));
return GaussianDistribution::fromPrecisionMean(0, 0);
});
$this->setVariableFactory($newFactory); $this->setVariableFactory($newFactory);
$this->_layers = [ $this->_layers = [
@ -70,7 +65,7 @@ class TrueSkillFactorGraph extends FactorGraph
public function runSchedule() public function runSchedule()
{ {
$fullSchedule = $this->createFullSchedule(); $fullSchedule = $this->createFullSchedule();
$fullScheduleDelta = $fullSchedule->visit(); $fullSchedule->visit();
} }
public function getProbabilityOfRanking() public function getProbabilityOfRanking()

@ -72,16 +72,12 @@ class TwoTeamTrueSkillCalculator extends SkillCalculator
$totalPlayers = $selfTeam->count() + $otherTeam->count(); $totalPlayers = $selfTeam->count() + $otherTeam->count();
$meanGetter = function ($currentRating) { $meanGetter = fn($currentRating) => $currentRating->getMean();
return $currentRating->getMean();
};
$selfMeanSum = BasicMath::sum($selfTeam->getAllRatings(), $meanGetter); $selfMeanSum = BasicMath::sum($selfTeam->getAllRatings(), $meanGetter);
$otherTeamMeanSum = BasicMath::sum($otherTeam->getAllRatings(), $meanGetter); $otherTeamMeanSum = BasicMath::sum($otherTeam->getAllRatings(), $meanGetter);
$varianceGetter = function ($currentRating) { $varianceGetter = fn($currentRating) => BasicMath::square($currentRating->getStandardDeviation());
return BasicMath::square($currentRating->getStandardDeviation());
};
$c = sqrt( $c = sqrt(
BasicMath::sum($selfTeam->getAllRatings(), $varianceGetter) BasicMath::sum($selfTeam->getAllRatings(), $varianceGetter)
@ -148,22 +144,18 @@ class TwoTeamTrueSkillCalculator extends SkillCalculator
// We've verified that there's just two teams // We've verified that there's just two teams
$team1Ratings = $teams[0]->getAllRatings(); $team1Ratings = $teams[0]->getAllRatings();
$team1Count = count($team1Ratings); $team1Count = is_countable($team1Ratings) ? count($team1Ratings) : 0;
$team2Ratings = $teams[1]->getAllRatings(); $team2Ratings = $teams[1]->getAllRatings();
$team2Count = count($team2Ratings); $team2Count = is_countable($team2Ratings) ? count($team2Ratings) : 0;
$totalPlayers = $team1Count + $team2Count; $totalPlayers = $team1Count + $team2Count;
$betaSquared = BasicMath::square($gameInfo->getBeta()); $betaSquared = BasicMath::square($gameInfo->getBeta());
$meanGetter = function ($currentRating) { $meanGetter = fn($currentRating) => $currentRating->getMean();
return $currentRating->getMean();
};
$varianceGetter = function ($currentRating) { $varianceGetter = fn($currentRating) => BasicMath::square($currentRating->getStandardDeviation());
return BasicMath::square($currentRating->getStandardDeviation());
};
$team1MeanSum = BasicMath::sum($team1Ratings, $meanGetter); $team1MeanSum = BasicMath::sum($team1Ratings, $meanGetter);
$team1StdDevSquared = BasicMath::sum($team1Ratings, $varianceGetter); $team1StdDevSquared = BasicMath::sum($team1Ratings, $varianceGetter);