Moved UnitTests to tests/ and Skills to src/

This commit is contained in:
Alexander Liljengård
2016-05-24 13:53:56 +02:00
parent 11b5033c8a
commit 4ab0c5d719
64 changed files with 0 additions and 0 deletions

View File

@ -0,0 +1,189 @@
<?php
namespace Moserware\Skills\TrueSkill\Layers;
require_once(dirname(__FILE__) . "/../../FactorGraphs/Schedule.php");
require_once(dirname(__FILE__) . "/../TrueSkillFactorGraph.php");
require_once(dirname(__FILE__) . "/TrueSkillFactorGraphLayer.php");
require_once(dirname(__FILE__) . "/TeamPerformancesToTeamPerformanceDifferencesLayer.php");
require_once(dirname(__FILE__) . "/TeamDifferencesComparisonLayer.php");
use Moserware\Skills\FactorGraphs\ScheduleLoop;
use Moserware\Skills\FactorGraphs\ScheduleSequence;
use Moserware\Skills\FactorGraphs\ScheduleStep;
use Moserware\Skills\TrueSkill\TrueSkillFactorGraph;
// The whole purpose of this is to do a loop on the bottom
class IteratedTeamDifferencesInnerLayer extends TrueSkillFactorGraphLayer
{
private $_TeamDifferencesComparisonLayer;
private $_TeamPerformancesToTeamPerformanceDifferencesLayer;
public function __construct(TrueSkillFactorGraph &$parentGraph,
TeamPerformancesToTeamPerformanceDifferencesLayer &$teamPerformancesToPerformanceDifferences,
TeamDifferencesComparisonLayer &$teamDifferencesComparisonLayer)
{
parent::__construct($parentGraph);
$this->_TeamPerformancesToTeamPerformanceDifferencesLayer = $teamPerformancesToPerformanceDifferences;
$this->_TeamDifferencesComparisonLayer = $teamDifferencesComparisonLayer;
}
public function &getLocalFactors()
{
$localFactors =
\array_merge($this->_TeamPerformancesToTeamPerformanceDifferencesLayer->getLocalFactors(),
$this->_TeamDifferencesComparisonLayer->getLocalFactors());
return $localFactors;
}
public function buildLayer()
{
$inputVariablesGroups = &$this->getInputVariablesGroups();
$this->_TeamPerformancesToTeamPerformanceDifferencesLayer->setInputVariablesGroups($inputVariablesGroups);
$this->_TeamPerformancesToTeamPerformanceDifferencesLayer->buildLayer();
$teamDifferencesOutputVariablesGroups = &$this->_TeamPerformancesToTeamPerformanceDifferencesLayer->getOutputVariablesGroups();
$this->_TeamDifferencesComparisonLayer->setInputVariablesGroups($teamDifferencesOutputVariablesGroups);
$this->_TeamDifferencesComparisonLayer->buildLayer();
}
public function createPriorSchedule()
{
switch (count($this->getInputVariablesGroups()))
{
case 0:
case 1:
throw new InvalidOperationException();
case 2:
$loop = $this->createTwoTeamInnerPriorLoopSchedule();
break;
default:
$loop = $this->createMultipleTeamInnerPriorLoopSchedule();
break;
}
// When dealing with differences, there are always (n-1) differences, so add in the 1
$totalTeamDifferences = count($this->_TeamPerformancesToTeamPerformanceDifferencesLayer->getLocalFactors());
$totalTeams = $totalTeamDifferences + 1;
$localFactors = &$this->_TeamPerformancesToTeamPerformanceDifferencesLayer->getLocalFactors();
$firstDifferencesFactor = &$localFactors[0];
$lastDifferencesFactor = &$localFactors[$totalTeamDifferences - 1];
$innerSchedule = new ScheduleSequence(
"inner schedule",
array(
$loop,
new ScheduleStep(
"teamPerformanceToPerformanceDifferenceFactors[0] @ 1",
$firstDifferencesFactor, 1),
new ScheduleStep(
sprintf("teamPerformanceToPerformanceDifferenceFactors[teamTeamDifferences = %d - 1] @ 2", $totalTeamDifferences),
$lastDifferencesFactor, 2)
)
);
return $innerSchedule;
}
private function createTwoTeamInnerPriorLoopSchedule()
{
$teamPerformancesToTeamPerformanceDifferencesLayerLocalFactors = &$this->_TeamPerformancesToTeamPerformanceDifferencesLayer->getLocalFactors();
$teamDifferencesComparisonLayerLocalFactors = &$this->_TeamDifferencesComparisonLayer->getLocalFactors();
$firstPerfToTeamDiff = &$teamPerformancesToTeamPerformanceDifferencesLayerLocalFactors[0];
$firstTeamDiffComparison = &$teamDifferencesComparisonLayerLocalFactors[0];
$itemsToSequence = array(
new ScheduleStep(
"send team perf to perf differences",
$firstPerfToTeamDiff,
0),
new ScheduleStep(
"send to greater than or within factor",
$firstTeamDiffComparison,
0)
);
return $this->scheduleSequence(
$itemsToSequence,
"loop of just two teams inner sequence");
}
private function createMultipleTeamInnerPriorLoopSchedule()
{
$totalTeamDifferences = count($this->_TeamPerformancesToTeamPerformanceDifferencesLayer->getLocalFactors());
$forwardScheduleList = array();
for ($i = 0; $i < $totalTeamDifferences - 1; $i++)
{
$teamPerformancesToTeamPerformanceDifferencesLayerLocalFactors = &$this->_TeamPerformancesToTeamPerformanceDifferencesLayer->getLocalFactors();
$teamDifferencesComparisonLayerLocalFactors = &$this->_TeamDifferencesComparisonLayer->getLocalFactors();
$currentTeamPerfToTeamPerfDiff = &$teamPerformancesToTeamPerformanceDifferencesLayerLocalFactors[$i];
$currentTeamDiffComparison = &$teamDifferencesComparisonLayerLocalFactors[$i];
$currentForwardSchedulePiece =
$this->scheduleSequence(
array(
new ScheduleStep(
sprintf("team perf to perf diff %d", $i),
$currentTeamPerfToTeamPerfDiff, 0),
new ScheduleStep(
sprintf("greater than or within result factor %d", $i),
$currentTeamDiffComparison, 0),
new ScheduleStep(
sprintf("team perf to perf diff factors [%d], 2", $i),
$currentTeamPerfToTeamPerfDiff, 2)
), sprintf("current forward schedule piece %d", $i));
$forwardScheduleList[] = $currentForwardSchedulePiece;
}
$forwardSchedule = new ScheduleSequence("forward schedule", $forwardScheduleList);
$backwardScheduleList = array();
for ($i = 0; $i < $totalTeamDifferences - 1; $i++)
{
$teamPerformancesToTeamPerformanceDifferencesLayerLocalFactors = &$this->_TeamPerformancesToTeamPerformanceDifferencesLayer->getLocalFactors();
$teamDifferencesComparisonLayerLocalFactors = &$this->_TeamDifferencesComparisonLayer->getLocalFactors();
$differencesFactor = &$teamPerformancesToTeamPerformanceDifferencesLayerLocalFactors[$totalTeamDifferences - 1 - $i];
$comparisonFactor = &$teamDifferencesComparisonLayerLocalFactors[$totalTeamDifferences - 1 - $i];
$performancesToDifferencesFactor = &$teamPerformancesToTeamPerformanceDifferencesLayerLocalFactors[$totalTeamDifferences - 1 - $i];
$currentBackwardSchedulePiece = new ScheduleSequence(
"current backward schedule piece",
array(
new ScheduleStep(
sprintf("teamPerformanceToPerformanceDifferenceFactors[totalTeamDifferences - 1 - %d] @ 0", $i),
$differencesFactor, 0),
new ScheduleStep(
sprintf("greaterThanOrWithinResultFactors[totalTeamDifferences - 1 - %d] @ 0", $i),
$comparisonFactor, 0),
new ScheduleStep(
sprintf("teamPerformanceToPerformanceDifferenceFactors[totalTeamDifferences - 1 - %d] @ 1", $i),
$performancesToDifferencesFactor, 1)
));
$backwardScheduleList[] = $currentBackwardSchedulePiece;
}
$backwardSchedule = new ScheduleSequence("backward schedule", $backwardScheduleList);
$forwardBackwardScheduleToLoop =
new ScheduleSequence(
"forward Backward Schedule To Loop",
array($forwardSchedule, $backwardSchedule));
$initialMaxDelta = 0.0001;
$loop = new ScheduleLoop(
sprintf("loop with max delta of %f", $initialMaxDelta),
$forwardBackwardScheduleToLoop,
$initialMaxDelta);
return $loop;
}
}
?>

