Skip to main content

LogWeight

Struct LogWeight 

Source
pub struct LogWeight(/* private fields */);
Expand description

Log weight for numerically stable probability computation

The log semiring addresses numerical stability issues inherent in probability computation by working in the logarithmic domain. This enables handling of very small probabilities (e.g., 10^-100) that would underflow in linear probability space, while maintaining mathematically equivalent probabilistic semantics.

§Mathematical Semantics

  • Value Range: Real numbers ℝ plus positive infinity (+∞)
  • Addition (⊕): -log(e^(-a) + e^(-b)) (log-sum-exp) - combines probabilities
  • Multiplication (⊗): a + b (addition in log space) - multiplies probabilities
  • Zero (0̄): +∞ - represents impossible event (probability 0)
  • One (1̄): 0.0 - represents certain event (probability 1)

§Relationship to Probability Semiring

The log semiring is related to the probability semiring through logarithmic transformation:

  • If p, q are probabilities, then -log p ⊕ -log q = -log(p + q)
  • If p, q are probabilities, then -log p ⊗ -log q = -log(p × q)

This preserves probabilistic semantics while providing numerical stability.

§Use Cases

§Large-Vocabulary Speech Recognition

use arcweight::prelude::*;

// Acoustic model probabilities (very small values)
let acoustic_prob = LogWeight::from_probability(1e-50);  // Converts to log space
let language_prob = LogWeight::from_probability(0.001);

// Combine probabilities safely
let combined = acoustic_prob.times(&language_prob);  // Multiplication in log space

// Convert back to probability if needed
let final_prob = combined.to_probability();
println!("Final probability: {:.2e}", final_prob);  // ~1e-53

§Machine Translation with Large Models

use arcweight::prelude::*;

// Translation model scores (often very small probabilities)
let phrase_prob = LogWeight::from_probability(1e-20);
let alignment_prob = LogWeight::from_probability(1e-15);
let reordering_prob = LogWeight::from_probability(0.1);

// Combine all model scores
let translation_score = phrase_prob
    .times(&alignment_prob)
    .times(&reordering_prob);

// Alternative translations (add probabilities)
let alternative1 = LogWeight::from_probability(1e-35);
let alternative2 = LogWeight::from_probability(2e-35);
let combined_alternatives = alternative1.plus(&alternative2);  // LogSumExp

§Neural Language Model Integration

use arcweight::prelude::*;

// Softmax probabilities from neural networks
let word_probs = vec![
    LogWeight::from_probability(0.4),   // Most likely word
    LogWeight::from_probability(0.3),   // Second choice
    LogWeight::from_probability(0.2),   // Third choice
    LogWeight::from_probability(0.1),   // Least likely
];

// Compute probability of any of these words
let any_word_prob = word_probs.into_iter()
    .fold(LogWeight::zero(), |acc, prob| acc.plus(&prob));

// Should be close to 1.0 (sum of probabilities)
assert!((any_word_prob.to_probability() - 1.0).abs() < 1e-10);

§Sequence Analysis in Bioinformatics

use arcweight::prelude::*;

// DNA sequence alignment with very long sequences
let base_prob = LogWeight::from_probability(0.25);  // Each base equally likely
let sequence_length = 1000;

// Probability of specific sequence (would underflow in linear space)
let mut sequence_prob = LogWeight::one();
for _ in 0..sequence_length {
    sequence_prob = sequence_prob.times(&base_prob);
}

// Convert to scientific notation for display
println!("Sequence probability: {:.2e}", sequence_prob.to_probability());

§Working with FSTs

use arcweight::prelude::*;

let log_p1 = LogWeight::from_probability(0.5);   // Convert from probability
let log_p2 = LogWeight::from_probability(0.25);  // Convert from probability

// Addition performs log-sum-exp (combines probabilities)
let sum = log_p1 + log_p2;  // -log(0.5 + 0.25) = -log(0.75)
assert!((sum.to_probability() - 0.75).abs() < 1e-6);

