memory-graph 0.3.30__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.
- memory_graph/__init__.py +322 -0
- memory_graph/call_stack.py +9 -0
- memory_graph/config.py +35 -0
- memory_graph/config_default.py +108 -0
- memory_graph/config_helpers.py +56 -0
- memory_graph/extension_numpy.py +30 -0
- memory_graph/extension_pandas.py +26 -0
- memory_graph/html_table.py +137 -0
- memory_graph/list_view.py +57 -0
- memory_graph/memory_to_nodes.py +200 -0
- memory_graph/node_base.py +136 -0
- memory_graph/node_key_value.py +124 -0
- memory_graph/node_leaf.py +23 -0
- memory_graph/node_linear.py +100 -0
- memory_graph/node_table.py +83 -0
- memory_graph/sequence.py +111 -0
- memory_graph/slicer.py +46 -0
- memory_graph/slices.py +163 -0
- memory_graph/slices_iterator.py +55 -0
- memory_graph/slices_table_iterator.py +79 -0
- memory_graph/test.py +245 -0
- memory_graph/test_max_graph_depth.py +27 -0
- memory_graph/test_memory_graph.py +15 -0
- memory_graph/test_memory_to_nodes.py +15 -0
- memory_graph/test_sequence.py +37 -0
- memory_graph/test_slicer.py +50 -0
- memory_graph/test_slices.py +91 -0
- memory_graph/test_slices_iterator.py +28 -0
- memory_graph/utils.py +105 -0
- memory_graph-0.3.30.dist-info/METADATA +897 -0
- memory_graph-0.3.30.dist-info/RECORD +34 -0
- memory_graph-0.3.30.dist-info/WHEEL +5 -0
- memory_graph-0.3.30.dist-info/licenses/LICENSE.txt +25 -0
- memory_graph-0.3.30.dist-info/top_level.txt +1 -0
memory_graph/test.py
ADDED
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
# This file is part of memory_graph.
|
|
2
|
+
# Copyright (c) 2023, Bas Terwijn.
|
|
3
|
+
# SPDX-License-Identifier: BSD-2-Clause
|
|
4
|
+
|
|
5
|
+
""" Some test data to make memory graph of for test purposes. """
|
|
6
|
+
import memory_graph.utils as utils
|
|
7
|
+
import memory_graph.config as config
|
|
8
|
+
|
|
9
|
+
import numpy as np
|
|
10
|
+
import pandas as pd
|
|
11
|
+
import memory_graph.extension_numpy
|
|
12
|
+
import memory_graph.extension_pandas
|
|
13
|
+
|
|
14
|
+
from memory_graph.node_table import Node_Table
|
|
15
|
+
|
|
16
|
+
import random
|
|
17
|
+
|
|
18
|
+
def test_singular(fun):
|
|
19
|
+
data = 100
|
|
20
|
+
fun(data)
|
|
21
|
+
|
|
22
|
+
def test_linear(fun):
|
|
23
|
+
data = [None, True, 1, 2.2, complex(3,4), 'hello this is a very long string that should be cut off at some point.']
|
|
24
|
+
fun(data)
|
|
25
|
+
|
|
26
|
+
def test_linears(fun):
|
|
27
|
+
data = [(1,2), [3,4], {5,6}, frozenset((7,8)), {9:'nine', 10:'ten'} , bytes('11', 'utf-8'), bytearray('12', 'utf-8')]
|
|
28
|
+
data.append( [i for i in range(20)] )
|
|
29
|
+
fun(data)
|
|
30
|
+
|
|
31
|
+
def test_colors(fun):
|
|
32
|
+
data1 = [None, True, 1, 2.2, complex(3,4), 'hello']
|
|
33
|
+
class My_Class:
|
|
34
|
+
class_var = 1
|
|
35
|
+
def __init__(self):
|
|
36
|
+
self.var=2
|
|
37
|
+
data2 = [(1,2), [3,4], {5,6}, frozenset((7,8)), {9:'9', 10:'10'} , bytes('11', 'utf-8'), bytearray('12', 'utf-8'), My_Class(), My_Class]
|
|
38
|
+
restore = config.not_node_types.copy()
|
|
39
|
+
config.not_node_types.clear()
|
|
40
|
+
fun([data1, data2])
|
|
41
|
+
config.not_node_types = restore
|
|
42
|
+
|
|
43
|
+
def test_empty_linear(fun):
|
|
44
|
+
data = [tuple(), list(), set(), frozenset(), dict() , bytes(), bytearray()]
|
|
45
|
+
fun(data)
|
|
46
|
+
|
|
47
|
+
def test_nested_list(fun):
|
|
48
|
+
data = utils.nested_list([2,2,2,2,2,2,2])
|
|
49
|
+
fun(data)
|
|
50
|
+
|
|
51
|
+
def test_key_value(fun):
|
|
52
|
+
data1 = {1:'a', 2:'b', 3:'c', 4:'d'}
|
|
53
|
+
data2 = {10:100, 20:200, 30:300, 40:400}
|
|
54
|
+
data2[50] = ('c','c')
|
|
55
|
+
data2[60] = data1
|
|
56
|
+
data = {'first':data1, 'second':data2}
|
|
57
|
+
fun(data)
|
|
58
|
+
|
|
59
|
+
def test_class(fun):
|
|
60
|
+
class My_Class1:
|
|
61
|
+
def __init__(self):
|
|
62
|
+
self.foo1=10
|
|
63
|
+
self.bar1=20
|
|
64
|
+
class My_Class2:
|
|
65
|
+
def __init__(self):
|
|
66
|
+
self.foo2=10
|
|
67
|
+
self.bar2=20
|
|
68
|
+
data = [My_Class1(), My_Class2()]
|
|
69
|
+
fun(data)
|
|
70
|
+
|
|
71
|
+
def test_class_vars(fun):
|
|
72
|
+
class My_Class1:
|
|
73
|
+
class_var1 = 'a'
|
|
74
|
+
class_var2 = 'b'
|
|
75
|
+
def __init__(self):
|
|
76
|
+
self.var1=10
|
|
77
|
+
self.var2=20
|
|
78
|
+
def my_method(self):
|
|
79
|
+
return 100
|
|
80
|
+
m = My_Class1()
|
|
81
|
+
data = locals()
|
|
82
|
+
fun(data)
|
|
83
|
+
|
|
84
|
+
def test_share_tuple(fun):
|
|
85
|
+
class My_Class:
|
|
86
|
+
def __init__(self):
|
|
87
|
+
self.a=1
|
|
88
|
+
data = [('a',1), ('a',1), {'a':1}, {'a':1}, My_Class(),My_Class()]
|
|
89
|
+
fun(data)
|
|
90
|
+
|
|
91
|
+
def test_share_children(fun):
|
|
92
|
+
a=['a']
|
|
93
|
+
b=['b']
|
|
94
|
+
c=['c']
|
|
95
|
+
d=['d']
|
|
96
|
+
data = [ [a,b,c,], [a,c,d] ]
|
|
97
|
+
fun(data)
|
|
98
|
+
|
|
99
|
+
def test_list_split(fun):
|
|
100
|
+
data = [ list(range(i)) for i in range(50) ]
|
|
101
|
+
fun(data)
|
|
102
|
+
|
|
103
|
+
def test_key_value_split(fun):
|
|
104
|
+
data = { i:i*10 for i in range(1,20)}
|
|
105
|
+
fun(data)
|
|
106
|
+
|
|
107
|
+
def test_table(fun):
|
|
108
|
+
class My_Table:
|
|
109
|
+
def __init__(self,size):
|
|
110
|
+
self.size=size
|
|
111
|
+
self.data = [i for i in range(size[0]*size[1])]
|
|
112
|
+
data = My_Table((15,15))
|
|
113
|
+
config.type_to_color[My_Table] = 'plum1'
|
|
114
|
+
config.type_to_node[My_Table] = lambda data: (
|
|
115
|
+
Node_Table(data, data.data , data.size[0],
|
|
116
|
+
#column_names = [f'col{i}' for i in range(data.size[1])],
|
|
117
|
+
#row_names = [f'row{i}' for i in range(data.size[0])]
|
|
118
|
+
)
|
|
119
|
+
)
|
|
120
|
+
fun(data)
|
|
121
|
+
|
|
122
|
+
def test_numpy(fun):
|
|
123
|
+
a = np.array([1, 2, 3])
|
|
124
|
+
print(a, type(a))
|
|
125
|
+
data = [
|
|
126
|
+
np.array([1, 2, 3]),
|
|
127
|
+
np.matrix([[i*3+j for j in range(20)] for i in range(3)]),
|
|
128
|
+
np.random.rand(20,20)
|
|
129
|
+
]
|
|
130
|
+
#data = np.matrix('1 2; 3 4')
|
|
131
|
+
fun(data)
|
|
132
|
+
|
|
133
|
+
def test_pandas(fun):
|
|
134
|
+
data = [
|
|
135
|
+
pd.DataFrame({ "calories": [420, 380, 390],
|
|
136
|
+
"duration": [50, 40, 45]
|
|
137
|
+
}),
|
|
138
|
+
|
|
139
|
+
pd.DataFrame({ 'Name' : [ 'Tom', 'Anna', 'Steve', 'Lisa'],
|
|
140
|
+
'Age' : [ 28, 34, 29, 42],
|
|
141
|
+
'Length' : [ 1.70, 1.66, 1.82, 1.73] },
|
|
142
|
+
index=['one', 'two', 'three', 'four']),
|
|
143
|
+
|
|
144
|
+
pd.Series( [i for i in range(20)] )
|
|
145
|
+
]
|
|
146
|
+
fun(data)
|
|
147
|
+
|
|
148
|
+
def example_function(a):
|
|
149
|
+
return a*10
|
|
150
|
+
|
|
151
|
+
class Example_Class:
|
|
152
|
+
class_var1 = 100
|
|
153
|
+
class_var2 = 200
|
|
154
|
+
def __init__(self):
|
|
155
|
+
self.a=1
|
|
156
|
+
self.b=2
|
|
157
|
+
def example_method(self):
|
|
158
|
+
return self.a+self.b
|
|
159
|
+
|
|
160
|
+
def test_function():
|
|
161
|
+
return 10
|
|
162
|
+
|
|
163
|
+
def test_different_types(fun):
|
|
164
|
+
object = Example_Class()
|
|
165
|
+
object_type = type(object)
|
|
166
|
+
func = test_function
|
|
167
|
+
func_type = type(func)
|
|
168
|
+
method = Example_Class.example_method
|
|
169
|
+
method_type = type(method)
|
|
170
|
+
lambda_fun = lambda x: x*10
|
|
171
|
+
lambda_fun_type = type(lambda_fun)
|
|
172
|
+
data = memory_graph.stack()
|
|
173
|
+
fun(data)
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
class Node:
|
|
177
|
+
shared_data = [1,2,3]
|
|
178
|
+
|
|
179
|
+
def __init__(self, value):
|
|
180
|
+
self.smaller = None
|
|
181
|
+
self.shared = Node.shared_data
|
|
182
|
+
self.value = value
|
|
183
|
+
self.larger = None
|
|
184
|
+
|
|
185
|
+
class BinTree:
|
|
186
|
+
|
|
187
|
+
def __init__(self):
|
|
188
|
+
self.root = None
|
|
189
|
+
|
|
190
|
+
def insert_recursive(self, node, value):
|
|
191
|
+
nn = None
|
|
192
|
+
if value < node.value:
|
|
193
|
+
if node.smaller is None:
|
|
194
|
+
nn = Node(value)
|
|
195
|
+
node.smaller = nn
|
|
196
|
+
else:
|
|
197
|
+
nn = self.insert_recursive(node.smaller, value)
|
|
198
|
+
else:
|
|
199
|
+
if node.larger is None:
|
|
200
|
+
nn = Node(value)
|
|
201
|
+
node.larger = nn
|
|
202
|
+
else:
|
|
203
|
+
nn = self.insert_recursive(node.larger, value)
|
|
204
|
+
return nn
|
|
205
|
+
|
|
206
|
+
def insert(self, value):
|
|
207
|
+
nn = None
|
|
208
|
+
if self.root is None:
|
|
209
|
+
nn = Node(value)
|
|
210
|
+
self.root = nn
|
|
211
|
+
else:
|
|
212
|
+
nn = self.insert_recursive(self.root, value)
|
|
213
|
+
return nn
|
|
214
|
+
|
|
215
|
+
def test_missing_edges(fun):
|
|
216
|
+
random.seed(0)
|
|
217
|
+
config.max_graph_depth = 7
|
|
218
|
+
config.max_missing_edges = 5
|
|
219
|
+
tree = BinTree()
|
|
220
|
+
last_node = None
|
|
221
|
+
n = 200
|
|
222
|
+
for i in range(n):
|
|
223
|
+
last_node = tree.insert(random.randint(0,n*10))
|
|
224
|
+
fun( memory_graph.stack() )
|
|
225
|
+
|
|
226
|
+
def test_all(fun):
|
|
227
|
+
pass
|
|
228
|
+
test_singular(fun)
|
|
229
|
+
test_linear(fun)
|
|
230
|
+
test_linears(fun)
|
|
231
|
+
test_colors(fun)
|
|
232
|
+
test_empty_linear(fun)
|
|
233
|
+
test_nested_list(fun)
|
|
234
|
+
test_key_value(fun)
|
|
235
|
+
test_class(fun)
|
|
236
|
+
test_class_vars(fun)
|
|
237
|
+
test_share_tuple(fun)
|
|
238
|
+
test_share_children(fun)
|
|
239
|
+
test_list_split(fun)
|
|
240
|
+
test_key_value_split(fun)
|
|
241
|
+
test_table(fun)
|
|
242
|
+
test_numpy(fun)
|
|
243
|
+
test_pandas(fun)
|
|
244
|
+
test_different_types(fun)
|
|
245
|
+
test_missing_edges(fun)
|
|
@@ -0,0 +1,27 @@
|
|
|
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
|
+
|
|
7
|
+
def build_nested_list(depth = 15):
|
|
8
|
+
first = [1,2]
|
|
9
|
+
last = first
|
|
10
|
+
if depth>0:
|
|
11
|
+
first2, last = build_nested_list(depth-1)
|
|
12
|
+
first.append(first2)
|
|
13
|
+
return first, last
|
|
14
|
+
|
|
15
|
+
first,last = build_nested_list(15)
|
|
16
|
+
for i in range(20):
|
|
17
|
+
last.append('X')
|
|
18
|
+
|
|
19
|
+
child = ('who', 'are', 'my', 'parents?')
|
|
20
|
+
last[4] = child
|
|
21
|
+
last[5] = child
|
|
22
|
+
last[6] = child
|
|
23
|
+
last[7] = child
|
|
24
|
+
last[8] = child
|
|
25
|
+
|
|
26
|
+
mg.show([first,child])
|
|
27
|
+
#mg.show([first])
|
|
@@ -0,0 +1,15 @@
|
|
|
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
|
|
6
|
+
|
|
7
|
+
import memory_graph.test as test
|
|
8
|
+
|
|
9
|
+
if __name__ == '__main__':
|
|
10
|
+
test_fun_count = 0
|
|
11
|
+
def test_fun(data):
|
|
12
|
+
global test_fun_count
|
|
13
|
+
memory_graph.render(data, f'test_graph{test_fun_count}.png')
|
|
14
|
+
test_fun_count += 1
|
|
15
|
+
test.test_all(test_fun)
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# This file is part of memory_graph.
|
|
2
|
+
# Copyright (c) 2023, Bas Terwijn.
|
|
3
|
+
# SPDX-License-Identifier: BSD-2-Clause
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
import memory_graph.memory_to_nodes as memory_to_nodes
|
|
7
|
+
import memory_graph.config_helpers as config_helper
|
|
8
|
+
|
|
9
|
+
config_helper.set_config()
|
|
10
|
+
|
|
11
|
+
l1 = [1,2]
|
|
12
|
+
l2 = [3,4]
|
|
13
|
+
data = [l1,l2,l1,[5,l2]]
|
|
14
|
+
nodes = memory_to_nodes.memory_to_nodes(data)
|
|
15
|
+
#print(nodes)
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# This file is part of memory_graph.
|
|
2
|
+
# Copyright (c) 2023, Bas Terwijn.
|
|
3
|
+
# SPDX-License-Identifier: BSD-2-Clause
|
|
4
|
+
|
|
5
|
+
from memory_graph.sequence import Sequence1D, Sequence2D
|
|
6
|
+
from memory_graph.slicer import Slicer
|
|
7
|
+
|
|
8
|
+
def status(index):
|
|
9
|
+
if type(index) == tuple:
|
|
10
|
+
return index[0]
|
|
11
|
+
return index
|
|
12
|
+
|
|
13
|
+
def test_slicing(sequence, slicer):
|
|
14
|
+
print(sequence)
|
|
15
|
+
print(slicer)
|
|
16
|
+
for i in sequence.indices_all():
|
|
17
|
+
print(i, sequence[i])
|
|
18
|
+
slices = sequence.slice(slicer)
|
|
19
|
+
print('slices:',slices)
|
|
20
|
+
for index in slices:
|
|
21
|
+
print(index, ':', sequence[index])
|
|
22
|
+
for index in slices.table_iter(sequence.size()):
|
|
23
|
+
print(f'{index}: {sequence[index] if status(index)>=0 else None}')
|
|
24
|
+
|
|
25
|
+
def test_sequence():
|
|
26
|
+
sequence = Sequence1D([i for i in range(8)])
|
|
27
|
+
slicer = Slicer(2,3)
|
|
28
|
+
test_slicing(sequence, slicer)
|
|
29
|
+
|
|
30
|
+
width = 5
|
|
31
|
+
height = 6
|
|
32
|
+
sequence = Sequence2D([[x+y*width for x in range(width)] for y in range(height)])
|
|
33
|
+
slicer = (Slicer(1,2), Slicer(2,1))
|
|
34
|
+
test_slicing(sequence, slicer)
|
|
35
|
+
|
|
36
|
+
if __name__ == '__main__':
|
|
37
|
+
test_sequence()
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# This file is part of memory_graph.
|
|
2
|
+
# Copyright (c) 2023, Bas Terwijn.
|
|
3
|
+
# SPDX-License-Identifier: BSD-2-Clause
|
|
4
|
+
|
|
5
|
+
from memory_graph.slicer import Slicer
|
|
6
|
+
|
|
7
|
+
def test_slicer():
|
|
8
|
+
slicer = Slicer(0.1, 0.2, 0.3)
|
|
9
|
+
slices = slicer.get_slices(100)
|
|
10
|
+
assert slices.get_slices() == [[0, 10], [40, 60], [70, 100]], "Slicer error"
|
|
11
|
+
|
|
12
|
+
slicer = Slicer(10, 20, 30)
|
|
13
|
+
slices = slicer.get_slices(100)
|
|
14
|
+
assert slices.get_slices() == [[0, 10], [40, 60], [70, 100]], "Slicer error"
|
|
15
|
+
|
|
16
|
+
slicer = Slicer(0.1, 0.3)
|
|
17
|
+
slices = slicer.get_slices(100)
|
|
18
|
+
assert slices.get_slices() == [[0, 10], [70, 100]], "Slicer error"
|
|
19
|
+
|
|
20
|
+
slicer = Slicer(10, 30)
|
|
21
|
+
slices = slicer.get_slices(100)
|
|
22
|
+
assert slices.get_slices() == [[0, 10], [70, 100]], "Slicer error"
|
|
23
|
+
|
|
24
|
+
slicer = Slicer(0.1)
|
|
25
|
+
slices = slicer.get_slices(100)
|
|
26
|
+
assert slices.get_slices() == [[0, 10]], "Slicer error"
|
|
27
|
+
|
|
28
|
+
slicer = Slicer(10)
|
|
29
|
+
slices = slicer.get_slices(100)
|
|
30
|
+
assert slices.get_slices() == [[0, 10]], "Slicer error"
|
|
31
|
+
|
|
32
|
+
slicer = Slicer()
|
|
33
|
+
slices = slicer.get_slices(100)
|
|
34
|
+
assert slices.get_slices() == [[0, 100]], "Slicer error"
|
|
35
|
+
|
|
36
|
+
slicer = Slicer(2,2)
|
|
37
|
+
slices = slicer.get_slices(0)
|
|
38
|
+
assert slices.get_slices() == [], "Slicer error"
|
|
39
|
+
|
|
40
|
+
slicer = Slicer(2,2)
|
|
41
|
+
slices = slicer.get_slices(5)
|
|
42
|
+
assert slices.get_slices() == [[0,5]], "Slicer error"
|
|
43
|
+
|
|
44
|
+
slicer = Slicer(2,2)
|
|
45
|
+
slices = slicer.get_slices(6)
|
|
46
|
+
assert slices.get_slices() == [[0,2],[4,6]], "Slicer error"
|
|
47
|
+
|
|
48
|
+
if __name__ == '__main__':
|
|
49
|
+
test_slicer()
|
|
50
|
+
print('Slicer test passed')
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# This file is part of memory_graph.
|
|
2
|
+
# Copyright (c) 2023, Bas Terwijn.
|
|
3
|
+
# SPDX-License-Identifier: BSD-2-Clause
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
from memory_graph.slices import Slices1D, Slices2D
|
|
7
|
+
|
|
8
|
+
def test_slices1d():
|
|
9
|
+
test = Slices1D( [[10,20], [30,40], [60,70], [80,90]] )
|
|
10
|
+
slices = test.copy()
|
|
11
|
+
slices.add_slice([21,79])
|
|
12
|
+
assert slices.get_slices() == [[10,90]], "Slice error: merging begin and end"
|
|
13
|
+
|
|
14
|
+
slices = test.copy()
|
|
15
|
+
slices.add_slice([31,39])
|
|
16
|
+
assert slices.get_slices() == [[10,20], [30,40], [60,70], [80,90]], "Slice error: merging begin and end"
|
|
17
|
+
|
|
18
|
+
slices = test.copy()
|
|
19
|
+
slices.add_slice([15,50])
|
|
20
|
+
assert slices.get_slices() == [[10,50], [60,70], [80,90]], "Slice error: merging begin"
|
|
21
|
+
|
|
22
|
+
slices = test.copy()
|
|
23
|
+
slices.add_slice([15,65])
|
|
24
|
+
assert slices.get_slices() == [[10,70], [80,90]], "Slice error: merging begin"
|
|
25
|
+
|
|
26
|
+
slices = test.copy()
|
|
27
|
+
slices.add_slice([35,45])
|
|
28
|
+
assert slices.get_slices() == [[10,20], [30,45], [60,70], [80,90]], "Slice error: merging begin"
|
|
29
|
+
|
|
30
|
+
slices = test.copy()
|
|
31
|
+
slices.add_slice([25,65])
|
|
32
|
+
assert slices.get_slices() == [[10,20], [25,70], [80,90]], "Slice error: merging end"
|
|
33
|
+
|
|
34
|
+
slices = test.copy()
|
|
35
|
+
slices.add_slice([15,65])
|
|
36
|
+
assert slices.get_slices() == [[10,70], [80,90]], "Slice error: merging end"
|
|
37
|
+
|
|
38
|
+
slices = test.copy()
|
|
39
|
+
slices.add_slice([55,65])
|
|
40
|
+
assert slices.get_slices() == [[10,20], [30,40], [55,70], [80,90]], "Slice error: merging end"
|
|
41
|
+
|
|
42
|
+
slices = test.copy()
|
|
43
|
+
slices.add_slice([25,75])
|
|
44
|
+
assert slices.get_slices() == [[10,20], [25,75], [80,90]], "Slice error: merging none"
|
|
45
|
+
|
|
46
|
+
slices = test.copy()
|
|
47
|
+
slices.add_slice([5,6])
|
|
48
|
+
assert slices.get_slices() == [[5,6], [10,20], [30,40], [60,70], [80,90]], "Slice error: merging none"
|
|
49
|
+
|
|
50
|
+
slices = test.copy()
|
|
51
|
+
slices.add_slice([95,96])
|
|
52
|
+
assert slices.get_slices() == [[10,20], [30,40], [60,70], [80,90], [95,96]], "Slice error: merging none"
|
|
53
|
+
|
|
54
|
+
slices = test.copy()
|
|
55
|
+
assert not slices.add_slice([10,11])
|
|
56
|
+
assert not slices.add_slice([19,20])
|
|
57
|
+
assert not slices.add_slice([30,31])
|
|
58
|
+
assert not slices.add_slice([39,40])
|
|
59
|
+
assert not slices.add_slice([65,66])
|
|
60
|
+
assert slices.add_slice([9,10])
|
|
61
|
+
assert slices.add_slice([20,21])
|
|
62
|
+
assert slices.add_slice([28,29])
|
|
63
|
+
assert slices.add_slice([41,42])
|
|
64
|
+
assert slices.add_slice([75,76])
|
|
65
|
+
assert slices.add_slice([100,200])
|
|
66
|
+
|
|
67
|
+
test = Slices1D( [ [i,i+2] for i in range(0,30,4)] )
|
|
68
|
+
#print('test:',test)
|
|
69
|
+
for index in range(30):
|
|
70
|
+
#print('index:',index, 'has_index:',test.has_index(index))
|
|
71
|
+
assert test.has_index(index) == ((index//2) % 2 == 0), f"Error: {index}"
|
|
72
|
+
|
|
73
|
+
def test_slices2d():
|
|
74
|
+
from memory_graph.slices import Slices
|
|
75
|
+
slices2d = Slices2D( Slices1D([[20,30]]),
|
|
76
|
+
Slices1D([[20,30]])
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
slices2d.add_index((19,19))
|
|
80
|
+
slices2d.add_index((31,31))
|
|
81
|
+
print(slices2d)
|
|
82
|
+
slices2d.add_index((18,19))
|
|
83
|
+
print(slices2d)
|
|
84
|
+
slices2d.add_index((19,18))
|
|
85
|
+
slices2d.add_index((30,30))
|
|
86
|
+
print(slices2d)
|
|
87
|
+
|
|
88
|
+
if __name__ == "__main__":
|
|
89
|
+
test_slices1d()
|
|
90
|
+
test_slices2d()
|
|
91
|
+
print("Slices: All tests pass")
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# This file is part of memory_graph.
|
|
2
|
+
# Copyright (c) 2023, Bas Terwijn.
|
|
3
|
+
# SPDX-License-Identifier: BSD-2-Clause
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
from memory_graph.slices_iterator import Slices_Iterator1D, Slices_Iterator2D
|
|
7
|
+
from memory_graph.slices import Slices1D, Slices2D
|
|
8
|
+
|
|
9
|
+
def test_slices_iterator1d():
|
|
10
|
+
slices1d = Slices1D( [[10,20], [30,40], [60,70], [80,90]] )
|
|
11
|
+
iter = Slices_Iterator1D(slices1d)
|
|
12
|
+
for i in iter:
|
|
13
|
+
print(i)
|
|
14
|
+
assert list(Slices_Iterator1D(slices1d)) == [10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89], "Slices_Iterator: Error in iteration"
|
|
15
|
+
|
|
16
|
+
def test_slices_iterator2d():
|
|
17
|
+
slices2d = Slices2D( Slices1D( [[10,12], [20,22]] ),
|
|
18
|
+
Slices1D( [[10,12], [30,32]] ) )
|
|
19
|
+
iter = Slices_Iterator2D(slices2d)
|
|
20
|
+
for i in iter:
|
|
21
|
+
print(i)
|
|
22
|
+
assert list(Slices_Iterator2D(slices2d)) == [(10, 10), (10, 11), (10, 30), (10, 31), (11, 10), (11, 11), (11, 30), (11, 31), (20, 10), (20, 11), (20, 30), (20, 31), (21, 10), (21, 11), (21, 30), (21, 31)]
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
if __name__ == '__main__':
|
|
26
|
+
test_slices_iterator1d()
|
|
27
|
+
test_slices_iterator2d()
|
|
28
|
+
print("Slices_Iterator: All tests pass")
|
memory_graph/utils.py
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# This file is part of memory_graph.
|
|
2
|
+
# Copyright (c) 2023, Bas Terwijn.
|
|
3
|
+
# SPDX-License-Identifier: BSD-2-Clause
|
|
4
|
+
|
|
5
|
+
import math
|
|
6
|
+
import types
|
|
7
|
+
|
|
8
|
+
def has_dict_attributes(value):
|
|
9
|
+
""" Returns 'True' if 'value' has a '__dict__' attribute. """
|
|
10
|
+
return hasattr(value,"__dict__")
|
|
11
|
+
|
|
12
|
+
def get_dict_attributes(value):
|
|
13
|
+
""" Returns the items of the '__dict__' attribute of 'value'."""
|
|
14
|
+
return getattr(value,"__dict__")
|
|
15
|
+
|
|
16
|
+
def is_function(obj):
|
|
17
|
+
if isinstance(obj, types.FunctionType) or isinstance(obj, types.MethodType):
|
|
18
|
+
return True
|
|
19
|
+
return type(obj).__name__ in {'method_descriptor', 'builtin_function_or_method', 'getset_descriptor', 'classmethod_descriptor'}
|
|
20
|
+
|
|
21
|
+
def filter_dict(dictionary):
|
|
22
|
+
""" Filters out the unwanted dict attributes. """
|
|
23
|
+
if '__name__' in dictionary: # only filter stack frames, for example locals()
|
|
24
|
+
return [
|
|
25
|
+
(k,v) for k, v in dictionary.items() if
|
|
26
|
+
not (type(k) is str and k.startswith('__')) and
|
|
27
|
+
not isinstance(v,types.ModuleType) and
|
|
28
|
+
not is_function(v)
|
|
29
|
+
]
|
|
30
|
+
return [
|
|
31
|
+
(k,v) for k, v in dictionary.items() if
|
|
32
|
+
not (type(k) is str and k.startswith('__'))
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
def filter_type_attributes(tuples):
|
|
36
|
+
""" Filters out the unwanted type attributes (class/static methods). """
|
|
37
|
+
return [
|
|
38
|
+
(k,v) for k, v in tuples if
|
|
39
|
+
not (type(k) is str and k.startswith('__')) and
|
|
40
|
+
not type(v) in {classmethod, staticmethod} and
|
|
41
|
+
not callable(v)
|
|
42
|
+
]
|
|
43
|
+
|
|
44
|
+
def make_sliceable(data):
|
|
45
|
+
""" Returns a sliceble version of data, convert to list if not yet sliceble. """
|
|
46
|
+
try:
|
|
47
|
+
data[0:0]
|
|
48
|
+
return data
|
|
49
|
+
except TypeError:
|
|
50
|
+
return list(data)
|
|
51
|
+
|
|
52
|
+
def is_finite_iterable(data):
|
|
53
|
+
""" Returns 'True' if 'data' is finite iterable. """
|
|
54
|
+
try:
|
|
55
|
+
iter(data) # iterable
|
|
56
|
+
len(data) # and not infinite (not a strong test, but what else?)
|
|
57
|
+
return True
|
|
58
|
+
except TypeError:
|
|
59
|
+
return False
|
|
60
|
+
|
|
61
|
+
def get_type_name(data):
|
|
62
|
+
""" Returns the name of the type of 'data'. """
|
|
63
|
+
return type(data).__name__
|
|
64
|
+
|
|
65
|
+
def nested_list(sizes, i=0, value=[0]):
|
|
66
|
+
""" Returns a nested list with the given 'sizes' for test purposes. """
|
|
67
|
+
if i == len(sizes)-1:
|
|
68
|
+
data = []
|
|
69
|
+
for _ in range(sizes[i]):
|
|
70
|
+
data.append( value[0] )
|
|
71
|
+
value[0]+=1
|
|
72
|
+
else:
|
|
73
|
+
data = []
|
|
74
|
+
for size in range(sizes[i]):
|
|
75
|
+
data.append( nested_list(sizes,i+1) )
|
|
76
|
+
return data
|
|
77
|
+
|
|
78
|
+
def my_round(value):
|
|
79
|
+
""" Rounds the value to the nearest integer rounding '.5' up consistantly. """
|
|
80
|
+
return math.floor(value + 0.5)
|
|
81
|
+
|
|
82
|
+
def generator_has_data(generator):
|
|
83
|
+
""" Returns 'True' if the generator has data. """
|
|
84
|
+
try:
|
|
85
|
+
next(generator)
|
|
86
|
+
return True
|
|
87
|
+
except StopIteration:
|
|
88
|
+
return False
|
|
89
|
+
|
|
90
|
+
def take_through(condition, iterable):
|
|
91
|
+
for i in iterable:
|
|
92
|
+
yield i
|
|
93
|
+
if condition(i):
|
|
94
|
+
return
|
|
95
|
+
|
|
96
|
+
def take_after(condition, iterable):
|
|
97
|
+
taking = False
|
|
98
|
+
for i in iterable:
|
|
99
|
+
if taking:
|
|
100
|
+
yield i
|
|
101
|
+
elif condition(i):
|
|
102
|
+
taking = True
|
|
103
|
+
|
|
104
|
+
if __name__ == '__main__':
|
|
105
|
+
print( nested_list([4,3,2]) )
|