Skip to content

Commit

Permalink
Implement manhattan and chebyshev distance for integer vectors (#593)
Browse files Browse the repository at this point in the history
  • Loading branch information
tguichaoua authored Dec 24, 2024
1 parent 77c55be commit e8a53c6
Show file tree
Hide file tree
Showing 29 changed files with 1,393 additions and 12 deletions.
1 change: 1 addition & 0 deletions codegen/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ Each template starts with setting up a number of common variables based on the
inputs from the `codegen` program. Commonly used variables are:

* `self_t` - the name of the type being generated
* `unsigned_scalar_t` - the unsigned version of `scalar_t` (e.g. `u8`, `u16`, `u32`)
* `inner_t` - the inner storage type used by this type (e.g. `__m128` or
`core::storage::XYZ<f32>`)
* `deref_t` - the type used by the `Deref` and `DerefMut` implementation - not
Expand Down
63 changes: 63 additions & 0 deletions codegen/templates/vec.rs.tera
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
{% elif scalar_t == "i8" %}
{% set is_signed = true %}
{% set is_float = false %}
{% set unsigned_scalar_t = "u8" %}
{% set self_t = "I8Vec" ~ dim %}
{% set opposite_signedness_t = "U8Vec" ~ dim %}
{% set vec2_t = "I8Vec2" %}
Expand All @@ -55,6 +56,7 @@
{% elif scalar_t == "u8" %}
{% set is_signed = false %}
{% set is_float = false %}
{% set unsigned_scalar_t = "u8" %}
{% set self_t = "U8Vec" ~ dim %}
{% set opposite_signedness_t = "I8Vec" ~ dim %}
{% set vec2_t = "U8Vec2" %}
Expand All @@ -64,6 +66,7 @@
{% elif scalar_t == "i16" %}
{% set is_signed = true %}
{% set is_float = false %}
{% set unsigned_scalar_t = "u16" %}
{% set self_t = "I16Vec" ~ dim %}
{% set opposite_signedness_t = "U16Vec" ~ dim %}
{% set vec2_t = "I16Vec2" %}
Expand All @@ -74,6 +77,7 @@
{% elif scalar_t == "u16" %}
{% set is_signed = false %}
{% set is_float = false %}
{% set unsigned_scalar_t = "u16" %}
{% set self_t = "U16Vec" ~ dim %}
{% set opposite_signedness_t = "I16Vec" ~ dim %}
{% set vec2_t = "U16Vec2" %}
Expand All @@ -84,6 +88,7 @@
{% elif scalar_t == "i32" %}
{% set is_signed = true %}
{% set is_float = false %}
{% set unsigned_scalar_t = "u32" %}
{% set self_t = "IVec" ~ dim %}
{% set opposite_signedness_t = "UVec" ~ dim %}
{% set vec2_t = "IVec2" %}
Expand All @@ -94,6 +99,7 @@
{% elif scalar_t == "u32" %}
{% set is_signed = false %}
{% set is_float = false %}
{% set unsigned_scalar_t = "u32" %}
{% set self_t = "UVec" ~ dim %}
{% set opposite_signedness_t = "IVec" ~ dim %}
{% set vec2_t = "UVec2" %}
Expand All @@ -104,6 +110,7 @@
{% elif scalar_t == "i64" %}
{% set is_signed = true %}
{% set is_float = false %}
{% set unsigned_scalar_t = "u64" %}
{% set self_t = "I64Vec" ~ dim %}
{% set opposite_signedness_t = "U64Vec" ~ dim %}
{% set vec2_t = "I64Vec2" %}
Expand All @@ -114,6 +121,7 @@
{% elif scalar_t == "u64" %}
{% set is_signed = false %}
{% set is_float = false %}
{% set unsigned_scalar_t = "u64" %}
{% set self_t = "U64Vec" ~ dim %}
{% set opposite_signedness_t = "I64Vec" ~ dim %}
{% set vec2_t = "U64Vec2" %}
Expand Down Expand Up @@ -2215,6 +2223,61 @@ impl {{ self_t }} {
{% endif %}
{% endif %}

{% if not is_float %}

/// Computes the [manhattan distance] between two points.
///
/// # Overflow
/// This method may overflow if the result is greater than [`{{ unsigned_scalar_t }}::MAX`].
///
/// See also [`checked_manhattan_distance`][{{ self_t }}::checked_manhattan_distance].
///
/// [manhattan distance]: https://en.wikipedia.org/wiki/Taxicab_geometry
#[inline]
#[must_use]
pub fn manhattan_distance(self, other: Self) -> {{ unsigned_scalar_t }} {
{% for c in components %}
{% if not loop.first %} + {% endif %}
self.{{c}}.abs_diff(other.{{c}})
{% endfor %}
}

/// Computes the [manhattan distance] between two points.
///
/// This will returns [`None`] if the result is greater than [`{{ unsigned_scalar_t }}::MAX`].
///
/// [manhattan distance]: https://en.wikipedia.org/wiki/Taxicab_geometry
#[inline]
#[must_use]
pub fn checked_manhattan_distance(self, other: Self) -> Option<{{ unsigned_scalar_t }}> {
{% for c in components %}
{%- if loop.first -%}
let d = self.{{c}}.abs_diff(other.{{c}});
{%- elif loop.last -%}
d.checked_add(self.{{c}}.abs_diff(other.{{c}}))
{%- else -%}
let d = d.checked_add(self.{{c}}.abs_diff(other.{{c}}))?;
{%- endif -%}
{% endfor %}
}

/// Computes the [chebyshev distance] between two points.
///
/// [chebyshev distance]: https://en.wikipedia.org/wiki/Chebyshev_distance
#[inline]
#[must_use]
pub fn chebyshev_distance(self, other: Self) -> {{ unsigned_scalar_t }} {
// Note: the compiler will eventually optimize out the loop
[
{% for c in components %}
self.{{c}}.abs_diff(other.{{c}}),
{% endfor %}
].into_iter().max().unwrap()
}

{% endif %}


{% if is_signed and dim == 2 %}
/// Returns a vector that is equal to `self` rotated by 90 degrees.
#[inline]
Expand Down
39 changes: 39 additions & 0 deletions src/i16/i16vec2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,45 @@ impl I16Vec2 {
Self::new(self.x.rem_euclid(rhs.x), self.y.rem_euclid(rhs.y))
}

/// Computes the [manhattan distance] between two points.
///
/// # Overflow
/// This method may overflow if the result is greater than [`u16::MAX`].
///
/// See also [`checked_manhattan_distance`][I16Vec2::checked_manhattan_distance].
///
/// [manhattan distance]: https://en.wikipedia.org/wiki/Taxicab_geometry
#[inline]
#[must_use]
pub fn manhattan_distance(self, other: Self) -> u16 {
self.x.abs_diff(other.x) + self.y.abs_diff(other.y)
}

/// Computes the [manhattan distance] between two points.
///
/// This will returns [`None`] if the result is greater than [`u16::MAX`].
///
/// [manhattan distance]: https://en.wikipedia.org/wiki/Taxicab_geometry
#[inline]
#[must_use]
pub fn checked_manhattan_distance(self, other: Self) -> Option<u16> {
let d = self.x.abs_diff(other.x);
d.checked_add(self.y.abs_diff(other.y))
}

/// Computes the [chebyshev distance] between two points.
///
/// [chebyshev distance]: https://en.wikipedia.org/wiki/Chebyshev_distance
#[inline]
#[must_use]
pub fn chebyshev_distance(self, other: Self) -> u16 {
// Note: the compiler will eventually optimize out the loop
[self.x.abs_diff(other.x), self.y.abs_diff(other.y)]
.into_iter()
.max()
.unwrap()
}

/// Returns a vector that is equal to `self` rotated by 90 degrees.
#[inline]
#[must_use]
Expand Down
44 changes: 44 additions & 0 deletions src/i16/i16vec3.rs
Original file line number Diff line number Diff line change
Expand Up @@ -441,6 +441,50 @@ impl I16Vec3 {
)
}

/// Computes the [manhattan distance] between two points.
///
/// # Overflow
/// This method may overflow if the result is greater than [`u16::MAX`].
///
/// See also [`checked_manhattan_distance`][I16Vec3::checked_manhattan_distance].
///
/// [manhattan distance]: https://en.wikipedia.org/wiki/Taxicab_geometry
#[inline]
#[must_use]
pub fn manhattan_distance(self, other: Self) -> u16 {
self.x.abs_diff(other.x) + self.y.abs_diff(other.y) + self.z.abs_diff(other.z)
}

/// Computes the [manhattan distance] between two points.
///
/// This will returns [`None`] if the result is greater than [`u16::MAX`].
///
/// [manhattan distance]: https://en.wikipedia.org/wiki/Taxicab_geometry
#[inline]
#[must_use]
pub fn checked_manhattan_distance(self, other: Self) -> Option<u16> {
let d = self.x.abs_diff(other.x);
let d = d.checked_add(self.y.abs_diff(other.y))?;
d.checked_add(self.z.abs_diff(other.z))
}

/// Computes the [chebyshev distance] between two points.
///
/// [chebyshev distance]: https://en.wikipedia.org/wiki/Chebyshev_distance
#[inline]
#[must_use]
pub fn chebyshev_distance(self, other: Self) -> u16 {
// Note: the compiler will eventually optimize out the loop
[
self.x.abs_diff(other.x),
self.y.abs_diff(other.y),
self.z.abs_diff(other.z),
]
.into_iter()
.max()
.unwrap()
}

/// Casts all elements of `self` to `f32`.
#[inline]
#[must_use]
Expand Down
49 changes: 49 additions & 0 deletions src/i16/i16vec4.rs
Original file line number Diff line number Diff line change
Expand Up @@ -473,6 +473,55 @@ impl I16Vec4 {
)
}

