/** * Sends the factor-graph message with and returns the log-normalization constant. */ protected function sendMessageVariable(Message $message, Variable $variable) { $marginal = $variable->getValue(); $messageValue = $message->getValue(); $logZ = GaussianDistribution::logProductNormalization($marginal, $messageValue); $variable->setValue(GaussianDistribution::multiply($marginal, $messageValue)); return $logZ; }
public function testMultiplication() { // I verified this against the formula at http://www.tina-vision.net/tina-knoppix/tina-memo/2003-003.pdf $standardNormal = new GaussianDistribution(0, 1); $shiftedGaussian = new GaussianDistribution(2, 3); $product = GaussianDistribution::multiply($standardNormal, $shiftedGaussian); $this->assertEquals(0.2, $product->getMean(), '', GaussianDistributionTest::ERROR_TOLERANCE); $this->assertEquals(3.0 / sqrt(10), $product->getStandardDeviation(), '', GaussianDistributionTest::ERROR_TOLERANCE); $m4s5 = new GaussianDistribution(4, 5); $m6s7 = new GaussianDistribution(6, 7); $product2 = GaussianDistribution::multiply($m4s5, $m6s7); $expectedMean = (4 * square(7) + 6 * square(5)) / (square(5) + square(7)); $this->assertEquals($expectedMean, $product2->getMean(), '', GaussianDistributionTest::ERROR_TOLERANCE); $expectedSigma = sqrt(square(5) * square(7) / (square(5) + square(7))); $this->assertEquals($expectedSigma, $product2->getStandardDeviation(), '', GaussianDistributionTest::ERROR_TOLERANCE); }
private function updateHelper(Message $message1, Message $message2, Variable $variable1, Variable $variable2) { $message1Value = clone $message1->getValue(); $message2Value = clone $message2->getValue(); $marginal1 = clone $variable1->getValue(); $marginal2 = clone $variable2->getValue(); $a = $this->_precision / ($this->_precision + $marginal2->getPrecision() - $message2Value->getPrecision()); $newMessage = GaussianDistribution::fromPrecisionMean($a * ($marginal2->getPrecisionMean() - $message2Value->getPrecisionMean()), $a * ($marginal2->getPrecision() - $message2Value->getPrecision())); $oldMarginalWithoutMessage = GaussianDistribution::divide($marginal1, $message1Value); $newMarginal = GaussianDistribution::multiply($oldMarginalWithoutMessage, $newMessage); // Update the message and marginal $message1->setValue($newMessage); $variable1->setValue($newMarginal); // Return the difference in the new marginal return GaussianDistribution::subtract($newMarginal, $marginal1); }
protected function updateMessageVariable(Message &$message, Variable &$variable) { $oldMarginal = clone $variable->getValue(); $oldMessage = clone $message->getValue(); $messageFromVariable = GaussianDistribution::divide($oldMarginal, $oldMessage); $c = $messageFromVariable->getPrecision(); $d = $messageFromVariable->getPrecisionMean(); $sqrtC = sqrt($c); $dOnSqrtC = $d / $sqrtC; $epsilonTimesSqrtC = $this->_epsilon * $sqrtC; $d = $messageFromVariable->getPrecisionMean(); $denominator = 1.0 - TruncatedGaussianCorrectionFunctions::wWithinMargin($dOnSqrtC, $epsilonTimesSqrtC); $newPrecision = $c / $denominator; $newPrecisionMean = ($d + $sqrtC * TruncatedGaussianCorrectionFunctions::vWithinMargin($dOnSqrtC, $epsilonTimesSqrtC)) / $denominator; $newMarginal = GaussianDistribution::fromPrecisionMean($newPrecisionMean, $newPrecision); $newMessage = GaussianDistribution::divide(GaussianDistribution::multiply($oldMessage, $newMarginal), $oldMarginal); // Update the message and marginal $message->setValue($newMessage); $variable->setValue($newMarginal); // Return the difference in the new marginal return GaussianDistribution::subtract($newMarginal, $oldMarginal); }
private function updateHelper(array $weights, array $weightsSquared, array $messages, array $variables) { // Potentially look at http://mathworld.wolfram.com/NormalSumDistribution.html for clues as // to what it's doing $message0 = clone $messages[0]->getValue(); $marginal0 = clone $variables[0]->getValue(); // The math works out so that 1/newPrecision = sum of a_i^2 /marginalsWithoutMessages[i] $inverseOfNewPrecisionSum = 0.0; $anotherInverseOfNewPrecisionSum = 0.0; $weightedMeanSum = 0.0; $anotherWeightedMeanSum = 0.0; $weightsSquaredLength = count($weightsSquared); for ($i = 0; $i < $weightsSquaredLength; $i++) { // These flow directly from the paper $inverseOfNewPrecisionSum += $weightsSquared[$i] / ($variables[$i + 1]->getValue()->getPrecision() - $messages[$i + 1]->getValue()->getPrecision()); $diff = GaussianDistribution::divide($variables[$i + 1]->getValue(), $messages[$i + 1]->getValue()); $anotherInverseOfNewPrecisionSum += $weightsSquared[$i] / $diff->getPrecision(); $weightedMeanSum += $weights[$i] * ($variables[$i + 1]->getValue()->getPrecisionMean() - $messages[$i + 1]->getValue()->getPrecisionMean()) / ($variables[$i + 1]->getValue()->getPrecision() - $messages[$i + 1]->getValue()->getPrecision()); $anotherWeightedMeanSum += $weights[$i] * $diff->getPrecisionMean() / $diff->getPrecision(); } $newPrecision = 1.0 / $inverseOfNewPrecisionSum; $anotherNewPrecision = 1.0 / $anotherInverseOfNewPrecisionSum; $newPrecisionMean = $newPrecision * $weightedMeanSum; $anotherNewPrecisionMean = $anotherNewPrecision * $anotherWeightedMeanSum; $newMessage = GaussianDistribution::fromPrecisionMean($newPrecisionMean, $newPrecision); $oldMarginalWithoutMessage = GaussianDistribution::divide($marginal0, $message0); $newMarginal = GaussianDistribution::multiply($oldMarginalWithoutMessage, $newMessage); // Update the message and marginal $messages[0]->setValue($newMessage); $variables[0]->setValue($newMarginal); // Return the difference in the new marginal $finalDiff = GaussianDistribution::subtract($newMarginal, $marginal0); return $finalDiff; }