// Multiplication is addition in log space (multiplies probabilities)
let product = log_p1 * log_p2;  // -log(0.5 × 0.25) = -log(0.125)
assert!((product.to_probability() - 0.125).abs() < 1e-10);

// Identity elements
assert_eq!(LogWeight::zero(), LogWeight::INFINITY);  // Impossible event
assert_eq!(LogWeight::one(), LogWeight::new(0.0));   // Certain event

§Numerical Stability Implementation

The log semiring implements numerically stable log-sum-exp operation:

-log(e^(-a) + e^(-b)) = -max(a,b) - log(1 + e^(-|a-b|))

This formulation prevents overflow/underflow by:

  • Working with the larger magnitude value first
  • Computing the difference in a stable manner
  • Using the identity: log(1 + x) ≈ x for small x

§Performance Characteristics

  • Arithmetic: Addition is expensive (log-sum-exp), multiplication is O(1)
  • Memory: 8 bytes per weight (single f64)
  • Precision: Double precision for high-accuracy probability computation
  • Conversion: Efficient probability ↔ log conversions available
  • Range: Handles probabilities from ~10^-308 to 1.0

§Conversion Utilities

use arcweight::prelude::*;

// Convert from probability to log weight
let prob = 0.001;
let log_weight = LogWeight::from_probability(prob);
assert_eq!(log_weight.value(), &(-prob.ln()));

// Convert back to probability
let recovered_prob = log_weight.to_probability();
assert!((recovered_prob - prob).abs() < 1e-15);

// Handle edge cases
let zero_prob = LogWeight::from_probability(0.0);
assert!(<LogWeight as num_traits::Zero>::is_zero(&zero_prob));
assert_eq!(zero_prob.to_probability(), 0.0);

§Advanced Usage

§Normalization in Log Space

use arcweight::prelude::*;

// Normalize a probability distribution in log space
let log_probs = vec![
    LogWeight::new(1.0),  // Unnormalized log probabilities
    LogWeight::new(2.0),
    LogWeight::new(0.5),
];

// Compute log partition function (log of sum of probabilities)
let log_z = log_probs.iter()
    .fold(LogWeight::zero(), |acc, &p| acc.plus(&p));

// Normalize each probability
let normalized: Vec<_> = log_probs.iter()
    .map(|&p| p.divide(&log_z).unwrap())
    .collect();

// Verify normalization (sum should be 1.0)
let sum = normalized.iter()
    .fold(LogWeight::zero(), |acc, &p| acc.plus(&p));
assert!((sum.to_probability() - 1.0).abs() < 1e-10);

§Integration with FST Algorithms

Log weights work with all FST algorithms while providing numerical stability:

  • Shortest Path: Finds maximum probability paths
  • Forward-Backward: Stable computation of path probabilities
  • Composition: Combines probabilistic models
  • Determinization: Maintains probability distributions

§See Also

Implementations§

Source§

impl LogWeight

Source

pub const INFINITY: Self

Positive infinity (zero element)

Source

pub fn new(value: f64) -> Self

Create a new log weight

Source

pub fn from_probability(p: f64) -> Self

Convert from probability

Source

pub fn to_probability(&self) -> f64

Convert to probability

Trait Implementations§

Source§

impl Add for LogWeight

Source§

type Output = LogWeight

The resulting type after applying the + operator.
Source§

fn add(self, rhs: Self) -> Self::Output

Performs the + operation. Read more
Source§

impl Clone for LogWeight

Source§

fn clone(&self) -> LogWeight

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for LogWeight

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<'de> Deserialize<'de> for LogWeight

Source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
Source§

impl Display for LogWeight

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl DivisibleSemiring for LogWeight

Source§

fn divide(&self, other: &Self) -> Option<Self>

Division operation
Source§

impl Hash for LogWeight

Source§

fn hash<__H: Hasher>(&self, state: &mut __H)

