Concurrent loops finishing on their own?

188 Views Asked by At

I have this loop as part of a larger program (it's open source, and it can be downloaded and run within comma, the configuration is there):

 my $promise = start react whenever $channel-one -> @crew {
            Algorithm::Evolutionary::LogTimelineSchema::Evolutionary.log: {
                my %fitness-of;
                Algorithm::Evolutionary::LogTimelineSchema::Frequencies
                        .log( :@crew );
                my @unpacked-pop = generate-by-frequencies( $population-size, @crew );
                my $population = evaluate( population => @unpacked-pop,
                                            :%fitness-of,
                                            evaluator => &leading-ones);
                Algorithm::Evolutionary::LogTimelineSchema::GenerationsStart
                        .log( :population-size(@unpacked-pop.elems),
                              :distinct-elements( %fitness-of.keys.elems) );
                my atomicint $count = 0;
                while ($count⚛++ < $generations) &&
                        (best-fitness($population) < $max-fitness) {
                    LAST {
                        if best-fitness($population) >= $max-fitness {
                            Algorithm::Evolutionary::LogTimelineSchema::SolutionFound
                                    .log(
                                    {
                                        id => $*THREAD.id,
                                        best => best-fitness($population),
                                        found => True,
                                        finishing-at => DateTime.now.Str
                                    }
                                    );

                            say "Solution found" => $evaluations;
                            Algorithm::Evolutionary::LogTimelineSchema::SolutionFound
                                    .log( :$evaluations );
                            $channel-one.close;
                        } else {
                            say "Emitting after $count generations in thread ",
                                    $*THREAD.id, " Best fitness ",best-fitness($population);
                            if  $count < $generations {
                                Algorithm::Evolutionary::LogTimelineSchema::Weird
                                        .log(  id => $*THREAD.id,
                                                best => best-fitness($population),
                                                :$count,
                                                :population-size(@unpacked-pop.elems),
                                                :distinct-elements( %fitness-of.keys.elems)
                                        );
                            } else {
                                Algorithm::Evolutionary::LogTimelineSchema::Events.log(
                                        id => $*THREAD.id,
                                        best => best-fitness($population),
                                        :$count
                                        );
                            }
                            $to-mix.send( frequencies-best($population, 8) );
                        }
                    };
                    $population = generation( :$population, :%fitness-of,
                            evaluator => &leading-ones,
                            :$population-size
                            );
                    $evaluations += $population.elems;
                }
                Algorithm::Evolutionary::LogTimelineSchema::Generations
                        .log( :generations($count),
                              individuals => %fitness-of.keys.elems);
                $evaluations;
            };
        };

Check out the loop conditions:

                while ($count⚛++ < $generations) &&
                        (best-fitness($population) < $max-fitness) {

$count is a local variable that, besides, is atomic, and exceeding that count or achieving the best fitness seem to be the only way out.

Only it's not. The loop ends on its own accord, without meeting any of the conditions there. I have set out two different log events, "Weird", and "EndRun" (which you can see above), "Weird" is called when the loop ends without reaching either the best fitness or the number of generations; that one is almost always called, as seen in this Comma visualization enter image description here With the (sparse) triangles on the top showing when the loop ends when it should, the purple triangles below marking the "weird" endings. The printed log also shows the same thing:


Emitting after 8 generations in thread 10 Best fitness 48
Mixing in 12
Emitting after 5 generations in thread 7 Best fitness 47
Mixing in 12
Emitting after 2 generations in thread 8 Best fitness 48
Mixing in 12
Emitting after 1 generations in thread 10 Best fitness 48
Mixing in 8

It almost never reaches 16 generations, which is the value of $generations. I'm using Raku 2019.11, but this kind of thing happened before too. I'm not sure I've bumped into a bug, or I'm simply triggering some mechanism I don't really know about. Any idea?

Update: It also crashes from time to time...

/home/jmerelo/.rakudobrew/moar-2020.01/install/bin/rakudo /home/jmerelo/Papers/2020/2020-evostar-concurrent-eas/code/concurrent-ea-leading-ones.p6
Use of Nil in numeric context
  in block  at /home/jmerelo/Papers/2020/2020-evostar-concurrent-eas/code/concurrent-ea-leading-ones.p6 line 68
An operation first awaited:
  in sub MAIN at /home/jmerelo/Papers/2020/2020-evostar-concurrent-eas/code/concurrent-ea-leading-ones.p6 line 139
  in block <unit> at /home/jmerelo/Papers/2020/2020-evostar-concurrent-eas/code/concurrent-ea-leading-ones.p6 line 21

Died with the exception:
    A react block:
      in code  at /home/jmerelo/Papers/2020/2020-evostar-concurrent-eas/code/concurrent-ea-leading-ones.p6 line 55

    Died because of the exception:
        Type check failed in binding to parameter '@chromosome1'; expected Positional but got Any (Any)
          in sub crossover at /home/jmerelo/.rakudobrew/moar-2020.01/install/share/perl6/site/sources/C405508803395DA88D77FC9B113DB20EFC0C1C4C (Algorithm::Evolutionary::Simple) line 96
          in sub produce-offspring at /home/jmerelo/.rakudobrew/moar-2020.01/install/share/perl6/site/sources/C405508803395DA88D77FC9B113DB20EFC0C1C4C (Algorithm::Evolutionary::Simple) line 115
          in sub generation at /home/jmerelo/.rakudobrew/moar-2020.01/install/share/perl6/site/sources/C405508803395DA88D77FC9B113DB20EFC0C1C4C (Algorithm::Evolutionary::Simple) line 149
          in block  at /home/jmerelo/Papers/2020/2020-evostar-concurrent-eas/code/concurrent-ea-leading-ones.p6 line 107
          in block  at /home/jmerelo/.rakudobrew/moar-2020.01/install/share/perl6/site/sources/0F5CDA46B783643CA4E3D746E2329D0C256CB46B (Log::Timeline) line 95
          in method log at /home/jmerelo/.rakudobrew/moar-2020.01/install/share/perl6/site/sources/0F5CDA46B783643CA4E3D746E2329D0C256CB46B (Log::Timeline) line 90
          in block  at /home/jmerelo/Papers/2020/2020-evostar-concurrent-eas/code/concurrent-ea-leading-ones.p6 line 56

Update 2 Trying to golf it down as requested, I've changed the while to a for loop and it works like a charm. So at least that works for me, but still I'd like to know what's the deal with the tunneling while

0

There are 0 best solutions below