class Collatz::HailstoneSequence

Contains the results of computing a hailstone sequence via hailstone_sequence(~).

Attributes

terminal_condition[R]

A terminal condition that reflects the final state of the hailstone sequencing, whether than be that it succeeded at determining the stopping time, the total stopping time, found a cycle, or got stuck on zero (or surpassed the max total).

terminal_status[R]

A status value that has different meanings depending on what the terminal condition was. If the sequence completed either via reaching the stopping or total stopping time, or getting stuck on zero, then this value is the stopping/terminal time. If the sequence got stuck on a cycle, then this value is the cycle length. If the sequencing passes the maximum stopping time then this is the value that was provided as that maximum.

values[R]

The set of values that comprise the hailstone sequence.

Public Class Methods

new(initial_value, p, a, b, max_total_stopping_time, total_stopping_time) click to toggle source

Initialise and compute a new Hailstone Sequence.

@raise FailedSaneParameterCheck If p or a are 0.

@param Integer initial_value The value to begin the hailstone sequence from.

@param Integer p: Modulus used to devide n, iff n is equivalent to (0 mod p).

@param Integer a: Factor by which to multiply n.

@param Integer b: Value to add to the scaled value of n.

@param Integer max_total_stopping_time: Maximum amount of times to iterate the function, if 1 is not reached.

@param Boolean total_stopping_time: 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).

@return HailstoneSequence An initialised, and computed, hailstone sequence

# File lib/collatz/hailstone_sequence.rb, line 43
def initialize(initial_value, p, a, b, max_total_stopping_time, total_stopping_time)
  terminate = stopping_time_terminus(initial_value, total_stopping_time)
  if initial_value.zero?
    # 0 is always an immediate stop.
    @values = [0]
    @terminal_condition = SequenceState::ZERO_STOP
    @terminal_status = 0
  elsif initial_value == 1
    # 1 is always an immediate stop, with 0 stopping time.
    @values = [1]
    @terminal_condition = SequenceState::TOTAL_STOPPING_TIME
    @terminal_status = 0
  else
    # Otherwise, hail!
    min_max_total_stopping_time = [max_total_stopping_time, 1].max
    pre_values = Array.new(min_max_total_stopping_time+1)
    pre_values[0] = initial_value
    for k in 1..min_max_total_stopping_time do
      next_value = Collatz.function(pre_values[k-1], p: p, a: a, b: b)
      # Check if the next_value hailstone is either the stopping time, total
      # stopping time, the same as the initial value, or stuck at zero.
      if terminate.call(next_value)
        pre_values[k] = next_value
        if next_value == 1
          @terminal_condition = SequenceState::TOTAL_STOPPING_TIME
        else
          @terminal_condition = SequenceState::STOPPING_TIME
        end
        @terminal_status = k
        @values = pre_values.slice(0, k+1)
        return
      end
      if pre_values.include? next_value
        pre_values[k] = next_value
        cycle_init = 1
        for j in 1..k do
          if pre_values[k-j] == next_value
            cycle_init = j
            break
          end
        end
        @terminal_condition = SequenceState::CYCLE_LENGTH
        @terminal_status = cycle_init
        @values = pre_values.slice(0, k+1)
        return
      end
      if next_value.zero?
        pre_values[k] = 0
        @terminal_condition = SequenceState::ZERO_STOP
        @terminal_status = -k
        @values = pre_values.slice(0, k+1)
        return
      end
      pre_values[k] = next_value
    end
    @terminal_condition = SequenceState::MAX_STOP_OUT_OF_BOUNDS
    @terminal_status = min_max_total_stopping_time
    @values = pre_values
  end
end