memory-graph 0.3.15__tar.gz → 0.3.17__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.
Files changed (147) hide show
  1. {memory_graph-0.3.15/memory_graph.egg-info → memory_graph-0.3.17}/PKG-INFO +41 -50
  2. {memory_graph-0.3.15 → memory_graph-0.3.17}/README.md +40 -49
  3. memory_graph-0.3.17/TODO.txt +9 -0
  4. memory_graph-0.3.17/images/.ipynb_checkpoints/jupyter_example-checkpoint.ipynb +85 -0
  5. {memory_graph-0.3.15 → memory_graph-0.3.17}/images/add_one.py +1 -1
  6. memory_graph-0.3.17/images/avltree.py~ +41 -0
  7. memory_graph-0.3.17/images/avltree_fail.gv +26 -0
  8. memory_graph-0.3.17/images/bin_tree.png +0 -0
  9. memory_graph-0.3.17/images/bin_tree.py +38 -0
  10. memory_graph-0.3.17/images/bin_tree2.py +31 -0
  11. memory_graph-0.3.17/images/bin_tree2.py~ +31 -0
  12. {memory_graph-0.3.15 → memory_graph-0.3.17}/images/debugging01.png +0 -0
  13. {memory_graph-0.3.15 → memory_graph-0.3.17}/images/debugging02.png +0 -0
  14. {memory_graph-0.3.15 → memory_graph-0.3.17}/images/debugging03.png +0 -0
  15. {memory_graph-0.3.15 → memory_graph-0.3.17}/images/debugging04.png +0 -0
  16. {memory_graph-0.3.15 → memory_graph-0.3.17}/images/debugging05.png +0 -0
  17. {memory_graph-0.3.15 → memory_graph-0.3.17}/images/debugging06.png +0 -0
  18. {memory_graph-0.3.15 → memory_graph-0.3.17}/images/factorial.py +5 -5
  19. {memory_graph-0.3.15 → memory_graph-0.3.17}/images/factorial01.png +0 -0
  20. {memory_graph-0.3.15 → memory_graph-0.3.17}/images/factorial02.png +0 -0
  21. {memory_graph-0.3.15 → memory_graph-0.3.17}/images/factorial03.png +0 -0
  22. {memory_graph-0.3.15 → memory_graph-0.3.17}/images/factorial04.png +0 -0
  23. {memory_graph-0.3.15 → memory_graph-0.3.17}/images/factorial05.png +0 -0
  24. {memory_graph-0.3.15 → memory_graph-0.3.17}/images/factorial06.png +0 -0
  25. {memory_graph-0.3.15 → memory_graph-0.3.17}/images/factorial07.png +0 -0
  26. memory_graph-0.3.17/images/memory_graph.gv.pdf +0 -0
  27. memory_graph-0.3.17/images/memory_graph.pdf +0 -0
  28. memory_graph-0.3.17/images/my_graph.gv +35 -0
  29. memory_graph-0.3.17/images/my_graph.pdf +0 -0
  30. memory_graph-0.3.17/images/not_node_types.py~ +9 -0
  31. {memory_graph-0.3.15 → memory_graph-0.3.17}/images/power_set.py +2 -2
  32. {memory_graph-0.3.15 → memory_graph-0.3.17}/images/power_set1.png +0 -0
  33. {memory_graph-0.3.15 → memory_graph-0.3.17}/images/power_set10.png +0 -0
  34. {memory_graph-0.3.15 → memory_graph-0.3.17}/images/power_set11.png +0 -0
  35. {memory_graph-0.3.15 → memory_graph-0.3.17}/images/power_set12.png +0 -0
  36. {memory_graph-0.3.15 → memory_graph-0.3.17}/images/power_set13.png +0 -0
  37. {memory_graph-0.3.15 → memory_graph-0.3.17}/images/power_set14.png +0 -0
  38. {memory_graph-0.3.15 → memory_graph-0.3.17}/images/power_set15.png +0 -0
  39. {memory_graph-0.3.15 → memory_graph-0.3.17}/images/power_set16.png +0 -0
  40. {memory_graph-0.3.15 → memory_graph-0.3.17}/images/power_set17.png +0 -0
  41. {memory_graph-0.3.15 → memory_graph-0.3.17}/images/power_set18.png +0 -0
  42. {memory_graph-0.3.15 → memory_graph-0.3.17}/images/power_set19.png +0 -0
  43. {memory_graph-0.3.15 → memory_graph-0.3.17}/images/power_set2.png +0 -0
  44. {memory_graph-0.3.15 → memory_graph-0.3.17}/images/power_set20.png +0 -0
  45. {memory_graph-0.3.15 → memory_graph-0.3.17}/images/power_set21.png +0 -0
  46. {memory_graph-0.3.15 → memory_graph-0.3.17}/images/power_set22.png +0 -0
  47. {memory_graph-0.3.15 → memory_graph-0.3.17}/images/power_set3.png +0 -0
  48. {memory_graph-0.3.15 → memory_graph-0.3.17}/images/power_set4.png +0 -0
  49. {memory_graph-0.3.15 → memory_graph-0.3.17}/images/power_set5.png +0 -0
  50. {memory_graph-0.3.15 → memory_graph-0.3.17}/images/power_set6.png +0 -0
  51. {memory_graph-0.3.15 → memory_graph-0.3.17}/images/power_set7.png +0 -0
  52. {memory_graph-0.3.15 → memory_graph-0.3.17}/images/power_set8.png +0 -0
  53. {memory_graph-0.3.15 → memory_graph-0.3.17}/images/power_set9.png +0 -0
  54. memory_graph-0.3.17/install.txt +31 -0
  55. {memory_graph-0.3.15 → memory_graph-0.3.17}/memory_graph/__init__.py +24 -10
  56. {memory_graph-0.3.15 → memory_graph-0.3.17}/memory_graph/test.py +2 -2
  57. {memory_graph-0.3.15 → memory_graph-0.3.17/memory_graph.egg-info}/PKG-INFO +41 -50
  58. {memory_graph-0.3.15 → memory_graph-0.3.17}/memory_graph.egg-info/SOURCES.txt +17 -5
  59. {memory_graph-0.3.15 → memory_graph-0.3.17}/setup.py +1 -1
  60. memory_graph-0.3.17/src/auto_memory_graph.py +21 -0
  61. memory_graph-0.3.17/src/jupyter_example.ipynb +85 -0
  62. memory_graph-0.3.17/src/pyodide.html +182 -0
  63. memory_graph-0.3.17/uml/memory_graph.uxf +322 -0
  64. memory_graph-0.3.15/images/bin_tree.png +0 -0
  65. memory_graph-0.3.15/images/bin_tree.py +0 -47
  66. memory_graph-0.3.15/images/cmp.sh +0 -3
  67. memory_graph-0.3.15/images/cmp.sh~ +0 -1
  68. memory_graph-0.3.15/images/name_rebinding.py~ +0 -7
  69. memory_graph-0.3.15/memory_graph/t.py +0 -6
  70. {memory_graph-0.3.15 → memory_graph-0.3.17}/LICENSE.txt +0 -0
  71. {memory_graph-0.3.15 → memory_graph-0.3.17}/MANIFEST.in +0 -0
  72. {memory_graph-0.3.15 → memory_graph-0.3.17}/images/add_one.png +0 -0
  73. {memory_graph-0.3.15 → memory_graph-0.3.17}/images/avltree.py +0 -0
  74. {memory_graph-0.3.15 → memory_graph-0.3.17}/images/avltree_base.png +0 -0
  75. {memory_graph-0.3.15 → memory_graph-0.3.17}/images/avltree_dir.png +0 -0
  76. {memory_graph-0.3.15 → memory_graph-0.3.17}/images/avltree_fail.png +0 -0
  77. {memory_graph-0.3.15 → memory_graph-0.3.17}/images/avltree_key_value.png +0 -0
  78. {memory_graph-0.3.15 → memory_graph-0.3.17}/images/avltree_linear.png +0 -0
  79. {memory_graph-0.3.15 → memory_graph-0.3.17}/images/avltree_table.png +0 -0
  80. {memory_graph-0.3.15 → memory_graph-0.3.17}/images/copies.png +0 -0
  81. {memory_graph-0.3.15 → memory_graph-0.3.17}/images/copies.py +0 -0
  82. {memory_graph-0.3.15 → memory_graph-0.3.17}/images/copy_method.png +0 -0
  83. {memory_graph-0.3.15 → memory_graph-0.3.17}/images/copy_method.py +0 -0
  84. {memory_graph-0.3.15 → memory_graph-0.3.17}/images/create_gif.sh +0 -0
  85. {memory_graph-0.3.15 → memory_graph-0.3.17}/images/create_images.sh +0 -0
  86. {memory_graph-0.3.15 → memory_graph-0.3.17}/images/debug_vscode.png +0 -0
  87. {memory_graph-0.3.15 → memory_graph-0.3.17}/images/debugging.gif +0 -0
  88. {memory_graph-0.3.15 → memory_graph-0.3.17}/images/debugging.py +0 -0
  89. {memory_graph-0.3.15 → memory_graph-0.3.17}/images/extension_numpy.png +0 -0
  90. {memory_graph-0.3.15 → memory_graph-0.3.17}/images/extension_numpy.py +0 -0
  91. {memory_graph-0.3.15 → memory_graph-0.3.17}/images/extension_pandas.png +0 -0
  92. {memory_graph-0.3.15 → memory_graph-0.3.17}/images/extension_pandas.py +0 -0
  93. {memory_graph-0.3.15 → memory_graph-0.3.17}/images/factorial.gif +0 -0
  94. {memory_graph-0.3.15 → memory_graph-0.3.17}/images/hash_set.png +0 -0
  95. {memory_graph-0.3.15 → memory_graph-0.3.17}/images/hash_set.py +0 -0
  96. {memory_graph-0.3.15 → memory_graph-0.3.17}/images/highlight.png +0 -0
  97. {memory_graph-0.3.15 → memory_graph-0.3.17}/images/highlight.py +0 -0
  98. {memory_graph-0.3.15 → memory_graph-0.3.17}/images/immutable.py +0 -0
  99. {memory_graph-0.3.15 → memory_graph-0.3.17}/images/immutable1.png +0 -0
  100. {memory_graph-0.3.15 → memory_graph-0.3.17}/images/immutable2.png +0 -0
  101. {memory_graph-0.3.15 → memory_graph-0.3.17}/images/ipython.png +0 -0
  102. {memory_graph-0.3.15 → memory_graph-0.3.17}/images/jupyter_example.png +0 -0
  103. {memory_graph-0.3.15 → memory_graph-0.3.17}/images/linked_list.png +0 -0
  104. {memory_graph-0.3.15 → memory_graph-0.3.17}/images/linked_list.py +0 -0
  105. {memory_graph-0.3.15 → memory_graph-0.3.17}/images/many_types.png +0 -0
  106. {memory_graph-0.3.15 → memory_graph-0.3.17}/images/many_types.py +0 -0
  107. {memory_graph-0.3.15 → memory_graph-0.3.17}/images/mutable.py +0 -0
  108. {memory_graph-0.3.15 → memory_graph-0.3.17}/images/mutable1.png +0 -0
  109. {memory_graph-0.3.15 → memory_graph-0.3.17}/images/mutable2.png +0 -0
  110. {memory_graph-0.3.15 → memory_graph-0.3.17}/images/name_rebinding.py +0 -0
  111. {memory_graph-0.3.15 → memory_graph-0.3.17}/images/not_node_types.py +0 -0
  112. {memory_graph-0.3.15 → memory_graph-0.3.17}/images/not_node_types1.png +0 -0
  113. {memory_graph-0.3.15 → memory_graph-0.3.17}/images/not_node_types2.png +0 -0
  114. {memory_graph-0.3.15 → memory_graph-0.3.17}/images/power_set.gif +0 -0
  115. {memory_graph-0.3.15 → memory_graph-0.3.17}/images/pyodide.png +0 -0
  116. {memory_graph-0.3.15 → memory_graph-0.3.17}/images/rebinding1.png +0 -0
  117. {memory_graph-0.3.15 → memory_graph-0.3.17}/images/rebinding2.png +0 -0
  118. {memory_graph-0.3.15 → memory_graph-0.3.17}/images/uva.png +0 -0
  119. {memory_graph-0.3.15 → memory_graph-0.3.17}/memory_graph/config.py +0 -0
  120. {memory_graph-0.3.15 → memory_graph-0.3.17}/memory_graph/config_default.py +0 -0
  121. {memory_graph-0.3.15 → memory_graph-0.3.17}/memory_graph/config_helpers.py +0 -0
  122. {memory_graph-0.3.15 → memory_graph-0.3.17}/memory_graph/extension_numpy.py +0 -0
  123. {memory_graph-0.3.15 → memory_graph-0.3.17}/memory_graph/extension_pandas.py +0 -0
  124. {memory_graph-0.3.15 → memory_graph-0.3.17}/memory_graph/html_table.py +0 -0
  125. {memory_graph-0.3.15 → memory_graph-0.3.17}/memory_graph/list_view.py +0 -0
  126. {memory_graph-0.3.15 → memory_graph-0.3.17}/memory_graph/memory_to_nodes.py +0 -0
  127. {memory_graph-0.3.15 → memory_graph-0.3.17}/memory_graph/node_base.py +0 -0
  128. {memory_graph-0.3.15 → memory_graph-0.3.17}/memory_graph/node_key_value.py +0 -0
  129. {memory_graph-0.3.15 → memory_graph-0.3.17}/memory_graph/node_linear.py +0 -0
  130. {memory_graph-0.3.15 → memory_graph-0.3.17}/memory_graph/node_table.py +0 -0
  131. {memory_graph-0.3.15 → memory_graph-0.3.17}/memory_graph/sequence.py +0 -0
  132. {memory_graph-0.3.15 → memory_graph-0.3.17}/memory_graph/slicer.py +0 -0
  133. {memory_graph-0.3.15 → memory_graph-0.3.17}/memory_graph/slices.py +0 -0
  134. {memory_graph-0.3.15 → memory_graph-0.3.17}/memory_graph/slices_iterator.py +0 -0
  135. {memory_graph-0.3.15 → memory_graph-0.3.17}/memory_graph/slices_table_iterator.py +0 -0
  136. {memory_graph-0.3.15 → memory_graph-0.3.17}/memory_graph/test_max_graph_depth.py +0 -0
  137. {memory_graph-0.3.15 → memory_graph-0.3.17}/memory_graph/test_memory_graph.py +0 -0
  138. {memory_graph-0.3.15 → memory_graph-0.3.17}/memory_graph/test_memory_to_nodes.py +0 -0
  139. {memory_graph-0.3.15 → memory_graph-0.3.17}/memory_graph/test_sequence.py +0 -0
  140. {memory_graph-0.3.15 → memory_graph-0.3.17}/memory_graph/test_slicer.py +0 -0
  141. {memory_graph-0.3.15 → memory_graph-0.3.17}/memory_graph/test_slices.py +0 -0
  142. {memory_graph-0.3.15 → memory_graph-0.3.17}/memory_graph/test_slices_iterator.py +0 -0
  143. {memory_graph-0.3.15 → memory_graph-0.3.17}/memory_graph/utils.py +0 -0
  144. {memory_graph-0.3.15 → memory_graph-0.3.17}/memory_graph.egg-info/dependency_links.txt +0 -0
  145. {memory_graph-0.3.15 → memory_graph-0.3.17}/memory_graph.egg-info/requires.txt +0 -0
  146. {memory_graph-0.3.15 → memory_graph-0.3.17}/memory_graph.egg-info/top_level.txt +0 -0
  147. {memory_graph-0.3.15 → memory_graph-0.3.17}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: memory_graph
