use crate::norm::{DegenerateNormed, IndefiniteNormed, Normed};
use crate::scalar::Float;
use core::fmt::Debug;
use core::hash::Hash;
use num_traits::Float as _;
use num_traits::One;
#[derive(Clone, Copy)]
#[repr(transparent)]
pub struct Unit<T: Normed> {
inner: T,
}
impl<T: Normed> Unit<T> {
#[inline]
pub fn new_unchecked(inner: T) -> Self {
Self { inner }
}
#[inline]
pub fn into_inner(self) -> T {
self.inner
}
#[inline]
pub fn as_inner(&self) -> &T {
&self.inner
}
}
impl<T: Normed> Unit<T> {
#[inline]
pub fn try_new(inner: T) -> Option<Self>
where
T: Sized,
{
inner
.try_normalize()
.map(|normalized| Self { inner: normalized })
}
#[inline]
pub fn new_normalize(inner: T) -> Self
where
T: Sized,
{
Self::try_new(inner).expect("cannot normalize zero element")
}
}
impl<T: Normed> AsRef<T> for Unit<T> {
#[inline]
fn as_ref(&self) -> &T {
&self.inner
}
}
impl<T: Normed + Debug> Debug for Unit<T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_tuple("Unit").field(&self.inner).finish()
}
}
impl<T: Normed + PartialEq> PartialEq for Unit<T> {
fn eq(&self, other: &Self) -> bool {
self.inner == other.inner
}
}
impl<T: Normed + Eq> Eq for Unit<T> {}
impl<T: Normed + Hash> Hash for Unit<T> {
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
self.inner.hash(state);
}
}
#[cfg(feature = "serde")]
impl<T: Normed + serde::Serialize> serde::Serialize for Unit<T> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
self.inner.serialize(serializer)
}
}
#[cfg(feature = "serde")]
impl<'de, T: Normed + serde::Deserialize<'de>> serde::Deserialize<'de> for Unit<T> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let inner = T::deserialize(deserializer)?;
Ok(Self { inner })
}
}
impl<T: Normed + Clone> Normed for Unit<T> {
type Scalar = T::Scalar;
#[inline]
fn norm_squared(&self) -> Self::Scalar {
Self::Scalar::one()
}
#[inline]
fn norm(&self) -> Self::Scalar {
Self::Scalar::one()
}
#[inline]
fn try_normalize(&self) -> Option<Self> {
Some(self.clone())
}
#[inline]
fn normalize(&self) -> Self {
self.clone()
}
#[inline]
fn scale(&self, factor: Self::Scalar) -> Self {
let scaled = self.inner.scale(factor);
Self::try_new(scaled).unwrap_or_else(|| self.clone())
}
}
#[derive(Clone, Copy)]
#[repr(transparent)]
pub struct Bulk<T: DegenerateNormed> {
inner: T,
}
impl<T: DegenerateNormed> Bulk<T>
where
T::Scalar: Float,
{
#[inline]
pub fn try_new(inner: T) -> Option<Self>
where
T: Sized,
{
let n = inner.bulk_norm();
if n < T::Scalar::epsilon() {
return None;
}
Some(Self {
inner: inner.scale(<T::Scalar as One>::one() / n),
})
}
#[inline]
pub fn new_normalize(inner: T) -> Self
where
T: Sized,
{
Self::try_new(inner).expect("cannot bulk-normalize zero element")
}
}
impl<T: DegenerateNormed> Bulk<T> {
#[inline]
pub fn new_unchecked(inner: T) -> Self {
Self { inner }
}
#[inline]
pub fn into_inner(self) -> T {
self.inner
}
#[inline]
pub fn as_inner(&self) -> &T {
&self.inner
}
}
impl<T: DegenerateNormed> AsRef<T> for Bulk<T> {
#[inline]
fn as_ref(&self) -> &T {
&self.inner
}
}
impl<T: DegenerateNormed + Debug> Debug for Bulk<T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_tuple("Bulk").field(&self.inner).finish()
}
}
impl<T: DegenerateNormed + PartialEq> PartialEq for Bulk<T> {
fn eq(&self, other: &Self) -> bool {
self.inner == other.inner
}
}
impl<T: DegenerateNormed + Eq> Eq for Bulk<T> {}
impl<T: DegenerateNormed + Hash> Hash for Bulk<T> {
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
self.inner.hash(state);
}
}
#[cfg(feature = "serde")]
impl<T: DegenerateNormed + serde::Serialize> serde::Serialize for Bulk<T> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
self.inner.serialize(serializer)
}
}
#[cfg(feature = "serde")]
impl<'de, T: DegenerateNormed + serde::Deserialize<'de>> serde::Deserialize<'de> for Bulk<T> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let inner = T::deserialize(deserializer)?;
Ok(Self { inner })
}
}
impl<T: DegenerateNormed + Clone> Normed for Bulk<T> {
type Scalar = T::Scalar;
#[inline]
fn norm_squared(&self) -> Self::Scalar {
self.inner.norm_squared()
}
#[inline]
fn norm(&self) -> Self::Scalar {
self.inner.norm()
}
#[inline]
fn try_normalize(&self) -> Option<Self> {
self.inner.try_normalize().map(|n| Self { inner: n })
}
#[inline]
fn normalize(&self) -> Self {
Self {
inner: self.inner.normalize(),
}
}
#[inline]
fn scale(&self, factor: Self::Scalar) -> Self {
let scaled = self.inner.scale(factor);
Self::try_new(scaled).unwrap_or_else(|| self.clone())
}
}
impl<T: DegenerateNormed + Clone> DegenerateNormed for Bulk<T> {
#[inline]
fn bulk_norm_squared(&self) -> Self::Scalar {
Self::Scalar::one()
}
#[inline]
fn bulk_norm(&self) -> Self::Scalar {
Self::Scalar::one()
}
#[inline]
fn weight_norm_squared(&self) -> Self::Scalar {
self.inner.weight_norm_squared()
}
#[inline]
fn weight_norm(&self) -> Self::Scalar {
self.inner.weight_norm()
}
#[inline]
fn try_unitize(&self) -> Option<Self> {
self.inner.try_unitize().and_then(Self::try_new)
}
}
#[derive(Clone, Copy)]
#[repr(transparent)]
pub struct Unitized<T: DegenerateNormed> {
inner: T,
}
impl<T: DegenerateNormed> Unitized<T> {
#[inline]
pub fn try_new(inner: T) -> Option<Self>
where
T: Sized,
{
inner.try_unitize().map(|u| Self { inner: u })
}
#[inline]
pub fn new_normalize(inner: T) -> Self
where
T: Sized,
{
Self::try_new(inner).expect("cannot unitize element with zero weight (ideal element)")
}
}
impl<T: DegenerateNormed> Unitized<T> {
#[inline]
pub fn new_unchecked(inner: T) -> Self {
Self { inner }
}
#[inline]
pub fn into_inner(self) -> T {
self.inner
}
#[inline]
pub fn as_inner(&self) -> &T {
&self.inner
}
}
impl<T: DegenerateNormed> AsRef<T> for Unitized<T> {
#[inline]
fn as_ref(&self) -> &T {
&self.inner
}
}
impl<T: DegenerateNormed + Debug> Debug for Unitized<T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_tuple("Unitized").field(&self.inner).finish()
}
}
impl<T: DegenerateNormed + PartialEq> PartialEq for Unitized<T> {
fn eq(&self, other: &Self) -> bool {
self.inner == other.inner
}
}
impl<T: DegenerateNormed + Eq> Eq for Unitized<T> {}
impl<T: DegenerateNormed + Hash> Hash for Unitized<T> {
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
self.inner.hash(state);
}
}
#[cfg(feature = "serde")]
impl<T: DegenerateNormed + serde::Serialize> serde::Serialize for Unitized<T> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
self.inner.serialize(serializer)
}
}
#[cfg(feature = "serde")]
impl<'de, T: DegenerateNormed + serde::Deserialize<'de>> serde::Deserialize<'de> for Unitized<T> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let inner = T::deserialize(deserializer)?;
Ok(Self { inner })
}
}
#[derive(Clone, Copy)]
#[repr(transparent)]
pub struct Ideal<T: DegenerateNormed> {
inner: T,
}
impl<T: DegenerateNormed> Ideal<T> {
#[inline]
pub fn try_new(inner: T) -> Option<Self>
where
T: Sized,
{
if inner.weight_norm() < T::Scalar::epsilon() {
Some(Self { inner })
} else {
None }
}
}
impl<T: DegenerateNormed> Ideal<T> {
#[inline]
pub fn new_unchecked(inner: T) -> Self {
Self { inner }
}
#[inline]
pub fn into_inner(self) -> T {
self.inner
}
#[inline]
pub fn as_inner(&self) -> &T {
&self.inner
}
}
impl<T: DegenerateNormed> AsRef<T> for Ideal<T> {
#[inline]
fn as_ref(&self) -> &T {
&self.inner
}
}
impl<T: DegenerateNormed + Debug> Debug for Ideal<T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_tuple("Ideal").field(&self.inner).finish()
}
}
impl<T: DegenerateNormed + PartialEq> PartialEq for Ideal<T> {
fn eq(&self, other: &Self) -> bool {
self.inner == other.inner
}
}
impl<T: DegenerateNormed + Eq> Eq for Ideal<T> {}
impl<T: DegenerateNormed + Hash> Hash for Ideal<T> {
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
self.inner.hash(state);
}
}
#[cfg(feature = "serde")]
impl<T: DegenerateNormed + serde::Serialize> serde::Serialize for Ideal<T> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
self.inner.serialize(serializer)
}
}
#[cfg(feature = "serde")]
impl<'de, T: DegenerateNormed + serde::Deserialize<'de>> serde::Deserialize<'de> for Ideal<T> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let inner = T::deserialize(deserializer)?;
Ok(Self { inner })
}
}
#[derive(Clone, Copy)]
#[repr(transparent)]
pub struct Proper<T: IndefiniteNormed> {
inner: T,
}
impl<T: IndefiniteNormed> Proper<T> {
#[inline]
pub fn try_new(inner: T) -> Option<Self>
where
T: Sized,
{
if inner.is_timelike() {
Some(Self {
inner: inner.normalize(),
})
} else {
None }
}
}
impl<T: IndefiniteNormed> Proper<T> {
#[inline]
pub fn new_unchecked(inner: T) -> Self {
Self { inner }
}
#[inline]
pub fn into_inner(self) -> T {
self.inner
}
#[inline]
pub fn as_inner(&self) -> &T {
&self.inner
}
}
impl<T: IndefiniteNormed> AsRef<T> for Proper<T> {
#[inline]
fn as_ref(&self) -> &T {
&self.inner
}
}
impl<T: IndefiniteNormed + Debug> Debug for Proper<T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_tuple("Proper").field(&self.inner).finish()
}
}
impl<T: IndefiniteNormed + PartialEq> PartialEq for Proper<T> {
fn eq(&self, other: &Self) -> bool {
self.inner == other.inner
}
}
impl<T: IndefiniteNormed + Eq> Eq for Proper<T> {}
impl<T: IndefiniteNormed + Hash> Hash for Proper<T> {
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
self.inner.hash(state);
}
}
#[cfg(feature = "serde")]
impl<T: IndefiniteNormed + serde::Serialize> serde::Serialize for Proper<T> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
self.inner.serialize(serializer)
}
}
#[cfg(feature = "serde")]
impl<'de, T: IndefiniteNormed + serde::Deserialize<'de>> serde::Deserialize<'de> for Proper<T> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let inner = T::deserialize(deserializer)?;
Ok(Self { inner })
}
}
#[derive(Clone, Copy)]
#[repr(transparent)]
pub struct Spacelike<T: IndefiniteNormed> {
inner: T,
}
impl<T: IndefiniteNormed> Spacelike<T> {
#[inline]
pub fn try_new(inner: T) -> Option<Self>
where
T: Sized,
{
if inner.is_spacelike() {
let mag = inner.norm(); if mag > T::Scalar::epsilon() {
Some(Self {
inner: inner.scale(<T::Scalar as One>::one() / mag),
})
} else {
None
}
} else {
None }
}
}
impl<T: IndefiniteNormed> Spacelike<T> {
#[inline]
pub fn new_unchecked(inner: T) -> Self {
Self { inner }
}
#[inline]
pub fn into_inner(self) -> T {
self.inner
}
#[inline]
pub fn as_inner(&self) -> &T {
&self.inner
}
}
impl<T: IndefiniteNormed> AsRef<T> for Spacelike<T> {
#[inline]
fn as_ref(&self) -> &T {
&self.inner
}
}
impl<T: IndefiniteNormed + Debug> Debug for Spacelike<T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_tuple("Spacelike").field(&self.inner).finish()
}
}
impl<T: IndefiniteNormed + PartialEq> PartialEq for Spacelike<T> {
fn eq(&self, other: &Self) -> bool {
self.inner == other.inner
}
}
impl<T: IndefiniteNormed + Eq> Eq for Spacelike<T> {}
impl<T: IndefiniteNormed + Hash> Hash for Spacelike<T> {
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
self.inner.hash(state);
}
}
#[cfg(feature = "serde")]
impl<T: IndefiniteNormed + serde::Serialize> serde::Serialize for Spacelike<T> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
self.inner.serialize(serializer)
}
}
#[cfg(feature = "serde")]
impl<'de, T: IndefiniteNormed + serde::Deserialize<'de>> serde::Deserialize<'de> for Spacelike<T> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let inner = T::deserialize(deserializer)?;
Ok(Self { inner })
}
}
#[derive(Clone, Copy)]
#[repr(transparent)]
pub struct Null<T: IndefiniteNormed> {
inner: T,
}
impl<T: IndefiniteNormed> Null<T> {
#[inline]
pub fn try_new(inner: T) -> Option<Self>
where
T: Sized,
{
if inner.is_lightlike() {
Some(Self { inner })
} else {
None }
}
}
impl<T: IndefiniteNormed> Null<T> {
#[inline]
pub fn new_unchecked(inner: T) -> Self {
Self { inner }
}
#[inline]
pub fn into_inner(self) -> T {
self.inner
}
#[inline]
pub fn as_inner(&self) -> &T {
&self.inner
}
}
impl<T: IndefiniteNormed> AsRef<T> for Null<T> {
#[inline]
fn as_ref(&self) -> &T {
&self.inner
}
}
impl<T: IndefiniteNormed + Debug> Debug for Null<T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_tuple("Null").field(&self.inner).finish()
}
}
impl<T: IndefiniteNormed + PartialEq> PartialEq for Null<T> {
fn eq(&self, other: &Self) -> bool {
self.inner == other.inner
}
}
impl<T: IndefiniteNormed + Eq> Eq for Null<T> {}
impl<T: IndefiniteNormed + Hash> Hash for Null<T> {
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
self.inner.hash(state);
}
}
#[cfg(feature = "serde")]
impl<T: IndefiniteNormed + serde::Serialize> serde::Serialize for Null<T> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
self.inner.serialize(serializer)
}
}
#[cfg(feature = "serde")]
impl<'de, T: IndefiniteNormed + serde::Deserialize<'de>> serde::Deserialize<'de> for Null<T> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let inner = T::deserialize(deserializer)?;
Ok(Self { inner })
}
}
#[cfg(any(test, feature = "proptest-support"))]
mod arbitrary_impl {
use super::*;
use proptest::prelude::*;
use proptest::strategy::BoxedStrategy;
impl<T> Arbitrary for Unit<T>
where
T: Normed + Arbitrary + Debug + 'static,
{
type Parameters = ();
type Strategy = BoxedStrategy<Self>;
fn arbitrary_with(_: Self::Parameters) -> Self::Strategy {
any::<T>()
.prop_filter_map("normalizable", |t| Unit::try_new(t))
.boxed()
}
}
impl<T> Arbitrary for Bulk<T>
where
T: DegenerateNormed + Arbitrary + Debug + 'static,
T::Scalar: Float,
{
type Parameters = ();
type Strategy = BoxedStrategy<Self>;
fn arbitrary_with(_: Self::Parameters) -> Self::Strategy {
any::<T>()
.prop_filter_map("bulk-normalizable", |t| Bulk::try_new(t))
.boxed()
}
}
impl<T> Arbitrary for Unitized<T>
where
T: DegenerateNormed + Arbitrary + Debug + 'static,
{
type Parameters = ();
type Strategy = BoxedStrategy<Self>;
fn arbitrary_with(_: Self::Parameters) -> Self::Strategy {
any::<T>()
.prop_filter_map("unitizable (weight > 0)", |t| Unitized::try_new(t))
.boxed()
}
}
impl<T> Arbitrary for Ideal<T>
where
T: DegenerateNormed + Arbitrary + Debug + 'static,
{
type Parameters = ();
type Strategy = BoxedStrategy<Self>;
fn arbitrary_with(_: Self::Parameters) -> Self::Strategy {
any::<T>()
.prop_filter_map("ideal (weight ≈ 0)", |t| Ideal::try_new(t))
.boxed()
}
}
impl<T> Arbitrary for Proper<T>
where
T: IndefiniteNormed + Arbitrary + Debug + 'static,
{
type Parameters = ();
type Strategy = BoxedStrategy<Self>;
fn arbitrary_with(_: Self::Parameters) -> Self::Strategy {
any::<T>()
.prop_filter_map("timelike", |t| Proper::try_new(t))
.boxed()
}
}
impl<T> Arbitrary for Spacelike<T>
where
T: IndefiniteNormed + Arbitrary + Debug + 'static,
{
type Parameters = ();
type Strategy = BoxedStrategy<Self>;
fn arbitrary_with(_: Self::Parameters) -> Self::Strategy {
any::<T>()
.prop_filter_map("spacelike", |t| Spacelike::try_new(t))
.boxed()
}
}
impl<T> Arbitrary for Null<T>
where
T: IndefiniteNormed + Arbitrary + Debug + 'static,
{
type Parameters = ();
type Strategy = BoxedStrategy<Self>;
fn arbitrary_with(_: Self::Parameters) -> Self::Strategy {
any::<T>()
.prop_filter_map("lightlike (norm² ≈ 0)", |t| Null::try_new(t))
.boxed()
}
}
}