├── .gitattributes ├── CHANGELOG.md ├── .editorconfig ├── bower.json ├── package.json ├── test └── hidden-markov-model.js ├── LICENSE.md ├── README.md ├── .gitignore └── hidden-markov-model.js /.gitattributes: -------------------------------------------------------------------------------- 1 | # Convert line endings to LF (Line Feed) 2 | * text=auto -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | All notable changes to this project will be documented in this file. 3 | This project adheres to [Semantic Versioning](http://semver.org/). 4 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: http://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | [*] 7 | # use line feed 8 | end_of_line = lf 9 | 10 | # ensure file ends with a newline when saving 11 | insert_final_newline = true 12 | 13 | # soft tabs 14 | indent_style = space 15 | 16 | # number of columns used for each indentation level 17 | indent_size = 2 18 | 19 | # remove any whitespace characters preceding newline characters 20 | trim_trailing_whitespace = true 21 | 22 | # character set 23 | charset = utf-8 24 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hidden-markov-model", 3 | "main": "hidden-markov-model.js", 4 | "version": "0.0.1", 5 | "homepage": "https://github.com/miguelmota/hidden-markov-model", 6 | "authors": [ 7 | "Miguel Mota " 8 | ], 9 | "description": "Hidden Markov Models in JavaScript", 10 | "keywords": [ 11 | "hidden", 12 | "markov", 13 | "model", 14 | "HMM", 15 | "chain", 16 | "probability" 17 | ], 18 | "ignore": [ 19 | "**/.*", 20 | "node_modules", 21 | "bower_components", 22 | "test", 23 | "tests" 24 | ], 25 | "license": "MIT" 26 | } 27 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hidden-markov-model", 3 | "version": "0.0.1", 4 | "description": "Hidden Markov Models in JavaScript", 5 | "main": "hidden-markov-model.js", 6 | "directories": { 7 | "test": "test" 8 | }, 9 | "scripts": { 10 | "test": "tape test/*.js" 11 | }, 12 | "repository": { 13 | "type": "git", 14 | "url": "https://github.com/miguelmota/hidden-markov-model" 15 | }, 16 | "keywords": [ 17 | "hidden", 18 | "markov", 19 | "model", 20 | "HMM", 21 | "chain", 22 | "probability" 23 | ], 24 | "author": "Miguel Mota (http://www.miguelmota.com/)", 25 | "license": "MIT", 26 | "bugs": { 27 | "url": "https://github.com/miguelmota/hidden-markov-model/issues" 28 | }, 29 | "homepage": "https://github.com/miguelmota/hidden-markov-model", 30 | "dependencies": { 31 | "tape": "^3.0.3" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /test/hidden-markov-model.js: -------------------------------------------------------------------------------- 1 | var test = require('tape'); 2 | var HiddenMarkovModel = require('../hidden-markov-model'); 3 | 4 | test('HMM', function (t) { 5 | t.plan(3); 6 | 7 | var HMM = HiddenMarkovModel(); 8 | 9 | HMM.setInitialStateVector([0.6, 0.4]); // Healhy, Fever 10 | 11 | HMM.setTransitionMatrix([ 12 | // Heathly, Fever 13 | [0.7, 0.3], // Healhy 14 | [0.4, 0.6] // Fever 15 | ]); 16 | 17 | HMM.setEmissionMatrix([ 18 | // Normal, Cold, Dizzy 19 | [0.5, 0.4, 0.1], // Healthy 20 | [0.1, 0.3, 0.6] // Fever 21 | ]); 22 | 23 | // What is the probability that the given model is able generate the sequence of being Normal on day 1, Cold on day2, and Dizzy on day 3? 24 | var alpha = []; 25 | var result = HMM.forward([0, 1, 2], alpha); // Normal, Cold, Dizzy 26 | t.equal(result, 0.03628); 27 | 28 | t.deepEqual(alpha, [ [ 0.3, 0.04000000000000001 ], 29 | [ 0.09040000000000001, 0.0342 ], 30 | [ 0.007696000000000001, 0.028584000000000002 ] ] 31 | ); 32 | 33 | result = HMM.forward([]); 34 | t.equal(result, 0); 35 | }); 36 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT license 2 | 3 | Copyright (C) 2015 Miguel Mota 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 9 | of the Software, and to permit persons to whom the Software is furnished to do 10 | so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # hidden-markov-model 2 | 3 | [Hidden Markov Models](https://en.wikipedia.org/wiki/Hidden_Markov_model) in JavaScript. 4 | 5 | [![NPM](https://nodei.co/npm/hidden-markov-model.png)](https://nodei.co/npm/hidden-markov-model) 6 | 7 | # Install 8 | 9 | ```bash 10 | npm install hidden-markov-model 11 | ``` 12 | 13 | ```bash 14 | bower install hidden-markov-model 15 | ``` 16 | 17 | # Usage 18 | 19 | This example uses the [Forward algorithm](https://en.wikipedia.org/wiki/Forward_algorithm) to calculate the probability of an observed sequence. 20 | 21 | ```javascript 22 | var HiddenMarkovModel = require('hidden-markov-model'); 23 | 24 | var HMM = HiddenMarkovModel(); 25 | 26 | HMM.setInitialStateVector([0.6, 0.4]); // 1. Healthy, 2. Fever 27 | 28 | HMM.setTransitionMatrix([ 29 | // Heathly, Fever 30 | [0.7, 0.3], // Healhy 31 | [0.4, 0.6] // Fever 32 | ]); 33 | 34 | HMM.setEmissionMatrix([ 35 | // 1. Normal, 2. Cold, 3. Dizzy 36 | [0.5, 0.4, 0.1], // Healthy 37 | [0.1, 0.3, 0.6] // Fever 38 | ]); 39 | 40 | /* What is the probability that the Hidden Markov Model is able to 41 | * generate the observed sequence of being Normal on day 1, 42 | * Cold on day2, and Dizzy on day 3? 43 | */ 44 | var alpha = []; 45 | var result = HMM.forward([0, 1, 2], alpha); // Normal, Cold, Dizzy 46 | console.log(result); // 0.03628 47 | 48 | console.log(alpha); 49 | /* [ [ 0.3, 0.04000000000000001 ], 50 | [ 0.09040000000000001, 0.0342 ], 51 | [ 0.007696000000000001, 0.028584000000000002 ] ] 52 | */ 53 | ``` 54 | 55 | # License 56 | 57 | MIT 58 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | //this will affect all the git repos 2 | git config --global core.excludesfile ~/.gitignore 3 | 4 | 5 | //update files since .ignore won't if already tracked 6 | git rm --cached 7 | 8 | # Compiled source # 9 | ################### 10 | *.com 11 | *.class 12 | *.dll 13 | *.exe 14 | *.o 15 | *.so 16 | 17 | # Packages # 18 | ############ 19 | # it's better to unpack these files and commit the raw source 20 | # git has its own built in compression methods 21 | *.7z 22 | *.dmg 23 | *.gz 24 | *.iso 25 | *.jar 26 | *.rar 27 | *.tar 28 | *.zip 29 | 30 | # Logs and databases # 31 | ###################### 32 | *.log 33 | *.sql 34 | *.sqlite 35 | 36 | # OS generated files # 37 | ###################### 38 | .DS_Store 39 | .DS_Store? 40 | ._* 41 | .Spotlight-V100 42 | .Trashes 43 | # Icon? 44 | ehthumbs.db 45 | Thumbs.db 46 | .cache 47 | .project 48 | .settings 49 | .tmproj 50 | *.esproj 51 | nbproject 52 | 53 | # Numerous always-ignore extensions # 54 | ##################################### 55 | *.diff 56 | *.err 57 | *.orig 58 | *.rej 59 | *.swn 60 | *.swo 61 | *.swp 62 | *.vi 63 | *~ 64 | *.sass-cache 65 | *.grunt 66 | *.tmp 67 | 68 | # Dreamweaver added files # 69 | ########################### 70 | _notes 71 | dwsync.xml 72 | 73 | # Komodo # 74 | ########################### 75 | *.komodoproject 76 | .komodotools 77 | 78 | # Node # 79 | ##################### 80 | node_modules 81 | 82 | # Bower # 83 | ##################### 84 | bower_components 85 | 86 | # Folders to ignore # 87 | ##################### 88 | .hg 89 | .svn 90 | .CVS 91 | intermediate 92 | publish 93 | .idea 94 | .graphics 95 | _test 96 | _archive 97 | uploads 98 | tmp 99 | example 100 | 101 | # Vim files to ignore # 102 | ####################### 103 | .VimballRecord 104 | .netrwhist 105 | -------------------------------------------------------------------------------- /hidden-markov-model.js: -------------------------------------------------------------------------------- 1 | (function(root) { 2 | 'use strict'; 3 | 4 | function HiddenMarkovModel() { 5 | if (!(this instanceof HiddenMarkovModel)) { 6 | return new HiddenMarkovModel(); 7 | } 8 | 9 | this.initialStateVector = []; 10 | this.currentStateVector = []; 11 | this.transitionStateMatrix = []; 12 | this.emissionStateMatrix = []; 13 | this.iterationsCount = 0; 14 | } 15 | 16 | HiddenMarkovModel.prototype.setInitialStateVector = function(vector) { 17 | this.initialStateVector = vector; 18 | this.currentStateVector = vector; 19 | }; 20 | 21 | HiddenMarkovModel.prototype.getInitialStateVector = function() { 22 | return this.initialStateVector; 23 | }; 24 | 25 | HiddenMarkovModel.prototype.setTransitionMatrix = function(matrix) { 26 | this.transitionStateMatrix = matrix; 27 | }; 28 | 29 | HiddenMarkovModel.prototype.getTransitionMatrix = function() { 30 | return this.transitionStateMatrix; 31 | }; 32 | 33 | HiddenMarkovModel.prototype.setEmissionMatrix = function(matrix) { 34 | this.emissionStateMatrix = matrix; 35 | }; 36 | 37 | HiddenMarkovModel.prototype.getEmissionMatrix = function() { 38 | return this.emissionStateMatrix; 39 | }; 40 | 41 | HiddenMarkovModel.prototype.forward = function(observedSequence, alpha) { 42 | alpha = alpha || []; 43 | var PI = this.initialStateVector; 44 | var A = this.transitionStateMatrix; 45 | var B = this.emissionStateMatrix; 46 | var O = observedSequence || []; 47 | var T = O.length; 48 | var N = A.length; 49 | var probability = 0; 50 | 51 | if (!Array.isArray(O)) { 52 | throw new TypeError('Emssion sequence must be an array'); 53 | } 54 | 55 | if (!Array.isArray(alpha)) { 56 | throw new TypeError('Alpha must be an array'); 57 | } 58 | 59 | if (!O.length) { 60 | return probability; 61 | } 62 | 63 | /* 64 | * Example 65 | * Hidden = Healthy, Fever 66 | * Emission = Normal, Cold, Dizzy 67 | * 68 | * PI = [H, F] 69 | * O = [N, C, D] 70 | * 71 | * H : N C D 72 | * F : N C D 73 | */ 74 | 75 | // Initialization 76 | for (var i = 0; i < N; i++) { 77 | alpha[i] = []; 78 | /* 79 | * P_t1(N) = Pinit(H) * P(N|H) 80 | * P_t1(N) = Pinit(F) * P(N|F) 81 | */ 82 | alpha[0][i] = PI[i] * B[i][O[0]]; 83 | } 84 | 85 | // Recursion 86 | for (var i = 1; i < T; i++) { 87 | alpha[i] = []; 88 | for (var j = 0; j < N; j++) { 89 | /* 90 | * P_t2(C) = (P_t1(H) * P(H|H) * P(C|H)) + (P_t1(F) + P(H|F) * P(C|H)) + ... 91 | * P_t2(C) = (P_t1(H) * P(F|H) * P(C|F)) + (P_t1(F) + P(F|F) * P(C|F)) + ... 92 | */ 93 | var result = 0; 94 | for (var l = 0; l < N; l++) { 95 | result += alpha[i-1][l] * A[l][j] * B[j][O[i]]; 96 | } 97 | alpha[i][j] = result; 98 | } 99 | } 100 | 101 | // Termination 102 | for (var i = 0; i < N; i++) { 103 | probability += alpha[T-1][i]; 104 | } 105 | 106 | return probability; 107 | }; 108 | 109 | if (typeof exports !== 'undefined') { 110 | if (typeof module !== 'undefined' && module.exports) { 111 | exports = module.exports = HiddenMarkovModel; 112 | } 113 | exports.HiddenMarkovModel = HiddenMarkovModel; 114 | } else if (typeof define === 'function' && define.amd) { 115 | define([], function() { 116 | return HiddenMarkovModel; 117 | }); 118 | } else { 119 | root.HiddenMarkovModel = HiddenMarkovModel; 120 | } 121 | 122 | })(this); 123 | --------------------------------------------------------------------------------