3
- Version: 0.3.15
3
+ Version: 0.3.17
4
4
  Summary: Generate intuitive graphs of your Python data, great for debugging and understanding complex relationships.
5
5
  Home-page: https://github.com/bterwijn/memory_graph
6
6
  Author: Bas Terwijn
@@ -199,7 +199,7 @@ mg.show(locals())
199
199
 
200
200
 
201
201
  ### Custom Copy ###
202
- We can write our own custom copy function or method in case the three "copy" options don't do what we want. For example, in the code below the copy() method of My_Class copies the `digits` but shares the `letters` between two objects.
202
+ We can write our own custom copy function or method in case the three standard "copy" options don't do what we want. For example, in the code below the copy() method of My_Class copies the `digits` but shares the `letters` between two objects.
203
203
 
204
204
  ```python
205
205
  import memory_graph as mg
@@ -242,7 +242,7 @@ mg.render(locals(), 'rebinding2.png')
242
242
  | rebinding1.png | rebinding2.png |
243
243
 
244
244
  ## Call Stack ##
245
- The `mg.get_call_stack()` function retrieves the entire call stack, including the local variables for each function on the stack. This enables us to visualize the local variables across all active functions simultaneously. By examining the graph, we can determine whether any local variables from different functions share data. For instance, consider the function `add_one()` which adds the value `1` to each of its parameters `a`, `b`, and `c`.
245
+ The `mg.stack()` function retrieves the entire call stack, including the local variables for each function on the stack. This enables us to visualize the local variables across all active functions simultaneously. By examining the graph, we can determine whether any local variables from different functions share data. For instance, consider the function `add_one()` which adds the value `1` to each of its parameters `a`, `b`, and `c`.
246
246
 
247
247
  ```python
