PrivKV: Key-Value Data Collection with Local Differential Privacy论文阅读

文献阅读课需要制作ppt但是感觉选的这篇论文都是公式,决定做点动画直观展示一下。还没有完成会继续更新这个笔记

manim动画代码

但是其实不需要这两样也可以播放只是很丑陋。。。

论文的ppt做好了不知道怎么上传,后续整理成笔记完善一下这篇blog

概念 定义 噪声添加方式 优势 劣势 ε 相关性
差分隐私(DP,含 CDP) 保护查询结果不泄露个体数据,通过中心化添加噪声 在查询结果或中间计算中添加噪声 提供严格数学隐私保证,数据效用较高,适合有可信中心的场景 需要信任数据收集者,存在数据泄露风险 ε 小则隐私强,数据效用可能低
本地差分隐私(LDP) 用户本地扰动数据后再发送,无需可信第三方 每个数据点独立添加噪声 无需信任中心,增强隐私,用户控制数据,适合分布式架构 数据效用低,需较多用户参与,准确性通常低于 DP 常需高 ε 以平衡实用性
集中式差分隐私(CDP) 可信管理者收集数据后添加噪声发布结果 在聚合数据后添加噪声 数据效用较高,适合需要高准确度的场景 需要信任管理者,存在单点故障风险 与 DP 类似,ε 影响隐私与效用
python 复制代码
# -*- coding: utf-8 -*-
from manim import *
import numpy as np

config.background_color = "#121212" # Dark background

# ========================================================
# Helper Functions (Applying Fixes based on Analysis)
# ========================================================

def construct_intro(scene: Scene):
    """ Constructs the Introduction part of the animation. """
    # No issues reported here, code seems fine.
    title = Text("PrivKV: Key-Value Data Collection with Local Differential Privacy", font_size=40)
    title.to_edge(UP, buff=0.5)

    authors = Text("Author: Paper Reproduction Demo", font_size=24, color=BLUE_C)
    authors.next_to(title, DOWN, buff=0.5)

    scene.play(Write(title))
    scene.play(FadeIn(authors))
    scene.wait(2)

    problem_title = Text("Research Background", font_size=36, color=YELLOW)
    problem_title.to_edge(UP, buff=1.0) # Keep UP edge positioning

    problem_points = VGroup(
        Text("• User data privacy protection is increasingly important", font_size=24),
        Text("• Local Differential Privacy (LDP) does not require a trusted central party", font_size=24),
        Text("• Existing work mainly focuses on simple data types", font_size=24),
        Text("• Key-Value data is the main model for NoSQL", font_size=24),
        Text("• Challenge: Correlation exists between keys and values", font_size=24)
    ).arrange(DOWN, aligned_edge=LEFT, buff=0.4)
    # Ensure enough space below the title
    problem_points.next_to(problem_title, DOWN, buff=MED_LARGE_BUFF) # Increased buff

    scene.play(FadeOut(authors), TransformMatchingShapes(title, problem_title))
    scene.play(FadeIn(problem_points, lag_ratio=0.2))
    scene.wait(3)

    solution_title = Text("Our Work", font_size=36, color=YELLOW)
    solution_title.move_to(problem_title) # Keep position

    solution_points = VGroup(
        Text("• Proposed the first LDP solution for Key-Value data", font_size=24),
        Text("• Designed Local Perturbation Protocol (LPP) to handle key-value correlation", font_size=24),
        Text("• Developed an iterative scheme to improve accuracy (PrivKVM)", font_size=24),
        Text("• Proposed an adaptive scheme to balance accuracy and communication (PrivKVM+)", font_size=24),
        Text("• Optimization strategy: Virtual Iteration reduces network latency", font_size=24)
    ).arrange(DOWN, aligned_edge=LEFT, buff=0.4)
    # Ensure consistent spacing
    solution_points.next_to(solution_title, DOWN, buff=MED_LARGE_BUFF) # Match buff

    scene.play(Transform(problem_title, solution_title),
               FadeOut(problem_points, shift=DOWN*0.5),
               FadeIn(solution_points, shift=DOWN*0.5))
    scene.wait(3)

    return VGroup(problem_title, solution_points)


def construct_ldp_explanation(scene: Scene):
    """ Constructs the LDP Explanation part. """
    # No specific issues reported, but ensure formula clarity
    title = Text("Local Differential Privacy (LDP)", font_size=36)
    title.to_edge(UP, buff=0.5)
    scene.play(Write(title))
    scene.wait(1)

    ldp_def = VGroup(
        # Use slightly larger fonts for better readability
        MathTex(r"\text{For any two inputs } t, t' \in D \ \text{ and any output } t^* \text{:}", font_size=30),
        MathTex(r"\Pr[M(t) = t^*] \leq e^{\varepsilon} \times \Pr[M(t') = t^*]", font_size=36) # Larger formula
    ).arrange(DOWN, buff=0.4) # Slightly more space
    ldp_def.next_to(title, DOWN, buff=MED_LARGE_BUFF) # Consistent spacing

    scene.play(Write(ldp_def))
    scene.wait(2)

    explanation = VGroup()
    user_box = Rectangle(height=2.5, width=3, fill_color=BLUE_E, fill_opacity=0.3, stroke_color=BLUE)
    user_text = Text("User", font_size=24).next_to(user_box, UP, buff=0.2)
    user_data = MathTex(r"\text{Original data: } t").move_to(user_box)

    collector_box = Rectangle(height=2.5, width=3, fill_color=RED_E, fill_opacity=0.3, stroke_color=RED).shift(RIGHT * 5)
    collector_text = Text("Data Collector", font_size=24).next_to(collector_box, UP, buff=0.2)
    collector_data = MathTex(r"\text{Perturbed data: } t^*").move_to(collector_box)

    arrow = Arrow(user_box.get_right(), collector_box.get_left(), buff=0.1)
    ldp_mech = Text("LDP Perturbation\nMechanism M", font_size=22, color=GREEN, line_spacing=0.8).next_to(arrow, UP, buff=0.1)
    epsilon_text = MathTex(r"\text{Privacy budget: } \varepsilon").next_to(arrow, DOWN, buff=0.1)
    recovery_text = Text("Data collector cannot determine the original data", font_size=20, color=YELLOW).next_to(collector_box, DOWN, buff=0.5)

    explanation.add(
        user_box, user_text, user_data,
        collector_box, collector_text, collector_data,
        arrow, ldp_mech, epsilon_text
    )
    explanation.next_to(ldp_def, DOWN, buff=LARGE_BUFF) # Ensure space below definition

    scene.play(Create(user_box), Write(user_text), Write(user_data))
    scene.play(Create(collector_box), Write(collector_text), Write(collector_data))
    scene.play(GrowArrow(arrow), Write(ldp_mech), Write(epsilon_text))
    scene.play(Write(recovery_text))
    scene.wait(3)

    ldp_features = VGroup(
        Text("Key Features of LDP:", font_size=28, color=YELLOW),
        Text("• Perturbation occurs on the user side, not on a central server", font_size=22),
        Text("• Even if the data collector has all the data, original values cannot be recovered", font_size=22),
        Text("• Privacy guarantee is controlled by parameter ε (smaller ε = stronger privacy)", font_size=22)
    ).arrange(DOWN, aligned_edge=LEFT, buff=0.3)

    scene.play(
        FadeOut(ldp_def),
        FadeOut(explanation),
        FadeOut(recovery_text)
    )

    ldp_features.next_to(title, DOWN, buff=MED_LARGE_BUFF) # Match buff
    scene.play(Write(ldp_features, lag_ratio=0.2))
    scene.wait(3)

    return VGroup(title, ldp_features)


