File Coverage

blib/lib/PDL/HMM.pm
Criterion Covered Total %
statement 9 9 100.0
branch n/a
condition n/a
subroutine 3 3 100.0
pod n/a
total 12 12 100.0


line stmt bran cond sub pod time code
1             #
2             # GENERATED WITH PDL::PP from HMM.pd! Don't modify!
3             #
4             package PDL::HMM;
5              
6             our @EXPORT_OK = qw(logzero logadd logdiff logsumover hmmfw hmmalpha hmmfwq hmmalphaq hmmbw hmmbeta hmmbwq hmmbetaq hmmexpect0 hmmexpect hmmexpectq hmmmaximize hmmviterbi hmmviterbiq hmmpath hmmpathq );
7             our %EXPORT_TAGS = (Func=>\@EXPORT_OK);
8              
9 5     5   1872424 use PDL::Core;
  5         11  
  5         38  
10 5     5   1822 use PDL::Exporter;
  5         28  
  5         39  
11 5     5   199 use DynaLoader;
  5         10  
  5         4383  
12              
13              
14             our $VERSION = '0.06010';
15             our @ISA = ( 'PDL::Exporter','DynaLoader' );
16             push @PDL::Core::PP, __PACKAGE__;
17             bootstrap PDL::HMM $VERSION;
18              
19              
20              
21              
22              
23              
24              
25              
26             #line 23 "HMM.pd"
27              
28             =pod
29              
30             =head1 NAME
31              
32             PDL::HMM - Hidden Markov Model utilities in PDL
33              
34             =head1 SYNOPSIS
35              
36             use PDL::HMM;
37              
38             ##-----------------------------------------------------
39             ## Dimensions
40              
41             $N = $number_of_states;
42             $M = $number_of_symbols;
43             $T = $length_of_input;
44              
45             $A = $maximum_ambiguity;
46              
47             ##-----------------------------------------------------
48             ## Parameters
49              
50             $af = log(random($N,$N));
51             $bf = log(random($N,$M));
52             $pif = log(random($N));
53             $omegaf = log(random($N));
54              
55             @theta = ($a,$b,$pi,$omega) = hmmmaximize($af,$bf,$pif,$omegaf);
56              
57             $o = long(rint($M*random($T)));
58              
59             maximum_n_ind(dice_axis($a->logsumover+$pi+$b, 1,$o),
60             ($oq=zeroes(long,$A,$T))); ##-- for constrained variants
61              
62             ##-----------------------------------------------------
63             ## Log arithmetic
64              
65             $log0 = logzero;
66             $logz = logadd(log($x),log($y));
67             $logz = logdiff(log($x),log($y));
68             $logz = logsumover(log($x));
69              
70             ##-----------------------------------------------------
71             ## Sequence Probability
72              
73             $alpha = hmmfw ($a,$b,$pi, $o ); ##-- forward (full)
74             $alphaq = hmmfwq($a,$b,$pi, $o, $oq); ##-- forward (constrained)
75              
76             $beta = hmmbw ($a,$b,$omega, $o ); ##-- backward (full)
77             $betaq = hmmbwq($a,$b,$omega, $o,$oq); ##-- backward (constrained)
78              
79             ##-----------------------------------------------------
80             ## Parameter Estimation
81              
82             @expect = ($ea,$eb,$epi,$eomega) = hmmexpect0(@theta); ##-- initialize
83              
84             hmmexpect (@theta, $o, $alpha, $beta, $ea,$eb,$epi); ##-- expect (full)
85             hmmexpectq(@theta, $o,$oq, $alphaq,$betaq, $ea,$eb,$epi); ##-- expect (constrained)
86              
87             ($a,$b,$pi,$omega) = hmmmaximize($ea,$eb,$epi,$eomega); ##-- maximize
88              
89             ##-----------------------------------------------------
90             ## Sequence Analysis
91              
92             ($delta,$psi) = hmmviterbi ($a,$b,$pi, $o); ##-- trellis (full)
93             ($deltaq,$psiq) = hmmviterbiq($a,$b,$pi, $o,$oq); ##-- trellis (constrained)
94              
95             $paths = hmmpath ( $psi, sequence($N)); ##-- backtrace (full)
96             $pathsq = hmmpathq($oq, $psiq, sequence($A)); ##-- backtrace (constrained)
97              
98             =cut
99             #line 100 "HMM.pm"
100              
101              
102             =head1 FUNCTIONS
103              
104             =cut
105              
106              
107              
108              
109              
110             #line 178 "HMM.pd"
111              
112             =pod
113              
114             =head1 Log Arithmetic
115              
116             =cut
117             #line 118 "HMM.pm"
118              
119              
120             =head2 logzero
121              
122             =for sig
123              
124             Signature: ([o]a())
125             Types: (float double ldouble)
126              
127             =for usage
128              
129             $a = logzero();
130             logzero($a); # all arguments given
131             $a->logzero;
132              
133             =for ref
134              
135             Approximates $a() = log(0), avoids nan.
136              
137             =pod
138              
139             Broadcasts over its inputs.
140              
141             =for bad
142              
143             logzero() handles bad values. The state of the output PDL is always good.
144              
145             =cut
146              
147              
148              
149              
150             *logzero = \&PDL::logzero;
151              
152              
153              
154              
155              
156              
157             =head2 logadd
158              
159             =for sig
160              
161             Signature: (a(); b(); [o]c())
162             Types: (float double ldouble)
163              
164             =for usage
165              
166             $c = logadd($a, $b);
167             logadd($a, $b, $c); # all arguments given
168             $c = $a->logadd($b); # method call
169             $a->logadd($b, $c);
170             $a->inplace->logadd($b); # can be used inplace
171             logadd($a->inplace, $b);
172              
173             =for ref
174              
175             Computes $c() = log(exp($a()) + exp($b())), should be more stable.
176              
177             =pod
178              
179             Broadcasts over its inputs.
180              
181             =for bad
182              
183             C does not process bad values.
184             It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays.
185              
186             =cut
187              
188              
189              
190              
191             *logadd = \&PDL::logadd;
192              
193              
194              
195              
196              
197              
198             =head2 logdiff
199              
200             =for sig
201              
202             Signature: (a(); b(); [o]c())
203             Types: (float double ldouble)
204              
205             =for usage
206              
207             $c = logdiff($a, $b);
208             logdiff($a, $b, $c); # all arguments given
209             $c = $a->logdiff($b); # method call
210             $a->logdiff($b, $c);
211             $a->inplace->logdiff($b); # can be used inplace
212             logdiff($a->inplace, $b);
213              
214             =for ref
215              
216             Computes log symmetric difference c = log(exp(max(a,b)) - exp(min(a,b))), may be more stable.
217              
218             =pod
219              
220             Broadcasts over its inputs.
221              
222             =for bad
223              
224             C does not process bad values.
225             It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays.
226              
227             =cut
228              
229              
230              
231              
232             *logdiff = \&PDL::logdiff;
233              
234              
235              
236              
237              
238              
239             =head2 logsumover
240              
241             =for sig
242              
243             Signature: (a(n); [o]b())
244             Types: (float double ldouble)
245              
246             =for usage
247              
248             $b = logsumover($a);
249             logsumover($a, $b); # all arguments given
250             $b = $a->logsumover; # method call
251             $a->logsumover($b);
252              
253             =for ref
254              
255             Computes $b() = log(sumover(exp($a()))), should be more stable.
256              
257             =pod
258              
259             Broadcasts over its inputs.
260              
261             =for bad
262              
263             C does not process bad values.
264             It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays.
265              
266             =cut
267              
268              
269              
270              
271             *logsumover = \&PDL::logsumover;
272              
273              
274              
275              
276              
277             #line 234 "HMM.pd"
278              
279             =pod
280              
281             =head1 Sequence Probability
282              
283             =cut
284             #line 285 "HMM.pm"
285              
286              
287             =head2 hmmfw
288              
289             =for sig
290              
291             Signature: (a(N,N); b(N,M); pi(N); o(T); [o]alpha(N,T))
292             Types: (float double ldouble)
293              
294             =for usage
295              
296             $alpha = hmmfw($a, $b, $pi, $o);
297             hmmfw($a, $b, $pi, $o, $alpha); # all arguments given
298             $alpha = $a->hmmfw($b, $pi, $o); # method call
299             $a->hmmfw($b, $pi, $o, $alpha);
300              
301             Compute forward probability (alpha) matrix
302             for input $o given model parameters
303             @theta = ($a, $b, $pi, $omega).
304              
305             Output (pseudocode) for all 0<=i
306              
307             $alpha(i,t) = log P( $o(0:t), q(t)==i | @theta )
308              
309             Note that the final-state probability vector $omega() is neither
310             passed to this function nor used in the computation, but
311             can be used to compute the final sequence probability for $o as:
312              
313             log P( $o | @theta ) = logsumover( $omega() + $alpha(:,t-1) )
314              
315             =pod
316              
317             Broadcasts over its inputs.
318              
319             =for bad
320              
321             C does not process bad values.
322             It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays.
323              
324             =cut
325              
326              
327              
328              
329             *hmmfw = \&PDL::hmmfw;
330              
331              
332              
333              
334              
335             #line 325 "HMM.pd"
336              
337             *hmmalpha = \&hmmfw;
338             #line 339 "HMM.pm"
339              
340              
341             =head2 hmmfwq
342              
343             =for sig
344              
345             Signature: (a(N,N); b(N,M); pi(N); o(T); oq(Q,T); [o]alphaq(Q,T))
346             Types: (float double ldouble)
347              
348             =for usage
349              
350             $alphaq = hmmfwq($a, $b, $pi, $o, $oq);
351             hmmfwq($a, $b, $pi, $o, $oq, $alphaq); # all arguments given
352             $alphaq = $a->hmmfwq($b, $pi, $o, $oq); # method call
353             $a->hmmfwq($b, $pi, $o, $oq, $alphaq);
354              
355             Compute constrained forward probability (alphaq) matrix
356             for input $o given model parameters
357             @theta = ($a, $b, $pi, $omega),
358             considering only the initial
359             non-negative state indices in $oq(:,t) for each observation $o(t).
360              
361             Output (pseudocode) for all 0<=qi
362              
363             $alphaq(qi,t) = log P( $o(0:t), q(t)==$oq(qi,t) | @theta )
364              
365             Note that the final-state probability vector $omega() is neither
366             passed to this function nor used in the computation, but
367             can be used to compute the final sequence probability for $o as:
368              
369             log P( $o | @theta ) = logsumover( $alphaq(:,t-1) + $omega($oqTi) )
370              
371             where:
372              
373             $oqTi = $oq(:,t-1)->where($oq(:,t-1)>=0)
374              
375             =pod
376              
377             Broadcasts over its inputs.
378              
379             =for bad
380              
381             C does not process bad values.
382             It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays.
383              
384             =cut
385              
386              
387              
388              
389             *hmmfwq = \&PDL::hmmfwq;
390              
391              
392              
393              
394              
395             #line 423 "HMM.pd"
396              
397             *hmmalphaq = \&hmmfwq;
398             #line 399 "HMM.pm"
399              
400              
401             =head2 hmmbw
402              
403             =for sig
404              
405             Signature: (a(N,N); b(N,M); omega(N); o(T); [o]beta(N,T))
406             Types: (float double ldouble)
407              
408             =for usage
409              
410             $beta = hmmbw($a, $b, $omega, $o);
411             hmmbw($a, $b, $omega, $o, $beta); # all arguments given
412             $beta = $a->hmmbw($b, $omega, $o); # method call
413             $a->hmmbw($b, $omega, $o, $beta);
414              
415             Compute backward probability (beta) matrix
416             for input $o given model parameters
417             @theta = ($a, $b, $pi, $omega).
418              
419             Output (pseudocode) for all 0<=i
420              
421             $beta(i,t) = log P( $o(t+1:T-1) | q(t)==i, @theta )
422              
423             Note that the initial-state probability vector $pi() is neither
424             passed to this function nor used in the computation, but
425             can be used to compute the final sequence probability for $o as:
426              
427             log P( $o | @theta ) = logsumover( $pi() + $b(:,$o(0)) + $beta(:,0) )
428              
429             =pod
430              
431             Broadcasts over its inputs.
432              
433             =for bad
434              
435             C does not process bad values.
436             It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays.
437              
438             =cut
439              
440              
441              
442              
443             *hmmbw = \&PDL::hmmbw;
444              
445              
446              
447              
448              
449             #line 497 "HMM.pd"
450              
451             *hmmbeta = \&hmmbw;
452             #line 453 "HMM.pm"
453              
454              
455             =head2 hmmbwq
456              
457             =for sig
458              
459             Signature: (a(N,N); b(N,M); omega(N); o(T); oq(Q,T); [o]betaq(Q,T))
460             Types: (float double ldouble)
461              
462             =for usage
463              
464             $betaq = hmmbwq($a, $b, $omega, $o, $oq);
465             hmmbwq($a, $b, $omega, $o, $oq, $betaq); # all arguments given
466             $betaq = $a->hmmbwq($b, $omega, $o, $oq); # method call
467             $a->hmmbwq($b, $omega, $o, $oq, $betaq);
468              
469             Compute constrained backward probability (betaq) matrix
470             for input $o given model parameters
471             @theta = ($a, $b, $pi, $omega),
472             considering only the initial non-negative state indices in $oq(:,t) for
473             each observation $o(t).
474              
475             Output (pseudocode) for all 0<=qi
476              
477             $betaq(qi,t) = log P( $o(t+1:T-1) | q(t)==$oq(qi,t), @theta )
478              
479             Note that the initial-state probability vector $pi() is neither
480             passed to this function nor used in the computation, but
481             can be used to compute the final sequence probability for $o as:
482              
483             log P( $o | @theta ) = logsumover( $betaq(:,0) + $pi($oq0i) + $b($oq0i,$o(0)) )
484              
485             where:
486              
487             $oq0i = $oq(:,0)->where( $oq(:,0) >= 0 );
488              
489             =pod
490              
491             Broadcasts over its inputs.
492              
493             =for bad
494              
495             C does not process bad values.
496             It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays.
497              
498             =cut
499              
500              
501              
502              
503             *hmmbwq = \&PDL::hmmbwq;
504              
505              
506              
507              
508              
509             #line 571 "HMM.pd"
510              
511             *hmmbetaq = \&hmmbwq;
512              
513             #line 580 "HMM.pd"
514              
515             =pod
516              
517             =head1 Parameter Estimation
518              
519             =head2 hmmexpect0
520              
521             =for sig
522              
523             Signature: (a(N,N); b(N,M); pi(N); omega(N); [o]ea(N,N); [o]eb(N,M); [o]epi(N); [o]eomega(N))
524              
525             Initializes expectation matrices $ea(), $eb() and $epi() to logzero().
526             For use with hmmexpect().
527              
528             =cut
529              
530             sub hmmexpect0 {
531             my ($a,$b,$pi,$omega, $ea,$eb,$epi,$eomega) = @_;
532              
533             $ea = zeroes($a->type, $a->dims) if (!defined($ea));
534             $eb = zeroes($b->type, $b->dims) if (!defined($eb));
535             $epi = zeroes($pi->type, $pi->dims) if (!defined($epi));
536             $eomega = zeroes($omega->type, $omega->dims) if (!defined($eomega));
537              
538             $ea .= PDL::logzero();
539             $eb .= PDL::logzero();
540             $epi .= PDL::logzero();
541             $eomega .= PDL::logzero();
542              
543             return ($ea,$eb,$epi,$eomega);
544             }
545             #line 546 "HMM.pm"
546              
547              
548             =head2 hmmexpect
549              
550             =for sig
551              
552             Signature: (a(N,N); b(N,M); pi(N); omega(N); o(T); alpha(N,T); beta(N,T); [o]ea(N,N); [o]eb(N,M); [o]epi(N); [o]eomega(N))
553             Types: (float double ldouble)
554              
555             =for usage
556              
557             ($ea, $eb, $epi, $eomega) = hmmexpect($a, $b, $pi, $omega, $o, $alpha, $beta);
558             hmmexpect($a, $b, $pi, $omega, $o, $alpha, $beta, $ea, $eb, $epi, $eomega); # all arguments given
559             ($ea, $eb, $epi, $eomega) = $a->hmmexpect($b, $pi, $omega, $o, $alpha, $beta); # method call
560             $a->hmmexpect($b, $pi, $omega, $o, $alpha, $beta, $ea, $eb, $epi, $eomega);
561              
562             Compute partial Baum-Welch re-estimation of the model @theta = ($a, $b, $pi, $omega)
563             for the observation sequence $o() with forward- and backward-probability
564             matrices $alpha(), $beta(). Result is recorded as log pseudo-frequencies
565             in the expectation matrices $ea(), $eb(), $epi(), and $eomega(), which are required parameters,
566             and should have been initialized (e.g. by L()) before calling this function.
567              
568             Can safely be called sequentially for incremental reestimation.
569              
570             =pod
571              
572             Broadcasts over its inputs.
573              
574             =for bad
575              
576             C does not process bad values.
577             It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays.
578              
579             =cut
580              
581              
582              
583              
584             *hmmexpect = \&PDL::hmmexpect;
585              
586              
587              
588              
589              
590              
591             =head2 hmmexpectq
592              
593             =for sig
594              
595             Signature: (a(N,N); b(N,M); pi(N); omega(N); o(T); oq(Q,T); alphaq(Q,T); betaq(Q,T); [o]ea(N,N); [o]eb(N,M); [o]epi(N); [o]eomega(N))
596             Types: (float double ldouble)
597              
598             =for usage
599              
600             ($ea, $eb, $epi, $eomega) = hmmexpectq($a, $b, $pi, $omega, $o, $oq, $alphaq, $betaq);
601             hmmexpectq($a, $b, $pi, $omega, $o, $oq, $alphaq, $betaq, $ea, $eb, $epi, $eomega); # all arguments given
602             ($ea, $eb, $epi, $eomega) = $a->hmmexpectq($b, $pi, $omega, $o, $oq, $alphaq, $betaq); # method call
603             $a->hmmexpectq($b, $pi, $omega, $o, $oq, $alphaq, $betaq, $ea, $eb, $epi, $eomega);
604              
605             Compute constrained partial Baum-Welch re-estimation of the model @theta = ($a, $b, $pi, $omega)
606             for the observation sequence $o(),
607             with constrained forward- and backward-probability
608             matrices $alphaq(), $betaq(),
609             considering only the initial non-negative state
610             indices in $oq(:,t) for observation $o(t).
611             Result is recorded as log pseudo-frequencies
612             in the expectation matrices $ea(), $eb(), $epi(), and $eomega(), which are required parameters,
613             and should have been initialized (e.g. by L()) before calling this function.
614              
615             Can safely be called sequentially for incremental reestimation.
616              
617             =pod
618              
619             Broadcasts over its inputs.
620              
621             =for bad
622              
623             C does not process bad values.
624             It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays.
625              
626             =cut
627              
628              
629              
630              
631             *hmmexpectq = \&PDL::hmmexpectq;
632              
633              
634              
635              
636              
637             #line 789 "HMM.pd"
638              
639             =pod
640              
641             =head2 hmmmaximize
642              
643             =for sig
644              
645             Signature: (Ea(N,N); Eb(N,M); Epi(N); Eomega(N); [o]ahat(N,N); [o]bhat(N,M); [o]pihat(N); [o]omegahat(N));
646              
647             Maximizes expectation values from $Ea(), $Eb(), $Epi(), and $Eomega()
648             to log-probability matrices $ahat(), $bhat(), $pihat(), and $omegahat().
649             Can also be used to compile a maximum-likelihood model
650             from log-frequency matrices.
651              
652             =cut
653              
654             sub hmmmaximize {
655             my ($ea,$eb,$epi,$eomega, $ahat,$bhat,$pihat,$omegahat) = @_;
656              
657             $ahat = zeroes($ea->type, $ea->dims) if (!defined($ahat));
658             $bhat = zeroes($eb->type, $eb->dims) if (!defined($bhat));
659             $pihat = zeroes($epi->type, $epi->dims) if (!defined($pihat));
660             $omegahat = zeroes($eomega->type, $eomega->dims) if (!defined($omegahat));
661              
662             my $easumover = $ea->xchg(0,1)->logsumover->inplace->logadd($eomega);
663              
664             $ahat .= $ea - $easumover;
665             $bhat .= $eb - $eb->xchg(0,1)->logsumover;
666             $pihat .= $epi - $epi->logsumover;
667             $omegahat .= $eomega - $easumover;
668              
669             return ($ahat,$bhat,$pihat,$omegahat);
670             }
671              
672             #line 830 "HMM.pd"
673              
674             =pod
675              
676             =head1 Sequence Analysis
677              
678             =cut
679             #line 680 "HMM.pm"
680              
681              
682             =head2 hmmviterbi
683              
684             =for sig
685              
686             Signature: (a(N,N); b(N,M); pi(N); o(T); [o]delta(N,T); int [o]psi(N,T))
687             Types: (float double ldouble)
688              
689             =for usage
690              
691             ($delta, $psi) = hmmviterbi($a, $b, $pi, $o);
692             hmmviterbi($a, $b, $pi, $o, $delta, $psi); # all arguments given
693             ($delta, $psi) = $a->hmmviterbi($b, $pi, $o); # method call
694             $a->hmmviterbi($b, $pi, $o, $delta, $psi);
695              
696             Computes Viterbi algorithm trellises $delta() and $psi() for the
697             observation sequence $o() given the model parameters @theta = ($a,$b,$pi,$omega).
698              
699             Outputs:
700              
701             Probability matrix $delta(): log probability of best path to state $j at time $t:
702              
703             $delta(j,t) = max_{q(0:t)} log P( $o(0:t), q(0:t-1), $q(t)==j | @theta )
704              
705             Path backtrace matrix $psi(): best predecessor for state $j at time $t:
706              
707             $psi(j,t) = arg_{q(t-1)} max_{q(0:t)} P( $o(0:t), q(0:t-1), $q(t)==j | @theta )
708              
709             Note that if you are using termination probabilities $omega(),
710             then in order to find the most likely final state, you need to
711             compute the contribution of $omega() yourself, which is easy
712             to do:
713              
714             $best_final_q = maximum_ind($delta->slice(",-1") + $omega);
715              
716             =pod
717              
718             Broadcasts over its inputs.
719              
720             =for bad
721              
722             C does not process bad values.
723             It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays.
724              
725             =cut
726              
727              
728              
729              
730             *hmmviterbi = \&PDL::hmmviterbi;
731              
732              
733              
734              
735              
736              
737             =head2 hmmviterbiq
738              
739             =for sig
740              
741             Signature: (a(N,N); b(N,M); pi(N); o(T); oq(Q,T); [o]deltaq(Q,T); indx [o]psiq(Q,T))
742             Types: (float double ldouble)
743              
744             =for usage
745              
746             ($deltaq, $psiq) = hmmviterbiq($a, $b, $pi, $o, $oq);
747             hmmviterbiq($a, $b, $pi, $o, $oq, $deltaq, $psiq); # all arguments given
748             ($deltaq, $psiq) = $a->hmmviterbiq($b, $pi, $o, $oq); # method call
749             $a->hmmviterbiq($b, $pi, $o, $oq, $deltaq, $psiq);
750              
751             Computes constrained Viterbi algorithm trellises $deltaq() and $psiq() for the
752             observation sequence $o() given the model parameters @theta = ($a,$b,$pi,$omega),
753             considering only the initial non-negative state indices $oq(:,t) for each
754             observarion $o(t).
755              
756             Outputs:
757              
758             Constrained probability matrix $deltaq(): log probability of best path to state $oq(j,t) at time $t:
759              
760             $deltaq(j,t) = max_{j(0:t)} log P( $o(0:t), q(0:t-1)==$oq(:,j(0:t-1)), q(t)==$oq(j,t) | @theta )
761              
762             Constrained path backtrace matrix $psiq(): best predecessor index for state $oq(j,t) at time $t:
763              
764             $psiq(j,t) = arg_{j(t-1)} max_{j(0:t)} P( $o(0:t), q(0:t-1)=$oq(:,j(0:t-1)), q(t)==$oq(j,t) | @theta )
765              
766             Note that if you are using termination probabilities $omega(),
767             then in order to find the most likely final state, you need to
768             compute the contribution of $omega() yourself, which is quite easy
769             to do:
770              
771             $best_final_j = maximum_ind($deltaq->slice(",-1") + $omega->index($oq->slice(",(-1)")))
772              
773             =pod
774              
775             Broadcasts over its inputs.
776              
777             =for bad
778              
779             C does not process bad values.
780             It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays.
781              
782             =cut
783              
784              
785              
786              
787             *hmmviterbiq = \&PDL::hmmviterbiq;
788              
789              
790              
791              
792              
793              
794             =head2 hmmpath
795              
796             =for sig
797              
798             Signature: (psi(N,T); indx qfinal(); indx [o]path(T))
799             Types: (float double ldouble)
800              
801             =for usage
802              
803             $path = hmmpath($psi, $qfinal);
804             hmmpath($psi, $qfinal, $path); # all arguments given
805             $path = $psi->hmmpath($qfinal); # method call
806             $psi->hmmpath($qfinal, $path);
807              
808             Computes best-path backtrace $path() for the final state $qfinal()
809             from completed Viterbi trellis $psi().
810              
811             Outputs:
812              
813             Path backtrace $path(): state (in best sequence) at time $t:
814              
815             $path(t) = arg_{q(t)} max_{q(0:T-1)} log P( $o(), q(0:T-2), $q(T-1)==$qfinal() | @theta )
816              
817             This even threads over multiple final states, if specified,
818             so you can align paths to their final states just by calling:
819              
820             $bestpaths = hmmpath($psi, sequence($N));
821              
822             Note that $path(T-1) == $qfinal(): yes, this is redundant,
823             but also tends to be quite convenient.
824              
825             =pod
826              
827             Broadcasts over its inputs.
828              
829             =for bad
830              
831             C does not process bad values.
832             It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays.
833              
834             =cut
835              
836              
837              
838              
839             *hmmpath = \&PDL::hmmpath;
840              
841              
842              
843              
844              
845              
846             =head2 hmmpathq
847              
848             =for sig
849              
850             Signature: (indx oq(Q,T); psiq(Q,T); indx qfinalq(); indx [o]path(T))
851             Types: (float double ldouble)
852              
853             =for usage
854              
855             $path = hmmpathq($oq, $psiq, $qfinalq);
856             hmmpathq($oq, $psiq, $qfinalq, $path); # all arguments given
857             $path = $oq->hmmpathq($psiq, $qfinalq); # method call
858             $oq->hmmpathq($psiq, $qfinalq, $path);
859              
860             Computes constrained best-path backtrace $path() for the final state index $qfinalq()
861             from completed constrained Viterbi trellis $psiq().
862              
863             Outputs:
864              
865             Path backtrace $path(): state (in best sequence) at time $t:
866              
867             $path(t) = arg_{q(t)} max_{q(0:T-1)} log P( $o(), q(0:T-2), $q(T-1)==$oq($qfinalq(),T-1) | @theta )
868              
869             This is really just a convenience method for dealing with constrained
870             lookup -- the same thing can be accomplished using hmmpath() and
871             some PDL index magic.
872              
873             =pod
874              
875             Broadcasts over its inputs.
876              
877             =for bad
878              
879             C does not process bad values.
880             It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays.
881              
882             =cut
883              
884              
885              
886              
887             *hmmpathq = \&PDL::hmmpathq;
888              
889              
890              
891              
892              
893             #line 1132 "HMM.pd"
894              
895             ##---------------------------------------------------------------------
896             =pod
897              
898             =head1 COMMON PARAMETERS
899              
900             HMMs are specified by parameters $a(N,N), $b(N,M), $pi(N), and $omega(N);
901             input sequences are represented as vectors $o(T) of integer values in the range [0..M-1],
902             where the following notational conventions are used:
903              
904             =over 4
905              
906             =item States:
907              
908             The model has $N states, denoted $q,
909             0 <= $q < $N.
910              
911             =item Alphabet:
912              
913             The input- (aka "observation-") alphabet of the model has $M elements,
914             denoted $o(t), 0 <= $o(t) < $M.
915              
916             =item Time indices:
917              
918             Time indices are denoted $t,
919             1 <= $t < $T.
920              
921             =item Input Sequences:
922              
923             Input- (aka "observation-") sequences are represented as vectors of
924             of length $T whose component values are in the range [0..M-1],
925             i.e. alphabet indices.
926              
927             =item Initial Probabilities:
928              
929             The vector $pi(N) gives the (log) initial state probability distribution:
930              
931             $pi(i) = log P( $q(0)==i )
932              
933             =item Final Probabilities:
934              
935             The vector $omega(N) gives the (log) final state probability distribution:
936              
937             $omega(i) = log P( $q($T)==i )
938              
939             This parameter is a nonstandard extension.
940             You can simulate the behavior of more traditional definitions
941             (such as that given in Rabiner (1989)) by setting:
942              
943             $omega = zeroes($N);
944              
945             wherever it is required.
946              
947             =item Arc Probabilities:
948              
949             The matrix $a(N,N) gives the (log) conditional state-transition probability distribution:
950              
951             $a(i,j) = log P( $q(t+1)==j | $q(t)==i )
952              
953             =item Emission Probabilities:
954              
955             The matrix $b(N,M) gives the (log) conditional symbol emission probability:
956              
957             $b(j,o) = log P( $o(t)==o | $q(t)==j )
958              
959             =back
960              
961             =cut
962              
963             ##---------------------------------------------------------------------
964             =pod
965              
966             =head1 ACKNOWLEDGEMENTS
967              
968             Perl by Larry Wall.
969              
970             PDL by Karl Glazebrook, Tuomas J. Lukka, Christian Soeller, and others.
971              
972             Implementation based largely on the formulae in:
973             L. E. Rabiner, "A tutorial on Hidden Markov Models and selected
974             applications in speech recognition," Proceedings of the IEEE 77:2,
975             Februrary, 1989, pages 257--286.
976              
977             =cut
978              
979             ##----------------------------------------------------------------------
980             =pod
981              
982             =head1 KNOWN BUGS
983              
984             Probably many.
985              
986             =cut
987              
988             ##---------------------------------------------------------------------
989             =pod
990              
991             =head1 AUTHOR
992              
993             Bryan Jurish Emoocow@cpan.orgE
994              
995             =head2 Copyright Policy
996              
997             Copyright (C) 2005-2023 by Bryan Jurish. All rights reserved.
998              
999             This package is free software, and entirely without warranty.
1000             You may redistribute it and/or modify it under the same terms
1001             as Perl itself.
1002              
1003             =head1 SEE ALSO
1004              
1005             perl(1), PDL(3perl).
1006              
1007             =cut
1008             #line 1009 "HMM.pm"
1009              
1010             # Exit with OK status
1011              
1012             1;