Fix KMeans and EigenvalueDecomposition (#235)

* Fix kmeans cluster and eigenvalue decomposition

* Fix kmeans space

* Fix code style
This commit is contained in:
Arkadiusz Kondas 2018-02-18 00:09:24 +01:00 committed by GitHub
parent 797952e1bc
commit 0a15561352
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 60 additions and 22 deletions

View File

@ -76,7 +76,8 @@ class Cluster extends Point implements IteratorAggregate, Countable
public function updateCentroid(): void
{
if (empty($this->points)) {
$count = count($this->points);
if ($count === 0) {
return;
}
@ -88,7 +89,6 @@ class Cluster extends Point implements IteratorAggregate, Countable
}
}
$count = count($this->points);
for ($n = 0; $n < $this->dimension; ++$n) {
$this->coordinates[$n] = $centroid->coordinates[$n] / $count;
}

View File

@ -75,7 +75,7 @@ class Space extends SplObjectStorage
*/
public function getBoundaries()
{
if (empty($this)) {
if (count($this) === 0) {
return false;
}

View File

@ -99,7 +99,7 @@ class EigenvalueDecomposition
$this->n = count($Arg[0]);
$this->symmetric = true;
for ($j = 0; ($j < $this->n) && $this->symmetric; ++$j) {
for ($j = 0; ($j < $this->n) & $this->symmetric; ++$j) {
for ($i = 0; ($i < $this->n) & $this->symmetric; ++$i) {
$this->symmetric = ($this->A[$i][$j] == $this->A[$j][$i]);
}
@ -204,7 +204,7 @@ class EigenvalueDecomposition
$scale += array_sum(array_map('abs', $this->d));
if ($scale == 0.0) {
$this->e[$i] = $this->d[$i_];
$this->d = array_slice($this->V[$i_], 0, $i_);
$this->d = array_slice($this->V[$i_], 0, $this->n - 1);
for ($j = 0; $j < $i; ++$j) {
$this->V[$j][$i] = $this->V[$i][$j] = 0.0;
}
@ -244,7 +244,8 @@ class EigenvalueDecomposition
}
$f = 0.0;
if ($h === 0 || $h < 1e-32) {
if ($h == 0.0) {
$h = 1e-32;
}
@ -274,7 +275,6 @@ class EigenvalueDecomposition
}
// Accumulate transformations.
$j = 0;
for ($i = 0; $i < $this->n - 1; ++$i) {
$this->V[$this->n - 1][$i] = $this->V[$i][$i];
$this->V[$i][$i] = 1.0;
@ -302,7 +302,7 @@ class EigenvalueDecomposition
}
$this->d = $this->V[$this->n - 1];
$this->V[$this->n - 1] = array_fill(0, $j, 0.0);
$this->V[$this->n - 1] = array_fill(0, $this->n, 0.0);
$this->V[$this->n - 1][$this->n - 1] = 1.0;
$this->e[0] = 0.0;
}

View File

@ -10,34 +10,72 @@ use PHPUnit\Framework\TestCase;
class EigenvalueDecompositionTest extends TestCase
{
public function testSymmetricMatrixEigenPairs(): void
public function testKnownSymmetricMatrixDecomposition(): void
{
// Acceptable error
$epsilon = 0.001;
// First a simple example whose result is known and given in
// http://www.cs.otago.ac.nz/cosc453/student_tutorials/principal_components.pdf
$matrix = [
[0.616555556, 0.615444444],
[0.614444444, 0.716555556],
];
$knownEigvalues = [0.0490833989, 1.28402771];
$knownEigvectors = [[-0.735178656, 0.677873399], [-0.677873399, -0.735178656]];
$decomp = new EigenvalueDecomposition($matrix);
$eigVectors = $decomp->getEigenvectors();
$eigValues = $decomp->getRealEigenvalues();
$this->assertEquals($knownEigvalues, $eigValues, '', $epsilon);
$this->assertEquals($knownEigvectors, $eigVectors, '', $epsilon);
self::assertEquals([0.0490833989, 1.28402771], $decomp->getRealEigenvalues(), '', 0.001);
self::assertEquals([
[-0.735178656, 0.677873399],
[-0.677873399, -0.735178656],
], $decomp->getEigenvectors(), '', 0.001);
}
public function testMatrixWithAllZeroRow(): void
{
// http://www.wolframalpha.com/widgets/view.jsp?id=9aa01caf50c9307e9dabe159c9068c41
$matrix = [
[10, 0, 0],
[0, 6, 0],
[0, 0, 0],
];
$decomp = new EigenvalueDecomposition($matrix);
self::assertEquals([0.0, 6.0, 10.0], $decomp->getRealEigenvalues(), '', 0.0001);
self::assertEquals([
[0, 0, 1],
[0, 1, 0],
[1, 0, 0],
], $decomp->getEigenvectors(), '', 0.0001);
}
public function testMatrixThatCauseErrorWithStrictComparision(): void
{
// http://www.wolframalpha.com/widgets/view.jsp?id=9aa01caf50c9307e9dabe159c9068c41
$matrix = [
[1, 0, 3],
[0, 1, 7],
[3, 7, 4],
];
$decomp = new EigenvalueDecomposition($matrix);
self::assertEquals([-5.2620873481, 1.0, 10.2620873481], $decomp->getRealEigenvalues(), '', 0.000001);
self::assertEquals([
[-0.3042688, -0.709960552, 0.63511928],
[-0.9191450, 0.393919298, 0.0],
[0.25018574, 0.5837667, 0.7724140],
], $decomp->getEigenvectors(), '', 0.0001);
}
public function testRandomSymmetricMatrixEigenPairs(): void
{
// Acceptable error
$epsilon = 0.001;
// Secondly, generate a symmetric square matrix
// and test for A.v=λ.v
//
// (We, for now, omit non-symmetric matrices whose eigenvalues can be complex numbers)
$len = 3;
srand((int) microtime(true) * 1000);
$A = array_fill(0, $len, array_fill(0, $len, 0.0));
$seed = microtime(true) * 1000;
srand((int) $seed);
for ($i = 0; $i < $len; ++$i) {
for ($k = 0; $k < $len; ++$k) {
if ($i > $k) {
@ -60,7 +98,7 @@ class EigenvalueDecompositionTest extends TestCase
$leftSide = $m1->multiply($m2)->toArray();
$rightSide = $m2->multiplyByScalar($lambda)->toArray();
$this->assertEquals($leftSide, $rightSide, '', $epsilon);
self::assertEquals($leftSide, $rightSide, '', $epsilon);
}
}
}