diff options
| author | Mohammad S Anwar <mohammad.anwar@yahoo.com> | 2020-04-06 01:16:07 +0100 |
|---|---|---|
| committer | Mohammad S Anwar <mohammad.anwar@yahoo.com> | 2020-04-06 01:16:07 +0100 |
| commit | 729e2c12907fc758187da111cb51ddc510f58a8c (patch) | |
| tree | 9f485fdca2b98b2d93a1d98113c22c0daea8176a /challenge-054 | |
| parent | e00d3393c34b1e6e038ce4e1976888bced5dea79 (diff) | |
| download | perlweeklychallenge-club-729e2c12907fc758187da111cb51ddc510f58a8c.tar.gz perlweeklychallenge-club-729e2c12907fc758187da111cb51ddc510f58a8c.tar.bz2 perlweeklychallenge-club-729e2c12907fc758187da111cb51ddc510f58a8c.zip | |
- Added solutions by Colin Crain.
Diffstat (limited to 'challenge-054')
| -rw-r--r-- | challenge-054/colin-crain/perl/ch-1.pl | 251 | ||||
| -rw-r--r-- | challenge-054/colin-crain/perl/ch-2.pl | 150 | ||||
| -rw-r--r-- | challenge-054/colin-crain/raku/ch-1.p6 | 181 | ||||
| -rw-r--r-- | challenge-054/colin-crain/raku/ch-2.p6 | 139 |
4 files changed, 721 insertions, 0 deletions
diff --git a/challenge-054/colin-crain/perl/ch-1.pl b/challenge-054/colin-crain/perl/ch-1.pl new file mode 100644 index 0000000000..a143fe7dd8 --- /dev/null +++ b/challenge-054/colin-crain/perl/ch-1.pl @@ -0,0 +1,251 @@ +#! /opt/local/bin/perl +# +# kth_me_kate.pl +# +# TASK #1 +# kth Permutation Sequence +# Write a script to accept two integers n (>=1) and k (>=1). It +# should print the kth permutation of n integers. For more +# information, please follow the wiki page. +# +# https://en.wikipedia.org/wiki/Permutation#k-permutations_of_n +# +# For example, n=3 and k=4, the possible permutation sequences are +# listed below: +# +# 123 +# 132 +# 213 +# 231 +# 312 +# 321 +# The script should print the 4th permutation sequence 231. +# +# notes on the question: So what exactly are we looking for here? +# +# Despite the wiki link given, which sends us to the subheading +# "#k-permutations_of_n", we do not appear to be looking to +# calculate here what is known as nPk, or the k-permutations of n, +# and so we will neither quantify, enumerate nor ruminate on any +# possible ordered groupings of k items selected from a set of n +# elements. That's a really interesting puzzle in its own right, but +# that does not jibe with the rest of the challenge description. We +# can only infer that the specific subheading portion of the link +# given is what as known as a red herring, or false lead, or perhaps +# wild goose chase. +# +# The rest of the page is informative reading, though, and holds +# clues as to the intent of the challenge. The first is a +# permutation is an expression of a particular rearrangement, or +# remapping, of a sequence; the verb rather than the noun. +# +# Thus the actual items being permuted are irrelevant, and as such +# when speaking of permutations it is common to use an ascending +# sequence of natural numbers, 1 2 3 4 5... as tokens representing +# the elements to be rearranged. So n here is the number of +# elements, which is what we expect, and the ordered start set will +# be of the form +# +# ( 1 2 3 ... n-2 n-1 n) +# +# The task seems to ask us to establish a list of all permutations +# of this ordered set and then locate and output the kth member of +# that list. The problem arises when one takes into account there is +# no one single way to sequence the order of possible permutations +# of a starting set. There are commonly accepted ways to label +# premutations with unique identifiers for later reference, but no +# one way to enumerate them. Mathematically it is the relationships +# between individual permutations that are interesting, rather than +# their positional information in a list. +# +# The list of n=3 in the task outline is sorted ascending as though +# the individual permutations were strings; "1 2 3" is followed by +# "1 3 2". This is known as lexicographic order, and is what we will +# assume is requested. +# +# The description also notably starts the list of permutaions with +# the identity permutation, the mapping of each element to its +# original place. So we need to make sure we start counting from +# there, rather than the first alteration. Remember, to choose to do +# nothing is still a choice. +# +# +# method: Now before we continue, let it be known that these days I'm +# not shooting for the fastest, most sensible nor efficiant +# methodology to go about solving these challenges. For instance, +# there exist some quite good modules in CPAN to make permutations +# simple, painless and fast. Of these I prefer and recommend +# Algorithm::Permute, it's written in XS and very good, albeit with +# some odd quirks. I even used it here previously for the wordgame +# challenge. No, these days I view these excursions as thought +# experiments and just prefer, if I have time, to explore the +# problem space and see whats there. Modules are an integral part of +# the Perl ecosystem but today I'm just going to have at it and roll +# my own. I have my own idiosyncratic rules for proceeding, and +# these rules are by no means fixed nor consistent. +# +# I suppose I'm drawing on an old artist technique in my toolbox, to +# artificially add constraints to a challenge. Combined with my +# apparent fascination with parsing the minutiae of the challenge +# questions, and you get a little slice of my brain. Welcome to my +# world, we have snacks. +# +# To obtain the kth lexicographically sorted permutation sequence +# the first approach was to generate a list of permutations and +# select the kth element of that list. Seems reasonable. So we use a +# recursive routine, constructing the patterns from left to right, +# and at each element iterate through the remaining numbers in the +# starting pattern in a well ordered way. The resulting list of +# patterns will come out lexicographically sorted. We can accomplish +# this by passing a set of remaining numbers, a working permutaion +# under construction, and a results set to hold the permutaions once +# finished. +# +# This is all well and good, and works fine for reletively small +# values of n, but as-is it needs to construct all of the patterns +# first and then select the kth member. Furthermore, it will +# obviously blow up with all that recursion and looping; even though +# the sets shrink by one element each time we proceed the time will +# still be n! to finish. We can improve this dramatically for +# smaller numbers of k by coupling in some reference slots to store +# the number requested and the the permutation produced, and +# short-circuiting to collapse the remaining recursion if we have +# our answer, but this is by no means a universal safeguard. The +# final routine is quite workable within reason, and is located in +# +# permute_recursive( \@set, \@working, $permutations, $data) +# +# There is of course a better way to do this, which is to rearrange +# the sequences in place, using an algorithm that only requires +# the current permutation to generate the next. One such algorithm +# is Knuth's Algoritm L (Lexicographic permutation generation), +# which he notes is only describing a method that had been invented +# some 600 years previous. This is implimented as +# +# compute_next_permutation( \@set ) +# +# with a wrapper to apply it the correct number of times. +# +# +# +# 2020 colin crain +## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## + + + +use warnings; +use strict; +use feature ":5.26"; + +## ## ## ## ## MAIN: + +my ( $number_elements, $sequence_requested ) = @ARGV ; + +my $result = permute_with_recursion( $number_elements, $sequence_requested ); +say "recursion: the " . $sequence_requested . "th permutation sequence is $result->@*"; + +my $result2 = permute_in_place( $number_elements, $sequence_requested ); +say "in place : the " . $sequence_requested . "th permutation sequence is ", join ' ', $result2->@*; + + + +## ## ## ## ## SUBS: + +sub permute_with_recursion { + my ( $end, $selected_sequence ) = @_; + my @set = (1..$end); + my @working; + my $permutations = []; + my $data = { seq_number => $selected_sequence, + result => undef }; + + permute_recursive( \@set, \@working, $permutations, $data); + + return $data->{result}; +} + +sub permute_recursive { +## given a starting set, a working list and a permutations set +## computes complete permutations as arrays and places the arrays on the permutations array +## which is maintained throughout by reference + my ($setref, $workref, $permutations, $data) = @_; + my @set = $setref->@*; + + ## if there is only one element left, push it on the working list, + ## push that array reference onto the permutations array and return. + ## This unique permutation list is complete. + if ( scalar @set == 1 ) { + my @working = $workref->@*; + push @working, $set[0]; + if (scalar $permutations->@* == $data->{seq_number} - 1) { + $data->{result} = \@working; + } + else { + push $permutations->@*, \@working; + } + return; + } + + ## iterate through the remaining elements of the set, + ## creating new copy of the working list, moving the element + ## from the set to the working list and recursing with these + ## new lists. The permutations list reference is passed through unchanged. + for my $element ( @set ) { + + ## collapse the recursion if we have our result + last if defined $data->{result}; + + my @working = $workref->@*; + push @working, $element; + my @subset = grep { $_ != $element } @set; + permute_recursive( \@subset, \@working, $permutations, $data ); + } +} + +sub permute_in_place { + my ( $end, $selected_sequence ) = @_; + my @set = (1..$end); + + ## the unrearranged sequence, the identity permutation, + ## counts as sequence #1 as per the task + for (1..$selected_sequence-1) { + compute_next_permutation( \@set ); + } + + return \@set; +} + +sub compute_next_permutation { +## in place algorithm (from Knuth Algorithm L, The Art of Computer Programming) +# +# «before we start we assume a sorted sequence a[0] <= a[1] <= ... <= a[n]» +# L1. «Visit» Take the given arrangement +# L2. «Find j» Find the largest index j such that a[j] < a[j + 1]. If no such index +# exists, terminate the algorithm and we are done +# L3. «Increase a[j]» Find the largest index k greater than j such that a[j] < a[k], +# L3a. then swap the values of a[j] and a[k]. +# L4. «Reverse a[j+1]..a[n]» Reverse the subsequence starting at a[j + 1] through the end of the permutation, +# a[n]. Do nothing if j+1 >= n. Return to L1. + + ## L1 + my $set = shift; + my $end = scalar $set->@* - 1; + + ## L2 + my @one = grep { $set->[$_] < $set->[$_+1] } (0..$end-1); + my $j = $one[-1]; + return if ! defined $j; + + ## L3 + my @two = grep { $_ > $j and $set->[$_] > $set->[$j] } (0..$end); + my $k = $two[-1]; + + ## L3a + ($set->[$j], $set->[$k]) = ($set->[$k], $set->[$j]); + + ## L4 + return unless ( $j+1 < $end ); # { + + my @reversed = reverse($set->@[ ($j+1)..$end ]); + splice $set->@*, $j+1, $end-$j, @reversed; +} diff --git a/challenge-054/colin-crain/perl/ch-2.pl b/challenge-054/colin-crain/perl/ch-2.pl new file mode 100644 index 0000000000..f8b23c2e26 --- /dev/null +++ b/challenge-054/colin-crain/perl/ch-2.pl @@ -0,0 +1,150 @@ +#! /opt/local/bin/perl +# +# call_me_collatz.pl +# +# TASK #2 +# Collatz Conjecture +# It is thought that the following sequence will always reach 1: +# +# $n = $n / 2 when $n is even +# $n = 3*$n + 1 when $n is odd + +# For example, if we start at 23, we get the following sequence: +# +# 23 → 70 → 35 → 106 → 53 → 160 → 80 → 40 → 20 → 10 → 5 → 16 → 8 → 4 → 2 → 1 +# +# Write a function that finds the Collatz sequence for any positive +# integer. Notice how the sequence itself may go far above the +# original starting number. +# +# Extra Credit +# Have your script calculate the sequence length for all starting +# numbers up to 1000000 (1e6), and output the starting number and +# sequence length for the longest 20 sequences. +# +# +# method: since the conjecture is that _all_ such sequences converge, it +# seems safe to say that the it's been checked for a lot of numbers. +# So we'll make a loop that finds the next number, and finishes when +# that number reaches 1. It may run a while, but it should always +# eventually finish, right? +# +# For the sake of clarity, I've removed the logic of the conjecture +# into its own separate routine. +# +# For the metaanalysis (hey look, two 'a's in a row, see 53-2), +# keeping all the sequences for a million numbers gets big quickly, +# so for that task we throw out the numbers and only keep a total +# count of the length indexed on the starting number. +# +# To ensure reproducability, we will slightly modify the challenge +# to find the lowest numbers of the 20 longest sequences. The +# request wasn't for the numbers to create sequences of the longest +# twenty lengths, so we need a qualifier to determine which numbers +# to include if multiple sequences of equal length are completing +# for the last places in the list. By sorting first to find the +# highet values and secondarily to find the lowest number running +# the script on different systems running different hashing +# algorithms. +# +# Since we were in there looking at a couple of million numbers, it +# seemed reasonable to wonder what the largest number we found was. +# So I added a little ratcheting variable that updates the high +# number and the number of the sequence that spawned it whenever the +# previous value is exceeded. Its 56,991,483,520, in the sequence +# for the number 704,511. Huh. +# +# To enable the metaanalysis, pass any positive second argument on +# the command line. +# +# +# 2020 colin crain +## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## + + + +use warnings; +use strict; +use feature ":5.26"; + +## ## ## ## ## MAIN: +my $start = shift @ARGV // 23; +my $METAANALYSIS = shift @ARGV // 1; + + +## get the sequence and print it +say join ', ', make_collatz_sequence($start)->@*; + + + + +## metaanalysis section from here down in MAIN +exit unless $METAANALYSIS; +my $data = { seq_lengths => {}, + highest_number => 0, + highest_value => 0 }; + +get_collatz_metadata($data); + +## display length totals +my $count; +my @sorted = sort { $data->{seq_lengths}->{$b} <=> $data->{seq_lengths}->{$a} || $a <=> $b } keys $data->{seq_lengths}->%*; +say '-' x 35; +say ' count number sequence length'; +say '-------+--------+------------------'; +printf " %2d %6d %6d\n", ++$count, $_, $data->{seq_lengths}->{$_} for @sorted[0..19]; + +## display max number found +say '-' x 35; +say "largest value found was ", $data->{highest_value}; +say "for number ", $data->{highest_number}; + + + + +## ## ## ## ## SUBS: + +sub make_collatz_sequence { +## given a positive integer, returns a reference to the array +## of the Collatz sequence associated with it + my $prev = shift; + my @seq = ($prev); + my $next; + + while ($prev != 1) { + $next = next_collatz($prev); + push @seq, $next; + $prev = $next; + } + + return \@seq; +} + +sub next_collatz { +## get the next number according to the rules of the Collatz sequence + $_[0] % 2 == 0 ? $_[0] / 2 + : 3 * $_[0] + 1; +} + +sub get_collatz_metadata { +## run metaanalysis on the first 1,000,000 Collatz sequences + my $data = shift; + + for my $number (1..1000000) { + my $prev = $number; + my $len = 1; + my $next; + + while ($prev != 1) { + $next = $prev % 2 == 0 ? $prev / 2 + : 3 * $prev + 1; + $prev = $next; + if ($next > $data->{highest_value}) { + $data->{highest_number} = $number; + $data->{highest_value} = $next; + } + $len++; + } + $data->{seq_lengths}->{$number} = $len; + } +} diff --git a/challenge-054/colin-crain/raku/ch-1.p6 b/challenge-054/colin-crain/raku/ch-1.p6 new file mode 100644 index 0000000000..65fcc49383 --- /dev/null +++ b/challenge-054/colin-crain/raku/ch-1.p6 @@ -0,0 +1,181 @@ +use v6.d; + +# +# kth-me-kate.raku +# +# TASK #1 +# kth Permutation Sequence +# Write a script to accept two integers n (>=1) and k (>=1). It +# should print the kth permutation of n integers. For more +# information, please follow the wiki page. +# +# https://en.wikipedia.org/wiki/Permutation#k-permutations_of_n +# +# For example, n=3 and k=4, the possible permutation sequences are +# listed below: +# +# 123 +# 132 +# 213 +# 231 +# 312 +# 321 +# The script should print the 4th permutation sequence 231. +# +# notes on the question: So what exactly are we looking for here? +# +# Despite the wiki link given, which sends us to the subheading +# "#k-permutations_of_n", we do not appear to be looking to +# calculate here what is known as nPk, or the k-permutations of n, +# and so we will neither quantify, enumerate nor ruminate on any +# possible ordered groupings of k items selected from a set of n +# elements. That's a really interesting puzzle in its own right, but +# that does not jibe with the rest of the challenge description. We +# can only infer that the specific subheading portion of the link +# given is what as known as a red herring, or false lead, or perhaps +# wild goose chase. +# +# The rest of the page is informative reading, though, and holds +# clues as to the intent of the challenge. The first is a +# permutation is an expression of a particular rearrangement, or +# remapping, of a sequence; the verb rather than the noun. +# +# Thus the actual items being permuted are irrelevant, and as such +# when speaking of permutations it is common to use an ascending +# sequence of natural numbers, 1 2 3 4 5... as tokens representing +# the elements to be rearranged. So n here is the number of +# elements, which is what we expect, and the ordered start set will +# be of the form +# +# ( 1 2 3 ... n-2 n-1 n) +# +# The task seems to ask us to establish a list of all permutations +# of this ordered set and then locate and output the kth member of +# that list. The problem arises when one takes into account there is +# no one single way to sequence the order of possible permutations +# of a starting set. There are commonly accepted ways to label +# premutations with unique identifiers for later reference, but no +# one way to enumerate them. Mathematically it is the relationships +# between individual permutations that are interesting, rather than +# their positional information in a list. +# +# The list of n=3 in the task outline is sorted ascending as though +# the individual permutations were strings; "1 2 3" is followed by +# "1 3 2". This is known as lexicographic order, and is what we will +# assume is requested. +# +# The description also notably starts the list of permutaions with +# the identity permutation, the mapping of each element to its +# original place. So we need to make sure we start counting from +# there, rather than the first alteration. Remember, to choose to do +# nothing is still a choice. +# +# +# method: In the Perl 5 version of this challenge, I took a little +# excursion into routines for constructing permutations, eschewing +# modules like Algorithm::Permute for the task and perfering to roll +# my own routines, finally landing on an implimentation of Knuth's +# Algorithm L. +# +# In the Raku language, the operation of permutation is built in for +# positional types, albeit not exactly well defined in the +# documentation as to how it's executed. However calling +# +# @array.permutations +# +# to construct a list of lists of purmutations is trivially +# straightforward. A close examination of the lists produced appears +# to show the algorithm used produces lexicographically sorted +# permutations. Dumping these lists into an array and indexing on +# the $sequence_requested variable ( -1, to allow for 0-indexing ) +# produces the result. +# +# Because the algorithm used is not specified, it seemed reasonable +# to double check the ordering against a known lexicographically +# sorted algorithm, Knuth's Algorithm L. This is implimented in +# +# apply-algorithm-L ( @set ) +# +# below. Cross-referencing results for various inputs suggests there +# is no variance in the outputs of the twon functions. +# +# One glaring difference dows arise, though, and that is time of +# execution for larger permutation lists. By the time we get to +# n=10, the built in permutaions method takes about 10 seconds to +# produce a result. Examination shows that we are producing the +# entire permutaion set for the given list before selecting the +# permutation requested, and changing this behavior is not well +# documented. As it turns out, after some digging I was able to +# determine the output of .permutaions is a Seq, and can be coerced +# by the .lazy method. Applying this wrapper transfers to the Array +# assignment, so we are only evaluating the sequences we need and +# the execution time is reduced proportionally. +# +# It's worth noting that for large values of n and k, the built in +# routine, with or without lazy evaluation, so easily outstrips the +# raku implimentation of Algorithm L for speed I can't see any +# optimizing to close that gap. +# +# +# +# 2020 colin crain +## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## + +sub MAIN ( $number_elements, $sequence_requested where {$sequence_requested > 0}) { + +## built in routine + my @array = 1..$number_elements; + my @perm = @array.permutations.lazy; + + ## the challenge is indexing from 1, the first sequence is the identity permutation + say "using permutations routine:" ; + say @perm[$sequence_requested-1].join(' '); + +## algorithm L + my @result = permute_in_place( $number_elements, $sequence_requested ); + say "using Algorithm L"; + say @result.join(' '); + +} + +sub permute_in_place ( $number_elements, $sequence_requested is copy) { + my @set = 1 .. $number_elements; + + ## the challenge is indexing from 1, the first sequence is the identity permutation + ## if requested == 1, range is 0..0 (one less) which goes to -1 and the algorithm is not executed + apply-algorithm-L( @set ) while --$sequence_requested; + + return @set; +} + +sub apply-algorithm-L ( @set ) { +## in place algorithm (from Knuth Algorithm L, The Art of Computer Programming) +# «before we start we assume a sorted sequence a[0] <= a[1] <= ... <= a[n]» +# L1. «Visit» Take the given arrangement +# L2. «Find j» Find the largest index j such that a[j] < a[j + 1]. If no such index +# exists, terminate the algorithm and we are done +# L3. «Increase a[j]» Find the largest index k greater than j such that a[j] < a[k], +# L3a. then swap the values of a[j] and a[k]. +# L4. «Reverse a[j+1]..a[n]» Reverse the subsequence starting at a[j + 1] through the end of the permutation, +# a[n]. Do nothing if j+1 >= n. Return to L1. + + ## L1 + # @set is the standing iteration to be modified + + ## L2 + my @indexes = (^@set.end).grep( { @set[$_] < @set[$_+1] } ); + my $j = @indexes.tail; + return if ! defined $j; + + ## L3 + @indexes = (^@set.end+1).grep( { $_ > $j and @set[$_] > @set[$j] } ); + my $k = @indexes.tail; + + ## L3a + (@set[$j], @set[$k]) = (@set[$k], @set[$j]); + + ## L4 + return unless $j+1 < @set.end; + @set[$j+1..@set.end] = @set[$j+1..@set.end].reverse; + return; +} diff --git a/challenge-054/colin-crain/raku/ch-2.p6 b/challenge-054/colin-crain/raku/ch-2.p6 new file mode 100644 index 0000000000..d678d5abc9 --- /dev/null +++ b/challenge-054/colin-crain/raku/ch-2.p6 @@ -0,0 +1,139 @@ +use v6.d; + +# +# call_me_collatz.raku +# +# TASK #2 +# Collatz Conjecture +# It is thought that the following sequence will always reach 1: +# +# $n = $n / 2 when $n is even +# $n = 3*$n + 1 when $n is odd +# +# For example, if we start at 23, we get the following sequence: +# +# 23 → 70 → 35 → 106 → 53 → 160 → 80 → 40 → 20 → 10 → 5 → 16 → 8 → 4 → 2 → 1 +# +# Write a function that finds the Collatz sequence for any positive +# integer. Notice how the sequence itself may go far above the +# original starting number. +# +# Extra Credit +# Have your script calculate the sequence length for all starting +# numbers up to 1000000 (1e6), and output the starting number and +# sequence length for the longest 20 sequences. +# +# +# method: since the conjecture is that _all_ such sequences converge, it +# seems safe to say that the it's been checked for a lot of numbers. +# So we'll make a loop that finds the next number, and finishes when +# that number reaches 1. It may run a while, but it should always +# eventually finish, right? Certainly for n<1,000,000. +# +# For the sake of clarity, I've removed the logic of the conjecture +# into its own separate routine. +# +# For the metaanalysis (hey look, two 'a's in a row, see 53-2), +# keeping all the sequences for a million numbers gets big quickly, +# so for that task we throw out the numbers and only keep a total +# count of the length indexed on the starting number. +# +# To ensure reproducability, we will slightly modify the challenge +# to find the lowest numbers of the 20 longest sequences. The +# request wasn't for the numbers to create sequences of the longest +# twenty lengths, so we need a qualifier to determine which numbers +# to include if multiple sequences of equal length are completing +# for the last places in the list. By sorting first to find the +# highet values and secondarily to find the lowest number running +# the script on different systems running different hashing +# algorithms. +# +# Since we were in there looking at a couple of million numbers, it +# seemed reasonable to wonder what the largest number we found along +# the way actually was. So I added a little ratcheting variable that +# updates the high number and the number of the sequence that +# spawned it whenever the previous value is exceeded. It's +# 56,991,483,520, in the sequence for the number 704,511. Huh. +# +# To enable the metaanalysis, pass any positive second argument on +# the command line. +# +# +# +# 2020 colin crain +## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## + +sub MAIN (Int:D $start where {$start > 0} = 23, $do_meta = 0) { + + say join ', ', make_collatz_sequence($start); + + exit unless $do_meta; + my %sequences; + my %data = ( highest_number => 0, + highest_value => 0 ); + + get_collatz_metadata(%data, %sequences); + + ## display length totals + my $count; + my @sorted = (keys %sequences).sort({ %sequences{$^b} <=> %sequences{$^a} || $^a <=> $^b }); + + say '-' x 35; + say ' count number sequence length'; + say '-------+--------+------------------'; + + for ^20 -> $idx { + printf " %2d %6d %-6d\n", $idx+1, @sorted[$idx], %sequences{@sorted[$idx]} ; + } + + ## display max number found + say '-' x 35; + say "largest value found was ", %data<highest_value>; + say "for number ", %data<highest_number>; + +} + +sub make_collatz_sequence ( $start ) { + my $current = $start; + my @seq = ($current); + my $next; + + while ($current != 1) { + $next = next_collatz($current); + @seq.push: $next; + $current = $next; + } + + return @seq; +} + +sub next_collatz (Int:D $n ) { +## this confuses the compiler so we need to explicitly recast n/2 as an Int rather than a Rat +## which, by the way, is fine, because it always will remain an integer as n is even + $n %% 2 ?? ($n / 2).Int + !! 3 * $n + 1; +} + + +sub get_collatz_metadata ( %data, %sequences ) { +## run metaanalysis on the first 1,000,000 Collatz sequences + my $then = now; + for (1..1000000) -> $number { + my $prev = $number; + my $len = 1; + my $next; + + while ($prev != 1) { + $next = $prev % 2 == 0 ?? $prev / 2 + !! 3 * $prev + 1; + $prev = $next; + if ($next > %data<highest_value>) { + %data<highest_number> = $number; + %data<highest_value> = $next; + } + $len++; + } + %sequences{$number} = $len; + } + say "time: ", now - $then; +} |