View File

@ -0,0 +1,106 @@
<?php
namespace Moserware\Skills\TrueSkill\Layers;
require_once(dirname(__FILE__) . "/../../PartialPlay.php");
require_once(dirname(__FILE__) . "/../../FactorGraphs/Schedule.php");
require_once(dirname(__FILE__) . "/../Factors/GaussianWeightedSumFactor.php");
require_once(dirname(__FILE__) . "/../TrueSkillFactorGraph.php");
require_once(dirname(__FILE__) . "/TrueSkillFactorGraphLayer.php");
require_once(dirname(__FILE__) . "/TeamPerformancesToTeamPerformanceDifferencesLayer.php");
require_once(dirname(__FILE__) . "/TeamDifferencesComparisonLayer.php");
use Moserware\Skills\PartialPlay;
use Moserware\Skills\FactorGraphs\ScheduleLoop;
use Moserware\Skills\FactorGraphs\ScheduleSequence;
use Moserware\Skills\FactorGraphs\ScheduleStep;
use Moserware\Skills\TrueSkill\Factors\GaussianWeightedSumFactor;
use Moserware\Skills\TrueSkill\TrueSkillFactorGraph;
class PlayerPerformancesToTeamPerformancesLayer extends TrueSkillFactorGraphLayer
{
public function __construct(TrueSkillFactorGraph &$parentGraph)
{
parent::__construct($parentGraph);
}
public function buildLayer()
{
$inputVariablesGroups = &$this->getInputVariablesGroups();
foreach ($inputVariablesGroups as &$currentTeam)
{
$localCurrentTeam = &$currentTeam;
$teamPerformance = &$this->createOutputVariable($localCurrentTeam);
$newSumFactor = $this->createPlayerToTeamSumFactor($localCurrentTeam, $teamPerformance);
$this->addLayerFactor($newSumFactor);
// REVIEW: Does it make sense to have groups of one?
$outputVariablesGroups = &$this->getOutputVariablesGroups();
$outputVariablesGroups[] = array($teamPerformance);
}
}
public function createPriorSchedule()
{
$localFactors = &$this->getLocalFactors();
$sequence = &$this->scheduleSequence(
array_map(
function($weightedSumFactor)
{
return new ScheduleStep("Perf to Team Perf Step", $weightedSumFactor, 0);
},
$localFactors),
"all player perf to team perf schedule");
return $sequence;
}
protected function createPlayerToTeamSumFactor(&$teamMembers, &$sumVariable)
{
$weights = array_map(
function($v)
{
$player = &$v->getKey();
return PartialPlay::getPartialPlayPercentage($player);
},
$teamMembers);
return new GaussianWeightedSumFactor(
$sumVariable,
$teamMembers,
$weights);
}
public function createPosteriorSchedule()
{
$allFactors = array();
$localFactors = &$this->getLocalFactors();
foreach($localFactors as &$currentFactor)
{
$localCurrentFactor = &$currentFactor;
$numberOfMessages = $localCurrentFactor->getNumberOfMessages();
for($currentIteration = 1; $currentIteration < $numberOfMessages; $currentIteration++)
{
$allFactors[] = new ScheduleStep("team sum perf @" . $currentIteration,
$localCurrentFactor, $currentIteration);
}
}
return $this->scheduleSequence($allFactors, "all of the team's sum iterations");
}
private function &createOutputVariable(&$team)
{
$memberNames = \array_map(function ($currentPlayer)
{
return (string)($currentPlayer->getKey());
},
$team);
$teamMemberNames = \join(", ", $memberNames);
$outputVariable = &$this->getParentFactorGraph()->getVariableFactory()->createBasicVariable("Team[" . $teamMemberNames . "]'s performance");
return $outputVariable;
}
}
?>

