def construct(self): a = "a" b = "b" c = "c" d = "d" preferences = {a: [b, c, d], b: [c, d, a], c: [d, b, a], d: [a, b, c]} T = PreferenceTable(preferences, center=[-3.5, 0, 0]) C = Cycle([a, b, c, a], [b, c, d, b], center=[3, 0, 0]) self.play(*T.create()) self.play(*T.propose(a, b), *T.propose(b, c), *T.propose(c, d)) self.play(*T.accept_proposal(a, b), *T.accept_proposal(b, c), *T.accept_proposal(c, d)) self.wait() self.play(*C.create()) self.play(*C.accept(0, 1)) self.play(*C.reject(0, 1)) self.wait() # for anim in C.create_from_table(T): # self.play(anim) # self.wait(2) # self.play(*C.cut_first_prefs(T)) # self.wait(2) # self.play(*C.accept_second_prefs(T)) # self.wait(2) # self.play(*C.uncreate()) self.wait(2)
def construct(self): title = Text("Preference Cycles:") self.play(Create(title)) self.wait(1) self.play(ApplyMethod(title.shift, 3 * UP)) self.wait(1) definition = Tex("A sequence of players $a_1, a_2, \ldots, a_r$", color=WHITE).scale(0.8).shift(1.9 * UP) self.play(Create(definition)) self.wait(1) cycle = Cycle(["$a_1$", "$a_2$", "$a_3$", "$a_4$", "$a_5$", "$a_1$"], ["$b_1$", "$b_2$", "$b_3$", "$b_4$", "$b_5$", "$b_1$"], center=[0,-0.5,0]) self.play(*[Create(a) for a in cycle.A_mobs[:-1]]) definition2 = Tex("with first preferences $b_1, b_2, \ldots, b_r$", color=WHITE).scale(0.8).shift(1.4 * UP) self.play(Create(definition2)) self.wait(1) self.play(*[Create(b) for b in cycle.B_mobs[:-1]]) first_pref_arrows = [arrow for i,arrow in enumerate(cycle.arrows[:-2]) if i % 2 == 0] second_pref_arrows = [arrow for i,arrow in enumerate(cycle.arrows[:-2]) if i % 2 == 1] self.play(*[Create(ar.curr_arrow()) for ar in first_pref_arrows]) self.wait(2) definition3 = Tex("where the second favorite of $a_i$ is $b_{i+1},$", color=WHITE).scale(0.8).shift(2.4 * DOWN) self.play(Create(definition3)) self.wait(1) self.play(*[Create(ar.curr_arrow()) for ar in second_pref_arrows]) self.wait(2) definition4 = Tex("wrapping around for $a_r$ and $a_1$.", color=WHITE).scale(0.8).shift(2.9 * DOWN) self.play(Create(definition4)) self.play(Create(cycle.A_mobs[-1]), Create(cycle.B_mobs[-1])) self.play(Create(cycle.arrows[-2].curr_arrow()), Create(cycle.arrows[-1].curr_arrow())) self.wait(5) self.play(*[Uncreate(d) for d in (definition, definition2, definition3, definition4)]) self.wait(1) elimination = Tex("We \\emph{eliminate} the cycle by having $b_1$ reject $a_1$.", color=WHITE).scale(0.8).shift(1.5 * UP) self.play(Create(elimination)) self.wait(1) self.play(*(cycle.reject(0,0) + cycle.reject(5,5))) self.wait(1) elimination2 = Tex("Each $b_i$ has $a_i$ as its least favorite, so it rejects", color=WHITE).scale(0.8).shift(2.4 * DOWN) self.play(Create(elimination2)) elimination3 = Tex("$a_i$ to match with $a_{i-1}$.", color=WHITE).scale(0.8).shift(2.9 * DOWN) self.play(Create(elimination3)) self.wait(1) for i in range(5): self.play(*cycle.reject(i+1,i+1)) self.play(*cycle.accept(i,i+1)) self.wait(5)
def construct(self): why_text = Tex("Why we can remove cycles") self.play(Write(why_text)) self.play(ApplyMethod(why_text.shift, UP * 3.5)) lemma1 = r""" \begin{align*} \text{Lemma 1: }&\text{in any stable $M$ in the reduced table,}\\ &a_i\text{ and }b_i \text{ are matched either}\\ &\text{for all }i \text{ or for no }i\end{align*}""" lemma1 = Tex(lemma1).next_to(why_text, DOWN * 2) self.play(Write(lemma1)) def math_list(base, start, end): return [ "$" + base + "_" + str(i) + "$" for i in range(start, end) ] As = math_list("a", 1, 5) + ["$a_1$"] Bs = math_list("b", 1, 5) + ["$b_1$"] c = Cycle(As, Bs, center = DOWN * 1.5) self.play(*c.create()) self.wait(1) say_text = Tex("Let $b_3$ reject $a_3$") \ .next_to(lemma1, DOWN * 2) \ .shift(LEFT * 3) self.play(Write(say_text)) next_text = Tex("$a_3$ proposes to $b_4$") \ .next_to(lemma1, DOWN * 2) \ .shift(RIGHT * 3) self.wait(1) self.play(*c.reject(2, 2)) self.wait(1) self.play(Write(next_text)) self.play(*c.accept(2, 3)) self.play(*c.reject(3, 3)) self.play(*c.accept(3, 4)) self.play(*(c.reject(4, 4) + c.reject(0, 0))) self.play(*c.accept(0, 1)) self.play(*c.reject(1, 1)) self.play(*c.accept(1, 2)) self.play(*(c.uncreate())) self.wait(1) thus_text = Tex(r"""Thus if any $a_i$ is not matched with its $b_i$\\ then no $a_i$ can match with its $b_i$""") \ .next_to(lemma1, DOWN * 6) self.play(Write(thus_text)) self.wait(1) self.play(*[ Uncreate(m) for m in [thus_text, next_text, say_text] ]) shift_amt = 15 let_m = Tex(r""" Let $M$ be a stable matching where each $a_i$ is matched\\ with its $b_i$. Let $M'$ be the same matching, but each\\ $a_i$ is matched with its second choice $b_{i+1}$ """).next_to(why_text, DOWN * 2).shift(RIGHT * shift_amt) self.add(let_m) self.play(*[ ApplyMethod(t.shift, LEFT * shift_amt) for t in [lemma1, let_m] ]) lemma2 = Tex("Lemma 2: $M'$ is stable if $M$ is stable") \ .next_to(let_m, DOWN * 2) self.play(Write(lemma2)) self.wait() As = ["$a_k$", ""] Bs = ["$b_k$", "$b_{k+1}$"] c = Cycle(As, Bs, center = DOWN * 1.5) c.reject(0, 0) c.accept(0, 1) mobjs = c.get_all_mobjs() mobjs.pop(2) self.play(*[ Create(m) for m in mobjs ]) b_better_text = Tex(r"Each $b_i$ is better\\ off in $M'$ than $M$") \ .shift(LEFT * 4 + DOWN) self.play(Write(b_better_text)) a_happy_text = Tex(r"$a_k$ can only prefer \\"+\ r"$b_k$ to its current match\\" +\ r"but $b_k$ is happier with\\" +\ r"$a_{k-1}$, so $M'$ is\\" +\ r"stable here") \ .shift(RIGHT * 4 + DOWN * 2) self.play(Write(a_happy_text)) self.play(*[ Uncreate(m) for m in mobjs + [b_better_text, a_happy_text] ]) continue_m = Tex(r"Thus $M$ stable $\Rightarrow$ $M'$ stable,\\" +\ r"so if there exists a stable matching, we\\" +\ r"can find it by proceeding with $M'$ and\\" +\ r"eliminating our cycle") \ .shift(DOWN * 1.5) self.play(Write(continue_m)) self.wait(2) self.play(*[ ApplyMethod(t.shift, RIGHT * shift_amt) for t in [lemma1, let_m] ] + [ Uncreate(m) for m in [continue_m] ] + [ ApplyMethod(t.shift, DOWN * 0.8) for t in [lemma2] ]) plus = TextMobject("+").shift(UP * 0.5) impl = TextMobject("$\\Leftarrow$") \ .rotate_in_place(PI/2).shift(DOWN) self.play(Create(impl), Create(plus)) self.wait(1) final = Tex(r"We can always eliminate cycles without\\"\ r"changing the result").next_to(impl, DOWN) self.play(Write(final)) self.wait(2)