mirror of
https://github.com/furyfire/trueskill.git
synced 2025-01-15 17:37:39 +00:00
Compare commits
5 Commits
23fc14af0a
...
c18ccd38e2
Author | SHA1 | Date | |
---|---|---|---|
c18ccd38e2 | |||
3dddfc05db | |||
968c78d989 | |||
769514b38e | |||
36dea4ea03 |
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,6 +1,6 @@
|
||||
.vscode
|
||||
vendor
|
||||
.phpunit.cache
|
||||
.*.cache/
|
||||
*.phar
|
||||
.phpdoc/
|
||||
output/
|
53
.phpcs.xml
Normal file
53
.phpcs.xml
Normal file
@ -0,0 +1,53 @@
|
||||
<?xml version="1.0"?>
|
||||
<ruleset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="PHP_CodeSniffer" xsi:noNamespaceSchemaLocation="phpcs.xsd">
|
||||
<description>Coding standard</description>
|
||||
|
||||
<file>src/</file>
|
||||
<file>tests/</file>
|
||||
<file>benchmark/</file>
|
||||
|
||||
|
||||
<rule ref="PSR1">
|
||||
<exclude name="Generic.Files.LineLength"/>
|
||||
</rule>
|
||||
<rule ref="PSR2"></rule>
|
||||
<rule ref="PSR12"></rule>
|
||||
|
||||
<rule ref="Generic">
|
||||
<exclude name="Generic.WhiteSpace.DisallowSpaceIndent.SpacesUsed"/>
|
||||
<exclude name="Generic.Files.LowercasedFilename.NotFound"/>
|
||||
<exclude name="Generic.PHP.ClosingPHPTag.NotFound"/>
|
||||
<exclude name="Generic.Files.EndFileNoNewline.Found"/>
|
||||
<exclude name="Generic.Files.EndFileNoNewline.Found"/>
|
||||
<exclude name="Generic.Arrays.DisallowShortArraySyntax.Found"/>
|
||||
<exclude name="Generic.Functions.OpeningFunctionBraceKernighanRitchie.BraceOnNewLine"/>
|
||||
<exclude name="Generic.Classes.OpeningBraceSameLine.BraceOnNewLine"/>
|
||||
<exclude name="Generic.PHP.LowerCaseConstant.Found"/>
|
||||
<exclude name="Generic.Formatting.SpaceAfterCast"/>
|
||||
<exclude name="Generic.Formatting.MultipleStatementAlignment.NotSameWarning"/>
|
||||
<exclude name="Generic.Commenting.DocComment.MissingShort"/>
|
||||
<exclude name="Generic.NamingConventions.AbstractClassNamePrefix.Missing"/>
|
||||
<exclude name="Generic.CodeAnalysis.ForLoopWithTestFunctionCall.NotAllowed"/>
|
||||
<exclude name="Generic.NamingConventions.InterfaceNameSuffix.Missing"/>
|
||||
<exclude name="Generic.Commenting.Todo.TaskFound"/>
|
||||
<exclude name="Generic.CodeAnalysis.UnusedFunctionParameter.FoundInImplementedInterfaceAfterLastUse"/>
|
||||
<exclude name="Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClassAfterLastUsed"/>
|
||||
<exclude name="Generic.CodeAnalysis.UnusedFunctionParameter.FoundInImplementedInterfaceAfterLastUsed"/>
|
||||
<exclude name="Generic.Formatting.SpaceBeforeCast.NoSpace"/>
|
||||
<exclude name="Generic.CodeAnalysis.UselessOverridingMethod.Found"/>
|
||||
<exclude name="Squiz.Functions.MultiLineFunctionDeclaration.NewlineBeforeOpenBrace"/>
|
||||
</rule>
|
||||
|
||||
<!-- Ban some functions -->
|
||||
<rule ref="Generic.PHP.ForbiddenFunctions">
|
||||
<properties>
|
||||
<property name="forbiddenFunctions" type="array">
|
||||
<element key="sizeof" value="count"/>
|
||||
<element key="delete" value="unset"/>
|
||||
<element key="print" value="echo"/>
|
||||
<element key="is_null" value="null"/>
|
||||
<element key="create_function" value="null"/>
|
||||
</property>
|
||||
</properties>
|
||||
</rule>
|
||||
</ruleset>
|
13
.phplint.yml
Normal file
13
.phplint.yml
Normal file
@ -0,0 +1,13 @@
|
||||
path:
|
||||
- src/
|
||||
- tests/
|
||||
- benchmark/
|
||||
jobs: 10
|
||||
extensions:
|
||||
- php
|
||||
exclude:
|
||||
- vendor
|
||||
warning: true
|
||||
memory-limit: -1
|
||||
no-cache: true
|
||||
log-junit: "output/lint.xml"
|
@ -12,12 +12,4 @@ pipeline:
|
||||
image: composer
|
||||
commands:
|
||||
- composer install
|
||||
- composer analyze
|
||||
test:
|
||||
image: php:cli-bookworm
|
||||
commands:
|
||||
- vendor/bin/phpunit tests
|
||||
# document:
|
||||
# image: phpdoc/phpdoc
|
||||
# commands:
|
||||
# - phpdoc
|
||||
- vendor/bin/phpunit tests
|
144
benchmark/BasicBench.php
Normal file
144
benchmark/BasicBench.php
Normal file
@ -0,0 +1,144 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DNW\Skills\Benchmark;
|
||||
|
||||
use DNW\Skills\TrueSkill\TwoPlayerTrueSkillCalculator;
|
||||
use DNW\Skills\TrueSkill\TwoTeamTrueSkillCalculator;
|
||||
use DNW\Skills\TrueSkill\FactorGraphTrueSkillCalculator;
|
||||
use DNW\Skills\GameInfo;
|
||||
use DNW\Skills\Player;
|
||||
use DNW\Skills\Team;
|
||||
use DNW\Skills\Teams;
|
||||
|
||||
class BasicBench
|
||||
{
|
||||
/**
|
||||
* To benchmark performance when using TwoPlayerTrueSkillCalculator
|
||||
*
|
||||
* @Revs(20)
|
||||
* @Iterations(20)
|
||||
*/
|
||||
public function benchBasic2PlayersUsingTwoPlayerTrueSkillCalculator(): void
|
||||
{
|
||||
$gameInfo = new GameInfo();
|
||||
|
||||
$p1 = new Player("Winner");
|
||||
$p2 = new Player("Average");
|
||||
|
||||
$team1 = new Team($p1, $gameInfo->getDefaultRating());
|
||||
$team2 = new Team($p2, $gameInfo->getDefaultRating());
|
||||
|
||||
for ($i = 0; $i < 10; $i++) {
|
||||
$teams = Teams::concat($team1, $team2);
|
||||
|
||||
$calculator = new TwoPlayerTrueSkillCalculator();
|
||||
|
||||
$newRatings = $calculator->calculateNewRatings($gameInfo, $teams, [1, 2]);
|
||||
|
||||
$team1 = new Team($p1, $newRatings->getRating($p1));
|
||||
$team2 = new Team($p2, $newRatings->getRating($p2));
|
||||
|
||||
$newRatings->getRating($p1)->getConservativeRating();
|
||||
$newRatings->getRating($p2)->getConservativeRating();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* To benchmark performance when using TwoTeamTrueSkillCalculator for just two players in two teams
|
||||
*
|
||||
* @Revs(20)
|
||||
* @Iterations(20)
|
||||
*/
|
||||
public function benchBasic2PlayersUsingTwoTeamTrueSkillCalculator(): void
|
||||
{
|
||||
$gameInfo = new GameInfo();
|
||||
|
||||
$p1 = new Player("Winner");
|
||||
$p2 = new Player("Average");
|
||||
|
||||
$team1 = new Team($p1, $gameInfo->getDefaultRating());
|
||||
$team2 = new Team($p2, $gameInfo->getDefaultRating());
|
||||
|
||||
for ($i = 0; $i < 10; $i++) {
|
||||
$teams = Teams::concat($team1, $team2);
|
||||
|
||||
$calculator = new TwoTeamTrueSkillCalculator();
|
||||
|
||||
$newRatings = $calculator->calculateNewRatings($gameInfo, $teams, [1, 2]);
|
||||
|
||||
$team1 = new Team($p1, $newRatings->getRating($p1));
|
||||
$team2 = new Team($p2, $newRatings->getRating($p2));
|
||||
|
||||
$newRatings->getRating($p1)->getConservativeRating();
|
||||
$newRatings->getRating($p2)->getConservativeRating();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* To benchmark performance when using FactorGraphTrueSkillCalculator for just two players in two teams
|
||||
*
|
||||
* @Revs(20)
|
||||
* @Iterations(20)
|
||||
*/
|
||||
public function benchBasic2PlayersUsingFactorGraphTrueSkillCalculator(): void
|
||||
{
|
||||
$gameInfo = new GameInfo();
|
||||
|
||||
$p1 = new Player("Winner");
|
||||
$p2 = new Player("Average");
|
||||
|
||||
$team1 = new Team($p1, $gameInfo->getDefaultRating());
|
||||
$team2 = new Team($p2, $gameInfo->getDefaultRating());
|
||||
|
||||
for ($i = 0; $i < 10; $i++) {
|
||||
$teams = Teams::concat($team1, $team2);
|
||||
|
||||
$calculator = new FactorGraphTrueSkillCalculator();
|
||||
|
||||
$newRatings = $calculator->calculateNewRatings($gameInfo, $teams, [1, 2]);
|
||||
|
||||
$team1 = new Team($p1, $newRatings->getRating($p1));
|
||||
$team2 = new Team($p2, $newRatings->getRating($p2));
|
||||
|
||||
$newRatings->getRating($p1)->getConservativeRating();
|
||||
$newRatings->getRating($p2)->getConservativeRating();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* To benchmark performance when using FactorGraphTrueSkillCalculator with 3 players in 3 teams
|
||||
*
|
||||
* @Revs(20)
|
||||
* @Iterations(20)
|
||||
*/
|
||||
public function bench3Teams(): void
|
||||
{
|
||||
$gameInfo = new GameInfo();
|
||||
|
||||
$p1 = new Player("Winner");
|
||||
$p2 = new Player("Average");
|
||||
$p3 = new Player("Looser");
|
||||
|
||||
$team1 = new Team($p1, $gameInfo->getDefaultRating());
|
||||
$team2 = new Team($p2, $gameInfo->getDefaultRating());
|
||||
$team3 = new Team($p3, $gameInfo->getDefaultRating());
|
||||
|
||||
for ($i = 0; $i < 10; $i++) {
|
||||
$teams = Teams::concat($team1, $team2, $team3);
|
||||
|
||||
$calculator = new FactorGraphTrueSkillCalculator();
|
||||
|
||||
$newRatings = $calculator->calculateNewRatings($gameInfo, $teams, [1, 2, 3]);
|
||||
|
||||
$team1 = new Team($p1, $newRatings->getRating($p1));
|
||||
$team2 = new Team($p2, $newRatings->getRating($p2));
|
||||
$team3 = new Team($p3, $newRatings->getRating($p3));
|
||||
|
||||
$newRatings->getRating($p1)->getConservativeRating();
|
||||
$newRatings->getRating($p2)->getConservativeRating();
|
||||
$newRatings->getRating($p3)->getConservativeRating();
|
||||
}
|
||||
}
|
||||
}
|
@ -6,10 +6,10 @@
|
||||
"php": "^8.2"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^10",
|
||||
"phpstan/phpstan": "^1",
|
||||
"squizlabs/php_codesniffer": "*",
|
||||
"vimeo/psalm": "^5.14"
|
||||
"phpstan/phpstan": "^1.0",
|
||||
"vimeo/psalm": "^5.21.1",
|
||||
"phpmetrics/phpmetrics": "^3.0-dev",
|
||||
"phpunit/phpunit": "^10.5"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
@ -22,16 +22,26 @@
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"test": "vendor/bin/phpunit tests --display-warnings",
|
||||
"test-coverage": "vendor/bin/phpunit tests --testdox --coverage-filter src --coverage-html output/coverage --coverage-text --testdox-html output/test.html --log-junit output/test.xml",
|
||||
"document": "phpDocumentor --setting=graphs.enabled=true",
|
||||
"analyze": [
|
||||
"test": "phpunit",
|
||||
"document": "phpDocumentor",
|
||||
"benchmark": "phpbench run --report=default --output=build-artifact",
|
||||
"metrics": "vendor/bin/phpmetrics --config=phpmetrics.json",
|
||||
"lint": [
|
||||
"phplint",
|
||||
"phpcs"
|
||||
],
|
||||
"static": [
|
||||
"@analyze-phpstan",
|
||||
"@analyze-psalm",
|
||||
"@analyze-phpcs"
|
||||
"@analyze-psalm"
|
||||
],
|
||||
"analyze-phpstan":"vendor/bin/phpstan analyze --error-format=raw",
|
||||
"analyze-psalm": "vendor/bin/psalm --no-cache",
|
||||
"analyze-phpcs": "vendor/bin/phpcs --report=emacs --standard=PSR1,PSR2,PSR12 --exclude=Generic.Files.LineLength src tests"
|
||||
"all": [
|
||||
"@test",
|
||||
"@document",
|
||||
"@benchmark",
|
||||
"@lint",
|
||||
"@static"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
162
composer.lock
generated
162
composer.lock
generated
@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "667bb75c25a72b3d35f64ada9d9d9e0d",
|
||||
"content-hash": "129eec96c91a9ee234640b9d6bcd0f43",
|
||||
"packages": [],
|
||||
"packages-dev": [
|
||||
{
|
||||
@ -1082,6 +1082,82 @@
|
||||
},
|
||||
"time": "2024-01-11T11:49:22+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpmetrics/phpmetrics",
|
||||
"version": "v3.0.0rc5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpmetrics/PhpMetrics.git",
|
||||
"reference": "7a4ee5d6a8233f449fb9125ad586d3880c8a1b2f"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpmetrics/PhpMetrics/zipball/7a4ee5d6a8233f449fb9125ad586d3880c8a1b2f",
|
||||
"reference": "7a4ee5d6a8233f449fb9125ad586d3880c8a1b2f",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-tokenizer": "*",
|
||||
"nikic/php-parser": "^4",
|
||||
"php": ">=8.1"
|
||||
},
|
||||
"replace": {
|
||||
"halleck45/php-metrics": "*",
|
||||
"halleck45/phpmetrics": "*"
|
||||
},
|
||||
"require-dev": {
|
||||
"phake/phake": "^4.4.0",
|
||||
"phpstan/extension-installer": "^1.3",
|
||||
"phpstan/phpstan": "^1.10",
|
||||
"phpstan/phpstan-deprecation-rules": "^1.1",
|
||||
"phpstan/phpstan-phpunit": "^1.3",
|
||||
"phpstan/phpstan-strict-rules": "^1.5",
|
||||
"phpunit/phpunit": "^10.3",
|
||||
"roave/security-advisories": "dev-latest",
|
||||
"sebastian/comparator": ">=5.0.0",
|
||||
"squizlabs/php_codesniffer": "^3.7",
|
||||
"symfony/dom-crawler": "^6.3",
|
||||
"vimeo/psalm": "^5.15"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-dom": "To allow XML parsing and report results.",
|
||||
"ext-yaml": "To allow yaml parsing of configuration files."
|
||||
},
|
||||
"bin": [
|
||||
"bin/phpmetrics"
|
||||
],
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Hal\\": "src/Hal"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Jean-François Lépine",
|
||||
"email": "lepinejeanfrancois@yahoo.fr",
|
||||
"homepage": "http://www.lepine.pro",
|
||||
"role": "Copyright Holder"
|
||||
}
|
||||
],
|
||||
"description": "Static analyzer tool for PHP : Coupling, Cyclomatic complexity, Maintainability Index, Halstead's metrics... and more !",
|
||||
"homepage": "http://www.phpmetrics.org",
|
||||
"keywords": [
|
||||
"analysis",
|
||||
"qa",
|
||||
"quality",
|
||||
"testing"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/PhpMetrics/PhpMetrics/issues",
|
||||
"source": "https://github.com/phpmetrics/PhpMetrics/tree/v3.0.0rc5"
|
||||
},
|
||||
"time": "2024-01-17T10:59:12+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpstan/phpdoc-parser",
|
||||
"version": "1.25.0",
|
||||
@ -2694,86 +2770,6 @@
|
||||
],
|
||||
"time": "2023-11-14T14:08:51+00:00"
|
||||
},
|
||||
{
|
||||
"name": "squizlabs/php_codesniffer",
|
||||
"version": "3.8.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/PHPCSStandards/PHP_CodeSniffer.git",
|
||||
"reference": "14f5fff1e64118595db5408e946f3a22c75807f7"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/14f5fff1e64118595db5408e946f3a22c75807f7",
|
||||
"reference": "14f5fff1e64118595db5408e946f3a22c75807f7",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-simplexml": "*",
|
||||
"ext-tokenizer": "*",
|
||||
"ext-xmlwriter": "*",
|
||||
"php": ">=5.4.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.3.4"
|
||||
},
|
||||
"bin": [
|
||||
"bin/phpcbf",
|
||||
"bin/phpcs"
|
||||
],
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "3.x-dev"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"BSD-3-Clause"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Greg Sherwood",
|
||||
"role": "Former lead"
|
||||
},
|
||||
{
|
||||
"name": "Juliette Reinders Folmer",
|
||||
"role": "Current lead"
|
||||
},
|
||||
{
|
||||
"name": "Contributors",
|
||||
"homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer/graphs/contributors"
|
||||
}
|
||||
],
|
||||
"description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.",
|
||||
"homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer",
|
||||
"keywords": [
|
||||
"phpcs",
|
||||
"standards",
|
||||
"static analysis"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/PHPCSStandards/PHP_CodeSniffer/issues",
|
||||
"security": "https://github.com/PHPCSStandards/PHP_CodeSniffer/security/policy",
|
||||
"source": "https://github.com/PHPCSStandards/PHP_CodeSniffer",
|
||||
"wiki": "https://github.com/PHPCSStandards/PHP_CodeSniffer/wiki"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/PHPCSStandards",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/jrfnl",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://opencollective.com/php_codesniffer",
|
||||
"type": "open_collective"
|
||||
}
|
||||
],
|
||||
"time": "2024-01-11T20:47:48+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v7.0.3",
|
||||
@ -3649,7 +3645,9 @@
|
||||
],
|
||||
"aliases": [],
|
||||
"minimum-stability": "stable",
|
||||
"stability-flags": [],
|
||||
"stability-flags": {
|
||||
"phpmetrics/phpmetrics": 20
|
||||
},
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false,
|
||||
"platform": {
|
||||
|
11
phpbench.json
Normal file
11
phpbench.json
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"runner.bootstrap": "vendor/autoload.php",
|
||||
"runner.path": "benchmark/",
|
||||
"report.outputs": {
|
||||
"build-artifact": {
|
||||
"renderer": "html",
|
||||
"path": "output/benchmark.html",
|
||||
"title": "Benchmarking"
|
||||
}
|
||||
}
|
||||
}
|
20
phpmetrics.json
Normal file
20
phpmetrics.json
Normal file
@ -0,0 +1,20 @@
|
||||
{
|
||||
"composer": true,
|
||||
"includes": [
|
||||
"src"
|
||||
],
|
||||
"excludes": [
|
||||
"tests"
|
||||
],
|
||||
"report": {
|
||||
"html": "output/metrics/"
|
||||
},
|
||||
"plugins": {
|
||||
"git": {
|
||||
"binary": "git"
|
||||
},
|
||||
"junit": {
|
||||
"file": "output/test.xml"
|
||||
}
|
||||
}
|
||||
}
|
@ -3,3 +3,4 @@ parameters:
|
||||
paths:
|
||||
- src
|
||||
- tests
|
||||
- benchmark
|
||||
|
13
phpunit.xml
13
phpunit.xml
@ -1,6 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" backupGlobals="false" bootstrap="vendor/autoload.php" colors="true" processIsolation="false" stopOnFailure="false" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/10.2/phpunit.xsd" cacheDirectory=".phpunit.cache" backupStaticProperties="false">
|
||||
<coverage/>
|
||||
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" backupGlobals="false" bootstrap="vendor/autoload.php" colors="true" processIsolation="false" stopOnFailure="false" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/10.2/phpunit.xsd" cacheDirectory=".phpunit.cache" backupStaticProperties="false" displayDetailsOnTestsThatTriggerWarnings="true">
|
||||
<testsuites>
|
||||
<testsuite name="PHPSkills Test Suite">
|
||||
<directory>./tests/</directory>
|
||||
@ -11,4 +10,14 @@
|
||||
<directory suffix=".php">src/</directory>
|
||||
</include>
|
||||
</source>
|
||||
<logging>
|
||||
<junit outputFile="output/test/junit.xml"/>
|
||||
<testdoxHtml outputFile="output/test/index.html"/>
|
||||
</logging>
|
||||
|
||||
<coverage>
|
||||
<report>
|
||||
<html outputDirectory="output/coverage" />
|
||||
</report>
|
||||
</coverage>
|
||||
</phpunit>
|
||||
|
@ -11,6 +11,7 @@
|
||||
<projectFiles>
|
||||
<directory name="src" />
|
||||
<directory name="tests" />
|
||||
<directory name="benchmark" />
|
||||
<ignoreFiles>
|
||||
<directory name="vendor" />
|
||||
</ignoreFiles>
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DNW\Skills\FactorGraphs;
|
||||
|
||||
use DNW\Skills\Guard;
|
||||
@ -94,6 +96,7 @@ abstract class Factor implements \Stringable
|
||||
|
||||
/**
|
||||
* Sends the ith message to the marginal and returns the log-normalization constant
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function sendMessageIndex(int $messageIndex): float|int
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DNW\Skills\FactorGraphs;
|
||||
|
||||
class FactorGraph
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DNW\Skills\FactorGraphs;
|
||||
|
||||
use DNW\Skills\FactorGraphs\ScheduleSequence;
|
||||
@ -42,6 +44,7 @@ abstract class FactorGraphLayer
|
||||
|
||||
/**
|
||||
* This reference is still needed
|
||||
*
|
||||
* @return array<int,array<int,object>>
|
||||
*/
|
||||
public function &getOutputVariablesGroups(): array
|
||||
@ -82,11 +85,11 @@ abstract class FactorGraphLayer
|
||||
|
||||
public function createPriorSchedule(): ?ScheduleSequence
|
||||
{
|
||||
return null;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
public function createPosteriorSchedule(): ?ScheduleSequence
|
||||
{
|
||||
return null;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DNW\Skills\FactorGraphs;
|
||||
|
||||
/**
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DNW\Skills\FactorGraphs;
|
||||
|
||||
class KeyedVariable extends Variable
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DNW\Skills\FactorGraphs;
|
||||
|
||||
use DNW\Skills\Numerics\GaussianDistribution;
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DNW\Skills\FactorGraphs;
|
||||
|
||||
abstract class Schedule implements \Stringable
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DNW\Skills\FactorGraphs;
|
||||
|
||||
class ScheduleLoop extends Schedule
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DNW\Skills\FactorGraphs;
|
||||
|
||||
class ScheduleSequence extends Schedule
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DNW\Skills\FactorGraphs;
|
||||
|
||||
class ScheduleStep extends Schedule
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DNW\Skills\FactorGraphs;
|
||||
|
||||
use DNW\Skills\Numerics\GaussianDistribution;
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DNW\Skills\FactorGraphs;
|
||||
|
||||
class VariableFactory
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DNW\Skills;
|
||||
|
||||
/**
|
||||
@ -23,7 +25,8 @@ class GameInfo
|
||||
private float $beta = self::DEFAULT_BETA,
|
||||
private float $dynamicsFactor = self::DEFAULT_DYNAMICS_FACTOR,
|
||||
private float $drawProbability = self::DEFAULT_DRAW_PROBABILITY
|
||||
) {
|
||||
)
|
||||
{
|
||||
}
|
||||
|
||||
public function getInitialMean(): float
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DNW\Skills;
|
||||
|
||||
use Exception;
|
||||
@ -13,7 +15,7 @@ class Guard
|
||||
{
|
||||
public static function argumentNotNull(mixed $value, string $parameterName): void
|
||||
{
|
||||
if ($value == null) {
|
||||
if ($value == NULL) {
|
||||
throw new Exception($parameterName . ' can not be null');
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DNW\Skills;
|
||||
|
||||
/**
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DNW\Skills;
|
||||
|
||||
/**
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DNW\Skills;
|
||||
|
||||
interface ISupportPartialUpdate
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DNW\Skills\Numerics;
|
||||
|
||||
/**
|
||||
@ -13,7 +15,8 @@ class BasicMath
|
||||
/**
|
||||
* Squares the input (x^2 = x * x)
|
||||
*
|
||||
* @param float $x Value to square (x)
|
||||
* @param float $x Value to square (x)
|
||||
*
|
||||
* @return float The squared value (x^2)
|
||||
*/
|
||||
public static function square($x): float
|
||||
@ -24,8 +27,9 @@ class BasicMath
|
||||
/**
|
||||
* Sums the items in $itemsToSum
|
||||
*
|
||||
* @param mixed[] $itemsToSum The items to sum,
|
||||
* @param \Closure $callback The function to apply to each array element before summing.
|
||||
* @param mixed[] $itemsToSum The items to sum,
|
||||
* @param \Closure $callback The function to apply to each array element before summing.
|
||||
*
|
||||
* @return float The sum.
|
||||
*/
|
||||
public static function sum(array $itemsToSum, \Closure $callback): float
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DNW\Skills\Numerics;
|
||||
|
||||
class DiagonalMatrix extends Matrix
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DNW\Skills\Numerics;
|
||||
|
||||
/**
|
||||
@ -198,7 +200,8 @@ class GaussianDistribution implements \Stringable
|
||||
-1.523e-15,
|
||||
-9.4e-17,
|
||||
1.21e-16,
|
||||
-2.8e-17, ];
|
||||
-2.8e-17,
|
||||
];
|
||||
|
||||
$ncof = count($coefficients);
|
||||
$d = 0.0;
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DNW\Skills\Numerics;
|
||||
|
||||
class IdentityMatrix extends DiagonalMatrix
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DNW\Skills\Numerics;
|
||||
|
||||
use Exception;
|
||||
@ -11,7 +13,7 @@ class Matrix
|
||||
/**
|
||||
* @param array<int,array<int,float>> $matrixRowData
|
||||
*/
|
||||
public function __construct(private int $rowCount = 0, private int $columnCount = 0, private array $matrixRowData = array())
|
||||
public function __construct(private int $rowCount = 0, private int $columnCount = 0, private array $matrixRowData = [])
|
||||
{
|
||||
}
|
||||
|
||||
@ -307,7 +309,7 @@ class Matrix
|
||||
public function equals(Matrix $otherMatrix): bool
|
||||
{
|
||||
if (($this->rowCount != $otherMatrix->getRowCount()) || ($this->columnCount != $otherMatrix->getColumnCount())) {
|
||||
return false;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
for ($currentRow = 0; $currentRow < $this->rowCount; $currentRow++) {
|
||||
@ -319,11 +321,11 @@ class Matrix
|
||||
);
|
||||
|
||||
if ($delta > self::ERROR_TOLERANCE) {
|
||||
return false;
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DNW\Skills\Numerics;
|
||||
|
||||
// The whole purpose of this class is to make the code for the SkillCalculator(s)
|
||||
|
@ -1,12 +1,14 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DNW\Skills\Numerics;
|
||||
|
||||
class SquareMatrix extends Matrix
|
||||
{
|
||||
public function __construct(float|int ...$allValues)
|
||||
{
|
||||
$rows = (int) sqrt(count($allValues));
|
||||
$rows = (int)sqrt(count($allValues));
|
||||
$cols = $rows;
|
||||
|
||||
$matrixData = [];
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DNW\Skills\Numerics;
|
||||
|
||||
class Vector extends Matrix
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DNW\Skills;
|
||||
|
||||
/**
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DNW\Skills;
|
||||
|
||||
class PartialPlay
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DNW\Skills;
|
||||
|
||||
/**
|
||||
@ -26,7 +28,8 @@ class Player implements ISupportPartialPlay, ISupportPartialUpdate, \Stringable
|
||||
private mixed $Id,
|
||||
float $partialPlayPercentage = self::DEFAULT_PARTIAL_PLAY_PERCENTAGE,
|
||||
float $partialUpdatePercentage = self::DEFAULT_PARTIAL_UPDATE_PERCENTAGE
|
||||
) {
|
||||
)
|
||||
{
|
||||
// If they don't want to give a player an id, that's ok...
|
||||
Guard::argumentInRangeInclusive($partialPlayPercentage, 0.0, 1.0, 'partialPlayPercentage');
|
||||
Guard::argumentInRangeInclusive($partialUpdatePercentage, 0, 1.0, 'partialUpdatePercentage');
|
||||
@ -60,6 +63,6 @@ class Player implements ISupportPartialPlay, ISupportPartialUpdate, \Stringable
|
||||
|
||||
public function __toString(): string
|
||||
{
|
||||
return (string) $this->Id;
|
||||
return (string)$this->Id;
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DNW\Skills;
|
||||
|
||||
use DNW\Skills\Numerics\Range;
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DNW\Skills;
|
||||
|
||||
/**
|
||||
@ -10,8 +12,9 @@ class RankSorter
|
||||
/**
|
||||
* Performs an in-place sort of the items in according to the ranks in non-decreasing order.
|
||||
*
|
||||
* @param array<mixed> $teams The items to sort according to the order specified by ranks.
|
||||
* @param array<int> $teamRanks The ranks for each item where 1 is first place.
|
||||
* @param array<mixed> $teams The items to sort according to the order specified by ranks.
|
||||
* @param array<int> $teamRanks The ranks for each item where 1 is first place.
|
||||
*
|
||||
* @return array<int>
|
||||
*/
|
||||
public static function sort(array &$teams, array &$teamRanks): array
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DNW\Skills;
|
||||
|
||||
// Container for a player's rating.
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DNW\Skills;
|
||||
|
||||
class RatingContainer
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DNW\Skills;
|
||||
|
||||
use Exception;
|
||||
@ -13,15 +15,17 @@ abstract class SkillCalculator
|
||||
private int $supportedOptions,
|
||||
private readonly TeamsRange $totalTeamsAllowed,
|
||||
private readonly PlayersRange $playersPerTeamAllowed
|
||||
) {
|
||||
)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates new ratings based on the prior ratings and team ranks.
|
||||
*
|
||||
* @param GameInfo $gameInfo Parameters for the game.
|
||||
* @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 GameInfo $gameInfo Parameters for the game.
|
||||
* @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).
|
||||
*
|
||||
* @return RatingContainer All the players and their new ratings.
|
||||
*/
|
||||
abstract public function calculateNewRatings(
|
||||
@ -33,8 +37,9 @@ abstract class SkillCalculator
|
||||
/**
|
||||
* Calculates the match quality as the likelihood of all teams drawing.
|
||||
*
|
||||
* @param GameInfo $gameInfo Parameters for the game.
|
||||
* @param Team[] $teams A mapping of team players and their ratings.
|
||||
* @param GameInfo $gameInfo Parameters for the game.
|
||||
* @param Team[] $teams A mapping of team players and their ratings.
|
||||
*
|
||||
* @return float The quality of the match between the teams as a percentage (0% = bad, 100% = well matched).
|
||||
*/
|
||||
abstract public function calculateMatchQuality(GameInfo $gameInfo, array $teams): float;
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DNW\Skills;
|
||||
|
||||
class SkillCalculatorSupportedOptions
|
||||
|
@ -1,14 +1,16 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DNW\Skills;
|
||||
|
||||
class Team extends RatingContainer
|
||||
{
|
||||
public function __construct(Player $player = null, Rating $rating = null)
|
||||
public function __construct(Player $player = NULL, Rating $rating = NULL)
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
if (! is_null($player) && ! is_null($rating)) {
|
||||
if ($player && $rating) {
|
||||
$this->addPlayer($player, $rating);
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DNW\Skills;
|
||||
|
||||
class Teams
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DNW\Skills;
|
||||
|
||||
use DNW\Skills\Numerics\Range;
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DNW\Skills\TrueSkill;
|
||||
|
||||
use DNW\Skills\Numerics\GaussianDistribution;
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DNW\Skills\TrueSkill;
|
||||
|
||||
use DNW\Skills\GameInfo;
|
||||
@ -34,7 +36,8 @@ class FactorGraphTrueSkillCalculator extends SkillCalculator
|
||||
GameInfo $gameInfo,
|
||||
array $teams,
|
||||
array $teamRanks
|
||||
): RatingContainer {
|
||||
): RatingContainer
|
||||
{
|
||||
Guard::argumentNotNull($gameInfo, 'gameInfo');
|
||||
$this->validateTeamCountAndPlayersCountPerTeam($teams);
|
||||
|
||||
@ -124,7 +127,9 @@ class FactorGraphTrueSkillCalculator extends SkillCalculator
|
||||
|
||||
/**
|
||||
* Helper function that gets a list of values for all player ratings
|
||||
*
|
||||
* @param Team[] $teamAssignmentsList
|
||||
*
|
||||
* @return int[]
|
||||
*/
|
||||
private static function getPlayerRatingValues(array $teamAssignmentsList, \Closure $playerRatingFunction): array
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DNW\Skills\TrueSkill\Factors;
|
||||
|
||||
use DNW\Skills\FactorGraphs\Factor;
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DNW\Skills\TrueSkill\Factors;
|
||||
|
||||
use DNW\Skills\FactorGraphs\Message;
|
||||
@ -62,11 +64,9 @@ class GaussianGreaterThanFactor extends GaussianFactor
|
||||
$denom = 1.0 - TruncatedGaussianCorrectionFunctions::wExceedsMargin($dOnSqrtC, $epsilsonTimesSqrtC);
|
||||
|
||||
$newPrecision = $c / $denom;
|
||||
$newPrecisionMean = (
|
||||
$d +
|
||||
$newPrecisionMean = ($d +
|
||||
$sqrtC *
|
||||
TruncatedGaussianCorrectionFunctions::vExceedsMargin($dOnSqrtC, $epsilsonTimesSqrtC)
|
||||
) / $denom;
|
||||
TruncatedGaussianCorrectionFunctions::vExceedsMargin($dOnSqrtC, $epsilsonTimesSqrtC)) / $denom;
|
||||
|
||||
$newMarginal = GaussianDistribution::fromPrecisionMean($newPrecisionMean, $newPrecision);
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DNW\Skills\TrueSkill\Factors;
|
||||
|
||||
use DNW\Skills\FactorGraphs\KeyedVariable;
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DNW\Skills\TrueSkill\Factors;
|
||||
|
||||
use DNW\Skills\FactorGraphs\Message;
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DNW\Skills\TrueSkill\Factors;
|
||||
|
||||
use DNW\Skills\FactorGraphs\Message;
|
||||
@ -24,6 +26,7 @@ class GaussianWeightedSumFactor extends GaussianFactor
|
||||
/**
|
||||
* This following is used for convenience, for example, the first entry is [0, 1, 2]
|
||||
* corresponding to v[0] = a1*v[1] + a2*v[2]
|
||||
*
|
||||
* @var array<float[]> $weights
|
||||
*/
|
||||
private array $weights = [];
|
||||
@ -247,7 +250,7 @@ class GaussianWeightedSumFactor extends GaussianFactor
|
||||
$absValue = sprintf('%.2f', \abs($weights[$i])); // 0.00?
|
||||
$result .= $absValue;
|
||||
$result .= '*[';
|
||||
$result .= (string) $variablesToSum[$i];
|
||||
$result .= (string)$variablesToSum[$i];
|
||||
$result .= ']';
|
||||
|
||||
$isLast = ($i === $totalVars - 1);
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DNW\Skills\TrueSkill\Factors;
|
||||
|
||||
use DNW\Skills\FactorGraphs\Message;
|
||||
@ -65,8 +67,7 @@ class GaussianWithinFactor extends GaussianFactor
|
||||
$newPrecision = $c / $denominator;
|
||||
$newPrecisionMean = ($d +
|
||||
$sqrtC *
|
||||
TruncatedGaussianCorrectionFunctions::vWithinMargin($dOnSqrtC, $epsilonTimesSqrtC)
|
||||
) / $denominator;
|
||||
TruncatedGaussianCorrectionFunctions::vWithinMargin($dOnSqrtC, $epsilonTimesSqrtC)) / $denominator;
|
||||
|
||||
$newMarginal = GaussianDistribution::fromPrecisionMean($newPrecisionMean, $newPrecision);
|
||||
$newMessage = GaussianDistribution::divide(
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DNW\Skills\TrueSkill\Layers;
|
||||
|
||||
use DNW\Skills\FactorGraphs\ScheduleLoop;
|
||||
@ -15,7 +17,8 @@ class IteratedTeamDifferencesInnerLayer extends TrueSkillFactorGraphLayer
|
||||
TrueSkillFactorGraph $parentGraph,
|
||||
private readonly TeamPerformancesToTeamPerformanceDifferencesLayer $TeamPerformancesToTeamPerformanceDifferencesLayer,
|
||||
private readonly TeamDifferencesComparisonLayer $TeamDifferencesComparisonLayer
|
||||
) {
|
||||
)
|
||||
{
|
||||
parent::__construct($parentGraph);
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DNW\Skills\TrueSkill\Layers;
|
||||
|
||||
use DNW\Skills\FactorGraphs\ScheduleStep;
|
||||
@ -87,7 +89,7 @@ class PlayerPerformancesToTeamPerformancesLayer extends TrueSkillFactorGraphLaye
|
||||
*/
|
||||
private function createOutputVariable(array $team): Variable
|
||||
{
|
||||
$memberNames = array_map(fn ($currentPlayer) => (string) ($currentPlayer->getKey()), $team);
|
||||
$memberNames = array_map(fn ($currentPlayer) => (string)($currentPlayer->getKey()), $team);
|
||||
|
||||
$teamMemberNames = \implode(', ', $memberNames);
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DNW\Skills\TrueSkill\Layers;
|
||||
|
||||
use DNW\Skills\FactorGraphs\ScheduleStep;
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DNW\Skills\TrueSkill\Layers;
|
||||
|
||||
use DNW\Skills\FactorGraphs\KeyedVariable;
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DNW\Skills\TrueSkill\Layers;
|
||||
|
||||
use DNW\Skills\TrueSkill\DrawMargin;
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DNW\Skills\TrueSkill\Layers;
|
||||
|
||||
use DNW\Skills\FactorGraphs\Variable;
|
||||
@ -30,7 +32,8 @@ class TeamPerformancesToTeamPerformanceDifferencesLayer extends TrueSkillFactorG
|
||||
Variable $strongerTeam,
|
||||
Variable $weakerTeam,
|
||||
Variable $output
|
||||
): GaussianWeightedSumFactor {
|
||||
): GaussianWeightedSumFactor
|
||||
{
|
||||
$teams = [$strongerTeam, $weakerTeam];
|
||||
$weights = [1.0, -1.0];
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DNW\Skills\TrueSkill\Layers;
|
||||
|
||||
use DNW\Skills\FactorGraphs\FactorGraphLayer;
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DNW\Skills\TrueSkill;
|
||||
|
||||
use DNW\Skills\FactorGraphs\FactorGraph;
|
||||
@ -29,9 +31,9 @@ class TrueSkillFactorGraph extends FactorGraph
|
||||
private PlayerPriorValuesToSkillsLayer $priorLayer;
|
||||
|
||||
/**
|
||||
* @param GameInfo $gameInfo Parameters for the game.
|
||||
* @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 GameInfo $gameInfo Parameters for the game.
|
||||
* @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).
|
||||
*/
|
||||
public function __construct(private readonly GameInfo $gameInfo, array $teams, array $teamRanks)
|
||||
{
|
||||
@ -60,11 +62,11 @@ class TrueSkillFactorGraph extends FactorGraph
|
||||
|
||||
public function buildGraph(): void
|
||||
{
|
||||
$lastOutput = null;
|
||||
$lastOutput = NULL;
|
||||
|
||||
$layers = $this->layers;
|
||||
foreach ($layers as $currentLayer) {
|
||||
if ($lastOutput != null) {
|
||||
if ($lastOutput != NULL) {
|
||||
$currentLayer->setInputVariablesGroups($lastOutput);
|
||||
}
|
||||
|
||||
@ -105,7 +107,7 @@ class TrueSkillFactorGraph extends FactorGraph
|
||||
$layers = $this->layers;
|
||||
foreach ($layers as $currentLayer) {
|
||||
$currentPriorSchedule = $currentLayer->createPriorSchedule();
|
||||
if ($currentPriorSchedule != null) {
|
||||
if ($currentPriorSchedule != NULL) {
|
||||
$fullSchedule[] = $currentPriorSchedule;
|
||||
}
|
||||
}
|
||||
@ -114,7 +116,7 @@ class TrueSkillFactorGraph extends FactorGraph
|
||||
|
||||
foreach ($allLayersReverse as $currentLayer) {
|
||||
$currentPosteriorSchedule = $currentLayer->createPosteriorSchedule();
|
||||
if ($currentPosteriorSchedule != null) {
|
||||
if ($currentPosteriorSchedule != NULL) {
|
||||
$fullSchedule[] = $currentPosteriorSchedule;
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DNW\Skills\TrueSkill;
|
||||
|
||||
use DNW\Skills\Numerics\GaussianDistribution;
|
||||
@ -120,8 +122,7 @@ class TruncatedGaussianCorrectionFunctions
|
||||
$vt = self::vWithinMargin($teamPerformanceDifferenceAbsoluteValue, $drawMargin);
|
||||
|
||||
return $vt * $vt +
|
||||
(
|
||||
($drawMargin - $teamPerformanceDifferenceAbsoluteValue)
|
||||
(($drawMargin - $teamPerformanceDifferenceAbsoluteValue)
|
||||
*
|
||||
GaussianDistribution::at(
|
||||
$drawMargin - $teamPerformanceDifferenceAbsoluteValue
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DNW\Skills\TrueSkill;
|
||||
|
||||
use DNW\Skills\GameInfo;
|
||||
@ -35,7 +37,8 @@ class TwoPlayerTrueSkillCalculator extends SkillCalculator
|
||||
GameInfo $gameInfo,
|
||||
array $teams,
|
||||
array $teamRanks
|
||||
): RatingContainer {
|
||||
): RatingContainer
|
||||
{
|
||||
// Basic argument checking
|
||||
Guard::argumentNotNull($gameInfo, 'gameInfo');
|
||||
$this->validateTeamCountAndPlayersCountPerTeam($teams);
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DNW\Skills\TrueSkill;
|
||||
|
||||
use DNW\Skills\GameInfo;
|
||||
@ -68,7 +70,8 @@ class TwoTeamTrueSkillCalculator extends SkillCalculator
|
||||
Team $selfTeam,
|
||||
Team $otherTeam,
|
||||
PairwiseComparison $selfToOtherTeamComparison
|
||||
): void {
|
||||
): void
|
||||
{
|
||||
$drawMargin = DrawMargin::getDrawMarginFromDrawProbability(
|
||||
$gameInfo->getDrawProbability(),
|
||||
$gameInfo->getBeta()
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DNW\Skills\Tests\FactorGraphs;
|
||||
|
||||
use DNW\Skills\FactorGraphs\ScheduleStep;
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DNW\Skills\Tests\FactorGraphs;
|
||||
|
||||
use DNW\Skills\FactorGraphs\Variable;
|
||||
@ -11,8 +13,9 @@ class VariableTest extends TestCase
|
||||
public function test(): void
|
||||
{
|
||||
$gd_prior = new GaussianDistribution();
|
||||
$var = new Variable('dummy', $gd_prior);
|
||||
$var = new Variable('dummy', $gd_prior);
|
||||
$this->assertEquals($gd_prior, $var->getValue());
|
||||
|
||||
$gd_new = new GaussianDistribution();
|
||||
$this->assertEquals($gd_new, $var->getValue());
|
||||
$var->resetToPrior();
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DNW\Skills\Tests;
|
||||
|
||||
use DNW\Skills\Guard;
|
||||
@ -12,7 +14,7 @@ class GuardTest extends TestCase
|
||||
{
|
||||
$this->expectException(Exception::class);
|
||||
$this->expectExceptionMessage('dummy can not be null');
|
||||
Guard::argumentNotNull(null, "dummy");
|
||||
Guard::argumentNotNull(NULL, "dummy");
|
||||
}
|
||||
|
||||
public function testargumentIsValidIndex(): void
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DNW\Skills\Tests\Numerics;
|
||||
|
||||
use DNW\Skills\Numerics\BasicMath;
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DNW\Skills\Tests\Numerics;
|
||||
|
||||
use DNW\Skills\Numerics\BasicMath;
|
||||
@ -39,9 +41,9 @@ class GaussianDistributionTest extends TestCase
|
||||
public function testMultiplication(): void
|
||||
{
|
||||
// I verified this against the formula at http://www.tina-vision.net/tina-knoppix/tina-memo/2003-003.pdf
|
||||
$standardNormal = new GaussianDistribution(0, 1);
|
||||
$standardNormal = new GaussianDistribution(0, 1);
|
||||
$shiftedGaussian = new GaussianDistribution(2, 3);
|
||||
$product = GaussianDistribution::multiply($standardNormal, $shiftedGaussian);
|
||||
$product = GaussianDistribution::multiply($standardNormal, $shiftedGaussian);
|
||||
|
||||
$this->assertEqualsWithDelta(0.2, $product->getMean(), GaussianDistributionTest::ERROR_TOLERANCE);
|
||||
$this->assertEqualsWithDelta(3.0 / sqrt(10), $product->getStandardDeviation(), GaussianDistributionTest::ERROR_TOLERANCE);
|
||||
@ -61,15 +63,15 @@ class GaussianDistributionTest extends TestCase
|
||||
public function testDivision(): void
|
||||
{
|
||||
// Since the multiplication was worked out by hand, we use the same numbers but work backwards
|
||||
$product = new GaussianDistribution(0.2, 3.0 / sqrt(10));
|
||||
$product = new GaussianDistribution(0.2, 3.0 / sqrt(10));
|
||||
$standardNormal = new GaussianDistribution(0, 1);
|
||||
|
||||
$productDividedByStandardNormal = GaussianDistribution::divide($product, $standardNormal);
|
||||
$this->assertEqualsWithDelta(2.0, $productDividedByStandardNormal->getMean(), 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)))));
|
||||
$m4s5 = new GaussianDistribution(4, 5);
|
||||
$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)))));
|
||||
$m4s5 = new GaussianDistribution(4, 5);
|
||||
$product2DividedByM4S5 = GaussianDistribution::divide($product2, $m4s5);
|
||||
$this->assertEqualsWithDelta(6.0, $product2DividedByM4S5->getMean(), GaussianDistributionTest::ERROR_TOLERANCE);
|
||||
$this->assertEqualsWithDelta(7.0, $product2DividedByM4S5->getStandardDeviation(), GaussianDistributionTest::ERROR_TOLERANCE);
|
||||
@ -93,7 +95,7 @@ class GaussianDistributionTest extends TestCase
|
||||
// Verified with Ralf Herbrich's F# implementation
|
||||
$m1s2 = new GaussianDistribution(1, 2);
|
||||
$m3s4 = new GaussianDistribution(3, 4);
|
||||
$lrn = GaussianDistribution::logRatioNormalization($m1s2, $m3s4);
|
||||
$lrn = GaussianDistribution::logRatioNormalization($m1s2, $m3s4);
|
||||
$this->assertEqualsWithDelta(2.6157405972171204, $lrn, GaussianDistributionTest::ERROR_TOLERANCE);
|
||||
}
|
||||
|
||||
@ -101,7 +103,7 @@ class GaussianDistributionTest extends TestCase
|
||||
{
|
||||
// Verified with Ralf Herbrich's F# implementation
|
||||
$standardNormal = new GaussianDistribution(0, 1);
|
||||
$absDiff = GaussianDistribution::absoluteDifference($standardNormal, $standardNormal);
|
||||
$absDiff = GaussianDistribution::absoluteDifference($standardNormal, $standardNormal);
|
||||
$this->assertEqualsWithDelta(0.0, $absDiff, GaussianDistributionTest::ERROR_TOLERANCE);
|
||||
|
||||
$m1s2 = new GaussianDistribution(1, 2);
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DNW\Skills\Tests\Numerics;
|
||||
|
||||
use DNW\Skills\Numerics\IdentityMatrix;
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DNW\Skills\Tests\Numerics;
|
||||
|
||||
use DNW\Skills\Numerics\Range;
|
||||
|
19
tests/PlayerTest.php
Normal file
19
tests/PlayerTest.php
Normal file
@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DNW\Skills\Tests;
|
||||
|
||||
use DNW\Skills\Player;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class PlayerTest extends TestCase
|
||||
{
|
||||
public function test(): void
|
||||
{
|
||||
$p = new Player('dummy', 0.1, 0.2);
|
||||
$this->assertEquals('dummy', (string)$p);
|
||||
$this->assertEquals(0.1, $p->getPartialPlayPercentage());
|
||||
$this->assertEquals(0.2, $p->getPartialUpdatePercentage());
|
||||
}
|
||||
}
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DNW\Skills\Tests;
|
||||
|
||||
use DNW\Skills\RankSorter;
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DNW\Skills\Tests;
|
||||
|
||||
use DNW\Skills\Rating;
|
||||
@ -18,11 +20,11 @@ class RatingTest extends TestCase
|
||||
|
||||
public function testPartialUpdate(): void
|
||||
{
|
||||
$rating = new Rating(100, 10, 5);
|
||||
$rating_prior = new Rating(100, 10, 5);
|
||||
$rating_new = new Rating(200, 10, 5);
|
||||
$rating = new Rating(100, 10, 5);
|
||||
$ratingOld = new Rating(100, 10, 5);
|
||||
$ratingNew = new Rating(200, 10, 5);
|
||||
|
||||
$rating_partial = $rating ->getPartialUpdate($rating_prior, $rating_new, 0.5);
|
||||
$rating_partial = $rating->getPartialUpdate($ratingOld, $ratingNew, 0.5);
|
||||
|
||||
|
||||
$this->assertEquals(150, $rating_partial->getMean());
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DNW\Skills\Tests\TrueSkill;
|
||||
|
||||
use DNW\Skills\TrueSkill\DrawMargin;
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DNW\Skills\Tests\TrueSkill;
|
||||
|
||||
use DNW\Skills\TrueSkill\FactorGraphTrueSkillCalculator;
|
||||
@ -21,6 +23,6 @@ class FactorGraphTeamTrueSkillCalculatorTest extends TestCase
|
||||
public function testMethodisSupported(): void
|
||||
{
|
||||
$calculator = new FactorGraphTrueSkillCalculator();
|
||||
$this->assertEquals(true, $calculator->isSupported(SkillCalculatorSupportedOptions::PARTIAL_PLAY));
|
||||
$this->assertEquals(TRUE, $calculator->isSupported(SkillCalculatorSupportedOptions::PARTIAL_PLAY));
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DNW\Skills\Tests\TrueSkill;
|
||||
|
||||
use DNW\Skills\GameInfo;
|
||||
@ -25,7 +27,7 @@ class FactorGraphTrueSkillCalculatorTest extends TestCase
|
||||
new Player("hillary"),
|
||||
];
|
||||
|
||||
$teams = array();
|
||||
$teams = [];
|
||||
foreach ($players as $player) {
|
||||
$teams[] = new Team($player, $gameInfo->getDefaultRating());
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DNW\Skills\Tests\TrueSkill;
|
||||
|
||||
use DNW\Skills\GameInfo;
|
||||
@ -78,8 +80,8 @@ class TrueSkillCalculatorTests
|
||||
|
||||
private static function twoPlayerTestNotDrawn(TestCase $testClass, SkillCalculator $calculator): void
|
||||
{
|
||||
$player1 = new Player(1);
|
||||
$player2 = new Player(2);
|
||||
$player1 = new Player(1);
|
||||
$player2 = new Player(2);
|
||||
$gameInfo = new GameInfo();
|
||||
|
||||
$team1 = new Team($player1, $gameInfo->getDefaultRating());
|
||||
@ -108,6 +110,7 @@ class TrueSkillCalculatorTests
|
||||
$team2 = new Team($player2, $gameInfo->getDefaultRating());
|
||||
|
||||
$teams = Teams::concat($team1, $team2);
|
||||
|
||||
$newRatings = $calculator->calculateNewRatings($gameInfo, $teams, [1, 1]);
|
||||
|
||||
$player1NewRating = $newRatings->getRating($player1);
|
||||
@ -122,8 +125,8 @@ class TrueSkillCalculatorTests
|
||||
private static function twoPlayerChessTestNotDrawn(TestCase $testClass, SkillCalculator $calculator): void
|
||||
{
|
||||
// Inspired by a real bug :-)
|
||||
$player1 = new Player(1);
|
||||
$player2 = new Player(2);
|
||||
$player1 = new Player(1);
|
||||
$player2 = new Player(2);
|
||||
$gameInfo = new GameInfo(1200.0, 1200.0 / 3.0, 200.0, 1200.0 / 300.0, 0.03);
|
||||
|
||||
$team1 = new Team($player1, new Rating(1301.0007, 42.9232));
|
||||
@ -169,11 +172,9 @@ class TrueSkillCalculatorTests
|
||||
|
||||
private static function oneOnTwoSimpleTest(TestCase $testClass, SkillCalculator $calculator): void
|
||||
{
|
||||
$player1 = new Player(1);
|
||||
|
||||
$player1 = new Player(1);
|
||||
$gameInfo = new GameInfo();
|
||||
|
||||
$team1 = new Team();
|
||||
$team1 = new Team();
|
||||
$team1->addPlayer($player1, $gameInfo->getDefaultRating());
|
||||
|
||||
$player2 = new Player(2);
|
||||
@ -975,7 +976,7 @@ class TrueSkillCalculatorTests
|
||||
{
|
||||
$gameInfo = new GameInfo();
|
||||
|
||||
$p1 = new Player(1);
|
||||
$p1 = new Player(1);
|
||||
$team1 = new Team($p1, $gameInfo->getDefaultRating());
|
||||
|
||||
$p2 = new Player(2, 0.0);
|
||||
@ -985,7 +986,7 @@ class TrueSkillCalculatorTests
|
||||
$team2->addPlayer($p2, $gameInfo->getDefaultRating());
|
||||
$team2->addPlayer($p3, $gameInfo->getDefaultRating());
|
||||
|
||||
$teams = Teams::concat($team1, $team2);
|
||||
$teams = Teams::concat($team1, $team2);
|
||||
$newRatings = $calculator->calculateNewRatings($gameInfo, $teams, [1, 2]);
|
||||
|
||||
$p1NewRating = $newRatings->getRating($p1);
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DNW\Skills\Tests\TrueSkill;
|
||||
|
||||
use DNW\Skills\TrueSkill\TwoPlayerTrueSkillCalculator;
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DNW\Skills\Tests\TrueSkill;
|
||||
|
||||
use DNW\Skills\TrueSkill\TwoTeamTrueSkillCalculator;
|
||||
|
Reference in New Issue
Block a user