View File

@ -0,0 +1,87 @@
<?php
namespace Moserware\Skills\TrueSkill\Layers;
require_once(dirname(__FILE__) . "/../../Rating.php");
require_once(dirname(__FILE__) . "/../../FactorGraphs/Schedule.php");
require_once(dirname(__FILE__) . "/../../FactorGraphs/Variable.php");
require_once(dirname(__FILE__) . "/../../Numerics/BasicMath.php");
require_once(dirname(__FILE__) . "/../TrueSkillFactorGraph.php");
require_once(dirname(__FILE__) . "/../Factors/GaussianPriorFactor.php");
require_once(dirname(__FILE__) . "/TrueSkillFactorGraphLayer.php");
use Moserware\Skills\Rating;
use Moserware\Skills\FactorGraphs\ScheduleLoop;
use Moserware\Skills\FactorGraphs\ScheduleSequence;
use Moserware\Skills\FactorGraphs\ScheduleStep;
use Moserware\Skills\FactorGraphs\Variable;
use Moserware\Numerics\GaussianDistribution;
use Moserware\Skills\TrueSkill\TrueSkillFactorGraph;
use Moserware\Skills\TrueSkill\Factors\GaussianPriorFactor;
// We intentionally have no Posterior schedule since the only purpose here is to
// start the process.
class PlayerPriorValuesToSkillsLayer extends TrueSkillFactorGraphLayer
{
private $_teams;
public function __construct(TrueSkillFactorGraph &$parentGraph, array &$teams)
{
parent::__construct($parentGraph);
$this->_teams = $teams;
}
public function buildLayer()
{
$teams = &$this->_teams;
foreach ($teams as &$currentTeam)
{
$localCurrentTeam = &$currentTeam;
$currentTeamSkills = array();
$currentTeamAllPlayers = $localCurrentTeam->getAllPlayers();
foreach ($currentTeamAllPlayers as &$currentTeamPlayer)
{
$localCurrentTeamPlayer = &$currentTeamPlayer;
$currentTeamPlayerRating = $currentTeam->getRating($localCurrentTeamPlayer);
$playerSkill = &$this->createSkillOutputVariable($localCurrentTeamPlayer);
$priorFactor = &$this->createPriorFactor($localCurrentTeamPlayer, $currentTeamPlayerRating, $playerSkill);
$this->addLayerFactor($priorFactor);
$currentTeamSkills[] = $playerSkill;
}
$outputVariablesGroups = &$this->getOutputVariablesGroups();
$outputVariablesGroups[] = $currentTeamSkills;
}
}
public function createPriorSchedule()
{
$localFactors = &$this->getLocalFactors();
return $this->scheduleSequence(
array_map(
function(&$prior)
{
return new ScheduleStep("Prior to Skill Step", $prior, 0);
},
$localFactors),
"All priors");
}
private function createPriorFactor(&$player, Rating &$priorRating, Variable &$skillsVariable)
{
return new GaussianPriorFactor($priorRating->getMean(),
square($priorRating->getStandardDeviation()) +
square($this->getParentFactorGraph()->getGameInfo()->getDynamicsFactor()),
$skillsVariable);
}
private function &createSkillOutputVariable(&$key)
{
$parentFactorGraph = &$this->getParentFactorGraph();
$variableFactory = &$parentFactorGraph->getVariableFactory();
$skillOutputVariable = &$variableFactory->createKeyedVariable($key, $key . "'s skill");
return $skillOutputVariable;
}
}
?>

