memory-graph 0.3.61__tar.gz → 0.3.63__tar.gz
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.
- {memory_graph-0.3.61/memory_graph.egg-info → memory_graph-0.3.63}/PKG-INFO +97 -105
- {memory_graph-0.3.61 → memory_graph-0.3.63}/README.md +96 -104
- {memory_graph-0.3.61 → memory_graph-0.3.63}/memory_graph/__init__.py +1 -1
- {memory_graph-0.3.61 → memory_graph-0.3.63}/memory_graph/utils.py +2 -0
- {memory_graph-0.3.61 → memory_graph-0.3.63/memory_graph.egg-info}/PKG-INFO +97 -105
- memory_graph-0.3.63/memory_graph.egg-info/SOURCES.txt +39 -0
- {memory_graph-0.3.61 → memory_graph-0.3.63}/pyproject.toml +1 -1
- memory_graph-0.3.61/MANIFEST.in +0 -1
- memory_graph-0.3.61/images/add_one.png +0 -0
- memory_graph-0.3.61/images/add_one.py +0 -18
- memory_graph-0.3.61/images/avltree.py +0 -42
- memory_graph-0.3.61/images/avltree_dir.png +0 -0
- memory_graph-0.3.61/images/avltree_fail.png +0 -0
- memory_graph-0.3.61/images/avltree_key_value.png +0 -0
- memory_graph-0.3.61/images/avltree_leaf.png +0 -0
- memory_graph-0.3.61/images/avltree_linear.png +0 -0
- memory_graph-0.3.61/images/avltree_table.png +0 -0
- memory_graph-0.3.61/images/bin_search.png +0 -0
- memory_graph-0.3.61/images/bin_search.py +0 -40
- memory_graph-0.3.61/images/bin_search_linear.png +0 -0
- memory_graph-0.3.61/images/bin_tree.gif +0 -0
- memory_graph-0.3.61/images/bin_tree.png +0 -0
- memory_graph-0.3.61/images/bin_tree.py +0 -38
- memory_graph-0.3.61/images/binary.gif +0 -0
- memory_graph-0.3.61/images/binary.py +0 -14
- memory_graph-0.3.61/images/bitwise_operators.png +0 -0
- memory_graph-0.3.61/images/bitwise_operators.py +0 -39
- memory_graph-0.3.61/images/colab_example.png +0 -0
- memory_graph-0.3.61/images/copy_immutable.png +0 -0
- memory_graph-0.3.61/images/copy_immutable.py +0 -15
- memory_graph-0.3.61/images/copy_method.png +0 -0
- memory_graph-0.3.61/images/copy_method.py +0 -23
- memory_graph-0.3.61/images/copy_mix.png +0 -0
- memory_graph-0.3.61/images/copy_mix.py +0 -15
- memory_graph-0.3.61/images/copy_mutable.png +0 -0
- memory_graph-0.3.61/images/copy_mutable.py +0 -15
- memory_graph-0.3.61/images/create_gif.sh +0 -27
- memory_graph-0.3.61/images/create_images.sh +0 -47
- memory_graph-0.3.61/images/debug_vscode.png +0 -0
- memory_graph-0.3.61/images/debugging.gif +0 -0
- memory_graph-0.3.61/images/debugging.py +0 -13
- memory_graph-0.3.61/images/embedded1.png +0 -0
- memory_graph-0.3.61/images/embedded2.png +0 -0
- memory_graph-0.3.61/images/extension_numpy.png +0 -0
- memory_graph-0.3.61/images/extension_numpy.py +0 -15
- memory_graph-0.3.61/images/extension_pandas.png +0 -0
- memory_graph-0.3.61/images/extension_pandas.py +0 -17
- memory_graph-0.3.61/images/extension_torch.png +0 -0
- memory_graph-0.3.61/images/extension_torch.py +0 -10
- memory_graph-0.3.61/images/factorial.gif +0 -0
- memory_graph-0.3.61/images/factorial.py +0 -16
- memory_graph-0.3.61/images/hash_set.gif +0 -0
- memory_graph-0.3.61/images/hash_set.png +0 -0
- memory_graph-0.3.61/images/hash_set.py +0 -39
- memory_graph-0.3.61/images/hidden_edges.png +0 -0
- memory_graph-0.3.61/images/hidden_edges.py +0 -8
- memory_graph-0.3.61/images/immutable.py +0 -11
- memory_graph-0.3.61/images/immutable1.png +0 -0
- memory_graph-0.3.61/images/immutable2.png +0 -0
- memory_graph-0.3.61/images/introspect_depth.png +0 -0
- memory_graph-0.3.61/images/introspect_depth.py +0 -43
- memory_graph-0.3.61/images/ipython.png +0 -0
- memory_graph-0.3.61/images/jupyter_example.png +0 -0
- memory_graph-0.3.61/images/linked_list.gif +0 -0
- memory_graph-0.3.61/images/linked_list.png +0 -0
- memory_graph-0.3.61/images/linked_list.py +0 -35
- memory_graph-0.3.61/images/many_types.png +0 -0
- memory_graph-0.3.61/images/many_types.py +0 -13
- memory_graph-0.3.61/images/marimo_example.png +0 -0
- memory_graph-0.3.61/images/memory_graph_web_debugger.png +0 -0
- memory_graph-0.3.61/images/mutable.py +0 -11
- memory_graph-0.3.61/images/mutable1.png +0 -0
- memory_graph-0.3.61/images/mutable2.png +0 -0
- memory_graph-0.3.61/images/name_rebinding.py +0 -9
- memory_graph-0.3.61/images/not_node_types.py +0 -9
- memory_graph-0.3.61/images/power_set.gif +0 -0
- memory_graph-0.3.61/images/power_set.py +0 -26
- memory_graph-0.3.61/images/rebinding1.png +0 -0
- memory_graph-0.3.61/images/rebinding2.png +0 -0
- memory_graph-0.3.61/images/uva.png +0 -0
- memory_graph-0.3.61/images/vscode_copying.gif +0 -0
- memory_graph-0.3.61/images/wrap_int.png +0 -0
- memory_graph-0.3.61/images/wrap_int.py +0 -16
- memory_graph-0.3.61/memory_graph.egg-info/SOURCES.txt +0 -115
- {memory_graph-0.3.61 → memory_graph-0.3.63}/LICENSE.txt +0 -0
- {memory_graph-0.3.61 → memory_graph-0.3.63}/memory_graph/call_stack.py +0 -0
- {memory_graph-0.3.61 → memory_graph-0.3.63}/memory_graph/config.py +0 -0
- {memory_graph-0.3.61 → memory_graph-0.3.63}/memory_graph/config_default.py +0 -0
- {memory_graph-0.3.61 → memory_graph-0.3.63}/memory_graph/config_helpers.py +0 -0
- {memory_graph-0.3.61 → memory_graph-0.3.63}/memory_graph/extension_numpy.py +0 -0
- {memory_graph-0.3.61 → memory_graph-0.3.63}/memory_graph/extension_pandas.py +0 -0
- {memory_graph-0.3.61 → memory_graph-0.3.63}/memory_graph/extension_torch.py +0 -0
- {memory_graph-0.3.61 → memory_graph-0.3.63}/memory_graph/html_table.py +0 -0
- {memory_graph-0.3.61 → memory_graph-0.3.63}/memory_graph/list_view.py +0 -0
- {memory_graph-0.3.61 → memory_graph-0.3.63}/memory_graph/memory_to_nodes.py +0 -0
- {memory_graph-0.3.61 → memory_graph-0.3.63}/memory_graph/node_base.py +0 -0
- {memory_graph-0.3.61 → memory_graph-0.3.63}/memory_graph/node_key_value.py +0 -0
- {memory_graph-0.3.61 → memory_graph-0.3.63}/memory_graph/node_leaf.py +0 -0
- {memory_graph-0.3.61 → memory_graph-0.3.63}/memory_graph/node_linear.py +0 -0
- {memory_graph-0.3.61 → memory_graph-0.3.63}/memory_graph/node_table.py +0 -0
- {memory_graph-0.3.61 → memory_graph-0.3.63}/memory_graph/sequence.py +0 -0
- {memory_graph-0.3.61 → memory_graph-0.3.63}/memory_graph/slicer.py +0 -0
- {memory_graph-0.3.61 → memory_graph-0.3.63}/memory_graph/slices.py +0 -0
- {memory_graph-0.3.61 → memory_graph-0.3.63}/memory_graph/slices_iterator.py +0 -0
- {memory_graph-0.3.61 → memory_graph-0.3.63}/memory_graph/slices_table_iterator.py +0 -0
- {memory_graph-0.3.61 → memory_graph-0.3.63}/memory_graph/test.py +0 -0
- {memory_graph-0.3.61 → memory_graph-0.3.63}/memory_graph/test_max_graph_depth.py +0 -0
- {memory_graph-0.3.61 → memory_graph-0.3.63}/memory_graph/test_memory_graph.py +0 -0
- {memory_graph-0.3.61 → memory_graph-0.3.63}/memory_graph/test_memory_to_nodes.py +0 -0
- {memory_graph-0.3.61 → memory_graph-0.3.63}/memory_graph/test_sequence.py +0 -0
- {memory_graph-0.3.61 → memory_graph-0.3.63}/memory_graph/test_slicer.py +0 -0
- {memory_graph-0.3.61 → memory_graph-0.3.63}/memory_graph/test_slices.py +0 -0
- {memory_graph-0.3.61 → memory_graph-0.3.63}/memory_graph/test_slices_iterator.py +0 -0
- {memory_graph-0.3.61 → memory_graph-0.3.63}/memory_graph.egg-info/dependency_links.txt +0 -0
- {memory_graph-0.3.61 → memory_graph-0.3.63}/memory_graph.egg-info/requires.txt +0 -0
- {memory_graph-0.3.61 → memory_graph-0.3.63}/memory_graph.egg-info/top_level.txt +0 -0
- {memory_graph-0.3.61 → memory_graph-0.3.63}/setup.cfg +0 -0
- {memory_graph-0.3.61 → memory_graph-0.3.63}/setup.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: memory_graph
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.63
|
|
4
4
|
Summary: Teaching tool and debugging aid in context of references, mutable data types, and shallow and deep copy.
|
|
5
5
|
Author-email: Bas Terwijn <bterwijn@gmail.com>
|
|
6
6
|
License-Expression: BSD-2-Clause
|
|
@@ -26,7 +26,7 @@ pip install --upgrade memory_graph
|
|
|
26
26
|
Additionally [Graphviz](https://graphviz.org/download/) needs to be installed.
|
|
27
27
|
|
|
28
28
|
# Highlights #
|
|
29
|
-

|
|
30
30
|
Run a live demo in the 👉 [**Memory Graph Web Debugger**](https://memory-graph.com/#breakpoints=8&continues=1×tep=1.0&play) 👈 now, no installation required!
|
|
31
31
|
|
|
32
32
|
- learn the right **mental model** to think about Python data (references, mutability, shallow vs deep copy)
|
|
@@ -34,7 +34,7 @@ Run a live demo in the 👉 [**Memory Graph Web Debugger**](https://memory-graph
|
|
|
34
34
|
- understand function calls, variable scope, and the **complete program state** through call stack visualization
|
|
35
35
|
|
|
36
36
|
An example Binary Tree data structure:
|
|
37
|
-

|
|
38
38
|
Or see it in the [Memory Grah Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/bin_tree.py×tep=0.2&play).
|
|
39
39
|
|
|
40
40
|
# Videos #
|
|
@@ -57,7 +57,7 @@ class My_Class:
|
|
|
57
57
|
data = [ range(1, 2), (3, 4), {5, 6}, {7:'seven', 8:'eight'}, My_Class(9, 10) ]
|
|
58
58
|
mg.show(data)
|
|
59
59
|
```
|
|
60
|
-

|
|
61
61
|
|
|
62
62
|
Instead of showing the graph on screen you can also render it to an output file (see [Graphviz Output Formats](https://graphviz.org/docs/outputs/)) using for example:
|
|
63
63
|
|
|
@@ -96,7 +96,7 @@ mg.show( locals() )
|
|
|
96
96
|
|
|
97
97
|
</td><td>
|
|
98
98
|
|
|
99
|
-

|
|
100
100
|
|
|
101
101
|
a graph showing `a` and `b` share values
|
|
102
102
|
|
|
@@ -117,10 +117,20 @@ A better way to understand what values are shared is to draw a graph using [memo
|
|
|
117
117
|
|
|
118
118
|
[Call Stack](#call-stack)
|
|
119
119
|
|
|
120
|
+
[Data Model Exercises](#data-model-exercises)
|
|
121
|
+
|
|
122
|
+
[Block](#block)
|
|
123
|
+
|
|
120
124
|
[Debugging](#debugging)
|
|
121
125
|
|
|
122
126
|
[Data Structure Examples](#data-structure-examples)
|
|
123
127
|
|
|
128
|
+
[Sorting Algorithms](#sorting-algorithms)
|
|
129
|
+
|
|
130
|
+
[Bitwise Operators](#bitwise-operators)
|
|
131
|
+
|
|
132
|
+
[Sliding Puzzle Solver](#sliding-puzzle-solver)
|
|
133
|
+
|
|
124
134
|
[Configuration](#configuration)
|
|
125
135
|
|
|
126
136
|
[Introspection](#introspection)
|
|
@@ -158,7 +168,7 @@ The main difference are that running memory_graph locally is a key design choice
|
|
|
158
168
|
* [Reddit](https://www.reddit.com/r/Python_memory_graph/)
|
|
159
169
|
|
|
160
170
|
## Supported by ##
|
|
161
|
-
<img src="https://raw.githubusercontent.com/bterwijn/
|
|
171
|
+
<img src="https://raw.githubusercontent.com/bterwijn/memory_graph_images/main/images/uva.png" alt="University of Amsterdam" width="600">
|
|
162
172
|
|
|
163
173
|
___
|
|
164
174
|
___
|
|
@@ -183,7 +193,7 @@ mg.render(locals(), 'immutable1.png')
|
|
|
183
193
|
b += (1,)
|
|
184
194
|
mg.render(locals(), 'immutable2.png')
|
|
185
195
|
```
|
|
186
|
-
|  |  |
|
|
187
197
|
|:-----------------------------------------------------------:|:-------------------------------------------------------------:|
|
|
188
198
|
| immutable1.png | immutable2.png |
|
|
189
199
|
|
|
@@ -201,7 +211,7 @@ mg.render(locals(), 'mutable1.png')
|
|
|
201
211
|
b += [1] # equivalent to: b.append(1)
|
|
202
212
|
mg.render(locals(), 'mutable2.png')
|
|
203
213
|
```
|
|
204
|
-
|  |  |
|
|
205
215
|
|:-----------------------------------------------------------:|:-------------------------------------------------------------:|
|
|
206
216
|
| mutable1.png | mutable2.png |
|
|
207
217
|
|
|
@@ -218,7 +228,7 @@ a = [ [1, 2], ['x', 'y'] ] # a nested list (a list containing lists)
|
|
|
218
228
|
|
|
219
229
|
# three different ways to make a "copy" of 'a':
|
|
220
230
|
c1 = a
|
|
221
|
-
c2 = copy.copy(a) # equivalent to: a.copy() a[:] list(a)
|
|
231
|
+
c2 = copy.copy(a) # for list equivalent to: a.copy() a[:] list(a)
|
|
222
232
|
c3 = copy.deepcopy(a)
|
|
223
233
|
|
|
224
234
|
mg.show(locals())
|
|
@@ -228,7 +238,7 @@ mg.show(locals())
|
|
|
228
238
|
* `c2` is a **shallow copy**, only the first value is copied, all the underlying values are shared
|
|
229
239
|
* `c3` is a **deep copy**, all the values are copied, nothing is shared
|
|
230
240
|
|
|
231
|
-

|
|
232
242
|
|
|
233
243
|
Or see it in the [Memory Grah Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/copies.py&play).
|
|
234
244
|
|
|
@@ -256,12 +266,12 @@ b = a.custom_copy()
|
|
|
256
266
|
|
|
257
267
|
mg.show(locals())
|
|
258
268
|
```
|
|
259
|
-

|
|
260
270
|
|
|
261
271
|
Or see it in the [Memory Grah Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/custom_copy.py&breakpoints=15&continues=1&play).
|
|
262
272
|
|
|
263
273
|
## Name Rebinding ##
|
|
264
|
-
When `a` and `b` share a mutable value, then changing the value of `b` changes the value of `a` and vice versa. However, reassigning `b` does not change `a`. When you reassign `b`, you only **rebind** the name `b` to another value without affecting any other
|
|
274
|
+
When `a` and `b` share a mutable value, then changing the value of `b` changes the value of `a` and vice versa. However, reassigning `b` does not change `a`. When you reassign `b`, you only **rebind** the name `b` to another value without affecting any other variable.
|
|
265
275
|
|
|
266
276
|
```python
|
|
267
277
|
import memory_graph as mg
|
|
@@ -274,7 +284,7 @@ b += [1] # changes the value of 'b' and 'a'
|
|
|
274
284
|
b = [100, 200] # rebinds 'b' to another value, 'a' is unaffected
|
|
275
285
|
mg.render(locals(), 'rebinding2.png')
|
|
276
286
|
```
|
|
277
|
-
|  |  |
|
|
278
288
|
|:-----------------------------------------------------------:|:-------------------------------------------------------------:|
|
|
279
289
|
| rebinding1.png | rebinding2.png |
|
|
280
290
|
|
|
@@ -296,7 +306,7 @@ c3 = copy.deepcopy(a)
|
|
|
296
306
|
|
|
297
307
|
mg.show(locals())
|
|
298
308
|
```
|
|
299
|
-

|
|
300
310
|
|
|
301
311
|
## Copying a Mix of Mutable and Immutable Values ##
|
|
302
312
|
When copying a mix of values of mutable and immutable type, to save on time and space, a deep copy will try to copy as few values of immutable type as possible in order to copy each value of mutable type.
|
|
@@ -313,10 +323,10 @@ c3 = copy.deepcopy(a)
|
|
|
313
323
|
|
|
314
324
|
mg.show(locals())
|
|
315
325
|
```
|
|
316
|
-

|
|
317
327
|
|
|
318
328
|
# Call Stack #
|
|
319
|
-
The `mg.stack()` function retrieves the entire call stack, including the local variables for each function on the stack. This enables us to understand function calls, variable scope, and the **complete program state** through call stack visualization. By examining the graph, we can
|
|
329
|
+
The `mg.stack()` function retrieves the entire call stack, including the local variables for each function on the stack. This enables us to understand function calls, variable scope, and the **complete program state** through call stack visualization. By examining the graph, we can see whether local variables from different function calls share data. For instance, consider the function `add_one()` which adds the value `1` to each of its parameters `a`, `b`, and `c`.
|
|
320
330
|
|
|
321
331
|
```python
|
|
322
332
|
import memory_graph as mg
|
|
@@ -334,7 +344,7 @@ add_one(a, b, c.copy())
|
|
|
334
344
|
|
|
335
345
|
print(f"a:{a} b:{b} c:{c}")
|
|
336
346
|
```
|
|
337
|
-

|
|
338
348
|
|
|
339
349
|
Or see it in the [Memory Grah Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/function_call.py&play).
|
|
340
350
|
|
|
@@ -342,7 +352,7 @@ In the printed output we see that only `a` is changed as a result of the functio
|
|
|
342
352
|
```
|
|
343
353
|
a:[4, 3, 2, 1] b:(4, 3, 2) c:[4, 3, 2]
|
|
344
354
|
```
|
|
345
|
-
This is because `b` is of immutable type 'tuple' so its value gets copied automatically when it is changed. And because the function is called with a copy of `c`, its original value is not changed by the function. The value of variable `a` is the only value of mutable type that is shared between the root stack frame **'0: \<module>'** and the **'1: add_one'** stack frame of the function so only that variable is affected as a result of the function
|
|
355
|
+
This is because `b` is of immutable type 'tuple' so its value gets copied automatically when it is changed. And because the function is called with a copy of `c`, its original value is not changed by the function. The value of variable `a` is the only value of mutable type that is shared between the root stack frame **'0: \<module>'** and the **'1: add_one'** stack frame of the function call so only that variable is affected as a result of calling the function. The other changes remain confined to the local variables of the ```add_one()``` function.
|
|
346
356
|
|
|
347
357
|
## Function Call That Changes 'int' Value ##
|
|
348
358
|
Even though `int` is an immutable type, so an `int` value can not be changed by directly passing it to a function, we can still change it by wrapping it in a mutable container.
|
|
@@ -361,7 +371,7 @@ add_one(a, b)
|
|
|
361
371
|
|
|
362
372
|
print(f"a:{a} b:{b[0]}")
|
|
363
373
|
```
|
|
364
|
-

|
|
365
375
|
```
|
|
366
376
|
a:10 b:11
|
|
367
377
|
```
|
|
@@ -369,11 +379,11 @@ Or see it in the [Memory Grah Web Debugger](https://memory-graph.com/#codeurl=ht
|
|
|
369
379
|
|
|
370
380
|
The effect of calling `add_one()` is that `b[0]` increases by 1, while `a` is unaffected.
|
|
371
381
|
|
|
372
|
-
|
|
382
|
+
# Data Model Exercises #
|
|
373
383
|
|
|
374
|
-
Now is a good time to practice with
|
|
384
|
+
Now is a good time to practice with Python Data Model concepts. Here are [some exercises](https://github.com/bterwijn/memory_graph_videos/blob/main/exercises/exercises.md) on references, mutability, copies, and function calls.
|
|
375
385
|
|
|
376
|
-
|
|
386
|
+
# Block #
|
|
377
387
|
It is often helpful to temporarily block program execution to inspect the graph. For this we can use the `mg.block()` function:
|
|
378
388
|
|
|
379
389
|
```python
|
|
@@ -402,7 +412,7 @@ def factorial(n):
|
|
|
402
412
|
|
|
403
413
|
print( factorial(4) )
|
|
404
414
|
```
|
|
405
|
-

|
|
406
416
|
|
|
407
417
|
and the result is: 1 x 2 x 3 x 4 = 24
|
|
408
418
|
|
|
@@ -425,7 +435,7 @@ def binary(value: int) -> list[int]:
|
|
|
425
435
|
|
|
426
436
|
print( binary(100) )
|
|
427
437
|
```
|
|
428
|
-

|
|
429
439
|
```
|
|
430
440
|
[1, 1, 0, 0, 1, 0, 0]
|
|
431
441
|
```
|
|
@@ -457,7 +467,7 @@ def power_set(data):
|
|
|
457
467
|
print( power_set(['a', 'b', 'c']) )
|
|
458
468
|
```
|
|
459
469
|
|
|
460
|
-

|
|
461
471
|
```
|
|
462
472
|
[['a', 'b', 'c'], ['a', 'b'], ['a', 'c'], ['a'], ['b', 'c'], ['b'], ['c'], []]
|
|
463
473
|
```
|
|
@@ -488,7 +498,7 @@ The ```mg.stack()``` doesn't work well in **watch** context in most debuggers be
|
|
|
488
498
|
| [PyCharm](https://www.jetbrains.com/pycharm/) | `mg.stack_pycharm()` |
|
|
489
499
|
| [Wing](https://wingware.com/) | `mg.stack_wing()` |
|
|
490
500
|
|
|
491
|
-

|
|
492
502
|
See the [Quick Intro (3:49)](https://www.youtube.com/watch?v=23_bHcr7hqo) video for the setup.
|
|
493
503
|
|
|
494
504
|
## Other Debuggers ##
|
|
@@ -538,7 +548,7 @@ for i in range(1, 6):
|
|
|
538
548
|
```
|
|
539
549
|
and pressing <Enter> a number of times, results in:
|
|
540
550
|
|
|
541
|
-

|
|
542
552
|
|
|
543
553
|
# Data Structure Examples #
|
|
544
554
|
Package memory_graph can **visualize the structure of your data** to easily understand and debug data structures, some examples:
|
|
@@ -575,11 +585,11 @@ for i in range(n):
|
|
|
575
585
|
linked_list.add_back(value)
|
|
576
586
|
mg.block(mg.show, locals()) # <--- draw locals
|
|
577
587
|
```
|
|
578
|
-

|
|
579
589
|
|
|
580
590
|
### Linked List in Cursor AI ###
|
|
581
591
|
Here we show values being added to a Linked List in Cursor AI. When adding the last value '5' we "Step Into" the code to show more of the details.
|
|
582
|
-

|
|
583
593
|
|
|
584
594
|
Or see it in the [Memory Grah Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/linked_list.py×tep=0.2&play).
|
|
585
595
|
|
|
@@ -617,13 +627,13 @@ for i in range(n):
|
|
|
617
627
|
value = random.randrange(n)
|
|
618
628
|
tree.add(value)
|
|
619
629
|
```
|
|
620
|
-

|
|
621
631
|
|
|
622
632
|
### Binary Tree in Visual Studio Code ###
|
|
623
633
|
Here we show values being inserted in a Binary Tree in Visual Studio Code. When inserting the last value '29' we "Step Into" the code to show the recursive implementation.
|
|
624
|
-

|
|
625
635
|
|
|
626
|
-
|
|
636
|
+
See it in the [Memory Grah Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/bin_tree.py×tep=0.2&play) or see the more advanced [Multiway Tree](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/multiway_tree.py&breakpoints=19,33&continues=1×tep=0.2&play) with more than two children per node, making the tree less deep and more efficient.
|
|
627
637
|
|
|
628
638
|
## Hash Set ##
|
|
629
639
|
```python
|
|
@@ -661,14 +671,43 @@ for i in range(n):
|
|
|
661
671
|
new_value = random.randrange(n)
|
|
662
672
|
hash_set.add(new_value)
|
|
663
673
|
```
|
|
664
|
-

|
|
665
675
|
|
|
666
676
|
### Hash Set in PyCharm ###
|
|
667
677
|
Here we show values being inserted in a HashSet in PyCharm. When inserting the last value '44' we "Step Into" the code to show more of the details.
|
|
668
|
-

|
|
669
679
|
|
|
670
680
|
Or see it in the [Memory Grah Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/hash_set.py&breakpoints=32&continues=1×tep=0.5&play).
|
|
671
681
|
|
|
682
|
+
|
|
683
|
+
# Sorting Algorithms #
|
|
684
|
+
|
|
685
|
+
Visualization of different sorting algorithms in Memory Graph Web Debugger.
|
|
686
|
+

|
|
687
|
+
|
|
688
|
+
- [selection sort](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/selection_sort.py&breakpoints=13,27&continues=1×tep=0.2&play)
|
|
689
|
+
- [insertion sort](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/insertion_sort.py&breakpoints=13,29&continues=1×tep=0.2&play)
|
|
690
|
+
- [bubble sort](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/bubble_sort.py&breakpoints=29,38&continues=1×tep=0.2&play)
|
|
691
|
+
- [cocktail shaker sort](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/cocktail_sort.py&breakpoints=16,45&continues=1×tep=0.2&play)
|
|
692
|
+
|
|
693
|
+
|
|
694
|
+
# Bitwise Operators #
|
|
695
|
+
In this configuration example we show the decimal, binary and [two's complement representation](https://www.cs.cornell.edu/~tomf/notes/cps104/twoscomp.html) representation of `int` values of dictionary subclass `Bits` to show the result of [bitwise operators](https://docs.python.org/3/library/stdtypes.html?utm_source=chatgpt.com#bitwise-operations-on-integer-types). The `~` (inverse) operator can be a bit confusing if not shown with two's complement representation.
|
|
696
|
+
|
|
697
|
+
- [bitwise operators](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/bitwise_operators.py&breakpoints=22&continues=1&play)
|
|
698
|
+
|
|
699
|
+

|
|
700
|
+
|
|
701
|
+
|
|
702
|
+
# Sliding Puzzle Solver #
|
|
703
|
+
|
|
704
|
+
A sliding puzzle solver as a challenging example showing how memory_graph deals with large amounts of data. Click "Continue" to step through the breadth-first search generations until a solution path is found:
|
|
705
|
+
|
|
706
|
+
- [sliding puzzle solver](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/sliding_puzzle.py&breakpoints=17,27,29,40&continues=1)
|
|
707
|
+
|
|
708
|
+

|
|
709
|
+
|
|
710
|
+
|
|
672
711
|
# Configuration #
|
|
673
712
|
Different aspects of memory_graph can be configured. The default configuration can be reset by calling 'mg.config_default.reset()'. The Memory Graph Web Debugger gives examples of the [most important configurations](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/config.py&play).
|
|
674
713
|
|
|
@@ -748,7 +787,7 @@ mg.config.embedded_types.remove(int) # now show separate nodes for int values
|
|
|
748
787
|
|
|
749
788
|
mg.render(locals(), 'embedded2.png')
|
|
750
789
|
```
|
|
751
|
-
|  |  |
|
|
752
791
|
|:-----------------------------------------------------------:|:-------------------------------------------------------------:|
|
|
753
792
|
| embedded1.png — simplified | embedded2.png — technically correct |
|
|
754
793
|
|
|
@@ -770,7 +809,7 @@ tree.insert(15, "fifteen")
|
|
|
770
809
|
|
|
771
810
|
mg.show(locals())
|
|
772
811
|
```
|
|
773
|
-

|
|
774
813
|
|
|
775
814
|
## All attributes using dir() ##
|
|
776
815
|
A useful start is to give it some color, show the list of all its attributes using `dir()`, and setting an empty Slicer to see the attribute list in full.
|
|
@@ -793,7 +832,7 @@ mg.config.type_to_slicer[bintrees.avltree.Node] = mg.Slicer()
|
|
|
793
832
|
|
|
794
833
|
mg.show(locals())
|
|
795
834
|
```
|
|
796
|
-

|
|
797
836
|
|
|
798
837
|
Next figure out what the attributes are you want to graph and choose a Node type, there are four options:
|
|
799
838
|
|
|
@@ -816,7 +855,7 @@ mg.config.type_to_node[bintrees.avltree.Node] = lambda data: mg.Node_Leaf(data,
|
|
|
816
855
|
|
|
817
856
|
mg.show(locals())
|
|
818
857
|
```
|
|
819
|
-

|
|
820
859
|
|
|
821
860
|
## 2) Node_Linear ##
|
|
822
861
|
Node_Linear shows multiple values in a line like a list.
|
|
@@ -840,7 +879,7 @@ mg.config.type_to_node[bintrees.avltree.Node] = lambda data: mg.Node_Linear(data
|
|
|
840
879
|
|
|
841
880
|
mg.show(locals())
|
|
842
881
|
```
|
|
843
|
-

|
|
844
883
|
|
|
845
884
|
## 3) Node_Key_Value ##
|
|
846
885
|
Node_Key_Value shows key-value pairs like a dictionary. Note the required `items()` call at the end.
|
|
@@ -864,7 +903,7 @@ mg.config.type_to_node[bintrees.avltree.Node] = lambda data: mg.Node_Key_Value(d
|
|
|
864
903
|
|
|
865
904
|
mg.show(locals())
|
|
866
905
|
```
|
|
867
|
-

|
|
868
907
|
|
|
869
908
|
## 4) Node_Table ##
|
|
870
909
|
Node_Table shows all the values as a table.
|
|
@@ -886,7 +925,7 @@ mg.config.type_to_node[bintrees.avltree.Node] = lambda data: mg.Node_Table(data,
|
|
|
886
925
|
|
|
887
926
|
mg.show(locals())
|
|
888
927
|
```
|
|
889
|
-

|
|
890
929
|
|
|
891
930
|
## Binary Search ##
|
|
892
931
|
For binary search we can use a List_View class to represent a particular sublist without making a list copy.
|
|
@@ -929,64 +968,17 @@ value = data[random.randrange(n)]
|
|
|
929
968
|
index = bin_search(List_View(data, 0, len(data)), value)
|
|
930
969
|
print('index:', index, 'data[index]:', data[index])
|
|
931
970
|
```
|
|
932
|
-

|
|
933
972
|
|
|
934
973
|
Arguably the visualization is then more clear when we show a List_View object as an actual sublist using a Node_linear node:
|
|
935
974
|
|
|
936
975
|
```python
|
|
937
|
-
mg.config.
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-

|
|
942
|
-
|
|
943
|
-
## Bitwise Operators ##
|
|
944
|
-
In this configuration example we show the decimal, binary and [two's complement representation](https://www.cs.cornell.edu/~tomf/notes/cps104/twoscomp.html) representation of `int` values of dictionary subclass `Bits` to show the result of [bitwise operators](https://docs.python.org/3/library/stdtypes.html?utm_source=chatgpt.com#bitwise-operations-on-integer-types). The `~` (inverse) operator can be a bit confusing if not shown with two's complement representation.
|
|
945
|
-
|
|
946
|
-
```python
|
|
947
|
-
import memory_graph as mg
|
|
948
|
-
|
|
949
|
-
class Bits(dict):
|
|
950
|
-
""" Dictionary subclass that we will configure to show binary representations. """
|
|
951
|
-
|
|
952
|
-
def twos_complement(x: int, bits: int) -> str:
|
|
953
|
-
"""Return the two's complement bit string of x in `bits` bits."""
|
|
954
|
-
mask = (1 << bits) - 1
|
|
955
|
-
return format(x & mask, f"0{bits}b")
|
|
956
|
-
|
|
957
|
-
# configure memory_graph to show binary representations of values of type Bits
|
|
958
|
-
mg.config.type_to_node[Bits] = lambda x : mg.Node_Table(x,
|
|
959
|
-
[ ["expression", "decimal", "bin(expression)", "16bit two's complement"] ] +
|
|
960
|
-
[ [k, f'{v:>10}', f'{bin(v):>19}', twos_complement(v,16)] for k, v in x.items()] )
|
|
961
|
-
mg.config.type_to_slicer[Bits] = (mg.Slicer(), mg.Slicer()) # no slicing
|
|
962
|
-
mg.config.type_to_color[Bits] = 'gold'
|
|
963
|
-
mg.config.fontname = 'Courier' # monospace font
|
|
964
|
-
|
|
965
|
-
bits = Bits()
|
|
966
|
-
|
|
967
|
-
# now add some some variables and expressions
|
|
968
|
-
bits['a'] = 1
|
|
969
|
-
bits['b'] = 48
|
|
970
|
-
bits['c'] = 127
|
|
971
|
-
bits['a << 3'] = bits['a'] << 3 # bit shift left by 3
|
|
972
|
-
bits['b >> 3'] = bits['b'] >> 3 # bit shift right by 3
|
|
973
|
-
bits['a | b'] = bits['a'] | bits['b'] # bitwise or
|
|
974
|
-
bits['b & c'] = bits['b'] & bits['c'] # bitwise and
|
|
975
|
-
bits['b ^ c'] = bits['b'] ^ bits['c'] # bitwise exclusive or
|
|
976
|
-
|
|
977
|
-
# negative numbers, inverse, and two's complement
|
|
978
|
-
bits['d'] = 240
|
|
979
|
-
bits['e'] = -240
|
|
980
|
-
bits['f'] = -241 # -(d+1)
|
|
981
|
-
bits['~d'] = ~ bits['d'] # inverse -(x+1)
|
|
982
|
-
bits['~e'] = ~ bits['e'] # inverse -(x+1)
|
|
983
|
-
bits['~f'] = ~ bits['f'] # inverse -(x+1)
|
|
984
|
-
|
|
985
|
-
mg.s()
|
|
976
|
+
mg.config.type_to_node[List_View] = (lambda l: mg.Node_Linear(l,
|
|
977
|
+
[v if l.begin <= i < l.end else '' for i, v in enumerate(l.lst)]
|
|
978
|
+
if hasattr(l, 'end') else [])
|
|
979
|
+
)
|
|
986
980
|
```
|
|
987
|
-

|
|
981
|
+

|
|
990
982
|
|
|
991
983
|
# Graph Depth #
|
|
992
984
|
To limit the size of the graph the maximum depth of the graph is set by `mg.config.max_graph_depth`. Additionally for each type a depth can be set to further limit the graph, as is done for type `B` in the example below. Scissors indicate where the graph is cut short. Alternatively the `id()` of a data elements can be used to limit the graph for that specific element, as is done for the value referenced by variable `c`.
|
|
@@ -1038,7 +1030,7 @@ mg.config.type_to_depth[B] = 3
|
|
|
1038
1030
|
mg.config.type_to_depth[id(c)] = 2
|
|
1039
1031
|
mg.show(locals())
|
|
1040
1032
|
```
|
|
1041
|
-

|
|
1042
1034
|
|
|
1043
1035
|
## Hidden Edges ##
|
|
1044
1036
|
|
|
@@ -1054,7 +1046,7 @@ for i in range(20):
|
|
|
1054
1046
|
|
|
1055
1047
|
mg.show(locals())
|
|
1056
1048
|
```
|
|
1057
|
-

|
|
1058
1050
|
|
|
1059
1051
|
# Extensions #
|
|
1060
1052
|
Different extensions are available for types from other Python packages.
|
|
@@ -1075,7 +1067,7 @@ ndarray_3d = np.random.rand(2,2,2)
|
|
|
1075
1067
|
|
|
1076
1068
|
mg.show(locals())
|
|
1077
1069
|
```
|
|
1078
|
-

|
|
1079
1071
|
|
|
1080
1072
|
Or see it in the [Memory Grah Web Debugger](https://memory-graph.com/#micropip=numpy&codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/mg_numpy.py&continues=1).
|
|
1081
1073
|
|
|
@@ -1096,7 +1088,7 @@ dataframe2 = pd.DataFrame({ 'Name' : [ 'Tom', 'Anna', 'Steve', 'Lisa'],
|
|
|
1096
1088
|
index=['one', 'two', 'three', 'four']) # with row names
|
|
1097
1089
|
mg.show(locals())
|
|
1098
1090
|
```
|
|
1099
|
-

|
|
1100
1092
|
|
|
1101
1093
|
Or see it in the [Memory Grah Web Debugger](https://memory-graph.com/#micropip=pandas&codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/mg_pandas.py&continues=1).
|
|
1102
1094
|
|
|
@@ -1115,11 +1107,11 @@ tensor_3d = torch.rand(2, 2, 2)
|
|
|
1115
1107
|
|
|
1116
1108
|
mg.show(locals())
|
|
1117
1109
|
```
|
|
1118
|
-

|
|
1119
1111
|
|
|
1120
1112
|
# Memory Graph Web Debugger #
|
|
1121
1113
|
The <a href="https://memory-graph.com/#play" target="_blank">Memory Graph Web Debugger</a> lets us use memory_graph without any installation.
|
|
1122
|
-

|
|
1123
1115
|
|
|
1124
1116
|
# Jupyter Notebook #
|
|
1125
1117
|
In Jupyter Notebook `locals()` has additional variables that cause problems in the graph, use `mg.locals_jupyter()` to get the local variables with these problematic variables filtered out. Use `mg.stack_jupyter()` to get the whole call stack with these variables filtered out.
|
|
@@ -1132,7 +1124,7 @@ mg.block(display, mg.create_graph(mg.locals_jupyter()) ) # the same but blocked
|
|
|
1132
1124
|
```
|
|
1133
1125
|
|
|
1134
1126
|
See for example [jupyter_example.ipynb](https://raw.githubusercontent.com/bterwijn/memory_graph/main/src/jupyter_example.ipynb).
|
|
1135
|
-

|
|
1136
1128
|
|
|
1137
1129
|
# ipython #
|
|
1138
1130
|
In ipython `locals()` has additional variables that cause problems in the graph, use `mg.locals_ipython()` to get the local variables with these problematic variables filtered out. Use `mg.stack_ipython()` to get the whole call stack with these variables filtered out.
|
|
@@ -1142,19 +1134,19 @@ Additionally install file [auto_memory_graph.py](https://raw.githubusercontent.c
|
|
|
1142
1134
|
* Windows: `%USERPROFILE%\.ipython\profile_default\startup\`
|
|
1143
1135
|
|
|
1144
1136
|
Then after starting 'ipython' call function `mg_switch()` to turn on/off the automatic visualization of local variables after each command.
|
|
1145
|
-

|
|
1146
1138
|
|
|
1147
1139
|
# Google Colab #
|
|
1148
1140
|
In Google Colab `locals()` has additional variables that cause problems in the graph, use `mg.locals_colab()` to get the local variables with these problematic variables filtered out. Use `mg.stack_colab()` to get the whole call stack with these variables filtered out.
|
|
1149
1141
|
|
|
1150
1142
|
See for example [colab_example.ipynb](https://raw.githubusercontent.com/bterwijn/memory_graph/main/src/colab_example.ipynb).
|
|
1151
|
-

|
|
1152
1144
|
|
|
1153
1145
|
# Marimo #
|
|
1154
1146
|
In Marimo `locals()` has additional variables that cause problems in the graph, use `mg.locals_marimo()` to get the local variables with these problematic variables filtered out. Use `mg.stack_marimo()` to get the whole call stack with these variables filtered out. Memory_graph only works when running Marimo locally, not in the playground.
|
|
1155
1147
|
|
|
1156
1148
|
See for example [marimo_example.py](https://raw.githubusercontent.com/bterwijn/memory_graph/main/src/marimo_example.py).
|
|
1157
|
-

|
|
1158
1150
|
|
|
1159
1151
|
|
|
1160
1152
|
# Animated GIF #
|
|
@@ -1167,7 +1159,7 @@ in your source or better as a *watch* in a debugger so that stepping through the
|
|
|
1167
1159
|
|
|
1168
1160
|
animated0.png, animated1.png, animated2.png, ...
|
|
1169
1161
|
|
|
1170
|
-
Then use these images to make an animated GIF, for example using this Bash script [create_gif.sh](https://raw.githubusercontent.com/bterwijn/
|
|
1162
|
+
Then use these images to make an animated GIF, for example using this Bash script [create_gif.sh](https://raw.githubusercontent.com/bterwijn/memory_graph_images/main/images/create_gif.sh):
|
|
1171
1163
|
|
|
1172
1164
|
```bash
|
|
1173
1165
|
$ bash create_gif.sh animated
|