mirror of
https://github.com/Karaka-Management/phpOMS.git
synced 2026-01-11 17:58:41 +00:00
replace \Closure with Callable
This commit is contained in:
parent
bc1cd635fe
commit
11b6f5f471
|
|
@ -35,10 +35,10 @@ final class Kmeans
|
|||
/**
|
||||
* Metric to calculate the distance between two points
|
||||
*
|
||||
* @var \Closure
|
||||
* @var Callable
|
||||
* @since 1.0.0
|
||||
*/
|
||||
private \Closure $metric;
|
||||
private Callable $metric;
|
||||
|
||||
/**
|
||||
* Points of the cluster centers
|
||||
|
|
@ -53,11 +53,11 @@ final class Kmeans
|
|||
*
|
||||
* @param PointInterface[] $points Points to cluster
|
||||
* @param int<0, max> $clusters Amount of clusters
|
||||
* @param null|\Closure $metric metric to use for the distance between two points
|
||||
* @param null|Callable $metric metric to use for the distance between two points
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function __construct(array $points, int $clusters, \Closure $metric = null)
|
||||
public function __construct(array $points, int $clusters, Callable $metric = null)
|
||||
{
|
||||
$this->metric = $metric ?? function (PointInterface $a, PointInterface $b) {
|
||||
$aCoordinates = $a->getCoordinates();
|
||||
|
|
|
|||
82
Algorithm/Rating/BradleyTerry.php
Normal file
82
Algorithm/Rating/BradleyTerry.php
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
<?php
|
||||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Algorithm\Rating
|
||||
* @copyright Dennis Eichhorn
|
||||
* @license OMS License 2.0
|
||||
* @version 1.0.0
|
||||
* @link https://jingga.app
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace phpOMS\Algorithm\Rating;
|
||||
|
||||
/**
|
||||
* Calculate rating strength using the Bradley Terry model
|
||||
*
|
||||
* @package phpOMS\Algorithm\Rating
|
||||
* @license OMS License 2.0
|
||||
* @link https://jingga.app
|
||||
* @since 1.0.0
|
||||
* @see https://en.wikipedia.org/wiki/Bradley%E2%80%93Terry_model
|
||||
*/
|
||||
final class BradleyTerry
|
||||
{
|
||||
public int $K = 32;
|
||||
|
||||
public int $DEFAULT_ELO = 1500;
|
||||
|
||||
public int $MIN_ELO = 100;
|
||||
|
||||
// history = matrix of past victories/performance against other teams (diagonal is empty)
|
||||
/**
|
||||
* @example rating(
|
||||
* [
|
||||
* 'A' => ['A' => 0, 'B' => 2, 'C' => 0, 'D' => 1],
|
||||
* 'B' => ['A' => 3, 'B' => 0, 'C' => 5, 'D' => 0],
|
||||
* 'C' => ['A' => 0, 'B' => 3, 'C' => 0, 'D' => 1],
|
||||
* 'D' => ['A' => 4, 'B' => 0, 'C' => 3, 'D' => 0],
|
||||
* ],
|
||||
* 20
|
||||
* ) // [0.139, 0.226, 0.143, 0.492]
|
||||
*/
|
||||
public function rating(array $history, int $iterations = 20) : array
|
||||
{
|
||||
$keys = \array_keys($history);
|
||||
$pOld = [];
|
||||
foreach ($keys as $key) {
|
||||
$pOld[$key] = 1;
|
||||
}
|
||||
|
||||
$p = $pOld;
|
||||
for ($i = 0; $i < $iterations; ++$i) {
|
||||
foreach ($history as $idx => $row) {
|
||||
$W = \array_sum($row);
|
||||
|
||||
$d = 0;
|
||||
foreach ($history as $idx2 => $_) {
|
||||
if ($idx === $idx2) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$d += ($history[$idx][$idx2] + $history[$idx2][$idx])
|
||||
/ ($pOld[$idx] + $pOld[$idx2]);
|
||||
}
|
||||
|
||||
$p[$idx] = $W / $d;
|
||||
}
|
||||
|
||||
$norm = \array_sum($p);
|
||||
foreach ($p as $idx => $_) {
|
||||
$p[$idx] /= $norm;
|
||||
}
|
||||
|
||||
$pOld = $p;
|
||||
}
|
||||
|
||||
return $p;
|
||||
}
|
||||
}
|
||||
48
Algorithm/Rating/Elo.php
Normal file
48
Algorithm/Rating/Elo.php
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
<?php
|
||||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Algorithm\Rating
|
||||
* @copyright Dennis Eichhorn
|
||||
* @license OMS License 2.0
|
||||
* @version 1.0.0
|
||||
* @link https://jingga.app
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace phpOMS\Algorithm\Rating;
|
||||
|
||||
/**
|
||||
* Elo rating calculation using Elo rating
|
||||
*
|
||||
* @package phpOMS\Algorithm\Rating
|
||||
* @license OMS License 2.0
|
||||
* @link https://jingga.app
|
||||
* @since 1.0.0
|
||||
* @see https://en.wikipedia.org/wiki/Elo_rating_system
|
||||
*/
|
||||
final class Elo
|
||||
{
|
||||
public int $K = 32;
|
||||
|
||||
public int $DEFAULT_ELO = 1500;
|
||||
|
||||
public int $MIN_ELO = 100;
|
||||
|
||||
public function rating(int $elo, array $oElo, array $s)
|
||||
{
|
||||
$eloNew = $elo;
|
||||
foreach ($oElo as $idx => $o) {
|
||||
$expected = 1 / (1 + 10 ** (($o - $elo) / 400));
|
||||
$r = $this->K * ($s[$idx] - $expected);
|
||||
|
||||
$eloNew += $r;
|
||||
}
|
||||
|
||||
return [
|
||||
'elo' => (int) \max((int) $eloNew, $this->MIN_ELO),
|
||||
];
|
||||
}
|
||||
}
|
||||
109
Algorithm/Rating/Glicko1.php
Normal file
109
Algorithm/Rating/Glicko1.php
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
<?php
|
||||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Algorithm\Rating
|
||||
* @copyright Dennis Eichhorn
|
||||
* @license OMS License 2.0
|
||||
* @version 1.0.0
|
||||
* @link https://jingga.app
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace phpOMS\Algorithm\Rating;
|
||||
|
||||
/**
|
||||
* Elo rating calculation using Glicko-1
|
||||
*
|
||||
* @package phpOMS\Algorithm\Rating
|
||||
* @license OMS License 2.0
|
||||
* @link https://jingga.app
|
||||
* @since 1.0.0
|
||||
* @see https://en.wikipedia.org/wiki/Glicko_rating_system
|
||||
* @see http://www.glicko.net/glicko/glicko.pdf
|
||||
*/
|
||||
final class Glicko1
|
||||
{
|
||||
public const Q = 0.00575646273; // ln(10) / 400
|
||||
|
||||
public int $DEFAULT_ELO = 1500;
|
||||
|
||||
public int $DEFAULT_RD = 350;
|
||||
|
||||
public float $DEFAULT_C = 34.6;
|
||||
|
||||
public int $MIN_ELO = 100;
|
||||
|
||||
public int $MIN_RD = 50;
|
||||
|
||||
/**
|
||||
* Calcualte the glicko-1 elo
|
||||
*
|
||||
* @param int $eloOld Old elo
|
||||
* @param int $rdOld Old deviation (50 === +/-100 elo points)
|
||||
* @param int $lastMatchDate Last match date used to calculate the time difference (can be days, months, ... depending on your match interval)
|
||||
* @param int $matchDate Match date (usually day)
|
||||
* @param float[] $s Match results (1 = victor, 0 = loss, 0.5 = draw)
|
||||
* @param int[] $oElo Opponent elo
|
||||
* @param int[] $oRd Opponent deviation
|
||||
*
|
||||
* @return array{elo:int, rd:int}
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function rating(
|
||||
int $eloOld = 1500,
|
||||
int $rdOld = 50,
|
||||
int $lastMatchDate = 0,
|
||||
int $matchDate = 0,
|
||||
array $s = [],
|
||||
array $oElo = [],
|
||||
array $oRd = []
|
||||
) : array
|
||||
{
|
||||
// Step 1:
|
||||
$s = [];
|
||||
$E = [];
|
||||
$gRD = [];
|
||||
|
||||
$RD = \min(
|
||||
350,
|
||||
\max(
|
||||
\sqrt(
|
||||
$rdOld * $rdOld
|
||||
+ $this->DEFAULT_C * $this->DEFAULT_C * \max(0, $matchDate - $lastMatchDate)
|
||||
),
|
||||
$this->MIN_RD
|
||||
)
|
||||
);
|
||||
|
||||
// Step 2:
|
||||
foreach ($oElo as $id => $e) {
|
||||
$gRD_t = 1 / (\sqrt(1 + 3 * self::Q * self::Q * $oRd[$id] * $oRd[$id] / (\M_PI * \M_PI)));
|
||||
$gRD[] = $gRD_t;
|
||||
$E[] = 1 / (1 + \pow(10, $gRD_t * ($eloOld - $e) / -400));
|
||||
}
|
||||
|
||||
$d = 0;
|
||||
foreach ($E as $id => $_) {
|
||||
$d += $gRD[$id] * $gRD[$id] * $E[$id] * (1 - $E[$id]);
|
||||
}
|
||||
$d2 = 1 / (self::Q * self::Q * $d);
|
||||
|
||||
$r = 0;
|
||||
foreach ($E as $id => $_) {
|
||||
$r += $gRD[$id] * ($s[$id] - $E[$id]);
|
||||
}
|
||||
$r = $eloOld + self::Q / (1 / ($RD * $RD) + 1 / $d2) * $r;
|
||||
|
||||
// Step 3:
|
||||
$RD_ = \sqrt(1 / (1 / ($RD * $RD) + 1 / $d2));
|
||||
|
||||
return [
|
||||
'elo' => (int) \max((int) $r, $this->MIN_ELO),
|
||||
'rd' => (int) \max($RD_, $this->MIN_RD)
|
||||
];
|
||||
}
|
||||
}
|
||||
118
Algorithm/Rating/Glicko2.php
Normal file
118
Algorithm/Rating/Glicko2.php
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
<?php
|
||||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Algorithm\Rating
|
||||
* @copyright Dennis Eichhorn
|
||||
* @license OMS License 2.0
|
||||
* @version 1.0.0
|
||||
* @link https://jingga.app
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace phpOMS\Algorithm\Rating;
|
||||
|
||||
use phpOMS\Math\Solver\Root\Bisection;
|
||||
|
||||
/**
|
||||
* Elo rating calculation using Glicko-2
|
||||
*
|
||||
* @package phpOMS\Algorithm\Rating
|
||||
* @license OMS License 2.0
|
||||
* @link https://jingga.app
|
||||
* @since 1.0.0
|
||||
* @see https://en.wikipedia.org/wiki/Glicko_rating_system
|
||||
* @see http://www.glicko.net/glicko/glicko2.pdf
|
||||
*
|
||||
* @todo: implement
|
||||
*/
|
||||
final class Glicko2
|
||||
{
|
||||
public float $tau = 0.5;
|
||||
|
||||
public int $DEFAULT_ELO = 1500;
|
||||
|
||||
public int $DEFAULT_RD = 350;
|
||||
|
||||
public float $DEFAULT_VOLATILITY = 0.06;
|
||||
|
||||
public int $MIN_ELO = 100;
|
||||
|
||||
public int $MIN_RD = 50;
|
||||
|
||||
/**
|
||||
* @example $glicko->elo(1500, 200, 0.06, [1,0,0], [1400,1550,1700], [30,100,300]) // 1464, 151, 0.059
|
||||
*/
|
||||
public function rating(
|
||||
int $eloOld = 1500,
|
||||
int $rdOld = 50,
|
||||
float $volOld = 0.06,
|
||||
array $s = [],
|
||||
array $oElo = [],
|
||||
array $oRd = []
|
||||
) : array
|
||||
{
|
||||
$tau = $this->tau;
|
||||
|
||||
// Step 0:
|
||||
$rdOld = $rdOld / 173.7178;
|
||||
$eloOld = ($eloOld - $this->DEFAULT_ELO) / 173.7178;
|
||||
|
||||
foreach ($oElo as $idx => $value) {
|
||||
$oElo[$idx] = ($value - $this->DEFAULT_ELO) / 173.7178;
|
||||
}
|
||||
|
||||
foreach ($oRd as $idx => $value) {
|
||||
$oRd[$idx] = $value / 173.7178;
|
||||
}
|
||||
|
||||
// Step 1:
|
||||
$g = [];
|
||||
foreach ($oRd as $rd) {
|
||||
$g[] = 1 / \sqrt(1 + 3 * $rd * $rd / (\M_PI * \M_PI));
|
||||
}
|
||||
|
||||
$E = [];
|
||||
foreach ($oElo as $idx => $elo) {
|
||||
$E[] = 1 / (1 + \exp(-$g[$idx] * ($eloOld - $elo)));
|
||||
}
|
||||
|
||||
$v = 0;
|
||||
foreach ($g as $idx => $t) {
|
||||
$v += $t * $t * $E[$idx] * (1 - $E[$idx]);
|
||||
}
|
||||
$v = 1 / $v;
|
||||
|
||||
$tDelta = 0;
|
||||
foreach ($g as $idx => $t) {
|
||||
$tDelta += $t * ($s[$idx] - $E[$idx]);
|
||||
}
|
||||
$Delta = $v * $tDelta;
|
||||
|
||||
// Step 2:
|
||||
$fn = function($x) use ($Delta, $rdOld, $v, $tau, $volOld)
|
||||
{
|
||||
return 0.5 * (\exp($x) * ($Delta ** 2 - $rdOld ** 2 - $v - \exp($x))) / (($rdOld ** 2 + $v + \exp($x)) ** 2)
|
||||
- ($x - \log($volOld ** 2)) / ($tau ** 2);
|
||||
};
|
||||
|
||||
$root = Bisection::bisection($fn, -100, 100, 1000);
|
||||
$vol = \exp($root / 2);
|
||||
|
||||
// Step 3:
|
||||
$RD = 1 / \sqrt(1 / ($rdOld ** 2 + $vol ** 2) + 1 / $v);
|
||||
$r = $eloOld + $RD ** 2 * $tDelta;
|
||||
|
||||
// Undo step 0:
|
||||
$RD = 173.7178 * $RD;
|
||||
$r = 173.7178 * $r + $this->DEFAULT_ELO;
|
||||
|
||||
return [
|
||||
'elo' => (int) \max($r, $this->MIN_ELO),
|
||||
'rd' => (int) \max($RD, $this->MIN_RD),
|
||||
'vol' => $vol,
|
||||
];
|
||||
}
|
||||
}
|
||||
234
Algorithm/Rating/TrueSkill.php
Normal file
234
Algorithm/Rating/TrueSkill.php
Normal file
|
|
@ -0,0 +1,234 @@
|
|||
<?php
|
||||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Algorithm\Rating
|
||||
* @copyright Microsoft
|
||||
* @license This algorithm may be patented by Microsoft, verify and acquire a license if necessary
|
||||
* @version 1.0.0
|
||||
* @link https://jingga.app
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace phpOMS\Algorithm\Rating;
|
||||
|
||||
use phpOMS\Math\Stochastic\Distribution\NormalDistribution;
|
||||
|
||||
/**
|
||||
* Elo rating calculation using Elo rating
|
||||
*
|
||||
* @package phpOMS\Algorithm\Rating
|
||||
* @license OMS License 2.0
|
||||
* @link https://jingga.app
|
||||
* @since 1.0.0
|
||||
* @see https://www.moserware.com/assets/computing-your-skill/The%20Math%20Behind%20TrueSkill.pdf
|
||||
*
|
||||
* @todo implement https://github.com/sublee/trueskill/blob/master/trueskill/__init__.py
|
||||
*/
|
||||
class TrueSkill
|
||||
{
|
||||
public int $DEFAULT_MU = 25;
|
||||
|
||||
public float $DEFAULT_SIGMA = 25 / 3;
|
||||
|
||||
public float $DEFAULT_BETA = 25 / 3 / 2;
|
||||
|
||||
public float $DEFAULT_TAU = 25 / 3 / 100;
|
||||
|
||||
public float $DEFAULT_DRAW_PROBABILITY = 0.1;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// Draw margin = epsilon
|
||||
/**
|
||||
* P_{draw} = 2\Phi\left(\dfrac{\epsilon}{\sqrt{n_1 + n_2} * \beta}\right) - 1
|
||||
*/
|
||||
public function drawProbability(float $drawMargin, int $n1, int $n2, float $beta)
|
||||
{
|
||||
return 2 * NormalDistribution::getCdf($drawMargin / (\sqrt($n1 + $n2) * $beta), 0.0, 1.0) - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* \epsilon = \Phi^{-1}\left(\dfrac{P_{draw} + 1}{2}\right) * \sqrt{n_1 + n_2} * \beta
|
||||
*/
|
||||
public function drawMargin(float $drawProbability, int $n1, int $n2, float $beta)
|
||||
{
|
||||
return NormalDistribution::getIcdf(($drawProbability + 1) / 2.0, 0.0, 1.0) * \sqrt($n1 + $n2) * $beta;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mean additive truncated gaussion function "v" for wins
|
||||
*
|
||||
* @latex c = \sqrt{2 * \beta^2 + \sigma_{winner}^2 + \sigma_{loser}^2}
|
||||
* @latex \mu_{winner} = \mu_{winner} + \dfrac{\sigma_{winner}^2}{c} * \nu \left(\dfrac{\mu_{winner} - \mu_{loser}}{c}, \dfrac{\epsilon}{c}\right)
|
||||
* @latex \mu_{loser} = \mu_{loser} + \dfrac{\sigma_{loser}^2}{c} * \nu \left(\dfrac{\mu_{winner} - \mu_{loser}}{c}, \dfrac{\epsilon}{c}\right)
|
||||
* @latex t = \dfrac{\mu_{winner} - \mu_{loser}}{c}
|
||||
*
|
||||
* @latex \nu = \dfrac{\mathcal{N}(t - \epsilon)}{\Phi(t - \epsilon)}
|
||||
*
|
||||
* @param float $t Difference winner and loser mu
|
||||
* @param float $epsilon Draw margin
|
||||
*
|
||||
* @return float
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
private function vWin(float $t, float $epsilon) : float
|
||||
{
|
||||
return NormalDistribution::getPdf($t - $epsilon, 0, 1.0) / NormalDistribution::getCdf($t - $epsilon, 0.0, 1.0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Mean additive truncated gaussion function "v" for draws
|
||||
*
|
||||
* @latex c = \sqrt{2 * \beta^2 + \sigma_{winner}^2 + \sigma_{loser}^2}
|
||||
* @latex \mu_{winner} = \mu_{winner} + \dfrac{\sigma_{winner}^2}{c} * \nu \left(\dfrac{\mu_{winner} - \mu_{loser}}{c}, \dfrac{\epsilon}{c}\right)
|
||||
* @latex \mu_{loser} = \mu_{loser} + \dfrac{\sigma_{loser}^2}{c} * \nu \left(\dfrac{\mu_{winner} - \mu_{loser}}{c}, \dfrac{\epsilon}{c}\right)
|
||||
* @latex t = \dfrac{\mu_{winner} - \mu_{loser}}{c}
|
||||
* @latex \dfrac{\mathcal{N}(t - \epsilon)}{\Phi(t - \epsilon)}
|
||||
*
|
||||
* @latex \nu = \dfrac{\mathcal{N}(-\epsilon - t) - \mathcal{N}(\epsilon - t)}{\Phi(\epsilon - t) - \Phi(-\epsilon - t)}
|
||||
*
|
||||
* @param float $t Difference winner and loser mu
|
||||
* @param float $epsilon Draw margin
|
||||
*
|
||||
* @return float
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
private function vDraw(float $t, float $epsilon) : float
|
||||
{
|
||||
$tAbs = \abs($t);
|
||||
$a = $epsilon - $tAbs;
|
||||
$b = -$epsilon - $tAbs;
|
||||
|
||||
$aPdf = NormalDistribution::getPdf($a, 0.0, 1.0);
|
||||
$bPdf = NormalDistribution::getPdf($b, 0.0, 1.0);
|
||||
$numer = $bPdf - $aPdf;
|
||||
|
||||
$aCdf = NormalDistribution::getCdf($a, 0.0, 1.0);
|
||||
$bCdf = NormalDistribution::getCdf($b, 0.0, 1.0);
|
||||
$denom = $aCdf - $bCdf;
|
||||
|
||||
return $numer / $denom;
|
||||
}
|
||||
|
||||
/**
|
||||
* Variance multiplicative function "w" for draws
|
||||
*
|
||||
* @latex w = \nu * (\nu + t - \epsilon)
|
||||
*
|
||||
* @param float $t Difference winner and loser mu
|
||||
* @param float $epsilon Draw margin
|
||||
*
|
||||
* @return float
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
private function wWin(float $t, float $epsilon) : float
|
||||
{
|
||||
$v = $this->vWin($t, $epsilon);
|
||||
|
||||
return $v * ($v + $t - $epsilon);
|
||||
}
|
||||
|
||||
/**
|
||||
* Variance multiplicative function "w" for draws
|
||||
*
|
||||
* @latex w = \nu^2 + \dfrac{(\epsilon - t) * \mathcal{N}(\epsilon - t) + (\epsilon + t) * \mathcal{N}(\epsilon + t)}{\Phi(\epsilon - t) - \Phi(-\epsilon - t)}
|
||||
*
|
||||
* @param float $t Difference winner and loser mu
|
||||
* @param float $epsilon Draw margin
|
||||
*
|
||||
* @return float
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
private function wDraw(float $t, float $epsilon) : float
|
||||
{
|
||||
$tAbs = \abs($t);
|
||||
|
||||
$v = $this->vDraw($t, $epsilon);
|
||||
|
||||
return $v * $v
|
||||
+ (($epsilon - $t) * NormalDistribution::getPdf($epsilon - $tAbs, 0.0, 1.0) + ($epsilon + $tAbs) * NormalDistribution::getPdf($epsilon + $tAbs, 0.0, 1.0))
|
||||
/ (NormalDistribution::getCdf($epsilon - $tAbs, 0.0, 1.0) - NormalDistribution::getCdf(-$epsilon - $tAbs, 0.0, 1.0));
|
||||
}
|
||||
|
||||
private function buildRatingLayer()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private function buildPerformanceLayer()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private function buildTeamPerformanceLayer()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private function buildTruncLayer()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private function factorGraphBuilders()
|
||||
{
|
||||
// Rating layer
|
||||
|
||||
// Performance layer
|
||||
|
||||
// Team Performance layer
|
||||
|
||||
// Trunc layer
|
||||
|
||||
return [
|
||||
'rating_layer' => $ratingLayer,
|
||||
'performance_layer' => $ratingLayer,
|
||||
'team_performance_layer' => $ratingLayer,
|
||||
'trunc_layer' => $ratingLayer,
|
||||
];
|
||||
}
|
||||
|
||||
public function rating()
|
||||
{
|
||||
// Start values
|
||||
$mu = 25;
|
||||
$sigma = $mu / 3;
|
||||
$beta = $sigma / 2;
|
||||
$tau = $sigma / 100;
|
||||
$Pdraw = 0.1;
|
||||
|
||||
$alpha = 0.25;
|
||||
|
||||
// Partial update
|
||||
$sigmaPartial = $sigmaOld * $sigmaNew / \sqrt($alpha * $sigmaOld * $sigmaOld - ($alpha - 1) * $sigmaNew * $sigmaNew);
|
||||
$muPartial = $muOld * ($alpha - 1) * $sigmaNew * $sigmaNew - $muNew * $alpha * $sigmaOld * $sigmaOld
|
||||
/ (($alpha - 1) * $sigmaNew * $sigmaNew - $alpha * $sigmaOld * $sigmaOld);
|
||||
|
||||
|
||||
// New
|
||||
$tau = $pi * $mu;
|
||||
|
||||
$P = NormalDistribution::getCdf(($s1 - $s2) / (\sqrt(2) * $beta));
|
||||
$Delta = $alpha * $beta * \sqrt($pi) * (($y + 1) / 2 - $P);
|
||||
|
||||
$K = NormalDistribution::getCdf();
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
$pi = 1 / ($sigma * $sigma);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -137,12 +137,12 @@ final class UpdateMapper extends DataMapperAbstract
|
|||
$id = \is_object($tValue) ? $this->updateOwnsOne($propertyName, $tValue) : $tValue;
|
||||
$value = $this->parseValue($column['type'], $id);
|
||||
|
||||
$query->set([$this->mapper::TABLE . '.' . $column['name'] => $value]);
|
||||
$query->set([$column['name'] => $value]);
|
||||
} elseif (isset($this->mapper::BELONGS_TO[$propertyName])) {
|
||||
$id = \is_object($tValue) ? $this->updateBelongsTo($propertyName, $tValue) : $tValue;
|
||||
$value = $this->parseValue($column['type'], $id);
|
||||
|
||||
$query->set([$this->mapper::TABLE . '.' . $column['name'] => $value]);
|
||||
$query->set([$column['name'] => $value]);
|
||||
} elseif ($column['name'] !== $this->mapper::PRIMARYFIELD) {
|
||||
if (\stripos($column['internal'], '/') !== false) {
|
||||
$path = \substr($column['internal'], \stripos($column['internal'], '/') + 1);
|
||||
|
|
@ -151,11 +151,14 @@ final class UpdateMapper extends DataMapperAbstract
|
|||
|
||||
$value = $this->parseValue($column['type'], $tValue);
|
||||
|
||||
$query->set([$this->mapper::TABLE . '.' . $column['name'] => $value]);
|
||||
$query->set([$column['name'] => $value]);
|
||||
}
|
||||
}
|
||||
|
||||
$sth = $this->db->con->prepare($query->toSql());
|
||||
// @todo:
|
||||
// @bug: Sqlite doesn't allow table_name.column_name in set queries for whatver reason.
|
||||
|
||||
$sth = $this->db->con->prepare($a = $query->toSql());
|
||||
if ($sth !== false) {
|
||||
$sth->execute();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ final class Dispatcher implements DispatcherInterface
|
|||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function dispatch(array | string | \Closure $controller, mixed ...$data) : array
|
||||
public function dispatch(array | string | Callable $controller, mixed ...$data) : array
|
||||
{
|
||||
$views = [];
|
||||
$data = \array_values($data);
|
||||
|
|
@ -165,14 +165,14 @@ final class Dispatcher implements DispatcherInterface
|
|||
/**
|
||||
* Dispatch closure.
|
||||
*
|
||||
* @param \Closure $controller Controller string
|
||||
* @param Callable $controller Controller string
|
||||
* @param null|array $data Data
|
||||
*
|
||||
* @return mixed
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
private function dispatchClosure(\Closure $controller, array $data = null) : mixed
|
||||
private function dispatchClosure(Callable $controller, array $data = null) : mixed
|
||||
{
|
||||
return $data === null ? $controller($this->app) : $controller($this->app, ...$data);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ interface DispatcherInterface
|
|||
/**
|
||||
* Dispatch controller.
|
||||
*
|
||||
* @param array|\Closure|string $controller Controller
|
||||
* @param array|Callable|string $controller Controller
|
||||
* @param mixed ...$data Data
|
||||
*
|
||||
* @return array Returns array of all dispatched results
|
||||
|
|
@ -36,5 +36,5 @@ interface DispatcherInterface
|
|||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function dispatch(array | string | \Closure $controller, mixed ...$data) : array;
|
||||
public function dispatch(array | string | Callable $controller, mixed ...$data) : array;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -70,9 +70,9 @@ final class EventManager implements \Countable
|
|||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function dispatch(array | string | \Closure $func, mixed ...$data) : array
|
||||
public function dispatch(array | string | Callable $func, mixed ...$data) : array
|
||||
{
|
||||
if (!($func instanceof \Closure)) {
|
||||
if (!\is_callable($func)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
|
|
@ -136,7 +136,7 @@ final class EventManager implements \Countable
|
|||
* Attach new event
|
||||
*
|
||||
* @param string $group Name of the event (unique)
|
||||
* @param string|\Closure $callback Callback or route for the event
|
||||
* @param string|Callable $callback Callback or route for the event
|
||||
* @param bool $remove Remove event after triggering it?
|
||||
* @param bool $reset Reset event after triggering it? Remove must be false!
|
||||
*
|
||||
|
|
@ -144,7 +144,7 @@ final class EventManager implements \Countable
|
|||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function attach(string $group, string | \Closure $callback, bool $remove = false, bool $reset = false) : bool
|
||||
public function attach(string $group, string | Callable $callback, bool $remove = false, bool $reset = false) : bool
|
||||
{
|
||||
if (!isset($this->callbacks[$group])) {
|
||||
$this->callbacks[$group] = ['remove' => $remove, 'reset' => $reset, 'callbacks' => []];
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user