View File

@ -0,0 +1,84 @@
<?php
namespace Moserware\Skills\TrueSkill\Layers;
require_once(dirname(__FILE__) . "/../../FactorGraphs/Schedule.php");
require_once(dirname(__FILE__) . "/../../FactorGraphs/Variable.php");
require_once(dirname(__FILE__) . "/../../Numerics/BasicMath.php");
require_once(dirname(__FILE__) . "/../TrueSkillFactorGraph.php");
require_once(dirname(__FILE__) . "/../Factors/GaussianLikelihoodFactor.php");
require_once(dirname(__FILE__) . "/TrueSkillFactorGraphLayer.php");
use Moserware\Skills\FactorGraphs\ScheduleStep;
use Moserware\Skills\FactorGraphs\KeyedVariable;
use Moserware\Skills\TrueSkill\TrueSkillFactorGraph;
use Moserware\Skills\TrueSkill\Factors\GaussianLikelihoodFactor;
class PlayerSkillsToPerformancesLayer extends TrueSkillFactorGraphLayer
{
public function __construct(TrueSkillFactorGraph &$parentGraph)
{
parent::__construct($parentGraph);
}
public function buildLayer()
{
$inputVariablesGroups = &$this->getInputVariablesGroups();
$outputVariablesGroups = &$this->getOutputVariablesGroups();
foreach ($inputVariablesGroups as &$currentTeam)
{
$currentTeamPlayerPerformances = array();
foreach ($currentTeam as &$playerSkillVariable)
{
$localPlayerSkillVariable = &$playerSkillVariable;
$currentPlayer = &$localPlayerSkillVariable->getKey();
$playerPerformance = &$this->createOutputVariable($currentPlayer);
$newLikelihoodFactor = $this->createLikelihood($localPlayerSkillVariable, $playerPerformance);
$this->addLayerFactor($newLikelihoodFactor);
$currentTeamPlayerPerformances[] = $playerPerformance;
}
$outputVariablesGroups[] = $currentTeamPlayerPerformances;
}
}
private function createLikelihood(KeyedVariable &$playerSkill, KeyedVariable &$playerPerformance)
{
return new GaussianLikelihoodFactor(square($this->getParentFactorGraph()->getGameInfo()->getBeta()), $playerPerformance, $playerSkill);
}
private function &createOutputVariable(&$key)
{
$outputVariable = &$this->getParentFactorGraph()->getVariableFactory()->createKeyedVariable($key, $key . "'s performance");
return $outputVariable;
}
public function createPriorSchedule()
{
$localFactors = &$this->getLocalFactors();
return $this->scheduleSequence(
array_map(
function($likelihood)
{
return new ScheduleStep("Skill to Perf step", $likelihood, 0);
},
$localFactors),
"All skill to performance sending");
}
public function createPosteriorSchedule()
{
$localFactors = &$this->getLocalFactors();
return $this->scheduleSequence(
array_map(
function($likelihood)
{
return new ScheduleStep("name", $likelihood, 1);
},
$localFactors),
"All skill to performance sending");
}
}
?>