def construct_key_value_model(scene: Scene):
    """ Constructs the Key-Value Data Model part. """
    # Issue: Formulas potentially not displaying correctly.
    # Fix: Ensure MathTex syntax is correct (already checked, seems okay).
    #      Verify add/play logic (seems okay). Check scale/position/color (seems okay).
    #      Add comment about checking LaTeX installation if issues persist.
    title = Text("Key-Value Data Model", font_size=36)
    title.to_edge(UP, buff=0.5)
    scene.play(Write(title))
    scene.wait(1)

    # NOTE: If formulas below don't render, double-check LaTeX syntax and installation.
    definition = VGroup(
        Text("Definition:", font_size=28, color=YELLOW),
        MathTex(r"\bullet \text{ Key space } K = \{1, 2, \dots, d\}", font_size=24),
        MathTex(r"\bullet \text{ Value domain } V = [-1, 1]", font_size=24),
        # This line uses correct LaTeX angle brackets and set notation braces
        MathTex(r"\bullet \text{ User } i \text{ owns a set } S_i = \{\langle k_j, v_j \rangle\}", font_size=24),
        MathTex(r"\bullet \text{ Key } k_j \in K, \text{ Value } v_j \in V", font_size=24)
    ).arrange(DOWN, aligned_edge=LEFT, buff=0.3)
    definition.next_to(title, DOWN, buff=MED_LARGE_BUFF) # Consistent spacing

    scene.play(FadeIn(definition, lag_ratio=0.2))
    scene.wait(2)

    example_title = Text("Real-world Examples", font_size=28, color=YELLOW)
    example_title.next_to(definition, DOWN, buff=LARGE_BUFF) # More space before examples

    example1 = VGroup(
        Text("Ex 1: Video Ad Performance", font_size=24, color=BLUE),
        Text("• Key: Ad ID", font_size=22),
        Text("• Value: Viewing duration", font_size=22),
        Text("• Goal: Analyze ad popularity privately", font_size=22)
    ).arrange(DOWN, aligned_edge=LEFT, buff=0.2)

    example2 = VGroup(
        Text("Ex 2: Mobile App Activity", font_size=24, color=GREEN),
        Text("• Key: App ID", font_size=22),
        Text("• Value: Usage time/frequency", font_size=22),
        Text("• Goal: Analyze app usage privately", font_size=22)
    ).arrange(DOWN, aligned_edge=LEFT, buff=0.2)

    examples = VGroup(example1, example2).arrange(RIGHT, buff=1.5) # Increase buff for separation
    examples.next_to(example_title, DOWN, buff=MED_LARGE_BUFF) # Consistent spacing

    scene.play(Write(example_title))
    scene.play(FadeIn(examples, lag_ratio=0.2))
    scene.wait(3)

    return VGroup(title, definition, example_title, examples)


def construct_estimation_goals(scene: Scene):
    """ Constructs the Estimation Goals part. """
    # Issue: Formulas potentially not displaying. Same checks as above apply.
    title = Text("Statistical Goals", font_size=36)
    title.to_edge(UP, buff=0.5)
    scene.play(Write(title))
    scene.wait(1)

    freq_title = Text("1. Frequency Estimation", font_size=28, color=BLUE)
    freq_title.next_to(title, DOWN, buff=MED_LARGE_BUFF) # Consistent spacing

    # NOTE: If formulas below don't render, double-check LaTeX syntax and installation.
    freq_formula = MathTex(
        r"f_k = \frac{|\{u_i \mid \exists \langle k, v \rangle \in S_i\}|}{n}", font_size=30 # Slightly larger
    )
    freq_formula.next_to(freq_title, DOWN, buff=0.4)
    freq_explanation = Text("Proportion of users having key k", font_size=22)
    freq_explanation.next_to(freq_formula, DOWN, buff=0.3)

    scene.play(Write(freq_title))
    scene.play(Write(freq_formula))
    scene.play(FadeIn(freq_explanation))
    scene.wait(2)

    mean_title = Text("2. Mean Estimation", font_size=28, color=GREEN)
    mean_title.next_to(freq_explanation, DOWN, buff=LARGE_BUFF) # More vertical space

    # NOTE: If formulas below don't render, double-check LaTeX syntax and installation.
    mean_formula = MathTex(
        # Use \cdot for multiplication clarity if needed
        r"m_k = \frac{\sum_{i} \sum_{j:k_j=k} v_j}{n \cdot f_k}", font_size=30 # Slightly larger
    )
    mean_formula.next_to(mean_title, DOWN, buff=0.4)
    mean_explanation = Text("Average value for key k across relevant users", font_size=22)
    mean_explanation.next_to(mean_formula, DOWN, buff=0.3)

    scene.play(Write(mean_title))
    scene.play(Write(mean_formula))
    scene.play(FadeIn(mean_explanation))
    scene.wait(2)

    challenges_title = Text("Main Challenge", font_size=28, color=RED)
    # Position near the bottom clearly
    challenges_title.to_edge(DOWN, buff=1.5)

    challenges = Text("Key-Value Correlation: Perturbing key affects value interpretation", font_size=24)
    challenges.next_to(challenges_title, UP, buff=0.3) # Position above the title

    scene.play(Write(challenges)) # Write text first
    scene.play(Write(challenges_title)) # Then title below it
    scene.wait(3)

    return VGroup(title, freq_title, freq_formula, freq_explanation,
                  mean_title, mean_formula, mean_explanation,
                  challenges_title, challenges)


