Compare commits

...

9 Commits

Author SHA1 Message Date
063a64a4f6 Less Stringable
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
2024-03-19 16:24:19 +00:00
796bd993d0 Even less strings 2024-03-19 15:56:57 +00:00
bbff1fbbbc More stringable removal for performance. 2024-03-19 15:48:29 +00:00
ae5d2a8b73 String based "name" for Variable class removed for performance 2024-03-19 15:09:13 +00:00
0095829906 Stringable removed. 2024-03-19 14:38:55 +00:00
e5a96226ca More stringable 2024-03-19 14:10:19 +00:00
11fafc129a Slowly getting rid of stringable. 2024-03-19 14:10:11 +00:00
73ef2f45c8 Quicker hash 2024-03-19 12:57:56 +00:00
fd91e9b0c1 Minor performance boost 2024-03-19 12:49:14 +00:00
31 changed files with 142 additions and 256 deletions

70
composer.lock generated

@ -822,21 +822,21 @@
}, },
{ {
"name": "nikic/php-parser", "name": "nikic/php-parser",
"version": "v4.18.0", "version": "v4.19.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/nikic/PHP-Parser.git", "url": "https://github.com/nikic/PHP-Parser.git",
"reference": "1bcbb2179f97633e98bbbc87044ee2611c7d7999" "reference": "4e1b88d21c69391150ace211e9eaf05810858d0b"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/1bcbb2179f97633e98bbbc87044ee2611c7d7999", "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/4e1b88d21c69391150ace211e9eaf05810858d0b",
"reference": "1bcbb2179f97633e98bbbc87044ee2611c7d7999", "reference": "4e1b88d21c69391150ace211e9eaf05810858d0b",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"ext-tokenizer": "*", "ext-tokenizer": "*",
"php": ">=7.0" "php": ">=7.1"
}, },
"require-dev": { "require-dev": {
"ircmaxell/php-yacc": "^0.0.7", "ircmaxell/php-yacc": "^0.0.7",
@ -872,9 +872,9 @@
], ],
"support": { "support": {
"issues": "https://github.com/nikic/PHP-Parser/issues", "issues": "https://github.com/nikic/PHP-Parser/issues",
"source": "https://github.com/nikic/PHP-Parser/tree/v4.18.0" "source": "https://github.com/nikic/PHP-Parser/tree/v4.19.1"
}, },
"time": "2023-12-10T21:03:43+00:00" "time": "2024-03-17T08:10:35+00:00"
}, },
{ {
"name": "phar-io/manifest", "name": "phar-io/manifest",
@ -1287,16 +1287,16 @@
}, },
{ {
"name": "phpstan/phpstan", "name": "phpstan/phpstan",
"version": "1.10.60", "version": "1.10.63",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/phpstan/phpstan.git", "url": "https://github.com/phpstan/phpstan.git",
"reference": "95dcea7d6c628a3f2f56d091d8a0219485a86bbe" "reference": "ad12836d9ca227301f5fb9960979574ed8628339"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/95dcea7d6c628a3f2f56d091d8a0219485a86bbe", "url": "https://api.github.com/repos/phpstan/phpstan/zipball/ad12836d9ca227301f5fb9960979574ed8628339",
"reference": "95dcea7d6c628a3f2f56d091d8a0219485a86bbe", "reference": "ad12836d9ca227301f5fb9960979574ed8628339",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -1345,20 +1345,20 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2024-03-07T13:30:19+00:00" "time": "2024-03-18T16:53:53+00:00"
}, },
{ {
"name": "phpunit/php-code-coverage", "name": "phpunit/php-code-coverage",
"version": "10.1.13", "version": "10.1.14",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/sebastianbergmann/php-code-coverage.git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git",
"reference": "d51c3aec14896d5e80b354fad58e998d1980f8f8" "reference": "e3f51450ebffe8e0efdf7346ae966a656f7d5e5b"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/d51c3aec14896d5e80b354fad58e998d1980f8f8", "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/e3f51450ebffe8e0efdf7346ae966a656f7d5e5b",
"reference": "d51c3aec14896d5e80b354fad58e998d1980f8f8", "reference": "e3f51450ebffe8e0efdf7346ae966a656f7d5e5b",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -1415,7 +1415,7 @@
"support": { "support": {
"issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
"security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy",
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/10.1.13" "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/10.1.14"
}, },
"funding": [ "funding": [
{ {
@ -1423,7 +1423,7 @@
"type": "github" "type": "github"
} }
], ],
"time": "2024-03-09T16:54:15+00:00" "time": "2024-03-12T15:33:41+00:00"
}, },
{ {
"name": "phpunit/php-file-iterator", "name": "phpunit/php-file-iterator",
@ -1670,16 +1670,16 @@
}, },
{ {
"name": "phpunit/phpunit", "name": "phpunit/phpunit",
"version": "10.5.12", "version": "10.5.13",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git", "url": "https://github.com/sebastianbergmann/phpunit.git",
"reference": "41a9886b85ac7bf3929853baf96b95361cd69d2b" "reference": "20a63fc1c6db29b15da3bd02d4b6cf59900088a7"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/41a9886b85ac7bf3929853baf96b95361cd69d2b", "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/20a63fc1c6db29b15da3bd02d4b6cf59900088a7",
"reference": "41a9886b85ac7bf3929853baf96b95361cd69d2b", "reference": "20a63fc1c6db29b15da3bd02d4b6cf59900088a7",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -1751,7 +1751,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.12" "source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.13"
}, },
"funding": [ "funding": [
{ {
@ -1767,7 +1767,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2024-03-09T12:04:07+00:00" "time": "2024-03-12T15:37:41+00:00"
}, },
{ {
"name": "psalm/plugin-phpunit", "name": "psalm/plugin-phpunit",
@ -1934,16 +1934,16 @@
}, },
{ {
"name": "rector/rector", "name": "rector/rector",
"version": "1.0.2", "version": "1.0.3",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/rectorphp/rector.git", "url": "https://github.com/rectorphp/rector.git",
"reference": "7596fa6da06c6a20c012efe6bb3d9188a9113b11" "reference": "c59507a9090b465d65e1aceed91e5b81986e375b"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/rectorphp/rector/zipball/7596fa6da06c6a20c012efe6bb3d9188a9113b11", "url": "https://api.github.com/repos/rectorphp/rector/zipball/c59507a9090b465d65e1aceed91e5b81986e375b",
"reference": "7596fa6da06c6a20c012efe6bb3d9188a9113b11", "reference": "c59507a9090b465d65e1aceed91e5b81986e375b",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -1978,7 +1978,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.0.2" "source": "https://github.com/rectorphp/rector/tree/1.0.3"
}, },
"funding": [ "funding": [
{ {
@ -1986,7 +1986,7 @@
"type": "github" "type": "github"
} }
], ],
"time": "2024-03-03T12:32:31+00:00" "time": "2024-03-14T15:04:18+00:00"
}, },
{ {
"name": "sebastian/cli-parser", "name": "sebastian/cli-parser",
@ -3661,16 +3661,16 @@
}, },
{ {
"name": "vimeo/psalm", "name": "vimeo/psalm",
"version": "5.23.0", "version": "5.23.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/vimeo/psalm.git", "url": "https://github.com/vimeo/psalm.git",
"reference": "005e3184fb6de4350a873b9b8c4dc3cede9db762" "reference": "8471a896ccea3526b26d082f4461eeea467f10a4"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/vimeo/psalm/zipball/005e3184fb6de4350a873b9b8c4dc3cede9db762", "url": "https://api.github.com/repos/vimeo/psalm/zipball/8471a896ccea3526b26d082f4461eeea467f10a4",
"reference": "005e3184fb6de4350a873b9b8c4dc3cede9db762", "reference": "8471a896ccea3526b26d082f4461eeea467f10a4",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -3767,7 +3767,7 @@
"issues": "https://github.com/vimeo/psalm/issues", "issues": "https://github.com/vimeo/psalm/issues",
"source": "https://github.com/vimeo/psalm" "source": "https://github.com/vimeo/psalm"
}, },
"time": "2024-03-09T19:39:11+00:00" "time": "2024-03-11T20:33:46+00:00"
}, },
{ {
"name": "webmozart/assert", "name": "webmozart/assert",

@ -8,7 +8,7 @@ use DNW\Skills\Guard;
use DNW\Skills\HashMap; use DNW\Skills\HashMap;
use Exception; use Exception;
abstract class Factor implements \Stringable abstract class Factor
{ {
/** /**
* @var Message[] $messages * @var Message[] $messages
@ -17,16 +17,13 @@ abstract class Factor implements \Stringable
private readonly HashMap $messageToVariableBinding; private readonly HashMap $messageToVariableBinding;
private readonly string $name;
/** /**
* @var Variable[] $variables * @var Variable[] $variables
*/ */
private array $variables = []; private array $variables = [];
protected function __construct(string $name) protected function __construct()
{ {
$this->name = 'Factor[' . $name . ']';
$this->messageToVariableBinding = new HashMap(); $this->messageToVariableBinding = new HashMap();
} }
@ -80,7 +77,7 @@ abstract class Factor implements \Stringable
protected function updateMessageVariable(Message $message, Variable $variable): float protected function updateMessageVariable(Message $message, Variable $variable): float
{ {
throw new Exception(); throw new Exception("Must override updateMessageVariable(" . $message::class . ", " . $variable::class . ")");
} }
/** /**
@ -121,9 +118,4 @@ abstract class Factor implements \Stringable
return $message; return $message;
} }
public function __toString(): string
{
return $this->name;
}
} }

@ -70,9 +70,9 @@ abstract class FactorGraphLayer
/** /**
* @param Schedule[] $itemsToSequence * @param Schedule[] $itemsToSequence
*/ */
protected function scheduleSequence(array $itemsToSequence, string $name): ScheduleSequence protected function scheduleSequence(array $itemsToSequence): ScheduleSequence
{ {
return new ScheduleSequence($name, $itemsToSequence); return new ScheduleSequence($itemsToSequence);
} }
protected function addLayerFactor(Factor $factor): void protected function addLayerFactor(Factor $factor): void

@ -6,9 +6,9 @@ namespace DNW\Skills\FactorGraphs;
class KeyedVariable extends Variable class KeyedVariable extends Variable
{ {
public function __construct(private readonly mixed $key, string $name, mixed $prior) public function __construct(private readonly mixed $key, mixed $prior)
{ {
parent::__construct($name, $prior); parent::__construct($prior);
} }
public function getKey(): mixed public function getKey(): mixed

@ -6,9 +6,9 @@ namespace DNW\Skills\FactorGraphs;
use DNW\Skills\Numerics\GaussianDistribution; use DNW\Skills\Numerics\GaussianDistribution;
class Message implements \Stringable class Message
{ {
public function __construct(private GaussianDistribution $value, private readonly string $name) public function __construct(private GaussianDistribution $value)
{ {
} }
@ -21,9 +21,4 @@ class Message implements \Stringable
{ {
$this->value = $value; $this->value = $value;
} }
public function __toString(): string
{
return $this->name;
}
} }

@ -4,16 +4,7 @@ declare(strict_types=1);
namespace DNW\Skills\FactorGraphs; namespace DNW\Skills\FactorGraphs;
abstract class Schedule implements \Stringable abstract class Schedule
{ {
protected function __construct(private readonly string $name)
{
}
abstract public function visit(int $depth = -1, int $maxDepth = 0): float; abstract public function visit(int $depth = -1, int $maxDepth = 0): float;
public function __toString(): string
{
return $this->name;
}
} }

@ -6,9 +6,8 @@ namespace DNW\Skills\FactorGraphs;
class ScheduleLoop extends Schedule class ScheduleLoop extends Schedule
{ {
public function __construct(string $name, private readonly Schedule $scheduleToLoop, private readonly float $maxDelta) public function __construct(private readonly Schedule $scheduleToLoop, private readonly float $maxDelta)
{ {
parent::__construct($name);
} }
public function visit(int $depth = -1, int $maxDepth = 0): float public function visit(int $depth = -1, int $maxDepth = 0): float

@ -9,9 +9,8 @@ class ScheduleSequence extends Schedule
/** /**
* @param Schedule[] $schedules * @param Schedule[] $schedules
*/ */
public function __construct(string $name, private readonly array $schedules) public function __construct(private readonly array $schedules)
{ {
parent::__construct($name);
} }
public function visit(int $depth = -1, int $maxDepth = 0): float public function visit(int $depth = -1, int $maxDepth = 0): float

@ -6,15 +6,12 @@ namespace DNW\Skills\FactorGraphs;
class ScheduleStep extends Schedule class ScheduleStep extends Schedule
{ {
public function __construct(string $name, private readonly Factor $factor, private readonly int $index) public function __construct(private readonly Factor $factor, private readonly int $index)
{ {
parent::__construct($name);
} }
public function visit(int $depth = -1, int $maxDepth = 0): float public function visit(int $depth = -1, int $maxDepth = 0): float
{ {
$currentFactor = $this->factor; return $this->factor->updateMessageIndex($this->index);
return $currentFactor->updateMessageIndex($this->index);
} }
} }

@ -6,15 +6,12 @@ namespace DNW\Skills\FactorGraphs;
use DNW\Skills\Numerics\GaussianDistribution; use DNW\Skills\Numerics\GaussianDistribution;
class Variable implements \Stringable class Variable
{ {
private readonly string $name;
private mixed $value; private mixed $value;
public function __construct(string $name, private GaussianDistribution $prior) public function __construct(private GaussianDistribution $prior)
{ {
$this->name = 'Variable[' . $name . ']';
$this->resetToPrior(); $this->resetToPrior();
} }
@ -32,9 +29,4 @@ class Variable implements \Stringable
{ {
$this->value = $this->prior; $this->value = $this->prior;
} }
public function __toString(): string
{
return $this->name;
}
} }

@ -10,17 +10,17 @@ class VariableFactory
{ {
} }
public function createBasicVariable(string $name): Variable public function createBasicVariable(): Variable
{ {
$initializer = $this->variablePriorInitializer; $initializer = $this->variablePriorInitializer;
return new Variable($name, $initializer()); return new Variable($initializer());
} }
public function createKeyedVariable(mixed $key, string $name): KeyedVariable public function createKeyedVariable(mixed $key): KeyedVariable
{ {
$initializer = $this->variablePriorInitializer; $initializer = $this->variablePriorInitializer;
return new KeyedVariable($key, $name, $initializer()); return new KeyedVariable($key, $initializer());
} }
} }

@ -19,16 +19,16 @@ class HashMap
*/ */
private array $hashToKey = []; private array $hashToKey = [];
public function getValue(string|object $key): mixed public function getValue(object $key): object
{ {
$hash = self::getHash($key); $hash = spl_object_id($key);
return $this->hashToValue[$hash]; return $this->hashToValue[$hash];
} }
public function setValue(string|object $key, mixed $value): self public function setValue(object $key, mixed $value): self
{ {
$hash = self::getHash($key); $hash = spl_object_id($key);
$this->hashToKey[$hash] = $key; $this->hashToKey[$hash] = $key;
$this->hashToValue[$hash] = $value; $this->hashToValue[$hash] = $value;
@ -55,13 +55,4 @@ class HashMap
{ {
return count($this->hashToKey); return count($this->hashToKey);
} }
private static function getHash(string|object $key): string
{
if (is_object($key)) {
return spl_object_hash($key);
}
return $key;
}
} }

@ -10,8 +10,12 @@ namespace DNW\Skills\Numerics;
* @author Jeff Moser <jeff@moserware.com> * @author Jeff Moser <jeff@moserware.com>
* @copyright 2010 Jeff Moser * @copyright 2010 Jeff Moser
*/ */
class GaussianDistribution implements \Stringable class GaussianDistribution
{ {
private const DEFAULT_STANDARD_DEVIATION = 1.0;
private const DEFAULT_MEAN = 0.0;
/** /**
* Square Root 2π. * Square Root 2π.
* Precalculated constant for performance reasons * Precalculated constant for performance reasons
@ -31,17 +35,21 @@ class GaussianDistribution implements \Stringable
private const M_LOG_SQRT_2_PI = 0.9189385332046727417803297364056176398613974736377834128171515404; private const M_LOG_SQRT_2_PI = 0.9189385332046727417803297364056176398613974736377834128171515404;
// precision and precisionMean are used because they make multiplying and dividing simpler // precision and precisionMean are used because they make multiplying and dividing simpler
// (the the accompanying math paper for more details) // (see the accompanying math paper for more details)
private float $precision; private float $precision = 1.0;
private float $precisionMean; private float $precisionMean = 0.0;
private float $variance; private float $variance = 1.0;
public function __construct(private float $mean = 0.0, private float $standardDeviation = 1.0) public function __construct(private float $mean = self::DEFAULT_MEAN, private float $standardDeviation = self::DEFAULT_STANDARD_DEVIATION)
{ {
$this->variance = BasicMath::square($standardDeviation); if ($mean == self::DEFAULT_MEAN && $standardDeviation == self::DEFAULT_STANDARD_DEVIATION) {
//Use all the defaults
return;
}
$this->variance = BasicMath::square($standardDeviation);
if ($this->variance != 0) { if ($this->variance != 0) {
$this->precision = 1.0 / $this->variance; $this->precision = 1.0 / $this->variance;
$this->precisionMean = $this->precision * $this->mean; $this->precisionMean = $this->precision * $this->mean;
@ -180,7 +188,7 @@ class GaussianDistribution implements \Stringable
return $multiplier * $expPart; return $multiplier * $expPart;
} }
public static function cumulativeTo(float $x, float $mean = 0.0, float $standardDeviation = 1.0): float public static function cumulativeTo(float $x): float
{ {
$result = GaussianDistribution::errorFunctionCumulativeTo(-M_SQRT1_2 * $x); $result = GaussianDistribution::errorFunctionCumulativeTo(-M_SQRT1_2 * $x);
@ -270,9 +278,4 @@ class GaussianDistribution implements \Stringable
// 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 * $x);
} }
public function __toString(): string
{
return sprintf('mean=%.4f standardDeviation=%.4f', $this->mean, $this->standardDeviation);
}
} }

@ -7,7 +7,7 @@ namespace DNW\Skills;
/** /**
* Represents a player who has a Rating. * Represents a player who has a Rating.
*/ */
class Player implements ISupportPartialPlay, ISupportPartialUpdate, \Stringable class Player implements ISupportPartialPlay, ISupportPartialUpdate
{ {
private const DEFAULT_PARTIAL_PLAY_PERCENTAGE = 1.0; // = 100% play time private const DEFAULT_PARTIAL_PLAY_PERCENTAGE = 1.0; // = 100% play time
@ -20,7 +20,7 @@ class Player implements ISupportPartialPlay, ISupportPartialUpdate, \Stringable
/** /**
* Constructs a player. * Constructs a player.
* *
* @param mixed $Id The identifier for the player, such as a name. * @param mixed $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 $partialPlayPercentage 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 $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.
*/ */
@ -59,9 +59,4 @@ class Player implements ISupportPartialPlay, ISupportPartialUpdate, \Stringable
{ {
return $this->PartialUpdatePercentage; return $this->PartialUpdatePercentage;
} }
public function __toString(): string
{
return (string)$this->Id;
}
} }

@ -9,7 +9,7 @@ use DNW\Skills\Numerics\GaussianDistribution;
/** /**
* Container for a player's rating. * Container for a player's rating.
*/ */
class Rating implements \Stringable class Rating
{ {
private const CONSERVATIVE_STANDARD_DEVIATION_MULTIPLIER = 3; private const CONSERVATIVE_STANDARD_DEVIATION_MULTIPLIER = 3;
@ -73,9 +73,4 @@ class Rating implements \Stringable
return new Rating($partialPosteriorGaussion->getMean(), $partialPosteriorGaussion->getStandardDeviation(), $prior->conservativeStandardDeviationMultiplier); return new Rating($partialPosteriorGaussion->getMean(), $partialPosteriorGaussion->getStandardDeviation(), $prior->conservativeStandardDeviationMultiplier);
} }
public function __toString(): string
{
return sprintf('mean=%.4f, standardDeviation=%.4f', $this->mean, $this->standardDeviation);
}
} }

@ -32,7 +32,6 @@ abstract class GaussianFactor extends Factor
$variable, $variable,
new Message( new Message(
$newDistribution, $newDistribution,
sprintf('message from %s to %s', (string)$this, (string)$variable)
) )
); );
} }

@ -16,12 +16,9 @@ use DNW\Skills\TrueSkill\TruncatedGaussianCorrectionFunctions;
*/ */
class GaussianGreaterThanFactor extends GaussianFactor class GaussianGreaterThanFactor extends GaussianFactor
{ {
private readonly float $epsilon; public function __construct(private readonly float $epsilon, Variable $variable)
public function __construct(float $epsilon, Variable $variable)
{ {
parent::__construct(\sprintf('%s > %.2f', (string)$variable, $epsilon)); parent::__construct();
$this->epsilon = $epsilon;
$this->createVariableToMessageBinding($variable); $this->createVariableToMessageBinding($variable);
} }

@ -21,7 +21,8 @@ class GaussianLikelihoodFactor extends GaussianFactor
public function __construct(float $betaSquared, Variable $variable1, Variable $variable2) public function __construct(float $betaSquared, Variable $variable1, Variable $variable2)
{ {
parent::__construct(sprintf('Likelihood of %s going to %s', (string)$variable2, (string)$variable1)); //Likelihood of $variable1 going to $variable2
parent::__construct();
$this->precision = 1.0 / $betaSquared; $this->precision = 1.0 / $betaSquared;
$this->createVariableToMessageBinding($variable1); $this->createVariableToMessageBinding($variable1);
$this->createVariableToMessageBinding($variable2); $this->createVariableToMessageBinding($variable2);

@ -19,11 +19,11 @@ class GaussianPriorFactor extends GaussianFactor
public function __construct(float $mean, float $variance, Variable $variable) public function __construct(float $mean, float $variance, Variable $variable)
{ {
parent::__construct(sprintf('Prior value going to %s', (string)$variable)); //Prior value going to $variable
parent::__construct();
$this->newMessage = new GaussianDistribution($mean, sqrt($variance)); $this->newMessage = new GaussianDistribution($mean, sqrt($variance));
$newMessage = new Message( $newMessage = new Message(
GaussianDistribution::fromPrecisionMean(0, 0), GaussianDistribution::fromPrecisionMean(0, 0)
sprintf('message from %s to %s', (string)$this, (string)$variable)
); );
$this->createVariableToMessageBindingWithMessage($variable, $newMessage); $this->createVariableToMessageBindingWithMessage($variable, $newMessage);

@ -42,7 +42,7 @@ class GaussianWeightedSumFactor extends GaussianFactor
*/ */
public function __construct(Variable $sumVariable, array $variablesToSum, array $variableWeights) public function __construct(Variable $sumVariable, array $variablesToSum, array $variableWeights)
{ {
parent::__construct(self::createName((string)$sumVariable, $variablesToSum, $variableWeights)); parent::__construct();
// The first weights are a straightforward copy // The first weights are a straightforward copy
// v_0 = a_1*v_1 + a_2*v_2 + ... + a_n * v_n // v_0 = a_1*v_1 + a_2*v_2 + ... + a_n * v_n
@ -235,42 +235,4 @@ class GaussianWeightedSumFactor extends GaussianFactor
$updatedVariables $updatedVariables
); );
} }
/**
* @param Variable[] $variablesToSum
* @param float[] $weights
*/
private static function createName(string $sumVariable, array $variablesToSum, array $weights): string
{
// TODO: Perf? Use PHP equivalent of StringBuilder? implode on arrays?
$result = $sumVariable;
$result .= ' = ';
$totalVars = count($variablesToSum);
for ($i = 0; $i < $totalVars; ++$i) {
$isFirst = ($i == 0);
if ($isFirst && ($weights[$i] < 0)) {
$result .= '-';
}
$absValue = sprintf('%.2f', \abs($weights[$i])); // 0.00?
$result .= $absValue;
$result .= '*[';
$result .= (string)$variablesToSum[$i];
$result .= ']';
$isLast = ($i === $totalVars - 1);
if (! $isLast) {
if ($weights[$i + 1] >= 0) {
$result .= ' + ';
} else {
$result .= ' - ';
}
}
}
return $result;
}
} }

@ -16,12 +16,10 @@ use DNW\Skills\TrueSkill\TruncatedGaussianCorrectionFunctions;
*/ */
class GaussianWithinFactor extends GaussianFactor class GaussianWithinFactor extends GaussianFactor
{ {
private readonly float $epsilon; public function __construct(private readonly float $epsilon, Variable $variable)
public function __construct(float $epsilon, Variable $variable)
{ {
parent::__construct(sprintf('%s <= %.2f', (string)$variable, $epsilon)); //$epsilon <= $variable
$this->epsilon = $epsilon; parent::__construct();
$this->createVariableToMessageBinding($variable); $this->createVariableToMessageBinding($variable);
} }

@ -63,17 +63,17 @@ class IteratedTeamDifferencesInnerLayer extends TrueSkillFactorGraphLayer
$firstDifferencesFactor = $localFactors[0]; $firstDifferencesFactor = $localFactors[0];
$lastDifferencesFactor = $localFactors[$totalTeamDifferences - 1]; $lastDifferencesFactor = $localFactors[$totalTeamDifferences - 1];
//inner schedule
return new ScheduleSequence( return new ScheduleSequence(
'inner schedule',
[ [
$loop, $loop,
//teamPerformanceToPerformanceDifferenceFactors[0] @ 1
new ScheduleStep( new ScheduleStep(
'teamPerformanceToPerformanceDifferenceFactors[0] @ 1',
$firstDifferencesFactor, $firstDifferencesFactor,
1 1
), ),
//teamPerformanceToPerformanceDifferenceFactors[teamTeamDifferences = %d - 1] @ 2
new ScheduleStep( new ScheduleStep(
sprintf('teamPerformanceToPerformanceDifferenceFactors[teamTeamDifferences = %d - 1] @ 2', $totalTeamDifferences),
$lastDifferencesFactor, $lastDifferencesFactor,
2 2
), ),
@ -89,21 +89,21 @@ class IteratedTeamDifferencesInnerLayer extends TrueSkillFactorGraphLayer
$firstPerfToTeamDiff = $teamPerformancesToTeamPerformanceDifferencesLayerLocalFactors[0]; $firstPerfToTeamDiff = $teamPerformancesToTeamPerformanceDifferencesLayerLocalFactors[0];
$firstTeamDiffComparison = $teamDifferencesComparisonLayerLocalFactors[0]; $firstTeamDiffComparison = $teamDifferencesComparisonLayerLocalFactors[0];
$itemsToSequence = [ $itemsToSequence = [
//send team perf to perf differences
new ScheduleStep( new ScheduleStep(
'send team perf to perf differences',
$firstPerfToTeamDiff, $firstPerfToTeamDiff,
0 0
), ),
//send to greater than or within factor
new ScheduleStep( new ScheduleStep(
'send to greater than or within factor',
$firstTeamDiffComparison, $firstTeamDiffComparison,
0 0
), ),
]; ];
//loop of just two teams inner sequence
return $this->scheduleSequence( return $this->scheduleSequence(
$itemsToSequence, $itemsToSequence
'loop of just two teams inner sequence'
); );
} }
@ -120,32 +120,33 @@ class IteratedTeamDifferencesInnerLayer extends TrueSkillFactorGraphLayer
$currentTeamPerfToTeamPerfDiff = $teamPerformancesToTeamPerformanceDifferencesLayerLocalFactors[$i]; $currentTeamPerfToTeamPerfDiff = $teamPerformancesToTeamPerformanceDifferencesLayerLocalFactors[$i];
$currentTeamDiffComparison = $teamDifferencesComparisonLayerLocalFactors[$i]; $currentTeamDiffComparison = $teamDifferencesComparisonLayerLocalFactors[$i];
//current forward schedule piece $i
$currentForwardSchedulePiece = $currentForwardSchedulePiece =
$this->scheduleSequence( $this->scheduleSequence(
[ [
//team perf to perf diff
new ScheduleStep( new ScheduleStep(
sprintf('team perf to perf diff %d', $i),
$currentTeamPerfToTeamPerfDiff, $currentTeamPerfToTeamPerfDiff,
0 0
), ),
//greater than or within result factor
new ScheduleStep( new ScheduleStep(
sprintf('greater than or within result factor %d', $i),
$currentTeamDiffComparison, $currentTeamDiffComparison,
0 0
), ),
//'team perf to perf diff factors
new ScheduleStep( new ScheduleStep(
sprintf('team perf to perf diff factors [%d], 2', $i),
$currentTeamPerfToTeamPerfDiff, $currentTeamPerfToTeamPerfDiff,
2 2
), ),
], ]
sprintf('current forward schedule piece %d', $i)
); );
$forwardScheduleList[] = $currentForwardSchedulePiece; $forwardScheduleList[] = $currentForwardSchedulePiece;
} }
$forwardSchedule = new ScheduleSequence('forward schedule', $forwardScheduleList); //forward schedule
$forwardSchedule = new ScheduleSequence($forwardScheduleList);
$backwardScheduleList = []; $backwardScheduleList = [];
@ -157,21 +158,21 @@ class IteratedTeamDifferencesInnerLayer extends TrueSkillFactorGraphLayer
$comparisonFactor = $teamDifferencesComparisonLayerLocalFactors[$totalTeamDifferences - 1 - $i]; $comparisonFactor = $teamDifferencesComparisonLayerLocalFactors[$totalTeamDifferences - 1 - $i];
$performancesToDifferencesFactor = $teamPerformancesToTeamPerformanceDifferencesLayerLocalFactors[$totalTeamDifferences - 1 - $i]; $performancesToDifferencesFactor = $teamPerformancesToTeamPerformanceDifferencesLayerLocalFactors[$totalTeamDifferences - 1 - $i];
//current backward schedule piece
$currentBackwardSchedulePiece = new ScheduleSequence( $currentBackwardSchedulePiece = new ScheduleSequence(
'current backward schedule piece',
[ [
//teamPerformanceToPerformanceDifferenceFactors[totalTeamDifferences - 1 - %d] @ 0
new ScheduleStep( new ScheduleStep(
sprintf('teamPerformanceToPerformanceDifferenceFactors[totalTeamDifferences - 1 - %d] @ 0', $i),
$differencesFactor, $differencesFactor,
0 0
), ),
//greaterThanOrWithinResultFactors[totalTeamDifferences - 1 - %d] @ 0
new ScheduleStep( new ScheduleStep(
sprintf('greaterThanOrWithinResultFactors[totalTeamDifferences - 1 - %d] @ 0', $i),
$comparisonFactor, $comparisonFactor,
0 0
), ),
//teamPerformanceToPerformanceDifferenceFactors[totalTeamDifferences - 1 - %d] @ 1
new ScheduleStep( new ScheduleStep(
sprintf('teamPerformanceToPerformanceDifferenceFactors[totalTeamDifferences - 1 - %d] @ 1', $i),
$performancesToDifferencesFactor, $performancesToDifferencesFactor,
1 1
), ),
@ -180,18 +181,19 @@ class IteratedTeamDifferencesInnerLayer extends TrueSkillFactorGraphLayer
$backwardScheduleList[] = $currentBackwardSchedulePiece; $backwardScheduleList[] = $currentBackwardSchedulePiece;
} }
$backwardSchedule = new ScheduleSequence('backward schedule', $backwardScheduleList); //backward schedule
$backwardSchedule = new ScheduleSequence($backwardScheduleList);
$forwardBackwardScheduleToLoop = $forwardBackwardScheduleToLoop =
//forward Backward Schedule To Loop
new ScheduleSequence( new ScheduleSequence(
'forward Backward Schedule To Loop',
[$forwardSchedule, $backwardSchedule] [$forwardSchedule, $backwardSchedule]
); );
$initialMaxDelta = 0.0001; $initialMaxDelta = 0.0001;
//loop with max delta
return new ScheduleLoop( return new ScheduleLoop(
sprintf('loop with max delta of %f', $initialMaxDelta),
$forwardBackwardScheduleToLoop, $forwardBackwardScheduleToLoop,
$initialMaxDelta $initialMaxDelta
); );

@ -7,8 +7,6 @@ namespace DNW\Skills\TrueSkill\Layers;
use DNW\Skills\FactorGraphs\ScheduleStep; use DNW\Skills\FactorGraphs\ScheduleStep;
use DNW\Skills\FactorGraphs\ScheduleSequence; use DNW\Skills\FactorGraphs\ScheduleSequence;
use DNW\Skills\PartialPlay; use DNW\Skills\PartialPlay;
use DNW\Skills\Player;
use DNW\Skills\Team;
use DNW\Skills\TrueSkill\Factors\GaussianWeightedSumFactor; use DNW\Skills\TrueSkill\Factors\GaussianWeightedSumFactor;
use DNW\Skills\FactorGraphs\Variable; use DNW\Skills\FactorGraphs\Variable;
use DNW\Skills\FactorGraphs\KeyedVariable; use DNW\Skills\FactorGraphs\KeyedVariable;
@ -23,7 +21,7 @@ class PlayerPerformancesToTeamPerformancesLayer extends TrueSkillFactorGraphLaye
*/ */
foreach ($inputVariablesGroups as $currentTeam) { foreach ($inputVariablesGroups as $currentTeam) {
$localCurrentTeam = $currentTeam; $localCurrentTeam = $currentTeam;
$teamPerformance = $this->createOutputVariable($localCurrentTeam); $teamPerformance = $this->createOutputVariable();
$newSumFactor = $this->createPlayerToTeamSumFactor($localCurrentTeam, $teamPerformance); $newSumFactor = $this->createPlayerToTeamSumFactor($localCurrentTeam, $teamPerformance);
$this->addLayerFactor($newSumFactor); $this->addLayerFactor($newSumFactor);
@ -38,12 +36,13 @@ class PlayerPerformancesToTeamPerformancesLayer extends TrueSkillFactorGraphLaye
{ {
$localFactors = $this->getLocalFactors(); $localFactors = $this->getLocalFactors();
//all player perf to team perf schedule
return $this->scheduleSequence( return $this->scheduleSequence(
array_map( array_map(
static fn($weightedSumFactor): ScheduleStep => new ScheduleStep('Perf to Team Perf Step', $weightedSumFactor, 0), //Perf to Team Perf Step
static fn($weightedSumFactor): ScheduleStep => new ScheduleStep($weightedSumFactor, 0),
$localFactors $localFactors
), )
'all player perf to team perf schedule'
); );
} }
@ -75,26 +74,23 @@ class PlayerPerformancesToTeamPerformancesLayer extends TrueSkillFactorGraphLaye
$localCurrentFactor = $currentFactor; $localCurrentFactor = $currentFactor;
$numberOfMessages = $localCurrentFactor->getNumberOfMessages(); $numberOfMessages = $localCurrentFactor->getNumberOfMessages();
for ($currentIteration = 1; $currentIteration < $numberOfMessages; ++$currentIteration) { for ($currentIteration = 1; $currentIteration < $numberOfMessages; ++$currentIteration) {
//team sum perf
$allFactors[] = new ScheduleStep( $allFactors[] = new ScheduleStep(
'team sum perf @' . $currentIteration,
$localCurrentFactor, $localCurrentFactor,
$currentIteration $currentIteration
); );
} }
} }
return $this->scheduleSequence($allFactors, "all of the team's sum iterations"); //all of the team's sum iterations
return $this->scheduleSequence($allFactors);
} }
/** /**
* @param KeyedVariable[] $team * Team's performance
*/ */
private function createOutputVariable(array $team): Variable private function createOutputVariable(): Variable
{ {
$memberNames = array_map(static fn($currentPlayer): string => (string)($currentPlayer->getKey()), $team); return $this->getParentFactorGraph()->getVariableFactory()->createBasicVariable();
$teamMemberNames = \implode(', ', $memberNames);
return $this->getParentFactorGraph()->getVariableFactory()->createBasicVariable('Team[' . $teamMemberNames . "]'s performance");
} }
} }

@ -53,12 +53,13 @@ class PlayerPriorValuesToSkillsLayer extends TrueSkillFactorGraphLayer
{ {
$localFactors = $this->getLocalFactors(); $localFactors = $this->getLocalFactors();
//All priors
return $this->scheduleSequence( return $this->scheduleSequence(
array_map( array_map(
static fn($prior): ScheduleStep => new ScheduleStep('Prior to Skill Step', $prior, 0), //Prior to Skill Step
static fn($prior): ScheduleStep => new ScheduleStep($prior, 0),
$localFactors $localFactors
), )
'All priors'
); );
} }
@ -77,6 +78,6 @@ class PlayerPriorValuesToSkillsLayer extends TrueSkillFactorGraphLayer
$parentFactorGraph = $this->getParentFactorGraph(); $parentFactorGraph = $this->getParentFactorGraph();
$variableFactory = $parentFactorGraph->getVariableFactory(); $variableFactory = $parentFactorGraph->getVariableFactory();
return $variableFactory->createKeyedVariable($key, $key . "'s skill"); return $variableFactory->createKeyedVariable($key);
} }
} }

