Start of factor graph port. Things don't work yet, but a lot of syntax updates towards PHP

This commit is contained in:
Jeff Moser
2010-09-18 11:11:44 -04:00
parent 4a76cc34cc
commit e434696b44
25 changed files with 1637 additions and 20 deletions

View File

@ -0,0 +1,147 @@
<?php
namespace Moserware\Skills\TrueSkill\Layers;
// 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 buildLayer()
{
$this->_TeamPerformancesToTeamPerformanceDifferencesLayer->setRawInputVariablesGroups($this->getInputVariablesGroups());
$this->_TeamPerformancesToTeamPerformanceDifferencesLayer->buildLayer();
$this->_TeamDifferencesComparisonLayer->setRawInputVariablesGroups(
$this->_TeamPerformancesToTeamPerformanceDifferencesLayer->getRawOutputVariablesGroups());
$this->_TeamDifferencesComparisonLayer->buildLayer();
}
public function createPriorSchedule()
{
// BLOG about $loop
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;
$innerSchedule = new ScheduleSequence(
"inner schedule",
array(
$loop,
new ScheduleStep(
"teamPerformanceToPerformanceDifferenceFactors[0] @ 1",
($this->_TeamPerformancesToTeamPerformanceDifferencesLayer->getLocalFactors())[0], 1),
new ScheduleStep(
"teamPerformanceToPerformanceDifferenceFactors[teamTeamDifferences = {0} - 1] @ 2",
($this->_TeamPerformancesToTeamPerformanceDifferencesLayer->getLocalFactors())[$totalTeamDifferences - 1], 2)
)
);
return innerSchedule;
}
private function createTwoTeamInnerPriorLoopSchedule()
{
return $this->scheduleSequence(
array(
new ScheduleStep(
"send team perf to perf differences",
($this->_TeamPerformancesToTeamPerformanceDifferencesLayer->getLocalFactors())[0],
0),
new ScheduleStep(
"send to greater than or within factor",
($this->_TeamDifferencesComparisonLayer->getLocalFactors())[0],
0)
),
"loop of just two teams inner sequence");
}
private function createMultipleTeamInnerPriorLoopSchedule()
{
$totalTeamDifferences = count($this->_TeamPerformancesToTeamPerformanceDifferencesLayer->getLocalFactors());
$forwardScheduleList = array();
for ($i = 0; $i < $totalTeamDifferences - 1; $i++)
{
$currentForwardSchedulePiece =
$this->scheduleSequence(
array(
new ScheduleStep(
sprintf("team perf to perf diff %d", $i),
($this->_TeamPerformancesToTeamPerformanceDifferencesLayer->getLocalFactors())[$i], 0),
new ScheduleStep(
sprintf("greater than or within result factor %d", $i),
($this->_TeamDifferencesComparisonLayer->getLocalFactors())[$i], 0),
new ScheduleStep(
sprintf("team perf to perf diff factors [%d], 2", $i),
($this->_TeamPerformancesToTeamPerformanceDifferencesLayer->getLocalFactors())[$i], 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++)
{
$currentBackwardSchedulePiece = new ScheduleSequence(
"current backward schedule piece",
array(
new ScheduleStep(
sprintf("teamPerformanceToPerformanceDifferenceFactors[totalTeamDifferences - 1 - %d] @ 0", $i),
($this->_TeamPerformancesToTeamPerformanceDifferencesLayer->getLocalFactors())[$totalTeamDifferences - 1 - $i], 0),
new ScheduleStep(
sprintf("greaterThanOrWithinResultFactors[totalTeamDifferences - 1 - %d] @ 0", $i),
($this->_TeamDifferencesComparisonLayer->getLocalFactors())[$totalTeamDifferences - 1 - $i], 0),
new ScheduleStep(
sprintf("teamPerformanceToPerformanceDifferenceFactors[totalTeamDifferences - 1 - %d] @ 1", $i),
($this->_TeamPerformancesToTeamPerformanceDifferencesLayer->getLocalFactors())[$totalTeamDifferences - 1 - $i], 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,71 @@
<?php
namespace Moserware\Skills\TrueSkill\Layers;
class PlayerPerformancesToTeamPerformancesLayer extends TrueSkillFactorGraphLayer
{
public function __construct(TrueSkillFactorGraph $parentGraph)
{
parent::__construct($parentGraph);
}
public function buildLayer()
{
foreach ($this->getInputVariablesGroups() as $currentTeam)
{
$teamPerformance = $this->createOutputVariable($currentTeam);
$this->addLayerFactor($this->createPlayerToTeamSumFactor($currentTeam, $teamPerformance));
// REVIEW: Does it make sense to have groups of one?
$this->getOutputVariablesGroups() = $teamPerformance;
}
}
public function createPriorSchedule()
{
return $this->scheduleSequence(
array_map(
function($weightedSumFactor)
{
return new ScheduleStep("Perf to Team Perf Step", $weightedSumFactor, 0);
},
$this->getLocalFactors()),
"all player perf to team perf schedule");
}
protected function createPlayerToTeamSumFactor($teamMembers, $sumVariable)
{
return new GaussianWeightedSumFactor(
$sumVariable,
$teamMembers,
array_map(
function($v)
{
return PartialPlay::getPartialPlayPercentage($v->getKey());
},
$teamMembers));
}
public function createPosteriorSchedule()
{
// BLOG
return $this->scheduleSequence(
from currentFactor in LocalFactors
from currentIteration in
Enumerable.Range(1, currentFactor.NumberOfMessages - 1)
select new ScheduleStep<GaussianDistribution>(
"team sum perf @" + currentIteration,
currentFactor,
currentIteration),
"all of the team's sum iterations");
}
private function createOutputVariable($team)
{
$teamMemberNames = String.Join(", ", team.Select(teamMember => teamMember.Key.ToString()).ToArray());
return ParentFactorGraph.VariableFactory.CreateBasicVariable("Team[{0}]'s performance", teamMemberNames);
}
}
?>

View File

@ -0,0 +1,59 @@
<?php
namespace Moserware\Skills\TrueSkill\Layers;
// We intentionally have no Posterior schedule since the only purpose here is to
class PlayerPriorValuesToSkillsLayer extends TrueSkillFactorGraphLayer
{
private $_teams;
public function __construct(TrueSkillFactorGraph $parentGraph, $teams)
{
parent::__construct($parentGraph);
$this->_teams = $teams;
}
public function buildLayer()
{
foreach ($this->_teams as $currentTeam)
{
$currentTeamSkills = array();
foreach ($currentTeam as $currentTeamPlayer)
{
$playerSkill = $this->createSkillOutputVariable($currentTeamPlayer.Key);
$this->addLayerFactor($this->createPriorFactor($currentTeamPlayer.Key, $currentTeamPlayer.Value, $playerSkill));
$currentTeamSkills[] = $playerSkill;
}
OutputVariablesGroups.Add(currentTeamSkills);
}
}
public function createPriorSchedule()
{
return $this->scheduleSequence(
array_map(
function($prior)
{
return new ScheduleStep("Prior to Skill Step", $prior, 0);
},
$this->getLocalFactors()),
"All priors");
}
private function createPriorFactor($player, $priorRating, $skillsVariable)
{
return new GaussianPriorFactor($priorRating->getMean(),
square($priorRating->getStandardDeviation()) +
square($this->getParentFactorGraph()->getGameInfo()->getDynamicsFactor()),
$skillsVariable);
}
private function createSkillOutputVariable($key)
{
return $this->getParentFactorGraph()->getVariableFactory()->createKeyedVariable($key, "{0}'s skill", $key);
}
}
?>

View File

@ -0,0 +1,64 @@
<?php
namespace Moserware\Skills\TrueSkill\Layers;
class PlayerSkillsToPerformancesLayer extends TrueSkillFactorGraphLayer
{
public function __construct(TrueSkillFactorGraph $parentGraph)
{
parent::__construct($parentGraph);
}
public function buildLayer()
{
foreach ($this->getInputVariablesGroups() as $currentTeam)
{
$currentTeamPlayerPerformances = array();
foreach ($currentTeam as $playerSkillVariable)
{
$playerPerformance = $this->createOutputVariable($playerSkillVariable->getKey());
$this->addLayerFactor($this->createLikelihood($playerSkillVariable, $playerPerformance));
$currentTeamPlayerPerformances[] = $playerPerformance;
}
$this->getOutputVariablesGroups()[] = $currentTeamPlayerPerformances;
}
}
private function createLikelihood($playerSkill, $playerPerformance)
{
return new GaussianLikelihoodFactor(square($this->getParentFactorGraph()->getGameInfo()->getBeta()), $playerPerformance, $playerSkill);
}
private function createOutputVariable($key)
{
return $this->getParentFactorGraph()->getVariableFactory()->createKeyedVariable($key, "{0}'s performance", $key);
}
public function createPriorSchedule()
{
return $this->scheduleSequence(
array_map(
function($likelihood)
{
return $this->scheduleStep("Skill to Perf step", $likelihood, 0);
},
$this->getLocalFactors()),
"All skill to performance sending");
}
public function createPosteriorSchedule()
{
return $this->scheduleSequence(
array_map(
function($likelihood)
{
return new ScheduleStep("name", $likelihood, 1);
},
$this->getLocalFactors()),
"All skill to performance sending");
}
}
?>

View File

@ -0,0 +1,38 @@
<?php
namespace Moserware\Skills\TrueSkill\Layers;
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,42 @@
<?php
namespace Moserware\Skills\TrueSkill\Layers;
class TeamPerformancesToTeamPerformanceDifferencesLayer extends TrueSkillFactorGraphLayer
{
public function __construct(TrueSkillFactorGraph $parentGraph)
{
parent::__construct($parentGraph);
}
public function buildLayer()
{
$inputVariablesGroup = $this->getInputVariablesGroups();
$inputVariablesGroupCount = count($inputVariablesGroup);
for ($i = 0; $i < $inputVariablesGroupCount - 1; $i++)
{
$strongerTeam = $inputVariablesGroups[$i][0];
$weakerTeam = $inputVariablesGroups[$i + 1][0];
$currentDifference = $this->createOutputVariable();
$this->addLayerFactor($this->createTeamPerformanceToDifferenceFactor($strongerTeam, $weakerTeam, currentDifference));
// REVIEW: Does it make sense to have groups of one?
$this->getOutputVariablesGroups()[] = $currentDifference;
}
}
private function createTeamPerformanceToDifferenceFactor(
Variable $strongerTeam, Variable $weakerTeam, Variable $output)
{
return new GaussianWeightedSumFactor($output, array($strongerTeam, $weakerTeam), array(1.0, -1.0));
}
private function createOutputVariable()
{
return $this->getParentFactorGraph()->getVariableFactory()->createBasicVariable("Team performance difference");
}
}
?>

View File

@ -0,0 +1,13 @@
<?php
namespace Moserware\Skills\TrueSkill\Layers;
abstract class TrueSkillFactorGraphLayer extends FactorGraphLayer
{
public function __construct(TrueSkillFactorGraph $parentGraph)
{
parent::__construct($parentGraph);
}
}
?>