1*3379af09SAndreas Gohr<?php 2*3379af09SAndreas Gohr 3*3379af09SAndreas Gohr/** 4*3379af09SAndreas Gohr * This file is part of PHP K-Means 5*3379af09SAndreas Gohr * 6*3379af09SAndreas Gohr * Copyright (c) 2014 Benjamin Delespierre 7*3379af09SAndreas Gohr * 8*3379af09SAndreas Gohr * Permission is hereby granted, free of charge, to any person obtaining a copy 9*3379af09SAndreas Gohr * of this software and associated documentation files (the "Software"), to deal 10*3379af09SAndreas Gohr * in the Software without restriction, including without limitation the rights 11*3379af09SAndreas Gohr * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12*3379af09SAndreas Gohr * copies of the Software, and to permit persons to whom the Software is furnished 13*3379af09SAndreas Gohr * to do so, subject to the following conditions: 14*3379af09SAndreas Gohr * 15*3379af09SAndreas Gohr * The above copyright notice and this permission notice shall be included in all 16*3379af09SAndreas Gohr * copies or substantial portions of the Software. 17*3379af09SAndreas Gohr * 18*3379af09SAndreas Gohr * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19*3379af09SAndreas Gohr * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20*3379af09SAndreas Gohr * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21*3379af09SAndreas Gohr * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22*3379af09SAndreas Gohr * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23*3379af09SAndreas Gohr * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24*3379af09SAndreas Gohr * THE SOFTWARE. 25*3379af09SAndreas Gohr */ 26*3379af09SAndreas Gohr 27*3379af09SAndreas Gohrnamespace KMeans; 28*3379af09SAndreas Gohr 29*3379af09SAndreas Gohrclass Cluster extends Point implements \IteratorAggregate, \Countable 30*3379af09SAndreas Gohr{ 31*3379af09SAndreas Gohr public const INIT_RANDOM = 1; 32*3379af09SAndreas Gohr public const INIT_KMEANS_PLUS_PLUS = 2; 33*3379af09SAndreas Gohr 34*3379af09SAndreas Gohr protected $space; 35*3379af09SAndreas Gohr protected $points; 36*3379af09SAndreas Gohr 37*3379af09SAndreas Gohr public function __construct(Space $space, array $coordinates) 38*3379af09SAndreas Gohr { 39*3379af09SAndreas Gohr parent::__construct($space, $coordinates); 40*3379af09SAndreas Gohr $this->points = new \SplObjectStorage(); 41*3379af09SAndreas Gohr } 42*3379af09SAndreas Gohr 43*3379af09SAndreas Gohr public function toArray(): array 44*3379af09SAndreas Gohr { 45*3379af09SAndreas Gohr $points = []; 46*3379af09SAndreas Gohr foreach ($this->points as $point) { 47*3379af09SAndreas Gohr $points[] = $point->toArray(); 48*3379af09SAndreas Gohr } 49*3379af09SAndreas Gohr 50*3379af09SAndreas Gohr return [ 51*3379af09SAndreas Gohr 'centroid' => parent::toArray(), 52*3379af09SAndreas Gohr 'points' => $points, 53*3379af09SAndreas Gohr ]; 54*3379af09SAndreas Gohr } 55*3379af09SAndreas Gohr 56*3379af09SAndreas Gohr public function attach(Point $point): Point 57*3379af09SAndreas Gohr { 58*3379af09SAndreas Gohr if ($point instanceof self) { 59*3379af09SAndreas Gohr throw new \LogicException("cannot attach a cluster to another"); 60*3379af09SAndreas Gohr } 61*3379af09SAndreas Gohr 62*3379af09SAndreas Gohr $this->points->attach($point); 63*3379af09SAndreas Gohr return $point; 64*3379af09SAndreas Gohr } 65*3379af09SAndreas Gohr 66*3379af09SAndreas Gohr public function detach(Point $point): Point 67*3379af09SAndreas Gohr { 68*3379af09SAndreas Gohr $this->points->detach($point); 69*3379af09SAndreas Gohr return $point; 70*3379af09SAndreas Gohr } 71*3379af09SAndreas Gohr 72*3379af09SAndreas Gohr public function attachAll(\SplObjectStorage $points): void 73*3379af09SAndreas Gohr { 74*3379af09SAndreas Gohr $this->points->addAll($points); 75*3379af09SAndreas Gohr } 76*3379af09SAndreas Gohr 77*3379af09SAndreas Gohr public function detachAll(\SplObjectStorage $points): void 78*3379af09SAndreas Gohr { 79*3379af09SAndreas Gohr $this->points->removeAll($points); 80*3379af09SAndreas Gohr } 81*3379af09SAndreas Gohr 82*3379af09SAndreas Gohr public function updateCentroid(): void 83*3379af09SAndreas Gohr { 84*3379af09SAndreas Gohr if (!$count = count($this->points)) { 85*3379af09SAndreas Gohr return; 86*3379af09SAndreas Gohr } 87*3379af09SAndreas Gohr 88*3379af09SAndreas Gohr $centroid = $this->space->newPoint(array_fill(0, $this->dimention, 0)); 89*3379af09SAndreas Gohr 90*3379af09SAndreas Gohr foreach ($this->points as $point) { 91*3379af09SAndreas Gohr for ($n = 0; $n < $this->dimention; $n++) { 92*3379af09SAndreas Gohr $centroid->coordinates[$n] += $point->coordinates[$n]; 93*3379af09SAndreas Gohr } 94*3379af09SAndreas Gohr } 95*3379af09SAndreas Gohr 96*3379af09SAndreas Gohr for ($n = 0; $n < $this->dimention; $n++) { 97*3379af09SAndreas Gohr $this->coordinates[$n] = $centroid->coordinates[$n] / $count; 98*3379af09SAndreas Gohr } 99*3379af09SAndreas Gohr } 100*3379af09SAndreas Gohr 101*3379af09SAndreas Gohr public function getIterator(): \Iterator 102*3379af09SAndreas Gohr { 103*3379af09SAndreas Gohr return $this->points; 104*3379af09SAndreas Gohr } 105*3379af09SAndreas Gohr 106*3379af09SAndreas Gohr public function count(): int 107*3379af09SAndreas Gohr { 108*3379af09SAndreas Gohr return count($this->points); 109*3379af09SAndreas Gohr } 110*3379af09SAndreas Gohr} 111