@ -48,19 +48,20 @@ class PlayerSkillsToPerformancesLayer extends TrueSkillFactorGraphLayer
private function createOutputVariable(mixed $key): KeyedVariable private function createOutputVariable(mixed $key): KeyedVariable
{ {
return $this->getParentFactorGraph()->getVariableFactory()->createKeyedVariable($key, $key . "'s performance"); return $this->getParentFactorGraph()->getVariableFactory()->createKeyedVariable($key);
} }
public function createPriorSchedule(): ?ScheduleSequence public function createPriorSchedule(): ?ScheduleSequence
{ {
$localFactors = $this->getLocalFactors(); $localFactors = $this->getLocalFactors();
//All skill to performance sending
return $this->scheduleSequence( return $this->scheduleSequence(
array_map( array_map(
static fn($likelihood): ScheduleStep => new ScheduleStep('Skill to Perf step', $likelihood, 0), //Skill to Perf step
static fn($likelihood): ScheduleStep => new ScheduleStep($likelihood, 0),
$localFactors $localFactors
), )
'All skill to performance sending'
); );
} }
@ -68,12 +69,12 @@ class PlayerSkillsToPerformancesLayer extends TrueSkillFactorGraphLayer
{ {
$localFactors = $this->getLocalFactors(); $localFactors = $this->getLocalFactors();
//All skill to performance sending
return $this->scheduleSequence( return $this->scheduleSequence(
array_map( array_map(
static fn($likelihood): ScheduleStep => new ScheduleStep('name', $likelihood, 1), static fn($likelihood): ScheduleStep => new ScheduleStep($likelihood, 1),
$localFactors $localFactors
), )
'All skill to performance sending'
); );
} }
} }

