mirror of
https://github.com/Llewellynvdm/php-ml.git
synced 2025-02-02 20:18:27 +00:00
Fix KMeans and EigenvalueDecomposition (#235)
* Fix kmeans cluster and eigenvalue decomposition * Fix kmeans space * Fix code style
This commit is contained in:
parent
797952e1bc
commit
0a15561352
@ -76,7 +76,8 @@ class Cluster extends Point implements IteratorAggregate, Countable
|
|||||||
|
|
||||||
public function updateCentroid(): void
|
public function updateCentroid(): void
|
||||||
{
|
{
|
||||||
if (empty($this->points)) {
|
$count = count($this->points);
|
||||||
|
if ($count === 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -88,7 +89,6 @@ class Cluster extends Point implements IteratorAggregate, Countable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$count = count($this->points);
|
|
||||||
for ($n = 0; $n < $this->dimension; ++$n) {
|
for ($n = 0; $n < $this->dimension; ++$n) {
|
||||||
$this->coordinates[$n] = $centroid->coordinates[$n] / $count;
|
$this->coordinates[$n] = $centroid->coordinates[$n] / $count;
|
||||||
}
|
}
|
||||||
|
@ -75,7 +75,7 @@ class Space extends SplObjectStorage
|
|||||||
*/
|
*/
|
||||||
public function getBoundaries()
|
public function getBoundaries()
|
||||||
{
|
{
|
||||||
if (empty($this)) {
|
if (count($this) === 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,7 +99,7 @@ class EigenvalueDecomposition
|
|||||||
$this->n = count($Arg[0]);
|
$this->n = count($Arg[0]);
|
||||||
$this->symmetric = true;
|
$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) {
|
for ($i = 0; ($i < $this->n) & $this->symmetric; ++$i) {
|
||||||
$this->symmetric = ($this->A[$i][$j] == $this->A[$j][$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));
|
$scale += array_sum(array_map('abs', $this->d));
|
||||||
if ($scale == 0.0) {
|
if ($scale == 0.0) {
|
||||||
$this->e[$i] = $this->d[$i_];
|
$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) {
|
for ($j = 0; $j < $i; ++$j) {
|
||||||
$this->V[$j][$i] = $this->V[$i][$j] = 0.0;
|
$this->V[$j][$i] = $this->V[$i][$j] = 0.0;
|
||||||
}
|
}
|
||||||
@ -244,7 +244,8 @@ class EigenvalueDecomposition
|
|||||||
}
|
}
|
||||||
|
|
||||||
$f = 0.0;
|
$f = 0.0;
|
||||||
if ($h === 0 || $h < 1e-32) {
|
|
||||||
|
if ($h == 0.0) {
|
||||||
$h = 1e-32;
|
$h = 1e-32;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -274,7 +275,6 @@ class EigenvalueDecomposition
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Accumulate transformations.
|
// Accumulate transformations.
|
||||||
$j = 0;
|
|
||||||
for ($i = 0; $i < $this->n - 1; ++$i) {
|
for ($i = 0; $i < $this->n - 1; ++$i) {
|
||||||
$this->V[$this->n - 1][$i] = $this->V[$i][$i];
|
$this->V[$this->n - 1][$i] = $this->V[$i][$i];
|
||||||
$this->V[$i][$i] = 1.0;
|
$this->V[$i][$i] = 1.0;
|
||||||
@ -302,7 +302,7 @@ class EigenvalueDecomposition
|
|||||||
}
|
}
|
||||||
|
|
||||||
$this->d = $this->V[$this->n - 1];
|
$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->V[$this->n - 1][$this->n - 1] = 1.0;
|
||||||
$this->e[0] = 0.0;
|
$this->e[0] = 0.0;
|
||||||
}
|
}
|
||||||
|
@ -10,34 +10,72 @@ use PHPUnit\Framework\TestCase;
|
|||||||
|
|
||||||
class EigenvalueDecompositionTest extends 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
|
// First a simple example whose result is known and given in
|
||||||
// http://www.cs.otago.ac.nz/cosc453/student_tutorials/principal_components.pdf
|
// http://www.cs.otago.ac.nz/cosc453/student_tutorials/principal_components.pdf
|
||||||
$matrix = [
|
$matrix = [
|
||||||
[0.616555556, 0.615444444],
|
[0.616555556, 0.615444444],
|
||||||
[0.614444444, 0.716555556],
|
[0.614444444, 0.716555556],
|
||||||
];
|
];
|
||||||
$knownEigvalues = [0.0490833989, 1.28402771];
|
|
||||||
$knownEigvectors = [[-0.735178656, 0.677873399], [-0.677873399, -0.735178656]];
|
|
||||||
|
|
||||||
$decomp = new EigenvalueDecomposition($matrix);
|
$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
|
// Secondly, generate a symmetric square matrix
|
||||||
// and test for A.v=λ.v
|
// and test for A.v=λ.v
|
||||||
//
|
|
||||||
// (We, for now, omit non-symmetric matrices whose eigenvalues can be complex numbers)
|
// (We, for now, omit non-symmetric matrices whose eigenvalues can be complex numbers)
|
||||||
$len = 3;
|
$len = 3;
|
||||||
|
srand((int) microtime(true) * 1000);
|
||||||
$A = array_fill(0, $len, array_fill(0, $len, 0.0));
|
$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 ($i = 0; $i < $len; ++$i) {
|
||||||
for ($k = 0; $k < $len; ++$k) {
|
for ($k = 0; $k < $len; ++$k) {
|
||||||
if ($i > $k) {
|
if ($i > $k) {
|
||||||
@ -60,7 +98,7 @@ class EigenvalueDecompositionTest extends TestCase
|
|||||||
$leftSide = $m1->multiply($m2)->toArray();
|
$leftSide = $m1->multiply($m2)->toArray();
|
||||||
$rightSide = $m2->multiplyByScalar($lambda)->toArray();
|
$rightSide = $m2->multiplyByScalar($lambda)->toArray();
|
||||||
|
|
||||||
$this->assertEquals($leftSide, $rightSide, '', $epsilon);
|
self::assertEquals($leftSide, $rightSide, '', $epsilon);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user