/
Circle.php
114 lines (96 loc) · 2.36 KB
/
Circle.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
<?php
namespace Rubix\ML\Datasets\Generators;
use Tensor\Matrix;
use Tensor\Vector;
use Rubix\ML\Datasets\Labeled;
use Rubix\ML\Exceptions\InvalidArgumentException;
use function Rubix\ML\array_transpose;
use const Rubix\ML\TWO_PI;
/**
* Circle
*
* Create a circle made of sample data points in 2 dimensions.
*
* @category Machine Learning
* @package Rubix/ML
* @author Andrew DalPino
*/
class Circle implements Generator
{
/**
* The center vector of the circle.
*
* @var Vector
*/
protected Vector $center;
/**
* The scaling factor of the circle.
*
* @var float
*/
protected float $scale;
/**
* The factor of gaussian noise to add to the data points.
*
* @var float
*/
protected float $noise;
/**
* @param float $x
* @param float $y
* @param float $scale
* @param float $noise
* @throws InvalidArgumentException
*/
public function __construct(
float $x = 0.0,
float $y = 0.0,
float $scale = 1.0,
float $noise = 0.1
) {
if ($scale < 0.0) {
throw new InvalidArgumentException('Scale must be'
. " greater than 0, $scale given.");
}
if ($noise < 0.0) {
throw new InvalidArgumentException('Noise must be'
. " greater than 0, $noise given.");
}
$this->center = Vector::quick([$x, $y]);
$this->scale = $scale;
$this->noise = $noise;
}
/**
* Return the dimensionality of the data this generates.
*
* @internal
*
* @return int<0,max>
*/
public function dimensions() : int
{
return 2;
}
/**
* Generate n data points.
*
* @param int<0,max> $n
* @return Labeled
*/
public function generate(int $n) : Labeled
{
$r = Vector::rand($n)->multiply(TWO_PI);
$x = $r->cos()->asArray();
$y = $r->sin()->asArray();
$coordinates = array_transpose([$x, $y]);
$noise = Matrix::gaussian($n, 2)
->multiply($this->noise);
$samples = Matrix::quick($coordinates)
->multiply($this->scale)
->add($this->center)
->add($noise)
->asArray();
$labels = $r->rad2deg()->asArray();
return Labeled::quick($samples, $labels);
}
}