@ -40,8 +40,11 @@ class TeamPerformancesToTeamPerformanceDifferencesLayer extends TrueSkillFactorG
return new GaussianWeightedSumFactor($output, $teams, $weights); return new GaussianWeightedSumFactor($output, $teams, $weights);
} }
/**
* Team performance difference
*/
private function createOutputVariable(): Variable private function createOutputVariable(): Variable
{ {
return $this->getParentFactorGraph()->getVariableFactory()->createBasicVariable('Team performance difference'); return $this->getParentFactorGraph()->getVariableFactory()->createBasicVariable();
} }
} }

@ -124,7 +124,8 @@ class TrueSkillFactorGraph extends FactorGraph
} }
} }
return new ScheduleSequence('Full schedule', $fullSchedule); //Full schedule
return new ScheduleSequence($fullSchedule);
} }
public function getUpdatedRatings(): RatingContainer public function getUpdatedRatings(): RatingContainer

@ -1,19 +0,0 @@
<?php
declare(strict_types=1);
namespace DNW\Skills\Tests\FactorGraphs;
use DNW\Skills\FactorGraphs\ScheduleStep;
use DNW\Skills\FactorGraphs\Factor;
use PHPUnit\Framework\TestCase;
class ScheduleStepTest extends TestCase
{
public function testtoStringInterface(): void
{
$stub = $this->createStub(Factor::class);
$ss = new ScheduleStep('dummy', $stub, 0);
$this->assertEquals('dummy', (string)$ss);
}
}