248
248
  import memory_graph as mg
@@ -251,7 +251,7 @@ def add_one(a, b, c):
251
251
  a += [1]
252
252
  b += (1,)
253
253
  c += [1]
254
- mg.show(mg.get_call_stack())
254
+ mg.show(mg.stack())
255
255
 
256
256
  a = [4, 3, 2]
257
257
  b = (4, 3, 2)
@@ -295,9 +295,9 @@ import memory_graph as mg
295
295
  def factorial(n):
296
296
  if n==0:
297
297
  return 1
298
- mg.block(mg.show, mg.get_call_stack())
298
+ mg.block(mg.show, mg.stack())
299
299
  result = n * factorial(n-1)
300
- mg.block(mg.show, mg.get_call_stack())
300
+ mg.block(mg.show, mg.stack())
301
301
  return result
302
302
 
303
303
  print(factorial(3))
@@ -314,7 +314,7 @@ A more interesting recursive example that shows sharing of data is power_set().
314
314
  import memory_graph as mg
315
315
 
316
316
  def get_subsets(subsets, data, i, subset):
317
- mg.block(mg.show, mg.get_call_stack())
317
+ mg.block(mg.show, mg.stack())
318
318
  if i == len(data):
319
319
  subsets.append(subset.copy())
320
320
  return
@@ -322,7 +322,7 @@ def get_subsets(subsets, data, i, subset):
322
322
  get_subsets(subsets, data, i+1, subset) # do include data[i]
323
323
  subset.pop()
324
324
  get_subsets(subsets, data, i+1, subset) # don't include data[i]
325
- mg.block(mg.show, mg.get_call_stack())
325
+ mg.block(mg.show, mg.stack())
326
326
 
327
327
  def power_set(data):
328
328
  subsets = []
