Title: | Functions Related to the Collatz/Syracuse/3n+1 Problem |
---|---|
Description: | Provides the basic functionality to interact with the Collatz conjecture. The parameterisation uses the same (P,a,b) notation as Conway's generalisations. Besides the function and reverse function, there is also functionality to retrieve the hailstone sequence, the "stopping time"/"total stopping time", or tree-graph. The only restriction placed on parameters is that both P and a can't be 0. For further reading, see <https://en.wikipedia.org/wiki/Collatz_conjecture>. |
Authors: | Nathan Levett [aut, cre] |
Maintainer: | Nathan Levett <[email protected]> |
License: | Apache License (== 2.0) |
Version: | 1.0.1 |
Built: | 2024-11-16 06:07:15 UTC |
Source: | https://github.com/skenvy/collatz |
Handles the sanity check for the parameterisation (P,a,b)
assert_sane_parameterication(P, a, b)
assert_sane_parameterication(P, a, b)
P |
Modulus used to devide n, iff n is equivalent to (0 mod P). |
a |
Factor by which to multiply n. |
b |
Value to add to the scaled value of n. |
Required by both the function and reverse function, to assert that they have sane parameters, otherwise will force stop the execution.
Functions related to the Collatz/Syracuse/3N+1 problem.
Provides the basic functionality to interact with the Collatz conjecture. The parameterisation uses the same (P,a,b) notation as Conway's generalisations. Besides the function and reverse function, there is also functionality to retrieve the hailstone sequence, the "stopping time"/"total stopping time", or tree-graph. The only restriction placed on parameters is that both P and a can't be 0.
Maintainer: Nathan Levett [email protected]
Useful links:
Report bugs at https://github.com/Skenvy/Collatz/issues/new/choose
Returns the output of a single application of a Collatz-esque function.
collatz_function(n, P = 2, a = 3, b = 1)
collatz_function(n, P = 2, a = 3, b = 1)
n |
(numeric|bigz) The value on which to perform the Collatz-esque function |
P |
(numeric|bigz): Modulus used to divide n, iff n is equivalent to (0 mod P). Default is 2. |
a |
(numeric|bigz) Factor by which to multiply n. Default is 3. |
b |
(numeric|bigz) Value to add to the scaled value of n. Default is 1. |
This function will compute and return the result of applying one iteration of a parameterised Collatz-esque function. Although it will operate with integer inputs, for overflow safety, provide a gmp Big Integer ('bigz').
a numeric, either in-built or a bigz from the gmp library.
# Returns the output of a single application of a Collatz-esque function. # Without `gmp` or parameterisation, we can try something simple like collatz_function(5) collatz_function(16) # If we want change the default parameterisation we can; collatz_function(4, 5, 2, 3) # Or if we only want to change one of them collatz_function(3, a=-2) # All the above work fine, but the function doesn't offer protection against # overflowing integers by default. To venture into the world of arbitrary # integer inputs we can use an `as.bigz` from `gmp`. Compare the two; collatz_function(99999999999999999999) collatz_function(gmp::as.bigz("99999999999999999999"))
# Returns the output of a single application of a Collatz-esque function. # Without `gmp` or parameterisation, we can try something simple like collatz_function(5) collatz_function(16) # If we want change the default parameterisation we can; collatz_function(4, 5, 2, 3) # Or if we only want to change one of them collatz_function(3, a=-2) # All the above work fine, but the function doesn't offer protection against # overflowing integers by default. To venture into the world of arbitrary # integer inputs we can use an `as.bigz` from `gmp`. Compare the two; collatz_function(99999999999999999999) collatz_function(gmp::as.bigz("99999999999999999999"))
Calculates the values of a hailstone sequence, from an initial value.
hailstone_sequence( initial_value, P = 2, a = 3, b = 1, max_total_stopping_time = 1000, total_stopping_time = TRUE, verbose = TRUE )
hailstone_sequence( initial_value, P = 2, a = 3, b = 1, max_total_stopping_time = 1000, total_stopping_time = TRUE, verbose = TRUE )
initial_value |
(numeric|bigz) The value to begin the hailstone sequence from. |
P |
(numeric|bigz): Modulus used to divide n, iff n is equivalent to (0 mod P). Default is 2. |
a |
(numeric|bigz) Factor by which to multiply n. Default is 3. |
b |
(numeric|bigz) Value to add to the scaled value of n. Default is 1. |
max_total_stopping_time |
(int) Maximum amount of times to iterate the function, if 1 is not reached. Default is 1000. |
total_stopping_time |
(bool) Whether or not to execute until the "total" stopping time (number of iterations to obtain 1) rather than the regular stopping time (number of iterations to reach a value less than the initial value). Default is TRUE. |
verbose |
(bool) If set to verbose, the hailstone sequence will include control string sequences to provide information about how the sequence terminated, whether by reaching a stopping time or entering a cycle. Default is TRUE. |
Returns a list of successive values obtained by iterating a Collatz-esque function, until either 1 is reached, or the total amount of iterations exceeds max_total_stopping_time, unless total_stopping_time is FALSE, which will terminate the hailstone at the "stopping time" value, i.e. the first value less than the initial value. While the sequence has the capability to determine that it has encountered a cycle, the cycle from "1" wont be attempted or reported as part of a cycle, regardless of default or custom parameterisation, as "1" is considered a "total stop".
A keyed list consisting of a $values list of numeric | bigz along with a $terminalCondition and $terminalStatus
# Compute a hailstone sequence, which defaults to the total stopping time; hailstone_sequence(5) # Or only compute down to the regular stopping time; hailstone_sequence(5, total_stopping_time=FALSE) # Remove verbose messaging; hailstone_sequence(5, verbose=FALSE) # It will also stop on finding a cycle; hailstone_sequence(-56) # And can be parameterised; hailstone_sequence(3, -1, 3, 1) # The hailstone sequence can run on `bigz`; hailstone_sequence(27+gmp::as.bigz("576460752303423488"))
# Compute a hailstone sequence, which defaults to the total stopping time; hailstone_sequence(5) # Or only compute down to the regular stopping time; hailstone_sequence(5, total_stopping_time=FALSE) # Remove verbose messaging; hailstone_sequence(5, verbose=FALSE) # It will also stop on finding a cycle; hailstone_sequence(-56) # And can be parameterised; hailstone_sequence(3, -1, 3, 1) # The hailstone sequence can run on `bigz`; hailstone_sequence(27+gmp::as.bigz("576460752303423488"))
Calculates the values that would return the input under the Collatz function.
reverse_function(n, P = 2, a = 3, b = 1)
reverse_function(n, P = 2, a = 3, b = 1)
n |
(numeric|bigz) The value on which to perform the reverse Collatz function |
P |
(numeric|bigz) Modulus used to divide n, iff n is equivalent to (0 mod P) Default is 2. |
a |
(numeric|bigz) Factor by which to multiply n. Default is 3. |
b |
(numeric|bigz) Value to add to the scaled value of n. Default is 1. |
Returns the output of a single application of a Collatz-esque reverse function. If only one value is returned, it is the value that would be divided by P. If two values are returned, the first is the value that would be divided by P, and the second value is that which would undergo the multiply and add step, regardless of which is larger.
A list of either numeric or bigz type
# Calculates the values that would return the input under the Collatz # function. Without `gmp` or parameterisation, we can try something # simple like reverse_function(1) reverse_function(2) reverse_function(4) # If we want change the default parameterisation we can; reverse_function(3, -3, -2, -5) # Or if we only want to change one of them reverse_function(16, a=5) # All the above work fine, but the function doesn't offer protection against # overflowing integers by default. To venture into the world of arbitrary # integer inputs we can use an `as.bigz` from `gmp`. Compare the two; reverse_function(99999999999999999999) reverse_function(gmp::as.bigz("99999999999999999999"))
# Calculates the values that would return the input under the Collatz # function. Without `gmp` or parameterisation, we can try something # simple like reverse_function(1) reverse_function(2) reverse_function(4) # If we want change the default parameterisation we can; reverse_function(3, -3, -2, -5) # Or if we only want to change one of them reverse_function(16, a=5) # All the above work fine, but the function doesn't offer protection against # overflowing integers by default. To venture into the world of arbitrary # integer inputs we can use an `as.bigz` from `gmp`. Compare the two; reverse_function(99999999999999999999) reverse_function(gmp::as.bigz("99999999999999999999"))
Determine the stopping time, or "total" stopping time, for an initial value.
stopping_time( initial_value, P = 2, a = 3, b = 1, max_stopping_time = 1000, total_stopping_time = FALSE )
stopping_time( initial_value, P = 2, a = 3, b = 1, max_stopping_time = 1000, total_stopping_time = FALSE )
initial_value |
(int): The value for which to find the stopping time. |
P |
(numeric|bigz): Modulus used to divide n, iff n is equivalent to (0 mod P). Default is 2. |
a |
(numeric|bigz) Factor by which to multiply n. Default is 3. |
b |
(numeric|bigz) Value to add to the scaled value of n. Default is 1. |
max_stopping_time |
(int) Maximum amount of times to iterate the function, if the stopping time is not reached. IF the max_stopping_time is reached, the function will return NaN. Default is 1000. |
total_stopping_time |
(bool) Whether or not to execute until the "total" stopping time (number of iterations to obtain 1) rather than the regular stopping time (number of iterations to reach a value less than the initial value). Default is FALSE. |
Returns the stopping time, the amount of iterations required to reach a value less than the initial value, or NaN if max_stopping_time is exceeded. Alternatively, if total_stopping_time is TRUE, then it will instead count the amount of iterations to reach 1. If the sequence does not stop, but instead ends in a cycle, the result will be (Inf). If (P,a,b) are such that it is possible to get stuck on zero, the result will be the negative of what would otherwise be the "total stopping time" to reach 1, where 0 is considered a "total stop" that should not occur as it does form a cycle of length 1.
An integer numeral if stopped, Inf if a cycle, NaN if OOB, else NA.
# Calculates the "stopping time", or optionally the "total" stopping time. # Without `gmp` or parameterisation, we can try something simple like stopping_time(27) stopping_time(27, total_stopping_time=TRUE) # If we want change the default parameterisation we can; stopping_time(3, 5, 2, 1) # Or if we only want to change one of them stopping_time(17, a=5) # All the above work fine, but the function doesn't offer protection against # overflowing integers by default. To venture into the world of arbitrary # integer inputs we can use an `as.bigz` from `gmp`. Compare the two; stopping_time(99999999999999999999) stopping_time(gmp::as.bigz("99999999999999999999")) # As an extra note, the original motivation for creating a range of Collatz # themed packages came from some earlier scripts for calculating the stopping # distances under certain parameterisations. An inconsequential result of # which was observing that all of the following, for however high `k` goes, # should equal `96`! stopping_time(27) stopping_time(27+gmp::as.bigz("576460752303423488")) stopping_time(27+(2*gmp::as.bigz("576460752303423488"))) stopping_time(27+(3*gmp::as.bigz("576460752303423488"))) stopping_time(27+(4*gmp::as.bigz("576460752303423488")))
# Calculates the "stopping time", or optionally the "total" stopping time. # Without `gmp` or parameterisation, we can try something simple like stopping_time(27) stopping_time(27, total_stopping_time=TRUE) # If we want change the default parameterisation we can; stopping_time(3, 5, 2, 1) # Or if we only want to change one of them stopping_time(17, a=5) # All the above work fine, but the function doesn't offer protection against # overflowing integers by default. To venture into the world of arbitrary # integer inputs we can use an `as.bigz` from `gmp`. Compare the two; stopping_time(99999999999999999999) stopping_time(gmp::as.bigz("99999999999999999999")) # As an extra note, the original motivation for creating a range of Collatz # themed packages came from some earlier scripts for calculating the stopping # distances under certain parameterisations. An inconsequential result of # which was observing that all of the following, for however high `k` goes, # should equal `96`! stopping_time(27) stopping_time(27+gmp::as.bigz("576460752303423488")) stopping_time(27+(2*gmp::as.bigz("576460752303423488"))) stopping_time(27+(3*gmp::as.bigz("576460752303423488"))) stopping_time(27+(4*gmp::as.bigz("576460752303423488")))
Provides the appropriate lambda to use to check if iterations on an initial value have reached either the stopping time, or total stopping time.
stopping_time_terminus(n, total_stop)
stopping_time_terminus(n, total_stop)
n |
The initial value to confirm against a stopping time check. |
total_stop |
If false, the lambda will confirm that iterations of n have reached the oriented stopping time to reach a value closer to 0. If true, the lambda will simply check equality to 1. |
An anonymous function to check for the stopping time.
Determine the Tree Graph to some depth by iteratively reversing values.
tree_graph( initial_value, max_orbit_distance, P = 2, a = 3, b = 1, cycle_prevention = list() )
tree_graph( initial_value, max_orbit_distance, P = 2, a = 3, b = 1, cycle_prevention = list() )
initial_value |
(int) The root value of the directed tree graph. |
max_orbit_distance |
(int) Maximum amount of times to iterate the reverse function. There is no natural termination to populating the tree graph, equivalent to the termination of hailstone sequences or stopping time attempts, so this is not an optional argument like max_stopping_time or max_total_stopping_time, as it is the intended target of orbits to obtain, rather than a limit to avoid uncapped computation. |
P |
(numeric|bigz): Modulus used to divide n, iff n is equivalent to (0 mod P). Default is 2. |
a |
(numeric|bigz) Factor by which to multiply n. Default is 3. |
b |
(numeric|bigz) Value to add to the scaled value of n. Default is 1. |
cycle_prevention |
(set[int]) Used to prevent cycles from precipitating by keeping track of all values added across previous nest depths. Only to be used internally by the function recursing. Does not expect input. |
Returns nested dictionaries that model the directed tree graph up to a maximum nesting of max_orbit_distance, with the initial_value as the root.
A set of nested dictionaries.
#Compute a tree graph, which takes both a value to initialise the tree from, # and an "orbit distance" for how many layers deep in the tree to compute; tree_graph(16, 3) # It will also stop on finding a cycle; tree_graph(4, 3) # And can be parameterised; tree_graph(1, 1, -3, -2, -5) # If b is a multiple of a, but not of Pa, then 0 can have a reverse; tree_graph(0, 1, 17, 2, -6) # The tree graph can run on `bigz`; tree_graph((27+gmp::as.bigz("576460752303423488")), 3)
#Compute a tree graph, which takes both a value to initialise the tree from, # and an "orbit distance" for how many layers deep in the tree to compute; tree_graph(16, 3) # It will also stop on finding a cycle; tree_graph(4, 3) # And can be parameterised; tree_graph(1, 1, -3, -2, -5) # If b is a multiple of a, but not of Pa, then 0 can have a reverse; tree_graph(0, 1, 17, 2, -6) # The tree graph can run on `bigz`; tree_graph((27+gmp::as.bigz("576460752303423488")), 3)