def construct_kv_challenge(scene: Scene):
    """ Constructs the Key-Value Perturbation Challenge part. """
    # No specific issues reported, layout seems okay. Ensure enough spacing.
    title = Text("Key-Value Correlation Challenge", font_size=36)
    title.to_edge(UP, buff=0.5)
    scene.play(Write(title))
    scene.wait(1)

    problem_text = VGroup(
        Text("Problem:", font_size=28, color=YELLOW),
        Text("How to perturb key-value pairs while preserving meaning?", font_size=24, line_spacing=0.8)
    ).arrange(DOWN, aligned_edge=LEFT, buff=0.3)
    problem_text.next_to(title, DOWN, buff=MED_LARGE_BUFF) # Consistent spacing

    scene.play(FadeIn(problem_text))
    scene.wait(2)

    naive_title = Text("Incorrect Approach: Perturb Key and Value Independently", font_size=28, color=RED)
    naive_title.next_to(problem_text, DOWN, buff=LARGE_BUFF) # More space

    original_data = VGroup(
        Text("Original User Data:", font_size=24),
        MathTex(r"S_i = \{\langle \text{Cancer}, 0.6 \rangle, \langle \text{HIV}, 0.9 \rangle, \dots\}", font_size=26)
    ).arrange(DOWN, buff=0.3)
    original_data.next_to(naive_title, DOWN, buff=MED_LARGE_BUFF) # Consistent spacing

    perturbation_flow = VGroup(
         MathTex(r"\text{Original Pair: } \langle \text{Cancer}, 0.6 \rangle"),
         MathTex(r"\Downarrow \text{ Independent Perturbation } \Downarrow"),
         MathTex(r"\text{Perturbed Pair: } \langle \text{Fever}, 0.75 \rangle \quad (\text{Key: Cancer} \to \text{Fever, Value: } 0.6 \to 0.75)")
    ).arrange(DOWN, buff=0.3)
    perturbation_flow.next_to(original_data, DOWN, buff=MED_LARGE_BUFF) # Consistent spacing

    problem_explanation = VGroup(
        Text("Issue:", font_size=24, color=RED),
        Text("Value 0.75 may be meaningless for the key 'Fever'", font_size=22),
        Text("Correlation is lost!", font_size=22)
    ).arrange(DOWN, buff=0.2)
    problem_explanation.next_to(perturbation_flow, DOWN, buff=MED_LARGE_BUFF) # Consistent spacing

    scene.play(Write(naive_title))
    scene.play(FadeIn(original_data))
    scene.play(Write(perturbation_flow))
    scene.play(FadeIn(problem_explanation))
    scene.wait(3)

    scene.play(
        FadeOut(naive_title), FadeOut(original_data),
        FadeOut(perturbation_flow), FadeOut(problem_explanation)
    )

    solution_text = VGroup(
        Text("Required Solution:", font_size=28, color=GREEN),
        Text("• Maintain key-value correlation during perturbation", font_size=24),
        Text("• Satisfy ε-local differential privacy", font_size=24),
        Text("• Enable accurate frequency and mean estimation", font_size=24)
    ).arrange(DOWN, aligned_edge=LEFT, buff=0.3)
    # Position relative to problem_text to ensure spacing
    solution_text.next_to(problem_text, DOWN, buff=LARGE_BUFF)

    scene.play(FadeIn(solution_text, lag_ratio=0.2))
    scene.wait(3)

    return VGroup(title, problem_text, solution_text)


def construct_vpp_algorithm(scene: Scene):
    """ Constructs the VPP Algorithm part. """
    # Issue: VPP Title Overlapping Content.
    # Fix: Ensure algorithm_group is positioned relative to title with enough buffer.
    # Issue: Potential for white blocks if MathTex fails. Check formulas.
    # --- Store the original title ---
    original_vpp_title = Text("Value Perturbation Primitive (VPP)", font_size=36)
    original_vpp_title.to_edge(UP, buff=0.5)
    scene.play(Write(original_vpp_title))
    scene.wait(1)

    # --- Algorithm description part ---
    algorithm_box = Rectangle(height=5.5, width=9, color=GREEN)
    algorithm_title = Text("Algorithm 2: Value Perturbation Primitive (VPP)", font_size=28)
    algorithm_title.next_to(algorithm_box, UP, buff=0.2)
    # ... (inputs, outputs, steps, content_group definition remains the same) ...
    inputs = VGroup(
        Text("Input:", font_size=24, color=YELLOW),
        MathTex(r"\text{- Value } v \in [-1, 1]", font_size=22),
        MathTex(r"\text{- Privacy budget } \varepsilon", font_size=22)
    ).arrange(DOWN, aligned_edge=LEFT, buff=0.1)

    outputs = VGroup(
        Text("Output:", font_size=24, color=YELLOW),
        MathTex(r"\text{- Perturbed value } v^* \in \{-1, 1\}", font_size=22)
    ).arrange(DOWN, aligned_edge=LEFT, buff=0.1)

    steps = VGroup(
        MathTex(r"1.~\text{Discretize to } \{-1, 1\}:", font_size=22),
        MathTex(r"~~~v_d = 1, \quad \text{w.p. } \frac{1+v}{2}", font_size=22), # Use w.p. for clarity
        MathTex(r"~~~v_d = -1, \quad \text{w.p. } \frac{1-v}{2}", font_size=22),
        MathTex(r"2.~\text{Randomized Response (perturb):}", font_size=22),
        MathTex(r"~~~v^* = v_d, \quad \text{w.p. } \frac{e^\varepsilon}{1+e^\varepsilon}", font_size=22),
        MathTex(r"~~~v^* = -v_d, \quad \text{w.p. } \frac{1}{1+e^\varepsilon}", font_size=22),
        MathTex(r"3.~\text{Return } v^*", font_size=22)
    ).arrange(DOWN, aligned_edge=LEFT, buff=0.15) # Slightly more buff

    content_group = VGroup(inputs, outputs, steps).arrange(DOWN, buff=0.4, aligned_edge=LEFT)
    content_group.move_to(algorithm_box.get_center()).shift(LEFT * 0.5)
    # --- End algorithm description part ---

    algorithm_group = VGroup(algorithm_box, algorithm_title, content_group)
    # Position explicitly below the *original* title with large buffer
    algorithm_group.scale(0.9).next_to(original_vpp_title, DOWN, buff=LARGE_BUFF)

    scene.play(FadeIn(algorithm_group))
    scene.wait(4)

    scene.play(FadeOut(algorithm_group)) # Fade out the algorithm description

    # --- Example part ---
    example_title = Text("VPP Example: v = 0.7, ε = 1.0", font_size=32)
    # Position consistently where the original title was
    example_title.to_edge(UP, buff=0.5)
    # Replace original title with example title smoothly
    scene.play(ReplacementTransform(original_vpp_title, example_title)) # Transform instead of just Write

    original_value = MathTex(r"\text{Original value: } v = 0.7", font_size=30)
    original_value.next_to(example_title, DOWN, buff=MED_LARGE_BUFF)
    scene.play(Write(original_value))
    scene.wait(1)

    # ... (Discretization and Perturbation steps definition remains the same) ...
    discretization_title = Text("Step 1: Discretization", font_size=28)
    discretization_title.next_to(original_value, DOWN, buff=MED_LARGE_BUFF)
    p_pos = (1 + 0.7) / 2
    p_neg = (1 - 0.7) / 2
    discretization_calc = VGroup(
        MathTex(fr"P(v_d = 1) = \frac{{1+0.7}}{{2}} = {p_pos:.2f}", font_size=24),
        MathTex(fr"P(v_d = -1) = \frac{{1-0.7}}{{2}} = {p_neg:.2f}", font_size=24)
    ).arrange(DOWN, buff=0.3)
    discretization_calc.next_to(discretization_title, DOWN, buff=0.3)

    scene.play(Write(discretization_title))
    scene.play(Write(discretization_calc))
    scene.wait(2)

    perturbation_title = Text("Step 2: Perturbation (Rand. Resp.)", font_size=28)
    perturbation_title.next_to(discretization_calc, DOWN, buff=LARGE_BUFF) # More space
    p_keep = np.exp(1.0) / (1 + np.exp(1.0))
    p_flip = 1 / (1 + np.exp(1.0))
    perturbation_calc = VGroup(
        MathTex(fr"P(\text{{Keep }} v_d) = \frac{{e^1}}{{1+e^1}} \approx {p_keep:.2f}", font_size=24),
        MathTex(fr"P(\text{{Flip }} v_d) = \frac{1}{{1+e^1}} \approx {p_flip:.2f}", font_size=24)
    ).arrange(DOWN, buff=0.3)
    perturbation_calc.next_to(perturbation_title, DOWN, buff=0.3)

    scene.play(Write(perturbation_title))
    scene.play(Write(perturbation_calc))
    scene.wait(2)
    # --- End Example part ---

    conclusion = Text("Result v* is either 1 or -1, satisfying ε-LDP", font_size=28, color=BLUE)
    conclusion.next_to(perturbation_calc, DOWN, buff=LARGE_BUFF)
    scene.play(Write(conclusion))
    scene.wait(3)

    # --- Fix: Fade out ALL elements of this section, including the example title ---
    elements_to_fade = VGroup(
        example_title, original_value, # Use the example_title which replaced the original one
        discretization_title, discretization_calc,
        perturbation_title, perturbation_calc,
        conclusion
    )
    scene.play(FadeOut(elements_to_fade))
    # --- End Fix ---

    # Return an empty group as all content specific to VPP is now faded out internally.
    return VGroup()