/// Computes the [manhattan distance] between two points.
///
/// # Overflow
/// This method may overflow if the result is greater than [`u16::MAX`].
///
/// See also [`checked_manhattan_distance`][I16Vec4::checked_manhattan_distance].
///
/// [manhattan distance]: https://en.wikipedia.org/wiki/Taxicab_geometry
#[inline]
#[must_use]
pub fn manhattan_distance(self, other: Self) -> u16 {
self.x.abs_diff(other.x)
+ self.y.abs_diff(other.y)
+ self.z.abs_diff(other.z)
+ self.w.abs_diff(other.w)
}

/// Computes the [manhattan distance] between two points.
///
/// This will returns [`None`] if the result is greater than [`u16::MAX`].
///
/// [manhattan distance]: https://en.wikipedia.org/wiki/Taxicab_geometry
#[inline]
#[must_use]
pub fn checked_manhattan_distance(self, other: Self) -> Option<u16> {
let d = self.x.abs_diff(other.x);
let d = d.checked_add(self.y.abs_diff(other.y))?;
let d = d.checked_add(self.z.abs_diff(other.z))?;
d.checked_add(self.w.abs_diff(other.w))
}

/// Computes the [chebyshev distance] between two points.
///
/// [chebyshev distance]: https://en.wikipedia.org/wiki/Chebyshev_distance
#[inline]
#[must_use]
pub fn chebyshev_distance(self, other: Self) -> u16 {
// Note: the compiler will eventually optimize out the loop
[
self.x.abs_diff(other.x),
self.y.abs_diff(other.y),
self.z.abs_diff(other.z),
self.w.abs_diff(other.w),
]
.into_iter()
.max()
.unwrap()
}

