It gets a result... unfortunately it's wrong. But hey, that's progress :) Lots of debugging code left in to make up for a less than ideal debugger

This commit is contained in:
Jeff Moser 2010-10-02 21:15:47 -04:00
parent c22683ab33
commit fc6cd5c961
22 changed files with 145 additions and 70 deletions

@ -35,12 +35,14 @@ abstract class Factor
return count($this->_messages);
}
protected function &getVariables()
// DEBUG: make protected
public function &getVariables()
{
return $this->_variables;
}
protected function &getMessages()
// DEBUG: make protected
public function &getMessages()
{
return $this->_messages;
}
@ -51,6 +53,11 @@ abstract class Factor
Guard::argumentIsValidIndex($messageIndex, count($this->_messages), "messageIndex");
$message = &$this->_messages[$messageIndex];
$variable = &$this->_messageToVariableBinding->getValue($message);
// DEBUG
$selfName = (string)$this;
$debugName = (string)$variable;
$debugHash = \spl_object_hash($variable);
$debugValue = $variable->getValue();
return $this->updateMessageVariable($message, $variable);
}
@ -86,9 +93,11 @@ abstract class Factor
protected function &createVariableToMessageBindingWithMessage(Variable &$variable, Message &$message)
{
$index = count($this->_messages);
$this->_messages[] = &$message;
$localMessages = &$this->_messages;
$localMessages[] = &$message;
$this->_messageToVariableBinding->setValue($message, $variable);
$this->_variables[] = &$variable;
$localVariables = &$this->_variables;
$localVariables[] = &$variable;
return $message;
}

@ -20,6 +20,8 @@ class Message
public function setValue(&$value)
{
// DEBUG
$selfName = (string)$this;
$this->_value = &$value;
}

@ -34,7 +34,10 @@ class ScheduleStep extends Schedule
public function visit($depth = -1, $maxDepth = 0)
{
$delta = $this->_factor->updateMessageIndex($this->_index);
$currentFactor = &$this->_factor;
// DEBUG
$currentFactorName = (string)$currentFactor;
$delta = $currentFactor->updateMessageIndex($this->_index);
return $delta;
}
}

@ -17,12 +17,18 @@ class Variable
public function &getValue()
{
$value = &$this->_value;
// DEBUG
$selfHash = \spl_object_hash($this);
$selfName = (string)$this;
return $value;
}
public function setValue(&$value)
{
$this->_value = $value;
// DEBUG
$selfName = (string)$this;
$selfHash = \spl_object_hash($this);
$this->_value = &$value;
}
public function resetToPrior()
@ -57,15 +63,16 @@ class DefaultVariable extends Variable
class KeyedVariable extends Variable
{
private $_key;
public function __construct($key, $name, &$prior)
public function __construct(&$key, $name, &$prior)
{
parent::__construct($name, $prior);
$this->_key = $key;
$this->_key = &$key;
}
public function getKey()
public function &getKey()
{
return $this->_key;
$key = &$this->_key;
return $key;
}
}