def construct_lpp_algorithm(scene: Scene):
    """ Constructs the LPP Algorithm part. """
    # No specific issues reported, layout seems okay.
    title = Text("Local Perturbation Protocol (LPP)", font_size=36)
    title.to_edge(UP, buff=0.5)
    scene.play(Write(title))
    scene.wait(1)

    lpp_summary = VGroup(
        Text("Algorithm 3: Local Perturbation Protocol (LPP)", font_size=28, color=YELLOW),
        MathTex(r"\text{Handles one pair } \langle k, v \rangle \text{ with budget } \varepsilon = \varepsilon_1 + \varepsilon_2", font_size=22), # Use MathTex
        Text("1. Perturb Key (k → j) using mechanism M₁ (budget ε₁)", font_size=22),
        Text("2. IF key is kept (k = j):", font_size=22),
        Text("   Perturb Value (v → v*) using VPP (budget ε₂)", font_size=22),
        Text("3. IF key is changed (k ≠ j):", font_size=22),
        Text("   Assign New Value (v* = ±1 uniformly) (implicit budget ε₂)", font_size=22),
        MathTex(r"4. \text{Output: } (j, \langle k, v^* \rangle) \quad \text{(Original key k included!)}", font_size=22, color=GREEN) # Use MathTex
    ).arrange(DOWN, aligned_edge=LEFT, buff=0.25)
    lpp_summary.next_to(title, DOWN, buff=MED_LARGE_BUFF).scale(0.95) # Add scaling

    scene.play(FadeIn(lpp_summary, lag_ratio=0.1))
    scene.wait(5)

    privacy_title = Text("LPP Privacy Guarantee", font_size=32, color=GREEN)
    privacy_theorem = MathTex(
        r"\text{Theorem 4.1: LPP satisfies } (\varepsilon_1 + \varepsilon_2)\text{-LDP}", font_size=28)

    privacy_group = VGroup(privacy_title, privacy_theorem).arrange(DOWN, buff=0.4)
    # Position near bottom, leaving space above
    privacy_group.to_edge(DOWN, buff=LARGE_BUFF)

    scene.play(FadeOut(lpp_summary, shift=UP*0.5), FadeIn(privacy_group, shift=UP*0.5))
    scene.wait(3)

    return VGroup(title, privacy_group)


def construct_privkv_algorithm(scene: Scene):
    """ Constructs the PrivKV Algorithm Flow part. """
    # Issue: privkv algorithm flow exceeding boundaries / flowchart
    # Fix: Scale down the workflow_group. Ensure positioning allows space.
    # Fix: Reduce font size within workflow boxes if necessary.
    title = Text("PrivKV Algorithm Flow", font_size=40)
    title.to_edge(UP, buff=0.5)
    scene.play(Write(title))
    scene.wait(1)

    privkv_summary = VGroup(
         Text("Algorithm 4: PrivKV (Basic)", font_size=28, color=YELLOW),
         Text("User Side (for each user i):", font_size=24),
         # --- Fix: Use MathTex for angle brackets ---
         MathTex(r"\bullet \text{ For each } \langle k, v \rangle \text{ in } S_i:", font_size=22),
         MathTex(r"  \bullet \text{ Apply } LPP(k, v, \varepsilon_1, \varepsilon_2) \to \text{ get } (j, \langle k, v^* \rangle)", font_size=22),
         # --- End Fix ---
         Text(" • Send all perturbed results to server", font_size=22),
         Text("Server Side:", font_size=24),
         # --- Fix: Use MathTex for formula elements ---
         MathTex(r"\bullet \text{ Collect all perturbed data}", font_size=22),
         MathTex(r"\bullet \text{ Estimate frequencies } (\hat{f}_k) \text{ and means } (\hat{m}_k) \text{ using calibration}", font_size=22),
         MathTex(r"\bullet \text{ Perform outlier correction}", font_size=22)
         # --- End Fix ---
    ).arrange(DOWN, aligned_edge=LEFT, buff=0.2) # Adjust buff as needed
    # Position and scale summary
    privkv_summary.next_to(title, DOWN, buff=MED_LARGE_BUFF).scale(0.9)

    scene.play(FadeIn(privkv_summary, lag_ratio=0.1))
    scene.wait(5)

    scene.play(FadeOut(privkv_summary))

    flow_title = Text("PrivKV Workflow", font_size=32)
    flow_title.to_edge(UP, buff=0.8) # Position relative to top edge

    # Components for workflow visualization - Reducing font size further
    internal_font_size = 16  # Smaller font inside boxes
    users_box = Rectangle(width=4, height=3, fill_color=BLUE_E, fill_opacity=0.2)
    users_title = Text("User i", font_size=24).next_to(users_box, UP, buff=0.2)

    user_text = VGroup(
        # --- Fix: Use MathTex for the line with angle brackets ---
        MathTex(r"\text{Owns } S_i = \{\langle k, v \rangle, \dots \}", font_size=internal_font_size),
        # --- End Fix ---
        Text("Applies LPP to each pair", font_size=internal_font_size),  # This line is plain text, so Text is fine
        MathTex(r"\text{Sends: } \{(j_1, \langle k_1, v_1^* \rangle), \dots\}", font_size=internal_font_size)
        # Already correctly using MathTex
    ).arrange(DOWN, aligned_edge=LEFT, buff=0.15).move_to(users_box)  # Tighter buff

    collector_box = Rectangle(width=4, height=3, fill_color=RED_E, fill_opacity=0.2)
    collector_title = Text("Data Collector", font_size=24).next_to(collector_box, UP, buff=0.2) # Keep title size reasonable
    collector_text = VGroup(
        Text("Receives data from N users", font_size=internal_font_size),
        MathTex(r"\text{Calibrates freq. } \hat{f}_k", font_size=internal_font_size), # Use MathTex
        MathTex(r"\text{Calibrates mean } \hat{m}_k", font_size=internal_font_size), # Use MathTex
        Text("Corrects outliers", font_size=internal_font_size)
    ).arrange(DOWN, aligned_edge=LEFT, buff=0.15).move_to(collector_box) # Tighter buff

    # Group boxes and position them first
    box_group = VGroup(
        VGroup(users_box, users_title, user_text).shift(LEFT * 3.5),
        VGroup(collector_box, collector_title, collector_text).shift(RIGHT * 3.5)
    )

    # Create arrow between the *final* positions of the boxes
    data_arrow = Arrow(users_box.get_right(), collector_box.get_left(), buff=0.2)
    data_text = MathTex(r"(j, \langle k, v^* \rangle)", font_size=20).next_to(data_arrow, UP, buff=0.1) # Smaller MathTex
    ldp_protection = Text("ε-LDP Protection", font_size=18, color=GREEN).next_to(data_arrow, DOWN, buff=0.1) # Smaller text

    workflow_group = VGroup(box_group, data_arrow, data_text, ldp_protection)

    # Fix: Scale down the entire workflow group and position it below the flow_title
    workflow_group.scale(0.85).next_to(flow_title, DOWN, buff=MED_LARGE_BUFF)

    scene.play(ReplacementTransform(title, flow_title)) # Transform original title
    # Animate boxes and text together
    scene.play(
        Create(users_box), Write(users_title),
        Create(collector_box), Write(collector_title),
        run_time=1.5
    )
    scene.play(
        Write(user_text), Write(collector_text),
        run_time=1.5
    )
    scene.play(GrowArrow(data_arrow), Write(data_text), Write(ldp_protection))
    scene.wait(3)

    # We need to return the elements that should be faded out by the main construct loop
    return VGroup(flow_title, workflow_group) # Return the current visible elements



def construct_privkvm_algorithm(scene: Scene):
    """ Constructs the PrivKVM Algorithm part. """
    # No specific issues reported, layout seems okay. Check MathTex.
    title = Text("PrivKVM: Iterative PrivKV", font_size=40)
    title.to_edge(UP, buff=0.5)
    scene.play(Write(title))
    scene.wait(1)

    privkvm_summary = VGroup(
        Text("Algorithm 5: PrivKVM (Iterative)", font_size=28, color=YELLOW),
        Text("Goal: Improve mean estimation accuracy via iteration.", font_size=24),
        Text("Key Idea:", font_size=24),
        Text(" • Run PrivKV multiple times (c iterations).", font_size=22),
        Text(" • In each iteration r > 1:", font_size=22),
        MathTex(r"   \bullet \text{ Server sends previous mean estimate } \hat{m}^{(r-1)} \text{ back to users.}", font_size=20), # MathTex
        MathTex(r"   \bullet \text{ User uses } \hat{m}^{(r-1)} \text{ to adjust value perturbation (focus noise).}", font_size=20), # MathTex
        Text(" • Server aggregates results from final iteration.", font_size=22)
    ).arrange(DOWN, aligned_edge=LEFT, buff=0.2)
    privkvm_summary.next_to(title, DOWN, buff=MED_LARGE_BUFF).scale(0.9)

    scene.play(FadeIn(privkvm_summary, lag_ratio=0.1))
    scene.wait(5)

    scene.play(FadeOut(privkvm_summary))

    theory_title = Text("PrivKVM Guarantees", font_size=32)
    theory_title.next_to(title, DOWN, buff=MED_LARGE_BUFF) # Position relative to main title space

    # NOTE: Check formulas below for potential LaTeX errors
    theory_text = VGroup(
        MathTex(r"\bullet \text{ Satisfies } \varepsilon\text{-LDP (Thm 5.2)}", font_size=26, color=BLUE),
        # Clarify limit notation
        MathTex(r"\bullet \text{ Converges: } \lim_{c \to \infty} \hat{m}^{(c)}_k = m_k \text{ (Thm 5.3)}", font_size=26, color=GREEN),
        MathTex(r"\bullet \text{ Accuracy improves with iterations (Thm 5.4)}", font_size=26, color=RED)
    ).arrange(DOWN, aligned_edge=LEFT, buff=0.4)
    theory_text.next_to(theory_title, DOWN, buff=MED_LARGE_BUFF)

    scene.play(Write(theory_title))
    scene.play(Write(theory_text, lag_ratio=0.2))
    scene.wait(4)

    return VGroup(title, theory_title, theory_text)