/// Casts all elements of `self` to `f32`.
#[inline]
#[must_use]
Expand Down
39 changes: 39 additions & 0 deletions src/i32/ivec2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,45 @@ impl IVec2 {
Self::new(self.x.rem_euclid(rhs.x), self.y.rem_euclid(rhs.y))
}

/// Computes the [manhattan distance] between two points.
///
/// # Overflow
/// This method may overflow if the result is greater than [`u32::MAX`].
///
/// See also [`checked_manhattan_distance`][IVec2::checked_manhattan_distance].
///
/// [manhattan distance]: https://en.wikipedia.org/wiki/Taxicab_geometry
#[inline]
#[must_use]
pub fn manhattan_distance(self, other: Self) -> u32 {
self.x.abs_diff(other.x) + self.y.abs_diff(other.y)
}

/// Computes the [manhattan distance] between two points.
///
/// This will returns [`None`] if the result is greater than [`u32::MAX`].
///
/// [manhattan distance]: https://en.wikipedia.org/wiki/Taxicab_geometry
#[inline]
#[must_use]
pub fn checked_manhattan_distance(self, other: Self) -> Option<u32> {
let d = self.x.abs_diff(other.x);
d.checked_add(self.y.abs_diff(other.y))
}

/// Computes the [chebyshev distance] between two points.
///
/// [chebyshev distance]: https://en.wikipedia.org/wiki/Chebyshev_distance
#[inline]
#[must_use]
pub fn chebyshev_distance(self, other: Self) -> u32 {
// Note: the compiler will eventually optimize out the loop
[self.x.abs_diff(other.x), self.y.abs_diff(other.y)]
.into_iter()
.max()
.unwrap()
}

/// Returns a vector that is equal to `self` rotated by 90 degrees.
#[inline]
#[must_use]
Expand Down
44 changes: 44 additions & 0 deletions src/i32/ivec3.rs
Original file line number Diff line number Diff line change
Expand Up @@ -441,6 +441,50 @@ impl IVec3 {
)
}

/// Computes the [manhattan distance] between two points.
///
/// # Overflow
/// This method may overflow if the result is greater than [`u32::MAX`].
///
/// See also [`checked_manhattan_distance`][IVec3::checked_manhattan_distance].
///
/// [manhattan distance]: https://en.wikipedia.org/wiki/Taxicab_geometry
#[inline]
#[must_use]
pub fn manhattan_distance(self, other: Self) -> u32 {
self.x.abs_diff(other.x) + self.y.abs_diff(other.y) + self.z.abs_diff(other.z)
}

/// Computes the [manhattan distance] between two points.
///
/// This will returns [`None`] if the result is greater than [`u32::MAX`].
///
/// [manhattan distance]: https://en.wikipedia.org/wiki/Taxicab_geometry
#[inline]
#[must_use]
pub fn checked_manhattan_distance(self, other: Self) -> Option<u32> {
let d = self.x.abs_diff(other.x);
let d = d.checked_add(self.y.abs_diff(other.y))?;
d.checked_add(self.z.abs_diff(other.z))
}

/// Computes the [chebyshev distance] between two points.
///
/// [chebyshev distance]: https://en.wikipedia.org/wiki/Chebyshev_distance
#[inline]
#[must_use]
pub fn chebyshev_distance(self, other: Self) -> u32 {
// Note: the compiler will eventually optimize out the loop
[
self.x.abs_diff(other.x),
self.y.abs_diff(other.y),
self.z.abs_diff(other.z),
]
.into_iter()
.max()
.unwrap()
}

/// Casts all elements of `self` to `f32`.
#[inline]
#[must_use]
Expand Down
Loading

0 comments on commit e8a53c6

Please sign in to comment.