mirror of
				https://github.com/furyfire/trueskill.git
				synced 2025-10-31 00:12:29 +01:00 
			
		
		
		
	PHPMD reintroduced.
This commit is contained in:
		| @@ -26,12 +26,13 @@ | |||||||
|   }, |   }, | ||||||
|   "scripts": { |   "scripts": { | ||||||
|     "test":          "phpunit", |     "test":          "phpunit", | ||||||
|     "document":      "phpDocumentor",  |     "document":      "phpDocumentor", | ||||||
|     "benchmark":     "phpbench run --report=default --output=build-artifact", |     "benchmark":     "phpbench run --report=default --output=build-artifact", | ||||||
|     "metrics":       "vendor/bin/phpmetrics --config=phpmetrics.json", |     "metrics":       "vendor/bin/phpmetrics --config=phpmetrics.json", | ||||||
|     "lint": [ |     "lint": [ | ||||||
|         "phplint", |         "phplint", | ||||||
|         "phpcs" |         "phpcs", | ||||||
|  |         "phpmd src/,tests/,benchmark/,examples/ text phpmd.ruleset.xml" | ||||||
|     ], |     ], | ||||||
|     "analyze": [ |     "analyze": [ | ||||||
|         "@analyze-phpstan", |         "@analyze-phpstan", | ||||||
| @@ -47,10 +48,9 @@ | |||||||
|     ], |     ], | ||||||
|     "all": [ |     "all": [ | ||||||
|       "@test", |       "@test", | ||||||
|       "@document", |  | ||||||
|       "@benchmark", |  | ||||||
|       "@lint", |       "@lint", | ||||||
|       "@analyze", |       "@analyze", | ||||||
|  |       "@document", | ||||||
|       "@metrics", |       "@metrics", | ||||||
|       "@html" |       "@html" | ||||||
|     ] |     ] | ||||||
|   | |||||||
							
								
								
									
										34
									
								
								composer.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										34
									
								
								composer.lock
									
									
									
										generated
									
									
									
								
							| @@ -1377,16 +1377,16 @@ | |||||||
|         }, |         }, | ||||||
|         { |         { | ||||||
|             "name": "phpstan/phpstan", |             "name": "phpstan/phpstan", | ||||||
|             "version": "1.11.5", |             "version": "1.11.6", | ||||||
|             "source": { |             "source": { | ||||||
|                 "type": "git", |                 "type": "git", | ||||||
|                 "url": "https://github.com/phpstan/phpstan.git", |                 "url": "https://github.com/phpstan/phpstan.git", | ||||||
|                 "reference": "490f0ae1c92b082f154681d7849aee776a7c1443" |                 "reference": "6ac78f1165346c83b4a753f7e4186d969c6ad0ee" | ||||||
|             }, |             }, | ||||||
|             "dist": { |             "dist": { | ||||||
|                 "type": "zip", |                 "type": "zip", | ||||||
|                 "url": "https://api.github.com/repos/phpstan/phpstan/zipball/490f0ae1c92b082f154681d7849aee776a7c1443", |                 "url": "https://api.github.com/repos/phpstan/phpstan/zipball/6ac78f1165346c83b4a753f7e4186d969c6ad0ee", | ||||||
|                 "reference": "490f0ae1c92b082f154681d7849aee776a7c1443", |                 "reference": "6ac78f1165346c83b4a753f7e4186d969c6ad0ee", | ||||||
|                 "shasum": "" |                 "shasum": "" | ||||||
|             }, |             }, | ||||||
|             "require": { |             "require": { | ||||||
| @@ -1431,7 +1431,7 @@ | |||||||
|                     "type": "github" |                     "type": "github" | ||||||
|                 } |                 } | ||||||
|             ], |             ], | ||||||
|             "time": "2024-06-17T15:10:54+00:00" |             "time": "2024-07-01T15:33:06+00:00" | ||||||
|         }, |         }, | ||||||
|         { |         { | ||||||
|             "name": "phpunit/php-code-coverage", |             "name": "phpunit/php-code-coverage", | ||||||
| @@ -1756,16 +1756,16 @@ | |||||||
|         }, |         }, | ||||||
|         { |         { | ||||||
|             "name": "phpunit/phpunit", |             "name": "phpunit/phpunit", | ||||||
|             "version": "10.5.24", |             "version": "10.5.25", | ||||||
|             "source": { |             "source": { | ||||||
|                 "type": "git", |                 "type": "git", | ||||||
|                 "url": "https://github.com/sebastianbergmann/phpunit.git", |                 "url": "https://github.com/sebastianbergmann/phpunit.git", | ||||||
|                 "reference": "5f124e3e3e561006047b532fd0431bf5bb6b9015" |                 "reference": "831bf82312be6037e811833ddbea0b8de60ea314" | ||||||
|             }, |             }, | ||||||
|             "dist": { |             "dist": { | ||||||
|                 "type": "zip", |                 "type": "zip", | ||||||
|                 "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/5f124e3e3e561006047b532fd0431bf5bb6b9015", |                 "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/831bf82312be6037e811833ddbea0b8de60ea314", | ||||||
|                 "reference": "5f124e3e3e561006047b532fd0431bf5bb6b9015", |                 "reference": "831bf82312be6037e811833ddbea0b8de60ea314", | ||||||
|                 "shasum": "" |                 "shasum": "" | ||||||
|             }, |             }, | ||||||
|             "require": { |             "require": { | ||||||
| @@ -1837,7 +1837,7 @@ | |||||||
|             "support": { |             "support": { | ||||||
|                 "issues": "https://github.com/sebastianbergmann/phpunit/issues", |                 "issues": "https://github.com/sebastianbergmann/phpunit/issues", | ||||||
|                 "security": "https://github.com/sebastianbergmann/phpunit/security/policy", |                 "security": "https://github.com/sebastianbergmann/phpunit/security/policy", | ||||||
|                 "source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.24" |                 "source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.25" | ||||||
|             }, |             }, | ||||||
|             "funding": [ |             "funding": [ | ||||||
|                 { |                 { | ||||||
| @@ -1853,7 +1853,7 @@ | |||||||
|                     "type": "tidelift" |                     "type": "tidelift" | ||||||
|                 } |                 } | ||||||
|             ], |             ], | ||||||
|             "time": "2024-06-20T13:09:54+00:00" |             "time": "2024-07-03T05:49:17+00:00" | ||||||
|         }, |         }, | ||||||
|         { |         { | ||||||
|             "name": "psalm/plugin-phpunit", |             "name": "psalm/plugin-phpunit", | ||||||
| @@ -2020,16 +2020,16 @@ | |||||||
|         }, |         }, | ||||||
|         { |         { | ||||||
|             "name": "rector/rector", |             "name": "rector/rector", | ||||||
|             "version": "1.1.1", |             "version": "1.2.0", | ||||||
|             "source": { |             "source": { | ||||||
|                 "type": "git", |                 "type": "git", | ||||||
|                 "url": "https://github.com/rectorphp/rector.git", |                 "url": "https://github.com/rectorphp/rector.git", | ||||||
|                 "reference": "c930cdb21294f10955ddfc31b720971e8333943d" |                 "reference": "2fa387553db22b6f9bcccf5ff16f2c2c18a52a65" | ||||||
|             }, |             }, | ||||||
|             "dist": { |             "dist": { | ||||||
|                 "type": "zip", |                 "type": "zip", | ||||||
|                 "url": "https://api.github.com/repos/rectorphp/rector/zipball/c930cdb21294f10955ddfc31b720971e8333943d", |                 "url": "https://api.github.com/repos/rectorphp/rector/zipball/2fa387553db22b6f9bcccf5ff16f2c2c18a52a65", | ||||||
|                 "reference": "c930cdb21294f10955ddfc31b720971e8333943d", |                 "reference": "2fa387553db22b6f9bcccf5ff16f2c2c18a52a65", | ||||||
|                 "shasum": "" |                 "shasum": "" | ||||||
|             }, |             }, | ||||||
|             "require": { |             "require": { | ||||||
| @@ -2067,7 +2067,7 @@ | |||||||
|             ], |             ], | ||||||
|             "support": { |             "support": { | ||||||
|                 "issues": "https://github.com/rectorphp/rector/issues", |                 "issues": "https://github.com/rectorphp/rector/issues", | ||||||
|                 "source": "https://github.com/rectorphp/rector/tree/1.1.1" |                 "source": "https://github.com/rectorphp/rector/tree/1.2.0" | ||||||
|             }, |             }, | ||||||
|             "funding": [ |             "funding": [ | ||||||
|                 { |                 { | ||||||
| @@ -2075,7 +2075,7 @@ | |||||||
|                     "type": "github" |                     "type": "github" | ||||||
|                 } |                 } | ||||||
|             ], |             ], | ||||||
|             "time": "2024-06-21T07:51:17+00:00" |             "time": "2024-07-01T14:24:45+00:00" | ||||||
|         }, |         }, | ||||||
|         { |         { | ||||||
|             "name": "sebastian/cli-parser", |             "name": "sebastian/cli-parser", | ||||||
|   | |||||||
							
								
								
									
										97
									
								
								examples/motogp/goat.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										97
									
								
								examples/motogp/goat.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,97 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | require __DIR__ . "/../../vendor/autoload.php"; | ||||||
|  |  | ||||||
|  | use League\Csv\Reader; | ||||||
|  | use League\Csv\Statement; | ||||||
|  | use DNW\Skills\TrueSkill\FactorGraphTrueSkillCalculator; | ||||||
|  | use DNW\Skills\GameInfo; | ||||||
|  | use DNW\Skills\Player; | ||||||
|  | use DNW\Skills\Team; | ||||||
|  | use DNW\Skills\Teams; | ||||||
|  |  | ||||||
|  | //load the CSV document from a stream | ||||||
|  | $stream = fopen('motogp.csv', 'r'); | ||||||
|  | $csv = Reader::createFromStream($stream); | ||||||
|  | $csv->setDelimiter(','); | ||||||
|  | $csv->setHeaderOffset(0); | ||||||
|  |  | ||||||
|  | //build a statement | ||||||
|  | $stmt = Statement::create()->where(static fn (array $record): bool => $record['category']=="MotoGP" ||  $record['category']=="500cc"); | ||||||
|  | //$stmt = Statement::create(); | ||||||
|  |  | ||||||
|  | /** @var $riders Player[] */ | ||||||
|  | $riders = []; | ||||||
|  | //query your records from the document | ||||||
|  | $records = $stmt->process($csv); | ||||||
|  |  | ||||||
|  | $gameInfo = new GameInfo(); | ||||||
|  | $calculator = new FactorGraphTrueSkillCalculator(); | ||||||
|  | $first_record = $records->first(); | ||||||
|  | $year_race = $first_record['year'].'_'.$first_record['sequence'].'_'.$first_record['category']; | ||||||
|  |  | ||||||
|  | $race_rate = []; | ||||||
|  | foreach($records as $record) | ||||||
|  | { | ||||||
|  |     if ($year_race !== $record['year'].'_'.$record['sequence'].'_'.$record['category']) | ||||||
|  |     { | ||||||
|  |         //Calculate the old race | ||||||
|  |         $newRatings = $calculator->calculateNewRatings($gameInfo, $teams, $pos); | ||||||
|  |  | ||||||
|  |         //update ratings | ||||||
|  |         $highest_rate = 0; | ||||||
|  |         $highest_rider = ""; | ||||||
|  |         foreach($riders as $rider) { | ||||||
|  |             //echo $rider['P']->getId().": ". $newRatings->getRating($rider['P'])->getConservativeRating() . PHP_EOL; | ||||||
|  |             $rider['T']->setRating($rider['P'], $newRatings->getRating($rider['P'])); | ||||||
|  |             if($newRatings->getRating($rider['P'])->getConservativeRating() > $highest_rate) | ||||||
|  |             { | ||||||
|  |                 $highest_rate = $newRatings->getRating($rider['P'])->getConservativeRating(); | ||||||
|  |                 $highest_rider = $rider['P']->getId(); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         echo sprintf('Highest rider: %s => %s', $highest_rider, $highest_rate).PHP_EOL; | ||||||
|  |  | ||||||
|  |         foreach($global_riders as $r) | ||||||
|  |         { | ||||||
|  |             $rate = $r['T']->getRating($r['P'])->getConservativeRating(); | ||||||
|  |  | ||||||
|  |             $race_rate[$year_race][$r['P']->getId()] = $rate; | ||||||
|  |             if (!isset($top_rating[$r['P']->getId()]) || $top_rating[$r['P']->getId()] < $rate) | ||||||
|  |             { | ||||||
|  |                 $top_rating[$r['P']->getId()] = $rate; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         //prepare for next race | ||||||
|  |         $year_race = $record['year'].'_'.$record['sequence'].'_'.$record['category']; | ||||||
|  |         $races[] =['year' => $record['year'], 'race'=> $record['sequence'], 'circuit'=> $record['circuit_name']]; | ||||||
|  |         echo "New Race: ".$year_race. ' => '. $record['circuit_name'].PHP_EOL; | ||||||
|  |         $riders = []; | ||||||
|  |         $teams = []; | ||||||
|  |         $pos = []; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     //Is it a new rider?  | ||||||
|  |     if(!isset($global_riders[$record['rider']])) | ||||||
|  |     { | ||||||
|  |         $global_riders[$record['rider']]['P'] = new Player($record['rider_name']); | ||||||
|  |         $global_riders[$record['rider']]['T'] = new Team($global_riders[$record['rider']]['P'], $gameInfo->getDefaultRating()); | ||||||
|  |         //echo "New Rider: ". $record['rider'] . " => ".$global_riders[$record['rider']]['P']->getId().PHP_EOL; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     $riders[] = $global_riders[$record['rider']]; | ||||||
|  |     $teams[] = $global_riders[$record['rider']]['T']; | ||||||
|  |      | ||||||
|  |     //Position or DNF? | ||||||
|  |     $pos[] = $record['position'] >= 1 ? $record['position'] : end($pos); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | echo "All time top score".PHP_EOL; | ||||||
|  | asort($top_rating); | ||||||
|  | foreach($top_rating as $n=>$r) | ||||||
|  | { | ||||||
|  |     echo sprintf('%s => %s', $n, $r).PHP_EOL; | ||||||
|  | } | ||||||
|  |  | ||||||
							
								
								
									
										56397
									
								
								examples/motogp/motogp.csv
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56397
									
								
								examples/motogp/motogp.csv
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										9
									
								
								phpmd.baseline.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								phpmd.baseline.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | |||||||
|  | <?xml version="1.0"?> | ||||||
|  | <phpmd-baseline> | ||||||
|  |   <violation rule="PHPMD\Rule\Design\TooManyPublicMethods" file="src/Numerics/GaussianDistribution.php"/> | ||||||
|  |   <violation rule="PHPMD\Rule\UnusedPrivateMethod" file="src/Numerics/GaussianDistribution.php" method="errorFunctionCumulativeTo"/> | ||||||
|  |   <violation rule="PHPMD\Rule\UnusedPrivateMethod" file="src/Numerics/GaussianDistribution.php" method="inverseErrorFunctionCumulativeTo"/> | ||||||
|  |   <violation rule="PHPMD\Rule\Design\WeightedMethodCount" file="src/Numerics/Matrix.php"/> | ||||||
|  |   <violation rule="PHPMD\Rule\Design\CouplingBetweenObjects" file="src/TrueSkill/FactorGraphTrueSkillCalculator.php"/> | ||||||
|  |   <violation rule="PHPMD\Rule\Design\CouplingBetweenObjects" file="src/TrueSkill/TrueSkillFactorGraph.php"/> | ||||||
|  | </phpmd-baseline> | ||||||
							
								
								
									
										49
									
								
								phpmd.ruleset.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								phpmd.ruleset.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,49 @@ | |||||||
|  | <?xml version="1.0"?> | ||||||
|  | <ruleset name="TrueSkill custom PHPMD rules" | ||||||
|  |          xmlns="http://pmd.sf.net/ruleset/1.0.0" | ||||||
|  |          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||||||
|  |          xsi:schemaLocation="http://pmd.sf.net/ruleset/1.0.0 | ||||||
|  |                      http://pmd.sf.net/ruleset_xml_schema.xsd" | ||||||
|  |          xsi:noNamespaceSchemaLocation=" | ||||||
|  |                      http://pmd.sf.net/ruleset_xml_schema.xsd"> | ||||||
|  |     <description> | ||||||
|  |         TrueSkill custom PHPMD rules | ||||||
|  |     </description> | ||||||
|  |  | ||||||
|  |     <!-- Import the entire unused code rule set --> | ||||||
|  |     <rule ref="rulesets/cleancode.xml"> | ||||||
|  |         <exclude name="StaticAccess" /> | ||||||
|  |         <exclude name="ElseExpression" /> | ||||||
|  |     </rule> | ||||||
|  |     <rule ref="rulesets/codesize.xml" > | ||||||
|  |         <exclude name="TooManyMethods" /> | ||||||
|  |         <exclude name="TooManyPublicMethods" /> | ||||||
|  |     </rule> | ||||||
|  |     <rule ref="rulesets/codesize.xml/TooManyMethods"> | ||||||
|  |         <priority>1</priority> | ||||||
|  |         <properties> | ||||||
|  |             <property name="ignorepattern" value="#^(set|get|test)|test$#i" /> | ||||||
|  |         </properties> | ||||||
|  |     </rule> | ||||||
|  |     <rule ref="rulesets/codesize.xml/TooManyPublicMethods"> | ||||||
|  |         <priority>1</priority> | ||||||
|  |         <properties> | ||||||
|  |             <property name="ignorepattern" value="#^(set|get|test)|test$#i" /> | ||||||
|  |         </properties> | ||||||
|  |     </rule> | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     <!--rule ref="rulesets/controversial.xml" /--> | ||||||
|  |     <rule ref="rulesets/design.xml" /> | ||||||
|  |     <rule ref="rulesets/naming.xml" > | ||||||
|  |         <exclude name="LongClassName" /> | ||||||
|  |         <exclude name="ShortClassName" /> | ||||||
|  |         <exclude name="ShortVariable" /> | ||||||
|  |         <exclude name="LongVariable" /> | ||||||
|  |         <exclude name="ShortMethodName" /> | ||||||
|  |     </rule> | ||||||
|  |     <rule ref="rulesets/unusedcode.xml" /> | ||||||
|  |  | ||||||
|  |     <!-- Import entire naming rule set and exclude rules --> | ||||||
|  |  | ||||||
|  | </ruleset> | ||||||
| @@ -15,7 +15,7 @@ abstract class Factor | |||||||
|      */ |      */ | ||||||
|     private array $messages = []; |     private array $messages = []; | ||||||
|  |  | ||||||
|     private readonly HashMap $messageToVariableBinding; |     private readonly HashMap $msgToVariableBinding; | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * @var Variable[] $variables |      * @var Variable[] $variables | ||||||
| @@ -24,7 +24,7 @@ abstract class Factor | |||||||
|  |  | ||||||
|     protected function __construct() |     protected function __construct() | ||||||
|     { |     { | ||||||
|         $this->messageToVariableBinding = new HashMap(); |         $this->msgToVariableBinding = new HashMap(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
| @@ -70,7 +70,7 @@ abstract class Factor | |||||||
|     { |     { | ||||||
|         Guard::argumentIsValidIndex($messageIndex, count($this->messages), 'messageIndex'); |         Guard::argumentIsValidIndex($messageIndex, count($this->messages), 'messageIndex'); | ||||||
|         $message = $this->messages[$messageIndex]; |         $message = $this->messages[$messageIndex]; | ||||||
|         $variable = $this->messageToVariableBinding->getValue($message); |         $variable = $this->msgToVariableBinding->getValue($message); | ||||||
|  |  | ||||||
|         return $this->updateMessageVariable($message, $variable); |         return $this->updateMessageVariable($message, $variable); | ||||||
|     } |     } | ||||||
| @@ -85,7 +85,7 @@ abstract class Factor | |||||||
|      */ |      */ | ||||||
|     public function resetMarginals(): void |     public function resetMarginals(): void | ||||||
|     { |     { | ||||||
|         $allValues = $this->messageToVariableBinding->getAllValues(); |         $allValues = $this->msgToVariableBinding->getAllValues(); | ||||||
|         foreach ($allValues as $currentVariable) { |         foreach ($allValues as $currentVariable) { | ||||||
|             $currentVariable->resetToPrior(); |             $currentVariable->resetToPrior(); | ||||||
|         } |         } | ||||||
| @@ -101,7 +101,7 @@ abstract class Factor | |||||||
|         Guard::argumentIsValidIndex($messageIndex, count($this->messages), 'messageIndex'); |         Guard::argumentIsValidIndex($messageIndex, count($this->messages), 'messageIndex'); | ||||||
|  |  | ||||||
|         $message = $this->messages[$messageIndex]; |         $message = $this->messages[$messageIndex]; | ||||||
|         $variable = $this->messageToVariableBinding->getValue($message); |         $variable = $this->msgToVariableBinding->getValue($message); | ||||||
|  |  | ||||||
|         return $this->sendMessageVariable($message, $variable); |         return $this->sendMessageVariable($message, $variable); | ||||||
|     } |     } | ||||||
| @@ -112,7 +112,7 @@ abstract class Factor | |||||||
|  |  | ||||||
|     protected function createVariableToMessageBindingWithMessage(Variable $variable, Message $message): Message |     protected function createVariableToMessageBindingWithMessage(Variable $variable, Message $message): Message | ||||||
|     { |     { | ||||||
|         $this->messageToVariableBinding->setValue($message, $variable); |         $this->msgToVariableBinding->setValue($message, $variable); | ||||||
|         $this->messages[] = $message; |         $this->messages[] = $message; | ||||||
|         $this->variables[] = $variable; |         $this->variables[] = $variable; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -17,7 +17,7 @@ abstract class FactorGraphLayer | |||||||
|     /** |     /** | ||||||
|      * @var array<int,array<int,Variable>> |      * @var array<int,array<int,Variable>> | ||||||
|      */ |      */ | ||||||
|     private array $outputVariablesGroups = []; |     private array $outputVarGroups = []; | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * @var array<int,array<int,Variable>> |      * @var array<int,array<int,Variable>> | ||||||
| @@ -48,7 +48,7 @@ abstract class FactorGraphLayer | |||||||
|      */ |      */ | ||||||
|     public function &getOutputVariablesGroups(): array |     public function &getOutputVariablesGroups(): array | ||||||
|     { |     { | ||||||
|         return $this->outputVariablesGroups; |         return $this->outputVarGroups; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|   | |||||||
| @@ -26,12 +26,12 @@ class FactorList | |||||||
|         $listCount = count($this->list); |         $listCount = count($this->list); | ||||||
|  |  | ||||||
|         for ($i = 0; $i < $listCount; ++$i) { |         for ($i = 0; $i < $listCount; ++$i) { | ||||||
|             $f = $this->list[$i]; |             $factor = $this->list[$i]; | ||||||
|  |  | ||||||
|             $numberOfMessages = $f->getNumberOfMessages(); |             $numberOfMessages = $factor->getNumberOfMessages(); | ||||||
|  |  | ||||||
|             for ($j = 0; $j < $numberOfMessages; ++$j) { |             for ($j = 0; $j < $numberOfMessages; ++$j) { | ||||||
|                 $sumLogZ += $f->sendMessageIndex($j); |                 $sumLogZ += $factor->sendMessageIndex($j); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -6,20 +6,20 @@ namespace DNW\Skills\FactorGraphs; | |||||||
|  |  | ||||||
| class VariableFactory | class VariableFactory | ||||||
| { | { | ||||||
|     public function __construct(private \Closure $variablePriorInitializer) |     public function __construct(private \Closure $varPriorInitializer) | ||||||
|     { |     { | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public function createBasicVariable(): Variable |     public function createBasicVariable(): Variable | ||||||
|     { |     { | ||||||
|         $initializer = $this->variablePriorInitializer; |         $initializer = $this->varPriorInitializer; | ||||||
|  |  | ||||||
|         return new Variable($initializer()); |         return new Variable($initializer()); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public function createKeyedVariable(mixed $key): KeyedVariable |     public function createKeyedVariable(mixed $key): KeyedVariable | ||||||
|     { |     { | ||||||
|         $initializer = $this->variablePriorInitializer; |         $initializer = $this->varPriorInitializer; | ||||||
|  |  | ||||||
|         return new KeyedVariable($key, $initializer()); |         return new KeyedVariable($key, $initializer()); | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -27,7 +27,7 @@ class GameInfo | |||||||
|  |  | ||||||
|     public function __construct( |     public function __construct( | ||||||
|         private readonly float $initialMean = self::DEFAULT_INITIAL_MEAN, |         private readonly float $initialMean = self::DEFAULT_INITIAL_MEAN, | ||||||
|         private readonly float $initialStandardDeviation = self::DEFAULT_INITIAL_STANDARD_DEVIATION, |         private readonly float $initialStdDev = self::DEFAULT_INITIAL_STANDARD_DEVIATION, | ||||||
|         private readonly float $beta = self::DEFAULT_BETA, |         private readonly float $beta = self::DEFAULT_BETA, | ||||||
|         private readonly float $dynamicsFactor = self::DEFAULT_DYNAMICS_FACTOR, |         private readonly float $dynamicsFactor = self::DEFAULT_DYNAMICS_FACTOR, | ||||||
|         private readonly float $drawProbability = self::DEFAULT_DRAW_PROBABILITY |         private readonly float $drawProbability = self::DEFAULT_DRAW_PROBABILITY | ||||||
| @@ -42,7 +42,7 @@ class GameInfo | |||||||
|  |  | ||||||
|     public function getInitialStandardDeviation(): float |     public function getInitialStandardDeviation(): float | ||||||
|     { |     { | ||||||
|         return $this->initialStandardDeviation; |         return $this->initialStdDev; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public function getBeta(): float |     public function getBeta(): float | ||||||
| @@ -62,6 +62,6 @@ class GameInfo | |||||||
|  |  | ||||||
|     public function getDefaultRating(): Rating |     public function getDefaultRating(): Rating | ||||||
|     { |     { | ||||||
|         return new Rating($this->initialMean, $this->initialStandardDeviation); |         return new Rating($this->initialMean, $this->initialStdDev); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -13,15 +13,15 @@ namespace DNW\Skills\Numerics; | |||||||
| class BasicMath | class BasicMath | ||||||
| { | { | ||||||
|     /** |     /** | ||||||
|      * Squares the input (x^2 = x * x) |      * Squares the input (input^2 = input * input) | ||||||
|      * |      * | ||||||
|      * @param $x Value to square (x) |      * @param $input Value to square (input) | ||||||
|      * |      * | ||||||
|      * @return float The squared value (x^2) |      * @return float The squared value (input^2) | ||||||
|      */ |      */ | ||||||
|     public static function square(float $x): float |     public static function square(float $input): float | ||||||
|     { |     { | ||||||
|         return $x * $x; |         return $input * $input; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|   | |||||||
| @@ -55,7 +55,6 @@ class GaussianDistribution | |||||||
|             $this->precisionMean = $this->precision * $this->mean; |             $this->precisionMean = $this->precision * $this->mean; | ||||||
|         } else { |         } else { | ||||||
|             $this->precision = \INF; |             $this->precision = \INF; | ||||||
|  |  | ||||||
|             $this->precisionMean = $this->mean == 0 ? 0 : \INF; |             $this->precisionMean = $this->mean == 0 ? 0 : \INF; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| @@ -175,7 +174,7 @@ class GaussianDistribution | |||||||
|         BasicMath::square($meanDifference) / (2 * $varianceDifference); |         BasicMath::square($meanDifference) / (2 * $varianceDifference); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public static function at(float $x, float $mean = 0.0, float $standardDeviation = 1.0): float |     public static function at(float $var, float $mean = 0.0, float $standardDeviation = 1.0): float | ||||||
|     { |     { | ||||||
|         // See http://mathworld.wolfram.com/NormalDistribution.html |         // See http://mathworld.wolfram.com/NormalDistribution.html | ||||||
|         //                1              -(x-mean)^2 / (2*stdDev^2) |         //                1              -(x-mean)^2 / (2*stdDev^2) | ||||||
| @@ -183,22 +182,22 @@ 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($x - $mean)) / (2 * BasicMath::square($standardDeviation))); |         $expPart = exp((-1.0 * BasicMath::square($var - $mean)) / (2 * BasicMath::square($standardDeviation))); | ||||||
|  |  | ||||||
|         return $multiplier * $expPart; |         return $multiplier * $expPart; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public static function cumulativeTo(float $x): float |     public static function cumulativeTo(float $var): float | ||||||
|     { |     { | ||||||
|         $result = GaussianDistribution::errorFunctionCumulativeTo(-M_SQRT1_2 * $x); |         $result = GaussianDistribution::errorFunctionCumulativeTo(-M_SQRT1_2 * $var); | ||||||
|  |  | ||||||
|         return 0.5 * $result; |         return 0.5 * $result; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     private static function errorFunctionCumulativeTo(float $x): float |     private static function errorFunctionCumulativeTo(float $var): float | ||||||
|     { |     { | ||||||
|         // Derived from page 265 of Numerical Recipes 3rd Edition |         // Derived from page 265 of Numerical Recipes 3rd Edition | ||||||
|         $z = abs($x); |         $z = abs($var); | ||||||
|  |  | ||||||
|         $t = 2.0 / (2.0 + $z); |         $t = 2.0 / (2.0 + $z); | ||||||
|         $ty = 4 * $t - 2; |         $ty = 4 * $t - 2; | ||||||
| @@ -246,7 +245,7 @@ class GaussianDistribution | |||||||
|  |  | ||||||
|         $ans = $t * exp(-$z * $z + 0.5 * ($coefficients[0] + $ty * $d) - $dd); |         $ans = $t * exp(-$z * $z + 0.5 * ($coefficients[0] + $ty * $d) - $dd); | ||||||
|  |  | ||||||
|         return ($x >= 0.0) ? $ans : (2.0 - $ans); |         return ($var >= 0.0) ? $ans : (2.0 - $ans); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     private static function inverseErrorFunctionCumulativeTo(float $p): float |     private static function inverseErrorFunctionCumulativeTo(float $p): float | ||||||
| @@ -272,9 +271,9 @@ class GaussianDistribution | |||||||
|         return ($p < 1.0) ? $x : -$x; |         return ($p < 1.0) ? $x : -$x; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public static function inverseCumulativeTo(float $x, 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 * $x); |         return $mean - M_SQRT2 * $standardDeviation * GaussianDistribution::inverseErrorFunctionCumulativeTo(2 * $var); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -76,10 +76,10 @@ class Matrix | |||||||
|         $transposeMatrix = []; |         $transposeMatrix = []; | ||||||
|  |  | ||||||
|         $rowMatrixData = $this->matrixRowData; |         $rowMatrixData = $this->matrixRowData; | ||||||
|         for ($currentRowTransposeMatrix = 0; $currentRowTransposeMatrix < $this->columnCount; ++$currentRowTransposeMatrix) { |         for ($curRowTransposeMx = 0; $curRowTransposeMx < $this->columnCount; ++$curRowTransposeMx) { | ||||||
|             for ($currentColumnTransposeMatrix = 0; $currentColumnTransposeMatrix < $this->rowCount; ++$currentColumnTransposeMatrix) { |             for ($curColTransposeMx = 0; $curColTransposeMx < $this->rowCount; ++$curColTransposeMx) { | ||||||
|                 $transposeMatrix[$currentRowTransposeMatrix][$currentColumnTransposeMatrix] = |                 $transposeMatrix[$curRowTransposeMx][$curColTransposeMx] = | ||||||
|                     $rowMatrixData[$currentColumnTransposeMatrix][$currentRowTransposeMatrix]; |                     $rowMatrixData[$curColTransposeMx][$curRowTransposeMx]; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -8,14 +8,14 @@ class PartialPlay | |||||||
| { | { | ||||||
|     public static function getPartialPlayPercentage(Player $player): float |     public static function getPartialPlayPercentage(Player $player): float | ||||||
|     { |     { | ||||||
|         $partialPlayPercentage = $player->getPartialPlayPercentage(); |         $partialPlayPct = $player->getPartialPlayPercentage(); | ||||||
|  |  | ||||||
|         // HACK to get around bug near 0 |         // HACK to get around bug near 0 | ||||||
|         $smallestPercentage = 0.0001; |         $smallestPct = 0.0001; | ||||||
|         if ($partialPlayPercentage < $smallestPercentage) { |         if ($partialPlayPct < $smallestPct) { | ||||||
|             return $smallestPercentage; |             return $smallestPct; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         return $partialPlayPercentage; |         return $partialPlayPct; | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -13,27 +13,27 @@ class Player implements ISupportPartialPlay, ISupportPartialUpdate | |||||||
|  |  | ||||||
|     private const DEFAULT_PARTIAL_UPDATE_PERCENTAGE = 1.0; |     private const DEFAULT_PARTIAL_UPDATE_PERCENTAGE = 1.0; | ||||||
|  |  | ||||||
|     private readonly float $PartialPlayPercentage; |     private readonly float $PartialPlayPct; | ||||||
|  |  | ||||||
|     private readonly float $PartialUpdatePercentage; |     private readonly 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 $partialPlayPercentage   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 $partialUpdatePercentage Indicated how much of a skill update a player should receive where 0 represents no update and 1.0 represents 100% of the update. |      * @param 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 readonly mixed $Id, | ||||||
|         float $partialPlayPercentage = self::DEFAULT_PARTIAL_PLAY_PERCENTAGE, |         float $partialPlayPct = self::DEFAULT_PARTIAL_PLAY_PERCENTAGE, | ||||||
|         float $partialUpdatePercentage = self::DEFAULT_PARTIAL_UPDATE_PERCENTAGE |         float $partialUpdatePct = self::DEFAULT_PARTIAL_UPDATE_PERCENTAGE | ||||||
|     ) |     ) | ||||||
|     { |     { | ||||||
|         Guard::argumentInRangeInclusive($partialPlayPercentage, 0.0, 1.0, 'partialPlayPercentage'); |         Guard::argumentInRangeInclusive($partialPlayPct, 0.0, 1.0, 'partialPlayPercentage'); | ||||||
|         Guard::argumentInRangeInclusive($partialUpdatePercentage, 0, 1.0, 'partialUpdatePercentage'); |         Guard::argumentInRangeInclusive($partialUpdatePct, 0, 1.0, 'partialUpdatePercentage'); | ||||||
|         $this->PartialPlayPercentage = $partialPlayPercentage; |         $this->PartialPlayPct = $partialPlayPct; | ||||||
|         $this->PartialUpdatePercentage = $partialUpdatePercentage; |         $this->PartialUpdatePct = $partialUpdatePct; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
| @@ -49,7 +49,7 @@ class Player implements ISupportPartialPlay, ISupportPartialUpdate | |||||||
|      */ |      */ | ||||||
|     public function getPartialPlayPercentage(): float |     public function getPartialPlayPercentage(): float | ||||||
|     { |     { | ||||||
|         return $this->PartialPlayPercentage; |         return $this->PartialPlayPct; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
| @@ -57,6 +57,6 @@ class Player implements ISupportPartialPlay, ISupportPartialUpdate | |||||||
|      */ |      */ | ||||||
|     public function getPartialUpdatePercentage(): float |     public function getPartialUpdatePercentage(): float | ||||||
|     { |     { | ||||||
|         return $this->PartialUpdatePercentage; |         return $this->PartialUpdatePct; | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -171,7 +171,8 @@ class FactorGraphTrueSkillCalculator extends SkillCalculator | |||||||
|  |  | ||||||
|         $currentColumn = 0; |         $currentColumn = 0; | ||||||
|  |  | ||||||
|         for ($i = 0; $i < count($teamAssignmentsList) - 1; ++$i) { |         $teamCnt = count($teamAssignmentsList); | ||||||
|  |         for ($i = 0; $i < $teamCnt - 1; ++$i) { | ||||||
|             $currentTeam = $teamAssignmentsList[$i]; |             $currentTeam = $teamAssignmentsList[$i]; | ||||||
|  |  | ||||||
|             // Need to add in 0's for all the previous players, since they're not |             // Need to add in 0's for all the previous players, since they're not | ||||||
|   | |||||||
| @@ -60,9 +60,9 @@ class GaussianLikelihoodFactor extends GaussianFactor | |||||||
|             $a * ($marginal2->getPrecision() - $message2Value->getPrecision()) |             $a * ($marginal2->getPrecision() - $message2Value->getPrecision()) | ||||||
|         ); |         ); | ||||||
|  |  | ||||||
|         $oldMarginalWithoutMessage = GaussianDistribution::divide($marginal1, $message1Value); |         $oldMarginalWithoutMsg = GaussianDistribution::divide($marginal1, $message1Value); | ||||||
|  |  | ||||||
|         $newMarginal = GaussianDistribution::multiply($oldMarginalWithoutMessage, $newMessage); |         $newMarginal = GaussianDistribution::multiply($oldMarginalWithoutMsg, $newMessage); | ||||||
|  |  | ||||||
|         // Update the message and marginal |         // Update the message and marginal | ||||||
|  |  | ||||||
|   | |||||||
| @@ -19,9 +19,9 @@ use DNW\Skills\Numerics\GaussianDistribution; | |||||||
| class GaussianWeightedSumFactor extends GaussianFactor | class GaussianWeightedSumFactor extends GaussianFactor | ||||||
| { | { | ||||||
|     /** |     /** | ||||||
|      * @var array<int[]> $variableIndexOrdersForWeights |      * @var array<int[]> $varIndexOrdersForWeights | ||||||
|      */ |      */ | ||||||
|     private array $variableIndexOrdersForWeights = []; |     private array $varIndexOrdersForWeights = []; | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * This following is used for convenience, for example, the first entry is [0, 1, 2] |      * This following is used for convenience, for example, the first entry is [0, 1, 2] | ||||||
| @@ -58,9 +58,9 @@ class GaussianWeightedSumFactor extends GaussianFactor | |||||||
|         $variablesToSumLength = count($variablesToSum); |         $variablesToSumLength = count($variablesToSum); | ||||||
|  |  | ||||||
|         // 0..n-1 |         // 0..n-1 | ||||||
|         $this->variableIndexOrdersForWeights[0] = []; |         $this->varIndexOrdersForWeights[0] = []; | ||||||
|         for ($i = 0; $i < ($variablesToSumLength + 1); ++$i) { |         for ($i = 0; $i < ($variablesToSumLength + 1); ++$i) { | ||||||
|             $this->variableIndexOrdersForWeights[0][] = $i; |             $this->varIndexOrdersForWeights[0][] = $i; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         $variableWeightsLength = count($variableWeights); |         $variableWeightsLength = count($variableWeights); | ||||||
| @@ -113,7 +113,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; | ||||||
|             $this->variableIndexOrdersForWeights[] = $variableIndices; |             $this->varIndexOrdersForWeights[] = $variableIndices; | ||||||
|  |  | ||||||
|             $this->weights[$weightsIndex] = $currentWeights; |             $this->weights[$weightsIndex] = $currentWeights; | ||||||
|             $this->weightsSquared[$weightsIndex] = $currentWeightsSquared; |             $this->weightsSquared[$weightsIndex] = $currentWeightsSquared; | ||||||
| @@ -160,9 +160,7 @@ class GaussianWeightedSumFactor extends GaussianFactor | |||||||
|  |  | ||||||
|         // The math works out so that 1/newPrecision = sum of a_i^2 /marginalsWithoutMessages[i] |         // The math works out so that 1/newPrecision = sum of a_i^2 /marginalsWithoutMessages[i] | ||||||
|         $inverseOfNewPrecisionSum = 0.0; |         $inverseOfNewPrecisionSum = 0.0; | ||||||
|         $anotherInverseOfNewPrecisionSum = 0.0; |  | ||||||
|         $weightedMeanSum = 0.0; |         $weightedMeanSum = 0.0; | ||||||
|         $anotherWeightedMeanSum = 0.0; |  | ||||||
|  |  | ||||||
|         $weightsSquaredLength = count($weightsSquared); |         $weightsSquaredLength = count($weightsSquared); | ||||||
|  |  | ||||||
| @@ -172,16 +170,11 @@ class GaussianWeightedSumFactor extends GaussianFactor | |||||||
|             $inverseOfNewPrecisionSum += $weightsSquared[$i] / |             $inverseOfNewPrecisionSum += $weightsSquared[$i] / | ||||||
|                 ($variables[$i + 1]->getValue()->getPrecision() - $messages[$i + 1]->getValue()->getPrecision()); |                 ($variables[$i + 1]->getValue()->getPrecision() - $messages[$i + 1]->getValue()->getPrecision()); | ||||||
|  |  | ||||||
|             $diff = GaussianDistribution::divide($variables[$i + 1]->getValue(), $messages[$i + 1]->getValue()); |  | ||||||
|             $anotherInverseOfNewPrecisionSum += $weightsSquared[$i] / $diff->getPrecision(); |  | ||||||
|  |  | ||||||
|             $weightedMeanSum += $weights[$i] |             $weightedMeanSum += $weights[$i] | ||||||
|                 * |                 * | ||||||
|                 ($variables[$i + 1]->getValue()->getPrecisionMean() - $messages[$i + 1]->getValue()->getPrecisionMean()) |                 ($variables[$i + 1]->getValue()->getPrecisionMean() - $messages[$i + 1]->getValue()->getPrecisionMean()) | ||||||
|                 / |                 / | ||||||
|                 ($variables[$i + 1]->getValue()->getPrecision() - $messages[$i + 1]->getValue()->getPrecision()); |                 ($variables[$i + 1]->getValue()->getPrecision() - $messages[$i + 1]->getValue()->getPrecision()); | ||||||
|  |  | ||||||
|             $anotherWeightedMeanSum += $weights[$i] * $diff->getPrecisionMean() / $diff->getPrecision(); |  | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         $newPrecision = 1.0 / $inverseOfNewPrecisionSum; |         $newPrecision = 1.0 / $inverseOfNewPrecisionSum; | ||||||
| @@ -214,7 +207,7 @@ class GaussianWeightedSumFactor extends GaussianFactor | |||||||
|         $updatedMessages = []; |         $updatedMessages = []; | ||||||
|         $updatedVariables = []; |         $updatedVariables = []; | ||||||
|  |  | ||||||
|         $indicesToUse = $this->variableIndexOrdersForWeights[$messageIndex]; |         $indicesToUse = $this->varIndexOrdersForWeights[$messageIndex]; | ||||||
|         // The tricky part here is that we have to put the messages and variables in the same |         // The tricky part here is that we have to put the messages and variables in the same | ||||||
|         // order as the weights. Thankfully, the weights and messages share the same index numbers, |         // order as the weights. Thankfully, the weights and messages share the same index numbers, | ||||||
|         // so we just need to make sure they're consistent |         // so we just need to make sure they're consistent | ||||||
|   | |||||||
| @@ -15,8 +15,8 @@ class IteratedTeamDifferencesInnerLayer extends TrueSkillFactorGraphLayer | |||||||
| { | { | ||||||
|     public function __construct( |     public function __construct( | ||||||
|         TrueSkillFactorGraph $parentGraph, |         TrueSkillFactorGraph $parentGraph, | ||||||
|         private readonly TeamPerformancesToTeamPerformanceDifferencesLayer $TeamPerformancesToTeamPerformanceDifferencesLayer, |         private readonly TeamPerformancesToTeamPerformanceDifferencesLayer $teamPerformancesToTeamPerformanceDifferencesLayer, | ||||||
|         private readonly TeamDifferencesComparisonLayer $TeamDifferencesComparisonLayer |         private readonly TeamDifferencesComparisonLayer $teamDifferencesComparisonLayer | ||||||
|     ) |     ) | ||||||
|     { |     { | ||||||
|         parent::__construct($parentGraph); |         parent::__construct($parentGraph); | ||||||
| @@ -25,20 +25,20 @@ class IteratedTeamDifferencesInnerLayer extends TrueSkillFactorGraphLayer | |||||||
|     public function getLocalFactors(): array |     public function getLocalFactors(): array | ||||||
|     { |     { | ||||||
|         return array_merge( |         return array_merge( | ||||||
|             $this->TeamPerformancesToTeamPerformanceDifferencesLayer->getLocalFactors(), |             $this->teamPerformancesToTeamPerformanceDifferencesLayer->getLocalFactors(), | ||||||
|             $this->TeamDifferencesComparisonLayer->getLocalFactors() |             $this->teamDifferencesComparisonLayer->getLocalFactors() | ||||||
|         ); |         ); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public function buildLayer(): void |     public function buildLayer(): void | ||||||
|     { |     { | ||||||
|         $inputVariablesGroups = $this->getInputVariablesGroups(); |         $inputVariablesGroups = $this->getInputVariablesGroups(); | ||||||
|         $this->TeamPerformancesToTeamPerformanceDifferencesLayer->setInputVariablesGroups($inputVariablesGroups); |         $this->teamPerformancesToTeamPerformanceDifferencesLayer->setInputVariablesGroups($inputVariablesGroups); | ||||||
|         $this->TeamPerformancesToTeamPerformanceDifferencesLayer->buildLayer(); |         $this->teamPerformancesToTeamPerformanceDifferencesLayer->buildLayer(); | ||||||
|  |  | ||||||
|         $teamDifferencesOutputVariablesGroups = $this->TeamPerformancesToTeamPerformanceDifferencesLayer->getOutputVariablesGroups(); |         $teamDifferencesOutputVariablesGroups = $this->teamPerformancesToTeamPerformanceDifferencesLayer->getOutputVariablesGroups(); | ||||||
|         $this->TeamDifferencesComparisonLayer->setInputVariablesGroups($teamDifferencesOutputVariablesGroups); |         $this->teamDifferencesComparisonLayer->setInputVariablesGroups($teamDifferencesOutputVariablesGroups); | ||||||
|         $this->TeamDifferencesComparisonLayer->buildLayer(); |         $this->teamDifferencesComparisonLayer->buildLayer(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public function createPriorSchedule(): ?ScheduleSequence |     public function createPriorSchedule(): ?ScheduleSequence | ||||||
| @@ -56,9 +56,9 @@ class IteratedTeamDifferencesInnerLayer extends TrueSkillFactorGraphLayer | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         // When dealing with differences, there are always (n-1) differences, so add in the 1 |         // When dealing with differences, there are always (n-1) differences, so add in the 1 | ||||||
|         $totalTeamDifferences = count($this->TeamPerformancesToTeamPerformanceDifferencesLayer->getLocalFactors()); |         $totalTeamDifferences = count($this->teamPerformancesToTeamPerformanceDifferencesLayer->getLocalFactors()); | ||||||
|  |  | ||||||
|         $localFactors = $this->TeamPerformancesToTeamPerformanceDifferencesLayer->getLocalFactors(); |         $localFactors = $this->teamPerformancesToTeamPerformanceDifferencesLayer->getLocalFactors(); | ||||||
|  |  | ||||||
|         $firstDifferencesFactor = $localFactors[0]; |         $firstDifferencesFactor = $localFactors[0]; | ||||||
|         $lastDifferencesFactor = $localFactors[$totalTeamDifferences - 1]; |         $lastDifferencesFactor = $localFactors[$totalTeamDifferences - 1]; | ||||||
| @@ -83,8 +83,8 @@ class IteratedTeamDifferencesInnerLayer extends TrueSkillFactorGraphLayer | |||||||
|  |  | ||||||
|     private function createTwoTeamInnerPriorLoopSchedule(): ScheduleSequence |     private function createTwoTeamInnerPriorLoopSchedule(): ScheduleSequence | ||||||
|     { |     { | ||||||
|         $teamPerformancesToTeamPerformanceDifferencesLayerLocalFactors = $this->TeamPerformancesToTeamPerformanceDifferencesLayer->getLocalFactors(); |         $teamPerformancesToTeamPerformanceDifferencesLayerLocalFactors = $this->teamPerformancesToTeamPerformanceDifferencesLayer->getLocalFactors(); | ||||||
|         $teamDifferencesComparisonLayerLocalFactors = $this->TeamDifferencesComparisonLayer->getLocalFactors(); |         $teamDifferencesComparisonLayerLocalFactors = $this->teamDifferencesComparisonLayer->getLocalFactors(); | ||||||
|  |  | ||||||
|         $firstPerfToTeamDiff = $teamPerformancesToTeamPerformanceDifferencesLayerLocalFactors[0]; |         $firstPerfToTeamDiff = $teamPerformancesToTeamPerformanceDifferencesLayerLocalFactors[0]; | ||||||
|         $firstTeamDiffComparison = $teamDifferencesComparisonLayerLocalFactors[0]; |         $firstTeamDiffComparison = $teamDifferencesComparisonLayerLocalFactors[0]; | ||||||
| @@ -109,13 +109,13 @@ class IteratedTeamDifferencesInnerLayer extends TrueSkillFactorGraphLayer | |||||||
|  |  | ||||||
|     private function createMultipleTeamInnerPriorLoopSchedule(): ScheduleLoop |     private function createMultipleTeamInnerPriorLoopSchedule(): ScheduleLoop | ||||||
|     { |     { | ||||||
|         $totalTeamDifferences = count($this->TeamPerformancesToTeamPerformanceDifferencesLayer->getLocalFactors()); |         $totalTeamDifferences = count($this->teamPerformancesToTeamPerformanceDifferencesLayer->getLocalFactors()); | ||||||
|  |  | ||||||
|         $forwardScheduleList = []; |         $forwardScheduleList = []; | ||||||
|  |  | ||||||
|         for ($i = 0; $i < $totalTeamDifferences - 1; ++$i) { |         for ($i = 0; $i < $totalTeamDifferences - 1; ++$i) { | ||||||
|             $teamPerformancesToTeamPerformanceDifferencesLayerLocalFactors = $this->TeamPerformancesToTeamPerformanceDifferencesLayer->getLocalFactors(); |             $teamPerformancesToTeamPerformanceDifferencesLayerLocalFactors = $this->teamPerformancesToTeamPerformanceDifferencesLayer->getLocalFactors(); | ||||||
|             $teamDifferencesComparisonLayerLocalFactors = $this->TeamDifferencesComparisonLayer->getLocalFactors(); |             $teamDifferencesComparisonLayerLocalFactors = $this->teamDifferencesComparisonLayer->getLocalFactors(); | ||||||
|  |  | ||||||
|             $currentTeamPerfToTeamPerfDiff = $teamPerformancesToTeamPerformanceDifferencesLayerLocalFactors[$i]; |             $currentTeamPerfToTeamPerfDiff = $teamPerformancesToTeamPerformanceDifferencesLayerLocalFactors[$i]; | ||||||
|             $currentTeamDiffComparison = $teamDifferencesComparisonLayerLocalFactors[$i]; |             $currentTeamDiffComparison = $teamDifferencesComparisonLayerLocalFactors[$i]; | ||||||
| @@ -151,8 +151,8 @@ class IteratedTeamDifferencesInnerLayer extends TrueSkillFactorGraphLayer | |||||||
|         $backwardScheduleList = []; |         $backwardScheduleList = []; | ||||||
|  |  | ||||||
|         for ($i = 0; $i < $totalTeamDifferences - 1; ++$i) { |         for ($i = 0; $i < $totalTeamDifferences - 1; ++$i) { | ||||||
|             $teamPerformancesToTeamPerformanceDifferencesLayerLocalFactors = $this->TeamPerformancesToTeamPerformanceDifferencesLayer->getLocalFactors(); |             $teamPerformancesToTeamPerformanceDifferencesLayerLocalFactors = $this->teamPerformancesToTeamPerformanceDifferencesLayer->getLocalFactors(); | ||||||
|             $teamDifferencesComparisonLayerLocalFactors = $this->TeamDifferencesComparisonLayer->getLocalFactors(); |             $teamDifferencesComparisonLayerLocalFactors = $this->teamDifferencesComparisonLayer->getLocalFactors(); | ||||||
|  |  | ||||||
|             $differencesFactor = $teamPerformancesToTeamPerformanceDifferencesLayerLocalFactors[$totalTeamDifferences - 1 - $i]; |             $differencesFactor = $teamPerformancesToTeamPerformanceDifferencesLayerLocalFactors[$totalTeamDifferences - 1 - $i]; | ||||||
|             $comparisonFactor = $teamDifferencesComparisonLayerLocalFactors[$totalTeamDifferences - 1 - $i]; |             $comparisonFactor = $teamDifferencesComparisonLayerLocalFactors[$totalTeamDifferences - 1 - $i]; | ||||||
|   | |||||||
| @@ -27,8 +27,8 @@ class PlayerPerformancesToTeamPerformancesLayer extends TrueSkillFactorGraphLaye | |||||||
|             $this->addLayerFactor($newSumFactor); |             $this->addLayerFactor($newSumFactor); | ||||||
|  |  | ||||||
|             // REVIEW: Does it make sense to have groups of one? |             // REVIEW: Does it make sense to have groups of one? | ||||||
|             $outputVariablesGroups = &$this->getOutputVariablesGroups(); |             $outputVarGroups = &$this->getOutputVariablesGroups(); | ||||||
|             $outputVariablesGroups[] = [$teamPerformance]; |             $outputVarGroups[] = [$teamPerformance]; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -34,12 +34,12 @@ class PlayerPriorValuesToSkillsLayer extends TrueSkillFactorGraphLayer | |||||||
|             $localCurrentTeam = $currentTeam; |             $localCurrentTeam = $currentTeam; | ||||||
|             $currentTeamSkills = []; |             $currentTeamSkills = []; | ||||||
|  |  | ||||||
|             $currentTeamAllPlayers = $localCurrentTeam->getAllPlayers(); |             $curTeamAllPlayers = $localCurrentTeam->getAllPlayers(); | ||||||
|             foreach ($currentTeamAllPlayers as $currentTeamPlayer) { |             foreach ($curTeamAllPlayers as $curTeamPlayer) { | ||||||
|                 $localCurrentTeamPlayer = $currentTeamPlayer; |                 $localCurTeamPlayer = $curTeamPlayer; | ||||||
|                 $currentTeamPlayerRating = $currentTeam->getRating($localCurrentTeamPlayer); |                 $curTeamPlayerRating = $currentTeam->getRating($localCurTeamPlayer); | ||||||
|                 $playerSkill = $this->createSkillOutputVariable($localCurrentTeamPlayer); |                 $playerSkill = $this->createSkillOutputVariable($localCurTeamPlayer); | ||||||
|                 $priorFactor = $this->createPriorFactor($currentTeamPlayerRating, $playerSkill); |                 $priorFactor = $this->createPriorFactor($curTeamPlayerRating, $playerSkill); | ||||||
|                 $this->addLayerFactor($priorFactor); |                 $this->addLayerFactor($priorFactor); | ||||||
|                 $currentTeamSkills[] = $playerSkill; |                 $currentTeamSkills[] = $playerSkill; | ||||||
|             } |             } | ||||||
|   | |||||||
| @@ -15,25 +15,25 @@ class PlayerSkillsToPerformancesLayer extends TrueSkillFactorGraphLayer | |||||||
| { | { | ||||||
|     public function buildLayer(): void |     public function buildLayer(): void | ||||||
|     { |     { | ||||||
|         $inputVariablesGroups = $this->getInputVariablesGroups(); |         $inputVarGroups = $this->getInputVariablesGroups(); | ||||||
|         $outputVariablesGroups = &$this->getOutputVariablesGroups(); |         $outputVarGroups = &$this->getOutputVariablesGroups(); | ||||||
|  |  | ||||||
|         foreach ($inputVariablesGroups as $currentTeam) { |         foreach ($inputVarGroups as $currentTeam) { | ||||||
|             $currentTeamPlayerPerformances = []; |             $currentTeamPlayerPerformances = []; | ||||||
|  |  | ||||||
|             /** |             /** | ||||||
|              * @var Variable $playerSkillVariable |              * @var Variable $playerSkillVar | ||||||
|              */ |              */ | ||||||
|             foreach ($currentTeam as $playerSkillVariable) { |             foreach ($currentTeam as $playerSkillVar) { | ||||||
|                 $localPlayerSkillVariable = $playerSkillVariable; |                 $localPlayerSkillVar = $playerSkillVar; | ||||||
|                 $currentPlayer = ($localPlayerSkillVariable instanceof KeyedVariable) ? $localPlayerSkillVariable->getKey() : ""; |                 $currentPlayer = ($localPlayerSkillVar instanceof KeyedVariable) ? $localPlayerSkillVar->getKey() : ""; | ||||||
|                 $playerPerformance = $this->createOutputVariable($currentPlayer); |                 $playerPerformance = $this->createOutputVariable($currentPlayer); | ||||||
|                 $newLikelihoodFactor = $this->createLikelihood($localPlayerSkillVariable, $playerPerformance); |                 $newLikelihoodFactor = $this->createLikelihood($localPlayerSkillVar, $playerPerformance); | ||||||
|                 $this->addLayerFactor($newLikelihoodFactor); |                 $this->addLayerFactor($newLikelihoodFactor); | ||||||
|                 $currentTeamPlayerPerformances[] = $playerPerformance; |                 $currentTeamPlayerPerformances[] = $playerPerformance; | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             $outputVariablesGroups[] = $currentTeamPlayerPerformances; |             $outputVarGroups[] = $currentTeamPlayerPerformances; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -118,9 +118,9 @@ class TrueSkillFactorGraph extends FactorGraph | |||||||
|         $allLayersReverse = array_reverse($this->layers); |         $allLayersReverse = array_reverse($this->layers); | ||||||
|  |  | ||||||
|         foreach ($allLayersReverse as $currentLayer) { |         foreach ($allLayersReverse as $currentLayer) { | ||||||
|             $currentPosteriorSchedule = $currentLayer->createPosteriorSchedule(); |             $curPosteriorSchedule = $currentLayer->createPosteriorSchedule(); | ||||||
|             if ($currentPosteriorSchedule != NULL) { |             if ($curPosteriorSchedule != NULL) { | ||||||
|                 $fullSchedule[] = $currentPosteriorSchedule; |                 $fullSchedule[] = $curPosteriorSchedule; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -102,33 +102,33 @@ class TruncatedGaussianCorrectionFunctions | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     // the multiplicative correction of a double-sided truncated Gaussian with unit variance |     // the multiplicative correction of a double-sided truncated Gaussian with unit variance | ||||||
|     public static function wWithinMarginScaled(float $teamPerformanceDifference, float $drawMargin, float $c): float |     public static function wWithinMarginScaled(float $teamPerformanceDiff, float $drawMargin, float $c): float | ||||||
|     { |     { | ||||||
|         return self::wWithinMargin($teamPerformanceDifference / $c, $drawMargin / $c); |         return self::wWithinMargin($teamPerformanceDiff / $c, $drawMargin / $c); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // From F#: |     // From F#: | ||||||
|     public static function wWithinMargin(float $teamPerformanceDifference, float $drawMargin): float |     public static function wWithinMargin(float $teamPerformanceDiff, float $drawMargin): float | ||||||
|     { |     { | ||||||
|         $teamPerformanceDifferenceAbsoluteValue = abs($teamPerformanceDifference); |         $teamPerformanceDiffAbsValue = abs($teamPerformanceDiff); | ||||||
|         $denominator = GaussianDistribution::cumulativeTo($drawMargin - $teamPerformanceDifferenceAbsoluteValue) |         $denominator = GaussianDistribution::cumulativeTo($drawMargin - $teamPerformanceDiffAbsValue) | ||||||
|             - |             - | ||||||
|             GaussianDistribution::cumulativeTo(-$drawMargin - $teamPerformanceDifferenceAbsoluteValue); |             GaussianDistribution::cumulativeTo(-$drawMargin - $teamPerformanceDiffAbsValue); | ||||||
|  |  | ||||||
|         if ($denominator < 2.222758749e-162) { |         if ($denominator < 2.222758749e-162) { | ||||||
|             return 1.0; |             return 1.0; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         $vt = self::vWithinMargin($teamPerformanceDifferenceAbsoluteValue, $drawMargin); |         $vt = self::vWithinMargin($teamPerformanceDiffAbsValue, $drawMargin); | ||||||
|  |  | ||||||
|         return $vt * $vt + |         return $vt * $vt + | ||||||
|         (($drawMargin - $teamPerformanceDifferenceAbsoluteValue) |         (($drawMargin - $teamPerformanceDiffAbsValue) | ||||||
|             * |             * | ||||||
|             GaussianDistribution::at( |             GaussianDistribution::at( | ||||||
|                 $drawMargin - $teamPerformanceDifferenceAbsoluteValue |                 $drawMargin - $teamPerformanceDiffAbsValue | ||||||
|             ) |             ) | ||||||
|             - (-$drawMargin - $teamPerformanceDifferenceAbsoluteValue) |             - (-$drawMargin - $teamPerformanceDiffAbsValue) | ||||||
|             * |             * | ||||||
|             GaussianDistribution::at(-$drawMargin - $teamPerformanceDifferenceAbsoluteValue)) / $denominator; |             GaussianDistribution::at(-$drawMargin - $teamPerformanceDiffAbsValue)) / $denominator; | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -125,9 +125,9 @@ class TwoTeamTrueSkillCalculator extends SkillCalculator | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         $selfTeamAllPlayers = $selfTeam->getAllPlayers(); |         $selfTeamAllPlayers = $selfTeam->getAllPlayers(); | ||||||
|         foreach ($selfTeamAllPlayers as $selfTeamCurrentPlayer) { |         foreach ($selfTeamAllPlayers as $selfTeamCurPlayer) { | ||||||
|             $localSelfTeamCurrentPlayer = $selfTeamCurrentPlayer; |             $localSelfTeamCurPlayer = $selfTeamCurPlayer; | ||||||
|             $previousPlayerRating = $selfTeam->getRating($localSelfTeamCurrentPlayer); |             $previousPlayerRating = $selfTeam->getRating($localSelfTeamCurPlayer); | ||||||
|  |  | ||||||
|             $meanMultiplier = (BasicMath::square($previousPlayerRating->getStandardDeviation()) + $tauSquared) / $c; |             $meanMultiplier = (BasicMath::square($previousPlayerRating->getStandardDeviation()) + $tauSquared) / $c; | ||||||
|             $stdDevMultiplier = (BasicMath::square($previousPlayerRating->getStandardDeviation()) + $tauSquared) / BasicMath::square($c); |             $stdDevMultiplier = (BasicMath::square($previousPlayerRating->getStandardDeviation()) + $tauSquared) / BasicMath::square($c); | ||||||
| @@ -139,7 +139,7 @@ class TwoTeamTrueSkillCalculator extends SkillCalculator | |||||||
|                 (BasicMath::square($previousPlayerRating->getStandardDeviation()) + $tauSquared) * (1 - $w * $stdDevMultiplier) |                 (BasicMath::square($previousPlayerRating->getStandardDeviation()) + $tauSquared) * (1 - $w * $stdDevMultiplier) | ||||||
|             ); |             ); | ||||||
|  |  | ||||||
|             $newPlayerRatings->setRating($localSelfTeamCurrentPlayer, new Rating($newMean, $newStdDev)); |             $newPlayerRatings->setRating($localSelfTeamCurPlayer, new Rating($newMean, $newStdDev)); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -7,6 +7,7 @@ namespace DNW\Skills\Tests; | |||||||
| use DNW\Skills\HashMap; | use DNW\Skills\HashMap; | ||||||
| use PHPUnit\Framework\TestCase; | use PHPUnit\Framework\TestCase; | ||||||
| use PHPUnit\Framework\Attributes\CoversClass; | use PHPUnit\Framework\Attributes\CoversClass; | ||||||
|  | use stdClass; | ||||||
|  |  | ||||||
| #[CoversClass(HashMap::class)] | #[CoversClass(HashMap::class)] | ||||||
| class HashMapTest extends TestCase | class HashMapTest extends TestCase | ||||||
| @@ -19,8 +20,8 @@ class HashMapTest extends TestCase | |||||||
|         $this->assertEquals([], $h->getAllValues()); |         $this->assertEquals([], $h->getAllValues()); | ||||||
|  |  | ||||||
|  |  | ||||||
|         $o1 = new \stdClass(); |         $o1 = new stdClass(); | ||||||
|         $o2 = new \stdClass(); |         $o2 = new stdClass(); | ||||||
|  |  | ||||||
|         $h->setValue($o1, 1); |         $h->setValue($o1, 1); | ||||||
|         $h->setvalue($o2, 2); |         $h->setvalue($o2, 2); | ||||||
|   | |||||||
| @@ -9,7 +9,6 @@ use DNW\Skills\Player; | |||||||
| use DNW\Skills\Rating; | use DNW\Skills\Rating; | ||||||
| use DNW\Skills\SkillCalculator; | use DNW\Skills\SkillCalculator; | ||||||
| use DNW\Skills\Team; | use DNW\Skills\Team; | ||||||
| use DNW\Skills\Teams; |  | ||||||
| use PHPUnit\Framework\TestCase; | use PHPUnit\Framework\TestCase; | ||||||
|  |  | ||||||
| class TrueSkillCalculatorTests | class TrueSkillCalculatorTests | ||||||
| @@ -70,7 +69,6 @@ class TrueSkillCalculatorTests | |||||||
|     // online calculator at http://atom.research.microsoft.com/trueskill/rankcalculator.aspx |     // online calculator at http://atom.research.microsoft.com/trueskill/rankcalculator.aspx | ||||||
|     // |     // | ||||||
|     // All match quality expected values came from the online calculator |     // All match quality expected values came from the online calculator | ||||||
|  |  | ||||||
|     // In both cases, there may be some discrepancy after the first decimal point. I think this is due to my implementation |     // In both cases, there may be some discrepancy after the first decimal point. I think this is due to my implementation | ||||||
|     // using slightly higher precision in GaussianDistribution. |     // using slightly higher precision in GaussianDistribution. | ||||||
|  |  | ||||||
| @@ -849,24 +847,7 @@ class TrueSkillCalculatorTests | |||||||
|         $team15 = new Team($player15, $gameInfo->getDefaultRating()); |         $team15 = new Team($player15, $gameInfo->getDefaultRating()); | ||||||
|         $team16 = new Team($player16, $gameInfo->getDefaultRating()); |         $team16 = new Team($player16, $gameInfo->getDefaultRating()); | ||||||
|  |  | ||||||
|         $teams = [ |         $teams = [$team1, $team2, $team3, $team4, $team5, $team6, $team7, $team8, $team9, $team10, $team11, $team12, $team13, $team14, $team15, $team16]; | ||||||
|             $team1, |  | ||||||
|             $team2, |  | ||||||
|             $team3, |  | ||||||
|             $team4, |  | ||||||
|             $team5, |  | ||||||
|             $team6, |  | ||||||
|             $team7, |  | ||||||
|             $team8, |  | ||||||
|             $team9, |  | ||||||
|             $team10, |  | ||||||
|             $team11, |  | ||||||
|             $team12, |  | ||||||
|             $team13, |  | ||||||
|             $team14, |  | ||||||
|             $team15, |  | ||||||
|             $team16 |  | ||||||
|         ]; |  | ||||||
|  |  | ||||||
|         $newRatings = $calculator->calculateNewRatings( |         $newRatings = $calculator->calculateNewRatings( | ||||||
|             $gameInfo, |             $gameInfo, | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user