def construct_privkvmplus_algorithm(scene: Scene):
    """ Constructs the PrivKVM+ Algorithm part. """
    # No specific issues reported, layout seems okay. Check MathTex.
    title = Text("PrivKVM+: Adaptive PrivKVM", font_size=40)
    title.to_edge(UP, buff=0.5)
    scene.play(Write(title))
    scene.wait(1)

    privkvmplus_summary = VGroup(
        Text("Algorithm 6: PrivKVM+ (Adaptive)", font_size=28, color=YELLOW),
        Text("Problem: PrivKVM uses a fixed number of iterations (c).", font_size=24),
        Text("Goal: Stop iterating adaptively when cost outweighs benefit.", font_size=24),
        Text("Key Idea:", font_size=24),
        MathTex(r" \bullet \text{ Define a Cost Function } F(r) = F_1(r) + F_2(r)", font_size=22), # MathTex
        Text("   • F₁(r): Accuracy Cost (decreases with iteration r)", font_size=20),
        Text("   • F₂(r): Communication Cost (increases with iteration r)", font_size=20),
        MathTex(r" \bullet \text{ Termination Condition: Stop at iteration } r \text{ if } F(r) \ge F(r-1)", font_size=22), # MathTex
        Text("   (Stop when total cost starts increasing)", font_size=20),
    ).arrange(DOWN, aligned_edge=LEFT, buff=0.2)
    privkvmplus_summary.next_to(title, DOWN, buff=MED_LARGE_BUFF).scale(0.9)

    scene.play(FadeIn(privkvmplus_summary, lag_ratio=0.1))
    scene.wait(5)

    scene.play(FadeOut(privkvmplus_summary))

    adaptive_title = Text("PrivKVM+ Adaptive Termination", font_size=36)
    adaptive_title.next_to(title, DOWN, buff=MED_LARGE_BUFF) # Reposition

    # NOTE: Check formulas below for potential LaTeX errors
    cost_group = VGroup(
        MathTex(r"\text{Total Cost: } F(r) = \underbrace{F_1(r)}_{\text{Accuracy}} + \underbrace{F_2(r)}_{\text{Communication}}", font_size=30),
        Text("Balances accuracy gain vs. communication overhead", font_size=22)
    ).arrange(DOWN, buff=0.4)
    cost_group.next_to(adaptive_title, DOWN, buff=MED_LARGE_BUFF)

    termination_group = VGroup(
        Text("Termination Condition:", font_size=28, color=YELLOW),
        MathTex(r"\text{Stop at iteration } r \text{ if } F(r) - F(r-1) \ge 0", font_size=28),
        Text("(Stop when cost function stops decreasing)", font_size=22)
    ).arrange(DOWN, buff=0.3)
    termination_group.next_to(cost_group, DOWN, buff=LARGE_BUFF) # More space

    scene.play(Write(adaptive_title))
    scene.play(Write(cost_group))
    scene.wait(2)
    scene.play(Write(termination_group))
    scene.wait(3)

    end_elements = VGroup(adaptive_title, cost_group, termination_group)
    return VGroup(title, end_elements)


def construct_virtual_iterations(scene: Scene):
    """ Constructs the Virtual Iterations part. """
    # No specific issues reported, but layout could be tight. Ensure spacing.
    title = Text("Virtual Iteration Optimization", font_size=40)
    title.to_edge(UP, buff=0.5)
    scene.play(Write(title))
    scene.wait(1)

    virtual_summary = VGroup(
        Text("Algorithm 7: Virtual Iteration", font_size=28, color=YELLOW),
        Text("Problem: PrivKVM/PrivKVM+ require multiple communication rounds.", font_size=24),
        Text("Goal: Reduce network latency while approximating iterative results.", font_size=24),
        Text("Key Idea:", font_size=24),
        Text(" • User sends only first iteration data (like PrivKV).", font_size=22),
        MathTex(r" \bullet \text{ Server calculates first iteration mean } \hat{m}^{(1)}.", font_size=22), # MathTex
        MathTex(r" \bullet \text{ Server *predicts* means for subsequent iterations } (\hat{m}^{(2)}, \dots, \hat{m}^{(c)})", font_size=22), # MathTex
        MathTex(r"   \text{using } \hat{m}^{(1)} \text{ and a convergence parameter } \theta.", font_size=22), # MathTex continuation
        Text(" • Achieves similar accuracy with only ONE round of communication.", font_size=22, color=GREEN)
    ).arrange(DOWN, aligned_edge=LEFT, buff=0.2)
    virtual_summary.next_to(title, DOWN, buff=MED_LARGE_BUFF).scale(0.9)

    scene.play(FadeIn(virtual_summary, lag_ratio=0.1))
    scene.wait(5)

    scene.play(FadeOut(virtual_summary))

    comparison_title = Text("Real vs. Virtual Iteration", font_size=36)
    comparison_title.next_to(title, DOWN, buff=MED_LARGE_BUFF) # Reposition

    # Visualization using simple boxes and arrows - increase spacing
    iter_box_width = 3.5 # Slightly wider boxes
    iter_box_height = 1.0
    real_iter_group = VGroup(
        Text("Real Iteration (PrivKVM)", font_size=24, color=RED),
        Rectangle(width=iter_box_width, height=iter_box_height, color=RED).add(Text("Round 1", font_size=18)),
        Arrow(UP*0.5, DOWN*0.5, color=RED),
        Rectangle(width=iter_box_width, height=iter_box_height, color=RED).add(Text("Round 2", font_size=18)),
        Arrow(UP*0.5, DOWN*0.5, color=RED),
        Text("...", font_size=24, color=RED),
        Arrow(UP*0.5, DOWN*0.5, color=RED),
        Rectangle(width=iter_box_width, height=iter_box_height, color=RED).add(Text("Round c", font_size=18)),
        Text("High Communication Cost", font_size=18, color=RED)
    ).arrange(DOWN, buff=0.25).shift(LEFT * 4.0) # Increase shift and buff

    virtual_iter_group = VGroup(
        Text("Virtual Iteration", font_size=24, color=GREEN),
        Rectangle(width=iter_box_width, height=iter_box_height, color=GREEN).add(Text("Round 1", font_size=18)),
        Arrow(UP*0.5, DOWN*0.5, color=GREEN),
        Rectangle(width=iter_box_width, height=1.5, color=GREEN).add(VGroup(Text("Server Prediction", font_size=18), Text("(Iter 2...c)", font_size=16)).arrange(DOWN)),
        Text("Low Communication Cost", font_size=18, color=GREEN)
    ).arrange(DOWN, buff=0.25).shift(RIGHT * 4.0) # Increase shift and buff

    divider = Line(UP*3, DOWN*2.5).shift(DOWN*0.2) # Adjust length/position
    comparison_placeholder = VGroup(real_iter_group, virtual_iter_group, divider)
    comparison_placeholder.scale(0.9).next_to(comparison_title, DOWN, buff=MED_LARGE_BUFF) # Scale down slightly

    scene.play(Write(comparison_title))
    scene.play(Write(comparison_placeholder))
    scene.wait(4)

    # NOTE: Check formula below for potential LaTeX errors
    prediction_title = Text("Mean Prediction Formula (Conceptual)", font_size=28)
    prediction_formula = MathTex(r"\hat{m}^{(r)}_k \approx \text{Predict}(\hat{m}^{(1)}_k, \theta, r)", font_size=24)
    prediction_group = VGroup(prediction_title, prediction_formula).arrange(DOWN)
    # Position near bottom edge
    prediction_group.to_edge(DOWN, buff=MED_SMALL_BUFF)

    scene.play(Write(prediction_group))
    scene.wait(3)

    end_elements = VGroup(comparison_title, comparison_placeholder, prediction_group)
    return VGroup(title, end_elements)