@ -13,13 +13,12 @@ class VariableTest extends TestCase
public function testGetterSetter(): void public function testGetterSetter(): void
{ {
$gd_prior = new GaussianDistribution(); $gd_prior = new GaussianDistribution();
$var = new Variable('dummy', $gd_prior); $var = new Variable($gd_prior);
$this->assertEquals($gd_prior, $var->getValue()); $this->assertEquals($gd_prior, $var->getValue());
$gd_new = new GaussianDistribution(); $gd_new = new GaussianDistribution();
$this->assertEquals($gd_new, $var->getValue()); $this->assertEquals($gd_new, $var->getValue());
$var->resetToPrior(); $var->resetToPrior();
$this->assertEquals($gd_prior, $var->getValue()); $this->assertEquals($gd_prior, $var->getValue());
$this->assertEquals('Variable[dummy]', (string)$var);
} }
} }

@ -12,7 +12,6 @@ class PlayerTest extends TestCase
public function testPlayerObjectGetterSetter(): void public function testPlayerObjectGetterSetter(): void
{ {
$p = new Player('dummy', 0.1, 0.2); $p = new Player('dummy', 0.1, 0.2);
$this->assertEquals('dummy', (string)$p);
$this->assertEquals('dummy', $p->getId()); $this->assertEquals('dummy', $p->getId());
$this->assertEquals(0.1, $p->getPartialPlayPercentage()); $this->assertEquals(0.1, $p->getPartialPlayPercentage());
$this->assertEquals(0.2, $p->getPartialUpdatePercentage()); $this->assertEquals(0.2, $p->getPartialUpdatePercentage());

@ -15,7 +15,6 @@ class RatingTest extends TestCase
$this->assertEquals(100, $rating->getMean()); $this->assertEquals(100, $rating->getMean());
$this->assertEquals(10, $rating->getStandardDeviation()); $this->assertEquals(10, $rating->getStandardDeviation());
$this->assertEquals(50, $rating->getConservativeRating()); $this->assertEquals(50, $rating->getConservativeRating());
$this->assertEquals("mean=100.0000, standardDeviation=10.0000", (string)$rating);
} }
public function testPartialUpdate(): void public function testPartialUpdate(): void
@ -26,10 +25,8 @@ class RatingTest extends TestCase
$rating_partial = $rating->getPartialUpdate($ratingOld, $ratingNew, 0.5); $rating_partial = $rating->getPartialUpdate($ratingOld, $ratingNew, 0.5);
$this->assertEquals(150, $rating_partial->getMean()); $this->assertEquals(150, $rating_partial->getMean());
$this->assertEquals(10, $rating_partial->getStandardDeviation()); $this->assertEquals(10, $rating_partial->getStandardDeviation());
$this->assertEquals(100, $rating_partial->getConservativeRating()); $this->assertEquals(100, $rating_partial->getConservativeRating());
$this->assertEquals("mean=150.0000, standardDeviation=10.0000", (string)$rating_partial);
} }
} }