2017-08-24 11:44:06 -07:00
|
|
|
from helpers import *
|
|
|
|
|
|
|
|
from mobject.tex_mobject import TexMobject
|
|
|
|
from mobject import Mobject
|
|
|
|
from mobject.image_mobject import ImageMobject
|
|
|
|
from mobject.vectorized_mobject import *
|
|
|
|
|
|
|
|
from animation.animation import Animation
|
|
|
|
from animation.transform import *
|
|
|
|
from animation.simple_animations import *
|
|
|
|
from animation.playground import *
|
|
|
|
from topics.geometry import *
|
|
|
|
from topics.characters import *
|
|
|
|
from topics.functions import *
|
|
|
|
from topics.fractals import *
|
|
|
|
from topics.number_line import *
|
|
|
|
from topics.combinatorics import *
|
|
|
|
from topics.numerals import *
|
|
|
|
from topics.three_dimensions import *
|
|
|
|
from topics.objects import *
|
|
|
|
from topics.probability import *
|
|
|
|
from topics.complex_numbers import *
|
|
|
|
from scene import Scene
|
|
|
|
from scene.reconfigurable_scene import ReconfigurableScene
|
|
|
|
from scene.zoomed_scene import *
|
|
|
|
from camera import Camera
|
|
|
|
from mobject.svg_mobject import *
|
|
|
|
from mobject.tex_mobject import *
|
|
|
|
|
2017-08-25 17:56:55 -07:00
|
|
|
from waves import *
|
|
|
|
|
|
|
|
#force_skipping
|
|
|
|
#revert_to_original_skipping_status
|
|
|
|
|
|
|
|
class FilterScene(ThreeDScene):
|
|
|
|
CONFIG = {
|
|
|
|
"filter_x_coordinates" : [0],
|
|
|
|
"pol_filter_configs" : [{}],
|
|
|
|
"EMWave_config" : {
|
|
|
|
"start_point" : SPACE_WIDTH*LEFT + DOWN+OUT
|
|
|
|
},
|
|
|
|
"start_phi" : 0.8*np.pi/2,
|
|
|
|
"start_theta" : -0.6*np.pi,
|
|
|
|
"ambient_rotation_rate" : 0.01,
|
|
|
|
}
|
|
|
|
def setup(self):
|
|
|
|
self.axes = ThreeDAxes()
|
|
|
|
self.add(self.axes)
|
|
|
|
for x in range(len(self.filter_x_coordinates) - len(self.pol_filter_configs)):
|
|
|
|
self.pol_filter_configs.append({})
|
|
|
|
self.pol_filters = VGroup(*[
|
|
|
|
PolarizingFilter(**config)
|
|
|
|
for config in self.pol_filter_configs
|
|
|
|
])
|
|
|
|
self.pol_filters.rotate(np.pi/2, RIGHT)
|
|
|
|
self.pol_filters.rotate(-np.pi/2, OUT)
|
|
|
|
self.pol_filters.shift(DOWN+OUT)
|
|
|
|
for x, pf in zip(self.filter_x_coordinates, self.pol_filters):
|
|
|
|
pf.shift(x*RIGHT)
|
|
|
|
self.add(self.pol_filters)
|
|
|
|
self.pol_filter = self.pol_filters[0]
|
|
|
|
|
|
|
|
self.set_camera_position(self.start_phi, self.start_theta)
|
|
|
|
if self.ambient_rotation_rate > 0:
|
|
|
|
self.begin_ambient_camera_rotation(self.ambient_rotation_rate)
|
|
|
|
|
|
|
|
def get_filter_absorbtion_animation(self, pol_filter, photon):
|
|
|
|
x = pol_filter.get_center()[0]
|
|
|
|
alpha = (x + SPACE_WIDTH) / (2*SPACE_WIDTH)
|
|
|
|
return ApplyMethod(
|
|
|
|
pol_filter.set_fill, RED,
|
|
|
|
run_time = photon.run_time,
|
|
|
|
rate_func = squish_rate_func(there_and_back, alpha - 0.1, alpha + 0.1)
|
|
|
|
)
|
|
|
|
|
|
|
|
class DirectionOfPolarization(FilterScene):
|
|
|
|
CONFIG = {
|
|
|
|
"pol_filter_configs" : [{
|
|
|
|
"include_arrow_label" : False,
|
|
|
|
}],
|
|
|
|
"target_theta" : -0.97*np.pi,
|
|
|
|
"target_phi" : 0.9*np.pi/2,
|
|
|
|
"ambient_rotation_rate" : 0.005,
|
2017-08-29 20:00:48 -07:00
|
|
|
"apply_filter" : False,
|
2017-08-25 17:56:55 -07:00
|
|
|
}
|
|
|
|
def setup(self):
|
|
|
|
self.reference_line = Line(ORIGIN, RIGHT)
|
|
|
|
self.reference_line.set_stroke(width = 0)
|
|
|
|
self.em_wave = EMWave(**self.EMWave_config)
|
|
|
|
self.add(self.em_wave)
|
|
|
|
|
|
|
|
FilterScene.setup(self)
|
|
|
|
|
|
|
|
def construct(self):
|
|
|
|
self.remove(self.pol_filter)
|
|
|
|
words = TextMobject("Polarization direction")
|
|
|
|
words.next_to(ORIGIN, UP+RIGHT, LARGE_BUFF)
|
|
|
|
words.shift(2*UP)
|
|
|
|
words.rotate(np.pi/2, RIGHT)
|
|
|
|
words.rotate(-np.pi/2, OUT)
|
|
|
|
|
|
|
|
em_wave = self.em_wave
|
|
|
|
|
|
|
|
self.add(em_wave)
|
|
|
|
self.dither(2)
|
|
|
|
self.move_camera(
|
|
|
|
phi = self.target_phi,
|
|
|
|
theta = self.target_theta
|
|
|
|
)
|
|
|
|
self.play(Write(words, run_time = 1))
|
|
|
|
self.change_polarization_direction(
|
|
|
|
2*np.pi/3,
|
|
|
|
run_time = 6,
|
|
|
|
rate_func = there_and_back
|
|
|
|
)
|
|
|
|
self.dither(2)
|
|
|
|
|
|
|
|
def change_polarization_direction(self, angle, **kwargs):
|
|
|
|
added_anims = kwargs.get("added_anims", [])
|
|
|
|
self.play(
|
|
|
|
ApplyMethod(
|
|
|
|
self.reference_line.rotate, angle,
|
|
|
|
**kwargs
|
|
|
|
),
|
|
|
|
*added_anims
|
|
|
|
)
|
|
|
|
|
|
|
|
def continual_update(self):
|
2017-08-28 10:52:49 -07:00
|
|
|
reference_angle = self.reference_line.get_angle()
|
|
|
|
self.em_wave.rotation = reference_angle
|
2017-08-25 17:56:55 -07:00
|
|
|
FilterScene.continual_update(self)
|
2017-08-28 10:52:49 -07:00
|
|
|
vect_groups = [self.em_wave.E_vects, self.em_wave.M_vects]
|
2017-08-25 17:56:55 -07:00
|
|
|
if self.apply_filter:
|
2017-08-27 14:43:18 -07:00
|
|
|
filters = sorted(
|
|
|
|
self.pol_filters,
|
|
|
|
lambda pf1, pf2 : cmp(
|
|
|
|
pf1.get_center()[0],
|
|
|
|
pf2.get_center()[0],
|
2017-08-25 17:56:55 -07:00
|
|
|
)
|
2017-08-27 14:43:18 -07:00
|
|
|
)
|
|
|
|
for pol_filter in filters:
|
|
|
|
filter_x = pol_filter.get_center()[0]
|
2017-08-28 10:52:49 -07:00
|
|
|
for vect_group, angle in zip(vect_groups, [0, -np.pi/2]):
|
2017-08-27 14:43:18 -07:00
|
|
|
proj_vect = rotate_vector(
|
|
|
|
OUT, pol_filter.filter_angle + angle, RIGHT,
|
|
|
|
)
|
|
|
|
proj_matrix = np.array([RIGHT] + [
|
|
|
|
proj_vect*np.dot(proj_vect, basis)
|
|
|
|
for basis in UP, OUT
|
|
|
|
]).T
|
|
|
|
for vect in vect_group:
|
|
|
|
start, end = vect.get_start_and_end()
|
|
|
|
if start[0] > filter_x:
|
|
|
|
vect.apply_matrix(proj_matrix)
|
|
|
|
vect.shift(start - vect.get_start())
|
2017-08-28 10:52:49 -07:00
|
|
|
vect.set_tip_points(vect.tip)
|
|
|
|
vect.set_rectangular_stem_points()
|
2017-08-25 17:56:55 -07:00
|
|
|
|
2017-08-27 23:52:28 -07:00
|
|
|
class PhotonPassesCompletelyOrNotAtAll(DirectionOfPolarization):
|
|
|
|
CONFIG = {
|
|
|
|
"pol_filter_configs" : [{
|
|
|
|
"include_arrow_label" : False,
|
|
|
|
"label_tex" : "\\text{Filter}",
|
|
|
|
}],
|
|
|
|
"EMWave_config" : {
|
|
|
|
"wave_number" : 0,
|
|
|
|
"A_vect" : [0, 1, 1],
|
2017-08-30 20:05:25 -07:00
|
|
|
"start_point" : SPACE_WIDTH*LEFT + DOWN + 1.5*OUT,
|
2017-08-27 23:52:28 -07:00
|
|
|
},
|
|
|
|
"start_theta" : -0.9*np.pi,
|
|
|
|
"target_theta" : -0.6*np.pi,
|
2017-08-29 20:00:48 -07:00
|
|
|
"apply_filter" : True,
|
2017-08-30 20:05:25 -07:00
|
|
|
"lower_portion_shift" : 3*IN
|
2017-08-27 23:52:28 -07:00
|
|
|
}
|
|
|
|
def setup(self):
|
|
|
|
DirectionOfPolarization.setup(self)
|
|
|
|
self.continual_update()
|
|
|
|
for vect in it.chain(self.em_wave.E_vects, self.em_wave.M_vects):
|
|
|
|
vect.reset_normal_vector()
|
|
|
|
self.remove(self.em_wave)
|
|
|
|
|
|
|
|
def construct(self):
|
|
|
|
pol_filter = self.pol_filter
|
2017-08-30 20:05:25 -07:00
|
|
|
pol_filter.shift(0.5*OUT)
|
|
|
|
lower_filter = pol_filter.copy()
|
|
|
|
lower_filter.save_state()
|
|
|
|
pol_filter.remove(pol_filter.label)
|
2017-08-27 23:52:28 -07:00
|
|
|
|
|
|
|
passing_words = TextMobject("Photon", "passes through")
|
|
|
|
passing_words.highlight(GREEN)
|
|
|
|
filtered_words = TextMobject("Photon", "is blocked")
|
|
|
|
filtered_words.highlight(RED)
|
|
|
|
for words in passing_words, filtered_words:
|
|
|
|
words.next_to(ORIGIN, UP+LEFT)
|
|
|
|
words.shift(2*UP)
|
|
|
|
words.add_background_rectangle()
|
|
|
|
words.rotate(np.pi/2, RIGHT)
|
2017-08-30 20:05:25 -07:00
|
|
|
filtered_words.shift(self.lower_portion_shift)
|
2017-08-27 23:52:28 -07:00
|
|
|
|
|
|
|
passing_photon = WavePacket(
|
|
|
|
run_time = 2,
|
|
|
|
get_filtered = False,
|
|
|
|
em_wave = self.em_wave.copy()
|
|
|
|
)
|
2017-08-30 20:05:25 -07:00
|
|
|
lower_em_wave = self.em_wave.copy()
|
|
|
|
lower_em_wave.mobject.shift(self.lower_portion_shift)
|
|
|
|
lower_em_wave.start_point += self.lower_portion_shift
|
2017-08-27 23:52:28 -07:00
|
|
|
filtered_photon = WavePacket(
|
|
|
|
run_time = 2,
|
|
|
|
get_filtered = True,
|
2017-08-30 20:05:25 -07:00
|
|
|
em_wave = lower_em_wave.copy()
|
2017-08-27 23:52:28 -07:00
|
|
|
)
|
|
|
|
|
|
|
|
self.play(
|
|
|
|
DrawBorderThenFill(pol_filter),
|
2017-08-30 20:05:25 -07:00
|
|
|
Write(pol_filter.label, run_time = 2)
|
2017-08-27 23:52:28 -07:00
|
|
|
)
|
|
|
|
self.move_camera(theta = self.target_theta)
|
|
|
|
self.play(
|
2017-08-30 20:05:25 -07:00
|
|
|
lower_filter.restore,
|
|
|
|
lower_filter.shift, self.lower_portion_shift,
|
|
|
|
FadeIn(passing_words),
|
|
|
|
FadeIn(filtered_words)
|
2017-08-27 23:52:28 -07:00
|
|
|
)
|
2017-08-30 20:05:25 -07:00
|
|
|
for x in range(3):
|
|
|
|
self.play(
|
|
|
|
passing_photon,
|
|
|
|
filtered_photon,
|
|
|
|
ApplyMethod(
|
|
|
|
lower_filter.set_fill, RED,
|
|
|
|
rate_func = squish_rate_func(there_and_back, 0.4, 0.6),
|
|
|
|
run_time = filtered_photon.run_time
|
|
|
|
)
|
|
|
|
)
|
|
|
|
self.dither()
|
2017-08-27 23:52:28 -07:00
|
|
|
|
|
|
|
class PhotonsThroughPerpendicularFilters(PhotonPassesCompletelyOrNotAtAll):
|
2017-08-25 17:56:55 -07:00
|
|
|
CONFIG = {
|
|
|
|
"filter_x_coordinates" : [-2, 2],
|
|
|
|
"pol_filter_configs" : [
|
|
|
|
{"filter_angle" : 0},
|
|
|
|
{"filter_angle" : np.pi/2},
|
|
|
|
],
|
|
|
|
"start_theta" : -0.9*np.pi,
|
|
|
|
"target_theta" : -0.6*np.pi,
|
|
|
|
"EMWave_config" : {
|
2017-08-27 23:52:28 -07:00
|
|
|
"A_vect" : [0, 0, 1],
|
2017-08-30 20:05:25 -07:00
|
|
|
"start_point" : SPACE_WIDTH*LEFT + DOWN + OUT,
|
2017-08-25 17:56:55 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
def construct(self):
|
2017-08-30 20:05:25 -07:00
|
|
|
photons = self.get_photons()
|
2017-08-25 17:56:55 -07:00
|
|
|
prob_text = self.get_probability_text()
|
|
|
|
self.pol_filters = VGroup(*reversed(self.pol_filters))
|
|
|
|
|
|
|
|
self.play(LaggedStart(DrawBorderThenFill, self.pol_filters))
|
2017-08-30 20:05:25 -07:00
|
|
|
self.add_foreground_mobject(self.pol_filters)
|
2017-08-25 17:56:55 -07:00
|
|
|
self.move_camera(
|
|
|
|
theta = self.target_theta,
|
2017-08-30 20:05:25 -07:00
|
|
|
added_anims = list(it.chain(*[
|
|
|
|
[
|
|
|
|
pf.arrow_label.rotate_in_place, np.pi/2, OUT,
|
|
|
|
pf.arrow_label.next_to, pf.arrow, RIGHT,
|
|
|
|
]
|
|
|
|
for pf in self.pol_filters
|
|
|
|
]))
|
2017-08-25 17:56:55 -07:00
|
|
|
)
|
2017-08-30 20:05:25 -07:00
|
|
|
self.shoot_photon()
|
|
|
|
self.dither()
|
|
|
|
self.shoot_photon()
|
|
|
|
self.play(FadeIn(prob_text))
|
|
|
|
for x in range(8):
|
|
|
|
self.shoot_photon()
|
|
|
|
|
|
|
|
|
|
|
|
def shoot_photon(self, *added_anims):
|
|
|
|
photon = self.get_photons()[1]
|
|
|
|
pol_filter = self.pol_filters[0]
|
|
|
|
absorbtion = self.get_filter_absorbtion_animation(pol_filter, photon)
|
|
|
|
self.play(photon, absorbtion)
|
|
|
|
|
2017-08-25 17:56:55 -07:00
|
|
|
|
|
|
|
def get_photons(self):
|
|
|
|
self.reference_line.rotate(np.pi/4)
|
|
|
|
self.continual_update()
|
|
|
|
return [
|
|
|
|
WavePacket(
|
|
|
|
filter_distance = SPACE_WIDTH + x,
|
|
|
|
get_filtered = True,
|
|
|
|
em_wave = self.em_wave.copy(),
|
2017-08-27 23:52:28 -07:00
|
|
|
run_time = 1,
|
2017-08-25 17:56:55 -07:00
|
|
|
)
|
2017-08-27 14:43:18 -07:00
|
|
|
for x in -2, 2, 10
|
2017-08-25 17:56:55 -07:00
|
|
|
]
|
|
|
|
|
|
|
|
def get_probability_text(self, prob = 0):
|
|
|
|
prob_text = TexMobject(
|
|
|
|
"P(", "\\substack", "{\\text{photons that make it} \\\\ ",
|
|
|
|
" \\text{here } ", "\\text{make it}",
|
|
|
|
" \\text{ here} }", ")", "=", str(int(prob*100)), "\\%",
|
|
|
|
arg_separator = ""
|
|
|
|
)
|
|
|
|
here1, here2 = prob_text.get_parts_by_tex("here")
|
|
|
|
here1.highlight(GREEN)
|
|
|
|
here2.highlight(RED)
|
|
|
|
prob_text.add_background_rectangle()
|
|
|
|
prob_text.next_to(ORIGIN, UP+RIGHT)
|
|
|
|
prob_text.shift(2.5*UP+LEFT)
|
|
|
|
prob_text.rotate(np.pi/2, RIGHT)
|
|
|
|
arrows = [
|
|
|
|
Arrow(
|
|
|
|
here.get_edge_center(IN),
|
|
|
|
DOWN+OUT + x*RIGHT,
|
|
|
|
color = here.get_color(),
|
|
|
|
normal_vector = DOWN+OUT,
|
|
|
|
)
|
|
|
|
for here, x in (here1, 0), (here2, 4)
|
|
|
|
]
|
|
|
|
prob_text.add(*arrows)
|
|
|
|
|
|
|
|
return prob_text
|
|
|
|
|
2017-08-27 14:43:18 -07:00
|
|
|
class MoreFiltersMoreLight(FilterScene):
|
|
|
|
CONFIG = {
|
|
|
|
"filter_x_coordinates" : range(-2, 3),
|
|
|
|
"pol_filter_configs" : [
|
|
|
|
{
|
|
|
|
"include_arrow_label" : False,
|
|
|
|
"filter_angle" : angle
|
|
|
|
}
|
|
|
|
for angle in np.linspace(0, np.pi/2, 5)
|
|
|
|
],
|
|
|
|
"ambient_rotation_rate" : 0,
|
2017-08-30 20:05:25 -07:00
|
|
|
"arrow_rgb" : (0, 0, 0),
|
|
|
|
"background_rgb" : (245, 245, 245),
|
2017-08-27 14:43:18 -07:00
|
|
|
}
|
|
|
|
def construct(self):
|
|
|
|
self.remove(self.axes)
|
2017-08-30 18:54:34 -07:00
|
|
|
pfs = VGroup(*reversed(self.pol_filters))
|
2017-08-30 18:33:55 -07:00
|
|
|
self.color_filters(pfs)
|
2017-08-27 14:43:18 -07:00
|
|
|
self.remove(pfs)
|
2017-08-30 18:33:55 -07:00
|
|
|
self.build_color_map(pfs)
|
2017-08-30 18:54:34 -07:00
|
|
|
self.add(pfs[0], pfs[2], pfs[4])
|
|
|
|
pfs.center().scale(1.5)
|
2017-08-27 14:43:18 -07:00
|
|
|
|
|
|
|
self.move_camera(
|
|
|
|
phi = 0.9*np.pi/2,
|
|
|
|
theta = -0.95*np.pi,
|
|
|
|
)
|
2017-08-30 18:54:34 -07:00
|
|
|
self.play(
|
|
|
|
Animation(pfs[0]),
|
|
|
|
pfs[2].shift, 3*OUT,
|
|
|
|
Animation(pfs[4]),
|
|
|
|
)
|
|
|
|
self.dither()
|
|
|
|
self.play(
|
|
|
|
Animation(pfs[0]),
|
|
|
|
pfs[2].shift, 3*IN,
|
|
|
|
Animation(pfs[4]),
|
|
|
|
)
|
|
|
|
|
|
|
|
pfs[1].shift(8*OUT)
|
|
|
|
self.play(
|
|
|
|
Animation(pfs[0]),
|
|
|
|
pfs[1].shift, 8*IN,
|
|
|
|
Animation(VGroup(pfs[2], pfs[4])),
|
|
|
|
run_time = 2
|
|
|
|
)
|
|
|
|
self.dither()
|
|
|
|
|
|
|
|
pfs[3].shift(8*OUT)
|
|
|
|
self.play(
|
|
|
|
Animation(VGroup(*pfs[:3])),
|
|
|
|
pfs[3].shift, 8*IN,
|
|
|
|
Animation(VGroup(*pfs[4:])),
|
|
|
|
run_time = 2
|
|
|
|
)
|
2017-08-27 14:43:18 -07:00
|
|
|
self.dither()
|
|
|
|
|
2017-08-30 18:33:55 -07:00
|
|
|
def color_filters(self, pfs):
|
|
|
|
colors = [RED, GREEN, BLUE, MAROON_B, PURPLE_C]
|
|
|
|
for pf, color in zip(pfs, colors):
|
|
|
|
pf.set_fill(color, 0.5)
|
|
|
|
pf.arrow.set_fill(WHITE, 1)
|
|
|
|
turn_off_3d_shading(pfs)
|
|
|
|
|
|
|
|
def build_color_map(self, pfs):
|
|
|
|
phi, theta = self.camera.get_phi(), self.camera.get_theta()
|
|
|
|
self.set_camera_position(np.pi/2, -np.pi)
|
|
|
|
|
|
|
|
self.original_rgbs = [(255, 255, 255)]
|
2017-08-30 20:05:25 -07:00
|
|
|
self.new_rgbs = [self.arrow_rgb]
|
2017-08-30 18:33:55 -07:00
|
|
|
for bool_array in it.product(*5*[[True, False]]):
|
|
|
|
pfs_to_use = VGroup(*[
|
|
|
|
pf
|
2017-08-30 18:54:34 -07:00
|
|
|
for pf, b in zip(pfs, bool_array)
|
2017-08-30 18:33:55 -07:00
|
|
|
if b
|
|
|
|
])
|
|
|
|
self.camera.capture_mobject(pfs_to_use)
|
|
|
|
frame = self.camera.get_image()
|
|
|
|
h, w, three = frame.shape
|
|
|
|
rgb = frame[3*h/8, 7*w/12]
|
|
|
|
self.original_rgbs.append(rgb)
|
|
|
|
|
|
|
|
angles = [pf.filter_angle for pf in pfs_to_use]
|
|
|
|
p = 0.5
|
|
|
|
for a1, a2 in zip(angles, angles[1:]):
|
|
|
|
p *= np.cos(a2 - a1)**2
|
|
|
|
new_rgb = (255*p*np.ones(3)).astype(int)
|
|
|
|
if not any(bool_array):
|
2017-08-30 20:05:25 -07:00
|
|
|
new_rgb = self.background_rgb
|
2017-08-30 18:33:55 -07:00
|
|
|
|
|
|
|
self.new_rgbs.append(new_rgb)
|
|
|
|
self.camera.reset()
|
|
|
|
self.set_camera_position(phi, theta)
|
|
|
|
|
2017-08-30 20:05:25 -07:00
|
|
|
def update_frame(self, mobjects = None, image = None):
|
|
|
|
FilterScene.update_frame(self, mobjects)
|
|
|
|
|
2017-08-30 18:33:55 -07:00
|
|
|
def get_frame(self):
|
|
|
|
frame = FilterScene.get_frame(self)
|
|
|
|
bool_arrays = [
|
|
|
|
(frame[:,:,0] == r) & (frame[:,:,1] == g) & (frame[:,:,2] == b)
|
|
|
|
for (r, g, b) in self.original_rgbs
|
|
|
|
]
|
|
|
|
for ba, new_rgb in zip(bool_arrays, self.new_rgbs):
|
|
|
|
frame[ba] = new_rgb
|
|
|
|
covered = reduce(
|
|
|
|
lambda b1, b2 : b1 | b2,
|
|
|
|
bool_arrays
|
|
|
|
)
|
2017-08-30 18:54:34 -07:00
|
|
|
frame[~covered] = [65, 65, 65]
|
2017-08-30 18:33:55 -07:00
|
|
|
return frame
|
|
|
|
|
2017-08-30 20:05:25 -07:00
|
|
|
class MoreFiltersMoreLightBlackBackground(MoreFiltersMoreLight):
|
|
|
|
CONFIG = {
|
|
|
|
"arrow_rgb" : (255, 255, 255),
|
|
|
|
"background_rgb" : (0, 0, 0),
|
|
|
|
}
|
|
|
|
|
2017-08-27 14:43:18 -07:00
|
|
|
class ConfusedPiCreature(Scene):
|
|
|
|
def construct(self):
|
|
|
|
randy = Randolph()
|
|
|
|
self.play(
|
|
|
|
randy.change, "confused", 3*(UP+RIGHT),
|
|
|
|
)
|
|
|
|
self.play(Blink(randy))
|
|
|
|
self.dither(2)
|
|
|
|
self.play(Blink(randy))
|
|
|
|
self.dither(2)
|
|
|
|
|
2017-08-25 17:56:55 -07:00
|
|
|
class AngryPiCreature(PiCreatureScene):
|
|
|
|
def construct(self):
|
|
|
|
self.pi_creature_says(
|
|
|
|
"No, \\emph{locality} \\\\ must be wrong!",
|
|
|
|
target_mode = "angry",
|
|
|
|
look_at_arg = 2*RIGHT,
|
|
|
|
run_time = 1
|
|
|
|
)
|
|
|
|
self.dither(3)
|
|
|
|
|
|
|
|
def create_pi_creature(self):
|
|
|
|
return Randolph().shift(DOWN+3*LEFT)
|
|
|
|
|
|
|
|
class ShowALittleMath(TeacherStudentsScene):
|
|
|
|
def construct(self):
|
2017-08-30 20:05:25 -07:00
|
|
|
exp1 = TexMobject(
|
|
|
|
"|", "\\psi", "\\rangle = ",
|
|
|
|
"\\alpha", "|\\uparrow\\rangle",
|
|
|
|
"+", "\\beta", "|\\rightarrow\\rangle"
|
2017-08-25 17:56:55 -07:00
|
|
|
)
|
2017-08-30 20:05:25 -07:00
|
|
|
exp2 = TexMobject(
|
|
|
|
"|| \\langle", "\\psi", "|", "\\psi", "\\rangle ||^2",
|
|
|
|
"= ", "\\alpha", "^2", "+", "\\beta", "^2"
|
|
|
|
)
|
|
|
|
color_map = {
|
|
|
|
"alpha" : GREEN,
|
|
|
|
"beta" : RED,
|
|
|
|
"psi" : BLUE
|
|
|
|
}
|
|
|
|
for exp in exp1, exp2:
|
|
|
|
exp.highlight_by_tex_to_color_map(color_map)
|
|
|
|
exp1.next_to(self.teacher.get_corner(UP+LEFT), UP, LARGE_BUFF)
|
2017-08-25 17:56:55 -07:00
|
|
|
|
2017-08-30 20:05:25 -07:00
|
|
|
exp2.move_to(exp1)
|
2017-08-25 17:56:55 -07:00
|
|
|
|
|
|
|
self.play(
|
2017-08-30 20:05:25 -07:00
|
|
|
Write(exp1, run_time = 2),
|
2017-08-25 17:56:55 -07:00
|
|
|
self.teacher.change, "raise_right_hand"
|
|
|
|
)
|
2017-08-30 20:05:25 -07:00
|
|
|
self.play(exp1.shift, UP)
|
2017-08-31 00:16:08 -07:00
|
|
|
self.play(*[
|
2017-08-30 20:05:25 -07:00
|
|
|
ReplacementTransform(
|
|
|
|
exp1.get_parts_by_tex(tex).copy(),
|
|
|
|
exp2.get_parts_by_tex(tex).copy(),
|
|
|
|
)
|
|
|
|
for tex in color_map.keys()
|
2017-08-31 00:16:08 -07:00
|
|
|
] + [Write(exp2, run_time = 2)])
|
2017-08-25 17:56:55 -07:00
|
|
|
self.change_student_modes(
|
|
|
|
*["pondering"]*3,
|
2017-08-30 20:05:25 -07:00
|
|
|
look_at_arg = exp2
|
2017-08-25 17:56:55 -07:00
|
|
|
)
|
|
|
|
self.dither(2)
|
|
|
|
|
|
|
|
class SecondVideoWrapper(Scene):
|
|
|
|
def construct(self):
|
|
|
|
title = TextMobject("Some light quantum mechanics")
|
|
|
|
title.to_edge(UP)
|
|
|
|
self.add(title)
|
|
|
|
|
|
|
|
screen_rect = ScreenRectangle(height = 6)
|
|
|
|
screen_rect.next_to(title, DOWN)
|
|
|
|
self.play(ShowCreation(screen_rect))
|
|
|
|
self.dither(3)
|
|
|
|
|
|
|
|
class BasicsOfPolarization(DirectionOfPolarization):
|
2017-08-29 20:00:48 -07:00
|
|
|
CONFIG = {
|
|
|
|
"apply_filter" : True,
|
|
|
|
}
|
2017-08-25 17:56:55 -07:00
|
|
|
def construct(self):
|
2017-08-31 00:16:08 -07:00
|
|
|
self.setup_rectangles()
|
2017-08-25 17:56:55 -07:00
|
|
|
self.show_continual_wave()
|
2017-08-28 15:18:57 -07:00
|
|
|
self.show_photons()
|
2017-08-25 17:56:55 -07:00
|
|
|
|
2017-08-31 00:16:08 -07:00
|
|
|
def setup_rectangles(self):
|
|
|
|
rect1 = Rectangle(
|
|
|
|
height = 2*self.em_wave.amplitude,
|
|
|
|
width = SPACE_WIDTH + 0.25,
|
|
|
|
stroke_color = BLUE,
|
|
|
|
fill_color = BLUE,
|
|
|
|
fill_opacity = 0.2,
|
|
|
|
)
|
|
|
|
rect1.rotate(np.pi/2, RIGHT)
|
|
|
|
pf_copy = self.pol_filter.deepcopy()
|
|
|
|
pf_copy.remove(pf_copy.arrow)
|
|
|
|
center = pf_copy.get_center()
|
|
|
|
rect1.move_to(center, RIGHT)
|
|
|
|
rect2 = rect1.copy()
|
|
|
|
rect2.move_to(center, LEFT)
|
|
|
|
|
|
|
|
self.rectangles = VGroup(rect1, rect2)
|
|
|
|
|
2017-08-25 17:56:55 -07:00
|
|
|
def show_continual_wave(self):
|
|
|
|
em_wave = self.em_wave
|
|
|
|
|
|
|
|
title = TextMobject("Waves in the ``electromagnetic field''")
|
|
|
|
title.to_edge(UP)
|
|
|
|
subtitle = TextMobject("Polarization = Direction of", "wiggling")
|
2017-08-31 00:16:08 -07:00
|
|
|
subtitle.highlight_by_tex("wiggling", BLUE)
|
2017-08-25 17:56:55 -07:00
|
|
|
subtitle.next_to(title, DOWN)
|
|
|
|
for words in title, subtitle:
|
|
|
|
words.add_background_rectangle()
|
|
|
|
words.rotate(np.pi/2, RIGHT)
|
|
|
|
|
|
|
|
self.play(Write(title))
|
|
|
|
self.dither(2)
|
2017-08-31 00:16:08 -07:00
|
|
|
self.play(
|
|
|
|
Write(subtitle, run_time = 2),
|
|
|
|
FadeIn(self.rectangles)
|
|
|
|
)
|
2017-08-25 17:56:55 -07:00
|
|
|
self.change_polarization_direction(np.pi/2, run_time = 3)
|
|
|
|
self.dither()
|
2017-08-31 00:16:08 -07:00
|
|
|
self.change_polarization_direction(-np.pi/12, run_time = 2)
|
2017-08-25 17:56:55 -07:00
|
|
|
self.move_camera(theta = -0.95*np.pi)
|
|
|
|
self.change_polarization_direction(-np.pi/6, run_time = 2)
|
2017-08-31 00:16:08 -07:00
|
|
|
self.change_polarization_direction(np.pi/6, run_time = 2)
|
2017-08-25 17:56:55 -07:00
|
|
|
self.move_camera(theta = -0.6*np.pi)
|
2017-08-31 00:16:08 -07:00
|
|
|
self.change_polarization_direction(-np.pi/6, run_time = 2)
|
|
|
|
self.change_polarization_direction(np.pi/6, run_time = 2)
|
|
|
|
self.change_polarization_direction(-5*np.pi/12, run_time = 2)
|
|
|
|
self.play(
|
|
|
|
FadeOut(em_wave.mobject),
|
|
|
|
FadeOut(self.rectangles),
|
|
|
|
)
|
2017-08-25 17:56:55 -07:00
|
|
|
self.remove(em_wave)
|
|
|
|
self.reference_line.put_start_and_end_on(ORIGIN, RIGHT)
|
|
|
|
|
|
|
|
def show_photons(self):
|
|
|
|
quantum_left_words = TextMobject(
|
|
|
|
"Quantum", "$\\Rightarrow$",
|
|
|
|
)
|
|
|
|
quantum_left_words.next_to(ORIGIN, UP+RIGHT)
|
|
|
|
quantum_left_words.shift(UP)
|
|
|
|
quantum_right_words = TextMobject(
|
|
|
|
"Completely through", "or \\\\",
|
|
|
|
"Completely blocked",
|
|
|
|
)
|
|
|
|
quantum_right_words.scale(0.8)
|
|
|
|
quantum_right_words.next_to(quantum_left_words, buff = 0)
|
|
|
|
quantum_right_words.highlight_by_tex("through", GREEN)
|
|
|
|
quantum_right_words.highlight_by_tex("blocked", RED)
|
|
|
|
quantum_words = VGroup(quantum_left_words, quantum_right_words)
|
|
|
|
quantum_words.rotate(np.pi/2, RIGHT)
|
|
|
|
|
2017-08-31 00:16:08 -07:00
|
|
|
prob_eq = TexMobject(
|
|
|
|
"&P(", "\\text{Pass}", ")", "=", "p\\\\",
|
|
|
|
"&P(", "\\text{Blocked}", ")", "=", "1-p",
|
|
|
|
)
|
|
|
|
prob_eq.highlight_by_tex_to_color_map({
|
|
|
|
"Pass" : GREEN,
|
|
|
|
"Blocked" : RED,
|
|
|
|
})
|
|
|
|
prob_eq.next_to(ORIGIN, DOWN+RIGHT)
|
|
|
|
prob_eq.shift(RIGHT)
|
|
|
|
prob_eq.rotate(np.pi/2, RIGHT)
|
|
|
|
|
2017-08-25 17:56:55 -07:00
|
|
|
config = dict(self.EMWave_config)
|
|
|
|
config.update({
|
|
|
|
"wave_number" : 0,
|
2017-08-27 23:52:28 -07:00
|
|
|
"A_vect" : [0, 1, -1],
|
2017-08-25 17:56:55 -07:00
|
|
|
})
|
|
|
|
self.em_wave = EMWave(**config)
|
|
|
|
self.continual_update()
|
|
|
|
passing_photon = WavePacket(
|
|
|
|
em_wave = self.em_wave.copy(),
|
2017-08-31 00:16:08 -07:00
|
|
|
run_time = 1.5,
|
2017-08-25 17:56:55 -07:00
|
|
|
)
|
|
|
|
filtered_photon = WavePacket(
|
|
|
|
em_wave = self.em_wave.copy(),
|
|
|
|
get_filtered = True,
|
2017-08-31 00:16:08 -07:00
|
|
|
run_time = 1.5,
|
2017-08-25 17:56:55 -07:00
|
|
|
)
|
|
|
|
|
|
|
|
self.play(FadeIn(
|
|
|
|
quantum_words,
|
|
|
|
run_time = 2,
|
|
|
|
submobject_mode = "lagged_start"
|
|
|
|
))
|
|
|
|
anim_sets = [
|
|
|
|
[passing_photon],
|
|
|
|
[
|
|
|
|
filtered_photon,
|
|
|
|
self.get_filter_absorbtion_animation(
|
|
|
|
self.pol_filter,
|
|
|
|
filtered_photon
|
|
|
|
)
|
|
|
|
],
|
|
|
|
]
|
2017-08-31 00:16:08 -07:00
|
|
|
|
|
|
|
for index in 0, 1:
|
|
|
|
self.play(*anim_sets[index])
|
|
|
|
self.play(
|
|
|
|
FadeIn(prob_eq, submobject_mode = "lagged_start"),
|
|
|
|
passing_photon
|
|
|
|
)
|
|
|
|
for index in 1, 0, 0, 1:
|
2017-08-25 17:56:55 -07:00
|
|
|
self.play(*anim_sets[index])
|
|
|
|
|
2017-08-31 00:16:08 -07:00
|
|
|
def continual_update(self):
|
|
|
|
DirectionOfPolarization.continual_update(self)
|
|
|
|
if self.rectangles not in self.mobjects:
|
|
|
|
return
|
|
|
|
|
|
|
|
r1, r2 = self.rectangles
|
|
|
|
|
|
|
|
target_angle = self.reference_line.get_angle()
|
|
|
|
anchors = r1.get_anchors()
|
|
|
|
vect = anchors[0] - anchors[3]
|
|
|
|
curr_angle = angle_of_vector([vect[2], -vect[1]])
|
|
|
|
r1.rotate_in_place(target_angle - curr_angle, RIGHT)
|
|
|
|
|
|
|
|
curr_depth = r2.get_depth()
|
|
|
|
target_depth = 2*self.em_wave.amplitude*np.cos(target_angle)
|
|
|
|
if target_depth == 0:
|
|
|
|
target_depth = 0.001
|
|
|
|
r2.stretch_in_place(target_depth/curr_depth, 2)
|
|
|
|
|
|
|
|
|
|
|
|
|
2017-08-25 17:56:55 -07:00
|
|
|
class AngleToProbabilityChart(Scene):
|
|
|
|
def construct(self):
|
2017-08-28 15:18:57 -07:00
|
|
|
left_title = TextMobject("Angle between \\\\ filters")
|
|
|
|
left_title.to_corner(UP+LEFT)
|
|
|
|
right_title = TextMobject(
|
|
|
|
"Probability that photons passing \\\\",
|
|
|
|
"through the first pass through the second"
|
2017-08-25 17:56:55 -07:00
|
|
|
)
|
2017-08-28 15:18:57 -07:00
|
|
|
right_title.next_to(left_title, RIGHT, LARGE_BUFF)
|
|
|
|
|
|
|
|
h_line = Line(LEFT, RIGHT).scale(SPACE_WIDTH)
|
|
|
|
h_line.to_edge(UP, buff = 2)
|
|
|
|
v_line = Line(UP, DOWN).scale(SPACE_HEIGHT)
|
|
|
|
v_line.next_to(left_title, RIGHT, MED_LARGE_BUFF)
|
|
|
|
v_line.to_edge(UP, buff = 0)
|
|
|
|
VGroup(h_line, v_line).highlight(BLUE)
|
|
|
|
self.add(left_title, right_title, h_line, v_line)
|
|
|
|
|
2017-08-29 00:04:25 -07:00
|
|
|
angles = [0, 22.5, 45, 67.5, 90]
|
2017-08-28 15:18:57 -07:00
|
|
|
angle_mobs = VGroup(*[
|
|
|
|
TexMobject(str(angle) + "^\\circ")
|
|
|
|
for angle in angles
|
|
|
|
])
|
|
|
|
angle_mobs.arrange_submobjects(DOWN, buff = MED_LARGE_BUFF)
|
|
|
|
angle_mobs.next_to(left_title, DOWN, LARGE_BUFF)
|
|
|
|
|
|
|
|
probs = [
|
|
|
|
np.cos(angle*np.pi/180.0)**2
|
|
|
|
for angle in angles
|
|
|
|
]
|
|
|
|
prob_mobs = VGroup(*[
|
|
|
|
TexMobject("%.1f"%(100*prob) + "\\%")
|
|
|
|
for prob in probs
|
|
|
|
])
|
|
|
|
prob_mobs.highlight(YELLOW)
|
|
|
|
|
|
|
|
angle_prob_pairs = zip(angle_mobs, prob_mobs)
|
|
|
|
for angle_mob, prob_mob in angle_prob_pairs:
|
|
|
|
prob_mob.next_to(angle_mob, RIGHT, buff = 3)
|
|
|
|
for prob_mob in prob_mobs[1:]:
|
|
|
|
prob_mob.align_to(prob_mobs[0], LEFT)
|
|
|
|
|
|
|
|
|
2017-08-29 00:04:25 -07:00
|
|
|
for i in [0, 4, 2, 1, 3]:
|
2017-08-28 15:18:57 -07:00
|
|
|
self.play(FadeIn(angle_mobs[i]))
|
|
|
|
self.play(ReplacementTransform(
|
|
|
|
angle_mobs[i].copy(), prob_mobs[i]
|
|
|
|
))
|
|
|
|
|
|
|
|
explanation = TextMobject("Based on $\\cos(\\theta)^2$")
|
|
|
|
explanation.next_to(prob_mobs, RIGHT, LARGE_BUFF)
|
|
|
|
self.play(Write(explanation, run_time = 2))
|
|
|
|
self.dither()
|
2017-08-25 17:56:55 -07:00
|
|
|
|
2017-08-29 00:04:25 -07:00
|
|
|
class ShowVariousFilterPairsWithPhotonsOverTime(PhotonsThroughPerpendicularFilters):
|
2017-08-25 17:56:55 -07:00
|
|
|
CONFIG = {
|
|
|
|
"filter_x_coordinates" : [-2, 2, 2, 2, 2],
|
|
|
|
"pol_filter_configs" : [
|
|
|
|
{"filter_angle" : angle}
|
|
|
|
for angle in 0, 0, np.pi/2, np.pi/4, np.pi/8
|
|
|
|
],
|
2017-08-28 15:18:57 -07:00
|
|
|
"apply_filter" : False,
|
2017-08-25 17:56:55 -07:00
|
|
|
}
|
2017-08-29 00:04:25 -07:00
|
|
|
def setup(self):
|
|
|
|
PhotonsThroughPerpendicularFilters.setup(self)
|
|
|
|
self.new_filters = self.pol_filters[2:]
|
|
|
|
self.remove(*self.new_filters)
|
|
|
|
self.pol_filters = self.pol_filters[:2]
|
|
|
|
|
2017-08-25 17:56:55 -07:00
|
|
|
def construct(self):
|
|
|
|
self.photons = self.get_photons()
|
|
|
|
|
|
|
|
self.add_filters()
|
|
|
|
self.add_probability_text()
|
|
|
|
self.show_photons()
|
2017-08-29 00:04:25 -07:00
|
|
|
for pol_filter in self.new_filters:
|
2017-08-25 17:56:55 -07:00
|
|
|
self.change_to_new_filter(pol_filter)
|
|
|
|
self.show_photons()
|
|
|
|
|
|
|
|
def add_filters(self):
|
|
|
|
self.remove(*self.pol_filters[1:])
|
|
|
|
self.dither()
|
|
|
|
self.play(ReplacementTransform(
|
|
|
|
self.pol_filters[0].copy().set_fill(BLACK, 1),
|
|
|
|
self.pol_filters[1]
|
|
|
|
))
|
|
|
|
self.move_camera(
|
2017-08-29 00:04:25 -07:00
|
|
|
theta = -0.65*np.pi,
|
2017-08-25 17:56:55 -07:00
|
|
|
added_anims = list(it.chain(*[
|
|
|
|
[
|
|
|
|
pf.arrow_label.rotate_in_place, np.pi/2, OUT,
|
|
|
|
pf.arrow_label.next_to, pf.arrow, RIGHT
|
|
|
|
]
|
|
|
|
for pf in self.pol_filters[:2]
|
|
|
|
]))
|
|
|
|
)
|
2017-08-27 23:52:28 -07:00
|
|
|
for pf in self.new_filters:
|
2017-08-25 17:56:55 -07:00
|
|
|
pf.arrow_label.rotate_in_place(np.pi/2, OUT)
|
|
|
|
pf.arrow_label.next_to(pf.arrow, RIGHT)
|
|
|
|
|
|
|
|
self.second_filter = self.pol_filters[1]
|
|
|
|
self.add_foreground_mobject(self.second_filter)
|
|
|
|
|
|
|
|
def add_probability_text(self):
|
|
|
|
prob_text = self.get_probability_text(self.get_prob())
|
|
|
|
self.play(FadeIn(prob_text))
|
|
|
|
self.prob_text = prob_text
|
|
|
|
|
|
|
|
def show_photons(self, n_photons = 5):
|
|
|
|
p = self.get_prob()
|
2017-08-27 23:52:28 -07:00
|
|
|
blocked_photon = copy.deepcopy(self.photons[0])
|
|
|
|
blocked_photon.rate_func = squish_rate_func(
|
|
|
|
lambda x : x, 0, 0.5,
|
|
|
|
)
|
|
|
|
first_absorbtion = self.get_filter_absorbtion_animation(
|
|
|
|
self.pol_filters[0], blocked_photon
|
|
|
|
)
|
|
|
|
first_absorbtion.rate_func = squish_rate_func(
|
|
|
|
first_absorbtion.rate_func, 0, 0.5,
|
|
|
|
)
|
|
|
|
|
2017-08-25 17:56:55 -07:00
|
|
|
photons = [
|
2017-08-28 15:18:57 -07:00
|
|
|
copy.deepcopy(self.photons[2 if q <= p else 1])
|
|
|
|
for q in np.arange(0, 1, 1./n_photons)
|
2017-08-25 17:56:55 -07:00
|
|
|
]
|
2017-08-28 15:18:57 -07:00
|
|
|
random.shuffle(photons)
|
2017-08-25 17:56:55 -07:00
|
|
|
for photon in photons:
|
2017-08-27 23:52:28 -07:00
|
|
|
photon.rate_func = squish_rate_func(
|
|
|
|
lambda x : x, 0.5, 1
|
|
|
|
)
|
2017-08-25 17:56:55 -07:00
|
|
|
added_anims = []
|
2017-08-27 23:52:28 -07:00
|
|
|
if photon.filter_distance == SPACE_WIDTH + 2:
|
|
|
|
absorbtion = self.get_filter_absorbtion_animation(
|
2017-08-25 17:56:55 -07:00
|
|
|
self.second_filter, photon
|
2017-08-27 23:52:28 -07:00
|
|
|
)
|
|
|
|
absorbtion.rate_func = squish_rate_func(
|
|
|
|
absorbtion.rate_func, 0.5, 1
|
|
|
|
)
|
|
|
|
added_anims.append(absorbtion)
|
|
|
|
self.play(
|
|
|
|
blocked_photon,
|
|
|
|
first_absorbtion,
|
|
|
|
photon,
|
|
|
|
*added_anims
|
|
|
|
)
|
2017-08-25 17:56:55 -07:00
|
|
|
self.dither()
|
|
|
|
|
2017-08-29 00:04:25 -07:00
|
|
|
def change_to_new_filter(self, pol_filter, added_anims = None):
|
|
|
|
if added_anims is None:
|
|
|
|
added_anims = []
|
|
|
|
self.play(
|
|
|
|
Transform(self.second_filter, pol_filter),
|
|
|
|
*added_anims
|
|
|
|
)
|
2017-08-25 17:56:55 -07:00
|
|
|
self.second_filter.filter_angle = pol_filter.filter_angle
|
|
|
|
new_prob_text = self.get_probability_text(self.get_prob())
|
|
|
|
new_prob_text[1][-2].highlight(YELLOW)
|
|
|
|
self.play(Transform(self.prob_text, new_prob_text))
|
|
|
|
|
|
|
|
####
|
|
|
|
|
2017-08-29 00:04:25 -07:00
|
|
|
def get_prob(self, pol_filter = None):
|
|
|
|
if pol_filter is None:
|
|
|
|
pol_filter = self.second_filter
|
|
|
|
return np.cos(pol_filter.filter_angle)**2
|
|
|
|
|
|
|
|
class ShowVariousFilterPairs(ShowVariousFilterPairsWithPhotonsOverTime):
|
|
|
|
CONFIG = {
|
2017-08-31 00:16:08 -07:00
|
|
|
"filter_x_coordinates" : [],
|
|
|
|
"filter_z_coordinates" : [2.5, 0, -2.5],
|
|
|
|
"angles" : [0, np.pi/4, np.pi/2],
|
2017-08-29 00:04:25 -07:00
|
|
|
"n_lines" : 20,
|
|
|
|
"line_start_length" : 16,
|
|
|
|
"line_end_length" : 16,
|
|
|
|
"new_group_shift_val" : 2.5*IN,
|
|
|
|
"prev_group_shift_val" : 1.75*IN,
|
|
|
|
"ambient_rotation_rate" : 0.015,
|
2017-08-31 00:16:08 -07:00
|
|
|
"lines_depth" : 1.2,
|
|
|
|
"lines_shift_vect" : SMALL_BUFF*OUT,
|
2017-08-29 00:04:25 -07:00
|
|
|
}
|
|
|
|
def setup(self):
|
|
|
|
ShowVariousFilterPairsWithPhotonsOverTime.setup(self)
|
2017-08-31 00:16:08 -07:00
|
|
|
self.remove(*self.pol_filters)
|
2017-08-29 00:04:25 -07:00
|
|
|
self.prev_groups = VGroup()
|
|
|
|
self.remove(self.axes)
|
2017-08-31 00:16:08 -07:00
|
|
|
self.setup_filters()
|
|
|
|
self.stop_ambient_camera_rotation()
|
|
|
|
self.prob_texts = VGroup()
|
|
|
|
|
|
|
|
def setup_filters(self):
|
|
|
|
self.filter_pairs = []
|
|
|
|
zs = self.filter_z_coordinates
|
|
|
|
for non_zero_angle, z in zip(self.angles, zs):
|
|
|
|
filter_pair = VGroup()
|
|
|
|
for angle, x in (0, -3), (non_zero_angle, 3):
|
|
|
|
pf = PolarizingFilter(filter_angle = angle)
|
|
|
|
pf.scale(0.7)
|
|
|
|
pf.rotate(np.pi/2, RIGHT)
|
|
|
|
pf.rotate(np.pi/2, IN)
|
|
|
|
pf.shift(x*RIGHT + z*OUT)
|
|
|
|
pf.arrow_label.rotate(np.pi/2, OUT)
|
|
|
|
pf.arrow_label.next_to(pf.arrow, RIGHT, SMALL_BUFF)
|
|
|
|
|
|
|
|
filter_pair.add(pf)
|
|
|
|
self.filter_pairs.append(filter_pair)
|
2017-08-29 00:04:25 -07:00
|
|
|
|
|
|
|
def construct(self):
|
2017-08-31 00:16:08 -07:00
|
|
|
self.add_top_filters()
|
|
|
|
self.show_light(self.filter_pairs[0])
|
|
|
|
self.turn_one_filter_pair_into_another(0, 2)
|
|
|
|
self.show_light(self.filter_pairs[2])
|
|
|
|
self.turn_one_filter_pair_into_another(2, 1)
|
|
|
|
self.show_light(self.filter_pairs[1])
|
|
|
|
|
|
|
|
def add_top_filters(self):
|
|
|
|
pf1, pf2 = pair = self.filter_pairs[0]
|
|
|
|
for pf in pair:
|
|
|
|
pf.save_state()
|
|
|
|
pf.arrow_label.rotate(np.pi/2, IN)
|
|
|
|
pf.arrow_label.next_to(pf.arrow, UP, SMALL_BUFF)
|
|
|
|
pf.shift(2*IN)
|
2017-08-29 00:04:25 -07:00
|
|
|
|
2017-08-31 00:16:08 -07:00
|
|
|
self.add(pf1)
|
|
|
|
self.play(
|
|
|
|
ReplacementTransform(pf1.copy().fade(1), pf2),
|
|
|
|
Animation(pf1)
|
|
|
|
)
|
|
|
|
self.move_camera(
|
|
|
|
0.9*np.pi/2, -0.6*np.pi,
|
|
|
|
added_anims = [
|
|
|
|
pf.restore
|
|
|
|
for pf in pair
|
|
|
|
]
|
|
|
|
)
|
|
|
|
|
|
|
|
def show_light(self, filter_pair):
|
|
|
|
pf1, pf2 = filter_pair
|
|
|
|
lines_to_pf1 = self.get_lines(None, pf1)
|
|
|
|
vect = lines_to_pf1[1].get_center() - lines_to_pf1[0].get_center()
|
|
|
|
lines_to_pf1.add(*lines_to_pf1.copy().shift(vect/2))
|
|
|
|
lines_to_pf2 = self.get_lines(pf1, pf2)
|
|
|
|
lines_from_pf2 = self.get_lines(pf2)
|
|
|
|
|
|
|
|
prob = self.get_prob(pf2)
|
|
|
|
n_black = int(prob*len(lines_from_pf2))
|
|
|
|
VGroup(*lines_from_pf2[n_black:]).set_stroke(BLACK, 0)
|
2017-08-29 00:04:25 -07:00
|
|
|
|
|
|
|
kwargs = {
|
|
|
|
"rate_func" : None,
|
|
|
|
"submobject_mode" : "all_at_once",
|
|
|
|
}
|
|
|
|
|
2017-08-31 00:16:08 -07:00
|
|
|
self.play(ShowCreation(lines_to_pf1, run_time = 2./3, **kwargs))
|
2017-08-29 00:04:25 -07:00
|
|
|
self.play(
|
2017-08-31 00:16:08 -07:00
|
|
|
ShowCreation(lines_to_pf2, **kwargs),
|
|
|
|
Animation(VGroup(pf1, lines_to_pf1)),
|
2017-08-29 00:04:25 -07:00
|
|
|
run_time = 1./6,
|
|
|
|
)
|
|
|
|
self.play(
|
2017-08-31 00:16:08 -07:00
|
|
|
ShowCreation(lines_from_pf2, **kwargs),
|
|
|
|
Animation(VGroup(pf2, lines_to_pf2, pf1, lines_to_pf1)),
|
2017-08-29 00:04:25 -07:00
|
|
|
run_time = 2./3,
|
|
|
|
)
|
|
|
|
|
2017-08-31 00:16:08 -07:00
|
|
|
group = VGroup(
|
|
|
|
lines_from_pf2, pf2, lines_to_pf2, pf1, lines_to_pf2
|
2017-08-29 00:04:25 -07:00
|
|
|
)
|
2017-08-31 00:16:08 -07:00
|
|
|
self.remove(filter_pair, *group)
|
|
|
|
self.add_foreground_mobject(group)
|
2017-08-29 00:04:25 -07:00
|
|
|
|
2017-08-31 00:16:08 -07:00
|
|
|
#Write probability
|
|
|
|
prob_text = self.get_probability_text(pf2)
|
|
|
|
self.play(Write(prob_text, run_time = 1))
|
|
|
|
self.dither()
|
2017-08-29 00:04:25 -07:00
|
|
|
|
2017-08-31 00:16:08 -07:00
|
|
|
self.prob_texts.add(prob_text)
|
2017-08-29 00:04:25 -07:00
|
|
|
|
2017-08-31 00:16:08 -07:00
|
|
|
def turn_one_filter_pair_into_another(self, i1, i2):
|
|
|
|
self.play(ReplacementTransform(
|
|
|
|
self.filter_pairs[i1].copy().fade(1),
|
|
|
|
self.filter_pairs[i2]
|
|
|
|
))
|
2017-08-29 00:04:25 -07:00
|
|
|
|
|
|
|
def get_probability_text(self, pol_filter = None):
|
|
|
|
if pol_filter is None:
|
|
|
|
pol_filter = self.second_filter
|
|
|
|
prob = self.get_prob(pol_filter)
|
|
|
|
prob_mob = TextMobject(str(int(prob*100)) + "\\%", " pass")
|
2017-08-31 00:16:08 -07:00
|
|
|
prob_mob.scale(0.7)
|
2017-08-29 00:04:25 -07:00
|
|
|
prob_mob.rotate(np.pi/2, RIGHT)
|
|
|
|
prob_mob.next_to(pol_filter.arrow_label, RIGHT)
|
|
|
|
prob_mob.highlight(
|
|
|
|
list(Color(RED).range_to(GREEN, 11))[int(prob*10)]
|
|
|
|
)
|
|
|
|
return prob_mob
|
|
|
|
|
|
|
|
|
|
|
|
#####
|
|
|
|
|
|
|
|
def get_lines(self, filter1 = None, filter2 = None, ratio = 1.0):
|
|
|
|
n = int(ratio*self.n_lines)
|
|
|
|
start, end = [
|
2017-08-31 00:16:08 -07:00
|
|
|
(f.point_from_proportion(0.75) if f is not None else None)
|
2017-08-29 00:04:25 -07:00
|
|
|
for f in filter1, filter2
|
|
|
|
]
|
|
|
|
if start is None:
|
|
|
|
start = end + self.line_start_length*LEFT
|
|
|
|
if end is None:
|
|
|
|
end = start + self.line_end_length*RIGHT
|
2017-08-29 20:00:48 -07:00
|
|
|
nudge = (float(self.lines_depth)/self.n_lines)*OUT
|
2017-08-29 00:04:25 -07:00
|
|
|
lines = VGroup(*[
|
|
|
|
Line(start, end).shift(x*nudge)
|
|
|
|
for x in range(n)
|
|
|
|
])
|
|
|
|
lines.set_stroke(YELLOW, 2)
|
|
|
|
lines.move_to(start, IN+LEFT)
|
2017-08-29 20:00:48 -07:00
|
|
|
lines.shift(self.lines_shift_vect)
|
2017-08-29 00:04:25 -07:00
|
|
|
return lines
|
2017-08-25 17:56:55 -07:00
|
|
|
|
2017-08-31 00:16:08 -07:00
|
|
|
class ShowVariousFilterPairsFrom0To45(ShowVariousFilterPairs):
|
2017-08-25 17:56:55 -07:00
|
|
|
CONFIG = {
|
2017-08-31 00:16:08 -07:00
|
|
|
"angles" : [0, np.pi/8, np.pi/4]
|
|
|
|
}
|
|
|
|
def construct(self):
|
|
|
|
ShowVariousFilterPairs.construct(self)
|
|
|
|
self.mention_probabilities()
|
|
|
|
|
|
|
|
def mention_probabilities(self):
|
|
|
|
rects = VGroup()
|
|
|
|
for prob_text in self.prob_texts:
|
|
|
|
prob_text.rotate(np.pi/2, LEFT)
|
|
|
|
rect = SurroundingRectangle(prob_text, color = BLUE)
|
|
|
|
VGroup(prob_text, rect).rotate(np.pi/2, RIGHT)
|
|
|
|
rects.add(rect)
|
|
|
|
|
|
|
|
cosines = VGroup(*[
|
|
|
|
TexMobject("\\cos^2(%s^\\circ)"%str(x))
|
|
|
|
for x in 45, 22.5
|
|
|
|
])
|
|
|
|
cosines.scale(0.8)
|
|
|
|
# cosines.highlight(BLUE)
|
|
|
|
cosines.rotate(np.pi/2, RIGHT)
|
|
|
|
for cos, rect in zip(cosines, rects[1:]):
|
|
|
|
cos.next_to(rect, OUT, SMALL_BUFF)
|
|
|
|
|
|
|
|
self.play(LaggedStart(ShowCreation, rects))
|
|
|
|
self.dither()
|
|
|
|
self.play(*map(Write, cosines), run_time = 2)
|
|
|
|
self.dither()
|
|
|
|
|
|
|
|
class ForgetPreviousActions(ShowVariousFilterPairs):
|
|
|
|
CONFIG = {
|
|
|
|
"filter_x_coordinates" : [-6, -2, 2, 2, 2],
|
2017-08-25 17:56:55 -07:00
|
|
|
"pol_filter_configs" : [
|
|
|
|
{"filter_angle" : angle}
|
2017-08-31 00:16:08 -07:00
|
|
|
for angle in np.pi/4, 0, np.pi/4, np.pi/3, np.pi/6
|
2017-08-25 17:56:55 -07:00
|
|
|
],
|
2017-08-31 00:16:08 -07:00
|
|
|
"start_theta" : -0.6*np.pi,
|
|
|
|
"EMWave_config" : {
|
|
|
|
"wave_number" : 0,
|
|
|
|
"start_point" : SPACE_WIDTH*LEFT + DOWN,
|
|
|
|
},
|
|
|
|
"apply_filter" : False,
|
2017-08-25 17:56:55 -07:00
|
|
|
}
|
2017-08-31 00:16:08 -07:00
|
|
|
def setup(self):
|
|
|
|
PhotonsThroughPerpendicularFilters.setup(self)
|
|
|
|
self.remove(self.axes)
|
|
|
|
|
|
|
|
VGroup(*self.pol_filters).shift(IN)
|
2017-08-27 14:43:18 -07:00
|
|
|
|
2017-08-25 17:56:55 -07:00
|
|
|
for pf in self.pol_filters:
|
|
|
|
pf.arrow_label.rotate_in_place(np.pi/2, OUT)
|
|
|
|
pf.arrow_label.next_to(pf.arrow, RIGHT)
|
|
|
|
|
2017-08-31 00:16:08 -07:00
|
|
|
self.stop_ambient_camera_rotation()
|
|
|
|
|
|
|
|
def construct(self):
|
|
|
|
front_filter = self.pol_filters[0]
|
|
|
|
first_filter = self.pol_filters[1]
|
|
|
|
possible_second_filters = self.pol_filters[2:]
|
|
|
|
for pf in possible_second_filters:
|
|
|
|
prob_text = self.get_probability_text(pf)
|
|
|
|
prob_text.scale(1.3, about_point = prob_text.get_left())
|
|
|
|
pf.add(prob_text)
|
|
|
|
|
|
|
|
second_filter = possible_second_filters[0].copy()
|
|
|
|
self.second_filter = second_filter
|
|
|
|
self.pol_filters = VGroup(
|
|
|
|
first_filter, second_filter
|
|
|
|
)
|
|
|
|
self.remove(front_filter)
|
|
|
|
self.remove(*possible_second_filters)
|
|
|
|
self.add(second_filter)
|
|
|
|
self.apply_filter = True
|
|
|
|
self.continual_update()
|
|
|
|
self.photons = self.get_photons()[1:]
|
|
|
|
|
|
|
|
group = VGroup(*self.pol_filters)
|
2017-08-27 14:43:18 -07:00
|
|
|
rect1 = SurroundingRectangle(group)
|
|
|
|
rect1.rotate_in_place(np.pi/2, RIGHT)
|
|
|
|
rect1.rescale_to_fit(group.get_depth()+MED_SMALL_BUFF, 2, True)
|
|
|
|
rect1.stretch_in_place(1.2, 0)
|
|
|
|
prob_words = TextMobject(
|
2017-08-25 17:56:55 -07:00
|
|
|
"Probabilities depend only\\\\",
|
|
|
|
"on this angle difference"
|
|
|
|
)
|
2017-08-27 14:43:18 -07:00
|
|
|
prob_words.add_background_rectangle()
|
|
|
|
prob_words.rotate(np.pi/2, RIGHT)
|
|
|
|
prob_words.next_to(rect1, OUT)
|
|
|
|
|
|
|
|
self.add(rect1)
|
2017-08-30 13:16:08 -07:00
|
|
|
self.play(FadeIn(prob_words))
|
2017-08-31 00:16:08 -07:00
|
|
|
for index in 1, 2:
|
|
|
|
self.shoot_photon()
|
|
|
|
self.play(Transform(
|
|
|
|
second_filter, possible_second_filters[index]
|
|
|
|
))
|
2017-08-27 14:43:18 -07:00
|
|
|
|
2017-08-31 00:16:08 -07:00
|
|
|
rect2 = SurroundingRectangle(front_filter, color = RED)
|
2017-08-27 14:43:18 -07:00
|
|
|
rect2.rotate_in_place(np.pi/2, RIGHT)
|
2017-08-31 00:16:08 -07:00
|
|
|
rect2.rescale_to_fit(front_filter.get_depth()+MED_SMALL_BUFF, 2, True)
|
2017-08-27 14:43:18 -07:00
|
|
|
rect2.stretch_in_place(1.5, 0)
|
|
|
|
ignore_words = TextMobject("Photon \\\\", "``forgets'' this")
|
|
|
|
ignore_words.add_background_rectangle()
|
|
|
|
ignore_words.rotate(np.pi/2, RIGHT)
|
|
|
|
ignore_words.next_to(rect2, OUT)
|
|
|
|
|
|
|
|
self.play(
|
|
|
|
ShowCreation(rect2),
|
2017-08-31 00:16:08 -07:00
|
|
|
Write(ignore_words, run_time = 1),
|
|
|
|
FadeIn(front_filter),
|
|
|
|
run_time = 1.5,
|
2017-08-27 14:43:18 -07:00
|
|
|
)
|
2017-08-31 00:16:08 -07:00
|
|
|
self.shoot_photon()
|
|
|
|
for index in 0, 1, 2:
|
|
|
|
self.play(Transform(
|
|
|
|
second_filter, possible_second_filters[index]
|
|
|
|
))
|
2017-08-30 13:16:08 -07:00
|
|
|
self.shoot_photon()
|
2017-08-27 14:43:18 -07:00
|
|
|
|
|
|
|
def shoot_photon(self):
|
|
|
|
photon = random.choice(self.photons)
|
|
|
|
added_anims = []
|
|
|
|
if photon.filter_distance == SPACE_WIDTH + 2:
|
2017-08-31 00:16:08 -07:00
|
|
|
added_anims.append(
|
|
|
|
ApplyMethod(
|
|
|
|
self.second_filter.highlight, RED,
|
|
|
|
rate_func = squish_rate_func(there_and_back, 0.5, 0.7)
|
|
|
|
)
|
|
|
|
)
|
2017-08-27 14:43:18 -07:00
|
|
|
self.play(photon, *added_anims, run_time = 1.5)
|
|
|
|
|
2017-08-29 00:04:25 -07:00
|
|
|
class IntroduceLabeledFilters(ShowVariousFilterPairs):
|
2017-08-28 15:18:57 -07:00
|
|
|
CONFIG = {
|
2017-08-29 00:04:25 -07:00
|
|
|
"filter_x_coordinates" : [-5, -2, 1],
|
2017-08-28 15:18:57 -07:00
|
|
|
"pol_filter_configs" : [
|
|
|
|
{"filter_angle" : angle}
|
|
|
|
for angle in [0, np.pi/8, np.pi/4]
|
|
|
|
],
|
|
|
|
"start_phi" : 0.9*np.pi/2,
|
|
|
|
"start_theta" : -0.85*np.pi,
|
2017-08-31 00:16:08 -07:00
|
|
|
"lines_depth" : 1.7,
|
|
|
|
"lines_shift_vect" : MED_SMALL_BUFF*OUT,
|
2017-08-29 00:04:25 -07:00
|
|
|
"line_start_length" : 3,
|
|
|
|
"line_end_length" : 9,
|
2017-08-28 15:18:57 -07:00
|
|
|
}
|
|
|
|
def setup(self):
|
|
|
|
PhotonsThroughPerpendicularFilters.setup(self)
|
|
|
|
self.remove(self.axes)
|
|
|
|
|
|
|
|
def construct(self):
|
|
|
|
self.add_letters_to_labels()
|
|
|
|
self.introduce_filters()
|
|
|
|
self.reposition_camera()
|
|
|
|
self.separate_cases()
|
2017-08-29 00:04:25 -07:00
|
|
|
self.show_bottom_lines()
|
|
|
|
self.comment_on_half_blocked_by_C()
|
|
|
|
self.show_top_lines()
|
|
|
|
self.comment_on_those_blocked_by_B()
|
2017-08-28 15:18:57 -07:00
|
|
|
|
|
|
|
def add_letters_to_labels(self):
|
|
|
|
for char, pf, color in zip("ABC", self.pol_filters, [RED, GREEN, BLUE]):
|
|
|
|
label = TextMobject(char)
|
|
|
|
label.scale(0.9)
|
|
|
|
label.add_background_rectangle()
|
|
|
|
label.highlight(color)
|
|
|
|
label.rotate(np.pi/2, RIGHT)
|
|
|
|
label.rotate(np.pi/2, IN)
|
|
|
|
label.next_to(pf.arrow_label, UP)
|
|
|
|
pf.arrow_label.add(label)
|
|
|
|
pf.arrow_label.next_to(pf.arrow, OUT, SMALL_BUFF)
|
|
|
|
self.remove(*self.pol_filters)
|
|
|
|
|
|
|
|
def introduce_filters(self):
|
|
|
|
self.A_filter, self.B_filter, self.C_filter = self.pol_filters
|
|
|
|
for pf in self.pol_filters:
|
|
|
|
pf.save_state()
|
|
|
|
pf.shift(4*OUT)
|
|
|
|
pf.fade(1)
|
|
|
|
self.play(pf.restore)
|
2017-08-29 00:04:25 -07:00
|
|
|
self.dither()
|
2017-08-28 15:18:57 -07:00
|
|
|
|
|
|
|
def reposition_camera(self):
|
|
|
|
self.move_camera(
|
2017-08-29 00:04:25 -07:00
|
|
|
theta = -0.65*np.pi,
|
2017-08-28 15:18:57 -07:00
|
|
|
added_anims = list(it.chain(*[
|
|
|
|
[
|
|
|
|
pf.arrow_label.rotate, np.pi/2, OUT,
|
|
|
|
pf.arrow_label.next_to, pf.arrow, RIGHT
|
|
|
|
]
|
|
|
|
for pf in self.pol_filters
|
|
|
|
]))
|
|
|
|
)
|
2017-08-29 00:04:25 -07:00
|
|
|
# self.stop_ambient_camera_rotation()
|
|
|
|
self.ambient_rotation_rate = 0.005
|
2017-08-28 15:18:57 -07:00
|
|
|
self.dither()
|
|
|
|
|
|
|
|
def separate_cases(self):
|
|
|
|
self.lower_pol_filters = VGroup(
|
2017-08-29 00:04:25 -07:00
|
|
|
self.A_filter.deepcopy(),
|
|
|
|
self.C_filter.deepcopy(),
|
2017-08-28 15:18:57 -07:00
|
|
|
)
|
2017-08-29 00:04:25 -07:00
|
|
|
self.lower_pol_filters.save_state()
|
|
|
|
self.lower_pol_filters.fade(1)
|
|
|
|
|
2017-08-28 15:18:57 -07:00
|
|
|
self.play(
|
2017-08-29 00:04:25 -07:00
|
|
|
self.lower_pol_filters.restore,
|
2017-08-28 15:18:57 -07:00
|
|
|
self.lower_pol_filters.shift, 3*IN,
|
2017-08-29 00:04:25 -07:00
|
|
|
self.pol_filters.shift, 1.5*OUT,
|
2017-08-28 15:18:57 -07:00
|
|
|
)
|
|
|
|
self.dither()
|
|
|
|
|
2017-08-29 00:04:25 -07:00
|
|
|
def show_bottom_lines(self):
|
|
|
|
A, C = self.lower_pol_filters
|
|
|
|
lines_to_A = self.get_lines(None, A)
|
2017-08-29 20:00:48 -07:00
|
|
|
vect = lines_to_A[1].get_center() - lines_to_A[0].get_center()
|
|
|
|
lines_to_A.add(*lines_to_A.copy().shift(vect/2))
|
2017-08-29 00:04:25 -07:00
|
|
|
lines_to_C = self.get_lines(A, C)
|
|
|
|
lines_from_C = self.get_lines(C, ratio = 0.5)
|
|
|
|
kwargs = {
|
|
|
|
"rate_func" : None,
|
|
|
|
"submobject_mode" : "all_at_once",
|
|
|
|
"run_time" : 1./3,
|
|
|
|
}
|
|
|
|
self.play(
|
|
|
|
ShowCreation(lines_to_A),
|
|
|
|
**kwargs
|
|
|
|
)
|
|
|
|
self.play(
|
|
|
|
ShowCreation(lines_to_C),
|
|
|
|
Animation(VGroup(A, lines_to_A)),
|
|
|
|
**kwargs
|
|
|
|
)
|
|
|
|
kwargs["run_time"] = 3*kwargs["run_time"]
|
|
|
|
self.play(
|
|
|
|
ShowCreation(lines_from_C),
|
|
|
|
Animation(VGroup(C, lines_to_C, A, lines_to_A)),
|
|
|
|
**kwargs
|
|
|
|
)
|
|
|
|
|
2017-08-29 20:00:48 -07:00
|
|
|
line_group = VGroup(lines_from_C, C, lines_to_C, A, lines_to_A)
|
|
|
|
self.remove(*line_group)
|
|
|
|
self.add_foreground_mobject(line_group)
|
|
|
|
|
2017-08-29 00:04:25 -07:00
|
|
|
def comment_on_half_blocked_by_C(self):
|
|
|
|
arrow = Arrow(
|
|
|
|
ORIGIN, 3.5*RIGHT+0.5*DOWN,
|
|
|
|
path_arc = -0.9*np.pi,
|
|
|
|
use_rectangular_stem = False,
|
|
|
|
color = BLUE,
|
|
|
|
stroke_width = 5,
|
|
|
|
)
|
|
|
|
words = TextMobject("50\\% blocked")
|
|
|
|
words.highlight(BLUE)
|
|
|
|
words.next_to(arrow, RIGHT, buff = 0)
|
|
|
|
group = VGroup(arrow, words)
|
|
|
|
group.rotate(np.pi/2, RIGHT)
|
|
|
|
group.shift(1.7*IN + 0.5*RIGHT)
|
|
|
|
|
|
|
|
self.play(
|
|
|
|
Write(words, run_time = 2),
|
|
|
|
ShowCreation(arrow)
|
|
|
|
)
|
|
|
|
self.dither(2)
|
|
|
|
|
|
|
|
self.blocked_at_C_words = words
|
|
|
|
|
|
|
|
def show_top_lines(self):
|
|
|
|
A, B, C = self.pol_filters
|
|
|
|
lines_to_A = self.get_lines(None, A)
|
2017-08-29 20:00:48 -07:00
|
|
|
vect = lines_to_A[1].get_center() - lines_to_A[0].get_center()
|
|
|
|
lines_to_A.add(*lines_to_A.copy().shift(vect/2))
|
2017-08-29 00:04:25 -07:00
|
|
|
lines_to_B = self.get_lines(A, B)
|
|
|
|
lines_to_C = self.get_lines(B, C, ratio = 0.85)
|
|
|
|
lines_from_C = self.get_lines(C, ratio = 0.85**2)
|
|
|
|
|
|
|
|
kwargs = {
|
|
|
|
"rate_func" : None,
|
|
|
|
"submobject_mode" : "all_at_once",
|
|
|
|
"run_time" : 1./5,
|
|
|
|
}
|
|
|
|
self.play(
|
|
|
|
ShowCreation(lines_to_A),
|
|
|
|
**kwargs
|
|
|
|
)
|
|
|
|
self.play(
|
|
|
|
ShowCreation(lines_to_B),
|
|
|
|
Animation(VGroup(A, lines_to_A)),
|
|
|
|
**kwargs
|
|
|
|
)
|
|
|
|
self.play(
|
|
|
|
ShowCreation(lines_to_C),
|
|
|
|
Animation(VGroup(B, lines_to_B, A, lines_to_A)),
|
|
|
|
**kwargs
|
|
|
|
)
|
|
|
|
kwargs["run_time"] = 3*kwargs["run_time"]
|
|
|
|
self.play(
|
|
|
|
ShowCreation(lines_from_C),
|
|
|
|
Animation(VGroup(C, lines_to_C, B, lines_to_B, A, lines_to_A)),
|
|
|
|
**kwargs
|
|
|
|
)
|
|
|
|
|
2017-08-29 20:00:48 -07:00
|
|
|
line_group = VGroup(
|
|
|
|
lines_from_C, C, lines_to_C, B, lines_to_B, A, lines_to_A
|
|
|
|
)
|
|
|
|
self.remove(*line_group)
|
|
|
|
self.add_foreground_mobject(line_group)
|
|
|
|
|
2017-08-29 00:04:25 -07:00
|
|
|
def comment_on_those_blocked_by_B(self):
|
|
|
|
arrow1 = Arrow(
|
|
|
|
2*LEFT, ORIGIN,
|
|
|
|
path_arc = 0.8*np.pi,
|
|
|
|
use_rectangular_stem = False,
|
|
|
|
color = GREEN,
|
|
|
|
stroke_width = 5,
|
|
|
|
buff = 0
|
|
|
|
)
|
|
|
|
arrow2 = arrow1.copy()
|
|
|
|
arrow2.next_to(arrow1, RIGHT, buff = LARGE_BUFF)
|
|
|
|
words1 = TextMobject("15\\%", "blocked")
|
|
|
|
words1.highlight(GREEN)
|
|
|
|
words2 = words1.copy()
|
|
|
|
words1.next_to(arrow1, DOWN, buff = SMALL_BUFF)
|
|
|
|
words2.next_to(arrow2, DOWN, buff = SMALL_BUFF)
|
|
|
|
words2.shift(MED_LARGE_BUFF*RIGHT)
|
|
|
|
|
|
|
|
words0 = TextMobject("85\\%", "pass")
|
|
|
|
words0.move_to(words1)
|
|
|
|
|
|
|
|
group = VGroup(arrow1, arrow2, words0, words1, words2)
|
|
|
|
group.rotate(np.pi/2, RIGHT)
|
|
|
|
group.shift(0.8*LEFT+1.5*OUT)
|
|
|
|
|
|
|
|
self.play(
|
|
|
|
ShowCreation(arrow1),
|
|
|
|
Write(words0, run_time = 1)
|
|
|
|
)
|
|
|
|
self.dither()
|
|
|
|
self.play(ReplacementTransform(words0, words1))
|
|
|
|
self.dither()
|
|
|
|
self.play(
|
|
|
|
ShowCreation(arrow2),
|
|
|
|
Write(words2)
|
|
|
|
)
|
|
|
|
self.dither(2)
|
|
|
|
for words in words1, words2, self.blocked_at_C_words:
|
|
|
|
self.play(Indicate(words))
|
|
|
|
self.dither(6)
|
2017-08-28 15:18:57 -07:00
|
|
|
|
2017-08-27 14:43:18 -07:00
|
|
|
class NumbersSuggestHiddenVariablesAreImpossible(TeacherStudentsScene):
|
|
|
|
def construct(self):
|
|
|
|
self.teacher_says(
|
|
|
|
"These numbers suggest\\\\",
|
|
|
|
"no hidden variables"
|
|
|
|
)
|
|
|
|
self.change_student_modes("erm", "sassy", "confused")
|
|
|
|
self.dither(3)
|
|
|
|
|
|
|
|
class VennDiagramProofByContradiction(Scene):
|
|
|
|
CONFIG = {
|
|
|
|
"circle_colors" : [RED, GREEN, BLUE]
|
|
|
|
}
|
|
|
|
def construct(self):
|
|
|
|
self.draw_venn_diagram()
|
|
|
|
self.show_100_photons()
|
|
|
|
self.show_one_photon_answering_questions()
|
|
|
|
self.put_all_photons_in_A()
|
|
|
|
self.separate_by_B()
|
|
|
|
self.separate_by_C()
|
|
|
|
self.show_two_relevant_subsets()
|
|
|
|
|
2017-08-29 20:00:48 -07:00
|
|
|
def draw_venn_diagram(self, send_to_corner = True):
|
|
|
|
venn_diagram = VGroup(*[
|
2017-08-27 14:43:18 -07:00
|
|
|
Circle(
|
|
|
|
radius = 3,
|
|
|
|
stroke_width = 3,
|
|
|
|
stroke_color = c,
|
|
|
|
fill_opacity = 0.2,
|
|
|
|
fill_color = c,
|
|
|
|
).shift(vect)
|
|
|
|
for c, vect in zip(
|
|
|
|
self.circle_colors,
|
|
|
|
compass_directions(3, UP)
|
|
|
|
)
|
|
|
|
])
|
2017-08-29 20:00:48 -07:00
|
|
|
venn_diagram.center()
|
2017-08-27 14:43:18 -07:00
|
|
|
props = [1./12, 0.5, 0]
|
2017-08-30 13:16:08 -07:00
|
|
|
angles = [0, np.pi/8, np.pi/4]
|
|
|
|
for circle, char, prop, angle in zip(venn_diagram, "ABC", props, angles):
|
|
|
|
label = TextMobject("Would pass \\\\ through", char + "$\\! \\uparrow$")
|
2017-08-27 14:43:18 -07:00
|
|
|
label.highlight_by_tex(char, circle.get_color())
|
2017-08-30 13:16:08 -07:00
|
|
|
label[1][1].rotate_in_place(-angle)
|
|
|
|
label[1][1].shift(0.5*SMALL_BUFF*UP)
|
2017-08-27 14:43:18 -07:00
|
|
|
center = circle.get_center()
|
|
|
|
label.move_to(center)
|
|
|
|
label.generate_target()
|
|
|
|
point = circle.point_from_proportion(prop)
|
|
|
|
label.target.next_to(point, point-center, SMALL_BUFF)
|
|
|
|
|
|
|
|
circle.label = label
|
|
|
|
|
|
|
|
last_circle = None
|
2017-08-29 20:00:48 -07:00
|
|
|
for circle in venn_diagram:
|
2017-08-27 14:43:18 -07:00
|
|
|
added_anims = []
|
|
|
|
if last_circle:
|
|
|
|
added_anims.append(MoveToTarget(last_circle.label))
|
|
|
|
self.play(
|
|
|
|
DrawBorderThenFill(circle, run_time = 2),
|
|
|
|
Write(circle.label, run_time = 2),
|
|
|
|
*added_anims
|
|
|
|
)
|
|
|
|
last_circle = circle
|
|
|
|
self.play(MoveToTarget(last_circle.label))
|
|
|
|
self.dither()
|
|
|
|
|
2017-08-29 20:00:48 -07:00
|
|
|
venn_diagram.add(*[c.label for c in venn_diagram])
|
|
|
|
self.venn_diagram = venn_diagram
|
|
|
|
for part in self.venn_diagram:
|
2017-08-27 14:43:18 -07:00
|
|
|
part.save_state()
|
2017-08-29 20:00:48 -07:00
|
|
|
if send_to_corner:
|
|
|
|
self.play(
|
|
|
|
self.venn_diagram.scale, 0.25,
|
|
|
|
self.venn_diagram.to_corner, UP+RIGHT
|
|
|
|
)
|
2017-08-27 14:43:18 -07:00
|
|
|
|
|
|
|
def show_100_photons(self):
|
|
|
|
photon = FunctionGraph(
|
|
|
|
lambda x : -np.cos(3*np.pi*x)*np.exp(-x*x),
|
|
|
|
x_min = -2,
|
|
|
|
x_max = 2,
|
2017-08-27 23:52:28 -07:00
|
|
|
color = YELLOW,
|
|
|
|
stroke_width = 2,
|
2017-08-27 14:43:18 -07:00
|
|
|
)
|
|
|
|
photon.shift(LEFT + 2*UP)
|
|
|
|
eyes = Eyes(photon)
|
|
|
|
photon.eyes = eyes
|
|
|
|
|
|
|
|
hundred, photon_word, s = words = TextMobject(
|
|
|
|
"100 ", "Photon", "s",
|
|
|
|
arg_separator = ""
|
|
|
|
)
|
|
|
|
words.next_to(eyes, UP)
|
|
|
|
|
|
|
|
self.play(
|
|
|
|
ShowCreation(photon),
|
|
|
|
FadeIn(photon.eyes),
|
|
|
|
Write(photon_word, run_time = 1.5)
|
|
|
|
)
|
|
|
|
photon.add(photon.eyes)
|
|
|
|
|
|
|
|
#Split to hundred
|
|
|
|
photons = VGroup(*[photon.deepcopy() for x in range(100)])
|
|
|
|
self.arrange_photons_in_circle(photons)
|
|
|
|
photons.scale_to_fit_height(6)
|
|
|
|
photons.next_to(words, DOWN)
|
|
|
|
photons.to_edge(LEFT)
|
|
|
|
|
|
|
|
self.play(
|
|
|
|
Write(hundred), Write(s),
|
|
|
|
ReplacementTransform(
|
|
|
|
VGroup(photon), photons,
|
|
|
|
submobject_mode = "lagged_start"
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
self.photons = photons
|
|
|
|
self.photon_words = words
|
|
|
|
|
|
|
|
def show_one_photon_answering_questions(self):
|
|
|
|
photon = self.photons[-1]
|
|
|
|
photon.save_state()
|
|
|
|
photon.generate_target()
|
|
|
|
photon.target.scale(4)
|
|
|
|
photon.target.next_to(self.photons, RIGHT)
|
|
|
|
|
|
|
|
answers = TextMobject(
|
|
|
|
"Pass through A?", "Yes\\\\",
|
|
|
|
"Pass through B?", "No\\\\",
|
|
|
|
"Pass through C?", "No\\\\",
|
|
|
|
)
|
|
|
|
answers.highlight_by_tex_to_color_map({
|
|
|
|
"Yes" : GREEN,
|
|
|
|
"No" : RED,
|
|
|
|
})
|
|
|
|
answers.next_to(photon.target, RIGHT)
|
|
|
|
|
|
|
|
self.play(
|
|
|
|
MoveToTarget(photon),
|
|
|
|
FadeIn(answers)
|
|
|
|
)
|
|
|
|
self.dither(2)
|
|
|
|
self.play(
|
|
|
|
FadeOut(answers),
|
|
|
|
photon.restore,
|
|
|
|
)
|
|
|
|
|
|
|
|
def put_all_photons_in_A(self):
|
2017-08-29 20:00:48 -07:00
|
|
|
A_circle, B_circle, C_circle = circles = self.venn_diagram[:3]
|
2017-08-27 14:43:18 -07:00
|
|
|
A_group, B_group, C_group = [
|
|
|
|
VGroup(circle, circle.label)
|
|
|
|
for circle in circles
|
|
|
|
]
|
|
|
|
B_group.save_state()
|
|
|
|
C_group.save_state()
|
|
|
|
|
|
|
|
A_group.generate_target()
|
|
|
|
A_group.target.scale(4)
|
2017-08-27 23:52:28 -07:00
|
|
|
A_group.target.shift(
|
|
|
|
(SPACE_HEIGHT-MED_LARGE_BUFF)*UP - \
|
|
|
|
A_group.target[0].get_top()
|
|
|
|
)
|
|
|
|
A_group.target[1].scale_in_place(0.8)
|
2017-08-27 14:43:18 -07:00
|
|
|
|
|
|
|
self.play(
|
|
|
|
B_group.fade, 1,
|
|
|
|
C_group.fade, 1,
|
|
|
|
MoveToTarget(A_group),
|
|
|
|
FadeOut(self.photon_words),
|
|
|
|
self.photons.scale_to_fit_height,
|
|
|
|
0.85*A_group.target.get_height(),
|
|
|
|
self.photons.move_to, A_group.target[0].get_center(),
|
|
|
|
)
|
|
|
|
self.dither()
|
|
|
|
|
|
|
|
self.A_group = A_group
|
|
|
|
self.B_group = B_group
|
|
|
|
self.C_group = C_group
|
|
|
|
|
|
|
|
def separate_by_B(self):
|
2017-08-27 23:52:28 -07:00
|
|
|
A_group = self.A_group
|
|
|
|
B_group = self.B_group
|
|
|
|
photons = self.photons
|
|
|
|
B_circle = B_group[0]
|
|
|
|
|
|
|
|
B_group.target = B_group.saved_state
|
|
|
|
B_group.target.scale(4)
|
|
|
|
B_group.target.move_to(A_group)
|
|
|
|
B_group.target.shift(1.25*DOWN+3.25*LEFT)
|
|
|
|
B_group.target[1].shift(DOWN)
|
|
|
|
B_group.target[1].scale_in_place(0.8)
|
|
|
|
B_center = B_group.target[0].get_center()
|
|
|
|
photons.sort_submobjects(
|
|
|
|
lambda p : np.linalg.norm(p-B_center)
|
|
|
|
)
|
|
|
|
in_B = VGroup(*photons[:85])
|
|
|
|
out_of_B = VGroup(*photons[85:])
|
|
|
|
out_of_B.sort_submobjects(lambda p : np.dot(p, 2*UP+LEFT))
|
|
|
|
|
|
|
|
words = TextMobject("15 blocked \\\\ by ", "B")
|
|
|
|
words.highlight_by_tex("B", GREEN)
|
|
|
|
words.scale(0.8)
|
|
|
|
words.next_to(A_group, LEFT, LARGE_BUFF, UP)
|
|
|
|
arrow = Arrow(words.get_right(), out_of_B[-1])
|
|
|
|
arrow.highlight(RED)
|
|
|
|
|
|
|
|
self.play(
|
|
|
|
MoveToTarget(B_group),
|
|
|
|
in_B.space_out_submobjects, 0.8,
|
|
|
|
in_B.shift, MED_SMALL_BUFF*(DOWN+LEFT),
|
|
|
|
)
|
|
|
|
self.play(
|
|
|
|
Write(words, run_time = 1),
|
|
|
|
ShowCreation(arrow)
|
|
|
|
)
|
|
|
|
self.play(LaggedStart(
|
|
|
|
Indicate, out_of_B,
|
|
|
|
rate_func = there_and_back,
|
|
|
|
color = RED,
|
|
|
|
scale_factor = 2,
|
|
|
|
))
|
|
|
|
self.dither()
|
|
|
|
|
|
|
|
self.in_B = in_B
|
|
|
|
self.out_of_B = out_of_B
|
|
|
|
self.out_of_B_words = words
|
|
|
|
self.out_of_B_arrow = arrow
|
2017-08-27 14:43:18 -07:00
|
|
|
|
|
|
|
def separate_by_C(self):
|
2017-08-27 23:52:28 -07:00
|
|
|
B_group = self.B_group
|
|
|
|
C_group = self.C_group
|
|
|
|
in_B = self.in_B
|
|
|
|
|
|
|
|
C_group.target = C_group.saved_state
|
|
|
|
C_group.target.scale(4)
|
|
|
|
C_group.target.move_to(B_group, DOWN)
|
|
|
|
C_group.target.shift(4.5*RIGHT)
|
|
|
|
C_center = C_group.target[0].get_center()
|
|
|
|
C_group.target[1].scale_in_place(0.8)
|
|
|
|
|
|
|
|
in_B.sort_submobjects(
|
|
|
|
lambda p : np.linalg.norm(p - C_center)
|
|
|
|
)
|
|
|
|
in_C = VGroup(*in_B[:-11])
|
|
|
|
out_of_C = VGroup(*in_B[-11:])
|
|
|
|
|
|
|
|
words = TextMobject(
|
|
|
|
"$<$ 15 passing", "B \\\\",
|
|
|
|
"get blocked by ", "C",
|
|
|
|
)
|
|
|
|
words.scale(0.8)
|
|
|
|
words.highlight_by_tex_to_color_map({
|
|
|
|
"B" : GREEN,
|
|
|
|
"C" : BLUE,
|
|
|
|
})
|
|
|
|
words.next_to(self.out_of_B_words, DOWN, LARGE_BUFF)
|
|
|
|
words.to_edge(LEFT)
|
|
|
|
arrow = Arrow(words.get_right(), out_of_C)
|
|
|
|
arrow.highlight(GREEN)
|
|
|
|
|
|
|
|
self.play(
|
|
|
|
MoveToTarget(C_group),
|
|
|
|
in_C.shift, MED_SMALL_BUFF*(DOWN+RIGHT),
|
|
|
|
out_of_C.shift, SMALL_BUFF*(UP+LEFT),
|
|
|
|
)
|
|
|
|
self.play(
|
|
|
|
Write(words, run_time = 1),
|
|
|
|
ShowCreation(arrow)
|
|
|
|
)
|
|
|
|
self.dither()
|
|
|
|
self.play(LaggedStart(
|
|
|
|
Indicate, out_of_C,
|
|
|
|
rate_func = there_and_back,
|
|
|
|
color = GREEN,
|
|
|
|
scale_factor = 2,
|
|
|
|
))
|
|
|
|
self.dither()
|
|
|
|
|
|
|
|
self.in_C = in_C
|
|
|
|
self.out_of_C = out_of_C
|
|
|
|
self.out_of_C_words = words
|
|
|
|
self.out_of_C_arrow = arrow
|
2017-08-27 14:43:18 -07:00
|
|
|
|
|
|
|
def show_two_relevant_subsets(self):
|
2017-08-27 23:52:28 -07:00
|
|
|
terms = VGroup(
|
|
|
|
TexMobject("N(", "A+", ",", "B-", ")"),
|
|
|
|
TexMobject("+ N(", "A+", ",", "B+", ",", "C-", ")"),
|
|
|
|
TexMobject("\\ge", "N(", "A+", ",", "C-", ")"),
|
|
|
|
)
|
|
|
|
terms.arrange_submobjects(RIGHT)
|
|
|
|
terms.to_edge(UP)
|
|
|
|
for term in terms:
|
|
|
|
term.highlight_by_tex_to_color_map({
|
|
|
|
"A" : RED,
|
|
|
|
"B" : GREEN,
|
|
|
|
"C" : BLUE,
|
|
|
|
})
|
|
|
|
|
|
|
|
all_out_of_C = VGroup(*it.chain(
|
|
|
|
self.out_of_B[6:],
|
|
|
|
self.out_of_C,
|
|
|
|
))
|
|
|
|
|
|
|
|
self.play(*[
|
|
|
|
ApplyMethod(
|
|
|
|
m.scale, 0.8,
|
|
|
|
method_kwargs = {
|
|
|
|
"about_point" : SPACE_HEIGHT*DOWN
|
|
|
|
}
|
|
|
|
)
|
|
|
|
for m in self.get_top_level_mobjects()
|
|
|
|
])
|
|
|
|
self.dither()
|
|
|
|
for term, group in zip(terms[:2], [self.out_of_B, self.out_of_C]):
|
|
|
|
self.play(LaggedStart(
|
2017-08-29 00:04:25 -07:00
|
|
|
ApplyFunction, group,
|
|
|
|
lambda mob : (lambda m : m.set_stroke(WHITE).scale_in_place(1.5), mob),
|
2017-08-27 23:52:28 -07:00
|
|
|
run_time = 1,
|
|
|
|
))
|
|
|
|
self.play(Write(term, run_time = 1))
|
|
|
|
self.play(
|
|
|
|
LaggedStart(
|
|
|
|
ApplyMethod, group,
|
|
|
|
lambda m : (m.scale_in_place, 1/1.5)
|
|
|
|
),
|
|
|
|
self.in_C.fade,
|
|
|
|
)
|
|
|
|
self.dither()
|
|
|
|
self.play(Write(terms[2], run_time = 1))
|
|
|
|
self.play(LaggedStart(
|
2017-08-29 00:04:25 -07:00
|
|
|
ApplyFunction, all_out_of_C,
|
2017-08-29 20:00:48 -07:00
|
|
|
lambda mob : (
|
|
|
|
lambda m : m.scale_in_place(1.5).set_style_data(
|
|
|
|
stroke_color = TEAL,
|
|
|
|
stroke_width = 1.5,
|
|
|
|
family = False,
|
|
|
|
), mob
|
|
|
|
),
|
2017-08-27 23:52:28 -07:00
|
|
|
run_time = 2,
|
|
|
|
))
|
|
|
|
|
|
|
|
words = [self.out_of_B_words, self.out_of_C_words]
|
|
|
|
arrows = [self.out_of_B_arrow, self.out_of_C_arrow]
|
|
|
|
indices = [2, 3]
|
|
|
|
for word, arrow, index, term in zip(words, arrows, indices, terms):
|
|
|
|
num = VGroup(*word[0][:index])
|
|
|
|
word[0].remove(*num)
|
2017-08-27 14:43:18 -07:00
|
|
|
|
2017-08-27 23:52:28 -07:00
|
|
|
self.play(
|
|
|
|
FadeOut(word),
|
|
|
|
FadeOut(arrow),
|
|
|
|
num.scale, 2,
|
|
|
|
num.next_to, term, DOWN
|
|
|
|
)
|
|
|
|
self.dither()
|
|
|
|
|
|
|
|
rect = SurroundingRectangle(VGroup(*terms[2][1:]))
|
|
|
|
should_be_50 = TextMobject("Should be 50...somehow")
|
|
|
|
should_be_50.scale(0.8)
|
|
|
|
should_be_50.next_to(rect, DOWN, MED_SMALL_BUFF, LEFT)
|
|
|
|
|
|
|
|
self.play(
|
|
|
|
ShowCreation(rect),
|
|
|
|
Write(should_be_50, run_time = 1)
|
|
|
|
)
|
|
|
|
self.dither()
|
|
|
|
|
|
|
|
morty = Mortimer()
|
|
|
|
morty.to_corner(DOWN+RIGHT)
|
|
|
|
contradiction = TextMobject("Contradiction!")
|
|
|
|
contradiction.next_to(morty, UP, aligned_edge = RIGHT)
|
|
|
|
contradiction.highlight(RED)
|
|
|
|
self.play(FadeIn(morty))
|
|
|
|
self.play(
|
|
|
|
morty.change, "hooray",
|
|
|
|
Write(contradiction, run_time = 1)
|
|
|
|
)
|
|
|
|
self.play(Blink(morty))
|
|
|
|
self.dither()
|
2017-08-27 14:43:18 -07:00
|
|
|
|
|
|
|
|
|
|
|
#######
|
|
|
|
|
|
|
|
def arrange_photons_in_circle(self, photons):
|
|
|
|
R = np.sqrt(len(photons) / np.pi)
|
|
|
|
pairs = []
|
|
|
|
rejected = []
|
|
|
|
for x, y in it.product(*[range(-int(R)-1, int(R)+2)]*2):
|
|
|
|
if x**2 + y**2 < R**2:
|
|
|
|
pairs.append((x, y))
|
|
|
|
else:
|
|
|
|
rejected.append((x, y))
|
|
|
|
rejected.sort(
|
|
|
|
lambda (x1, y1), (x2, y2) : (x2**2 + y2**2) - (x1**2 + y1**2)
|
|
|
|
)
|
|
|
|
for i in range(len(photons) - len(pairs)):
|
|
|
|
pairs.append(rejected.pop())
|
|
|
|
for photon, (x, y) in zip(photons, pairs):
|
|
|
|
photon.scale_to_fit_width(0.7)
|
|
|
|
photon.move_to(x*RIGHT + y*UP)
|
|
|
|
return photons
|
|
|
|
|
2017-08-29 20:00:48 -07:00
|
|
|
class PonderingPiCreature(Scene):
|
|
|
|
def construct(self):
|
|
|
|
randy = Randolph()
|
|
|
|
randy.to_edge(DOWN).shift(3*LEFT)
|
|
|
|
self.play(randy.change, "pondering", UP+RIGHT)
|
|
|
|
self.play(Blink(randy))
|
|
|
|
self.dither(2)
|
|
|
|
self.play(Blink(randy))
|
|
|
|
self.dither(2)
|
|
|
|
|
|
|
|
class ReEmphasizeVennDiagram(VennDiagramProofByContradiction):
|
|
|
|
def construct(self):
|
|
|
|
self.draw_venn_diagram(send_to_corner = False)
|
|
|
|
self.rescale_diagram()
|
|
|
|
self.setup_faded_circles()
|
|
|
|
self.shift_B_circle()
|
|
|
|
self.shift_C_circle()
|
|
|
|
self.write_inequality()
|
|
|
|
self.show_inequality_with_circle()
|
|
|
|
self.emphasize_containment()
|
|
|
|
self.write_50_percent()
|
|
|
|
self.write_assumption()
|
|
|
|
self.adjust_circles()
|
|
|
|
|
|
|
|
def rescale_diagram(self):
|
|
|
|
self.play(
|
|
|
|
self.venn_diagram.scale, 0.7,
|
|
|
|
self.venn_diagram.to_edge, DOWN, MED_SMALL_BUFF,
|
|
|
|
)
|
|
|
|
self.clear()
|
|
|
|
self.add_foreground_mobject(self.venn_diagram)
|
|
|
|
|
|
|
|
def setup_faded_circles(self):
|
|
|
|
self.circles = self.venn_diagram[:3]
|
|
|
|
self.black_circles = VGroup(*[
|
|
|
|
circ.copy().set_stroke(width = 0).set_fill(BLACK, 1)
|
|
|
|
for circ in self.circles
|
|
|
|
])
|
|
|
|
self.filled_circles = VGroup(*[
|
|
|
|
circ.copy().set_stroke(width = 0).set_fill(circ.get_color(), 1)
|
|
|
|
for circ in self.circles
|
|
|
|
])
|
|
|
|
|
|
|
|
def shift_B_circle(self):
|
|
|
|
A, B, C = self.circles
|
|
|
|
A0, B0, C0 = self.black_circles
|
|
|
|
A1, B1, C1 = self.filled_circles
|
|
|
|
|
|
|
|
words = TextMobject("Should be 15\\% \\\\ of circle ", "A")
|
|
|
|
words.scale(0.7)
|
|
|
|
words.highlight_by_tex("A", RED)
|
|
|
|
words.next_to(A, UP, LARGE_BUFF)
|
|
|
|
words.shift(RIGHT)
|
|
|
|
arrow = Arrow(
|
|
|
|
words.get_bottom(),
|
|
|
|
A.get_top() + MED_SMALL_BUFF*RIGHT,
|
|
|
|
color = RED
|
|
|
|
)
|
|
|
|
|
|
|
|
self.play(FadeIn(A1))
|
|
|
|
self.play(FadeIn(B0))
|
|
|
|
self.play(
|
|
|
|
FadeIn(words, submobject_mode = "lagged_start"),
|
|
|
|
ShowCreation(arrow)
|
|
|
|
)
|
|
|
|
self.dither()
|
|
|
|
vect = 0.6*(A.get_center() - B.get_center())
|
|
|
|
self.play(
|
|
|
|
B0.shift, vect,
|
|
|
|
B.shift, vect,
|
|
|
|
B.label.shift, vect,
|
|
|
|
run_time = 2,
|
|
|
|
rate_func = running_start,
|
|
|
|
)
|
|
|
|
B1.shift(vect)
|
|
|
|
self.dither()
|
|
|
|
|
|
|
|
self.in_A_out_B_words = words
|
|
|
|
self.in_A_out_B_arrow = arrow
|
|
|
|
for mob in words, arrow:
|
|
|
|
mob.save_state()
|
|
|
|
|
|
|
|
def shift_C_circle(self):
|
|
|
|
A, B, C = self.circles
|
|
|
|
A0, B0, C0 = self.black_circles
|
|
|
|
A1, B1, C1 = self.filled_circles
|
|
|
|
|
|
|
|
words = TextMobject("Should be 15\\% \\\\ of circle ", "B")
|
|
|
|
words.scale(0.7)
|
|
|
|
words.highlight_by_tex("B", GREEN)
|
|
|
|
words.next_to(B, LEFT)
|
|
|
|
words.shift(2.5*UP)
|
|
|
|
arrow = Arrow(
|
|
|
|
words.get_bottom(),
|
|
|
|
B.point_from_proportion(0.4),
|
|
|
|
color = GREEN
|
|
|
|
)
|
|
|
|
|
|
|
|
self.play(
|
|
|
|
FadeOut(A1),
|
|
|
|
FadeOut(B0),
|
|
|
|
self.in_A_out_B_words.fade, 0.7,
|
|
|
|
self.in_A_out_B_arrow.fade, 0.7,
|
|
|
|
FadeIn(B1),
|
|
|
|
FadeIn(words, submobject_mode = "lagged_start"),
|
|
|
|
ShowCreation(arrow)
|
|
|
|
)
|
|
|
|
self.play(FadeIn(C0))
|
|
|
|
self.dither(2)
|
|
|
|
vect = 0.5*(B.get_center() - C.get_center())
|
|
|
|
self.play(
|
|
|
|
C0.shift, vect,
|
|
|
|
C.shift, vect,
|
|
|
|
C.label.shift, vect,
|
|
|
|
run_time = 2,
|
|
|
|
rate_func = running_start,
|
|
|
|
)
|
|
|
|
C1.shift(vect)
|
|
|
|
self.dither()
|
2017-08-27 14:43:18 -07:00
|
|
|
|
2017-08-29 20:00:48 -07:00
|
|
|
self.in_B_out_C_words = words
|
|
|
|
self.in_B_out_C_arrow = arrow
|
|
|
|
|
|
|
|
def write_inequality(self):
|
|
|
|
A, B, C = self.circles
|
|
|
|
A0, B0, C0 = self.black_circles
|
|
|
|
A1, B1, C1 = self.filled_circles
|
|
|
|
|
|
|
|
inequality = VGroup(
|
|
|
|
TexMobject("N(", "A", "+", ",", "C", "-", ")"),
|
|
|
|
TexMobject("\\le"),
|
|
|
|
TexMobject("N(", "B", "+", ",", "C", "-", ")"),
|
|
|
|
TexMobject("+"),
|
|
|
|
TexMobject("N(", "A", "+", ",", "B-", ")"),
|
|
|
|
)
|
|
|
|
inequality.arrange_submobjects(RIGHT)
|
|
|
|
for tex in inequality:
|
|
|
|
tex.highlight_by_tex_to_color_map({
|
|
|
|
"A" : RED,
|
|
|
|
"B" : GREEN,
|
|
|
|
"C" : BLUE,
|
|
|
|
})
|
|
|
|
inequality.to_edge(UP)
|
2017-08-27 14:43:18 -07:00
|
|
|
|
2017-08-29 20:00:48 -07:00
|
|
|
self.play(
|
|
|
|
Write(inequality),
|
|
|
|
A.label[0].fade, 1,
|
|
|
|
A.label[1].move_to, A.label[0], LEFT,
|
|
|
|
B.label[0].fade, 1,
|
|
|
|
C.label[0].fade, 1,
|
|
|
|
C.label[1].move_to, C.label[0], LEFT,
|
|
|
|
self.in_A_out_B_words.fade, 1,
|
|
|
|
self.in_A_out_B_arrow.fade, 1,
|
|
|
|
)
|
|
|
|
for circle in A, B, C:
|
|
|
|
circle.label.remove(circle.label[0])
|
|
|
|
self.remove(circle.label[0])
|
|
|
|
|
|
|
|
|
|
|
|
self.inequality = inequality
|
|
|
|
|
|
|
|
def show_inequality_with_circle(self):
|
|
|
|
A, B, C = self.circles
|
|
|
|
A0, B0, C0 = self.black_circles
|
|
|
|
A1, B1, C1 = self.filled_circles
|
|
|
|
inequality = self.inequality
|
|
|
|
|
|
|
|
groups = VGroup(*[
|
|
|
|
VGroup(
|
|
|
|
m2.copy(), m1.copy(),
|
|
|
|
self.venn_diagram.copy()
|
|
|
|
)
|
|
|
|
for m1, m2 in (C0, A1), (C0, B1), (B0, A1)
|
|
|
|
])
|
|
|
|
groups[0][0].set_fill(YELLOW)
|
|
|
|
for group in groups[0], groups[2]:
|
|
|
|
group.save_state()
|
|
|
|
group.fade(1)
|
2017-08-27 14:43:18 -07:00
|
|
|
|
|
|
|
|
2017-08-29 20:00:48 -07:00
|
|
|
self.remove(self.venn_diagram, self.black_circles, self.filled_circles)
|
|
|
|
self.play(
|
|
|
|
groups[0].restore,
|
|
|
|
groups[0].scale_in_place, 0.5,
|
|
|
|
groups[0].shift, 4*LEFT,
|
|
|
|
##
|
|
|
|
groups[2].restore,
|
|
|
|
groups[2].scale_in_place, 0.5,
|
|
|
|
groups[2].shift, 4*RIGHT,
|
|
|
|
self.in_A_out_B_words.restore,
|
|
|
|
self.in_A_out_B_words.move_to, 4*RIGHT+UP,
|
|
|
|
FadeOut(self.in_A_out_B_arrow),
|
|
|
|
##
|
|
|
|
groups[1].scale_in_place, 0.5,
|
|
|
|
self.in_B_out_C_words.move_to, UP,
|
|
|
|
FadeOut(self.in_B_out_C_arrow),
|
|
|
|
)
|
|
|
|
self.play(
|
|
|
|
inequality.space_out_submobjects, 1.2,
|
|
|
|
inequality.shift, DOWN,
|
|
|
|
)
|
|
|
|
self.dither(2)
|
2017-08-24 11:44:06 -07:00
|
|
|
|
2017-08-29 20:00:48 -07:00
|
|
|
self.groups = groups
|
2017-08-24 11:44:06 -07:00
|
|
|
|
2017-08-29 20:00:48 -07:00
|
|
|
def emphasize_containment(self):
|
|
|
|
groups = self.groups
|
|
|
|
c1, c2 = [VGroup(*group[:2]).copy() for group in groups[1:]]
|
|
|
|
foreground = VGroup(groups[0][-1], *groups[1:])
|
2017-08-24 11:44:06 -07:00
|
|
|
|
2017-08-29 20:00:48 -07:00
|
|
|
rect = SurroundingRectangle(groups[0])
|
2017-08-24 11:44:06 -07:00
|
|
|
|
2017-08-29 20:00:48 -07:00
|
|
|
self.play(ShowCreation(rect))
|
|
|
|
self.play(FadeOut(rect))
|
|
|
|
self.play(
|
|
|
|
ApplyMethod(
|
|
|
|
c1.shift, 4*LEFT,
|
|
|
|
path_arc = -np.pi/2,
|
|
|
|
),
|
|
|
|
Animation(foreground)
|
|
|
|
)
|
|
|
|
self.play(
|
|
|
|
ApplyMethod(
|
|
|
|
c2.shift, 8*LEFT,
|
|
|
|
path_arc = -np.pi/2,
|
|
|
|
),
|
|
|
|
Animation(c1),
|
|
|
|
Animation(foreground),
|
|
|
|
run_time = 1.5
|
|
|
|
)
|
|
|
|
self.play(
|
|
|
|
FadeOut(c2),
|
|
|
|
FadeOut(c1),
|
|
|
|
Animation(foreground),
|
|
|
|
run_time = 2
|
|
|
|
)
|
|
|
|
self.dither()
|
2017-08-24 11:44:06 -07:00
|
|
|
|
2017-08-29 20:00:48 -07:00
|
|
|
def write_50_percent(self):
|
|
|
|
words = TextMobject(
|
|
|
|
"Should be 50\\% \\\\ of circle ", "A",
|
|
|
|
"...somehow"
|
|
|
|
)
|
|
|
|
words.scale(0.7)
|
|
|
|
words.highlight_by_tex("A", RED)
|
|
|
|
words.move_to(4*LEFT + UP)
|
2017-08-24 11:44:06 -07:00
|
|
|
|
2017-08-29 20:00:48 -07:00
|
|
|
self.play(Write(words))
|
|
|
|
self.dither()
|
2017-08-24 11:44:06 -07:00
|
|
|
|
2017-08-29 20:00:48 -07:00
|
|
|
def write_assumption(self):
|
|
|
|
words = TextMobject("Assume circles have the same size$^*$")
|
|
|
|
words.scale(0.8)
|
|
|
|
words.to_edge(UP)
|
|
|
|
|
|
|
|
footnote = TextMobject("""
|
|
|
|
*If you prefer, you can avoid the need for that
|
|
|
|
assumption by swapping the roles of A and C here
|
|
|
|
and writing a second inequality for added constraint.
|
|
|
|
""")
|
|
|
|
footnote.scale(0.5)
|
|
|
|
footnote.to_corner(DOWN+RIGHT)
|
|
|
|
footnote.add(words[-1])
|
|
|
|
words.remove(words[-1])
|
|
|
|
|
|
|
|
self.footnote = footnote
|
|
|
|
|
|
|
|
self.play(FadeIn(words))
|
|
|
|
|
|
|
|
def adjust_circles(self):
|
|
|
|
groups = self.groups
|
|
|
|
A_group = VGroup(
|
|
|
|
groups[0][0],
|
|
|
|
groups[2][0],
|
|
|
|
groups[0][2][0],
|
|
|
|
groups[1][2][0],
|
|
|
|
groups[2][2][0],
|
|
|
|
)
|
|
|
|
B_group = VGroup(
|
|
|
|
groups[1][0],
|
|
|
|
groups[2][1],
|
|
|
|
groups[0][2][1],
|
|
|
|
groups[1][2][1],
|
|
|
|
groups[2][2][1],
|
|
|
|
)
|
|
|
|
C_group = VGroup(
|
|
|
|
groups[0][1],
|
|
|
|
groups[1][1],
|
|
|
|
groups[0][2][2],
|
|
|
|
groups[1][2][2],
|
|
|
|
groups[2][2][2],
|
|
|
|
)
|
|
|
|
movers = [A_group, B_group, C_group]
|
|
|
|
vects = [UP, UP+LEFT, UP+RIGHT]
|
|
|
|
phases = [0, np.pi/8, np.pi/4]
|
|
|
|
amplitude = MED_SMALL_BUFF
|
|
|
|
|
|
|
|
self.time = 0
|
|
|
|
dt = self.frame_duration
|
|
|
|
freqs = [1.5, 2, 1]
|
|
|
|
|
|
|
|
def move_around(total_time):
|
|
|
|
self.time
|
|
|
|
for x in range(int(total_time/dt)):
|
|
|
|
self.time += dt
|
|
|
|
for mover, vect, phase, freq in zip(movers, vects, phases, freqs):
|
|
|
|
cos_val = np.cos(freq*self.time + phase)
|
|
|
|
mover.shift(amplitude*cos_val*vect*dt)
|
|
|
|
self.dither(self.frame_duration)
|
|
|
|
|
|
|
|
move_around(3)
|
|
|
|
self.add(self.footnote)
|
|
|
|
move_around(1)
|
|
|
|
self.remove(self.footnote)
|
|
|
|
move_around(11)
|
|
|
|
|
|
|
|
class NoFirstMeasurementPreferenceBasedOnDirection(ShowVariousFilterPairs):
|
|
|
|
CONFIG = {
|
|
|
|
"filter_x_coordinates" : [0, 0, 0],
|
|
|
|
"pol_filter_configs" : [
|
|
|
|
{"filter_angle" : angle}
|
|
|
|
for angle in 0, np.pi/8, np.pi/4
|
|
|
|
],
|
|
|
|
"lines_depth" : 1.2,
|
|
|
|
"lines_shift_vect" : SMALL_BUFF*OUT,
|
|
|
|
"n_lines" : 30,
|
|
|
|
}
|
|
|
|
def setup(self):
|
|
|
|
DirectionOfPolarization.setup(self)
|
|
|
|
self.remove(self.axes, self.em_wave)
|
|
|
|
zs = [2.5, 0, -2.5]
|
|
|
|
chars = "ABC"
|
|
|
|
colors = [RED, GREEN, BLUE]
|
|
|
|
for z, char, color, pf in zip(zs, chars, colors, self.pol_filters):
|
|
|
|
pf.scale_in_place(0.7)
|
|
|
|
pf.move_to(z*OUT)
|
|
|
|
label = TextMobject(char)
|
|
|
|
label.add_background_rectangle()
|
|
|
|
label.highlight(color)
|
|
|
|
label.scale(0.7)
|
|
|
|
label.rotate(np.pi/2, RIGHT)
|
|
|
|
label.rotate(-np.pi/2, OUT)
|
|
|
|
label.next_to(pf.arrow_label, UP, SMALL_BUFF)
|
|
|
|
pf.arrow_label.add(label)
|
2017-08-24 11:44:06 -07:00
|
|
|
|
2017-08-29 20:00:48 -07:00
|
|
|
self.add_foreground_mobject(pf)
|
2017-08-24 11:44:06 -07:00
|
|
|
|
2017-08-29 20:00:48 -07:00
|
|
|
def construct(self):
|
|
|
|
self.reposition_camera()
|
|
|
|
self.show_lines()
|
2017-08-24 11:44:06 -07:00
|
|
|
|
2017-08-29 20:00:48 -07:00
|
|
|
def reposition_camera(self):
|
|
|
|
words = TextMobject("No statistical preference")
|
|
|
|
words.to_corner(UP+LEFT)
|
|
|
|
words.rotate(np.pi/2, RIGHT)
|
|
|
|
self.move_camera(
|
|
|
|
theta = -0.6*np.pi,
|
|
|
|
added_anims = list(it.chain(*[
|
|
|
|
[
|
|
|
|
pf.arrow_label.rotate, np.pi/2, OUT,
|
2017-08-30 13:16:08 -07:00
|
|
|
pf.arrow_label.next_to, pf.arrow, OUT+RIGHT, SMALL_BUFF
|
2017-08-29 20:00:48 -07:00
|
|
|
]
|
|
|
|
for pf in self.pol_filters
|
|
|
|
] + [[FadeIn(words)]]))
|
|
|
|
)
|
2017-08-24 11:44:06 -07:00
|
|
|
|
2017-08-29 20:00:48 -07:00
|
|
|
def show_lines(self):
|
|
|
|
all_pre_lines = VGroup()
|
|
|
|
all_post_lines = VGroup()
|
|
|
|
for pf in self.pol_filters:
|
|
|
|
pre_lines = self.get_lines(None, pf)
|
|
|
|
post_lines = self.get_lines(pf, None)
|
|
|
|
VGroup(
|
|
|
|
*random.sample(post_lines, self.n_lines/2)
|
|
|
|
).set_stroke(BLACK, 0)
|
|
|
|
all_pre_lines.add(*pre_lines)
|
|
|
|
all_post_lines.add(*post_lines)
|
|
|
|
|
2017-08-30 13:16:08 -07:00
|
|
|
kwargs = {
|
|
|
|
"rate_func" : None,
|
|
|
|
"submobject_mode" : "all_at_once"
|
|
|
|
}
|
|
|
|
self.play(ShowCreation(all_pre_lines, **kwargs))
|
|
|
|
self.play(
|
|
|
|
ShowCreation(all_post_lines, **kwargs),
|
|
|
|
Animation(self.pol_filters),
|
|
|
|
Animation(all_pre_lines),
|
|
|
|
)
|
|
|
|
self.add_foreground_mobject(all_pre_lines)
|
2017-08-29 20:00:48 -07:00
|
|
|
self.dither(7)
|
2017-08-24 11:44:06 -07:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2017-08-27 23:52:28 -07:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2017-08-24 11:44:06 -07:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2017-08-28 10:52:49 -07:00
|
|
|
|
2017-08-24 11:44:06 -07:00
|
|
|
|
|
|
|
|