@ -7,29 +7,31 @@ class HashMap
private $_hashToValue = array();
private $_hashToKey = array();
public function &getValue($key)
public function &getValue(&$key)
{
$hash = self::getHash($key);
$hashValue = &$this->_hashToValue[$hash];
return $hashValue;
}
public function setValue($key, $value)
public function setValue(&$key, &$value)
{
$hash = self::getHash($key);
$this->_hashToKey[$hash] = $key;
$this->_hashToValue[$hash] = $value;
$this->_hashToKey[$hash] = &$key;
$this->_hashToValue[$hash] = &$value;
return $this;
}
public function getAllKeys()
public function &getAllKeys()
{
return \array_values($this->_hashToKey);
$keys = &\array_values($this->_hashToKey);
return $keys;
}
public function getAllValues()
{
return \array_values($this->_hashToValue);
$values = &\array_values($this->_hashToValue);
return $values;
}
public function count()
@ -37,7 +39,7 @@ class HashMap
return \count($this->_hashToKey);
}
private static function getHash($key)
private static function getHash(&$key)
{
if(\is_object($key))
{

@ -2,6 +2,8 @@
namespace Moserware\Skills;
require_once(dirname(__FILE__) . "/HashMap.php");
require_once(dirname(__FILE__) . "/Player.php");
require_once(dirname(__FILE__) . "/Rating.php");
class RatingContainer
{
@ -12,25 +14,27 @@ class RatingContainer
$this->_playerToRating = new HashMap();
}
public function &getRating($player)
public function &getRating(Player &$player)
{
$rating = &$this->_playerToRating->getValue($player);
return $rating;
}
public function setRating($player, $rating)
public function setRating(Player &$player, Rating $rating)
{
return $this->_playerToRating->setValue($player, $rating);
}
public function getAllPlayers()
public function &getAllPlayers()
{
return $this->_playerToRating->getAllKeys();
$allPlayers = &$this->_playerToRating->getAllKeys();
return $allPlayers;
}
public function getAllRatings()
public function &getAllRatings()
{
return $this->_playerToRating->getAllValues();
$allRatings = &$this->_playerToRating->getAllValues();
return $allRatings;
}
public function count()

@ -1,11 +1,13 @@
<?php
namespace Moserware\Skills;
require_once(dirname(__FILE__) . '/Player.php');
require_once(dirname(__FILE__) . '/Rating.php');
require_once(dirname(__FILE__) . '/RatingContainer.php');
class Team extends RatingContainer
{
public function __construct(&$player = null, &$rating = null)
public function __construct(Player &$player = null, Rating &$rating = null)
{
parent::__construct();
@ -15,12 +17,11 @@ class Team extends RatingContainer
}
}
public function addPlayer(&$player, &$rating)
public function addPlayer(Player &$player, Rating &$rating)
{
$this->setRating($player, $rating);
return $this;
}
}
}
?>

@ -9,7 +9,8 @@ class Teams
$result = array();
foreach ($args as &$currentTeam) {
$result[] = $currentTeam;
$localCurrentTeam = &$currentTeam;
$result[] = $localCurrentTeam;
}
return $result;

@ -53,7 +53,10 @@ class FactorGraphTrueSkillCalculator extends SkillCalculator
$factorGraph->buildGraph();
$factorGraph->runSchedule();
$probabilityOfOutcome = $factorGraph->getProbabilityOfRanking();
$test = $factorGraph->getUpdatedRatings();
// DEBUG: Fix this :)
//$probabilityOfOutcome = $factorGraph->getProbabilityOfRanking();
return $factorGraph->getUpdatedRatings();
}

@ -31,9 +31,10 @@ abstract class GaussianFactor extends Factor
public function &createVariableToMessageBinding(Variable &$variable)
{
$newDistribution = GaussianDistribution::fromPrecisionMean(0, 0);
$binding = &parent::createVariableToMessageBindingWithMessage($variable,
new Message(
GaussianDistribution::fromPrecisionMean(0, 0),
$newDistribution,
sprintf("message from %s to %s", $this, $variable)));
return $binding;
}

@ -39,9 +39,15 @@ class GaussianLikelihoodFactor extends GaussianFactor
private function updateHelper(Message &$message1, Message &$message2,
Variable &$variable1, Variable &$variable2)
{
$message1Value = clone $message1->getValue();
$message2Value = clone $message2->getValue();
// DEBUG
$message1ValueTest = $message1->getValue();
$variable1ValueTest = $variable1->getValue();
$message2ValueTest = $message2->getValue();
$variable2ValueTest = $variable2->getValue();
$message1Value = clone $message1->getValue();
$message2Value = clone $message2->getValue();
$marginal1 = clone $variable1->getValue();
$marginal2 = clone $variable2->getValue();
@ -67,7 +73,7 @@ class GaussianLikelihoodFactor extends GaussianFactor
public function updateMessageIndex($messageIndex)
{
$messages = &$this->getMessages();
$vars = &$this->getVariables();
$vars = &$this->getVariables();
switch ($messageIndex)
{

@ -39,7 +39,8 @@ class GaussianPriorFactor extends GaussianFactor
$oldMarginal->getPrecision() + $this->_newMessage->getPrecision() - $oldMessage->getValue()->getPrecision());
$variable->setValue($newMarginal);
$message->setValue($this->_newMessage);
$newMessage = &$this->_newMessage;
$message->setValue($newMessage);
return GaussianDistribution::subtract($oldMarginal, $newMarginal);
}
}

