Skip to content

Instantly share code, notes, and snippets.

@tor-gu
Created August 1, 2022 18:38
Show Gist options
  • Select an option

  • Save tor-gu/474d8da00f3b820ae5b8bb81f6d19f47 to your computer and use it in GitHub Desktop.

Select an option

Save tor-gu/474d8da00f3b820ae5b8bb81f6d19f47 to your computer and use it in GitHub Desktop.
Animation of frequency of digits in continued fractions of sqrt(n)
library(tidyverse)
library(future)
library(furrr)
library(gganimate)
plan(multisession, workers = 12)
cf_init <- function(D) {
r = as.integer(floor((sqrt(D))))
list(
D = D, r = r, a = r, b = r, c = D - r ^ 2
)
}
cf_next <- function(step) {
a = as.integer(floor((step$r + step$b) / step$c))
b = a * step$c - step$b
c = (step$D - b ^ 2) %/% step$c
list(
D = step$D, r = step$r, a = a, b = b, c = c
)
}
cf_all_steps <- function(D) {
step <- cf_init(D)
steps = step %>% as_tibble()
if (step$c != 0) {
while (step$a <= step$r) {
step <- cf_next(step)
steps <- bind_rows(steps,
step %>% as_tibble())
}
}
steps[-1, ]
}
cf_get_cf <- function(D) {
cf_all_steps(D) %>% select(D, a) %>% mutate(k = row_number())
}
MAX_D <- 100000
STEPS <- 110
density <- 2:MAX_D %>% setNames(nm = .) %>%
future_map(cf_get_cf) %>%
future_map( ~ count(., a)) %>%
future_map( ~ mutate(., density = n / sum(n))) %>%
bind_rows(.id = "D") %>%
mutate(D = as.integer(D))
allDs <- density$D %>% unique()
Ds <-
allDs[as.integer((length(allDs) ^ (1 / STEPS)) ^ (1:STEPS))] %>%
unique()
summarize_density <- function(density) {
density %>%
group_by(a) %>%
summarize(sum_density = sum(density)) %>%
mutate(density = sum_density / sum(sum_density)) %>%
select(-sum_density)
}
density_summary <- Ds %>% setNames(nm = .) %>%
map(~ filter(density, D <= .)) %>%
map_df(summarize_density, .id = "D") %>%
mutate(D = as.integer(D)) %>%
mutate(parity = factor(a %% 2, labels = c("Even numbers", "Odd numbers")))
density_reference <- tibble(a = 1:max(density_summary$a)) %>%
mutate(density = (2 * log(a + 1) - log(a) - log(a + 2)) / log(2))
equation_text <-
"italic(y) == 2 * plain(log)[2](italic(x)+1) - plain(log)[2](italic(x)) - plain(log)[2](italic(x)+2)"
title_text <-
"Frequency of numbers appearing in continued fraction of fractional part of \U221A n"
subtitle_text <- "For all \U221A n up to \U221A {closest_state}"
animation <- density_summary %>%
ggplot(aes(x = a, y = density)) +
geom_point(aes(color = parity)) +
geom_line(data = density_reference, mapping = aes(x = a, y = density)) +
scale_y_log10(
breaks = c(1, .1, .01, .001, .0001),
labels = c("1", ".1", ".01", ".001", ".0001")
) +
transition_states(D) +
shadow_wake(.1) +
labs(
title = str_wrap(width = 70, title_text),
subtitle = subtitle_text,
x = element_blank(),
y = "Frequency"
) +
theme(legend.position = "bottom",
legend.title = element_blank())
animation_log_scale <- animate(
animation +
scale_x_log10() +
annotate(
"text",
label = equation_text,
x = 40,
y = .1,
parse = TRUE
),
nframes = 213,
start_pause = 5,
end_pause = 10,
renderer = gifski_renderer()
)
animation_low_values <- animate(
animation +
xlim(1, 30) +
annotate(
"text",
label = equation_text,
x = 20,
y = .1,
parse = TRUE
),
nframes = 213,
start_pause = 5,
end_pause = 10,
renderer = gifski_renderer()
)
anim_save("cf_log_scale.gif", animation_log_scale)
anim_save("cf_low_values.gif", animation_low_values)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment