Skip to content

Instantly share code, notes, and snippets.

@jblachly
Created April 11, 2017 11:45
Show Gist options
  • Save jblachly/45bae5aada5679c8cb24226de4d0e6bb to your computer and use it in GitHub Desktop.
Save jblachly/45bae5aada5679c8cb24226de4d0e6bb to your computer and use it in GitHub Desktop.
module minkowski;
import std.math : abs, pow, sqrt;
import std.algorithm;
import std.stdio;
float minkowski_distance(F)(F[] v1, F[] v2, int p=1)
{
// Theoretically the Minkowski distance can be defined for noninteger powers
// but I do not want to deal with this right now
if (p < 1) throw new Exception("Minkowski distance with p < 1 is not a metric because it violattes the triangle inequality");
assert(v1.length == v2.length);
/// I could adopt a "running sum" strategy and compute the sum
/// running_sum += pow( abs(x_i - y-i), 2)
/// perhaps by first doing all subtractions then all exponentiations
/// I can take advantage of pipelining and/or parallelization (future)
F[] v3;
v3.length = v1.length;
for(int i; i<v1.length; i++) {
v3[i] = abs( (v1[i] - v2[i]) );
}
if(p == 1) {
auto sigma = std.algorithm.sum(v3);
writeln(sigma);
return sigma;
} else {
auto sigma = std.algorithm.sum( v3.map!(a => pow(a, p)) );
writeln(sigma);
return sigma.pow( 1 / cast(float)p );
}
}
unittest
{
float[] v1 = [2, 6];
float[] v2 = [3, 4];
float[] v3 = [3, 8];
float[] v5 = [6, 2];
// Manhattan distance (default)
assert(minkowski_distance(v1, v2) == 3);
assert(minkowski_distance(v3, v2) == 4);
assert(minkowski_distance(v5, v2) == 5);
float[] e1 = [0, 0, 0];
float[] e2 = [0, 1, 1];
// Euclidean distance
assert(minkowski_distance(e1, e2, 2) == sqrt(2.0));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment