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, qare probabilities, then-log p ⊕ -log q = -log(p + q) - If
p, qare 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) ≈ xfor smallx
§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
- Core Concepts - Log Semiring for mathematical background
ProbabilityWeightfor simple probability computationTropicalWeightfor optimization problems
Implementations§
Trait Implementations§
Source§impl<'de> Deserialize<'de> for LogWeight
impl<'de> Deserialize<'de> for LogWeight
Source§fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
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 DivisibleSemiring for LogWeight
impl DivisibleSemiring for LogWeight
Source§impl Ord for LogWeight
impl Ord for LogWeight
Source§impl PartialOrd for LogWeight
impl PartialOrd for LogWeight
Source§impl Semiring for LogWeight
impl Semiring for LogWeight
Source§fn properties() -> SemiringProperties
fn properties() -> SemiringProperties
Semiring properties
Source§fn approx_eq(&self, other: &Self, epsilon: f64) -> bool
fn approx_eq(&self, other: &Self, epsilon: f64) -> bool
Approximate equality for floating-point weights
Source§fn plus_assign(&mut self, other: &Self)
fn plus_assign(&mut self, other: &Self)
In-place semiring addition
Source§fn times_assign(&mut self, other: &Self)
fn times_assign(&mut self, other: &Self)
In-place semiring multiplication
impl Copy for LogWeight
impl Eq for LogWeight
impl StructuralPartialEq for LogWeight
Auto Trait Implementations§
impl Freeze for LogWeight
impl RefUnwindSafe for LogWeight
impl Send for LogWeight
impl Sync for LogWeight
impl Unpin for LogWeight
impl UnwindSafe for LogWeight
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
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 moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
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