in reply to Re^5: checking a set of numbers for consistency mod p
in thread checking a set of numbers for consistency mod p

> holes are tricky, still need to cover this buggy edge case, which is legit but won't pass now.

edge-case covered too :)

# https://perlmonks.org/?node_id=11142871 use v5.12; use warnings; use Data::Dump qw/pp dd/; use constant DBG => 0; my $range = 32; $range = 8 if DBG; my %sieves; sub get_sieve { my ( $prime, $range ) = @_; my @sieve = 0; # p^0 = 1 my @pos = (0); while ( @sieve < 2*$range ) { @sieve = (@sieve) x $prime ; $sieve[-1]++; push @pos, @sieve-1; } pop @pos; # forget edge return { prime => $prime, sieve => [ @sieve[0 .. 2*$range-1] ], sieve_pos => \@pos, sieve_max => @pos-1, }; } sub valid_set_lanx { warn "call:",pp \@_ if DBG; my($p, $a_known) = @_; die "sequence bigger than range=$range" if @$a_known > $range; my $h_sieve_cache = $sieves{$p} //= get_sieve($p,$range); my ($a_sieve, $a_sieve_pos, $sieve_max) = @{$h_sieve_cache}{qw/sie +ve sieve_pos sieve_max/}; warn "SIEVE CACHE:", pp $h_sieve_cache if DBG; # --- find first max in known my @known = @$a_known; my $max_known = 0; my $max_pos = 0; my $idx = 0; for my $e (@known) { next unless defined $e; if ($e > $max_known) { $max_known = $e; $max_pos = $idx; } } continue { $idx++; } # --- reduce max into sieve range if ($max_known > $sieve_max) { $max_known = $sieve_max; $known[$max_pos] = $max_known; } my $idx_sieve = $a_sieve_pos->[$max_known]- $max_pos; # --- shift right if undefined holes cause problems my $shift = 1; $idx_sieve += 1+ $a_sieve_pos->[$max_known + ($shift++)] while $idx_sieve < 0; if ( DBG ) { #warn pp [\@known,$a_sieve,$max_known,$a_sieve_pos->[$max_know +n],$idx_sieve,$max_pos]; warn (". "x $idx_sieve, join " ", map { $_ // "?" } @known); warn "@$a_sieve"; } my $ok = 1; for my $e (@known) { #warn (($a_sieve->[$idx_sieve] //"?"), " - ", ($e//"?")) if DB +G; next unless defined $e; return $ok = 0 if $e != $a_sieve->[$idx_sieve] } continue { $idx_sieve++ } return $ok; } # test the examples: expect [yes, yes, no, no] say pp($_)," => \t", valid_set_lanx(@$_) ? "yes" : "no" for ( [ 2, [0, 1, 0, 2, 0]], [ 2, [1, 0, 5, 0, 1]], [ 2, [2, undef, undef, undef, 2]], [ 3, [1, 0, 0, 1, 0, 0, 1]], [ 2, [1, 0, 8, 0, 1]], [ 3, [undef, 0, 0, undef, 0, 0, 1]], );
OUTPUT:
[2, [0, 1, 0, 2, 0]] => yes [2, [1, 0, 5, 0, 1]] => yes [2, [2, undef, undef, undef, 2]] => no [3, [1, 0, 0, 1, 0, 0, 1]] => no [2, [1, 0, 8, 0, 1]] => yes [3, [undef, 0, 0, undef, 0, 0, 1]] => yes

Cheers Rolf
(addicted to the Perl Programming Language :)
Wikisyntax for the Monastery