Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 41 additions & 17 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,47 +1,71 @@
ARG BASE_CONTAINER=python:3.10-slim-buster
FROM ${BASE_CONTAINER} as suitesparse
ARG BASE_CONTAINER=python:3.12-slim-bookworm
FROM ${BASE_CONTAINER} AS suitesparse
ENV DEBIAN_FRONTEND=noninteractive

RUN apt-get update && apt-get install -yq build-essential cmake git

ARG SUITESPARSE
ARG COMPACT
ARG COMPACT=0

WORKDIR /build
RUN git clone https://github.com/eliben/pycparser.git --depth 1

WORKDIR /build/GraphBLAS/build
# Use `-DJITINIT=2` so that the JIT functionality is available, but disabled by default.
# Level 2, "run", means that pre-JIT kernels may be used, which does not require a compiler at runtime.
# Disable JIT entirely to avoid segfaulting in tests (matches CI in suitesparse.sh).
RUN git clone https://github.com/DrTimothyAldenDavis/GraphBLAS.git --depth 1 --branch ${SUITESPARSE} \
&& cd GraphBLAS/build \
&& cmake .. -DCMAKE_INSTALL_PREFIX=/usr -DGBCOMPACT=${COMPACT} \
&& cmake .. \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX=/usr \
-DCOMPACT=${COMPACT} \
-DJITINIT=2 \
-DGRAPHBLAS_USE_JIT=OFF \
&& make -j$(nproc) \
&& make install

FROM ${BASE_CONTAINER} as psg
ARG SUITESPARSE
FROM ${BASE_CONTAINER} AS psg
ARG VERSION
ENV PYTHONUNBUFFERED 1
ENV PYTHONUNBUFFERED=1

COPY --from=suitesparse /usr/include/GraphBLAS.h /usr/local/include/
COPY --from=suitesparse /usr/lib/x86_64-linux-gnu/libgraphblas* /usr/lib/x86_64-linux-gnu/
COPY --from=suitesparse /build/pycparser/utils/fake_libc_include/* /usr/local/lib/python3.10/site-packages/pycparser/utils/fake_libc_include/
COPY --from=suitesparse /usr/include/suitesparse/GraphBLAS.h /usr/local/include/suitesparse/GraphBLAS.h
# Copy only the real versioned library; recreate symlinks (Docker COPY collapses cross-stage symlinks).
COPY --from=suitesparse /usr/lib/x86_64-linux-gnu/libgraphblas.so.*.*.* /usr/lib/x86_64-linux-gnu/
RUN cd /usr/lib/x86_64-linux-gnu \
&& REAL=$(ls libgraphblas.so.*.*.*) \
&& SOMAJOR=libgraphblas.so.$(echo "$REAL" | sed -E 's/libgraphblas\.so\.([0-9]+).*/\1/') \
&& ln -sf "$REAL" "$SOMAJOR" \
&& ln -sf "$SOMAJOR" libgraphblas.so \
&& ldconfig

RUN apt-get update && apt-get install -yq build-essential git
RUN pip3 install numpy cffi pytest cython
RUN pip3 install --break-system-packages numpy cffi pytest cython pycparser setuptools wheel setuptools-git-versioning

COPY --from=suitesparse /build/pycparser/utils/fake_libc_include/* /usr/local/lib/python3.12/site-packages/pycparser/utils/fake_libc_include/

RUN mkdir -p /psg
ADD . /psg

WORKDIR /psg
RUN git tag ${VERSION} && \
# `git tag || true` so the build is idempotent when ${VERSION} already matches an existing tag in the source tree.
RUN (git tag ${VERSION} || true) && \
python3 suitesparse_graphblas/create_headers.py && \
python3 setup.py install && \
pip3 install --break-system-packages --no-build-isolation --no-deps . && \
ldconfig

#RUN pytest --pyargs suitesparse_graphblas.tests
RUN apt-get -y --purge remove git python3-pip && apt-get clean

FROM ${BASE_CONTAINER}
COPY --from=suitesparse /usr/lib/x86_64-linux-gnu/libgraphblas* /usr/lib/x86_64-linux-gnu/
COPY --from=suitesparse /usr/lib/x86_64-linux-gnu/libgomp* /usr/lib/x86_64-linux-gnu/
COPY --from=psg /usr/local/lib/python3.10/site-packages /usr/local/lib/python3.10/site-packages
COPY --from=suitesparse /usr/lib/x86_64-linux-gnu/libgraphblas.so.*.*.* /usr/lib/x86_64-linux-gnu/
COPY --from=suitesparse /usr/lib/x86_64-linux-gnu/libgomp.so.*.*.* /usr/lib/x86_64-linux-gnu/
COPY --from=psg /usr/local/lib/python3.12/site-packages /usr/local/lib/python3.12/site-packages
RUN cd /usr/lib/x86_64-linux-gnu \
&& GBREAL=$(ls libgraphblas.so.*.*.*) \
&& GBSOMAJOR=libgraphblas.so.$(echo "$GBREAL" | sed -E 's/libgraphblas\.so\.([0-9]+).*/\1/') \
&& ln -sf "$GBREAL" "$GBSOMAJOR" \
&& ln -sf "$GBSOMAJOR" libgraphblas.so \
&& GMREAL=$(ls libgomp.so.*.*.*) \
&& GMSOMAJOR=libgomp.so.$(echo "$GMREAL" | sed -E 's/libgomp\.so\.([0-9]+).*/\1/') \
&& ln -sf "$GMREAL" "$GMSOMAJOR" \
&& ldconfig
6 changes: 3 additions & 3 deletions suitesparse_graphblas/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ class burble:

>>> from suitesparse_graphblas import burble, lib, matrix
>>>
>>> A = matrix.new(lib.GrB_BOOL, 3, 3)
>>> A = matrix.matrix_new(lib.GrB_BOOL, 3, 3)
>>> burble.is_enabled
False
>>> burble.enable()
Expand All @@ -239,15 +239,15 @@ class burble:
Example with explicit enable and disable:

>>> burble.enable()
>>> n = matrix.nvals(A)
>>> n = matrix.matrix_nvals(A)
[ GrB_Matrix_nvals
1.91e-06 sec ]
>>> burble.disable()

Example as a context manager:

>>> with burble():
>>> n = matrix.nvals(A)
>>> n = matrix.matrix_nvals(A)
[ GrB_Matrix_nvals
1.91e-06 sec ]

Expand Down
26 changes: 13 additions & 13 deletions suitesparse_graphblas/io/binary.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,19 +123,19 @@ def binwrite(A, filename, comments=None, opener=Path.open):
typecode = ffinew("int32_t*")
matrix_type = ffi.new("GrB_Type*")

nrows[0] = matrix.nrows(A)
ncols[0] = matrix.ncols(A)
nvals[0] = matrix.nvals(A)
matrix_type[0] = matrix.type(A)
nrows[0] = matrix.matrix_nrows(A)
ncols[0] = matrix.matrix_ncols(A)
nvals[0] = matrix.matrix_nvals(A)
matrix_type[0] = matrix.matrix_type(A)

check_status(A, lib.GxB_Type_size(typesize, matrix_type[0]))
typecode[0] = _ss_typecodes[matrix_type[0]]

format[0] = matrix.format(A)
hyper_switch[0] = matrix.hyper_switch(A)
bitmap_switch[0] = matrix.bitmap_switch(A)
sparsity_status[0] = matrix.sparsity_status(A)
sparsity_control[0] = matrix.sparsity_control(A)
format[0] = matrix.matrix_format(A)
hyper_switch[0] = matrix.matrix_hyper_switch(A)
bitmap_switch[0] = matrix.matrix_bitmap_switch(A)
sparsity_status[0] = matrix.matrix_sparsity_status(A)
sparsity_control[0] = matrix.matrix_sparsity_control(A)

by_row = format[0] == lib.GxB_BY_ROW
by_col = format[0] == lib.GxB_BY_COL
Expand Down Expand Up @@ -446,7 +446,7 @@ def binread(filename, opener=Path.open):

Ax[0] = readinto_new_buffer(f, "uint8_t*", typesize[0] if is_iso[0] else Ax_size[0])

A = matrix.new(atype, nrows[0], ncols[0])
A = matrix.matrix_new(atype, nrows[0], ncols[0])

if by_col and is_hyper:
check_status(
Expand Down Expand Up @@ -546,7 +546,7 @@ def binread(filename, opener=Path.open):
else:
raise TypeError("Unknown format {format[0]}")

matrix.set_sparsity_control(A, sparsity_control[0])
matrix.set_hyper_switch(A, hyper_switch[0])
matrix.set_bitmap_switch(A, bitmap_switch[0])
matrix.matrix_set_sparsity_control(A, sparsity_control[0])
matrix.matrix_set_hyper_switch(A, hyper_switch[0])
matrix.matrix_set_bitmap_switch(A, bitmap_switch[0])
return A
8 changes: 4 additions & 4 deletions suitesparse_graphblas/io/serialize.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ def deserialize_matrix(data, *, free=True, nthreads=None):
"""Deserialize a Matrix from bytes.

The `free` argument is called when the object is garbage
collected, the default is `matrix.free()`. If `free` is None then
collected, the default is `matrix.matrix_free()`. If `free` is None then
there is no automatic garbage collection and it is up to the user
to free the matrix.
"""
Expand All @@ -108,15 +108,15 @@ def deserialize_matrix(data, *, free=True, nthreads=None):
if free:
if callable(free):
return ffi.gc(A, free)
return ffi.gc(A, matrix.free)
return ffi.gc(A, matrix.matrix_free)
return A


def deserialize_vector(data, *, free=True, nthreads=None):
"""Deserialize a Vector from bytes.

The `free` argument is called when the object is garbage
collected, the default is `vector.free()`. If `free` is None then
collected, the default is `vector.vector_free()`. If `free` is None then
there is no automatic garbage collection and it is up to the user
to free the vector.
"""
Expand All @@ -136,7 +136,7 @@ def deserialize_vector(data, *, free=True, nthreads=None):
if free:
if callable(free):
return ffi.gc(v, free)
return ffi.gc(v, vector.free)
return ffi.gc(v, vector.vector_free)
return v


Expand Down
Loading
Loading