This commit is contained in:
Dennis Eichhorn 2023-11-09 00:18:12 +00:00
parent 1675a82410
commit 9018cf5b57
5 changed files with 119 additions and 28 deletions

View File

@ -74,4 +74,37 @@ final class Elo
'elo' => (int) \max($eloNew, $this->MIN_ELO),
];
}
/**
* Calculate an approximated win probability based on elo points.
*
* @param int $elo1 Elo of the player we want to calculate the win probability for
* @param int $elo2 Opponent elo
* @param bool $draw Is a draw possible?
*
* @return float
*
* @since 1.0.0
*/
public function winProbability(int $elo1, int $elo2, bool $draw = false) : float
{
return $draw
? -1.0 // @todo: implement
: 1 / (1 + \pow(10, ($elo2 - $elo1) / 400));
}
/**
* Calculate an approximated draw probability based on elo points.
*
* @param int $elo1 Elo of the player we want to calculate the win probability for
* @param int $elo2 Opponent elo
*
* @return float
*
* @since 1.0.0
*/
public function drawProbability(int $elo1, int $elo2) : float
{
return -1.0; // @todo: implement
}
}

View File

@ -29,18 +29,58 @@ use phpOMS\Math\Stochastic\Distribution\NormalDistribution;
*/
class TrueSkill
{
public int $DEFAULT_MU = 25;
public const DEFAULT_MU = 25;
public float $DEFAULT_SIGMA = 25 / 3;
public const DEFAULT_SIGMA = 25 / 3;
public float $DEFAULT_BETA = 25 / 3 / 2;
public const DEFAULT_BETA = 25 / 3 / 2;
public float $DEFAULT_TAU = 25 / 3 / 100;
public const DEFAULT_TAU = 25 / 3 / 100;
public float $DEFAULT_DRAW_PROBABILITY = 0.1;
public const DEFAULT_DRAW_PROBABILITY = 0.1;
public function __construct()
private float $mu = 0.0;
private float $sigma = 0.0;
private float $beta = 0.0;
private float $tau = 0.0;
private float $drawProbability = 0.0;
public function __construct(
float $mu = null,
float $sigma = null,
float $beta = null,
float $tau = null,
float $drawProbability = null)
{
$this->mu = $mu ?? self::DEFAULT_MU;
$this->sigma = $sigma ?? self::DEFAULT_SIGMA;
$this->beta = $beta ?? self::DEFAULT_BETA;
$this->tau = $tau ?? self::DEFAULT_TAU;
$this->drawProbability = $drawProbability ?? self::DEFAULT_DRAW_PROBABILITY;
}
public function winProbability(array $team1, array $team2, float $drawMargin = 0.0)
{
$sigmaSum = 0.0;
$mu1 = 0.0;
foreach ($team1 as $player) {
$mu1 += $player->mu;
$sigmaSum += $player->sigma * $player->sigma;
}
$mu2 = 0.0;
foreach ($team2 as $player) {
$mu2 += $player->mu;
$sigmaSum += $player->sigma * $player->sigma;
}
$deltaMu = $mu1 - $mu2;
return NormalDistribution::getCdf(
($deltaMu - $drawMargin) / \sqrt((\count($team1) + \count($team2)) * ($this->beta * $this->beta) + $sigmaSum),
0,
1
);
}
// Draw margin = epsilon

View File

@ -82,9 +82,7 @@ class Matrix implements \ArrayAccess, \Iterator
$this->n = $n;
$this->m = $m;
for ($i = 0; $i < $m; ++$i) {
$this->matrix[$i] = \array_fill(0, $n, 0);
}
$this->matrix = \array_fill(0, $m, \array_fill(0, $n, 0));
}
/**
@ -492,7 +490,7 @@ class Matrix implements \ArrayAccess, \Iterator
$newMatrixArr = $this->matrix;
foreach ($newMatrixArr as $i => $vector) {
foreach ($vector as $j => $value) {
foreach ($vector as $j => $_) {
$newMatrixArr[$i][$j] += $scalar;
}
}
@ -542,24 +540,44 @@ class Matrix implements \ArrayAccess, \Iterator
}
$matrixArr = $matrix->toArray();
$newMatrix = new self($this->m, $nDim);
$newMatrixArr = $newMatrix->toArray();
$newMatrixArr = \array_fill(0, $this->m, \array_fill(0, $nDim, 0));
for ($i = 0; $i < $this->m; ++$i) { // Row of $this
for ($c = 0; $c < $nDim; ++$c) { // Column of $matrix
$temp = 0;
for ($j = 0; $j < $mDim; ++$j) { // Row of $matrix
$temp += ($this->matrix[$i][$j] ?? 0) * ($matrixArr[$j][$c] ?? 0);
if ($mDim > 10 || $nDim > 10) {
// Standard transposed for iteration over rows -> higher cache hit
$transposedMatrixArr = array();
for ($k = 0; $k < $mDim; ++$k) {
for ($j = 0; $j < $nDim; ++$j) {
$transposedMatrixArr[$k][$j] = $matrixArr[$j][$k];
}
}
$newMatrixArr[$i][$c] = $temp;
for ($i = 0; $i < $this->m; ++$i) {
for ($j = 0; $j < $this->n; ++$j) {
$temp = 0;
for ($k = 0; $k < $mDim; ++$k) {
$temp += $this->matrix[$i][$k] * $transposedMatrixArr[$i][$k];
}
$newMatrixArr[$i][$j] = $temp;
}
}
} else {
// Standard
for ($i = 0; $i < $this->m; ++$i) {
for ($j = 0; $j < $nDim; ++$j) {
$temp = 0;
for ($k = 0; $k < $mDim; ++$k) {
$temp += $this->matrix[$i][$k] * $matrixArr[$k][$j];
}
$newMatrixArr[$i][$j] = $temp;
}
}
}
$newMatrix->setMatrix($newMatrixArr); /* @phpstan-ignore-line */
return $newMatrix;
return self::fromArray($newMatrixArr);
}
/**

View File

@ -53,7 +53,7 @@ final class Vector extends Matrix
*/
public function setV(int $m, int | float $value) : void
{
parent::set($m , 0, $value);
$this->matrix[$m][0] = $value;
}
/**
@ -67,7 +67,7 @@ final class Vector extends Matrix
*/
public function getV(int $m) : int | float
{
return parent::get($m, 0);
return $this->matrix[$m][0];
}
/**
@ -82,7 +82,7 @@ final class Vector extends Matrix
public function setMatrixV(array $vector) : self
{
foreach ($vector as $key => $value) {
$this->setV($key, $value);
$this->matrix[$key][0] = $value;
}
return $this;
@ -194,9 +194,9 @@ final class Vector extends Matrix
public function cross3(self $vector) : self
{
$crossArray = [
$this->getV(1) * $vector->getV(2) - $this->getV(2) * $vector->getV(1),
$this->getV(2) * $vector->getV(0) - $this->getV(0) * $vector->getV(2),
$this->getV(0) * $vector->getV(1) - $this->getV(1) * $vector->getV(0),
$this->matrix[1][0] * $vector->matrix[2][0] - $this->matrix[2][0] * $vector->matrix[1][0],
$this->matrix[2][0] * $vector->matrix[0][0] - $this->matrix[0][0] * $vector->matrix[2][0],
$this->matrix[0][0] * $vector->matrix[1][0] - $this->matrix[1][0] * $vector->matrix[0][0],
];
return self::fromArray($crossArray);