Feeds this value into the given Hasher. Read more
1.3.0 · Source§

fn hash_slice<H>(data: &[Self], state: &mut H)
where H: Hasher, Self: Sized,

Feeds a slice of this type into the given Hasher. Read more
Source§

impl Mul for LogWeight

Source§

type Output = LogWeight

The resulting type after applying the * operator.
Source§

fn mul(self, rhs: Self) -> Self::Output

Performs the * operation. Read more
Source§

impl One for LogWeight

Source§

fn one() -> Self

Returns the multiplicative identity element of Self, 1. Read more
Source§

fn set_one(&mut self)

Sets self to the multiplicative identity element of Self, 1.
Source§

fn is_one(&self) -> bool
where Self: PartialEq,

Returns true if self is equal to the multiplicative identity. Read more
Source§

impl Ord for LogWeight

Source§

fn cmp(&self, other: &LogWeight) -> Ordering

This method returns an Ordering between self and other. Read more
1.21.0 · Source§

fn max(self, other: Self) -> Self
where Self: Sized,

Compares and returns the maximum of two values. Read more
1.21.0 · Source§

fn min(self, other: Self) -> Self
where Self: Sized,

Compares and returns the minimum of two values. Read more
1.50.0 · Source§

fn clamp(self, min: Self, max: Self) -> Self
where Self: Sized,

Restrict a value to a certain interval. Read more
Source§

impl PartialEq for LogWeight

Source§

fn eq(&self, other: &LogWeight) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl PartialOrd for LogWeight

Source§

fn partial_cmp(&self, other: &LogWeight) -> Option<Ordering>

This method returns an ordering between self and other values if one exists. Read more
1.0.0 · Source§

fn lt(&self, other: &Rhs) -> bool

Tests less than (for self and other) and is used by the < operator. Read more
1.0.0 · Source§

fn le(&self, other: &Rhs) -> bool

Tests less than or equal to (for self and other) and is used by the <= operator. Read more
1.0.0 · Source§

fn gt(&self, other: &Rhs) -> bool

Tests greater than (for self and other) and is used by the > operator. Read more
1.0.0 · Source§

fn ge(&self, other: &Rhs) -> bool

Tests greater than or equal to (for self and other) and is used by the >= operator. Read more
Source§

impl Semiring for LogWeight

Source§

type Value = f64

Type of the underlying value
Source§

fn new(value: Self::Value) -> Self

Create a new weight from a value
Source§

fn value(&self) -> &Self::Value

Get the underlying value
Source§

fn properties() -> SemiringProperties

Semiring properties
Source§

fn approx_eq(&self, other: &Self, epsilon: f64) -> bool

Approximate equality for floating-point weights
Source§

fn plus(&self, other: &Self) -> Self

Semiring addition (⊕)
Source§

fn times(&self, other: &Self) -> Self

Semiring multiplication (⊗)
Source§

fn plus_assign(&mut self, other: &Self)

In-place semiring addition
Source§

fn times_assign(&mut self, other: &Self)

In-place semiring multiplication
Source§

fn is_zero(&self) -> bool

Check if weight is zero (additive identity)
Source§

fn is_one(&self) -> bool

Check if weight is one (multiplicative identity)
Source§

impl Serialize for LogWeight

Source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where __S: Serializer,

Serialize this value into the given Serde serializer. Read more
Source§

impl Zero for LogWeight

Source§

fn zero() -> Self

Returns the additive identity element of Self, 0. Read more
Source§

fn is_zero(&self) -> bool

Returns true if self is equal to the additive identity.
Source§

fn set_zero(&mut self)

Sets self to the additive identity element of Self, 0.
Source§

impl Copy for LogWeight

Source§

impl Eq for LogWeight

Source§

impl StructuralPartialEq for LogWeight

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T> ToString for T
where T: Display + ?Sized,

Source§

fn to_string(&self) -> String

Converts the given value to a String. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> DeserializeOwned for T
where T: for<'de> Deserialize<'de>,