mirror of
https://github.com/furyfire/trueskill.git
synced 2025-12-13 11:07:01 +01:00
Compare commits
18 Commits
5a414b8307
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 770c4dbcc6 | |||
| d7a60176bb | |||
| 60102910e3 | |||
| dd4ecff60a | |||
| 03a9a3987a | |||
| ec2e637315 | |||
| 1d06fa0b0a | |||
| a097fa7f71 | |||
| ad9d7f94de | |||
| 1725979b1c | |||
| ac7e3f5c2d | |||
| adc587ac0d | |||
| d729caac1f | |||
| bd9fccb87b | |||
| 55656b7889 | |||
| 38f332b223 | |||
| b38a9656eb | |||
| 3c617e9869 |
5
.gitignore
vendored
5
.gitignore
vendored
@@ -1,6 +1,5 @@
|
|||||||
.*/
|
vendor/
|
||||||
vendor
|
|
||||||
.*.cache/
|
.*.cache/
|
||||||
*.phar
|
|
||||||
.phpdoc/
|
.phpdoc/
|
||||||
output/
|
output/
|
||||||
|
tools/
|
||||||
12
.phive/phars.xml
Normal file
12
.phive/phars.xml
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<phive xmlns="https://phar.io/phive">
|
||||||
|
<phar name="phpmd" version="^2.15.0" installed="2.15.0" location="./tools/phpmd" copy="false"/>
|
||||||
|
<phar name="phpstan" version="^2.1.12" installed="2.1.32" location="./tools/phpstan" copy="false"/>
|
||||||
|
<phar name="psalm" version="^7.0.0-beta6" installed="7.0.0-beta11" location="./tools/psalm" copy="false"/>
|
||||||
|
<phar name="phpcs" version="^3.12.2" installed="3.13.5" location="./tools/phpcs" copy="false"/>
|
||||||
|
<phar name="phpcbf" version="^3.12.2" installed="3.13.5" location="./tools/phpcbf" copy="false"/>
|
||||||
|
<phar name="phpdocumentor" version="^3.7.1" installed="3.9.1" location="./tools/phpdocumentor" copy="false"/>
|
||||||
|
<phar name="phpbench" version="^1.4.1" installed="1.4.3" location="./tools/phpbench" copy="false"/>
|
||||||
|
<phar name="infection" version="^0.29.14" installed="0.29.14" location="./tools/infection" copy="false"/>
|
||||||
|
<phar name="phpunit" version="^12.1.3" installed="12.4.4" location="./tools/phpunit" copy="false"/>
|
||||||
|
</phive>
|
||||||
32
.phpcs.xml
32
.phpcs.xml
@@ -6,6 +6,11 @@
|
|||||||
<file>tests/</file>
|
<file>tests/</file>
|
||||||
<file>benchmark/</file>
|
<file>benchmark/</file>
|
||||||
|
|
||||||
|
<arg name="basepath" value="."/>
|
||||||
|
<arg name="colors"/>
|
||||||
|
<arg name="parallel" value="8"/>
|
||||||
|
<arg name="report" value="emacs"/>
|
||||||
|
<arg value="p"/>
|
||||||
|
|
||||||
<rule ref="PSR1">
|
<rule ref="PSR1">
|
||||||
<exclude name="Generic.Files.LineLength"/>
|
<exclude name="Generic.Files.LineLength"/>
|
||||||
@@ -18,23 +23,19 @@
|
|||||||
<exclude name="Generic.Files.LowercasedFilename.NotFound"/>
|
<exclude name="Generic.Files.LowercasedFilename.NotFound"/>
|
||||||
<exclude name="Generic.PHP.ClosingPHPTag.NotFound"/>
|
<exclude name="Generic.PHP.ClosingPHPTag.NotFound"/>
|
||||||
<exclude name="Generic.Files.EndFileNoNewline.Found"/>
|
<exclude name="Generic.Files.EndFileNoNewline.Found"/>
|
||||||
<exclude name="Generic.Files.EndFileNoNewline.Found"/>
|
|
||||||
<exclude name="Generic.Arrays.DisallowShortArraySyntax.Found"/>
|
<exclude name="Generic.Arrays.DisallowShortArraySyntax.Found"/>
|
||||||
<exclude name="Generic.Functions.OpeningFunctionBraceKernighanRitchie.BraceOnNewLine"/>
|
<exclude name="Generic.Functions.OpeningFunctionBraceKernighanRitchie.BraceOnNewLine"/>
|
||||||
<exclude name="Generic.Classes.OpeningBraceSameLine.BraceOnNewLine"/>
|
<exclude name="Generic.Classes.OpeningBraceSameLine.BraceOnNewLine"/>
|
||||||
<exclude name="Generic.PHP.LowerCaseConstant.Found"/>
|
<exclude name="Generic.PHP.LowerCaseConstant.Found"/>
|
||||||
<exclude name="Generic.Formatting.SpaceAfterCast"/>
|
|
||||||
<exclude name="Generic.Formatting.MultipleStatementAlignment.NotSameWarning"/>
|
<exclude name="Generic.Formatting.MultipleStatementAlignment.NotSameWarning"/>
|
||||||
<exclude name="Generic.Commenting.DocComment.MissingShort"/>
|
<exclude name="Generic.Commenting.DocComment.MissingShort"/>
|
||||||
<exclude name="Generic.NamingConventions.AbstractClassNamePrefix.Missing"/>
|
<exclude name="Generic.NamingConventions.AbstractClassNamePrefix.Missing"/>
|
||||||
<exclude name="Generic.CodeAnalysis.ForLoopWithTestFunctionCall.NotAllowed"/>
|
<exclude name="Generic.CodeAnalysis.ForLoopWithTestFunctionCall.NotAllowed"/>
|
||||||
<exclude name="Generic.NamingConventions.InterfaceNameSuffix.Missing"/>
|
<exclude name="Generic.NamingConventions.InterfaceNameSuffix.Missing"/>
|
||||||
<exclude name="Generic.Commenting.Todo.TaskFound"/>
|
|
||||||
<exclude name="Generic.CodeAnalysis.UnusedFunctionParameter.FoundInImplementedInterfaceAfterLastUse"/>
|
<exclude name="Generic.CodeAnalysis.UnusedFunctionParameter.FoundInImplementedInterfaceAfterLastUse"/>
|
||||||
<exclude name="Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClassAfterLastUsed"/>
|
<exclude name="Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClassAfterLastUsed"/>
|
||||||
<exclude name="Generic.CodeAnalysis.UnusedFunctionParameter.FoundInImplementedInterfaceAfterLastUsed"/>
|
<exclude name="Generic.CodeAnalysis.UnusedFunctionParameter.FoundInImplementedInterfaceAfterLastUsed"/>
|
||||||
<exclude name="Generic.Formatting.SpaceBeforeCast.NoSpace"/>
|
|
||||||
<exclude name="Generic.CodeAnalysis.UselessOverridingMethod.Found"/>
|
|
||||||
<exclude name="Squiz.Functions.MultiLineFunctionDeclaration.NewlineBeforeOpenBrace"/>
|
<exclude name="Squiz.Functions.MultiLineFunctionDeclaration.NewlineBeforeOpenBrace"/>
|
||||||
</rule>
|
</rule>
|
||||||
|
|
||||||
@@ -50,4 +51,25 @@
|
|||||||
</property>
|
</property>
|
||||||
</properties>
|
</properties>
|
||||||
</rule>
|
</rule>
|
||||||
|
|
||||||
|
<rule ref="Generic.Formatting.SpaceAfterCast">
|
||||||
|
<properties>
|
||||||
|
<property name="spacing" value="0"/>
|
||||||
|
</properties>
|
||||||
|
</rule>
|
||||||
|
|
||||||
|
<!-- Do not allow unreachable code. -->
|
||||||
|
<rule ref="Squiz.PHP.NonExecutableCode"/>
|
||||||
|
|
||||||
|
<!-- Do not allow ambiguous conditions. -->
|
||||||
|
<rule ref="Generic.CodeAnalysis.RequireExplicitBooleanOperatorPrecedence"/>
|
||||||
|
|
||||||
|
<!-- The testing bootstrap file uses string concats to stop IDEs seeing the class aliases -->
|
||||||
|
<rule ref="Generic.Strings.UnnecessaryStringConcat" />
|
||||||
|
|
||||||
|
<!-- This test file specifically *needs* Windows line endings for testing purposes. -->
|
||||||
|
<rule ref="Generic.Files.LineEndings.InvalidEOLChar" />
|
||||||
|
|
||||||
|
<!-- Avoid false positive with this sniff detecting itself -->
|
||||||
|
<rule ref="Generic.Commenting.Todo"/>
|
||||||
</ruleset>
|
</ruleset>
|
||||||
12
.phplint.yml
12
.phplint.yml
@@ -1,12 +0,0 @@
|
|||||||
path:
|
|
||||||
- src/
|
|
||||||
- tests/
|
|
||||||
- benchmark/
|
|
||||||
jobs: 10
|
|
||||||
extensions:
|
|
||||||
- php
|
|
||||||
exclude:
|
|
||||||
- vendor
|
|
||||||
warning: true
|
|
||||||
memory-limit: -1
|
|
||||||
log-junit: "output/lint.xml"
|
|
||||||
3
.vscode/settings.json
vendored
Normal file
3
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"php.version": "8.4"
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
---
|
---
|
||||||
title: README
|
title: README
|
||||||
|
lang: en
|
||||||
...
|
...
|
||||||
# PHP TrueSkill Implementation
|
# PHP TrueSkill Implementation
|
||||||
This is a PHP port of the Moserware.Skills project that's available at
|
This is a PHP port of the Moserware.Skills project that's available at
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ use DNW\Skills\Team;
|
|||||||
/**
|
/**
|
||||||
* Basic Benchmarks.
|
* Basic Benchmarks.
|
||||||
*/
|
*/
|
||||||
class BasicBench
|
final class BasicBench
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* To benchmark performance when using TwoPlayerTrueSkillCalculator
|
* To benchmark performance when using TwoPlayerTrueSkillCalculator
|
||||||
@@ -42,8 +42,10 @@ class BasicBench
|
|||||||
$team1 = new Team($p1, $newRatings->getRating($p1));
|
$team1 = new Team($p1, $newRatings->getRating($p1));
|
||||||
$team2 = new Team($p2, $newRatings->getRating($p2));
|
$team2 = new Team($p2, $newRatings->getRating($p2));
|
||||||
|
|
||||||
$newRatings->getRating($p1)->getConservativeRating();
|
ob_start();
|
||||||
$newRatings->getRating($p2)->getConservativeRating();
|
echo $newRatings->getRating($p1)->getConservativeRating();
|
||||||
|
echo $newRatings->getRating($p2)->getConservativeRating();
|
||||||
|
ob_clean();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,8 +75,10 @@ class BasicBench
|
|||||||
$team1 = new Team($p1, $newRatings->getRating($p1));
|
$team1 = new Team($p1, $newRatings->getRating($p1));
|
||||||
$team2 = new Team($p2, $newRatings->getRating($p2));
|
$team2 = new Team($p2, $newRatings->getRating($p2));
|
||||||
|
|
||||||
$newRatings->getRating($p1)->getConservativeRating();
|
ob_start();
|
||||||
$newRatings->getRating($p2)->getConservativeRating();
|
echo $newRatings->getRating($p1)->getConservativeRating();
|
||||||
|
echo $newRatings->getRating($p2)->getConservativeRating();
|
||||||
|
ob_clean();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -104,8 +108,10 @@ class BasicBench
|
|||||||
$team1 = new Team($p1, $newRatings->getRating($p1));
|
$team1 = new Team($p1, $newRatings->getRating($p1));
|
||||||
$team2 = new Team($p2, $newRatings->getRating($p2));
|
$team2 = new Team($p2, $newRatings->getRating($p2));
|
||||||
|
|
||||||
$newRatings->getRating($p1)->getConservativeRating();
|
ob_start();
|
||||||
$newRatings->getRating($p2)->getConservativeRating();
|
echo $newRatings->getRating($p1)->getConservativeRating();
|
||||||
|
echo $newRatings->getRating($p2)->getConservativeRating();
|
||||||
|
ob_clean();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -138,9 +144,11 @@ class BasicBench
|
|||||||
$team2 = new Team($p2, $newRatings->getRating($p2));
|
$team2 = new Team($p2, $newRatings->getRating($p2));
|
||||||
$team3 = new Team($p3, $newRatings->getRating($p3));
|
$team3 = new Team($p3, $newRatings->getRating($p3));
|
||||||
|
|
||||||
$newRatings->getRating($p1)->getConservativeRating();
|
ob_start();
|
||||||
$newRatings->getRating($p2)->getConservativeRating();
|
echo $newRatings->getRating($p1)->getConservativeRating();
|
||||||
$newRatings->getRating($p3)->getConservativeRating();
|
echo $newRatings->getRating($p2)->getConservativeRating();
|
||||||
|
echo $newRatings->getRating($p3)->getConservativeRating();
|
||||||
|
ob_clean();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,19 @@
|
|||||||
{
|
{
|
||||||
"name": "dnw/php-trueskill",
|
"name": "dnw/php-trueskill",
|
||||||
"description": "Trueskill implementation by Moserware updated for PHP 8.4",
|
"description": "Trueskill implementation by Moserware updated for PHP 8.4",
|
||||||
"keywords": ["trueskill", "matchmaking", "ranking", "skill", "elo"],
|
"keywords": [
|
||||||
|
"trueskill",
|
||||||
|
"matchmaking",
|
||||||
|
"ranking",
|
||||||
|
"skill",
|
||||||
|
"elo"
|
||||||
|
],
|
||||||
"require": {
|
"require": {
|
||||||
"php": "^8.4"
|
"php": "^8.4"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"phpstan/phpstan": "^1.0",
|
|
||||||
"vimeo/psalm": "dev-master",
|
|
||||||
"phpmetrics/phpmetrics": "^3.0-dev",
|
"phpmetrics/phpmetrics": "^3.0-dev",
|
||||||
"phpunit/phpunit": "^11.2",
|
"phpunit/phpunit": "^11.2",
|
||||||
"psalm/plugin-phpunit": "^0.18.4",
|
|
||||||
"rector/rector": "^1.0",
|
"rector/rector": "^1.0",
|
||||||
"league/csv": "^9.0"
|
"league/csv": "^9.0"
|
||||||
},
|
},
|
||||||
@@ -25,34 +28,36 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "phpunit",
|
"test": "tools/phpunit",
|
||||||
"document": "phpDocumentor",
|
"document": "tools/phpdocumentor",
|
||||||
"benchmark": "phpbench run --report=default --output=build-artifact",
|
"benchmark": "tools/phpbench run --report=default --output=build-artifact",
|
||||||
"metrics": "vendor/bin/phpmetrics --config=phpmetrics.yml",
|
"metrics": "phpmetrics --config=phpmetrics.yml",
|
||||||
"lint": [
|
"lint": [
|
||||||
"phplint",
|
"tools/phpcbf",
|
||||||
"phpcs",
|
"tools/phpcs",
|
||||||
"phpcbf src/ tests/ benchmark/ examples/",
|
"tools/phpmd src/,tests/,benchmark/,examples/ text phpmd.ruleset.xml"
|
||||||
"phpmd src/,tests/,benchmark/,examples/ text phpmd.ruleset.xml"
|
|
||||||
],
|
],
|
||||||
"analyze": [
|
"analyze": [
|
||||||
"@analyze-phpstan",
|
"@analyze-phpstan",
|
||||||
"@analyze-psalm",
|
"@analyze-psalm",
|
||||||
"@analyze-rector"
|
"@analyze-rector"
|
||||||
],
|
],
|
||||||
"analyze-phpstan":"vendor/bin/phpstan analyze --error-format=raw",
|
"analyze-phpstan": "tools/phpstan analyze --error-format=raw",
|
||||||
"analyze-psalm": "vendor/bin/psalm --no-cache --show-info=true",
|
"analyze-psalm": "tools/psalm --show-info=true",
|
||||||
"analyze-rector": "vendor/bin/rector --dry-run",
|
"analyze-rector": "rector --dry-run",
|
||||||
"html": [
|
"html": [
|
||||||
"pandoc -s README.md -o output/README.html",
|
"pandoc --verbose -s README.md -o output/README.html",
|
||||||
"pandoc -s docs/index.rst -o output/index.html"
|
"pandoc --verbose -f rst -s docs/index.rst -o output/index.html --metadata=lang:en",
|
||||||
|
"tools/phpcs --generator=MarkDown | pandoc --verbose -f markdown -s -o output/CodeStandard.html --metadata title='Code Standard' --metadata=lang:en"
|
||||||
],
|
],
|
||||||
"all": [
|
"all": [
|
||||||
"@test",
|
"@test",
|
||||||
"@lint",
|
"@lint",
|
||||||
"@analyze",
|
"@analyze",
|
||||||
|
"@document",
|
||||||
"@metrics",
|
"@metrics",
|
||||||
"@html"
|
"@html"
|
||||||
]
|
]
|
||||||
}
|
},
|
||||||
|
"type": "library"
|
||||||
}
|
}
|
||||||
|
|||||||
2786
composer.lock
generated
2786
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,7 @@
|
|||||||
|
=============
|
||||||
Documentation
|
Documentation
|
||||||
=============
|
=============
|
||||||
|
|
||||||
This is a PHP port of the Moserware.Skills project that's available at
|
This is a PHP port of the Moserware.Skills project that's available at
|
||||||
|
|
||||||
http://github.com/moserware/Skills
|
http://github.com/moserware/Skills
|
||||||
@@ -17,9 +19,9 @@ https://www.moserware.com/2010/03/computing-your-skill.html
|
|||||||
|
|
||||||
From Microsoft
|
From Microsoft
|
||||||
--------------
|
--------------
|
||||||
The TrueSkill ranking system is a skill based ranking system for Xbox Live(opens in new tab) developed at Microsoft Research(opens in new tab). The purpose of a ranking system is to both identify and track the skills of gamers in a game (mode) in order to be able to match them into competitive matches. TrueSkill has been used to rank and match players in many different games, from Halo 3 to Forza Motorsport 7(opens in new tab).
|
The TrueSkill ranking system is a skill based ranking system for Xbox Live developed at Microsoft Research. The purpose of a ranking system is to both identify and track the skills of gamers in a game (mode) in order to be able to match them into competitive matches. TrueSkill has been used to rank and match players in many different games, from Halo 3 to Forza Motorsport 7.
|
||||||
|
|
||||||
An improved version of the TrueSkill ranking system, named TrueSkill 2(opens in new tab), launched with Gears of War 4(opens in new tab) and was later incorporated into Halo 5(opens in new tab).
|
An improved version of the TrueSkill ranking system, named TrueSkill 2, launched with Gears of War 4 and was later incorporated into Halo 5.
|
||||||
|
|
||||||
The classic TrueSkill ranking system only uses the final standings of all teams in a match in order to update the skill estimates (ranks) of all players in the match. The TrueSkill 2 ranking system also uses the individual scores of players in order to weight the contribution of each player to each team. As a result, TrueSkill 2 is much faster at figuring out the skill of a new player.
|
The classic TrueSkill ranking system only uses the final standings of all teams in a match in order to update the skill estimates (ranks) of all players in the match. The TrueSkill 2 ranking system also uses the individual scores of players in order to weight the contribution of each player to each team. As a result, TrueSkill 2 is much faster at figuring out the skill of a new player.
|
||||||
|
|
||||||
@@ -33,11 +35,16 @@ Links
|
|||||||
* `Test report <test/index.html>`_
|
* `Test report <test/index.html>`_
|
||||||
* `Mutation testing <mutation/infection.html>`_
|
* `Mutation testing <mutation/infection.html>`_
|
||||||
* `Code metrics <metrics/index.html>`_
|
* `Code metrics <metrics/index.html>`_
|
||||||
|
* `Code Standard <CodeStandard.html>`_
|
||||||
|
* `Benchmark <benchmark.html>`_
|
||||||
|
|
||||||
|
|
||||||
Standard Tools
|
Standard Tools
|
||||||
--------------
|
--------------
|
||||||
* PHP8.3
|
* PHP8.4
|
||||||
|
|
||||||
|
Development Tools
|
||||||
|
-------------------
|
||||||
* PlantUML
|
* PlantUML
|
||||||
* GraphViz
|
* GraphViz
|
||||||
* Pandoc
|
* Pandoc
|
||||||
@@ -47,7 +54,5 @@ PHP Tools
|
|||||||
---------
|
---------
|
||||||
For development Composer and the following packages are used (Recommended as Phars installed via Phive)
|
For development Composer and the following packages are used (Recommended as Phars installed via Phive)
|
||||||
|
|
||||||
* sudo phive install -g composer phpdocumentor infection phpcs phpcbf phploc phpbench
|
|
||||||
* sudo phive install -g overtrue/phplint --force-accept-unsigned
|
|
||||||
* composer install
|
* composer install
|
||||||
* composer all
|
* composer all
|
||||||
@@ -11,13 +11,14 @@ use DNW\Skills\Team;
|
|||||||
use DNW\Skills\Teams;
|
use DNW\Skills\Teams;
|
||||||
|
|
||||||
//load the CSV document from a stream
|
//load the CSV document from a stream
|
||||||
$stream = fopen('motogp.csv', 'r');
|
$csv = Reader::createFromPath('motogp.csv', 'r');
|
||||||
$csv = Reader::createFromStream($stream);
|
|
||||||
$csv->setDelimiter(',');
|
$csv->setDelimiter(',');
|
||||||
$csv->setHeaderOffset(0);
|
$csv->setHeaderOffset(0);
|
||||||
|
$csv->setEscape('');
|
||||||
|
|
||||||
//build a statement
|
//build a statement
|
||||||
$stmt = Statement::create()->where(static fn (array $record): bool => $record['category'] == "MotoGP" || $record['category'] == "500cc");
|
$statement = new Statement();
|
||||||
|
$stmt = $statement->where(static fn (array $record): bool => $record['category'] == "MotoGP" || $record['category'] == "500cc");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var $riders Player[]
|
* @var $riders Player[]
|
||||||
|
|||||||
@@ -16,5 +16,5 @@
|
|||||||
</source>
|
</source>
|
||||||
</api>
|
</api>
|
||||||
</version>
|
</version>
|
||||||
<!--setting name="graphs.enabled" value="true"/-->
|
<setting name="graphs.enabled" value="true"/>
|
||||||
</phpdocumentor>
|
</phpdocumentor>
|
||||||
@@ -24,7 +24,7 @@ abstract class FactorGraphLayer
|
|||||||
*/
|
*/
|
||||||
private array $inputVariablesGroups = [];
|
private array $inputVariablesGroups = [];
|
||||||
|
|
||||||
protected function __construct(private readonly TrueSkillFactorGraph $parentFactorGraph)
|
public function __construct(private readonly TrueSkillFactorGraph $parentFactorGraph)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ namespace DNW\Skills\FactorGraphs;
|
|||||||
/**
|
/**
|
||||||
* Helper class for computing the factor graph's normalization constant.
|
* Helper class for computing the factor graph's normalization constant.
|
||||||
*/
|
*/
|
||||||
class FactorList
|
final class FactorList
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @var Factor[] $list
|
* @var Factor[] $list
|
||||||
@@ -31,11 +31,11 @@ class FactorList
|
|||||||
$numberOfMessages = $factor->getNumberOfMessages();
|
$numberOfMessages = $factor->getNumberOfMessages();
|
||||||
|
|
||||||
for ($j = 0; $j < $numberOfMessages; ++$j) {
|
for ($j = 0; $j < $numberOfMessages; ++$j) {
|
||||||
$sumLogZ += $factor->sendMessageIndex($j);
|
$sumLogZ += (float)$factor->sendMessageIndex($j);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$sumLogS = 0;
|
$sumLogS = 0.0;
|
||||||
|
|
||||||
foreach ($list as &$currentFactor) {
|
foreach ($list as &$currentFactor) {
|
||||||
$sumLogS += $currentFactor->getLogNormalization();
|
$sumLogS += $currentFactor->getLogNormalization();
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace DNW\Skills\FactorGraphs;
|
namespace DNW\Skills\FactorGraphs;
|
||||||
|
|
||||||
class KeyedVariable extends Variable
|
final class KeyedVariable extends Variable
|
||||||
{
|
{
|
||||||
public function __construct(private readonly mixed $key, mixed $prior)
|
public function __construct(private readonly mixed $key, mixed $prior)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ namespace DNW\Skills\FactorGraphs;
|
|||||||
|
|
||||||
use DNW\Skills\Numerics\GaussianDistribution;
|
use DNW\Skills\Numerics\GaussianDistribution;
|
||||||
|
|
||||||
class Message
|
final class Message
|
||||||
{
|
{
|
||||||
public function __construct(private GaussianDistribution $value)
|
public function __construct(private GaussianDistribution $value)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace DNW\Skills\FactorGraphs;
|
namespace DNW\Skills\FactorGraphs;
|
||||||
|
|
||||||
class ScheduleLoop extends Schedule
|
final class ScheduleLoop extends Schedule
|
||||||
{
|
{
|
||||||
public function __construct(private readonly Schedule $scheduleToLoop, private readonly float $maxDelta)
|
public function __construct(private readonly Schedule $scheduleToLoop, private readonly float $maxDelta)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace DNW\Skills\FactorGraphs;
|
namespace DNW\Skills\FactorGraphs;
|
||||||
|
|
||||||
class ScheduleSequence extends Schedule
|
final class ScheduleSequence extends Schedule
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @param Schedule[] $schedules
|
* @param Schedule[] $schedules
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace DNW\Skills\FactorGraphs;
|
namespace DNW\Skills\FactorGraphs;
|
||||||
|
|
||||||
class ScheduleStep extends Schedule
|
final class ScheduleStep extends Schedule
|
||||||
{
|
{
|
||||||
public function __construct(private readonly Factor $factor, private readonly int $index)
|
public function __construct(private readonly Factor $factor, private readonly int $index)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -4,9 +4,9 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace DNW\Skills\FactorGraphs;
|
namespace DNW\Skills\FactorGraphs;
|
||||||
|
|
||||||
class VariableFactory
|
final readonly class VariableFactory
|
||||||
{
|
{
|
||||||
public function __construct(private readonly \Closure $varPriorInitializer)
|
public function __construct(private \Closure $varPriorInitializer)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ namespace DNW\Skills;
|
|||||||
/**
|
/**
|
||||||
* Parameters about the game for calculating the TrueSkill.
|
* Parameters about the game for calculating the TrueSkill.
|
||||||
*/
|
*/
|
||||||
class GameInfo
|
final readonly class GameInfo
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Default initial mean / 6
|
* Default initial mean / 6
|
||||||
@@ -26,11 +26,11 @@ class GameInfo
|
|||||||
private const float DEFAULT_INITIAL_STANDARD_DEVIATION = 8.3333333333333333333333333333333;
|
private const float DEFAULT_INITIAL_STANDARD_DEVIATION = 8.3333333333333333333333333333333;
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private readonly float $initialMean = self::DEFAULT_INITIAL_MEAN,
|
private float $initialMean = self::DEFAULT_INITIAL_MEAN,
|
||||||
private readonly float $initialStdDev = self::DEFAULT_INITIAL_STANDARD_DEVIATION,
|
private float $initialStdDev = self::DEFAULT_INITIAL_STANDARD_DEVIATION,
|
||||||
private readonly float $beta = self::DEFAULT_BETA,
|
private float $beta = self::DEFAULT_BETA,
|
||||||
private readonly float $dynamicsFactor = self::DEFAULT_DYNAMICS_FACTOR,
|
private float $dynamicsFactor = self::DEFAULT_DYNAMICS_FACTOR,
|
||||||
private readonly float $drawProbability = self::DEFAULT_DRAW_PROBABILITY
|
private float $drawProbability = self::DEFAULT_DRAW_PROBABILITY
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ use Exception;
|
|||||||
*
|
*
|
||||||
* @see http://www.moserware.com/2008/01/borrowing-ideas-from-3-interesting.html
|
* @see http://www.moserware.com/2008/01/borrowing-ideas-from-3-interesting.html
|
||||||
*/
|
*/
|
||||||
class Guard
|
final class Guard
|
||||||
{
|
{
|
||||||
public static function argumentIsValidIndex(int $index, int $count, string $parameterName): void
|
public static function argumentIsValidIndex(int $index, int $count, string $parameterName): void
|
||||||
{
|
{
|
||||||
@@ -23,7 +23,7 @@ class Guard
|
|||||||
public static function argumentInRangeInclusive(float $value, float $min, float $max, string $parameterName): void
|
public static function argumentInRangeInclusive(float $value, float $min, float $max, string $parameterName): void
|
||||||
{
|
{
|
||||||
if (($value < $min) || ($value > $max)) {
|
if (($value < $min) || ($value > $max)) {
|
||||||
throw new Exception($parameterName . ' is not in the valid range [' . $min . ', ' . $max . ']');
|
throw new Exception($parameterName . ' is not in the valid range [' . (int)$min . ', ' . (int)$max . ']');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,15 +7,15 @@ namespace DNW\Skills;
|
|||||||
/**
|
/**
|
||||||
* Basic hashmap that supports object keys.
|
* Basic hashmap that supports object keys.
|
||||||
*/
|
*/
|
||||||
class HashMap
|
final class HashMap
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @var mixed[] $hashToValue
|
* @var mixed[] $hashToValue Store the hash to value mapping.
|
||||||
*/
|
*/
|
||||||
private array $hashToValue = [];
|
private array $hashToValue = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var mixed[] $hashToKey
|
* @var mixed[] $hashToKey Store the hash to original key mapping.
|
||||||
*/
|
*/
|
||||||
private array $hashToKey = [];
|
private array $hashToKey = [];
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ 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 BasicMath
|
final class BasicMath
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Squares the input (input^2 = input * input)
|
* Squares the input (input^2 = input * input)
|
||||||
@@ -27,7 +27,7 @@ class BasicMath
|
|||||||
/**
|
/**
|
||||||
* Sums the items in $itemsToSum
|
* Sums the items in $itemsToSum
|
||||||
*
|
*
|
||||||
* @param mixed[] $itemsToSum The items to sum,
|
* @param mixed[] $itemsToSum The items to sum.
|
||||||
* @param \Closure $callback The function to apply to each array element before summing.
|
* @param \Closure $callback The function to apply to each array element before summing.
|
||||||
*
|
*
|
||||||
* @return float The sum.
|
* @return float The sum.
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ 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
|
final class GaussianDistribution
|
||||||
{
|
{
|
||||||
private const float DEFAULT_STANDARD_DEVIATION = 1.0;
|
private const float DEFAULT_STANDARD_DEVIATION = 1.0;
|
||||||
|
|
||||||
@@ -34,8 +34,9 @@ class GaussianDistribution
|
|||||||
*/
|
*/
|
||||||
private const float M_LOG_SQRT_2_PI = 0.9189385332046727417803297364056176398613974736377834128171515404;
|
private const float M_LOG_SQRT_2_PI = 0.9189385332046727417803297364056176398613974736377834128171515404;
|
||||||
|
|
||||||
// precision and precisionMean are used because they make multiplying and dividing simpler
|
/**
|
||||||
// (see the accompanying math paper for more details)
|
* Precision and precisionMean are used because they make multiplying and dividing simpler.
|
||||||
|
*/
|
||||||
private float $precision = 1.0;
|
private float $precision = 1.0;
|
||||||
|
|
||||||
private float $precisionMean = 0.0;
|
private float $precisionMean = 0.0;
|
||||||
@@ -171,7 +172,7 @@ class GaussianDistribution
|
|||||||
$meanDifference = $numerator->mean - $denominator->mean;
|
$meanDifference = $numerator->mean - $denominator->mean;
|
||||||
|
|
||||||
return log($denominator->variance) + self::M_LOG_SQRT_2_PI - log($varianceDifference) / 2.0 +
|
return log($denominator->variance) + self::M_LOG_SQRT_2_PI - log($varianceDifference) / 2.0 +
|
||||||
BasicMath::square($meanDifference) / (2 * $varianceDifference);
|
BasicMath::square($meanDifference) / (2.0 * $varianceDifference);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function at(float $var, float $mean = 0.0, float $standardDeviation = 1.0): float
|
public static function at(float $var, float $mean = 0.0, float $standardDeviation = 1.0): float
|
||||||
@@ -182,7 +183,7 @@ class GaussianDistribution
|
|||||||
// stdDev * sqrt(2*pi)
|
// stdDev * sqrt(2*pi)
|
||||||
|
|
||||||
$multiplier = 1.0 / ($standardDeviation * self::M_SQRT_2_PI);
|
$multiplier = 1.0 / ($standardDeviation * self::M_SQRT_2_PI);
|
||||||
$expPart = exp((-1.0 * BasicMath::square($var - $mean)) / (2 * BasicMath::square($standardDeviation)));
|
$expPart = exp((-1.0 * BasicMath::square($var - $mean)) / (2.0 * BasicMath::square($standardDeviation)));
|
||||||
|
|
||||||
return $multiplier * $expPart;
|
return $multiplier * $expPart;
|
||||||
}
|
}
|
||||||
@@ -200,7 +201,7 @@ class GaussianDistribution
|
|||||||
$z = abs($var);
|
$z = abs($var);
|
||||||
|
|
||||||
$t = 2.0 / (2.0 + $z);
|
$t = 2.0 / (2.0 + $z);
|
||||||
$ty = 4 * $t - 2;
|
$ty = 4.0 * $t - 2.0;
|
||||||
|
|
||||||
$coefficients = [
|
$coefficients = [
|
||||||
-1.3026537197817094,
|
-1.3026537197817094,
|
||||||
@@ -259,8 +260,8 @@ class GaussianDistribution
|
|||||||
return 100;
|
return 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
$pp = ($p < 1.0) ? $p : 2 - $p;
|
$pp = ($p < 1.0) ? $p : 2.0 - $p;
|
||||||
$t = sqrt(-2 * log($pp / 2.0)); // Initial guess
|
$t = sqrt(-2.0 * log($pp / 2.0)); // Initial guess
|
||||||
$x = -M_SQRT1_2 * ((2.30753 + $t * 0.27061) / (1.0 + $t * (0.99229 + $t * 0.04481)) - $t);
|
$x = -M_SQRT1_2 * ((2.30753 + $t * 0.27061) / (1.0 + $t * (0.99229 + $t * 0.04481)) - $t);
|
||||||
|
|
||||||
for ($j = 0; $j < 2; ++$j) {
|
for ($j = 0; $j < 2; ++$j) {
|
||||||
@@ -274,6 +275,6 @@ class GaussianDistribution
|
|||||||
public static function inverseCumulativeTo(float $var, float $mean = 0.0, float $standardDeviation = 1.0): float
|
public static function inverseCumulativeTo(float $var, float $mean = 0.0, float $standardDeviation = 1.0): float
|
||||||
{
|
{
|
||||||
// From numerical recipes, page 320
|
// From numerical recipes, page 320
|
||||||
return $mean - M_SQRT2 * $standardDeviation * GaussianDistribution::inverseErrorFunctionCumulativeTo(2 * $var);
|
return $mean - M_SQRT2 * $standardDeviation * GaussianDistribution::inverseErrorFunctionCumulativeTo(2.0 * $var);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace DNW\Skills\Numerics;
|
namespace DNW\Skills\Numerics;
|
||||||
|
|
||||||
class IdentityMatrix extends DiagonalMatrix
|
final class IdentityMatrix extends DiagonalMatrix
|
||||||
{
|
{
|
||||||
public function __construct(int $rows)
|
public function __construct(int $rows)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ class Matrix
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getValue(int $row, int $col): float|int
|
public function getValue(int $row, int $col): float
|
||||||
{
|
{
|
||||||
$this->checkRowCol($row, $col);
|
$this->checkRowCol($row, $col);
|
||||||
return $this->matrixRowData[$row][$col];
|
return $this->matrixRowData[$row][$col];
|
||||||
@@ -212,7 +212,7 @@ class Matrix
|
|||||||
return self::scalarMultiply($determinantInverse, $adjugate);
|
return self::scalarMultiply($determinantInverse, $adjugate);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function scalarMultiply(float|int $scalarValue, Matrix $matrix): Matrix
|
public static function scalarMultiply(float $scalarValue, Matrix $matrix): Matrix
|
||||||
{
|
{
|
||||||
$rows = $matrix->getRowCount();
|
$rows = $matrix->getRowCount();
|
||||||
$columns = $matrix->getColumnCount();
|
$columns = $matrix->getColumnCount();
|
||||||
@@ -265,7 +265,7 @@ class Matrix
|
|||||||
|
|
||||||
for ($currentRow = 0; $currentRow < $resultRows; ++$currentRow) {
|
for ($currentRow = 0; $currentRow < $resultRows; ++$currentRow) {
|
||||||
for ($currentColumn = 0; $currentColumn < $resultColumns; ++$currentColumn) {
|
for ($currentColumn = 0; $currentColumn < $resultColumns; ++$currentColumn) {
|
||||||
$productValue = 0;
|
$productValue = 0.0;
|
||||||
|
|
||||||
for ($vectorIndex = 0; $vectorIndex < $left->getColumnCount(); ++$vectorIndex) {
|
for ($vectorIndex = 0; $vectorIndex < $left->getColumnCount(); ++$vectorIndex) {
|
||||||
$leftValue = $left->getValue($currentRow, $vectorIndex);
|
$leftValue = $left->getValue($currentRow, $vectorIndex);
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace DNW\Skills\Numerics;
|
namespace DNW\Skills\Numerics;
|
||||||
|
|
||||||
class SquareMatrix extends Matrix
|
final class SquareMatrix extends Matrix
|
||||||
{
|
{
|
||||||
public function __construct(float|int ...$allValues)
|
public function __construct(float|int ...$allValues)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace DNW\Skills\Numerics;
|
namespace DNW\Skills\Numerics;
|
||||||
|
|
||||||
class Vector extends Matrix
|
final class Vector extends Matrix
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @param float[] $vectorValues
|
* @param float[] $vectorValues
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace DNW\Skills;
|
namespace DNW\Skills;
|
||||||
|
|
||||||
class PartialPlay
|
final class PartialPlay
|
||||||
{
|
{
|
||||||
public static function getPartialPlayPercentage(Player $player): float
|
public static function getPartialPlayPercentage(Player $player): float
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -7,25 +7,31 @@ namespace DNW\Skills;
|
|||||||
/**
|
/**
|
||||||
* Represents a player who has a Rating.
|
* Represents a player who has a Rating.
|
||||||
*/
|
*/
|
||||||
class Player implements ISupportPartialPlay, ISupportPartialUpdate
|
final readonly class Player implements ISupportPartialPlay, ISupportPartialUpdate
|
||||||
{
|
{
|
||||||
private const float DEFAULT_PARTIAL_PLAY_PERCENTAGE = 1.0; // = 100% play time
|
private const float DEFAULT_PARTIAL_PLAY_PERCENTAGE = 1.0; // = 100% play time
|
||||||
|
|
||||||
private const float DEFAULT_PARTIAL_UPDATE_PERCENTAGE = 1.0;
|
private const float DEFAULT_PARTIAL_UPDATE_PERCENTAGE = 1.0;
|
||||||
|
|
||||||
private readonly float $PartialPlayPct;
|
/**
|
||||||
|
* @var float The weight percentage to give this player when calculating a new rank.
|
||||||
|
*/
|
||||||
|
private float $PartialPlayPct;
|
||||||
|
|
||||||
private readonly float $PartialUpdatePct;
|
/**
|
||||||
|
* @var float Indicated how much of a skill update a player should receive where 0 represents no update and 1.0 represents 100% of the update.
|
||||||
|
*/
|
||||||
|
private float $PartialUpdatePct;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a player.
|
* Constructs a player.
|
||||||
*
|
*
|
||||||
* @param string|int $Id The identifier for the player, such as a name.
|
* @param string|int $Id The identifier for the player, such as a name.
|
||||||
* @param float $partialPlayPct The weight percentage to give this player when calculating a new rank.
|
* @param float $partialPlayPct The weight percentage to give this player when calculating a new rank.
|
||||||
* @param float $partialUpdatePct 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 float $partialUpdatePct 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(
|
public function __construct(
|
||||||
private readonly mixed $Id,
|
private mixed $Id,
|
||||||
float $partialPlayPct = self::DEFAULT_PARTIAL_PLAY_PERCENTAGE,
|
float $partialPlayPct = self::DEFAULT_PARTIAL_PLAY_PERCENTAGE,
|
||||||
float $partialUpdatePct = self::DEFAULT_PARTIAL_UPDATE_PERCENTAGE
|
float $partialUpdatePct = self::DEFAULT_PARTIAL_UPDATE_PERCENTAGE
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -6,6 +6,6 @@ namespace DNW\Skills;
|
|||||||
|
|
||||||
use DNW\Skills\Numerics\Range;
|
use DNW\Skills\Numerics\Range;
|
||||||
|
|
||||||
class PlayersRange extends Range
|
final class PlayersRange extends Range
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ namespace DNW\Skills;
|
|||||||
/**
|
/**
|
||||||
* Helper class to sort ranks in non-decreasing order.
|
* Helper class to sort ranks in non-decreasing order.
|
||||||
*/
|
*/
|
||||||
class RankSorter
|
final class RankSorter
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Performs an in-place sort of the items in according to the ranks in non-decreasing order.
|
* Performs an in-place sort of the items in according to the ranks in non-decreasing order.
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ use DNW\Skills\Numerics\GaussianDistribution;
|
|||||||
/**
|
/**
|
||||||
* Container for a player's rating.
|
* Container for a player's rating.
|
||||||
*/
|
*/
|
||||||
class Rating
|
final readonly class Rating
|
||||||
{
|
{
|
||||||
private const float CONSERVATIVE_STANDARD_DEVIATION_MULTIPLIER = 3;
|
private const float CONSERVATIVE_STANDARD_DEVIATION_MULTIPLIER = 3;
|
||||||
|
|
||||||
@@ -18,9 +18,9 @@ class 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 $conservativeStandardDeviationMultiplier optional The number of standardDeviations to subtract from the mean to achieve a conservative rating.
|
||||||
*/
|
*/
|
||||||
public function __construct(private readonly float $mean, private readonly float $standardDeviation, private readonly float|int $conservativeStandardDeviationMultiplier = self::CONSERVATIVE_STANDARD_DEVIATION_MULTIPLIER)
|
public function __construct(private float $mean, private float $standardDeviation, private float $conservativeStandardDeviationMultiplier = self::CONSERVATIVE_STANDARD_DEVIATION_MULTIPLIER)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,9 @@ namespace DNW\Skills;
|
|||||||
|
|
||||||
class RatingContainer
|
class RatingContainer
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* Link Player to a Rating using a hash map.
|
||||||
|
*/
|
||||||
private readonly HashMap $playerToRating;
|
private readonly HashMap $playerToRating;
|
||||||
|
|
||||||
public function __construct()
|
public function __construct()
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace DNW\Skills;
|
namespace DNW\Skills;
|
||||||
|
|
||||||
class Team extends RatingContainer
|
final class Team extends RatingContainer
|
||||||
{
|
{
|
||||||
public function __construct(?Player $player = NULL, ?Rating $rating = NULL)
|
public function __construct(?Player $player = NULL, ?Rating $rating = NULL)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -6,6 +6,6 @@ namespace DNW\Skills;
|
|||||||
|
|
||||||
use DNW\Skills\Numerics\Range;
|
use DNW\Skills\Numerics\Range;
|
||||||
|
|
||||||
class TeamsRange extends Range
|
final class TeamsRange extends Range
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,6 @@ final class DrawMargin
|
|||||||
//
|
//
|
||||||
// margin = inversecdf((draw probability + 1)/2) * sqrt(n1+n2) * beta
|
// margin = inversecdf((draw probability + 1)/2) * sqrt(n1+n2) * beta
|
||||||
// n1 and n2 are the number of players on each team
|
// n1 and n2 are the number of players on each team
|
||||||
return GaussianDistribution::inverseCumulativeTo(.5 * ($drawProbability + 1), 0, 1) * M_SQRT2 * $beta;
|
return GaussianDistribution::inverseCumulativeTo(0.5 * ($drawProbability + 1.0), 0.0, 1.0) * M_SQRT2 * $beta;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ use DNW\Skills\Rating;
|
|||||||
/**
|
/**
|
||||||
* Calculates TrueSkill using a full factor graph.
|
* Calculates TrueSkill using a full factor graph.
|
||||||
*/
|
*/
|
||||||
class FactorGraphTrueSkillCalculator extends SkillCalculator
|
final class FactorGraphTrueSkillCalculator extends SkillCalculator
|
||||||
{
|
{
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
@@ -192,7 +192,7 @@ class FactorGraphTrueSkillCalculator extends SkillCalculator
|
|||||||
$nextTeam = $teamAssignmentsList[$i + 1];
|
$nextTeam = $teamAssignmentsList[$i + 1];
|
||||||
foreach ($nextTeam->getAllPlayers() as $nextTeamPlayer) {
|
foreach ($nextTeam->getAllPlayers() as $nextTeamPlayer) {
|
||||||
// Add a -1 * playing time to represent the difference
|
// Add a -1 * playing time to represent the difference
|
||||||
$playerAssignments[$currentColumn][] = -1 * PartialPlay::getPartialPlayPercentage($nextTeamPlayer);
|
$playerAssignments[$currentColumn][] = -1.0 * PartialPlay::getPartialPlayPercentage($nextTeamPlayer);
|
||||||
--$rowsRemaining;
|
--$rowsRemaining;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ use DNW\Skills\TrueSkill\TruncatedGaussianCorrectionFunctions;
|
|||||||
*
|
*
|
||||||
* See the accompanying math paper for more details.
|
* See the accompanying math paper for more details.
|
||||||
*/
|
*/
|
||||||
class GaussianGreaterThanFactor extends GaussianFactor
|
final class GaussianGreaterThanFactor extends GaussianFactor
|
||||||
{
|
{
|
||||||
public function __construct(private readonly float $epsilon, Variable $variable)
|
public function __construct(private readonly float $epsilon, Variable $variable)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ use Exception;
|
|||||||
*
|
*
|
||||||
* See the accompanying math paper for more details.
|
* See the accompanying math paper for more details.
|
||||||
*/
|
*/
|
||||||
class GaussianLikelihoodFactor extends GaussianFactor
|
final class GaussianLikelihoodFactor extends GaussianFactor
|
||||||
{
|
{
|
||||||
private readonly float $precision;
|
private readonly float $precision;
|
||||||
|
|
||||||
@@ -32,7 +32,7 @@ class GaussianLikelihoodFactor extends GaussianFactor
|
|||||||
public function getLogNormalization(): float
|
public function getLogNormalization(): float
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @var KeyedVariable[]|mixed $vars
|
* @var KeyedVariable[] $vars
|
||||||
*/
|
*/
|
||||||
$vars = $this->getVariables();
|
$vars = $this->getVariables();
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ use DNW\Skills\Numerics\GaussianDistribution;
|
|||||||
*
|
*
|
||||||
* See the accompanying math paper for more details.
|
* See the accompanying math paper for more details.
|
||||||
*/
|
*/
|
||||||
class GaussianPriorFactor extends GaussianFactor
|
final class GaussianPriorFactor extends GaussianFactor
|
||||||
{
|
{
|
||||||
private readonly GaussianDistribution $newMessage;
|
private readonly GaussianDistribution $newMessage;
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ use DNW\Skills\Numerics\GaussianDistribution;
|
|||||||
*
|
*
|
||||||
* See the accompanying math paper for more details.
|
* See the accompanying math paper for more details.
|
||||||
*/
|
*/
|
||||||
class GaussianWeightedSumFactor extends GaussianFactor
|
final class GaussianWeightedSumFactor extends GaussianFactor
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @var array<int[]> $varIndexOrdersForWeights
|
* @var array<int[]> $varIndexOrdersForWeights
|
||||||
@@ -72,12 +72,12 @@ class GaussianWeightedSumFactor extends GaussianFactor
|
|||||||
|
|
||||||
$weightsLength = $variableWeightsLength + 1;
|
$weightsLength = $variableWeightsLength + 1;
|
||||||
for ($weightsIndex = 1; $weightsIndex < $weightsLength; ++$weightsIndex) {
|
for ($weightsIndex = 1; $weightsIndex < $weightsLength; ++$weightsIndex) {
|
||||||
$currentWeights = \array_fill(0, $variableWeightsLength, 0);
|
$currentWeights = \array_fill(0, $variableWeightsLength, 0.0);
|
||||||
|
|
||||||
$variableIndices = \array_fill(0, $variableWeightsLength + 1, 0);
|
$variableIndices = \array_fill(0, $variableWeightsLength + 1, 0.0);
|
||||||
$variableIndices[0] = $weightsIndex;
|
$variableIndices[0] = $weightsIndex;
|
||||||
|
|
||||||
$currentWeightsSquared = \array_fill(0, $variableWeightsLength, 0);
|
$currentWeightsSquared = \array_fill(0, $variableWeightsLength, 0.0);
|
||||||
|
|
||||||
// keep a single variable to keep track of where we are in the array.
|
// keep a single variable to keep track of where we are in the array.
|
||||||
// This is helpful since we skip over one of the spots
|
// This is helpful since we skip over one of the spots
|
||||||
@@ -90,9 +90,9 @@ class GaussianWeightedSumFactor extends GaussianFactor
|
|||||||
|
|
||||||
$currentWeight = (-$variableWeights[$currentWeightSourceIndex] / $variableWeights[$weightsIndex - 1]);
|
$currentWeight = (-$variableWeights[$currentWeightSourceIndex] / $variableWeights[$weightsIndex - 1]);
|
||||||
|
|
||||||
if ($variableWeights[$weightsIndex - 1] == 0) {
|
if ($variableWeights[$weightsIndex - 1] == 0.0) {
|
||||||
// HACK: Getting around division by zero
|
// HACK: Getting around division by zero
|
||||||
$currentWeight = 0;
|
$currentWeight = 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
$currentWeights[$currentDestinationWeightIndex] = $currentWeight;
|
$currentWeights[$currentDestinationWeightIndex] = $currentWeight;
|
||||||
@@ -112,7 +112,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($variableWeights)] = 0.0;
|
||||||
$this->varIndexOrdersForWeights[] = $variableIndices;
|
$this->varIndexOrdersForWeights[] = $variableIndices;
|
||||||
|
|
||||||
$this->weights[$weightsIndex] = $currentWeights;
|
$this->weights[$weightsIndex] = $currentWeights;
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ use DNW\Skills\TrueSkill\TruncatedGaussianCorrectionFunctions;
|
|||||||
*
|
*
|
||||||
* See the accompanying math paper for more details.
|
* See the accompanying math paper for more details.
|
||||||
*/
|
*/
|
||||||
class GaussianWithinFactor extends GaussianFactor
|
final class GaussianWithinFactor extends GaussianFactor
|
||||||
{
|
{
|
||||||
public function __construct(private readonly float $epsilon, Variable $variable)
|
public function __construct(private readonly float $epsilon, Variable $variable)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ use DNW\Skills\TrueSkill\TrueSkillFactorGraph;
|
|||||||
use Exception;
|
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
|
final class IteratedTeamDifferencesInnerLayer extends TrueSkillFactorGraphLayer
|
||||||
{
|
{
|
||||||
public function __construct(
|
public function __construct(
|
||||||
TrueSkillFactorGraph $parentGraph,
|
TrueSkillFactorGraph $parentGraph,
|
||||||
@@ -44,7 +44,7 @@ class IteratedTeamDifferencesInnerLayer extends TrueSkillFactorGraphLayer
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[\Override]
|
#[\Override]
|
||||||
public function createPriorSchedule(): ?ScheduleSequence
|
public function createPriorSchedule(): ScheduleSequence
|
||||||
{
|
{
|
||||||
switch (count($this->getInputVariablesGroups())) {
|
switch (count($this->getInputVariablesGroups())) {
|
||||||
case 0:
|
case 0:
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ use DNW\Skills\TrueSkill\Factors\GaussianWeightedSumFactor;
|
|||||||
use DNW\Skills\FactorGraphs\Variable;
|
use DNW\Skills\FactorGraphs\Variable;
|
||||||
use DNW\Skills\FactorGraphs\KeyedVariable;
|
use DNW\Skills\FactorGraphs\KeyedVariable;
|
||||||
|
|
||||||
class PlayerPerformancesToTeamPerformancesLayer extends TrueSkillFactorGraphLayer
|
final class PlayerPerformancesToTeamPerformancesLayer extends TrueSkillFactorGraphLayer
|
||||||
{
|
{
|
||||||
#[\Override]
|
#[\Override]
|
||||||
public function buildLayer(): void
|
public function buildLayer(): void
|
||||||
@@ -34,7 +34,7 @@ class PlayerPerformancesToTeamPerformancesLayer extends TrueSkillFactorGraphLaye
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[\Override]
|
#[\Override]
|
||||||
public function createPriorSchedule(): ?ScheduleSequence
|
public function createPriorSchedule(): ScheduleSequence
|
||||||
{
|
{
|
||||||
$localFactors = $this->getLocalFactors();
|
$localFactors = $this->getLocalFactors();
|
||||||
|
|
||||||
@@ -51,7 +51,7 @@ class PlayerPerformancesToTeamPerformancesLayer extends TrueSkillFactorGraphLaye
|
|||||||
/**
|
/**
|
||||||
* @param KeyedVariable[] $teamMembers
|
* @param KeyedVariable[] $teamMembers
|
||||||
*/
|
*/
|
||||||
protected function createPlayerToTeamSumFactor(array $teamMembers, Variable $sumVariable): GaussianWeightedSumFactor
|
private function createPlayerToTeamSumFactor(array $teamMembers, Variable $sumVariable): GaussianWeightedSumFactor
|
||||||
{
|
{
|
||||||
$weights = array_map(
|
$weights = array_map(
|
||||||
static function ($v): float {
|
static function ($v): float {
|
||||||
@@ -69,7 +69,7 @@ class PlayerPerformancesToTeamPerformancesLayer extends TrueSkillFactorGraphLaye
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[\Override]
|
#[\Override]
|
||||||
public function createPosteriorSchedule(): ?ScheduleSequence
|
public function createPosteriorSchedule(): ScheduleSequence
|
||||||
{
|
{
|
||||||
$allFactors = [];
|
$allFactors = [];
|
||||||
$localFactors = $this->getLocalFactors();
|
$localFactors = $this->getLocalFactors();
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ use DNW\Skills\FactorGraphs\ScheduleSequence;
|
|||||||
|
|
||||||
// We intentionally have no Posterior schedule since the only purpose here is to
|
// We intentionally have no Posterior schedule since the only purpose here is to
|
||||||
// start the process.
|
// start the process.
|
||||||
class PlayerPriorValuesToSkillsLayer extends TrueSkillFactorGraphLayer
|
final class PlayerPriorValuesToSkillsLayer extends TrueSkillFactorGraphLayer
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @param Team[] $teams
|
* @param Team[] $teams
|
||||||
@@ -51,7 +51,7 @@ class PlayerPriorValuesToSkillsLayer extends TrueSkillFactorGraphLayer
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[\Override]
|
#[\Override]
|
||||||
public function createPriorSchedule(): ?ScheduleSequence
|
public function createPriorSchedule(): ScheduleSequence
|
||||||
{
|
{
|
||||||
$localFactors = $this->getLocalFactors();
|
$localFactors = $this->getLocalFactors();
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ use DNW\Skills\Numerics\BasicMath;
|
|||||||
use DNW\Skills\TrueSkill\Factors\GaussianLikelihoodFactor;
|
use DNW\Skills\TrueSkill\Factors\GaussianLikelihoodFactor;
|
||||||
use DNW\Skills\FactorGraphs\ScheduleSequence;
|
use DNW\Skills\FactorGraphs\ScheduleSequence;
|
||||||
|
|
||||||
class PlayerSkillsToPerformancesLayer extends TrueSkillFactorGraphLayer
|
final class PlayerSkillsToPerformancesLayer extends TrueSkillFactorGraphLayer
|
||||||
{
|
{
|
||||||
#[\Override]
|
#[\Override]
|
||||||
public function buildLayer(): void
|
public function buildLayer(): void
|
||||||
@@ -53,7 +53,7 @@ class PlayerSkillsToPerformancesLayer extends TrueSkillFactorGraphLayer
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[\Override]
|
#[\Override]
|
||||||
public function createPriorSchedule(): ?ScheduleSequence
|
public function createPriorSchedule(): ScheduleSequence
|
||||||
{
|
{
|
||||||
$localFactors = $this->getLocalFactors();
|
$localFactors = $this->getLocalFactors();
|
||||||
|
|
||||||
@@ -68,7 +68,7 @@ class PlayerSkillsToPerformancesLayer extends TrueSkillFactorGraphLayer
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[\Override]
|
#[\Override]
|
||||||
public function createPosteriorSchedule(): ?ScheduleSequence
|
public function createPosteriorSchedule(): ScheduleSequence
|
||||||
{
|
{
|
||||||
$localFactors = $this->getLocalFactors();
|
$localFactors = $this->getLocalFactors();
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ use DNW\Skills\TrueSkill\Factors\GaussianGreaterThanFactor;
|
|||||||
use DNW\Skills\TrueSkill\Factors\GaussianWithinFactor;
|
use DNW\Skills\TrueSkill\Factors\GaussianWithinFactor;
|
||||||
use DNW\Skills\TrueSkill\TrueSkillFactorGraph;
|
use DNW\Skills\TrueSkill\TrueSkillFactorGraph;
|
||||||
|
|
||||||
class TeamDifferencesComparisonLayer extends TrueSkillFactorGraphLayer
|
final class TeamDifferencesComparisonLayer extends TrueSkillFactorGraphLayer
|
||||||
{
|
{
|
||||||
private readonly float $epsilon;
|
private readonly float $epsilon;
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ namespace DNW\Skills\TrueSkill\Layers;
|
|||||||
use DNW\Skills\FactorGraphs\Variable;
|
use DNW\Skills\FactorGraphs\Variable;
|
||||||
use DNW\Skills\TrueSkill\Factors\GaussianWeightedSumFactor;
|
use DNW\Skills\TrueSkill\Factors\GaussianWeightedSumFactor;
|
||||||
|
|
||||||
class TeamPerformancesToTeamPerformanceDifferencesLayer extends TrueSkillFactorGraphLayer
|
final class TeamPerformancesToTeamPerformanceDifferencesLayer extends TrueSkillFactorGraphLayer
|
||||||
{
|
{
|
||||||
#[\Override]
|
#[\Override]
|
||||||
public function buildLayer(): void
|
public function buildLayer(): void
|
||||||
@@ -29,11 +29,7 @@ class TeamPerformancesToTeamPerformanceDifferencesLayer extends TrueSkillFactorG
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function createTeamPerformanceToDifferenceFactor(
|
private function createTeamPerformanceToDifferenceFactor(Variable $strongerTeam, Variable $weakerTeam, Variable $output): GaussianWeightedSumFactor
|
||||||
Variable $strongerTeam,
|
|
||||||
Variable $weakerTeam,
|
|
||||||
Variable $output
|
|
||||||
): GaussianWeightedSumFactor
|
|
||||||
{
|
{
|
||||||
$teams = [$strongerTeam, $weakerTeam];
|
$teams = [$strongerTeam, $weakerTeam];
|
||||||
$weights = [1.0, -1.0];
|
$weights = [1.0, -1.0];
|
||||||
|
|||||||
@@ -9,8 +9,4 @@ use DNW\Skills\TrueSkill\TrueSkillFactorGraph;
|
|||||||
|
|
||||||
abstract class TrueSkillFactorGraphLayer extends FactorGraphLayer
|
abstract class TrueSkillFactorGraphLayer extends FactorGraphLayer
|
||||||
{
|
{
|
||||||
public function __construct(TrueSkillFactorGraph $parentGraph)
|
|
||||||
{
|
|
||||||
parent::__construct($parentGraph);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ use DNW\Skills\TrueSkill\Layers\PlayerSkillsToPerformancesLayer;
|
|||||||
use DNW\Skills\TrueSkill\Layers\TeamDifferencesComparisonLayer;
|
use DNW\Skills\TrueSkill\Layers\TeamDifferencesComparisonLayer;
|
||||||
use DNW\Skills\TrueSkill\Layers\TeamPerformancesToTeamPerformanceDifferencesLayer;
|
use DNW\Skills\TrueSkill\Layers\TeamPerformancesToTeamPerformanceDifferencesLayer;
|
||||||
|
|
||||||
class TrueSkillFactorGraph extends FactorGraph
|
final class TrueSkillFactorGraph extends FactorGraph
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @var FactorGraphLayer[] $layers
|
* @var FactorGraphLayer[] $layers
|
||||||
@@ -33,6 +33,8 @@ class TrueSkillFactorGraph extends FactorGraph
|
|||||||
private readonly PlayerPriorValuesToSkillsLayer $priorLayer;
|
private readonly PlayerPriorValuesToSkillsLayer $priorLayer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Constructor
|
||||||
|
*
|
||||||
* @param GameInfo $gameInfo Parameters for the game.
|
* @param GameInfo $gameInfo Parameters for the game.
|
||||||
* @param Team[] $teams A mapping of team players and their ratings.
|
* @param Team[] $teams A mapping of team players and their ratings.
|
||||||
* @param int[] $teamRanks The ranks of the teams where 1 is first place. For a tie, repeat the number (e.g. 1, 2, 2).
|
* @param int[] $teamRanks The ranks of the teams where 1 is first place. For a tie, repeat the number (e.g. 1, 2, 2).
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ namespace DNW\Skills\TrueSkill;
|
|||||||
|
|
||||||
use DNW\Skills\Numerics\GaussianDistribution;
|
use DNW\Skills\Numerics\GaussianDistribution;
|
||||||
|
|
||||||
class TruncatedGaussianCorrectionFunctions
|
final class TruncatedGaussianCorrectionFunctions
|
||||||
{
|
{
|
||||||
// These functions from the bottom of page 4 of the TrueSkill paper.
|
// These functions from the bottom of page 4 of the TrueSkill paper.
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ use DNW\Skills\TeamsRange;
|
|||||||
* When you only have two players, a lot of the math simplifies. The main purpose of this class
|
* When you only have two players, a lot of the math simplifies. The main purpose of this class
|
||||||
* is to show the bare minimum of what a TrueSkill implementation should have.
|
* is to show the bare minimum of what a TrueSkill implementation should have.
|
||||||
*/
|
*/
|
||||||
class TwoPlayerTrueSkillCalculator extends SkillCalculator
|
final class TwoPlayerTrueSkillCalculator extends SkillCalculator
|
||||||
{
|
{
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
@@ -32,11 +32,7 @@ class TwoPlayerTrueSkillCalculator extends SkillCalculator
|
|||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
#[\Override]
|
#[\Override]
|
||||||
public function calculateNewRatings(
|
public function calculateNewRatings(GameInfo $gameInfo, array $teams, array $teamRanks): RatingContainer
|
||||||
GameInfo $gameInfo,
|
|
||||||
array $teams,
|
|
||||||
array $teamRanks
|
|
||||||
): RatingContainer
|
|
||||||
{
|
{
|
||||||
// Basic argument checking
|
// Basic argument checking
|
||||||
$this->validateTeamCountAndPlayersCountPerTeam($teams);
|
$this->validateTeamCountAndPlayersCountPerTeam($teams);
|
||||||
@@ -95,7 +91,7 @@ class TwoPlayerTrueSkillCalculator extends SkillCalculator
|
|||||||
+
|
+
|
||||||
BasicMath::square($opponentRating->getStandardDeviation())
|
BasicMath::square($opponentRating->getStandardDeviation())
|
||||||
+
|
+
|
||||||
2 * BasicMath::square($gameInfo->getBeta())
|
2.0 * BasicMath::square($gameInfo->getBeta())
|
||||||
);
|
);
|
||||||
|
|
||||||
$winningMean = $selfRating->getMean();
|
$winningMean = $selfRating->getMean();
|
||||||
@@ -118,11 +114,11 @@ class TwoPlayerTrueSkillCalculator extends SkillCalculator
|
|||||||
// non-draw case
|
// non-draw case
|
||||||
$v = TruncatedGaussianCorrectionFunctions::vExceedsMarginScaled($meanDelta, $drawMargin, $c);
|
$v = TruncatedGaussianCorrectionFunctions::vExceedsMarginScaled($meanDelta, $drawMargin, $c);
|
||||||
$w = TruncatedGaussianCorrectionFunctions::wExceedsMarginScaled($meanDelta, $drawMargin, $c);
|
$w = TruncatedGaussianCorrectionFunctions::wExceedsMarginScaled($meanDelta, $drawMargin, $c);
|
||||||
$rankMultiplier = $comparison->value;
|
$rankMultiplier = (float)$comparison->value;
|
||||||
} else {
|
} else {
|
||||||
$v = TruncatedGaussianCorrectionFunctions::vWithinMarginScaled($meanDelta, $drawMargin, $c);
|
$v = TruncatedGaussianCorrectionFunctions::vWithinMarginScaled($meanDelta, $drawMargin, $c);
|
||||||
$w = TruncatedGaussianCorrectionFunctions::wWithinMarginScaled($meanDelta, $drawMargin, $c);
|
$w = TruncatedGaussianCorrectionFunctions::wWithinMarginScaled($meanDelta, $drawMargin, $c);
|
||||||
$rankMultiplier = 1;
|
$rankMultiplier = 1.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
$meanMultiplier = (BasicMath::square($selfRating->getStandardDeviation()) + BasicMath::square($gameInfo->getDynamicsFactor())) / $c;
|
$meanMultiplier = (BasicMath::square($selfRating->getStandardDeviation()) + BasicMath::square($gameInfo->getDynamicsFactor())) / $c;
|
||||||
@@ -131,7 +127,7 @@ class TwoPlayerTrueSkillCalculator extends SkillCalculator
|
|||||||
$stdDevMultiplier = $varianceWithDynamics / BasicMath::square($c);
|
$stdDevMultiplier = $varianceWithDynamics / BasicMath::square($c);
|
||||||
|
|
||||||
$newMean = $selfRating->getMean() + ($rankMultiplier * $meanMultiplier * $v);
|
$newMean = $selfRating->getMean() + ($rankMultiplier * $meanMultiplier * $v);
|
||||||
$newStdDev = sqrt($varianceWithDynamics * (1 - $w * $stdDevMultiplier));
|
$newStdDev = sqrt($varianceWithDynamics * (1.0 - $w * $stdDevMultiplier));
|
||||||
|
|
||||||
return new Rating($newMean, $newStdDev);
|
return new Rating($newMean, $newStdDev);
|
||||||
}
|
}
|
||||||
@@ -160,16 +156,16 @@ class TwoPlayerTrueSkillCalculator extends SkillCalculator
|
|||||||
|
|
||||||
// This is the square root part of the equation:
|
// This is the square root part of the equation:
|
||||||
$sqrtPart = sqrt(
|
$sqrtPart = sqrt(
|
||||||
(2 * $betaSquared)
|
(2.0 * $betaSquared)
|
||||||
/
|
/
|
||||||
(2 * $betaSquared + $player1SigmaSquared + $player2SigmaSquared)
|
(2.0 * $betaSquared + $player1SigmaSquared + $player2SigmaSquared)
|
||||||
);
|
);
|
||||||
|
|
||||||
// This is the exponent part of the equation:
|
// This is the exponent part of the equation:
|
||||||
$expPart = exp(
|
$expPart = exp(
|
||||||
(-1 * BasicMath::square($player1Rating->getMean() - $player2Rating->getMean()))
|
(-1.0 * BasicMath::square($player1Rating->getMean() - $player2Rating->getMean()))
|
||||||
/
|
/
|
||||||
(2 * (2 * $betaSquared + $player1SigmaSquared + $player2SigmaSquared))
|
(2.0 * (2.0 * $betaSquared + $player1SigmaSquared + $player2SigmaSquared))
|
||||||
);
|
);
|
||||||
|
|
||||||
return $sqrtPart * $expPart;
|
return $sqrtPart * $expPart;
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ use DNW\Skills\TeamsRange;
|
|||||||
*
|
*
|
||||||
* When you only have two teams, the math is still simple: no factor graphs are used yet.
|
* When you only have two teams, the math is still simple: no factor graphs are used yet.
|
||||||
*/
|
*/
|
||||||
class TwoTeamTrueSkillCalculator extends SkillCalculator
|
final class TwoTeamTrueSkillCalculator extends SkillCalculator
|
||||||
{
|
{
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
@@ -64,13 +64,7 @@ class TwoTeamTrueSkillCalculator extends SkillCalculator
|
|||||||
return $results;
|
return $results;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function updatePlayerRatings(
|
private static function updatePlayerRatings(GameInfo $gameInfo, RatingContainer $newPlayerRatings, Team $selfTeam, Team $otherTeam, PairwiseComparison $selfToOtherTeamComparison): void
|
||||||
GameInfo $gameInfo,
|
|
||||||
RatingContainer $newPlayerRatings,
|
|
||||||
Team $selfTeam,
|
|
||||||
Team $otherTeam,
|
|
||||||
PairwiseComparison $selfToOtherTeamComparison
|
|
||||||
): void
|
|
||||||
{
|
{
|
||||||
$drawMargin = DrawMargin::getDrawMarginFromDrawProbability(
|
$drawMargin = DrawMargin::getDrawMarginFromDrawProbability(
|
||||||
$gameInfo->getDrawProbability(),
|
$gameInfo->getDrawProbability(),
|
||||||
@@ -94,7 +88,7 @@ class TwoTeamTrueSkillCalculator extends SkillCalculator
|
|||||||
+
|
+
|
||||||
BasicMath::sum($otherTeam->getAllRatings(), $varianceGetter)
|
BasicMath::sum($otherTeam->getAllRatings(), $varianceGetter)
|
||||||
+
|
+
|
||||||
$totalPlayers * $betaSquared
|
(float)$totalPlayers * $betaSquared
|
||||||
);
|
);
|
||||||
|
|
||||||
$winningMean = $selfMeanSum;
|
$winningMean = $selfMeanSum;
|
||||||
@@ -117,12 +111,12 @@ class TwoTeamTrueSkillCalculator extends SkillCalculator
|
|||||||
// non-draw case
|
// non-draw case
|
||||||
$v = TruncatedGaussianCorrectionFunctions::vExceedsMarginScaled($meanDelta, $drawMargin, $c);
|
$v = TruncatedGaussianCorrectionFunctions::vExceedsMarginScaled($meanDelta, $drawMargin, $c);
|
||||||
$w = TruncatedGaussianCorrectionFunctions::wExceedsMarginScaled($meanDelta, $drawMargin, $c);
|
$w = TruncatedGaussianCorrectionFunctions::wExceedsMarginScaled($meanDelta, $drawMargin, $c);
|
||||||
$rankMultiplier = $selfToOtherTeamComparison->value;
|
$rankMultiplier = (float)$selfToOtherTeamComparison->value;
|
||||||
} else {
|
} else {
|
||||||
// assume draw
|
// assume draw
|
||||||
$v = TruncatedGaussianCorrectionFunctions::vWithinMarginScaled($meanDelta, $drawMargin, $c);
|
$v = TruncatedGaussianCorrectionFunctions::vWithinMarginScaled($meanDelta, $drawMargin, $c);
|
||||||
$w = TruncatedGaussianCorrectionFunctions::wWithinMarginScaled($meanDelta, $drawMargin, $c);
|
$w = TruncatedGaussianCorrectionFunctions::wWithinMarginScaled($meanDelta, $drawMargin, $c);
|
||||||
$rankMultiplier = 1;
|
$rankMultiplier = 1.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
$selfTeamAllPlayers = $selfTeam->getAllPlayers();
|
$selfTeamAllPlayers = $selfTeam->getAllPlayers();
|
||||||
@@ -137,7 +131,7 @@ class TwoTeamTrueSkillCalculator extends SkillCalculator
|
|||||||
$newMean = $previousPlayerRating->getMean() + $playerMeanDelta;
|
$newMean = $previousPlayerRating->getMean() + $playerMeanDelta;
|
||||||
|
|
||||||
$newStdDev = sqrt(
|
$newStdDev = sqrt(
|
||||||
(BasicMath::square($previousPlayerRating->getStandardDeviation()) + $tauSquared) * (1 - $w * $stdDevMultiplier)
|
(BasicMath::square($previousPlayerRating->getStandardDeviation()) + $tauSquared) * (1.0 - $w * $stdDevMultiplier)
|
||||||
);
|
);
|
||||||
|
|
||||||
$newPlayerRatings->setRating($localSelfTeamCurPlayer, new Rating($newMean, $newStdDev));
|
$newPlayerRatings->setRating($localSelfTeamCurPlayer, new Rating($newMean, $newStdDev));
|
||||||
@@ -159,7 +153,7 @@ class TwoTeamTrueSkillCalculator extends SkillCalculator
|
|||||||
$team2Ratings = $teams[1]->getAllRatings();
|
$team2Ratings = $teams[1]->getAllRatings();
|
||||||
$team2Count = count($team2Ratings);
|
$team2Count = count($team2Ratings);
|
||||||
|
|
||||||
$totalPlayers = $team1Count + $team2Count;
|
$totalPlayers = (float)($team1Count + $team2Count);
|
||||||
|
|
||||||
$betaSquared = BasicMath::square($gameInfo->getBeta());
|
$betaSquared = BasicMath::square($gameInfo->getBeta());
|
||||||
|
|
||||||
@@ -184,9 +178,9 @@ class TwoTeamTrueSkillCalculator extends SkillCalculator
|
|||||||
);
|
);
|
||||||
|
|
||||||
$expPart = exp(
|
$expPart = exp(
|
||||||
(-1 * BasicMath::square($team1MeanSum - $team2MeanSum))
|
(-1.0 * BasicMath::square($team1MeanSum - $team2MeanSum))
|
||||||
/
|
/
|
||||||
(2 * ($totalPlayers * $betaSquared + $team1StdDevSquared + $team2StdDevSquared))
|
(2.0 * ($totalPlayers * $betaSquared + $team1StdDevSquared + $team2StdDevSquared))
|
||||||
);
|
);
|
||||||
|
|
||||||
return $expPart * $sqrtPart;
|
return $expPart * $sqrtPart;
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ use PHPUnit\Framework\Attributes\UsesClass;
|
|||||||
|
|
||||||
#[CoversClass(Variable::class)]
|
#[CoversClass(Variable::class)]
|
||||||
#[UsesClass(GaussianDistribution::class)]
|
#[UsesClass(GaussianDistribution::class)]
|
||||||
class VariableTest extends TestCase
|
final class VariableTest extends TestCase
|
||||||
{
|
{
|
||||||
public function testGetterSetter(): void
|
public function testGetterSetter(): void
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ use PHPUnit\Framework\Attributes\UsesClass;
|
|||||||
|
|
||||||
#[CoversClass(GameInfo::class)]
|
#[CoversClass(GameInfo::class)]
|
||||||
#[UsesClass(Rating::class)]
|
#[UsesClass(Rating::class)]
|
||||||
class GameInfoTest extends TestCase
|
final class GameInfoTest extends TestCase
|
||||||
{
|
{
|
||||||
public function testMembers(): void
|
public function testMembers(): void
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ use PHPUnit\Framework\TestCase;
|
|||||||
use PHPUnit\Framework\Attributes\CoversClass;
|
use PHPUnit\Framework\Attributes\CoversClass;
|
||||||
|
|
||||||
#[CoversClass(Guard::class)]
|
#[CoversClass(Guard::class)]
|
||||||
class GuardTest extends TestCase
|
final class GuardTest extends TestCase
|
||||||
{
|
{
|
||||||
public function testargumentIsValidIndexArgumentAbove(): void
|
public function testargumentIsValidIndexArgumentAbove(): void
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ use PHPUnit\Framework\Attributes\CoversClass;
|
|||||||
use stdClass;
|
use stdClass;
|
||||||
|
|
||||||
#[CoversClass(HashMap::class)]
|
#[CoversClass(HashMap::class)]
|
||||||
class HashMapTest extends TestCase
|
final class HashMapTest extends TestCase
|
||||||
{
|
{
|
||||||
public function testHashmap(): void
|
public function testHashmap(): void
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ use PHPUnit\Framework\TestCase;
|
|||||||
use PHPUnit\Framework\Attributes\CoversClass;
|
use PHPUnit\Framework\Attributes\CoversClass;
|
||||||
|
|
||||||
#[CoversClass(BasicMath::class)]
|
#[CoversClass(BasicMath::class)]
|
||||||
class BasicMathTest extends TestCase
|
final class BasicMathTest extends TestCase
|
||||||
{
|
{
|
||||||
public function testSquare(): void
|
public function testSquare(): void
|
||||||
{
|
{
|
||||||
@@ -23,7 +23,7 @@ class BasicMathTest extends TestCase
|
|||||||
$arr = [1, 1, 1, 1];
|
$arr = [1, 1, 1, 1];
|
||||||
|
|
||||||
$func_return = static fn(float $f): float => $f;
|
$func_return = static fn(float $f): float => $f;
|
||||||
$func_double = static fn(float $f): float => $f * 2;
|
$func_double = static fn(float $f): float => $f * 2.0;
|
||||||
$this->assertEquals(4, BasicMath::sum($arr, $func_return));
|
$this->assertEquals(4, BasicMath::sum($arr, $func_return));
|
||||||
$this->assertEquals(8, BasicMath::sum($arr, $func_double));
|
$this->assertEquals(8, BasicMath::sum($arr, $func_double));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ use PHPUnit\Framework\Attributes\UsesClass;
|
|||||||
|
|
||||||
#[CoversClass(GaussianDistribution::class)]
|
#[CoversClass(GaussianDistribution::class)]
|
||||||
#[UsesClass(BasicMath::class)]
|
#[UsesClass(BasicMath::class)]
|
||||||
class GaussianDistributionTest extends TestCase
|
final class GaussianDistributionTest extends TestCase
|
||||||
{
|
{
|
||||||
private const float ERROR_TOLERANCE = 0.000001;
|
private const float ERROR_TOLERANCE = 0.000001;
|
||||||
|
|
||||||
@@ -24,7 +24,7 @@ class GaussianDistributionTest extends TestCase
|
|||||||
$this->assertEquals(9, $gd->getVariance());
|
$this->assertEquals(9, $gd->getVariance());
|
||||||
$this->assertEquals(3, $gd->getStandardDeviation());
|
$this->assertEquals(3, $gd->getStandardDeviation());
|
||||||
$this->assertEquals(1 / 9, $gd->getPrecision());
|
$this->assertEquals(1 / 9, $gd->getPrecision());
|
||||||
$this->assertEquals(1 / 9 * 10, $gd->getPrecisionMean());
|
$this->assertEquals(1.0 / 9.0 * 10.0, $gd->getPrecisionMean());
|
||||||
$this->assertEqualsWithDelta(0.13298076013, $gd->getNormalizationConstant(), GaussianDistributionTest::ERROR_TOLERANCE);
|
$this->assertEqualsWithDelta(0.13298076013, $gd->getNormalizationConstant(), GaussianDistributionTest::ERROR_TOLERANCE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -57,7 +57,7 @@ class GaussianDistributionTest extends TestCase
|
|||||||
|
|
||||||
$product2 = GaussianDistribution::multiply($m4s5, $m6s7);
|
$product2 = GaussianDistribution::multiply($m4s5, $m6s7);
|
||||||
|
|
||||||
$expectedMean = (4 * BasicMath::square(7) + 6 * BasicMath::square(5)) / (BasicMath::square(5) + BasicMath::square(7));
|
$expectedMean = (4.0 * BasicMath::square(7) + 6.0 * BasicMath::square(5)) / (BasicMath::square(5) + BasicMath::square(7));
|
||||||
$this->assertEqualsWithDelta($expectedMean, $product2->getMean(), GaussianDistributionTest::ERROR_TOLERANCE);
|
$this->assertEqualsWithDelta($expectedMean, $product2->getMean(), GaussianDistributionTest::ERROR_TOLERANCE);
|
||||||
|
|
||||||
$expectedSigma = sqrt(((BasicMath::square(5) * BasicMath::square(7)) / (BasicMath::square(5) + BasicMath::square(7))));
|
$expectedSigma = sqrt(((BasicMath::square(5) * BasicMath::square(7)) / (BasicMath::square(5) + BasicMath::square(7))));
|
||||||
@@ -74,7 +74,7 @@ class GaussianDistributionTest extends TestCase
|
|||||||
$this->assertEqualsWithDelta(2.0, $productDividedByStandardNormal->getMean(), GaussianDistributionTest::ERROR_TOLERANCE);
|
$this->assertEqualsWithDelta(2.0, $productDividedByStandardNormal->getMean(), GaussianDistributionTest::ERROR_TOLERANCE);
|
||||||
$this->assertEqualsWithDelta(3.0, $productDividedByStandardNormal->getStandardDeviation(), GaussianDistributionTest::ERROR_TOLERANCE);
|
$this->assertEqualsWithDelta(3.0, $productDividedByStandardNormal->getStandardDeviation(), GaussianDistributionTest::ERROR_TOLERANCE);
|
||||||
|
|
||||||
$product2 = new GaussianDistribution((4 * BasicMath::square(7) + 6 * BasicMath::square(5)) / (BasicMath::square(5) + BasicMath::square(7)), sqrt(((BasicMath::square(5) * BasicMath::square(7)) / (BasicMath::square(5) + BasicMath::square(7)))));
|
$product2 = new GaussianDistribution((4.0 * BasicMath::square(7) + 6.0 * BasicMath::square(5)) / (BasicMath::square(5) + BasicMath::square(7)), sqrt(((BasicMath::square(5) * BasicMath::square(7)) / (BasicMath::square(5) + BasicMath::square(7)))));
|
||||||
$m4s5 = new GaussianDistribution(4, 5);
|
$m4s5 = new GaussianDistribution(4, 5);
|
||||||
$product2DividedByM4S5 = GaussianDistribution::divide($product2, $m4s5);
|
$product2DividedByM4S5 = GaussianDistribution::divide($product2, $m4s5);
|
||||||
$this->assertEqualsWithDelta(6.0, $product2DividedByM4S5->getMean(), GaussianDistributionTest::ERROR_TOLERANCE);
|
$this->assertEqualsWithDelta(6.0, $product2DividedByM4S5->getMean(), GaussianDistributionTest::ERROR_TOLERANCE);
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ use Exception;
|
|||||||
#[CoversClass(DiagonalMatrix::class)]
|
#[CoversClass(DiagonalMatrix::class)]
|
||||||
#[CoversClass(Vector::class)]
|
#[CoversClass(Vector::class)]
|
||||||
// phpcs:disable PSR2.Methods.FunctionCallSignature,Generic.Functions.FunctionCallArgumentSpacing.TooMuchSpaceAfterComma
|
// phpcs:disable PSR2.Methods.FunctionCallSignature,Generic.Functions.FunctionCallArgumentSpacing.TooMuchSpaceAfterComma
|
||||||
class MatrixTest extends TestCase
|
final class MatrixTest extends TestCase
|
||||||
{
|
{
|
||||||
public function testEmptyMatrix(): void
|
public function testEmptyMatrix(): void
|
||||||
{
|
{
|
||||||
@@ -295,7 +295,7 @@ class MatrixTest extends TestCase
|
|||||||
1, 0, 6);
|
1, 0, 6);
|
||||||
|
|
||||||
$cInverse = $c->getInverse();
|
$cInverse = $c->getInverse();
|
||||||
$d = Matrix::scalarMultiply((1.0 / 22), new SquareMatrix(24, -12, -2,
|
$d = Matrix::scalarMultiply((1.0 / 22.0), new SquareMatrix(24, -12, -2,
|
||||||
5, 3, -5,
|
5, 3, -5,
|
||||||
-4, 2, 4));
|
-4, 2, 4));
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ use PHPUnit\Framework\Attributes\CoversClass;
|
|||||||
use Exception;
|
use Exception;
|
||||||
|
|
||||||
#[CoversClass(Range::class)]
|
#[CoversClass(Range::class)]
|
||||||
class RangeTest extends TestCase
|
final class RangeTest extends TestCase
|
||||||
{
|
{
|
||||||
public function testConstructInvalidParam(): void
|
public function testConstructInvalidParam(): void
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ use PHPUnit\Framework\Attributes\UsesClass;
|
|||||||
#[CoversClass(PartialPlay::class)]
|
#[CoversClass(PartialPlay::class)]
|
||||||
#[UsesClass(Player::class)]
|
#[UsesClass(Player::class)]
|
||||||
#[UsesClass(Guard::class)]
|
#[UsesClass(Guard::class)]
|
||||||
class PartialPlayTest extends TestCase
|
final class PartialPlayTest extends TestCase
|
||||||
{
|
{
|
||||||
public function testgetPartialPlayPercentage(): void
|
public function testgetPartialPlayPercentage(): void
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ use PHPUnit\Framework\Attributes\UsesClass;
|
|||||||
|
|
||||||
#[CoversClass(Player::class)]
|
#[CoversClass(Player::class)]
|
||||||
#[UsesClass(Guard::class)]
|
#[UsesClass(Guard::class)]
|
||||||
class PlayerTest extends TestCase
|
final class PlayerTest extends TestCase
|
||||||
{
|
{
|
||||||
public function testPlayerObjectGetterSetter(): void
|
public function testPlayerObjectGetterSetter(): void
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ use PHPUnit\Framework\TestCase;
|
|||||||
use PHPUnit\Framework\Attributes\CoversClass;
|
use PHPUnit\Framework\Attributes\CoversClass;
|
||||||
|
|
||||||
#[CoversClass(RankSorter::class)]
|
#[CoversClass(RankSorter::class)]
|
||||||
class RankSorterTest extends TestCase
|
final class RankSorterTest extends TestCase
|
||||||
{
|
{
|
||||||
public function testSort(): void
|
public function testSort(): void
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ use PHPUnit\Framework\Attributes\UsesClass;
|
|||||||
#[UsesClass(Player::class)]
|
#[UsesClass(Player::class)]
|
||||||
#[UsesClass(Rating::class)]
|
#[UsesClass(Rating::class)]
|
||||||
#[UsesClass(Guard::class)]
|
#[UsesClass(Guard::class)]
|
||||||
class RatingContainerTest extends TestCase
|
final class RatingContainerTest extends TestCase
|
||||||
{
|
{
|
||||||
public function testRatingContainer(): void
|
public function testRatingContainer(): void
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ use PHPUnit\Framework\Attributes\UsesClass;
|
|||||||
#[CoversClass(Rating::class)]
|
#[CoversClass(Rating::class)]
|
||||||
#[UsesClass(BasicMath::class)]
|
#[UsesClass(BasicMath::class)]
|
||||||
#[UsesClass(GaussianDistribution::class)]
|
#[UsesClass(GaussianDistribution::class)]
|
||||||
class RatingTest extends TestCase
|
final class RatingTest extends TestCase
|
||||||
{
|
{
|
||||||
public function testGetRatingParameters(): void
|
public function testGetRatingParameters(): void
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ use PHPUnit\Framework\Attributes\RequiresPhpunit;
|
|||||||
#[UsesClass(PlayersRange::class)]
|
#[UsesClass(PlayersRange::class)]
|
||||||
#[UsesClass(TeamsRange::class)]
|
#[UsesClass(TeamsRange::class)]
|
||||||
#[RequiresPhpunit('<12.0')]
|
#[RequiresPhpunit('<12.0')]
|
||||||
class SkillCalculatorTest extends TestCase
|
final class SkillCalculatorTest extends TestCase
|
||||||
{
|
{
|
||||||
public function testisSupported(): void
|
public function testisSupported(): void
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ use PHPUnit\Framework\Attributes\UsesClass;
|
|||||||
#[UsesClass(Player::class)]
|
#[UsesClass(Player::class)]
|
||||||
#[UsesClass(Rating::class)]
|
#[UsesClass(Rating::class)]
|
||||||
#[UsesClass(Guard::class)]
|
#[UsesClass(Guard::class)]
|
||||||
class TeamTest extends TestCase
|
final class TeamTest extends TestCase
|
||||||
{
|
{
|
||||||
public function testTeam(): void
|
public function testTeam(): void
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ use PHPUnit\Framework\Attributes\UsesClass;
|
|||||||
#[CoversClass(DrawMargin::class)]
|
#[CoversClass(DrawMargin::class)]
|
||||||
#[UsesClass(BasicMath::class)]
|
#[UsesClass(BasicMath::class)]
|
||||||
#[UsesClass(GaussianDistribution::class)]
|
#[UsesClass(GaussianDistribution::class)]
|
||||||
class DrawMarginTest extends TestCase
|
final class DrawMarginTest extends TestCase
|
||||||
{
|
{
|
||||||
private const float ERROR_TOLERANCE = 0.000001;
|
private const float ERROR_TOLERANCE = 0.000001;
|
||||||
|
|
||||||
|
|||||||
@@ -10,16 +10,9 @@ use DNW\Skills\Player;
|
|||||||
use DNW\Skills\Team;
|
use DNW\Skills\Team;
|
||||||
use DNW\Skills\TrueSkill\FactorGraphTrueSkillCalculator;
|
use DNW\Skills\TrueSkill\FactorGraphTrueSkillCalculator;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
use PHPUnit\Framework\Attributes\CoversClass;
|
|
||||||
use PHPUnit\Framework\Attributes\CoversNothing;
|
use PHPUnit\Framework\Attributes\CoversNothing;
|
||||||
use PHPUnit\Framework\Attributes\UsesClass;
|
|
||||||
|
|
||||||
#[CoversClass(FactorGraphTrueSkillCalculator::class)]
|
final class FactorGraphTrueSkillCalculatorTest extends TestCase
|
||||||
#[UsesClass(\DNW\Skills\Numerics\Range::class)]
|
|
||||||
#[UsesClass(\DNW\Skills\PlayersRange::class)]
|
|
||||||
#[UsesClass(\DNW\Skills\SkillCalculator::class)]
|
|
||||||
#[UsesClass(\DNW\Skills\TeamsRange::class)]
|
|
||||||
class FactorGraphTrueSkillCalculatorTest extends TestCase
|
|
||||||
{
|
{
|
||||||
#[CoversNothing]
|
#[CoversNothing]
|
||||||
public function testMicrosoftResearchExample(): void
|
public function testMicrosoftResearchExample(): void
|
||||||
@@ -75,6 +68,7 @@ class FactorGraphTrueSkillCalculatorTest extends TestCase
|
|||||||
TrueSkillCalculatorTests::testPartialPlayScenarios($this, $calculator);
|
TrueSkillCalculatorTests::testPartialPlayScenarios($this, $calculator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[CoversNothing]
|
||||||
public function testMethodisSupported(): void
|
public function testMethodisSupported(): void
|
||||||
{
|
{
|
||||||
$calculator = new FactorGraphTrueSkillCalculator();
|
$calculator = new FactorGraphTrueSkillCalculator();
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ use DNW\Skills\SkillCalculator;
|
|||||||
use DNW\Skills\Team;
|
use DNW\Skills\Team;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
class TrueSkillCalculatorTests
|
final class TrueSkillCalculatorTests
|
||||||
{
|
{
|
||||||
private const float ERROR_TOLERANCE_TRUESKILL = 0.085;
|
private const float ERROR_TOLERANCE_TRUESKILL = 0.085;
|
||||||
|
|
||||||
@@ -811,15 +811,15 @@ class TrueSkillCalculatorTests
|
|||||||
|
|
||||||
private static function sixteenTeamsOfOneNotDrawn(TestCase $testClass, SkillCalculator $calculator): void
|
private static function sixteenTeamsOfOneNotDrawn(TestCase $testClass, SkillCalculator $calculator): void
|
||||||
{
|
{
|
||||||
$player1 = new Player(1);
|
$player1 = new Player(1);
|
||||||
$player2 = new Player(2);
|
$player2 = new Player(2);
|
||||||
$player3 = new Player(3);
|
$player3 = new Player(3);
|
||||||
$player4 = new Player(4);
|
$player4 = new Player(4);
|
||||||
$player5 = new Player(5);
|
$player5 = new Player(5);
|
||||||
$player6 = new Player(6);
|
$player6 = new Player(6);
|
||||||
$player7 = new Player(7);
|
$player7 = new Player(7);
|
||||||
$player8 = new Player(8);
|
$player8 = new Player(8);
|
||||||
$player9 = new Player(9);
|
$player9 = new Player(9);
|
||||||
$player10 = new Player(10);
|
$player10 = new Player(10);
|
||||||
$player11 = new Player(11);
|
$player11 = new Player(11);
|
||||||
$player12 = new Player(12);
|
$player12 = new Player(12);
|
||||||
@@ -830,15 +830,15 @@ class TrueSkillCalculatorTests
|
|||||||
|
|
||||||
$gameInfo = new GameInfo();
|
$gameInfo = new GameInfo();
|
||||||
|
|
||||||
$team1 = new Team($player1, $gameInfo->getDefaultRating());
|
$team1 = new Team($player1, $gameInfo->getDefaultRating());
|
||||||
$team2 = new Team($player2, $gameInfo->getDefaultRating());
|
$team2 = new Team($player2, $gameInfo->getDefaultRating());
|
||||||
$team3 = new Team($player3, $gameInfo->getDefaultRating());
|
$team3 = new Team($player3, $gameInfo->getDefaultRating());
|
||||||
$team4 = new Team($player4, $gameInfo->getDefaultRating());
|
$team4 = new Team($player4, $gameInfo->getDefaultRating());
|
||||||
$team5 = new Team($player5, $gameInfo->getDefaultRating());
|
$team5 = new Team($player5, $gameInfo->getDefaultRating());
|
||||||
$team6 = new Team($player6, $gameInfo->getDefaultRating());
|
$team6 = new Team($player6, $gameInfo->getDefaultRating());
|
||||||
$team7 = new Team($player7, $gameInfo->getDefaultRating());
|
$team7 = new Team($player7, $gameInfo->getDefaultRating());
|
||||||
$team8 = new Team($player8, $gameInfo->getDefaultRating());
|
$team8 = new Team($player8, $gameInfo->getDefaultRating());
|
||||||
$team9 = new Team($player9, $gameInfo->getDefaultRating());
|
$team9 = new Team($player9, $gameInfo->getDefaultRating());
|
||||||
$team10 = new Team($player10, $gameInfo->getDefaultRating());
|
$team10 = new Team($player10, $gameInfo->getDefaultRating());
|
||||||
$team11 = new Team($player11, $gameInfo->getDefaultRating());
|
$team11 = new Team($player11, $gameInfo->getDefaultRating());
|
||||||
$team12 = new Team($player12, $gameInfo->getDefaultRating());
|
$team12 = new Team($player12, $gameInfo->getDefaultRating());
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ use PHPUnit\Framework\Attributes\UsesClass;
|
|||||||
#[CoversClass(TruncatedGaussianCorrectionFunctions::class)]
|
#[CoversClass(TruncatedGaussianCorrectionFunctions::class)]
|
||||||
#[UsesClass(BasicMath::class)]
|
#[UsesClass(BasicMath::class)]
|
||||||
#[UsesClass(GaussianDistribution::class)]
|
#[UsesClass(GaussianDistribution::class)]
|
||||||
class TruncatedGaussianCorrectionFunctionsTest extends TestCase
|
final class TruncatedGaussianCorrectionFunctionsTest extends TestCase
|
||||||
{
|
{
|
||||||
public function testvGreaterThan(): void
|
public function testvGreaterThan(): void
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -6,11 +6,9 @@ namespace DNW\Skills\Tests\TrueSkill;
|
|||||||
|
|
||||||
use DNW\Skills\TrueSkill\TwoPlayerTrueSkillCalculator;
|
use DNW\Skills\TrueSkill\TwoPlayerTrueSkillCalculator;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
use PHPUnit\Framework\Attributes\CoversClass;
|
|
||||||
use PHPUnit\Framework\Attributes\CoversNothing;
|
use PHPUnit\Framework\Attributes\CoversNothing;
|
||||||
|
|
||||||
#[CoversClass(TwoPlayerTrueSkillCalculator::class)]
|
final class TwoPlayerTrueSkillCalculatorTest extends TestCase
|
||||||
class TwoPlayerTrueSkillCalculatorTest extends TestCase
|
|
||||||
{
|
{
|
||||||
#[CoversNothing]
|
#[CoversNothing]
|
||||||
public function testTwoPlayerTrueSkillCalculator(): void
|
public function testTwoPlayerTrueSkillCalculator(): void
|
||||||
|
|||||||
@@ -6,11 +6,9 @@ namespace DNW\Skills\Tests\TrueSkill;
|
|||||||
|
|
||||||
use DNW\Skills\TrueSkill\TwoTeamTrueSkillCalculator;
|
use DNW\Skills\TrueSkill\TwoTeamTrueSkillCalculator;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
use PHPUnit\Framework\Attributes\CoversClass;
|
|
||||||
use PHPUnit\Framework\Attributes\CoversNothing;
|
use PHPUnit\Framework\Attributes\CoversNothing;
|
||||||
|
|
||||||
#[CoversClass(TwoTeamTrueSkillCalculator::class)]
|
final class TwoTeamTrueSkillCalculatorTest extends TestCase
|
||||||
class TwoTeamTrueSkillCalculatorTest extends TestCase
|
|
||||||
{
|
{
|
||||||
#[CoversNothing]
|
#[CoversNothing]
|
||||||
public function testTwoTeamTrueSkillCalculator(): void
|
public function testTwoTeamTrueSkillCalculator(): void
|
||||||
|
|||||||
Reference in New Issue
Block a user