@ -119,8 +119,13 @@ class GaussianWeightedSumFactor extends GaussianFactor
foreach ($variablesToSum as &$currentVariable)
{
$this->createVariableToMessageBinding($currentVariable);
$localCurrentVariable = &$currentVariable;
$this->createVariableToMessageBinding($localCurrentVariable);
}
// DEBUG
$selfName = (string)$this;
$selfVars = &$this->getVariables();
}
public function getLogNormalization()
@ -201,6 +206,8 @@ class GaussianWeightedSumFactor extends GaussianFactor
public function updateMessageIndex($messageIndex)
{
// DEBUG
$currentFactorName = (string)$this;
$allMessages = &$this->getMessages();
$allVariables = &$this->getVariables();
@ -221,6 +228,12 @@ class GaussianWeightedSumFactor extends GaussianFactor
$updatedVariables[] = &$allVariables[$indicesToUse[$i]];
}
// DEBUG
foreach($allVariables as &$currentVariable)
{
$currentVarVal = &$currentVariable->getValue();
}
return $this->updateHelper($this->_weights[$messageIndex],
$this->_weightsSquared[$messageIndex],
$updatedMessages,

@ -83,14 +83,16 @@ class IteratedTeamDifferencesInnerLayer extends TrueSkillFactorGraphLayer
$teamPerformancesToTeamPerformanceDifferencesLayerLocalFactors = &$this->_TeamPerformancesToTeamPerformanceDifferencesLayer->getLocalFactors();
$teamDifferencesComparisonLayerLocalFactors = &$this->_TeamDifferencesComparisonLayer->getLocalFactors();
$firstPerfToTeamDiff = &$teamPerformancesToTeamPerformanceDifferencesLayerLocalFactors[0];
$firstTeamDiffComparison = &$teamDifferencesComparisonLayerLocalFactors[0];
$itemsToSequence = array(
new ScheduleStep(
"send team perf to perf differences",
&$teamPerformancesToTeamPerformanceDifferencesLayerLocalFactors[0],
$firstPerfToTeamDiff,
0),
new ScheduleStep(
"send to greater than or within factor",
&$teamDifferencesComparisonLayerLocalFactors[0],
$firstTeamDiffComparison,
0)
);
@ -110,18 +112,21 @@ class IteratedTeamDifferencesInnerLayer extends TrueSkillFactorGraphLayer
$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),
&$teamPerformancesToTeamPerformanceDifferencesLayerLocalFactors[$i], 0),
$currentTeamPerfToTeamPerfDiff, 0),
new ScheduleStep(
sprintf("greater than or within result factor %d", $i),
&$teamDifferencesComparisonLayerLocalFactors[$i], 0),
$currentTeamDiffComparison, 0),
new ScheduleStep(
sprintf("team perf to perf diff factors [%d], 2", $i),
&$teamPerformancesToTeamPerformanceDifferencesLayerLocalFactors[$i], 2)
$currentTeamPerfToTeamPerfDiff, 2)
), sprintf("current forward schedule piece %d", $i));
$forwardScheduleList[] = $currentForwardSchedulePiece;

@ -28,14 +28,16 @@ class PlayerPerformancesToTeamPerformancesLayer extends TrueSkillFactorGraphLaye
$inputVariablesGroups = &$this->getInputVariablesGroups();
foreach ($inputVariablesGroups as &$currentTeam)
{
$teamPerformance = &$this->createOutputVariable($currentTeam);
$newSumFactor = $this->createPlayerToTeamSumFactor($currentTeam, $teamPerformance);
$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()
@ -58,7 +60,8 @@ class PlayerPerformancesToTeamPerformancesLayer extends TrueSkillFactorGraphLaye
$weights = array_map(
function($v)
{
return PartialPlay::getPartialPlayPercentage($v->getKey());
$player = &$v->getKey();
return PartialPlay::getPartialPlayPercentage($player);
},
$teamMembers);
@ -76,17 +79,18 @@ class PlayerPerformancesToTeamPerformancesLayer extends TrueSkillFactorGraphLaye
$localFactors = &$this->getLocalFactors();
foreach($localFactors as &$currentFactor)
{
$numberOfMessages = $currentFactor->getNumberOfMessages();
$localCurrentFactor = &$currentFactor;
$numberOfMessages = $localCurrentFactor->getNumberOfMessages();
for($currentIteration = 1; $currentIteration < $numberOfMessages; $currentIteration++)
{
$allFactors[] = new ScheduleStep("team sum perf @" . $currentIteration,
$currentFactor, $currentIteration);
$localCurrentFactor, $currentIteration);
}
}
return $this->scheduleSequence($allFactors, "all of the team's sum iterations");
}
private function createOutputVariable(&$team)
private function &createOutputVariable(&$team)
{
$memberNames = \array_map(function ($currentPlayer)
{
@ -95,7 +99,8 @@ class PlayerPerformancesToTeamPerformancesLayer extends TrueSkillFactorGraphLaye
$team);
$teamMemberNames = \join(", ", $memberNames);
return $this->getParentFactorGraph()->getVariableFactory()->createBasicVariable("Team[" . $teamMemberNames . "]'s performance");
$outputVariable = &$this->getParentFactorGraph()->getVariableFactory()->createBasicVariable("Team[" . $teamMemberNames . "]'s performance");
return $outputVariable;
}
}

