3b1b-manim/old_projects/256.py
2019-05-02 20:36:14 -07:00

912 lines
26 KiB
Python

from manimlib.imports import *
from old_projects.crypto import sha256_tex_mob, bit_string_to_mobject, BitcoinLogo
def get_google_logo():
result = SVGMobject(
file_name = "google_logo",
height = 0.75
)
blue, red, yellow, green = [
"#4885ed", "#db3236", "#f4c20d", "#3cba54"
]
colors = [red, yellow, blue, green, red, blue]
result.set_color_by_gradient(*colors)
return result
class LastVideo(Scene):
def construct(self):
title = TextMobject("Crypto", "currencies", arg_separator = "")
title[0].set_color(YELLOW)
title.scale(1.5)
title.to_edge(UP)
screen_rect = ScreenRectangle(height = 6)
screen_rect.next_to(title, DOWN)
self.add(title)
self.play(ShowCreation(screen_rect))
self.wait()
class BreakUp2To256(PiCreatureScene):
def construct(self):
self.initialize_bits()
self.add_number()
self.break_up_as_powers_of_two()
self.break_up_as_four_billions()
self.reorganize_four_billions()
def initialize_bits(self):
bits = bit_string_to_mobject("")
bits.to_corner(UP+LEFT)
one = TexMobject("1")[0]
one.replace(bits[0], dim_to_match = 1)
self.add(bits)
self.add_foreground_mobject(VGroup(*bits[-15:]))
self.number = 0
self.bits = bits
self.one = one
self.zero = bits[0].copy()
def add_number(self):
brace = Brace(self.bits, RIGHT)
number, possibilities = expression = TextMobject(
"$2^{256}$", "possibilities"
)
number.set_color(YELLOW)
expression.next_to(brace, RIGHT)
words = TextMobject("Seems big...I guess...")
words.next_to(self.pi_creature.get_corner(UP+LEFT), UP)
self.play(
self.pi_creature.change, "raise_right_hand",
GrowFromCenter(brace),
Write(expression, run_time = 1)
)
self.wait()
self.play(
self.pi_creature.change, "maybe",
Write(words)
)
self.wait(2)
self.play(
self.pi_creature.change, "happy",
FadeOut(words)
)
self.wait()
self.expression = expression
self.bits_brace = brace
def break_up_as_powers_of_two(self):
bits = self.bits
bits.generate_target()
subgroups = [
VGroup(*bits.target[32*i:32*(i+1)])
for i in range(8)
]
subexpressions = VGroup()
for i, subgroup in enumerate(subgroups):
subgroup.shift(i*MED_LARGE_BUFF*DOWN)
subexpression = TextMobject(
"$2^{32}$", "possibilities"
)
subexpression[0].set_color(GREEN)
subexpression.next_to(subgroup, RIGHT)
subexpressions.add(subexpression)
self.play(
FadeOut(self.bits_brace),
ReplacementTransform(
VGroup(self.expression),
subexpressions
),
MoveToTarget(bits)
)
self.play(self.pi_creature.change, "pondering")
self.wait()
self.subexpressions = subexpressions
def break_up_as_four_billions(self):
new_subexpressions = VGroup()
for subexpression in self.subexpressions:
new_subexpression = TextMobject(
"4 Billion", "possibilities"
)
new_subexpression[0].set_color(YELLOW)
new_subexpression.move_to(subexpression, LEFT)
new_subexpressions.add(new_subexpression)
self.play(
Transform(
self.subexpressions, new_subexpressions,
run_time = 2,
lag_ratio = 0.5,
),
FadeOut(self.pi_creature)
)
self.wait(3)
def reorganize_four_billions(self):
target = VGroup(*[
TextMobject(
"$\\big($", "4 Billion", "$\\big)$",
arg_separator = ""
)
for x in range(8)
])
target.arrange(RIGHT, buff = SMALL_BUFF)
target.to_edge(UP)
target.set_width(FRAME_WIDTH - LARGE_BUFF)
parens = VGroup(*it.chain(*[
[t[0], t[2]] for t in target
]))
target_four_billions = VGroup(*[t[1] for t in target])
target_four_billions.set_color(YELLOW)
four_billions, to_fade = [
VGroup(*[se[i] for se in self.subexpressions])
for i in range(2)
]
self.play(
self.bits.to_corner, DOWN+LEFT,
Transform(four_billions, target_four_billions),
LaggedStartMap(FadeIn, parens),
FadeOut(to_fade)
)
self.wait()
######
def wait(self, time = 1):
self.play(Animation(self.bits, run_time = time))
def update_frame(self, *args, **kwargs):
self.number += 1
new_bit_string = bin(self.number)[2:]
for i, bit in enumerate(reversed(new_bit_string)):
index = -i-1
bit_mob = self.bits[index]
if bit == "0":
new_mob = self.zero.copy()
else:
new_mob = self.one.copy()
new_mob.replace(bit_mob, dim_to_match = 1)
Transform(bit_mob, new_mob).update(1)
Scene.update_frame(self, *args, **kwargs)
class ShowTwoTo32(Scene):
def construct(self):
mob = TexMobject("2^{32} = 4{,}294{,}967{,}296")
mob.scale(1.5)
self.add(mob)
self.wait()
class MainBreakdown(Scene):
CONFIG = {
"n_group_rows" : 8,
"n_group_cols" : 8,
}
def construct(self):
self.add_four_billions()
self.gpu_packed_computer()
self.kilo_google()
self.half_all_people_on_earth()
self.four_billion_earths()
self.four_billion_galxies()
self.show_time_scale()
self.show_probability()
def add_four_billions(self):
top_line = VGroup()
four_billions = VGroup()
for x in range(8):
mob = TextMobject(
"$\\big($", "4 Billion", "$\\big)$",
arg_separator = ""
)
top_line.add(mob)
four_billions.add(mob[1])
top_line.arrange(RIGHT, buff = SMALL_BUFF)
top_line.set_width(FRAME_WIDTH - LARGE_BUFF)
top_line.to_edge(UP)
four_billions.set_color(YELLOW)
self.add(top_line)
self.top_line = top_line
self.four_billions = four_billions
def gpu_packed_computer(self):
self.show_gpu()
self.cram_computer_with_gpus()
def show_gpu(self):
gpu = SVGMobject(
file_name = "gpu",
height = 1,
fill_color = LIGHT_GREY,
)
name = TextMobject("Graphics", "Processing", "Unit")
for word in name:
word[0].set_color(BLUE)
name.to_edge(LEFT)
gpu.next_to(name, UP)
hash_names = VGroup(*[
TextMobject("hash")
for x in range(10)
])
hash_names.arrange(DOWN, buff = MED_SMALL_BUFF)
hash_names.next_to(name, RIGHT, buff = 2)
paths = VGroup()
for hash_name in hash_names:
hash_name.add_background_rectangle(opacity = 0.5)
path = VMobject()
start_point = name.get_right() + SMALL_BUFF*RIGHT
end_point = start_point + (4+hash_name.get_width())*RIGHT
path.set_points([
start_point,
start_point+RIGHT,
hash_name.get_left()+LEFT,
hash_name.get_left(),
hash_name.get_left(),
hash_name.get_right(),
hash_name.get_right(),
hash_name.get_right() + RIGHT,
end_point + LEFT,
end_point,
])
paths.add(path)
paths.set_stroke(width = 3)
paths.set_color_by_gradient(BLUE, GREEN)
def get_passing_flash():
return ShowPassingFlash(
paths,
lag_ratio = 0,
time_width = 0.7,
run_time = 2,
)
rate_words = TextMobject(
"$<$ 1 Billion", "Hashes/sec"
)
rate_words.next_to(name, DOWN)
self.play(FadeIn(name))
self.play(DrawBorderThenFill(gpu))
self.play(
get_passing_flash(),
FadeIn(hash_names)
)
for x in range(2):
self.play(
get_passing_flash(),
Animation(hash_names)
)
self.play(
Write(rate_words, run_time = 2),
get_passing_flash(),
Animation(hash_names)
)
self.play(get_passing_flash(), Animation(hash_names))
self.play(*list(map(FadeOut, [name, hash_names])))
self.gpu = gpu
self.rate_words = rate_words
def cram_computer_with_gpus(self):
gpu = self.gpu
gpus = VGroup(gpu, *[gpu.copy() for x in range(5)])
rate_words = self.rate_words
four_billion = self.four_billions[0]
laptop = Laptop()
laptop.next_to(rate_words, RIGHT)
laptop.to_edge(RIGHT)
new_rate_words = TextMobject("4 Billion", "Hashes/sec")
new_rate_words.move_to(rate_words)
new_rate_words[0].set_color(BLUE)
hps, h_line, target_laptop = self.get_fraction(
0, TextMobject("H/s"), Laptop()
)
hps.scale_in_place(0.7)
self.play(FadeIn(laptop))
self.play(
gpus.arrange, RIGHT, SMALL_BUFF,
gpus.next_to, rate_words, UP,
gpus.to_edge, LEFT
)
self.play(
Transform(
four_billion.copy(), new_rate_words[0],
remover = True,
),
Transform(rate_words, new_rate_words)
)
self.wait()
self.play(
LaggedStartMap(
ApplyFunction, gpus,
lambda g : (
lambda m : m.scale(0.01).move_to(laptop),
g
),
remover = True
)
)
self.wait()
self.play(
Transform(
rate_words[0], four_billion.copy().set_color(BLUE),
remover = True,
),
four_billion.set_color, BLUE,
Transform(rate_words[1], hps),
)
self.play(
Transform(laptop, target_laptop),
ShowCreation(h_line),
)
self.wait()
def kilo_google(self):
self.create_four_billion_copies(1, Laptop())
google = self.get_google_logo()
google.next_to(
self.group_of_four_billion_things, UP,
buff = LARGE_BUFF,
aligned_edge = LEFT
)
google.shift(RIGHT)
millions = TextMobject("$\\sim$ Millions of servers")
millions.next_to(google, RIGHT)
plus_plus = TexMobject("++")
plus_plus.next_to(google, RIGHT, SMALL_BUFF)
plus_plus.set_stroke(width = 2)
kilo = TextMobject("Kilo")
kilo.scale(1.5)
kilo.next_to(google[-1], LEFT, SMALL_BUFF, DOWN)
kilogoogle = VGroup(kilo, google, plus_plus)
four_billion = self.four_billions[1]
laptop, h_line, target_kilogoogle = self.get_fraction(
1, Laptop(), self.get_kilogoogle()
)
self.revert_to_original_skipping_status()
self.play(DrawBorderThenFill(google))
self.wait(2)
self.play(Write(millions))
self.wait(2)
self.play(LaggedStartMap(
Indicate, self.group_of_four_billion_things,
run_time = 4,
rate_func = there_and_back,
lag_ratio = 0.25,
))
self.play(FadeOut(millions), FadeIn(plus_plus))
self.play(Write(kilo))
self.wait()
self.play(
four_billion.restore,
FadeOut(self.group_of_four_billion_things)
)
self.play(
Transform(kilogoogle, target_kilogoogle),
FadeIn(laptop),
FadeIn(h_line),
)
self.wait()
def half_all_people_on_earth(self):
earth = self.get_earth()
people = TextMobject("7.3 Billion people")
people.next_to(earth, RIGHT)
group = VGroup(earth, people)
group.next_to(self.four_billions, DOWN, MED_LARGE_BUFF)
group.shift(RIGHT)
kg, h_line, target_earth = self.get_fraction(
2, self.get_kilogoogle(), self.get_earth(),
)
self.play(
GrowFromCenter(earth),
Write(people)
)
self.wait()
self.create_four_billion_copies(2, self.get_kilogoogle())
self.wait()
self.play(
self.four_billions[2].restore,
Transform(earth, target_earth),
FadeIn(h_line),
FadeIn(kg),
FadeOut(self.group_of_four_billion_things),
FadeOut(people)
)
self.wait()
def four_billion_earths(self):
self.create_four_billion_copies(
3, self.get_earth()
)
milky_way = ImageMobject("milky_way")
milky_way.set_height(3)
milky_way.to_edge(LEFT, buff = 0)
milky_way.shift(DOWN)
n_stars_estimate = TextMobject("100 to 400 \\\\ billion stars")
n_stars_estimate.next_to(milky_way, RIGHT)
n_stars_estimate.shift(UP)
earth, h_line, denom = self.get_fraction(
3, self.get_earth(), self.get_galaxy()
)
self.revert_to_original_skipping_status()
self.play(FadeIn(milky_way))
self.play(Write(n_stars_estimate))
self.wait()
self.play(LaggedStartMap(
Indicate, self.group_of_four_billion_things,
rate_func = there_and_back,
lag_ratio = 0.2,
run_time = 3,
))
self.wait()
self.play(
ReplacementTransform(
self.group_of_four_billion_things,
VGroup(earth)
),
ShowCreation(h_line),
FadeIn(denom),
self.four_billions[3].restore,
FadeOut(milky_way),
FadeOut(n_stars_estimate),
)
self.wait()
def four_billion_galxies(self):
self.create_four_billion_copies(4, self.get_galaxy())
num, h_line, denom = fraction = self.get_fraction(
4, self.get_galaxy(), TextMobject("GGSC").set_color(BLUE)
)
name = TextMobject(
"Giga", "Galactic \\\\", " Super", " Computer",
arg_separator = ""
)
for word in name:
word[0].set_color(BLUE)
name.next_to(self.group_of_four_billion_things, UP)
self.play(Write(name))
self.wait()
self.play(
self.four_billions[4].restore,
ReplacementTransform(
self.group_of_four_billion_things, VGroup(num),
run_time = 2,
lag_ratio = 0.5
),
ShowCreation(h_line),
ReplacementTransform(
name, denom
),
)
self.wait()
def show_time_scale(self):
fb1, fb2 = self.four_billions[5:7]
seconds_to_years = TextMobject("seconds $\\approx$ 126.8 years")
seconds_to_years.shift(LEFT)
years_to_eons = TextMobject(
"$\\times$ 126.8 years", "$\\approx$ 507 Billion years",
)
years_to_eons.next_to(
seconds_to_years, DOWN,
aligned_edge = LEFT,
)
universe_lifetimes = TextMobject("$\\approx 37 \\times$ Age of universe")
universe_lifetimes.next_to(
years_to_eons[1], DOWN,
aligned_edge = LEFT
)
for fb, words in (fb1, seconds_to_years), (fb2, years_to_eons):
self.play(
fb.scale, 1.3,
fb.next_to, words, LEFT,
fb.set_color, BLUE,
Write(words)
)
self.wait()
self.play(Write(universe_lifetimes))
self.wait()
def show_probability(self):
four_billion = self.four_billions[7]
words = TextMobject(
"1 in ", "4 Billion\\\\",
"chance of success"
)
words.next_to(four_billion, DOWN, buff = MED_LARGE_BUFF)
words.to_edge(RIGHT)
words[1].set_color(BLUE)
self.play(
Write(VGroup(*words[::2])),
Transform(four_billion, words[1])
)
self.wait()
############
def create_four_billion_copies(self, index, mobject):
four_billion = self.four_billions[index]
four_billion.set_color(BLUE)
four_billion.save_state()
group = VGroup(*[
VGroup(*[
mobject.copy().set_height(0.25)
for x in range(self.n_group_rows)
]).arrange(DOWN, buff = SMALL_BUFF)
for y in range(self.n_group_cols-1)
])
dots = TexMobject("\\dots")
group.add(dots)
group.add(*[group[0].copy() for x in range(2)])
group.arrange(RIGHT, buff = SMALL_BUFF)
group.set_height(FRAME_Y_RADIUS)
max_width = 1.25*FRAME_X_RADIUS
if group.get_width() > max_width:
group.set_width(max_width)
group.to_corner(DOWN+RIGHT)
group = VGroup(*it.chain(*group))
brace = Brace(group, LEFT)
self.play(
four_billion.scale, 2,
four_billion.next_to, brace, LEFT,
GrowFromCenter(brace),
LaggedStartMap(
FadeIn, group,
run_time = 3,
lag_ratio = 0.2
)
)
self.wait()
group.add_to_back(brace)
self.group_of_four_billion_things = group
def get_fraction(self, index, numerator, denominator):
four_billion = self.four_billions[index]
if hasattr(four_billion, "saved_state"):
four_billion = four_billion.saved_state
space = LARGE_BUFF
h_line = Line(LEFT, RIGHT)
h_line.set_width(four_billion.get_width())
h_line.next_to(four_billion, DOWN, space)
for mob in numerator, denominator:
mob.set_height(0.75*space)
max_width = h_line.get_width()
if mob.get_width() > max_width:
mob.set_width(max_width)
numerator.next_to(h_line, UP, SMALL_BUFF)
denominator.next_to(h_line, DOWN, SMALL_BUFF)
fraction = VGroup(numerator, h_line, denominator)
return fraction
def get_google_logo(self):
return get_google_logo()
def get_kilogoogle(self):
G = self.get_google_logo()[-1]
kilo = TextMobject("K")
kilo.scale(1.5)
kilo.next_to(G[-1], LEFT, SMALL_BUFF, DOWN)
plus_plus = TexMobject("++")
plus_plus.set_stroke(width = 1)
plus_plus.next_to(G, RIGHT, SMALL_BUFF)
return VGroup(kilo, G, plus_plus)
def get_earth(self):
earth = SVGMobject(
file_name = "earth",
height = 1.5,
fill_color = BLACK,
)
circle = Circle(
stroke_width = 3,
stroke_color = GREEN,
fill_opacity = 1,
fill_color = BLUE_C,
)
circle.replace(earth)
earth.add_to_back(circle)
return earth
def get_galaxy(self):
return SVGMobject(
file_name = "galaxy",
fill_opacity = 0,
stroke_width = 3,
stroke_color = WHITE,
height = 1,
)
class WriteTWoTo160(Scene):
def construct(self):
mob = TextMobject("$2^{160}$ ", "Hashes/sec")
mob[0].set_color(BLUE)
mob.scale(2)
self.play(Write(mob))
self.wait()
class StateOfBitcoin(TeacherStudentsScene):
def construct(self):
title = TextMobject("Total", "B", "mining")
title.to_edge(UP)
bitcoin_logo = BitcoinLogo()
bitcoin_logo.set_height(0.5)
bitcoin_logo.move_to(title[1])
title.remove(title[1])
rate = TextMobject(
"5 Billion Billion",
"$\\frac{\\text{Hashes}}{\\text{Second}}$"
)
rate.next_to(title, DOWN, MED_LARGE_BUFF)
google = get_google_logo()
kilo = TextMobject("Kilo")
kilo.scale(1.5)
kilo.next_to(google[-1], LEFT, SMALL_BUFF, DOWN)
third = TexMobject("1 \\over 3")
third.next_to(kilo, LEFT)
kilogoogle = VGroup(*it.chain(third, kilo, google))
kilogoogle.sort()
kilogoogle.next_to(rate, DOWN, MED_LARGE_BUFF)
rate.save_state()
rate.shift(DOWN)
rate.set_fill(opacity = 0)
all_text = VGroup(title, bitcoin_logo, rate, kilogoogle)
gpu = SVGMobject(
file_name = "gpu",
height = 1,
fill_color = LIGHT_GREY,
)
gpu.shift(0.5*FRAME_X_RADIUS*RIGHT)
gpu_name = TextMobject("GPU")
gpu_name.set_color(BLUE)
gpu_name.next_to(gpu, UP)
gpu_group = VGroup(gpu, gpu_name)
gpu_group.to_edge(UP)
cross = Cross(gpu_group)
gpu_group.add(cross)
asic = TextMobject(
"Application", "Specific\\\\", "Integrated", "Circuit"
)
for word in asic:
word[0].set_color(YELLOW)
asic.move_to(gpu)
asic.to_edge(UP)
asic.shift(LEFT)
circuit = SVGMobject(
file_name = "circuit",
height = asic.get_height(),
fill_color = WHITE,
)
random.shuffle(circuit.submobjects)
circuit.set_color_by_gradient(WHITE, GREY)
circuit.next_to(asic, RIGHT)
asic_rate = TextMobject("Trillion hashes/sec")
asic_rate.next_to(asic, DOWN, MED_LARGE_BUFF)
asic_rate.set_color(GREEN)
self.play(
Write(title),
DrawBorderThenFill(bitcoin_logo)
)
self.play(
self.teacher.change, "raise_right_hand",
rate.restore,
)
self.change_student_modes(*["pondering"]*3)
self.play(LaggedStartMap(FadeIn, kilogoogle))
self.change_student_modes(*["surprised"]*3)
self.wait()
self.change_student_modes(
*["plain"]*3,
added_anims = [
all_text.to_edge, LEFT,
self.teacher.change_mode, "happy"
],
look_at_arg = gpu
)
self.play(
Write(gpu_name),
DrawBorderThenFill(gpu)
)
self.play(ShowCreation(cross))
self.wait()
self.play(
Write(asic),
gpu_group.to_edge, DOWN,
self.teacher.change, "raise_right_hand",
)
self.change_student_modes(
*["pondering"]*3,
added_anims = [Write(asic_rate)]
)
self.play(LaggedStartMap(
FadeIn, circuit,
run_time = 3,
lag_ratio = 0.2,
))
self.wait()
class QAndA(PiCreatureScene):
def construct(self):
self.pi_creature.center().to_edge(DOWN)
self.show_powers_of_two()
num_subscriber_words = TexMobject(
"> 2^{18} = 262{,}144", "\\text{ subscribers}"
)
num_subscriber_words.to_edge(UP)
num_subscriber_words.shift(RIGHT)
num_subscriber_words.set_color_by_tex("subscribers", RED)
q_and_a = TextMobject("Q\\&A")
q_and_a.next_to(self.pi_creature.get_corner(UP+LEFT), UP)
q_and_a.save_state()
q_and_a.shift(DOWN)
q_and_a.set_fill(opacity = 0)
reddit = TextMobject("reddit.com/r/3blue1brown")
reddit.next_to(num_subscriber_words, DOWN, LARGE_BUFF)
twitter = TextMobject("@3blue1brown")
twitter.set_color(BLUE_C)
twitter.next_to(reddit, DOWN)
self.play(Write(num_subscriber_words))
self.play(self.pi_creature.change, "gracious", num_subscriber_words)
self.wait()
self.play(
q_and_a.restore,
self.pi_creature.change, "raise_right_hand",
)
self.wait()
self.play(Write(reddit))
self.wait()
self.play(
FadeIn(twitter),
self.pi_creature.change_mode, "shruggie"
)
self.wait(2)
def show_powers_of_two(self):
rows = 16
cols = 64
dots = VGroup(*[
VGroup(*[
Dot() for x in range(rows)
]).arrange(DOWN, buff = SMALL_BUFF)
for y in range(cols)
]).arrange(RIGHT, buff = SMALL_BUFF)
dots.set_width(FRAME_WIDTH - 2*LARGE_BUFF)
dots.next_to(self.pi_creature, UP)
dots = VGroup(*it.chain(*dots))
top = dots.get_top()
dots.sort(
lambda p : get_norm(p-top)
)
powers_of_two = VGroup(*[
Integer(2**i)
for i in range(int(np.log2(rows*cols))+1)
])
curr_power = powers_of_two[0]
curr_power.to_edge(UP)
self.play(
Write(curr_power),
FadeIn(dots[0])
)
for i, power_of_two in enumerate(powers_of_two):
if i == 0:
continue
power_of_two.to_edge(UP)
self.play(
FadeIn(VGroup(*dots[2**(i-1) : 2**i])),
Transform(
curr_power, power_of_two,
rate_func = squish_rate_func(smooth, 0, 0.5)
)
)
self.wait()
self.play(
FadeOut(dots),
FadeOut(powers_of_two)
)
class Thumbnail(Scene):
def construct(self):
num = TexMobject("2^{256}")
num.set_height(2)
num.set_color(BLUE_C)
num.set_stroke(BLUE_B, 3)
num.shift(MED_SMALL_BUFF*UP)
num.add_background_rectangle(opacity = 1)
num.background_rectangle.scale_in_place(1.5)
self.add(num)
background_num_str = "115792089237316195423570985008687907853269984665640564039457584007913129639936"
n_chars = len(background_num_str)
new_str = ""
for i, char in enumerate(background_num_str):
new_str += char
# if i%3 == 1:
# new_str += "{,}"
if i%(n_chars/4) == 0:
new_str += " \\\\ "
background_num = TexMobject(new_str)
background_num.set_width(FRAME_WIDTH - LARGE_BUFF)
background_num.set_fill(opacity = 0.2)
secure = TextMobject("Secure?")
secure.scale(4)
secure.shift(FRAME_Y_RADIUS*DOWN/2)
secure.set_color(RED)
secure.set_stroke(RED_A, 3)
lock = SVGMobject(
file_name = "shield_locked",
fill_color = WHITE,
)
lock.set_height(6)
self.add(background_num, num)