Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Custom Distance Metric Implementation Example #59

Closed
TurtIeSocks opened this issue May 29, 2022 · 2 comments
Closed

Custom Distance Metric Implementation Example #59

TurtIeSocks opened this issue May 29, 2022 · 2 comments

Comments

@TurtIeSocks
Copy link

Hi, sorry for the dumb question, I'm new to rust and algorithms in general but I'm trying to implement a distance metric using lat, lon coordinates to return the number of meters:

    fn earth_distance(start: [f64; 2], end: [f64; 2]) -> f64 {
        let d_lat: f64 = (end[0] - start[0]).to_radians();
        let d_lon: f64 = (end[1] - start[1]).to_radians();
        let lat1: f64 = (start[0]).to_radians();
        let lat2: f64 = (end[0]).to_radians();
    
        let a: f64 = ((d_lat / 2.0).sin()) * ((d_lat / 2.0).sin())
            + ((d_lon / 2.0).sin()) * ((d_lon / 2.0).sin()) * (lat1.cos()) * (lat2.cos());
        let c: f64 = 2.0 * ((a.sqrt()).atan2((1.0 - a).sqrt()));
    
        6.371 * c
    }

I notcied that petal-clustering has support for custom metric functions, but it's not clear how to implement this in my code. Any advice would be greatly appreciated, thank you!

@minshao
Copy link
Contributor

minshao commented May 31, 2022

Basically, Metric is a trait defined in petal-neighbors crate, you just need to implement the trait so that functions requires it could use it:

use petal_neighbors::distance::Metric;
use ndarray::{Array2, ArrayView1, ArrayView2};

struct EarthDistance {}

impl<A> Metric<A> for EarthDistance
where
    A: Float + Zero + AddAssign,
{
    fn distance(&self, start: &ArrayView1<A>, end: &ArrayView1<A>) -> A {
         // your definition of the distance here
        let d_lat: f64 = (end[0] - start[0]).to_radians();
        let d_lon: f64 = (end[1] - start[1]).to_radians();
        let lat1: f64 = (start[0]).to_radians();
        let lat2: f64 = (end[0]).to_radians();
    
        let a: f64 = ((d_lat / 2.0).sin()) * ((d_lat / 2.0).sin())
            + ((d_lon / 2.0).sin()) * ((d_lon / 2.0).sin()) * (lat1.cos()) * (lat2.cos());
        let c: f64 = 2.0 * ((a.sqrt()).atan2((1.0 - a).sqrt()));
    
        6.371 * c
    }

    fn rdistance(&self, _: &ArrayView1<A>, _: &ArrayView1<A>) -> A {
         // required by the trait, even if you are not using it, still need to implement it.
         A::zero();
    }

    fn rdistance_to_distance(&self, _: A) -> A {
         A::zero();
    }

    fn distance_to_rdistance(&self, _: A) -> A {
         A::zero();
    }
}

The above is not tested, so you might still (or definitely will) need to make adjustments. Hope it would suffice as an example. And let me know if you have further questions~

@TurtIeSocks
Copy link
Author

Sorry for the delay, but I really appreciate the example! I'm still figuring some things out on my end, but this is mostly due to some core Rust knowledge that I need to work on. Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants