Skip to content

Commit 65d74a1

Browse files
committed
[Python] Add vector class impl (full vec C API support)
1 parent 2540fe2 commit 65d74a1

File tree

3 files changed

+279
-8
lines changed

3 files changed

+279
-8
lines changed

python/pycubool/bridge.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,15 @@ def get_sub_matrix_hints(time_check):
7272
return hints
7373

7474

75+
def get_sub_vector_hints(time_check):
76+
hints = _hint_no
77+
78+
if time_check:
79+
hints |= _hint_time_check
80+
81+
return hints
82+
83+
7584
def get_transpose_hints(time_check):
7685
hints = _hint_no
7786

@@ -110,6 +119,15 @@ def get_mxm_hints(is_accumulated, time_check):
110119
return hints
111120

112121

122+
def get_vxm_hints(time_check):
123+
hints = _hint_no
124+
125+
if time_check:
126+
hints |= _hint_time_check
127+
128+
return hints
129+
130+
113131
def get_ewiseadd_hints(time_check):
114132
hints = _hint_no
115133

python/pycubool/matrix.py

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,6 @@ def set_marker(self, marker: str):
269269
)
270270

271271
bridge.check(status)
272-
return None
273272

274273
@property
275274
def marker(self):
@@ -533,7 +532,7 @@ def mxm(self, other, out=None, accumulate=False, time_check=False):
533532
bridge.check(status)
534533
return out
535534

536-
def kronecker(self, other, time_check=False):
535+
def kronecker(self, other, out=None, time_check=False):
537536
"""
538537
Matrix-matrix kronecker product with boolean "x = and" operation.
539538
Returns kronecker product of `self` and `other` matrices.
@@ -556,12 +555,14 @@ def kronecker(self, other, time_check=False):
556555
'
557556
558557
:param other: Input matrix
558+
:param out: Optional out matrix to store result
559559
:param time_check: Pass True to measure and log elapsed time of the operation
560560
:return: Matrices kronecker product matrix
561561
"""
562562

563-
shape = (self.nrows * other.nrows, self.ncols * other.ncols)
564-
out = Matrix.empty(shape)
563+
if out is None:
564+
shape = (self.nrows * other.nrows, self.ncols * other.ncols)
565+
out = Matrix.empty(shape)
565566

566567
status = wrapper.loaded_dll.cuBool_Kronecker(
567568
out.hnd,
@@ -573,7 +574,7 @@ def kronecker(self, other, time_check=False):
573574
bridge.check(status)
574575
return out
575576

576-
def ewiseadd(self, other, time_check=False):
577+
def ewiseadd(self, other, out=None, time_check=False):
577578
"""
578579
Element-wise matrix-matrix addition with boolean "+ = or" operation.
579580
Returns element-wise sum of `self` and `other` matrix.
@@ -591,12 +592,14 @@ def ewiseadd(self, other, time_check=False):
591592
'
592593
593594
:param other: Input matrix to sum
595+
:param out: Optional out matrix to store result
594596
:param time_check: Pass True to measure and log elapsed time of the operation
595597
:return: Element-wise matrix-matrix sum
596598
"""
597599

598-
shape = (self.nrows, self.ncols)
599-
out = Matrix.empty(shape)
600+
if out is None:
601+
shape = (self.nrows, self.ncols)
602+
out = Matrix.empty(shape)
600603

601604
status = wrapper.loaded_dll.cuBool_Matrix_EWiseAdd(
602605
out.hnd,
@@ -643,7 +646,6 @@ def reduce(self, time_check=False):
643646
def equals(self, other) -> bool:
644647
"""
645648
Compare two matrices. Returns true if they are equal.
646-
todo: Add this method into C API
647649
648650
:param other: Other matrix to compare
649651
:return: True if matrices are equal

python/pycubool/vector.py

Lines changed: 251 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,3 +45,254 @@ class Vector:
4545

4646
def __init__(self, hnd):
4747
self.hnd = hnd
48+
49+
@classmethod
50+
def empty(cls, nrows):
51+
52+
hnd = ctypes.c_void_p(0)
53+
54+
status = wrapper.loaded_dll.cuBool_Vector_New(
55+
ctypes.byref(hnd), ctypes.c_uint(nrows)
56+
)
57+
58+
bridge.check(status)
59+
60+
return Vector(hnd)
61+
62+
@classmethod
63+
def from_list(cls, nrows, rows, is_sorted=False, no_duplicates=False):
64+
out = cls.empty(nrows)
65+
out.build(rows, is_sorted=is_sorted, no_duplicates=no_duplicates)
66+
return out
67+
68+
@classmethod
69+
def generate(cls, nrows, density: float):
70+
density = min(1.0, max(density, 0.0))
71+
nvals_max = nrows
72+
nvals_to_gen = int(nvals_max * density)
73+
74+
m = nrows
75+
rows = list()
76+
77+
for i in range(nvals_to_gen):
78+
rows.append(random.randrange(0, m))
79+
80+
return Vector.from_list(nrows=nrows, rows=rows, is_sorted=False, no_duplicates=False)
81+
82+
def build(self, rows, is_sorted=False, no_duplicates=False):
83+
84+
nvals = len(rows)
85+
t_rows = (ctypes.c_uint * len(rows))(*rows)
86+
87+
status = wrapper.loaded_dll.cuBool_Vector_Build(
88+
self.hnd, t_rows,
89+
ctypes.c_uint(nvals),
90+
ctypes.c_uint(bridge.get_build_hints(is_sorted, no_duplicates))
91+
)
92+
93+
bridge.check(status)
94+
95+
def dup(self):
96+
hnd = ctypes.c_void_p(0)
97+
98+
status = wrapper.loaded_dll.cuBool_Vector_Duplicate(
99+
self.hnd, ctypes.byref(hnd)
100+
)
101+
102+
bridge.check(status)
103+
return Vector(hnd)
104+
105+
def set_marker(self, marker: str):
106+
assert marker is not None
107+
108+
status = wrapper.loaded_dll.cuBool_Vector_SetMarker(
109+
self.hnd, marker.encode("utf-8")
110+
)
111+
112+
bridge.check(status)
113+
114+
@property
115+
def marker(self):
116+
size = ctypes.c_uint(0)
117+
status = wrapper.loaded_dll.cuBool_Vector_Marker(
118+
self.hnd, ctypes.POINTER(ctypes.c_char)(), ctypes.byref(size)
119+
)
120+
121+
bridge.check(status)
122+
123+
c_buffer = (ctypes.c_char * int(size.value))()
124+
status = wrapper.loaded_dll.cuBool_Vector_Marker(
125+
self.hnd, c_buffer, ctypes.byref(size)
126+
)
127+
128+
bridge.check(status)
129+
return c_buffer.value.decode("utf-8")
130+
131+
@property
132+
def nrows(self) -> int:
133+
result = ctypes.c_uint(0)
134+
135+
status = wrapper.loaded_dll.cuBool_Vector_Nrows(
136+
self.hnd, ctypes.byref(result)
137+
)
138+
139+
bridge.check(status)
140+
return int(result.value)
141+
142+
@property
143+
def nvals(self) -> int:
144+
result = ctypes.c_uint(0)
145+
146+
status = wrapper.loaded_dll.cuBool_Vector_Nvals(
147+
self.hnd, ctypes.byref(result)
148+
)
149+
150+
bridge.check(status)
151+
return int(result.value)
152+
153+
def to_list(self):
154+
count = self.nvals
155+
156+
rows = (ctypes.c_uint * count)()
157+
nvals = ctypes.c_uint(count)
158+
159+
status = wrapper.loaded_dll.cuBool_Vector_ExtractValues(
160+
self.hnd, rows, ctypes.byref(nvals)
161+
)
162+
163+
bridge.check(status)
164+
165+
return rows
166+
167+
def to_string(self, width=3):
168+
nrows = self.nrows
169+
nvals = self.nvals
170+
rows = self.to_list()
171+
172+
cell_empty = "."
173+
cell_filled = "1"
174+
cell_sep = " "
175+
format_str = "{:>%s}" % width
176+
177+
result = ""
178+
179+
v = 0
180+
for i in range(nrows):
181+
line = format_str.format(i) + " |" + cell_sep
182+
if v < nvals and rows[v] == i:
183+
line += format_str.format(cell_filled) + cell_sep
184+
v += 1
185+
else:
186+
line += format_str.format(cell_empty) + cell_sep
187+
line += "| " + format_str.format(i) + "\n"
188+
result += line
189+
190+
result += "\n"
191+
return result
192+
193+
def extract_vector(self, i, nrows, out=None, time_check=False):
194+
if out is None:
195+
out = Vector.empty(nrows)
196+
197+
status = wrapper.loaded_dll.cuBool_Vector_ExtractSubVector(
198+
out.hnd, self.hnd,
199+
ctypes.c_uint(i),
200+
ctypes.c_uint(nrows),
201+
ctypes.c_uint(bridge.get_sub_vector_hints(time_check=time_check))
202+
)
203+
204+
bridge.check(status)
205+
return out
206+
207+
def vxm(self, other, out=None, time_check=False):
208+
if out is None:
209+
out = Vector.empty(other.ncols)
210+
211+
status = wrapper.loaded_dll.cuBool_VxM(
212+
out.hnd,
213+
self.hnd,
214+
other.hnd,
215+
ctypes.c_uint(bridge.get_vxm_hints(time_check=time_check))
216+
)
217+
218+
bridge.check(status)
219+
return out
220+
221+
def ewiseadd(self, other, out=None, time_check=False):
222+
if out is None:
223+
out = Vector.empty(self.nrows)
224+
225+
status = wrapper.loaded_dll.cuBool_Vector_EWiseAdd(
226+
out.hnd,
227+
self.hnd,
228+
other.hnd,
229+
ctypes.c_uint(bridge.get_ewiseadd_hints(time_check=time_check))
230+
)
231+
232+
def reduce(self, time_check=False):
233+
value = ctypes.c_uint(0)
234+
235+
status = wrapper.loaded_dll.cuBool_Vector_Reduce(
236+
ctypes.byref(value),
237+
self.hnd,
238+
ctypes.c_uint(bridge.get_reduce_hints(time_check=time_check))
239+
)
240+
241+
bridge.check(status)
242+
return int(value.value)
243+
244+
def equals(self, other) -> bool:
245+
if not self.nrows == other.nrows:
246+
return False
247+
if not self.nvals == other.nvals:
248+
return False
249+
250+
self_rows = self.to_list()
251+
other_rows = self.to_list()
252+
253+
for i in range(len(self_rows)):
254+
if self_rows[i] != other_rows[i]:
255+
return False
256+
257+
return True
258+
259+
def __str__(self):
260+
return self.to_string()
261+
262+
def __iter__(self):
263+
return self.to_list()
264+
265+
def __getitem__(self, item):
266+
if isinstance(item, slice):
267+
i = item.start
268+
nrows = item.stop
269+
270+
assert item.step is None
271+
272+
if i is None:
273+
i = 0
274+
275+
assert 0 <= i < self.nrows
276+
277+
if nrows is None:
278+
nrows = self.nrows
279+
280+
return self.extract_vector(i, nrows - i)
281+
282+
raise Exception("Invalid vector slicing")
283+
284+
def __setitem__(self, key, value):
285+
assert value is True
286+
287+
if isinstance(key, int):
288+
i = key
289+
290+
status = wrapper.loaded_dll.cuBool_Vector_SetElement(
291+
self.hnd,
292+
ctypes.c_uint(i)
293+
)
294+
295+
bridge.check(status)
296+
return
297+
298+
raise Exception("Invalid item assignment")

0 commit comments

Comments
 (0)