siskos1 has asked for the wisdom of the Perl Monks concerning the following question:

hello, please read question. dont just say "use my". it will be a long question and i am not sure if i can tell correctly. i will try. i want to implement viterbi algorithm in a recursive way. i can do it in a iterative way by assigning each values at each level in forward way. but i want to do it with recursion in backward way. (i have stuck in a similar problem so i want to learn this) i am stuck in a place where "i want to assign a recursive function to all keys of a hash" and return it. ( of course all those keys recall that function again) .but i cant hold those temporary values. i can hold but those get mixed with calculation of other levels. for example;
foreach my $yy ( keys %{$trans->{$state}} ) { $trans->{$state}->{$yy} * viterbi($yy, $r) ; }
this part is main part. all code is here :
@observation = qw(empty a a empty); $trans = { 'end' => {M2 => 1}, 'M2' => { I1 => 0.1, M1 => 0.3}, 'I1' => { begin => 0.8}, 'M1' => { begin => 0.2}, }; sub viterbi { my $state = shift; my $output = shift; # V (begin)(0) =1; V(anyother)(0) =0; V(begin)(other_numbers) =0; if($state eq begin) { if($output == 0) { return 1;} else { return 0; } + } elsif ( ($state ne begin) && ($output == 0) ) {return 0; } else { $r=$output-1; #maximum of below foreach# foreach my $yy ( keys %{$trans->{$state}} ) { $trans->{$state}->{$yy} * viterbi($yy, $r) ; } } } print "\n\n", viterbi(end, 3);
i didnt add any of my wrong codes to main foreach part, for those who want to try the code after knowing what to do, answer must be 0.08. for those who know viterbi, i didnt add emission probabilities because it is the easy part i guess. but i really want to know how to make the program hold all temporary values for all recursive calculations. if i put them in an array, program adds values not layer by layer but level by level, so things doesnt work. iterative solution is possible but i cant figure out how to solve it in a recursive way. thanks so much whoever helps. thanks again

Replies are listed 'Best First'.
Re: how can i hold temporary values in a recursive function
by BrowserUk (Patriarch) on Apr 18, 2010 at 17:06 UTC

    Several ways:

    1. Simple closure:
      { my %state; sub recursive { my $arg = shift; ... if( ( $arg = $state{ $arg } ) == ... ) { return recursive( $arg ); else { return 0 } } }
    2. Closure via helper function:
      sub rec_helper { my %state; my $recursive; $recursive = sub { my( $arg ) = shift; ... if( ( $arg = $state{ $arg ) ) == ... ) { return $recursive->( $arg ); } else { return 0; } }; }
    3. State passed through args (often via helper function ):
      sub recursive { my( $state, $arg ) = @_; ... if( ( $arg = $state->{ $arg } ) == ... ) { return recursive( $state, $arg ); } else { return 0; } } sub rec_helper{ my $arg = shift; my %state; return recursive( \%state, $arg ); }

    And many variations on those themes.


    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
      #2 leaks memory every time you call rec_helper. The sub you create references $recursive which references the sub, so you have a memory cycle. The simplest solution is to avoid using a lexical to hold the reference to the sub. It even simplifies the code a little.
      sub rec_helper { my %state; local *recursive = sub { my( $arg ) = shift; ... if( ( $arg = $state{ $arg ) ) == ... ) { return recursive( $arg ); } else { return 0; } }; }
Re: how can i hold temporary values in a recursive function
by LanX (Saint) on Apr 18, 2010 at 16:45 UTC
    I can only guess what you want, maybe its a closure to memorize the recursive results?

    { my %memo; sub rec_func { my $key=key_from_input(@_); unless (exists $memo{$key}) { $memo{$key}=calculate(@_); } return $memo{key}; } }

    This should effectively cache complicated calculations based on the call-parameters...

    (untested)

    Of course you are free to decide what you are caching...

    Cheers Rolf

        I suppose he needs a more general flexibility to memoize based on more complicated input ("Level"?) Thats why I didn't mention Memoize

        For those interested see Viterbi Algorithm and Algorithm-Viterbi

        Cheers Rolf

Re: how can i hold temporary values in a recursive function
by GrandFather (Saint) on Apr 18, 2010 at 20:57 UTC

    Add strictures then turn your sketch into real code. At present there are too many places where it is not clear what you want to happen because of errors in your code (bare words 'begin' and 'end' and multiplications in void context for example). If the general help others have offered isn't enough to solve your problem then we need something that can actually be run.

    True laziness is hard work
      It would be polite for you to make at least a minimal effort to understand the OP. For example, when the OP says
      #maximum of below foreach# foreach my $yy ( keys %{$trans->{$state}} ) { $trans->{$state}->{$yy} * viterbi($yy, $r) ; }
      it's obvious he means max(map { ... } keys ...) We're humans here, not computers, so we should act like, and treat each other as, humans.

      Of course, you're not obliged to make that effort. But if you don't want to, why waste everyone's time with an unhelpful comment?

        In fact I spent on the order of half an hour playing with the OP's code, but I couldn't figure out what a useful starting condition might be. Revisiting the OP's node I've only just noticed the print "\n\n", viterbi(end, 3); at the end of the large code block. I guess I was misled by the comment 'this part is main part' following the first code fragment into thinking that was the driving code for what followed rather than the 'key part of the code' as, in hind sight, the OP presumably meant. On reflection it's not surprising that my static analysis of the code wasn't getting anywhere fast!

        Bottom line? 'Don't attribute to malice what you can account for by stupidity!'

        True laziness is hard work
Re: how can i hold temporary values in a recursive function
by GrandFather (Saint) on Apr 21, 2010 at 02:45 UTC

    It's not clear where you are having difficulty - your title and most of your question text is at odds with the code you provide. However the following code fixes various errors and fills in missing code. It generates the answer you want and uses Memoize to optimise viterbi's performance by caching results for given arguments lists.

    use strict; use warnings; use Memoize qw(); my $trans = { 'end' => {M2 => 1}, 'M2' => {I1 => 0.1, M1 => 0.3}, 'I1' => {begin => 0.8}, 'M1' => {begin => 0.2}, }; Memoize::memoize ('viterbi'); print viterbi('end', 3); sub viterbi { my ($state, $output) = @_; return $output == 0 ? 1 : return 0 if $state eq 'begin'; return 0 if $output == 0; my $r = $output - 1; my $max; for my $yy (keys %{$trans->{$state}}) { my $value = $trans->{$state}->{$yy} * viterbi($yy, $r); $max = $value if ! defined $max || $value > $max; } return $max; }

    Prints:

    0.08
    True laziness is hard work