From cc0d818b9782ed4cb85ceb18df3c4f8e5ab49b67 Mon Sep 17 00:00:00 2001 From: Mark Rogoyski Date: Sat, 2 Mar 2024 15:44:15 -0800 Subject: [PATCH] Add Chebyshev Distance. --- src/Statistics/Distance.php | 31 ++++++++++ tests/Statistics/DistanceTest.php | 94 +++++++++++++++++++++++++++++++ 2 files changed, 125 insertions(+) diff --git a/src/Statistics/Distance.php b/src/Statistics/Distance.php index 8b569a6d7..553163da8 100644 --- a/src/Statistics/Distance.php +++ b/src/Statistics/Distance.php @@ -470,4 +470,35 @@ function (float $|pᵢ − qᵢ|, float $|pᵢ| + |qᵢ|) { $|p| + |q| )); } + + /** + * Chebyshev Distance + * A metric defined on a real coordinate space where the distance between two points + * is the greatest of their differences along any coordinate dimension. + * + * D(x, y) = max(|xᵢ − yᵢ|) + * + * https://en.wikipedia.org/wiki/Chebyshev_distance + * + * @param array $xs + * @param array $ys + * + * @return float + * + * @throws Exception\BadDataException + */ + public static function chebyshev(array $xs, array $ys): float + { + if (\count($xs) !== \count($ys)) { + throw new Exception\BadDataException('xs and ys must have the same number of elements'); + } + + return \max(\array_map( + function (float $xᵢ, $yᵢ) { + return \abs($xᵢ - $yᵢ); + }, + $xs, + $ys + )); + } } diff --git a/tests/Statistics/DistanceTest.php b/tests/Statistics/DistanceTest.php index 6de04b048..264b76713 100644 --- a/tests/Statistics/DistanceTest.php +++ b/tests/Statistics/DistanceTest.php @@ -1252,4 +1252,98 @@ public function testCanberraExceptionDifferentNumberElements() // When $distance = Distance::canberra($p, $q); } + + /** + * @test chebyshev + * @dataProvider dataProviderForChebyshev + * @param array $x + * @param array $y + * @param float $expected + */ + public function testChebyshev(array $x, array $y, float $expected): void + { + // When + $distance = Distance::chebyshev($x, $y); + + // Then + $this->assertEqualsWithDelta($expected, $distance, 0.0001); + } + + public function dataProviderForChebyshev(): array + { + return [ + [ + [0], + [0], + 0 + ], + [ + [1], + [1], + 0 + ], + [ + [1], + [0], + 1 + ], + [ + [0], + [1], + 1 + ], + [ + [1, 2], + [2, 4], + 2 + ], + [ + [1, 2, 3], + [2, 4, 6], + 3 + ], + [ + [0, 3, 4, 5], + [7, 6, 3, -1], + 7 + ], + [ + [1, 2, 3, 4], + [-5, -6, 7, 8], + 8 + ], + [ + [1, 5, 2, 3, 10], + [4, 15, 20, 5, 5], + 18 + ], + [ + [1, 5, 2, 3, 10], + [1, 5, 2, 3, 10], + 0 + ], + [ + [4, 15, 20, 5, 5], + [4, 15, 20, 5, 5], + 0 + ], + ]; + } + + /** + * @test chebyshev exception when inputs are different lengths + * @throws Exception\BadDataException + */ + public function testChebyshevExceptionDifferentNumberElements() + { + // Given + $xs = [1, 2, 3]; + $ys = [2, 3]; + + // Then + $this->expectException(Exception\BadDataException::class); + + // When + Distance::chebyshev($xs, $ys); + } }