def construct_theoretical_analysis(scene: Scene):
    """ Constructs the Theoretical Analysis summary part. """
    # No specific issues reported, layout seems okay. Check MathTex.
    title = Text("Theoretical Analysis Summary", font_size=40)
    title.to_edge(UP, buff=0.5)
    scene.play(Write(title))
    scene.wait(1)

    # NOTE: Check formulas below for potential LaTeX errors
    analysis_summary = VGroup(
        Text("Privacy Guarantee (ε-LDP):", font_size=30, color=BLUE),
        MathTex(r"\bullet \text{ LPP satisfies } (\varepsilon_1 + \varepsilon_2)\text{-LDP (Thm 4.1)}", font_size=24), # MathTex
        MathTex(r"\bullet \text{ PrivKVM satisfies } \varepsilon\text{-LDP (Thm 5.2)}", font_size=24), # MathTex
        # --- Fix: Replace Spacer with an invisible Rectangle ---
        Rectangle(height=0.3, width=0.01, stroke_opacity=0, fill_opacity=0), # Add spacer for visual separation
        # --- End Fix ---
        Text("Convergence Guarantee (PrivKVM):", font_size=30, color=GREEN),
        MathTex(r"\bullet \text{ Mean estimate converges to true mean as iterations } \to \infty \text{ (Thm 5.3)}", font_size=24), # MathTex
        # --- Fix: Replace Spacer with an invisible Rectangle ---
        Rectangle(height=0.3, width=0.01, stroke_opacity=0, fill_opacity=0), # Add spacer
        # --- End Fix ---
        Text("Accuracy Guarantee (PrivKVM):", font_size=30, color=RED),
        Text(" • Error bound provided for mean estimate (MSE)", font_size=24),
        MathTex(r"\bullet \text{ Depends on } n \text{ (users), } d \text{ (keys), } \varepsilon \text{ (privacy), } c \text{ (iterations) (Thm 5.4)}", font_size=24), # MathTex
    ).arrange(DOWN, aligned_edge=LEFT, buff=0.3) # Adjust spacing
    analysis_summary.next_to(title, DOWN, buff=MED_LARGE_BUFF).scale(0.95)

    scene.play(Write(analysis_summary, lag_ratio=0.1))
    scene.wait(5)

    return VGroup(title, analysis_summary)



def construct_comparison(scene: Scene):
    """ Constructs the Comparison of PrivKV Methods part. """
    # Issue: Virtual Iteration Comparison Chart issues (clarity/missing steps).
    # Fix: Ensure labels are clear, positioned well. Consider slightly longer waits or staged appearance.
    # Fix: The RIGHT vs R issue is already corrected in the provided code.
    title = Text("Comparison of PrivKV Methods", font_size=40)
    title.to_edge(UP, buff=0.5)
    scene.play(Write(title))
    scene.wait(1)

    # Table section seems okay, styling applied.
    table_data = [
        ["Method", "Iterations", "Communication", "Key Feature"],
        ["PrivKV", "1", "1 Round", "Basic, no downlink"],
        ["PrivKVM", "Fixed (c)", "c Rounds", "Higher accuracy"],
        ["PrivKVM+", "Adaptive (r ≤ c)", "r Rounds", "Balances Acc/Comm"],
        ["+ Virtual Iter.", "(c predicted)", "1 Round", "Low latency approx."]
    ]
    comparison_table = Table(
        table_data, include_outer_lines=True,
        line_config={"stroke_width": 1, "color": WHITE},
    ).scale(0.55)
    comparison_table.next_to(title, DOWN, buff=MED_LARGE_BUFF) # Consistent spacing
    comparison_table.get_rows()[0].set_color(YELLOW)
    if len(comparison_table.get_horizontal_lines()) > 1:
        comparison_table.get_horizontal_lines()[1].set_stroke(color=YELLOW, width=3)
    comparison_table.get_horizontal_lines().set_color(WHITE)
    comparison_table.get_vertical_lines().set_color(WHITE)
    if len(comparison_table.get_horizontal_lines()) > 1:
        comparison_table.get_horizontal_lines()[1].set_stroke(color=YELLOW, width=3)
    comparison_table.get_columns()[1].set_color(BLUE_C)
    comparison_table.get_columns()[2].set_color(GREEN_C)
    comparison_table.get_columns()[3].set_color(RED_C)

    scene.play(FadeIn(comparison_table))
    scene.wait(5)
    scene.play(FadeOut(comparison_table))

    # Chart Section - ensure clarity
    performance_title = Text("Performance Comparison (Conceptual)", font_size=36)
    performance_title.next_to(title, DOWN, buff=MED_LARGE_BUFF) # Reposition

    axes = Axes(
        x_range=[0, 5.1, 1], y_range=[0, 1.21, 0.2], # Extend range slightly
        x_length=7, y_length=4.5,
        axis_config={"include_tip": True, "numbers_to_include": np.arange(1, 6, 1)},
        y_axis_config={"numbers_to_include": np.arange(0.2, 1.3, 0.2)}
    ).shift(DOWN * 0.5)
    # Use MathTex for epsilon label
    x_label = axes.get_x_axis_label(MathTex(r"\varepsilon \text{ (Privacy Budget)}"), edge=DOWN, direction=DOWN)
    # Ensure y-label is clear and doesn't overlap axis numbers
    y_label = axes.get_y_axis_label(Text("Accuracy (e.g., 1 - MSE)", font_size=20), edge=LEFT, direction=LEFT, buff=0.5) # Increased buff

    # Curves and Labels - adjust positioning slightly if needed
    curve_privkv = axes.plot(lambda x: 0.8 * (1 - np.exp(-0.5 * x)), x_range=[0.1, 5], color=RED)
    label_privkv = MathTex("PrivKV", color=RED, font_size=24).next_to(curve_privkv.get_point_from_function(4.5), UR, buff=0.2) # Position near x=4.5, larger buff

    curve_privkvm = axes.plot(lambda x: 1.0 * (1 - np.exp(-0.7 * x)), x_range=[0.1, 5], color=GREEN)
    label_privkvm = MathTex("PrivKVM / +", color=GREEN, font_size=24).next_to(curve_privkvm.get_end(), UR, buff=0.2) # Larger buff

    curve_virtual = axes.plot(lambda x: 0.95 * (1 - np.exp(-0.65 * x)), x_range=[0.1, 5], color=BLUE)
    # Use get_point_from_function for more control if needed, ensure buff is sufficient
    label_virtual = MathTex("Virtual Iter.", color=BLUE, font_size=24).next_to(curve_virtual.get_end(), RIGHT, buff=0.2) # Larger buff

    chart_group = VGroup(axes, x_label, y_label,
                         curve_privkv, label_privkv,
                         curve_privkvm, label_privkvm,
                         curve_virtual, label_virtual)
    chart_group.next_to(performance_title, DOWN, buff=0.5) # Increased buff

    scene.play(Write(performance_title))
    scene.play(Create(axes), Write(x_label), Write(y_label))
    scene.wait(0.5) # Small pause
    scene.play(Create(curve_privkv), Write(label_privkv))
    scene.wait(0.5) # Small pause
    scene.play(Create(curve_privkvm), Write(label_privkvm))
    scene.wait(0.5) # Small pause
    scene.play(Create(curve_virtual), Write(label_virtual))
    scene.wait(4)

    return VGroup(title, performance_title, chart_group)