View File

@ -0,0 +1,48 @@
<?php
namespace Moserware\Skills\TrueSkill\Layers;
require_once(dirname(__FILE__) . "/../DrawMargin.php");
require_once(dirname(__FILE__) . "/../TrueSkillFactorGraph.php");
require_once(dirname(__FILE__) . "/../Factors/GaussianGreaterThanFactor.php");
require_once(dirname(__FILE__) . "/../Factors/GaussianWithinFactor.php");
require_once(dirname(__FILE__) . "/TrueSkillFactorGraphLayer.php");
use Moserware\Skills\TrueSkill\DrawMargin;
use Moserware\Skills\TrueSkill\TrueSkillFactorGraph;
use Moserware\Skills\TrueSkill\Factors\GaussianGreaterThanFactor;
use Moserware\Skills\TrueSkill\Factors\GaussianWithinFactor;
class TeamDifferencesComparisonLayer extends TrueSkillFactorGraphLayer
{
private $_epsilon;
private $_teamRanks;
public function __construct(TrueSkillFactorGraph &$parentGraph, array &$teamRanks)
{
parent::__construct($parentGraph);
$this->_teamRanks = $teamRanks;
$gameInfo = &$this->getParentFactorGraph()->getGameInfo();
$this->_epsilon = DrawMargin::getDrawMarginFromDrawProbability($gameInfo->getDrawProbability(), $gameInfo->getBeta());
}
public function buildLayer()
{
$inputVarGroups = &$this->getInputVariablesGroups();
$inputVarGroupsCount = count($inputVarGroups);
for ($i = 0; $i < $inputVarGroupsCount; $i++)
{
$isDraw = ($this->_teamRanks[$i] == $this->_teamRanks[$i + 1]);
$teamDifference = &$inputVarGroups[$i][0];
$factor =
$isDraw
? new GaussianWithinFactor($this->_epsilon, $teamDifference)
: new GaussianGreaterThanFactor($this->_epsilon, $teamDifference);
$this->addLayerFactor($factor);
}
}
}
?>