@ -24,7 +24,7 @@ class PlayerPriorValuesToSkillsLayer extends TrueSkillFactorGraphLayer
{
private $_teams;
public function __construct(TrueSkillFactorGraph &$parentGraph, &$teams)
public function __construct(TrueSkillFactorGraph &$parentGraph, array &$teams)
{
parent::__construct($parentGraph);
$this->_teams = $teams;
@ -35,14 +35,16 @@ class PlayerPriorValuesToSkillsLayer extends TrueSkillFactorGraphLayer
$teams = &$this->_teams;
foreach ($teams as &$currentTeam)
{
$localCurrentTeam = &$currentTeam;
$currentTeamSkills = array();
$currentTeamAllPlayers = &$currentTeam->getAllPlayers();
$currentTeamAllPlayers = $localCurrentTeam->getAllPlayers();
foreach ($currentTeamAllPlayers as &$currentTeamPlayer)
{
$currentTeamPlayerRating = $currentTeam->getRating($currentTeamPlayer);
$playerSkill = $this->createSkillOutputVariable($currentTeamPlayer);
$priorFactor = $this->createPriorFactor($currentTeamPlayer, $currentTeamPlayerRating, $playerSkill);
$localCurrentTeamPlayer = &$currentTeamPlayer;
$currentTeamPlayerRating = $currentTeam->getRating($localCurrentTeamPlayer);
$playerSkill = &$this->createSkillOutputVariable($localCurrentTeamPlayer);
$priorFactor = &$this->createPriorFactor($localCurrentTeamPlayer, $currentTeamPlayerRating, $playerSkill);
$this->addLayerFactor($priorFactor);
$currentTeamSkills[] = $playerSkill;
}
@ -73,11 +75,12 @@ class PlayerPriorValuesToSkillsLayer extends TrueSkillFactorGraphLayer
$skillsVariable);
}
private function createSkillOutputVariable($key)
private function &createSkillOutputVariable(&$key)
{
$parentFactorGraph = &$this->getParentFactorGraph();
$variableFactory = &$parentFactorGraph->getVariableFactory();
return $variableFactory->createKeyedVariable($key, $key . "'s skill");
$skillOutputVariable = &$variableFactory->createKeyedVariable($key, $key . "'s skill");
return $skillOutputVariable;
}
}

@ -31,9 +31,10 @@ class PlayerSkillsToPerformancesLayer extends TrueSkillFactorGraphLayer
foreach ($currentTeam as &$playerSkillVariable)
{
$currentPlayer = &$playerSkillVariable->getKey();
$playerPerformance = $this->createOutputVariable($currentPlayer);
$newLikelihoodFactor = $this->createLikelihood($playerSkillVariable, $playerPerformance);
$localPlayerSkillVariable = &$playerSkillVariable;
$currentPlayer = &$localPlayerSkillVariable->getKey();
$playerPerformance = &$this->createOutputVariable($currentPlayer);
$newLikelihoodFactor = $this->createLikelihood($localPlayerSkillVariable, $playerPerformance);
$this->addLayerFactor($newLikelihoodFactor);
$currentTeamPlayerPerformances[] = $playerPerformance;
}
@ -47,9 +48,10 @@ class PlayerSkillsToPerformancesLayer extends TrueSkillFactorGraphLayer
return new GaussianLikelihoodFactor(square($this->getParentFactorGraph()->getGameInfo()->getBeta()), $playerPerformance, $playerSkill);
}
private function createOutputVariable(&$key)
private function &createOutputVariable(&$key)
{
return $this->getParentFactorGraph()->getVariableFactory()->createKeyedVariable($key, $key . "'s performance");
$outputVariable = &$this->getParentFactorGraph()->getVariableFactory()->createKeyedVariable($key, $key . "'s performance");
return $outputVariable;
}
public function createPriorSchedule()