@@ -346,13 +346,13 @@ mg.render(locals(), "my_graph.pdf")
346
346
  as a *watch* in a debugger tool such as the integrated debugger in Visual Studio Code. Then open the "my_graph.pdf" output file to continuously see all the local variables while debugging. This avoids having to add any memory_graph `show()` or `render()` calls to your code.
347
347
 
348
348
  ### Call Stack in Watch Context ###
349
- The ```mg.get_call_stack()``` doesn't work well in *watch* context in most debuggers because debuggers introduce additional stack frames that cause problems. Use these alternative functions for various debuggers to filter out these problematic stack frames:
349
+ The ```mg.stack()``` doesn't work well in *watch* context in most debuggers because debuggers introduce additional stack frames that cause problems. Use these alternative functions for various debuggers to filter out these problematic stack frames:
350
350
 
351
351
  | debugger | function to get the call stack |
352
352
  |:---|:---|
353
- | **pdb, pudb** | `mg.get_call_stack_pdb()` |
354
- | **Visual Studio Code** | `mg.get_call_stack_vscode()` |
355
- | **Pycharm** | `mg.get_call_stack_pycharm()` |
353
+ | **pdb, pudb** | `mg.stack_pdb()` |
354
+ | **Visual Studio Code** | `mg.stack_vscode()` |
355
+ | **Pycharm** | `mg.stack_pycharm()` |
356
356
 
