import numpy as np
from numpy.random import default_rng
import matplotlib.pyplot as plt
from math import sqrt
[docs]def print_progress(step, total):
"""
Prints a progress bar.
Args:
step (int): progress counter
total (int): counter at completion
"""
message = "simulation progress ["
total_bar_length = 60
percentage = int(step / total * 100)
bar_fill = int(step / total * total_bar_length)
for i in range(total_bar_length):
if i < bar_fill:
message += "|"
else:
message += " "
message += "] "+str(percentage)+" %"
if step < total:
print(message, end="\r")
else:
print(message)
[docs]def get_random_sequence(n_toss=100):
"""
Generate a random sequence of coin tosses.
The function returns a random list of ones (heads) and zeros (tails).
.. note ::
This function is incomplete!
Args:
n_toss (int): number of tosses
Returns:
list: random sequence of 0's and 1's
"""
sequence = np.zeros(n_toss) # todo
return sequence
[docs]def count_max_streak(sequence):
"""
Calculates the length of the longest subsequence of
identical values in a sequence.
Args:
sequence (list): a list of values
Returns:
int: the length of the longest subsequence
"""
previous_toss = -1 # stores the previous value
max_streak = 0 # the longest streak found
current_streak = 0 # the length of the current streak
# run through the sequence and check each toss
for toss in sequence:
# If the next toss gives the same value
# as the previous one, the streak continues.
if toss == previous_toss:
current_streak += 1
# If the next toss is different than the
# previous one, the streak ended and a new
# one begins.
else:
previous_toss = toss # start new sequence
# check if this was the longest streak
if current_streak > max_streak:
max_streak = current_streak
current_streak = 1
# check if this last streak was the longest streak
if current_streak > max_streak:
max_streak = current_streak
return max_streak
[docs]def calculate_statistics(samples):
"""
Calculates and returns the sample mean, variance,
standard deviation and error of mean for the given set of samples.
For a sequence of :math:`N` values for a random variable :math:`X`,
the mean is estimated by the average
.. math ::
\\mu_X = \\langle X \\rangle = \\frac{1}{N} \\sum_i X_i
and the variance by the sample variance
.. math ::
\\sigma^2_X = \\frac{1}{N-1} \\sum_i (X_i - \\mu_X)^2.
Standard deviation is the square root of variance
.. math ::
\\sigma_X = \\sqrt{ \\sigma^2_X }
and the standard error of mean is
.. math ::
\\Delta X = \\frac{ \\sigma_X }{ \\sqrt{ N } }.
.. note ::
This function is incomplete!
Args:
samples (list): sequence of random results, :math:`X_i`
Returns:
float, float, float, float: mean, variance, standard deviation, error of mean
"""
expect = 0.0
variance = 0.0
std = 0.0
error = 0.0
# todo
return expect, variance, std, error
[docs]def calculate_statistics_for_distribution(distribution):
"""
Calculates and returns the sample mean and variance
for the given discrete distribution.
The distribution :math:`f` is a list or an array specifying
the number of times each result 0, 1, 2, 3, ... was measured.
For instance, if 4 is measured 12 times, :math:`f(4) = 12`.
For a distribution, the mean is estimated by
.. math ::
\\mu_X = \\langle X \\rangle = \\frac{1}{N} \\sum_k k f(k)
and the variance by the sample variance
.. math ::
\\sigma^2_X = \\frac{1}{N-1} \\sum_k f(k)(k - \\mu_X)^2.
Standard deviation is the square root of variance
.. math ::
\\sigma_X = \\sqrt{ \\sigma^2_X }
and the standard error of mean is
.. math ::
\\Delta X = \\frac{ \\sigma_X }{ \\sqrt{ N } }.
.. note ::
This function is incomplete!
Args:
distribution (list): vector containing the number of times each result was obtained
Returns:
float, float, float, float: mean, variance, standard deviation, error of mean
"""
expect = 0.0
variance = 0.0
std = 0.0
error = 0.0
# todo
return expect, variance, std, error
[docs]def run_series(n_toss, n_repeats):
"""
Runs a series of coin toss sequences and calculates statistics
for the longest streak of heads or tails.
The method flips a coin a given number of times
using :meth:`get_random_sequence`
and then counts the length of the longest sequence of
heads or tails in the sequence with
:meth:`count_max_streak`.
Then it repeats this experiments a given number of times
and records the length of the longest streak in each
sequence.
In the end, the method :meth:`calculate_statistics`
or :meth:`calculate_statistics_for_distribution`
is used to calculate statistics for the length of
this longest streak.
Args:
n_toss (int): the length of each sequence
n_repeats (int): the number of sequences
Returns:
array, float, float, float: distribution, mean, standard deviation, error of mean
for the longest streak
"""
# list of all max streaks
streaks = []
# an array counting how many max streaks of 1, 2, 3, ...
# we get when repeating the coin toss experiment
# several times
bins = np.zeros(n_toss+1)
# generate n_repeats sequences and count the
# maximum streak for each one
for repeat in range(n_repeats):
sequence = get_random_sequence(n_toss)
max_streak = count_max_streak(sequence)
print_progress(repeat+1,n_repeats)
# save the length of the max streak
streaks.append(max_streak)
# add one to the counter that counts how many
# times a strak of this length appears
bins[max_streak] += 1
# calculate statistics (pick either function)
expect, variance, std, error = calculate_statistics(streaks)
#expect, variance, std, error = calculate_statistics_for_distribution(bins)
return bins, expect, std, error
[docs]def main(n_toss, n_repeats):
"""
The main program.
Performs either one or several coin toss sequences
and analyses the results.
Args:
n_toss (int): the length of each sequence
n_repeats (int): the number of sequences
"""
# do we run only one sequence or a series?
if n_repeats == 1: # only one
sequence = get_random_sequence(n_toss)
max_streak = count_max_streak(sequence)
print( "sequence:" )
print( sequence )
print( "max streak: "+str(max_streak))
else: # series of sequences
distribution, expect, std, error = run_series(n_toss, n_repeats)
# print statistics
print( "N: ", n_repeats )
print( "expectation value: ", expect )
print( "standard deviation: ", std )
print( "standard error of mean: ", error )
# Plot the probability distribution for
# getting a max streak of any length
distribution /= n_repeats
plt.plot(distribution[0:20],'-o')
plt.show()
if __name__ == "__main__":
# create a new RNG globally
random = default_rng()
n_toss = 100
n_repeats = 1
main(n_toss, n_repeats)