|
7 | 7 | load_dotenv() |
8 | 8 |
|
9 | 9 | from scene_utils import CHAPTER0_MATRIX_DATA, create_labeled_matrix, hide_zero_entries, setup_scene |
| 10 | +from scene_utils.graph_utils import create_karate_graph |
10 | 11 |
|
11 | 12 |
|
12 | 13 | class Scene2(VoiceoverScene, Scene): |
@@ -94,30 +95,129 @@ def construct(self): |
94 | 95 | self.play(FadeIn(matrix_group)) |
95 | 96 | self.wait(1) |
96 | 97 |
|
| 98 | + # Transition: fade out COO code, keep matrix |
| 99 | + self.play(FadeOut(matrix_code)) |
| 100 | + |
| 101 | + # Section 4: from_dicts constructor |
| 102 | + with self.voiceover( |
| 103 | + """For more Pythonic construction, GraphBLAS supports |
| 104 | + dictionary format. Nested dictionaries map row indices to |
| 105 | + column-value pairs. This is intuitive for representing |
| 106 | + adjacency lists where each row describes outgoing edges.""" |
| 107 | + ): |
| 108 | + dict_code = Code( |
| 109 | + code_string="""# Matrix from nested dictionaries |
| 110 | +A = gb.Matrix.from_dicts({ |
| 111 | + 0: {1: 1, 3: 2}, |
| 112 | + 1: {2: 5}, |
| 113 | + 3: {4: 2, 5: 9}, |
| 114 | + 4: {2: 5}, |
| 115 | + 5: {4: 2} |
| 116 | +}, nrows=6, ncols=6)""", |
| 117 | + language="python", |
| 118 | + background="window" |
| 119 | + ).scale(0.65) |
| 120 | + dict_code.to_edge(LEFT, buff=0.3).shift(DOWN * 0.5) |
| 121 | + self.play(FadeIn(dict_code)) |
| 122 | + self.wait(1) |
| 123 | + |
| 124 | + # Transition to edgelist |
| 125 | + self.play(FadeOut(dict_code)) |
| 126 | + |
| 127 | + # Section 5: from_edgelist constructor |
| 128 | + with self.voiceover( |
| 129 | + """Edge lists are common in graph data. GraphBLAS can build |
| 130 | + matrices directly from sequences of row-column pairs or |
| 131 | + triples that include values. This mirrors how graph edges |
| 132 | + are often stored in files.""" |
| 133 | + ): |
| 134 | + edgelist_code = Code( |
| 135 | + code_string="""# Matrix from edge list |
| 136 | +edges = [ |
| 137 | + (0, 1, 1), (0, 3, 2), |
| 138 | + (1, 2, 5), |
| 139 | + (3, 4, 2), (3, 5, 9), |
| 140 | + (4, 2, 5), |
| 141 | + (5, 4, 2) |
| 142 | +] |
| 143 | +A = gb.Matrix.from_edgelist( |
| 144 | + edges, nrows=6, ncols=6 |
| 145 | +)""", |
| 146 | + language="python", |
| 147 | + background="window" |
| 148 | + ).scale(0.65) |
| 149 | + edgelist_code.to_edge(LEFT, buff=0.3).shift(DOWN * 0.5) |
| 150 | + self.play(FadeIn(edgelist_code)) |
| 151 | + self.wait(1) |
| 152 | + |
| 153 | + # Transition to mmread - clear the small matrix |
| 154 | + self.play(FadeOut(edgelist_code), FadeOut(matrix_group)) |
| 155 | + |
| 156 | + # Section 6: Matrix Market file reading |
| 157 | + with self.voiceover( |
| 158 | + """Real-world graphs are often stored in Matrix Market format. |
| 159 | + GraphBLAS can read these files directly. Here we load the |
| 160 | + Zachary karate club network, a classic 34-node social network |
| 161 | + from 1977.""" |
| 162 | + ): |
| 163 | + mmread_code = Code( |
| 164 | + code_string="""# Read Matrix Market file |
| 165 | +import graphblas.io as gbio |
| 166 | +
|
| 167 | +A = gbio.mmread("karate.mtx") |
| 168 | +print(A) # 34x34 matrix, 78 edges""", |
| 169 | + language="python", |
| 170 | + background="window" |
| 171 | + ).scale(0.7) |
| 172 | + mmread_code.to_edge(LEFT, buff=0.5).shift(DOWN * 0.5) |
| 173 | + self.play(FadeIn(mmread_code)) |
| 174 | + |
| 175 | + # Show the karate graph |
| 176 | + karate_graph = create_karate_graph(scale=0.08, node_radius=0.2) |
| 177 | + karate_graph.to_edge(RIGHT, buff=0.5).shift(DOWN * 0.3) |
| 178 | + self.play(FadeIn(karate_graph)) |
| 179 | + |
| 180 | + # Add info label |
| 181 | + info_label = Tex("34 nodes, 78 edges").scale(0.7) |
| 182 | + info_label.next_to(karate_graph, DOWN, buff=0.3) |
| 183 | + self.play(FadeIn(info_label)) |
| 184 | + self.wait(1) |
| 185 | + |
| 186 | + # Transition back to sparse philosophy - recreate the 6x6 matrix |
| 187 | + self.play(FadeOut(mmread_code), FadeOut(karate_graph), FadeOut(info_label)) |
| 188 | + |
| 189 | + # Recreate matrix for sparse philosophy section |
| 190 | + matrix2, row_labels2, col_labels2 = create_labeled_matrix( |
| 191 | + matrix_data, scale=1.5, v_buff=0.5, h_buff=0.5 |
| 192 | + ) |
| 193 | + matrix_group2 = VGroup(matrix2, *row_labels2, *col_labels2) |
| 194 | + matrix_group2.move_to(ORIGIN) |
| 195 | + self.play(FadeIn(matrix_group2)) |
| 196 | + |
97 | 197 | with self.voiceover( |
98 | 198 | """Notice how most entries in this matrix are zero. In |
99 | 199 | GraphBLAS, these zeros are not stored at all - they simply |
100 | 200 | don't exist in the sparse representation. This is what makes |
101 | 201 | GraphBLAS efficient for large, sparse graphs.""" |
102 | 202 | ): |
103 | 203 | # Hide zero entries to show sparse nature |
104 | | - hide_anims = hide_zero_entries(matrix, matrix_data) |
| 204 | + hide_anims = hide_zero_entries(matrix2, matrix_data) |
105 | 205 | self.play(*hide_anims) |
106 | 206 |
|
107 | 207 | # Highlight non-zero positions (matching Chapter 0 matrix) |
108 | 208 | nz_positions = [(0, 1), (0, 3), (1, 2), (3, 4), (3, 5), (4, 2), (5, 4)] |
109 | | - nz_highlights = [ |
| 209 | + nz_highlights2 = [ |
110 | 210 | SurroundingRectangle( |
111 | | - matrix.get_entries()[i * 6 + j], color=YELLOW, buff=0.1 |
| 211 | + matrix2.get_entries()[i * 6 + j], color=YELLOW, buff=0.1 |
112 | 212 | ) |
113 | 213 | for i, j in nz_positions |
114 | 214 | ] |
115 | | - self.play(*[Create(h) for h in nz_highlights]) |
| 215 | + self.play(*[Create(h) for h in nz_highlights2]) |
116 | 216 | self.wait(2) |
117 | 217 |
|
118 | 218 | # Cleanup |
119 | 219 | self.play( |
120 | | - FadeOut(title), FadeOut(matrix_code), |
121 | | - FadeOut(matrix_group), *[FadeOut(h) for h in nz_highlights] |
| 220 | + FadeOut(title), |
| 221 | + FadeOut(matrix_group2), *[FadeOut(h) for h in nz_highlights2] |
122 | 222 | ) |
123 | 223 | self.wait(0.5) |
0 commit comments