357
357
  ![debug_vscode.png](https://raw.githubusercontent.com/bterwijn/memory_graph/main/images/debug_vscode.png)
358
358
 
@@ -363,7 +363,7 @@ mg.save_call_stack("call_stack.txt")
363
363
  ```
364
364
  Choose 'after' and 'up_to' what function you want to slice and then call this function to get the desired call stack:
365
365
  ```
366
- mg.get_call_stack_after_up_to(after_function, up_to_function="<module>")
366
+ mg.stack_after_up_to(after_function, up_to_function="<module>")
367
367
  ```
368
368
 
369
369
  ### Debugging without Debugger Tool ###
@@ -373,13 +373,13 @@ To simplify debugging without a debugger tool, we offer these alias functions th
373
373
  | alias | purpose | function call |
374
374
  |:---|:---|:---|
375
375
  | `mg.sl()` | **s**how **l**ocal variables | `mg.show(locals())` |
376
- | `mg.ss()` | **s**how the call **s**tack | `mg.show(mg.get_call_stack())` |
376
+ | `mg.ss()` | **s**how the call **s**tack | `mg.show(mg.stack())` |
377
377
  | `mg.bsl()` | **b**lock after **s**howing **l**ocal variables | `mg.block(mg.show, locals())` |
378
- | `mg.bss()` | **b**lock after **s**howing the call **s**tack | `mg.block(mg.show, mg.get_call_stack())` |
378
+ | `mg.bss()` | **b**lock after **s**howing the call **s**tack | `mg.block(mg.show, mg.stack())` |
379
379
  | `mg.rl()` | **r**ender **l**ocal variables | `mg.render(locals())` |
380
- | `mg.rs()` | **r**ender the call **s**tack | `mg.render(mg.get_call_stack())` |
380
+ | `mg.rs()` | **r**ender the call **s**tack | `mg.render(mg.stack())` |
381
381
  | `mg.brl()` | **b**lock after **r**endering **l**ocal variables | `mg.block(mg.render, locals())` |
382
- | `mg.brs()` | **b**lock after **r**endering the call **s**tack | `mg.block(mg.render, mg.get_call_stack())` |
382
+ | `mg.brs()` | **b**lock after **r**endering the call **s**tack | `mg.block(mg.render, mg.stack())` |
383
383
  | `mg.l()` | same as `mg.bsl()` | |
384
384
  | `mg.s()` | same as `mg.bss()` | |
385
385
 
@@ -430,7 +430,7 @@ class LinkedList:
430
430
  new_node.next = self.head
431
431
  self.head.prev = new_node
432
432
  self.head = new_node
433
- mg.block(mg.show, locals()) # <--- draw graph
433
+ mg.block(mg.show, locals()) # <--- draw locals
434
434
 
435
435
  linked_list = LinkedList()
436
436
  n = 100
@@ -446,42 +446,33 @@ import memory_graph as mg
446
446
  import random
447
447
  random.seed(0) # use same random numbers each run
448
448
 
449
- class Node:
450
-
451
- def __init__(self, value):
452
- self.smaller = None
453
- self.value = value
454
- self.larger = None
455
-
456
449
  class BinTree:
457
450
 
458
- def __init__(self):
459
- self.root = None
451
+ def __init__(self, value=None, smaller=None, larger=None):
452
+ self.smaller = smaller
453
+ self.value = value
454
+ self.larger = larger
460
455
 
461
- def add_recursive(self, new_value, node):
462
- if new_value < node.value:
463
- if node.smaller is None:
464
- node.smaller = Node(new_value)
456
+ def add(self, value):
457
+ if self.value is None:
458
+ self.value = value
459
+ elif value < self.value:
460
+ if self.smaller is None:
461
+ self.smaller = BinTree(value)
465
462
  else:
466
- self.add_recursive(new_value, node.smaller)
463
+ self.smaller.add(value)
467
464
  else:
468
- if node.larger is None:
469
- node.larger = Node(new_value)
465
+ if self.larger is None:
466
+ self.larger = BinTree(value)
470
467
  else:
471
- self.add_recursive(new_value, node.larger)
472
- mg.block(mg.show, locals()) # <--- draw graph
473
-
474
- def add(self, value):
475
- if self.root is None:
476
- self.root = Node(value)
477
- else:
478
- self.add_recursive(value, self.root)
468
+ self.larger.add(value)
469
+ mg.block(mg.show, mg.stack()) # <--- draw stack
479
470
 
480
471
  tree = BinTree()
481
472
  n = 100
482
473
  for i in range(n):
483
- new_value = random.randrange(n)
484
- tree.add(new_value)
474
+ value = random.randrange(n)
475
+ tree.add(value)
485
476
  ```
486
477
  ![bin_tree.png](https://raw.githubusercontent.com/bterwijn/memory_graph/main/images/bin_tree.png)
487
478
 
@@ -502,7 +493,7 @@ class HashSet:
502
493
  self.buckets[index] = []
503
494
  bucket = self.buckets[index]
504
495
  bucket.append(value)
505
- mg.block(mg.show, locals()) # <--- draw graph
496
+ mg.block(mg.show, locals()) # <--- draw locals
506
497
 
507
498
  def contains(self, value):
508
499
  index = hash(value) % len(self.buckets)
@@ -552,7 +543,7 @@ Different aspects of memory_graph can be configured. The default configuration i
552
543
  - Maps each type to a Slicer. A slicer determines how many elements of a data type are shown in the graph to prevent the graph from getting too big. 'Slicer()' does no slicing, 'Slicer(1,2,3)' shows just 1 element at the beginning, 2 in the middle, and 3 at the end.
553
544
 
554
545
  ### Simplified Graph ###
555
- Memory_graph simplifies the visualization (and the viewer's mental model) by **not** showing separate nodes for immutable types like `bool`, `int`, `float`, `complex`, and `str` by default. This simplification can sometimes be slightly misleading. As in the example below, after a shallow copy, lists `a` and `b` technically share their `int` values, but the graph makes it appear as though `a` and `b` each have their own copies. However, since `int` is immutable, this simplification will never lead to unexpected changeschanging `a` won’t effect `b`.
546
+ Memory_graph simplifies the visualization (and the viewer's mental model) by **not** showing separate nodes for immutable types like `bool`, `int`, `float`, `complex`, and `str` by default. This simplification can sometimes be slightly misleading. As in the example below, after a shallow copy, lists `a` and `b` technically share their `int` values, but the graph makes it appear as though `a` and `b` each have their own copies. However, since `int` is immutable, this simplification will never lead to unexpected changes (changing `a` won’t affect `b`) so will never result in bugs.
556
547
 
557
548
  The simplification strikes a balance: it is slightly misleading but keeps the graph clean and easy to understand and focuses on the mutable types where unexpected changes can occur. This is why it is the default behavior. If you do want to show separate nodes for `int` values, such as for educational purposes, you can simply remove `int` from the `mg.config.not_node_types` set:
558
549
  ```python
@@ -765,7 +756,7 @@ mg.show(locals())
765
756
 
766
757
 
767
758
  ## Jupyter Notebook ##
768
- 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.get_call_stack_jupyter()` to get the whole call stack with these variables filtered out.
759
+ 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.
769
760
 
770
761
  We can use `mg.show()` and `mg.render()` in a Jupyter Notebook, but alternatively we can also use `mg.create_graph()` to create a graph and the `display()` function to render it inline with for example:
771
762
 
@@ -778,11 +769,11 @@ See for example [jupyter_example.ipynb](https://raw.githubusercontent.com/bterwi
778
769
  ![jupyter_example.png](https://raw.githubusercontent.com/bterwijn/memory_graph/main/images/jupyter_example.png)
779
770
 
780
771
  ## ipython ##
781
- 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.get_call_stack_ipython()` to get the whole call stack with these variables filtered out.
772
+ 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.
782
773
 
783
774
  Additionally install file [auto_memory_graph.py](https://raw.githubusercontent.com/bterwijn/memory_graph/main/src/auto_memory_graph.py) in the ipython startup directory:
784
- * Linux/Mac: ~/.ipython/profile_default/startup/
785
- * Windows: %USERPROFILE%\.ipython\profile_default\startup\
775
+ * Linux/Mac: `~/.ipython/profile_default/startup/`
776
+ * Windows: `%USERPROFILE%\.ipython\profile_default\startup\`
786
777
 
787
778
  Then after starting 'ipython' call function `mg_switch()` to turn on/off the automatic visualization of local variables after each command.
788
779
  ![ipyton.png](https://raw.githubusercontent.com/bterwijn/memory_graph/main/images/ipython.png)
@@ -180,7 +180,7 @@ mg.show(locals())
180
180
 
181
181
 
182
182
  ### Custom Copy ###
183
- We can write our own custom copy function or method in case the three "copy" options don't do what we want. For example, in the code below the copy() method of My_Class copies the `digits` but shares the `letters` between two objects.
183
+ We can write our own custom copy function or method in case the three standard "copy" options don't do what we want. For example, in the code below the copy() method of My_Class copies the `digits` but shares the `letters` between two objects.
184
184
 
185
185
  ```python
186
186
  import memory_graph as mg
@@ -223,7 +223,7 @@ mg.render(locals(), 'rebinding2.png')
223
223
  | rebinding1.png | rebinding2.png |
224
224
 
225
225
  ## Call Stack ##
226
- The `mg.get_call_stack()` function retrieves the entire call stack, including the local variables for each function on the stack. This enables us to visualize the local variables across all active functions simultaneously. By examining the graph, we can determine whether any local variables from different functions share data. For instance, consider the function `add_one()` which adds the value `1` to each of its parameters `a`, `b`, and `c`.
226
+ The `mg.stack()` function retrieves the entire call stack, including the local variables for each function on the stack. This enables us to visualize the local variables across all active functions simultaneously. By examining the graph, we can determine whether any local variables from different functions share data. For instance, consider the function `add_one()` which adds the value `1` to each of its parameters `a`, `b`, and `c`.
227
227
 
228
228
  ```python
229
229
  import memory_graph as mg
@@ -232,7 +232,7 @@ def add_one(a, b, c):
232
232
  a += [1]
233
233
  b += (1,)
234
234
  c += [1]
235
- mg.show(mg.get_call_stack())
235
+ mg.show(mg.stack())
236
236
 
237
237
  a = [4, 3, 2]
238
238
  b = (4, 3, 2)
@@ -276,9 +276,9 @@ import memory_graph as mg
276
276
  def factorial(n):
277
277
  if n==0:
278
278
  return 1
279
- mg.block(mg.show, mg.get_call_stack())
279
+ mg.block(mg.show, mg.stack())
280
280
  result = n * factorial(n-1)
281
- mg.block(mg.show, mg.get_call_stack())
281
+ mg.block(mg.show, mg.stack())
282
282
  return result
283
283
 
284
284
  print(factorial(3))
@@ -295,7 +295,7 @@ A more interesting recursive example that shows sharing of data is power_set().
295
295
  import memory_graph as mg
296
296
 
297
297
  def get_subsets(subsets, data, i, subset):
298
- mg.block(mg.show, mg.get_call_stack())
298
+ mg.block(mg.show, mg.stack())
299
299
  if i == len(data):
300
300
  subsets.append(subset.copy())
301
301
  return
@@ -303,7 +303,7 @@ def get_subsets(subsets, data, i, subset):
303
303
  get_subsets(subsets, data, i+1, subset) # do include data[i]
304
304
  subset.pop()
305
305
  get_subsets(subsets, data, i+1, subset) # don't include data[i]
306
- mg.block(mg.show, mg.get_call_stack())
306
+ mg.block(mg.show, mg.stack())
307
307
 
308
308
  def power_set(data):
309
309
  subsets = []
@@ -327,13 +327,13 @@ mg.render(locals(), "my_graph.pdf")
327
327
  as a *watch* in a debugger tool such as the integrated debugger in Visual Studio Code. Then open the "my_graph.pdf" output file to continuously see all the local variables while debugging. This avoids having to add any memory_graph `show()` or `render()` calls to your code.
328
328
 
329
329
  ### Call Stack in Watch Context ###
330
- The ```mg.get_call_stack()``` doesn't work well in *watch* context in most debuggers because debuggers introduce additional stack frames that cause problems. Use these alternative functions for various debuggers to filter out these problematic stack frames:
330
+ The ```mg.stack()``` doesn't work well in *watch* context in most debuggers because debuggers introduce additional stack frames that cause problems. Use these alternative functions for various debuggers to filter out these problematic stack frames:
331
331
 
332
332
  | debugger | function to get the call stack |
333
333
  |:---|:---|
334
- | **pdb, pudb** | `mg.get_call_stack_pdb()` |
335
- | **Visual Studio Code** | `mg.get_call_stack_vscode()` |
336
- | **Pycharm** | `mg.get_call_stack_pycharm()` |
334
+ | **pdb, pudb** | `mg.stack_pdb()` |
335
+ | **Visual Studio Code** | `mg.stack_vscode()` |
336
+ | **Pycharm** | `mg.stack_pycharm()` |
337
337
 
338
338
  ![debug_vscode.png](https://raw.githubusercontent.com/bterwijn/memory_graph/main/images/debug_vscode.png)
339
339
 
@@ -344,7 +344,7 @@ mg.save_call_stack("call_stack.txt")
344
344
  ```
345
345
  Choose 'after' and 'up_to' what function you want to slice and then call this function to get the desired call stack:
346
346
  ```
347
- mg.get_call_stack_after_up_to(after_function, up_to_function="<module>")
347
+ mg.stack_after_up_to(after_function, up_to_function="<module>")
348
348
  ```
349
349
 
350
350
  ### Debugging without Debugger Tool ###
@@ -354,13 +354,13 @@ To simplify debugging without a debugger tool, we offer these alias functions th
354
354
  | alias | purpose | function call |
355
355
  |:---|:---|:---|
356
356
  | `mg.sl()` | **s**how **l**ocal variables | `mg.show(locals())` |
357
- | `mg.ss()` | **s**how the call **s**tack | `mg.show(mg.get_call_stack())` |
357
+ | `mg.ss()` | **s**how the call **s**tack | `mg.show(mg.stack())` |
358
358
  | `mg.bsl()` | **b**lock after **s**howing **l**ocal variables | `mg.block(mg.show, locals())` |
359
- | `mg.bss()` | **b**lock after **s**howing the call **s**tack | `mg.block(mg.show, mg.get_call_stack())` |
359
+ | `mg.bss()` | **b**lock after **s**howing the call **s**tack | `mg.block(mg.show, mg.stack())` |
360
360
  | `mg.rl()` | **r**ender **l**ocal variables | `mg.render(locals())` |
361
- | `mg.rs()` | **r**ender the call **s**tack | `mg.render(mg.get_call_stack())` |
361
+ | `mg.rs()` | **r**ender the call **s**tack | `mg.render(mg.stack())` |
362
362
  | `mg.brl()` | **b**lock after **r**endering **l**ocal variables | `mg.block(mg.render, locals())` |
363
- | `mg.brs()` | **b**lock after **r**endering the call **s**tack | `mg.block(mg.render, mg.get_call_stack())` |
363
+ | `mg.brs()` | **b**lock after **r**endering the call **s**tack | `mg.block(mg.render, mg.stack())` |
364
364
  | `mg.l()` | same as `mg.bsl()` | |
365
365
  | `mg.s()` | same as `mg.bss()` | |
366
366
 
@@ -411,7 +411,7 @@ class LinkedList:
411
411
  new_node.next = self.head
412
412
  self.head.prev = new_node
413
413
  self.head = new_node
414
- mg.block(mg.show, locals()) # <--- draw graph
414
+ mg.block(mg.show, locals()) # <--- draw locals
415
415
 
416
416
  linked_list = LinkedList()
417
417
  n = 100
@@ -427,42 +427,33 @@ import memory_graph as mg
427
427
  import random
428
428
  random.seed(0) # use same random numbers each run
429
429
 
430
- class Node:
431
-
432
- def __init__(self, value):
433
- self.smaller = None
434
- self.value = value
435
- self.larger = None
436
-
437
430
  class BinTree:
438
431
 
439
- def __init__(self):
440
- self.root = None
432
+ def __init__(self, value=None, smaller=None, larger=None):
433
+ self.smaller = smaller
434
+ self.value = value
435
+ self.larger = larger
441
436
 
442
- def add_recursive(self, new_value, node):
443
- if new_value < node.value:
444
- if node.smaller is None:
445
- node.smaller = Node(new_value)
437
+ def add(self, value):
438
+ if self.value is None:
439
+ self.value = value
440
+ elif value < self.value:
441
+ if self.smaller is None:
442
+ self.smaller = BinTree(value)
446
443
  else:
447
- self.add_recursive(new_value, node.smaller)
444
+ self.smaller.add(value)
448
445
  else:
449
- if node.larger is None:
450
- node.larger = Node(new_value)
446
+ if self.larger is None:
447
+ self.larger = BinTree(value)
451
448
  else:
452
- self.add_recursive(new_value, node.larger)
453
- mg.block(mg.show, locals()) # <--- draw graph
454
-
455
- def add(self, value):
456
- if self.root is None:
457
- self.root = Node(value)
458
- else:
459
- self.add_recursive(value, self.root)
449
+ self.larger.add(value)
450
+ mg.block(mg.show, mg.stack()) # <--- draw stack
460
451
 
461
452
  tree = BinTree()
462
453
  n = 100
463
454
  for i in range(n):
464
- new_value = random.randrange(n)
465
- tree.add(new_value)
455
+ value = random.randrange(n)
456
+ tree.add(value)
466
457
  ```
467
458
  ![bin_tree.png](https://raw.githubusercontent.com/bterwijn/memory_graph/main/images/bin_tree.png)
468
459
 
@@ -483,7 +474,7 @@ class HashSet:
483
474
  self.buckets[index] = []
484
475
  bucket = self.buckets[index]
485
476
  bucket.append(value)
486
- mg.block(mg.show, locals()) # <--- draw graph
477
+ mg.block(mg.show, locals()) # <--- draw locals
487
478
 
488
479
  def contains(self, value):
489
480
  index = hash(value) % len(self.buckets)
@@ -533,7 +524,7 @@ Different aspects of memory_graph can be configured. The default configuration i
533
524
  - Maps each type to a Slicer. A slicer determines how many elements of a data type are shown in the graph to prevent the graph from getting too big. 'Slicer()' does no slicing, 'Slicer(1,2,3)' shows just 1 element at the beginning, 2 in the middle, and 3 at the end.
534
525
 
535
526
  ### Simplified Graph ###
536
- Memory_graph simplifies the visualization (and the viewer's mental model) by **not** showing separate nodes for immutable types like `bool`, `int`, `float`, `complex`, and `str` by default. This simplification can sometimes be slightly misleading. As in the example below, after a shallow copy, lists `a` and `b` technically share their `int` values, but the graph makes it appear as though `a` and `b` each have their own copies. However, since `int` is immutable, this simplification will never lead to unexpected changeschanging `a` won’t effect `b`.
527
+ Memory_graph simplifies the visualization (and the viewer's mental model) by **not** showing separate nodes for immutable types like `bool`, `int`, `float`, `complex`, and `str` by default. This simplification can sometimes be slightly misleading. As in the example below, after a shallow copy, lists `a` and `b` technically share their `int` values, but the graph makes it appear as though `a` and `b` each have their own copies. However, since `int` is immutable, this simplification will never lead to unexpected changes (changing `a` won’t affect `b`) so will never result in bugs.
537
528
 
538
529
  The simplification strikes a balance: it is slightly misleading but keeps the graph clean and easy to understand and focuses on the mutable types where unexpected changes can occur. This is why it is the default behavior. If you do want to show separate nodes for `int` values, such as for educational purposes, you can simply remove `int` from the `mg.config.not_node_types` set:
539
530
  ```python
@@ -746,7 +737,7 @@ mg.show(locals())
746
737
 
747
738
 
748
739
  ## Jupyter Notebook ##
749
- 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.get_call_stack_jupyter()` to get the whole call stack with these variables filtered out.
740
+ 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.
750
741
 
751
742
  We can use `mg.show()` and `mg.render()` in a Jupyter Notebook, but alternatively we can also use `mg.create_graph()` to create a graph and the `display()` function to render it inline with for example:
752
743
 
@@ -759,11 +750,11 @@ See for example [jupyter_example.ipynb](https://raw.githubusercontent.com/bterwi
759
750
  ![jupyter_example.png](https://raw.githubusercontent.com/bterwijn/memory_graph/main/images/jupyter_example.png)
760
751
 
761
752
  ## ipython ##
762
- 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.get_call_stack_ipython()` to get the whole call stack with these variables filtered out.
753
+ 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.
763
754
 
764
755
  Additionally install file [auto_memory_graph.py](https://raw.githubusercontent.com/bterwijn/memory_graph/main/src/auto_memory_graph.py) in the ipython startup directory:
765
- * Linux/Mac: ~/.ipython/profile_default/startup/
766
- * Windows: %USERPROFILE%\.ipython\profile_default\startup\
756
+ * Linux/Mac: `~/.ipython/profile_default/startup/`
757
+ * Windows: `%USERPROFILE%\.ipython\profile_default\startup\`
767
758
 
768
759
  Then after starting 'ipython' call function `mg_switch()` to turn on/off the automatic visualization of local variables after each command.
769
760
  ![ipyton.png](https://raw.githubusercontent.com/bterwijn/memory_graph/main/images/ipython.png)
@@ -0,0 +1,9 @@
1
+
2
+ mg.block(fun, print_loc=True), update docs, stack-overflow posts
3
+
4
+ Jupyter Notebook inline render using display()
5
+
6
+ webassembly inline render
7
+
8
+ optional max introspect depth for each type/id
9
+ https://discuss.python.org/t/request-for-feedback-memory-graph-a-python-visualization-tool-for-education/78347
@@ -0,0 +1,85 @@
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "id": "23f6d43f-dd17-4020-971e-5bb8a5b1e30b",
6
+ "metadata": {},
7
+ "source": [
8
+ "# test: locals_jupyter()\n",
9
+ "Show a graph build with the filtered Jupyter locals using function `mg.locals_jupyter()`. Just adding integers to a list:"
10
+ ]
11
+ },
12
+ {
13
+ "cell_type": "code",
14
+ "execution_count": null,
15
+ "id": "e8913787-bbef-4adb-b027-ac0f28500233",
16
+ "metadata": {},
17
+ "outputs": [],
18
+ "source": [
19
+ "import memory_graph as mg\n",
20
+ "\n",
21
+ "data = []\n",
22
+ "for i in range(5):\n",
23
+ " data.append(i)\n",
24
+ " display(mg.create_graph(mg.locals_jupyter())) # display in jupyter notebook\n",
25
+ " mg.block(mg.show, mg.locals_jupyter()) # display in PDF reader\n",
26
+ " "
27
+ ]
28
+ },
29
+ {
30
+ "cell_type": "markdown",
31
+ "id": "f66d9b8d-0937-4ad0-97b4-a7459e84c4f2",
32
+ "metadata": {},
33
+ "source": [
34
+ "# test: get_call_stack_jupyter()\n",
35
+ "Show a graph build the filterd Jupyter call stack from function `mg.get_call_stack_jupyter()`. Recursively filling a list with all permutation of elements with resampling:"
36
+ ]
37
+ },
38
+ {
39
+ "cell_type": "code",
40
+ "execution_count": null,
41
+ "id": "15d0c443-7cc6-4b4f-a9db-598aaf261364",
42
+ "metadata": {},
43
+ "outputs": [],
44
+ "source": [
45
+ "import memory_graph as mg\n",
46
+ "\n",
47
+ "def get_all_permutations(permutations, elements, data, max_length):\n",
48
+ " if len(data) == max_length: # recursive stop condition\n",
49
+ " permutations.append(data.copy())\n",
50
+ " else:\n",
51
+ " for i in elements:\n",
52
+ " data.append(i)\n",
53
+ " mg.block(mg.show, mg.get_call_stack_jupyter())\n",
54
+ " get_all_permutations(permutations, elements, data, max_length)\n",
55
+ " data.pop()\n",
56
+ " mg.block(mg.show, mg.get_call_stack_jupyter())\n",
57
+ "\n",
58
+ "permutations = []\n",
59
+ "get_all_permutations(permutations, ['L','R'], [], 3)\n",
60
+ "print(permutations)"
61
+ ]
62
+ }
63
+ ],
64
+ "metadata": {
65
+ "kernelspec": {
66
+ "display_name": "Python 3 (ipykernel)",
67
+ "language": "python",
68
+ "name": "python3"
69
+ },
70
+ "language_info": {
71
+ "codemirror_mode": {
72
+ "name": "ipython",
73
+ "version": 3
74
+ },
75
+ "file_extension": ".py",
76
+ "mimetype": "text/x-python",
77
+ "name": "python",
78
+ "nbconvert_exporter": "python",
79
+ "pygments_lexer": "ipython3",
80
+ "version": "3.12.3"
81
+ }
82
+ },
83
+ "nbformat": 4,
84
+ "nbformat_minor": 5
85
+ }
@@ -8,7 +8,7 @@ def add_one(a, b, c):
8
8
  a += [1]
9
9
  b += (1,)
10
10
  c += [1]
11
- mg.render( mg.get_call_stack(), "add_one.png")
11
+ mg.render( mg.stack(), "add_one.png")
12
12
 
13
13
  a = [4, 3, 2]
14
14
  b = (4, 3, 2)
@@ -0,0 +1,41 @@
1
+ import memory_graph as mg
2
+ import bintrees
3
+
4
+ # Create an AVL tree
5
+ tree = bintrees.AVLTree()
6
+ tree.insert(10, "ten")
7
+ tree.insert(5, "five")
8
+ tree.insert(20, "twenty")
9
+ tree.insert(15, "fifteen")
10
+
11
+ mg.render(locals(), 'avltree_fail.png')
12
+
13
+ mg.config.type_to_color[bintrees.avltree.Node] = "sandybrown"
14
+ mg.render(locals(), 'avltree_color.png')
15
+
16
+ mg.config.type_to_node[bintrees.avltree.Node] = lambda data: mg.node_linear.Node_Linear(data, dir(data))
17
+ mg.config.type_to_slicer[bintrees.avltree.Node] = mg.slicer.Slicer()
18
+ mg.render(locals(), 'avltree_dir.png')
19
+
20
+ mg.config.type_to_node[bintrees.avltree.Node] = lambda data: mg.node_base.Node_Base(f"key:{data.key} value:{data.value}")
21
+ mg.render(locals(), 'avltree_base.png')
22
+
23
+ mg.config.type_to_node[bintrees.avltree.Node] = lambda data: mg.node_linear.Node_Linear(data,
24
+ ['left', data.left,
25
+ 'key', data.key,
26
+ 'value', data.value,
27
+ 'right', data.right])
28
+ mg.render(locals(), 'avltree_linear.png')
29
+
30
+ mg.config.type_to_node[bintrees.avltree.Node] = lambda data: mg.node_key_value.Node_Key_Value(data,
31
+ {'left': data.left,
32
+ 'key': data.key,
33
+ 'value': data.value,
34
+ 'right': data.right}.items())
35
+ mg.render(locals(), 'avltree_key_value.png')
36
+
37
+ mg.config.type_to_node[bintrees.avltree.Node] = lambda data: mg.node_table.Node_Table(data,
38
+ [[data.key, data.value],
39
+ [data.left, data.right]]
40
+ )
41
+ mg.render(locals(), 'avltree_table.png')
@@ -0,0 +1,26 @@
1
+ digraph memory_graph {
2
+ node [shape=plaintext]
3
+ node130513740275104 [label=<
4
+ <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="0" BGCOLOR="white"><TR><TD PORT="table">
5
+ &lt;bintrees.avltree.Node object at 0x76b3992...
6
+ </TD></TR></TABLE>
7
+ > xlabel="Node"]
8
+ node130513740453920 [label=<
9
+ <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="0" BGCOLOR="seagreen1"><TR><TD PORT="table">
10
+ <TABLE BORDER="0" CELLBORDER="0" CELLSPACING="5" CELLPADDING="0">
11
+ <TR><TD BORDER="1" STYLE="ROUNDED"> _root </TD><TD BORDER="1" STYLE="ROUNDED"> _count </TD></TR>
12
+ <TR><TD BORDER="1" PORT="ref0"> </TD><TD BORDER="1"> 4 </TD></TR>
13
+ </TABLE>
14
+ </TD></TR></TABLE>
15
+ > xlabel=AVLTree]
16
+ node130513740453920:ref0 -> node130513740275104:table [style=solid]
17
+ node130513742307200 [label=<
18
+ <TABLE BORDER="0" CELLBORDER="3" CELLSPACING="0" CELLPADDING="0" BGCOLOR="dodgerblue1"><TR><TD PORT="table">
19
+ <TABLE BORDER="0" CELLBORDER="0" CELLSPACING="5" CELLPADDING="0">
20
+ <TR><TD BORDER="1" STYLE="ROUNDED"> tree </TD></TR>
21
+ <TR><TD BORDER="1" PORT="ref0"> </TD></TR>
22
+ </TABLE>
23
+ </TD></TR></TABLE>
24
+ > xlabel=dict]
25
+ node130513742307200:ref0 -> node130513740453920:table [style=solid]
26
+ }
Binary file
@@ -0,0 +1,38 @@
1
+ # This file is part of memory_graph.
2
+ # Copyright (c) 2023, Bas Terwijn.
3
+ # SPDX-License-Identifier: BSD-2-Clause
4
+
5
+ import memory_graph as mg
6
+ import random
7
+ random.seed(0) # use same random numbers each run
8
+
9
+ class BinTree:
10
+
11
+ def __init__(self, value=None, smaller=None, larger=None):
12
+ self.smaller = smaller
13
+ self.value = value
14
+ self.larger = larger
15
+
16
+ def add(self, value):
17
+ if self.value is None:
18
+ self.value = value
19
+ elif value < self.value:
20
+ if self.smaller is None:
21
+ self.smaller = BinTree(value)
22
+ else:
23
+ self.smaller.add(value)
24
+ else:
25
+ if self.larger is None:
26
+ self.larger = BinTree(value)
27
+ else:
28
+ self.larger.add(value)
29
+ if value == 51:
30
+ mg.render(mg.stack(), f"bin_tree.png")
31
+ exit(0)
32
+
33
+ tree = BinTree()
34
+ n = 100
35
+ for i in range(n):
36
+ value = random.randrange(n)
37
+ tree.add(value)
38
+