def construct_conclusion(scene: Scene):
    """ Constructs the Conclusion part. """
    # No specific issues reported, layout seems okay.
    title = Text("Conclusion", font_size=48)
    title.to_edge(UP, buff=0.5)
    scene.play(Write(title))
    scene.wait(1)

    # Using VGroups with MathTex numbers for better alignment
    summary = VGroup(
        VGroup(MathTex(r"1.~"), Text("PrivKV: First LDP solution for Key-Value data.", font_size=28)).arrange(RIGHT, buff=0.2),
        VGroup(MathTex(r"2.~"), Text("Addresses key-value correlation via LPP.", font_size=28)).arrange(RIGHT, buff=0.2),
        VGroup(MathTex(r"3.~"), Text("PrivKVM improves accuracy via iteration.", font_size=28)).arrange(RIGHT, buff=0.2),
        VGroup(MathTex(r"4.~"), Text("PrivKVM+ adaptively balances accuracy/communication.", font_size=28)).arrange(RIGHT, buff=0.2),
        VGroup(MathTex(r"5.~"), Text("Virtual Iteration reduces latency, maintains accuracy.", font_size=28)).arrange(RIGHT, buff=0.2)
    ).arrange(DOWN, aligned_edge=LEFT, buff=0.4) # Adjust buff
    summary.scale(0.9).next_to(title, DOWN, buff=LARGE_BUFF) # Increase buff

    scene.play(FadeIn(summary, lag_ratio=0.1))
    scene.wait(5)

    scene.play(FadeOut(summary))

    final_message = Text("PrivKV: Key-Value Data Collection with LDP\n\nThanks for watching!",
                         font_size=36, t2c={'PrivKV': YELLOW, 'LDP': BLUE}, line_spacing=1.2)
    final_message.center()

    scene.play(Write(final_message))
    scene.wait(3)

    return VGroup(title, final_message)

# ========================================================
# Main Scene (Orchestrator) - No changes needed here
# ========================================================

class MainAnimation(Scene):
    def construct(self):
        # Section 1: Intro
        intro_elements = construct_intro(self)
        self.wait(1)
        self.play(FadeOut(intro_elements, shift=DOWN))
        self.wait(0.5)

        # Section 2: LDP Explanation
        ldp_elements = construct_ldp_explanation(self)
        self.wait(1)
        self.play(FadeOut(ldp_elements, shift=DOWN))
        self.wait(0.5)

        # Section 3: Key-Value Data Model
        kv_model_elements = construct_key_value_model(self)
        self.wait(1)
        self.play(FadeOut(kv_model_elements, shift=DOWN))
        self.wait(0.5)

        # Section 4: Estimation Goals
        goals_elements = construct_estimation_goals(self)
        self.wait(1)
        self.play(FadeOut(goals_elements, shift=DOWN))
        self.wait(0.5)

        # Section 5: Key-Value Perturbation Challenge
        challenge_elements = construct_kv_challenge(self)
        self.wait(1)
        self.play(FadeOut(challenge_elements, shift=DOWN))
        self.wait(0.5)

        # Section 6: VPP Algorithm
        vpp_elements = construct_vpp_algorithm(self)
        # vpp_elements might be empty if all content faded internally
        if vpp_elements: # Only fade if something was returned
             self.play(FadeOut(vpp_elements, shift=DOWN))
        self.wait(0.5)

        # Section 7: LPP Algorithm
        lpp_elements = construct_lpp_algorithm(self)
        self.wait(1)
        self.play(FadeOut(lpp_elements, shift=DOWN))
        self.wait(0.5)

        # Section 8: PrivKV Algorithm Flow
        privkv_elements = construct_privkv_algorithm(self)
        self.wait(1)
        self.play(FadeOut(privkv_elements, shift=DOWN))
        self.wait(0.5)

        # Section 9: PrivKVM Algorithm
        privkvm_elements = construct_privkvm_algorithm(self)
        self.wait(1)
        self.play(FadeOut(privkvm_elements, shift=DOWN))
        self.wait(0.5)

        # Section 10: PrivKVM+ Algorithm
        privkvmplus_elements = construct_privkvmplus_algorithm(self)
        self.wait(1)
        self.play(FadeOut(privkvmplus_elements, shift=DOWN))
        self.wait(0.5)

        # Section 11: Virtual Iterations
        virtual_elements = construct_virtual_iterations(self)
        self.wait(1)
        self.play(FadeOut(virtual_elements, shift=DOWN))
        self.wait(0.5)

        # Section 12: Theoretical Analysis
        theory_elements = construct_theoretical_analysis(self)
        self.wait(1)
        self.play(FadeOut(theory_elements, shift=DOWN))
        self.wait(0.5)

        # Section 13: Comparison of Algorithms
        comparison_elements = construct_comparison(self)
        self.wait(1)
        self.play(FadeOut(comparison_elements, shift=DOWN))
        self.wait(0.5)

        # Section 14: Conclusion
        conclusion_elements = construct_conclusion(self)
        self.wait(4)
        self.play(FadeOut(conclusion_elements, shift=DOWN))
        self.wait(1)


# To run this revised code:
# python -m manim -pql your_file_name.py MainAnimation
相关推荐
regret~1 小时前
【论文笔记】SOTR: Segmenting Objects with Transformers
论文阅读·python·深度学习
寻丶幽风4 小时前
论文阅读笔记——STDArm
论文阅读·笔记·机器人·具身智能·动态推理
hongjianMa9 小时前
【论文阅读】Joint Deep Modeling of Users and Items Using Reviews for Recommendation
论文阅读·python·深度学习·卷积神经网络·推荐系统·推荐算法·多模态
会编程的加缪20 小时前
文献总结:TPAMI端到端自动驾驶综述——End-to-End Autonomous Driving: Challenges and Frontiers
论文阅读·人工智能·深度学习·机器学习·自动驾驶
Zhouqi_Hua1 天前
LLM论文笔记 27: Looped Transformers for Length Generalization
论文阅读·人工智能·笔记·语言模型·论文笔记
Gamma and Beta1 天前
Fine Structure-Aware Sampling(AAAI 2024)论文笔记和启发
论文阅读·人工智能·计算机视觉·3d
roman_日积跬步-终至千里1 天前
【论文阅读】LLMOPT:一种提升优化泛化能力的统一学习框架
论文阅读·学习
s1ckrain2 天前
【论文阅读】PEEKABOO: Interactive Video Generation via Masked-Diffusion
论文阅读·计算机视觉·aigc
墨绿色的摆渡人2 天前
论文笔记(八十三)STACKGEN: Generating Stable Structures from Silhouettes via Diffusion
论文阅读