### 3 releases

0.1.2 | Nov 17, 2022 |
---|---|

0.1.1 | Nov 17, 2022 |

0.1.0 | Nov 17, 2022 |

#**611** in Math

**MIT**license

17KB

340 lines

# hmmmm 🤔

Yet another aptly-named Hidden-Markov Model library for Rust.

**Important Note:** This crate depends on the feature `generic_const_exprs`

. For now, usage of this crate is limited to use with the `nightly`

Rust channel.

`generic_const_exprs`

`nightly`

## Usage

### Installation

`cargo`` add hmmmm`` --`features derive

### States + Observations

To create a

, we first need two enums corresponding to the
states and observations of the hidden Markov model. This can be done
by using the `Hmm`

and `#``[``derive``(``State``)``]`

proc macros in the `#``[``derive``(``Observation``)``]`

crate:`hmmmm_derive`

`#``[``repr``(``u8``)``]`
`#``[``derive``(``State``)``]`
`enum` `Condition` `{`
Healthy`,`
`}`
`#``[``repr``(``u8``)``]`
`#``[``derive``(``Observation``)``]`
`enum` `Feeling` `{`
Normal`,`
Cold`,`
Dizzy`,`
`}`

Note that the attribute

is required for both enums
definitions, as we need to have the enums be: `repr``(``u8``)`**a)** as small as
possible for efficient computation and **b)** easily cast between
itself and

/ `u8`

. The derive macros will throw a compilation
error if this attribute is not present on the enum.`usize`

### Probabilities

A

requires 3 different probability matrices:`Hmm`

- Initial (state) probabilities -
`[``f64``;`N`]` - Transition probabilities -
`[``[``f64``;`N`]``;`N`]` - Emission probabilities -
`[``[``f64``;`M`]``;`N`]`

...where

is the number of possible states and `N`

is the
number of possible observations.`O`

These can be:

- Manualy declared, e.g.:

`let` pr_initial`:` `[``f64``;` `2``]` `=` `[``0.``6``,` `0.``4``]``;` `//` [Healthy, Fever]

- Declared via the methods in

, e.g.:`hmmmm`utils`::`

`let` pr_initial`:` `[``f64``;` `2``]` `=` `pr_i``(``|``cond``|` `match` cond `{`
`Condition``::`Healthy `=>` `0.``6``,`
`Condition``::`Fever `=>` `0.``4``,`
`}``)``;`

### Constructing the HMM

Now that we have our states, observations, and corresponding
probability matrices we can construct our

:`Hmm`

`let` pr_initial`:` `[``f64``;` `2``]` `=` `[``0.``6``,` `0.``4``]``;`
`let` pr_transition`:` `[``[``f64``;` `2``]``;` `2``]` `=` `[`
`[``0.``7``,` `0.``3``]``,`
`[``0.``4``,` `0.``6``]`
`]``;`
`let` pr_emission`:` `[``[``f64``;` `3``]``;` `2``]` `=` `[`
`[``0.``5``,` `0.``4``,` `0.``1``]``,`
`[``0.``1``,` `0.``3``,` `0.``6``]`
`]`
`let` hmm `=` `Hmm``::``<`Condition, Feeling`>``::`new`(`
pr_initial`,`
pr_transition`,`
pr_emission
`)``;`

## Algorithms

### Viterbi

The Viterbi algorithm obtains the maximum a posteriori estimate (MAP) of the most likely sequence of hidden states given an input sequence of observations.

**Input:** the sequence of observations - `&``Vec``<`O`>`

**Output:** a tuple containing the log (base 2) probability of the MAP hidden state sequence and the corresponding hidden state sequence - `(``f64``,` `Vec``<`S`>``)`

**Example:**

`/*` Using the HMM `hmm` from the previous section `*/`
`let` signal `=` `vec!``[``Feeling``::`Normal`,` `Feeling``::`Cold`,` `Feeling``::`Dizzy`]``;`
`let` `(`pr`,` sequence`)` `=` hmm`.``map_estimate``::``<`Viterbi`>``(``&`signal`)``;`
`/*`
pr = −6.04739805022
sequence = [Condition::Healthy, Condition::Healthy, Condition::Fever]
`*/`

#### Dependencies

~385–680KB

~13K SLoC