View File

@ -0,0 +1,56 @@
<?php
namespace Moserware\Skills\TrueSkill\Layers;
require_once(dirname(__FILE__) . "/../../FactorGraphs/Variable.php");
require_once(dirname(__FILE__) . "/../TrueSkillFactorGraph.php");
require_once(dirname(__FILE__) . "/../Factors/GaussianWeightedSumFactor.php");
require_once(dirname(__FILE__) . "/TrueSkillFactorGraphLayer.php");
use Moserware\Skills\FactorGraphs\Variable;
use Moserware\Skills\TrueSkill\DrawMargin;
use Moserware\Skills\TrueSkill\TrueSkillFactorGraph;
use Moserware\Skills\TrueSkill\Factors\GaussianWeightedSumFactor;
class TeamPerformancesToTeamPerformanceDifferencesLayer extends TrueSkillFactorGraphLayer
{
public function __construct(TrueSkillFactorGraph &$parentGraph)
{
parent::__construct($parentGraph);
}
public function buildLayer()
{
$inputVariablesGroups = &$this->getInputVariablesGroups();
$inputVariablesGroupsCount = count($inputVariablesGroups);
$outputVariablesGroup = &$this->getOutputVariablesGroups();
for ($i = 0; $i < $inputVariablesGroupsCount - 1; $i++)
{
$strongerTeam = &$inputVariablesGroups[$i][0];
$weakerTeam = &$inputVariablesGroups[$i + 1][0];
$currentDifference = &$this->createOutputVariable();
$newDifferencesFactor = $this->createTeamPerformanceToDifferenceFactor($strongerTeam, $weakerTeam, $currentDifference);
$this->addLayerFactor($newDifferencesFactor);
// REVIEW: Does it make sense to have groups of one?
$outputVariablesGroup[] = array($currentDifference);
}
}
private function createTeamPerformanceToDifferenceFactor(
Variable &$strongerTeam, Variable &$weakerTeam, Variable &$output)
{
$teams = array($strongerTeam, $weakerTeam);
$weights = array(1.0, -1.0);
return new GaussianWeightedSumFactor($output, $teams, $weights);
}
private function &createOutputVariable()
{
$outputVariable = &$this->getParentFactorGraph()->getVariableFactory()->createBasicVariable("Team performance difference");
return $outputVariable;
}
}
?>

View File

@ -0,0 +1,18 @@
<?php
namespace Moserware\Skills\TrueSkill\Layers;
require_once(dirname(__FILE__) . "/../../FactorGraphs/FactorGraphLayer.php");
require_once(dirname(__FILE__) . "/../TrueSkillFactorGraph.php");
use Moserware\Skills\FactorGraphs\FactorGraphLayer;
use Moserware\Skills\TrueSkill\TrueSkillFactorGraph;
abstract class TrueSkillFactorGraphLayer extends FactorGraphLayer
{
public function __construct(TrueSkillFactorGraph &$parentGraph)
{
parent::__construct($parentGraph);
}
}
?>