Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.11.x will end 14 Nov 2022 (12 months plus 6 months extension).
  • Bug fixes for security issues in 3.11.x will end 13 Nov 2023 (18 months plus 12 months extension).
  • PHP version: minimum PHP 7.3.0 Note: minimum PHP version has increased since Moodle 3.10. PHP 7.4.x is supported too.
   1  <?php
   2  
   3  declare(strict_types=1);
   4  
   5  namespace Phpml\Clustering\KMeans;
   6  
   7  use IteratorAggregate;
   8  use LogicException;
   9  use SplObjectStorage;
  10  
  11  class Cluster extends Point implements IteratorAggregate
  12  {
  13      /**
  14       * @var Space
  15       */
  16      protected $space;
  17  
  18      /**
  19       * @var SplObjectStorage|Point[]
  20       */
  21      protected $points;
  22  
  23      public function __construct(Space $space, array $coordinates)
  24      {
  25          parent::__construct($coordinates);
  26          $this->space = $space;
  27          $this->points = new SplObjectStorage();
  28      }
  29  
  30      public function getPoints(): array
  31      {
  32          $points = [];
  33          foreach ($this->points as $point) {
  34              if ($point->label === null) {
  35                  $points[] = $point->toArray();
  36              } else {
  37                  $points[$point->label] = $point->toArray();
  38              }
  39          }
  40  
  41          return $points;
  42      }
  43  
  44      public function toArray(): array
  45      {
  46          return [
  47              'centroid' => parent::toArray(),
  48              'points' => $this->getPoints(),
  49          ];
  50      }
  51  
  52      public function attach(Point $point): Point
  53      {
  54          if ($point instanceof self) {
  55              throw new LogicException('Cannot attach a cluster to another');
  56          }
  57  
  58          $this->points->attach($point);
  59  
  60          return $point;
  61      }
  62  
  63      public function detach(Point $point): Point
  64      {
  65          $this->points->detach($point);
  66  
  67          return $point;
  68      }
  69  
  70      public function attachAll(SplObjectStorage $points): void
  71      {
  72          $this->points->addAll($points);
  73      }
  74  
  75      public function detachAll(SplObjectStorage $points): void
  76      {
  77          $this->points->removeAll($points);
  78      }
  79  
  80      public function updateCentroid(): void
  81      {
  82          $count = count($this->points);
  83          if ($count === 0) {
  84              return;
  85          }
  86  
  87          $centroid = $this->space->newPoint(array_fill(0, $this->dimension, 0));
  88  
  89          foreach ($this->points as $point) {
  90              for ($n = 0; $n < $this->dimension; ++$n) {
  91                  $centroid->coordinates[$n] += $point->coordinates[$n];
  92              }
  93          }
  94  
  95          for ($n = 0; $n < $this->dimension; ++$n) {
  96              $this->coordinates[$n] = $centroid->coordinates[$n] / $count;
  97          }
  98      }
  99  
 100      /**
 101       * @return Point[]|SplObjectStorage
 102       */
 103      public function getIterator()
 104      {
 105          return $this->points;
 106      }
 107  
 108      public function count(): int
 109      {
 110          return count($this->points);
 111      }
 112  
 113      public function setCoordinates(array $newCoordinates): void
 114      {
 115          $this->coordinates = $newCoordinates;
 116      }
 117  }