@ -46,9 +46,10 @@ class TeamPerformancesToTeamPerformanceDifferencesLayer extends TrueSkillFactorG
return new GaussianWeightedSumFactor($output, $teams, $weights);
}
private function createOutputVariable()
private function &createOutputVariable()
{
return $this->getParentFactorGraph()->getVariableFactory()->createBasicVariable("Team performance difference");
$outputVariable = &$this->getParentFactorGraph()->getVariableFactory()->createBasicVariable("Team performance difference");
return $outputVariable;
}
}

@ -37,7 +37,7 @@ class TrueSkillFactorGraph extends FactorGraph
private $_layers;
private $_priorLayer;
public function __construct(GameInfo &$gameInfo, &$teams, array $teamRanks)
public function __construct(GameInfo &$gameInfo, array &$teams, array $teamRanks)
{
$this->_priorLayer = new PlayerPriorValuesToSkillsLayer($this, $teams);
$this->_gameInfo = $gameInfo;
@ -98,7 +98,8 @@ class TrueSkillFactorGraph extends FactorGraph
$localFactors = &$currentLayer->getLocalFactors();
foreach ($localFactors as &$currentFactor)
{
$factorList->addFactor($currentFactor);
$localCurrentFactor = &$currentFactor;
$factorList->addFactor($localCurrentFactor);
}
}
@ -143,10 +144,12 @@ class TrueSkillFactorGraph extends FactorGraph
{
foreach ($currentTeam as &$currentPlayer)
{
$localCurrentPlayer = &$currentPlayer->getKey();
$test = \spl_object_hash($localCurrentPlayer);
$newRating = new Rating($currentPlayer->getValue()->getMean(),
$currentPlayer->getValue()->getStandardDeviation());
$result->setRating($currentPlayer, $newRating);
$result->setRating($localCurrentPlayer, $newRating);
}
}

@ -146,9 +146,10 @@ class TwoTeamTrueSkillCalculator extends SkillCalculator
$rankMultiplier = 1;
}
foreach ($selfTeam->getAllPlayers() as $selfTeamCurrentPlayer)
foreach ($selfTeam->getAllPlayers() as &$selfTeamCurrentPlayer)
{
$previousPlayerRating = $selfTeam->getRating($selfTeamCurrentPlayer);
$localSelfTeamCurrentPlayer = &$selfTeamCurrentPlayer;
$previousPlayerRating = $selfTeam->getRating($localSelfTeamCurrentPlayer);
$meanMultiplier = (square($previousPlayerRating->getStandardDeviation()) + $tauSquared)/$c;
$stdDevMultiplier = (square($previousPlayerRating->getStandardDeviation()) + $tauSquared)/square($c);
@ -159,7 +160,7 @@ class TwoTeamTrueSkillCalculator extends SkillCalculator
$newStdDev =
sqrt((square($previousPlayerRating->getStandardDeviation()) + $tauSquared)*(1 - $w*$stdDevMultiplier));
$newPlayerRatings->setRating($selfTeamCurrentPlayer, new Rating($newMean, $newStdDev));
$newPlayerRatings->setRating($localSelfTeamCurrentPlayer, new Rating($newMean, $newStdDev));
}
}

@ -11,7 +11,7 @@ use Moserware\Skills\TrueSkill\FactorGraphTrueSkillCalculator;
class FactorGraphTrueSkillCalculatorTest extends PHPUnit_Framework_TestCase
{
public function testFactorGraphTrueSkillCalculator()
{
{
$calculator = new FactorGraphTrueSkillCalculator();
TrueSkillCalculatorTests::testAllTwoPlayerScenarios($this, $calculator);

@ -67,6 +67,8 @@ class TrueSkillCalculatorTests
{
$player1 = new Player(1);
$player2 = new Player(2);
$p1Key = \spl_object_hash($player1);
$p2Key = \spl_object_hash($player2);
$gameInfo = new GameInfo();
$team1 = new Team($player1, $gameInfo->getDefaultRating());