animora 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- animora/__init__.py +189 -0
- animora/algorithms/__init__.py +65 -0
- animora/algorithms/backtracking.py +124 -0
- animora/algorithms/dynamic_programming.py +81 -0
- animora/algorithms/graph_traversal.py +125 -0
- animora/algorithms/pathfinding.py +244 -0
- animora/algorithms/search.py +97 -0
- animora/algorithms/sorting.py +336 -0
- animora/algorithms/trace.py +82 -0
- animora/animations/__init__.py +10 -0
- animora/cli/__init__.py +21 -0
- animora/cli/doctor.py +154 -0
- animora/cli/main.py +59 -0
- animora/cli/new.py +84 -0
- animora/cli/preview.py +83 -0
- animora/cli/render.py +97 -0
- animora/cli/templates/basic_scene.py.template +27 -0
- animora/components/__init__.py +27 -0
- animora/components/arrow.py +111 -0
- animora/components/connector.py +116 -0
- animora/components/dataviz/__init__.py +23 -0
- animora/components/dsa/__init__.py +38 -0
- animora/components/group.py +121 -0
- animora/components/label.py +100 -0
- animora/components/panel.py +131 -0
- animora/components/primitives/__init__.py +23 -0
- animora/components/shape.py +243 -0
- animora/components/text.py +104 -0
- animora/core/__init__.py +23 -0
- animora/core/animation.py +74 -0
- animora/core/component.py +181 -0
- animora/core/config.py +110 -0
- animora/core/scene.py +80 -0
- animora/datastructures/__init__.py +42 -0
- animora/datastructures/array.py +226 -0
- animora/datastructures/bst.py +339 -0
- animora/datastructures/graph.py +275 -0
- animora/datastructures/hash_table.py +242 -0
- animora/datastructures/heap.py +198 -0
- animora/datastructures/linked_list.py +245 -0
- animora/datastructures/queue.py +193 -0
- animora/datastructures/stack.py +193 -0
- animora/datastructures/tree.py +216 -0
- animora/dataviz/__init__.py +23 -0
- animora/dataviz/axes.py +146 -0
- animora/dataviz/bar_chart.py +179 -0
- animora/dataviz/histogram.py +156 -0
- animora/dataviz/line_chart.py +137 -0
- animora/dataviz/scatter_plot.py +130 -0
- animora/dataviz/table.py +170 -0
- animora/layout/__init__.py +30 -0
- animora/layout/base.py +63 -0
- animora/layout/circular.py +87 -0
- animora/layout/flow.py +105 -0
- animora/layout/graph.py +100 -0
- animora/layout/grid.py +90 -0
- animora/layout/horizontal.py +72 -0
- animora/layout/tree.py +179 -0
- animora/layout/vertical.py +72 -0
- animora/py.typed +1 -0
- animora/theme/__init__.py +48 -0
- animora/theme/builtin.py +156 -0
- animora/theme/context.py +51 -0
- animora/theme/theme.py +148 -0
- animora-0.1.0.dist-info/METADATA +326 -0
- animora-0.1.0.dist-info/RECORD +69 -0
- animora-0.1.0.dist-info/WHEEL +4 -0
- animora-0.1.0.dist-info/entry_points.txt +2 -0
- animora-0.1.0.dist-info/licenses/LICENSE +21 -0
animora/__init__.py
ADDED
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
"""Animora: High-level declarative animation framework built on Manim.
|
|
2
|
+
|
|
3
|
+
Democratizing the creation of high-quality educational, technical,
|
|
4
|
+
mathematical, and algorithmic animations.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from animora.algorithms.backtracking import n_queens, n_queens_trace
|
|
10
|
+
from animora.algorithms.dynamic_programming import fibonacci_dp, fibonacci_dp_trace
|
|
11
|
+
from animora.algorithms.graph_traversal import bfs, bfs_trace, dfs, dfs_trace
|
|
12
|
+
from animora.algorithms.pathfinding import (
|
|
13
|
+
a_star,
|
|
14
|
+
a_star_trace,
|
|
15
|
+
dijkstra,
|
|
16
|
+
dijkstra_trace,
|
|
17
|
+
)
|
|
18
|
+
from animora.algorithms.search import binary_search, binary_search_trace
|
|
19
|
+
from animora.algorithms.sorting import (
|
|
20
|
+
bubble_sort,
|
|
21
|
+
bubble_sort_trace,
|
|
22
|
+
insertion_sort,
|
|
23
|
+
insertion_sort_trace,
|
|
24
|
+
merge_sort,
|
|
25
|
+
merge_sort_trace,
|
|
26
|
+
quick_sort,
|
|
27
|
+
quick_sort_trace,
|
|
28
|
+
selection_sort,
|
|
29
|
+
selection_sort_trace,
|
|
30
|
+
)
|
|
31
|
+
from animora.algorithms.trace import (
|
|
32
|
+
OperationStep,
|
|
33
|
+
OperationTrace,
|
|
34
|
+
OperationType,
|
|
35
|
+
)
|
|
36
|
+
from animora.components.arrow import Arrow
|
|
37
|
+
from animora.components.connector import Connector
|
|
38
|
+
from animora.components.group import Group
|
|
39
|
+
from animora.components.label import Label
|
|
40
|
+
from animora.components.panel import Panel
|
|
41
|
+
from animora.components.shape import Shape, ShapeType
|
|
42
|
+
from animora.components.text import Text
|
|
43
|
+
from animora.core.animation import Animation
|
|
44
|
+
from animora.core.component import Component
|
|
45
|
+
from animora.core.config import BoundingBox, ComponentConfig
|
|
46
|
+
from animora.core.scene import Scene
|
|
47
|
+
from animora.datastructures.array import Array, ArrayListModel
|
|
48
|
+
from animora.datastructures.bst import BST, BSTModel, BSTNode
|
|
49
|
+
from animora.datastructures.graph import Graph, GraphModel
|
|
50
|
+
from animora.datastructures.hash_table import HashEntry, HashTable, HashTableChainingModel
|
|
51
|
+
from animora.datastructures.heap import Heap, HeapModel
|
|
52
|
+
from animora.datastructures.linked_list import LinkedList, LinkedListModel, ListNode
|
|
53
|
+
from animora.datastructures.queue import Queue, QueueModel
|
|
54
|
+
from animora.datastructures.stack import Stack, StackModel
|
|
55
|
+
from animora.datastructures.tree import GenericTreeModel, Tree, TreeNode
|
|
56
|
+
from animora.dataviz.axes import Axes
|
|
57
|
+
from animora.dataviz.bar_chart import BarChart
|
|
58
|
+
from animora.dataviz.histogram import Histogram
|
|
59
|
+
from animora.dataviz.line_chart import LineChart
|
|
60
|
+
from animora.dataviz.scatter_plot import ScatterPlot
|
|
61
|
+
from animora.dataviz.table import Table
|
|
62
|
+
from animora.layout.base import BaseLayout, LayoutItem, LayoutResult
|
|
63
|
+
from animora.layout.circular import CircularLayout
|
|
64
|
+
from animora.layout.flow import FlowLayout
|
|
65
|
+
from animora.layout.graph import GraphLayout
|
|
66
|
+
from animora.layout.grid import GridLayout
|
|
67
|
+
from animora.layout.horizontal import HorizontalLayout
|
|
68
|
+
from animora.layout.tree import TreeLayout
|
|
69
|
+
from animora.layout.vertical import VerticalLayout
|
|
70
|
+
from animora.theme.builtin import (
|
|
71
|
+
Cyberpunk,
|
|
72
|
+
DefaultTheme,
|
|
73
|
+
ModernDark,
|
|
74
|
+
Monokai,
|
|
75
|
+
PaperLight,
|
|
76
|
+
)
|
|
77
|
+
from animora.theme.context import (
|
|
78
|
+
get_active_theme,
|
|
79
|
+
set_active_theme,
|
|
80
|
+
use_theme,
|
|
81
|
+
)
|
|
82
|
+
from animora.theme.theme import (
|
|
83
|
+
AnimationTiming,
|
|
84
|
+
ColorPalette,
|
|
85
|
+
CornerRadius,
|
|
86
|
+
SpacingScale,
|
|
87
|
+
StrokeScale,
|
|
88
|
+
Theme,
|
|
89
|
+
Typography,
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
__version__ = "0.1.0"
|
|
93
|
+
|
|
94
|
+
__all__: list[str] = [
|
|
95
|
+
"BST",
|
|
96
|
+
"Animation",
|
|
97
|
+
"AnimationTiming",
|
|
98
|
+
"Array",
|
|
99
|
+
"ArrayListModel",
|
|
100
|
+
"Arrow",
|
|
101
|
+
"Axes",
|
|
102
|
+
"BSTModel",
|
|
103
|
+
"BSTNode",
|
|
104
|
+
"BarChart",
|
|
105
|
+
"BaseLayout",
|
|
106
|
+
"BoundingBox",
|
|
107
|
+
"CircularLayout",
|
|
108
|
+
"ColorPalette",
|
|
109
|
+
"Component",
|
|
110
|
+
"ComponentConfig",
|
|
111
|
+
"Connector",
|
|
112
|
+
"CornerRadius",
|
|
113
|
+
"Cyberpunk",
|
|
114
|
+
"DefaultTheme",
|
|
115
|
+
"FlowLayout",
|
|
116
|
+
"GenericTreeModel",
|
|
117
|
+
"Graph",
|
|
118
|
+
"GraphLayout",
|
|
119
|
+
"GraphModel",
|
|
120
|
+
"GridLayout",
|
|
121
|
+
"Group",
|
|
122
|
+
"HashEntry",
|
|
123
|
+
"HashTable",
|
|
124
|
+
"HashTableChainingModel",
|
|
125
|
+
"Heap",
|
|
126
|
+
"HeapModel",
|
|
127
|
+
"Histogram",
|
|
128
|
+
"HorizontalLayout",
|
|
129
|
+
"Label",
|
|
130
|
+
"LayoutItem",
|
|
131
|
+
"LayoutResult",
|
|
132
|
+
"LineChart",
|
|
133
|
+
"LinkedList",
|
|
134
|
+
"LinkedListModel",
|
|
135
|
+
"ListNode",
|
|
136
|
+
"ModernDark",
|
|
137
|
+
"Monokai",
|
|
138
|
+
"OperationStep",
|
|
139
|
+
"OperationTrace",
|
|
140
|
+
"OperationType",
|
|
141
|
+
"Panel",
|
|
142
|
+
"PaperLight",
|
|
143
|
+
"Queue",
|
|
144
|
+
"QueueModel",
|
|
145
|
+
"ScatterPlot",
|
|
146
|
+
"Scene",
|
|
147
|
+
"Shape",
|
|
148
|
+
"ShapeType",
|
|
149
|
+
"SpacingScale",
|
|
150
|
+
"Stack",
|
|
151
|
+
"StackModel",
|
|
152
|
+
"StrokeScale",
|
|
153
|
+
"Table",
|
|
154
|
+
"Text",
|
|
155
|
+
"Theme",
|
|
156
|
+
"Tree",
|
|
157
|
+
"TreeLayout",
|
|
158
|
+
"TreeNode",
|
|
159
|
+
"Typography",
|
|
160
|
+
"VerticalLayout",
|
|
161
|
+
"__version__",
|
|
162
|
+
"a_star",
|
|
163
|
+
"a_star_trace",
|
|
164
|
+
"bfs",
|
|
165
|
+
"bfs_trace",
|
|
166
|
+
"binary_search",
|
|
167
|
+
"binary_search_trace",
|
|
168
|
+
"bubble_sort",
|
|
169
|
+
"bubble_sort_trace",
|
|
170
|
+
"dfs",
|
|
171
|
+
"dfs_trace",
|
|
172
|
+
"dijkstra",
|
|
173
|
+
"dijkstra_trace",
|
|
174
|
+
"fibonacci_dp",
|
|
175
|
+
"fibonacci_dp_trace",
|
|
176
|
+
"get_active_theme",
|
|
177
|
+
"insertion_sort",
|
|
178
|
+
"insertion_sort_trace",
|
|
179
|
+
"merge_sort",
|
|
180
|
+
"merge_sort_trace",
|
|
181
|
+
"n_queens",
|
|
182
|
+
"n_queens_trace",
|
|
183
|
+
"quick_sort",
|
|
184
|
+
"quick_sort_trace",
|
|
185
|
+
"selection_sort",
|
|
186
|
+
"selection_sort_trace",
|
|
187
|
+
"set_active_theme",
|
|
188
|
+
"use_theme",
|
|
189
|
+
]
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"""Algorithm visualizations and operation tracing for Animora.
|
|
2
|
+
|
|
3
|
+
Provides educational animations and discrete operation traces for searching,
|
|
4
|
+
sorting, graph traversals, pathfinding, dynamic programming, and backtracking.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from animora.algorithms.backtracking import n_queens, n_queens_trace
|
|
10
|
+
from animora.algorithms.dynamic_programming import fibonacci_dp, fibonacci_dp_trace
|
|
11
|
+
from animora.algorithms.graph_traversal import bfs, bfs_trace, dfs, dfs_trace
|
|
12
|
+
from animora.algorithms.pathfinding import (
|
|
13
|
+
a_star,
|
|
14
|
+
a_star_trace,
|
|
15
|
+
dijkstra,
|
|
16
|
+
dijkstra_trace,
|
|
17
|
+
)
|
|
18
|
+
from animora.algorithms.search import binary_search, binary_search_trace
|
|
19
|
+
from animora.algorithms.sorting import (
|
|
20
|
+
bubble_sort,
|
|
21
|
+
bubble_sort_trace,
|
|
22
|
+
insertion_sort,
|
|
23
|
+
insertion_sort_trace,
|
|
24
|
+
merge_sort,
|
|
25
|
+
merge_sort_trace,
|
|
26
|
+
quick_sort,
|
|
27
|
+
quick_sort_trace,
|
|
28
|
+
selection_sort,
|
|
29
|
+
selection_sort_trace,
|
|
30
|
+
)
|
|
31
|
+
from animora.algorithms.trace import (
|
|
32
|
+
OperationStep,
|
|
33
|
+
OperationTrace,
|
|
34
|
+
OperationType,
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
__all__: list[str] = [
|
|
38
|
+
"OperationStep",
|
|
39
|
+
"OperationTrace",
|
|
40
|
+
"OperationType",
|
|
41
|
+
"a_star",
|
|
42
|
+
"a_star_trace",
|
|
43
|
+
"bfs",
|
|
44
|
+
"bfs_trace",
|
|
45
|
+
"binary_search",
|
|
46
|
+
"binary_search_trace",
|
|
47
|
+
"bubble_sort",
|
|
48
|
+
"bubble_sort_trace",
|
|
49
|
+
"dfs",
|
|
50
|
+
"dfs_trace",
|
|
51
|
+
"dijkstra",
|
|
52
|
+
"dijkstra_trace",
|
|
53
|
+
"fibonacci_dp",
|
|
54
|
+
"fibonacci_dp_trace",
|
|
55
|
+
"insertion_sort",
|
|
56
|
+
"insertion_sort_trace",
|
|
57
|
+
"merge_sort",
|
|
58
|
+
"merge_sort_trace",
|
|
59
|
+
"n_queens",
|
|
60
|
+
"n_queens_trace",
|
|
61
|
+
"quick_sort",
|
|
62
|
+
"quick_sort_trace",
|
|
63
|
+
"selection_sort",
|
|
64
|
+
"selection_sort_trace",
|
|
65
|
+
]
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
"""Backtracking algorithm visualization with animated state decision trees (N-Queens)."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import TYPE_CHECKING
|
|
6
|
+
|
|
7
|
+
from animora.algorithms.trace import OperationTrace, OperationType
|
|
8
|
+
from animora.core.animation import Animation
|
|
9
|
+
from animora.dataviz.table import Table
|
|
10
|
+
from animora.theme.context import get_active_theme
|
|
11
|
+
|
|
12
|
+
if TYPE_CHECKING:
|
|
13
|
+
pass
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
# -----------------------------------------------------------------------------
|
|
17
|
+
# 1. Pure Algorithm Logic with Operation Tracing (Dual-Correctness)
|
|
18
|
+
# -----------------------------------------------------------------------------
|
|
19
|
+
def n_queens_trace(n: int = 4) -> tuple[list[list[int]], OperationTrace]:
|
|
20
|
+
"""Solve N-Queens backtracking problem, recording placements and backtracks.
|
|
21
|
+
|
|
22
|
+
Returns (solutions, operation_trace) where each solution is a list of column
|
|
23
|
+
indices for each row.
|
|
24
|
+
"""
|
|
25
|
+
trace = OperationTrace()
|
|
26
|
+
solutions: list[list[int]] = []
|
|
27
|
+
board: list[int] = [-1] * n
|
|
28
|
+
|
|
29
|
+
def _is_safe(row: int, col: int) -> bool:
|
|
30
|
+
for prev_row in range(row):
|
|
31
|
+
prev_col = board[prev_row]
|
|
32
|
+
# Column conflict or diagonal conflict
|
|
33
|
+
if prev_col == col or abs(prev_col - col) == abs(prev_row - row):
|
|
34
|
+
return False
|
|
35
|
+
return True
|
|
36
|
+
|
|
37
|
+
def _solve(row: int) -> None:
|
|
38
|
+
if row == n:
|
|
39
|
+
solutions.append(list(board))
|
|
40
|
+
trace.add_step(
|
|
41
|
+
OperationType.HIGHLIGHT,
|
|
42
|
+
f"Valid N-Queens solution found: {list(board)}",
|
|
43
|
+
targets=tuple(enumerate(board)),
|
|
44
|
+
solution=list(board),
|
|
45
|
+
)
|
|
46
|
+
return
|
|
47
|
+
|
|
48
|
+
for col in range(n):
|
|
49
|
+
trace.add_step(
|
|
50
|
+
OperationType.TRY_CHOICE,
|
|
51
|
+
f"Try placing Queen at row {row}, column {col}",
|
|
52
|
+
targets=(row, col),
|
|
53
|
+
row=row,
|
|
54
|
+
col=col,
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
if _is_safe(row, col):
|
|
58
|
+
board[row] = col
|
|
59
|
+
_solve(row + 1)
|
|
60
|
+
# Backtrack
|
|
61
|
+
board[row] = -1
|
|
62
|
+
trace.add_step(
|
|
63
|
+
OperationType.BACKTRACK,
|
|
64
|
+
f"Backtrack from row {row}, column {col}",
|
|
65
|
+
targets=(row, col),
|
|
66
|
+
row=row,
|
|
67
|
+
col=col,
|
|
68
|
+
)
|
|
69
|
+
else:
|
|
70
|
+
trace.add_step(
|
|
71
|
+
OperationType.BACKTRACK,
|
|
72
|
+
f"Conflict detected at row {row}, column {col}",
|
|
73
|
+
targets=(row, col),
|
|
74
|
+
row=row,
|
|
75
|
+
col=col,
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
_solve(0)
|
|
79
|
+
return solutions, trace
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
# -----------------------------------------------------------------------------
|
|
83
|
+
# 2. Animation Generator Orchestration
|
|
84
|
+
# -----------------------------------------------------------------------------
|
|
85
|
+
def n_queens(
|
|
86
|
+
n: int = 4,
|
|
87
|
+
table: Table | None = None,
|
|
88
|
+
run_time: float | None = None,
|
|
89
|
+
) -> list[Animation]:
|
|
90
|
+
"""Generate animations for N-Queens backtracking exploration."""
|
|
91
|
+
active_theme = get_active_theme()
|
|
92
|
+
duration = run_time or active_theme.timing.fast
|
|
93
|
+
|
|
94
|
+
_solutions, trace = n_queens_trace(n)
|
|
95
|
+
animations: list[Animation] = []
|
|
96
|
+
|
|
97
|
+
if table is not None:
|
|
98
|
+
for step in trace:
|
|
99
|
+
if step.op_type == OperationType.TRY_CHOICE:
|
|
100
|
+
r, c = step.targets
|
|
101
|
+
anim = table.animate_highlight_cell(
|
|
102
|
+
r, c, color=active_theme.colors.warning, run_time=duration
|
|
103
|
+
)
|
|
104
|
+
animations.append(anim)
|
|
105
|
+
elif step.op_type == OperationType.BACKTRACK:
|
|
106
|
+
r, c = step.targets
|
|
107
|
+
anim = table.animate_highlight_cell(
|
|
108
|
+
r, c, color=active_theme.colors.error, run_time=duration
|
|
109
|
+
)
|
|
110
|
+
animations.append(anim)
|
|
111
|
+
elif step.op_type == OperationType.HIGHLIGHT:
|
|
112
|
+
for r, c in step.targets:
|
|
113
|
+
anim = table.animate_highlight_cell(
|
|
114
|
+
r, c, color=active_theme.colors.success, run_time=duration
|
|
115
|
+
)
|
|
116
|
+
animations.append(anim)
|
|
117
|
+
|
|
118
|
+
return animations
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
__all__ = [
|
|
122
|
+
"n_queens",
|
|
123
|
+
"n_queens_trace",
|
|
124
|
+
]
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"""Dynamic Programming visualization with animated memoization table filling."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import TYPE_CHECKING
|
|
6
|
+
|
|
7
|
+
from animora.algorithms.trace import OperationTrace, OperationType
|
|
8
|
+
from animora.core.animation import Animation
|
|
9
|
+
from animora.dataviz.table import Table
|
|
10
|
+
from animora.theme.context import get_active_theme
|
|
11
|
+
|
|
12
|
+
if TYPE_CHECKING:
|
|
13
|
+
pass
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
# -----------------------------------------------------------------------------
|
|
17
|
+
# 1. Pure Algorithm Logic with Operation Tracing (Dual-Correctness)
|
|
18
|
+
# -----------------------------------------------------------------------------
|
|
19
|
+
def fibonacci_dp_trace(n: int) -> tuple[int, list[int], OperationTrace]:
|
|
20
|
+
"""Compute N-th Fibonacci number using bottom-up DP, recording cell fills."""
|
|
21
|
+
if n < 0:
|
|
22
|
+
raise ValueError("n must be non-negative")
|
|
23
|
+
if n == 0:
|
|
24
|
+
trace = OperationTrace()
|
|
25
|
+
trace.add_step(OperationType.TABLE_FILL, "Base case: dp[0] = 0", targets=(0,), value=0)
|
|
26
|
+
return 0, [0], trace
|
|
27
|
+
|
|
28
|
+
dp = [0] * (n + 1)
|
|
29
|
+
dp[0] = 0
|
|
30
|
+
dp[1] = 1
|
|
31
|
+
|
|
32
|
+
trace = OperationTrace()
|
|
33
|
+
trace.add_step(OperationType.TABLE_FILL, "Base case: dp[0] = 0", targets=(0,), value=0)
|
|
34
|
+
trace.add_step(OperationType.TABLE_FILL, "Base case: dp[1] = 1", targets=(1,), value=1)
|
|
35
|
+
|
|
36
|
+
for i in range(2, n + 1):
|
|
37
|
+
dp[i] = dp[i - 1] + dp[i - 2]
|
|
38
|
+
trace.add_step(
|
|
39
|
+
OperationType.TABLE_FILL,
|
|
40
|
+
f"Compute dp[{i}] = dp[{i - 1}] ({dp[i - 1]}) + dp[{i - 2}] ({dp[i - 2]}) = {dp[i]}",
|
|
41
|
+
targets=(i,),
|
|
42
|
+
value=dp[i],
|
|
43
|
+
operand_a=dp[i - 1],
|
|
44
|
+
operand_b=dp[i - 2],
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
return dp[n], dp, trace
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
# -----------------------------------------------------------------------------
|
|
51
|
+
# 2. Animation Generator Orchestration
|
|
52
|
+
# -----------------------------------------------------------------------------
|
|
53
|
+
def fibonacci_dp(
|
|
54
|
+
n: int,
|
|
55
|
+
table: Table | None = None,
|
|
56
|
+
run_time: float | None = None,
|
|
57
|
+
) -> list[Animation]:
|
|
58
|
+
"""Generate animations filling a Table component cell-by-cell for DP Fibonacci."""
|
|
59
|
+
active_theme = get_active_theme()
|
|
60
|
+
duration = run_time or active_theme.timing.fast
|
|
61
|
+
|
|
62
|
+
_result, _dp_array, trace = fibonacci_dp_trace(n)
|
|
63
|
+
animations: list[Animation] = []
|
|
64
|
+
|
|
65
|
+
if table is not None:
|
|
66
|
+
for step in trace:
|
|
67
|
+
idx = step.targets[0]
|
|
68
|
+
if idx < table.num_cols:
|
|
69
|
+
# Row 1 is the DP values row (Row 0 is header)
|
|
70
|
+
anim = table.animate_highlight_cell(
|
|
71
|
+
1, idx, color=active_theme.colors.success, run_time=duration
|
|
72
|
+
)
|
|
73
|
+
animations.append(anim)
|
|
74
|
+
|
|
75
|
+
return animations
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
__all__ = [
|
|
79
|
+
"fibonacci_dp",
|
|
80
|
+
"fibonacci_dp_trace",
|
|
81
|
+
]
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
"""Breadth-First Search (BFS) and Depth-First Search (DFS) graph traversals."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from collections import deque
|
|
6
|
+
from typing import TYPE_CHECKING, Any
|
|
7
|
+
|
|
8
|
+
from animora.algorithms.trace import OperationTrace, OperationType
|
|
9
|
+
from animora.core.animation import Animation
|
|
10
|
+
from animora.datastructures.graph import Graph, GraphModel
|
|
11
|
+
from animora.theme.context import get_active_theme
|
|
12
|
+
|
|
13
|
+
if TYPE_CHECKING:
|
|
14
|
+
pass
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
# -----------------------------------------------------------------------------
|
|
18
|
+
# 1. Breadth-First Search (BFS)
|
|
19
|
+
# -----------------------------------------------------------------------------
|
|
20
|
+
def bfs_trace(graph_model: GraphModel, start: Any) -> tuple[list[Any], OperationTrace]:
|
|
21
|
+
"""Execute BFS traversal on GraphModel, returning (visited_order, operation_trace)."""
|
|
22
|
+
visited_order: list[Any] = []
|
|
23
|
+
trace = OperationTrace()
|
|
24
|
+
visited: set[Any] = {start}
|
|
25
|
+
queue: deque[Any] = deque([start])
|
|
26
|
+
|
|
27
|
+
trace.add_step(OperationType.VISIT_NODE, f"Start BFS at node {start}", targets=(start,))
|
|
28
|
+
visited_order.append(start)
|
|
29
|
+
|
|
30
|
+
while queue:
|
|
31
|
+
u = queue.popleft()
|
|
32
|
+
for v in graph_model.neighbors(u):
|
|
33
|
+
trace.add_step(OperationType.HIGHLIGHT_EDGE, f"Explore edge ({u}, {v})", targets=(u, v))
|
|
34
|
+
if v not in visited:
|
|
35
|
+
visited.add(v)
|
|
36
|
+
visited_order.append(v)
|
|
37
|
+
queue.append(v)
|
|
38
|
+
trace.add_step(OperationType.VISIT_NODE, f"Visit node {v}", targets=(v,))
|
|
39
|
+
|
|
40
|
+
return visited_order, trace
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def bfs(graph: Graph, start: Any, run_time: float | None = None) -> list[Animation]:
|
|
44
|
+
"""Generate animations for BFS on a Graph component."""
|
|
45
|
+
active_theme = get_active_theme()
|
|
46
|
+
duration = run_time or active_theme.timing.normal
|
|
47
|
+
|
|
48
|
+
_, trace = bfs_trace(graph.model, start)
|
|
49
|
+
animations: list[Animation] = []
|
|
50
|
+
|
|
51
|
+
for step in trace:
|
|
52
|
+
if step.op_type == OperationType.VISIT_NODE:
|
|
53
|
+
node = step.targets[0]
|
|
54
|
+
animations.append(
|
|
55
|
+
graph.animate_mark_visited(
|
|
56
|
+
node, color=active_theme.colors.success, run_time=duration
|
|
57
|
+
)
|
|
58
|
+
)
|
|
59
|
+
elif step.op_type == OperationType.HIGHLIGHT_EDGE:
|
|
60
|
+
u, v = step.targets
|
|
61
|
+
animations.append(
|
|
62
|
+
graph.animate_highlight_edge(
|
|
63
|
+
u, v, color=active_theme.colors.accent, run_time=duration
|
|
64
|
+
)
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
return animations
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
# -----------------------------------------------------------------------------
|
|
71
|
+
# 2. Depth-First Search (DFS)
|
|
72
|
+
# -----------------------------------------------------------------------------
|
|
73
|
+
def dfs_trace(graph_model: GraphModel, start: Any) -> tuple[list[Any], OperationTrace]:
|
|
74
|
+
"""Execute DFS traversal on GraphModel, returning (visited_order, operation_trace)."""
|
|
75
|
+
visited_order: list[Any] = []
|
|
76
|
+
trace = OperationTrace()
|
|
77
|
+
visited: set[Any] = set()
|
|
78
|
+
|
|
79
|
+
def _dfs_rec(u: Any) -> None:
|
|
80
|
+
visited.add(u)
|
|
81
|
+
visited_order.append(u)
|
|
82
|
+
trace.add_step(OperationType.VISIT_NODE, f"Visit node {u}", targets=(u,))
|
|
83
|
+
|
|
84
|
+
for v in graph_model.neighbors(u):
|
|
85
|
+
trace.add_step(OperationType.HIGHLIGHT_EDGE, f"Explore edge ({u}, {v})", targets=(u, v))
|
|
86
|
+
if v not in visited:
|
|
87
|
+
_dfs_rec(v)
|
|
88
|
+
|
|
89
|
+
_dfs_rec(start)
|
|
90
|
+
return visited_order, trace
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def dfs(graph: Graph, start: Any, run_time: float | None = None) -> list[Animation]:
|
|
94
|
+
"""Generate animations for DFS on a Graph component."""
|
|
95
|
+
active_theme = get_active_theme()
|
|
96
|
+
duration = run_time or active_theme.timing.normal
|
|
97
|
+
|
|
98
|
+
_, trace = dfs_trace(graph.model, start)
|
|
99
|
+
animations: list[Animation] = []
|
|
100
|
+
|
|
101
|
+
for step in trace:
|
|
102
|
+
if step.op_type == OperationType.VISIT_NODE:
|
|
103
|
+
node = step.targets[0]
|
|
104
|
+
animations.append(
|
|
105
|
+
graph.animate_mark_visited(
|
|
106
|
+
node, color=active_theme.colors.success, run_time=duration
|
|
107
|
+
)
|
|
108
|
+
)
|
|
109
|
+
elif step.op_type == OperationType.HIGHLIGHT_EDGE:
|
|
110
|
+
u, v = step.targets
|
|
111
|
+
animations.append(
|
|
112
|
+
graph.animate_highlight_edge(
|
|
113
|
+
u, v, color=active_theme.colors.accent, run_time=duration
|
|
114
|
+
)
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
return animations
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
__all__ = [
|
|
121
|
+
"bfs",
|
|
122
|
+
"bfs_trace",
|
|
123
|
+
"dfs",
|
|
124
|
+
"dfs_trace",
|
|
125
|
+
]
|