Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
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
43 changes: 21 additions & 22 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,36 +24,35 @@ jobs:
- name: Checks
uses: pre-commit/[email protected]

gcc:
build:
runs-on: 'ubuntu-latest'
strategy:
matrix:
include:
- cc: gcc-12
cxx: g++-12
- cc: clang
cxx: clang++
name: ${{ matrix.cc }}
env:
CXX: g++-12
CC: gcc-12
CC: ${{ matrix.cc }}
CXX: ${{ matrix.cxx }}
steps:
- uses: actions/checkout@v4
- name: CMake
run: |
sudo apt-get update
sudo apt-get install libhdf5-dev $CXX $CC
sudo apt-get install libhdf5-dev gcc-12 g++-12 clang
cmake -B build
- name: Build
run: VERBOSE=true make -C build -j `nproc`
- name: Test
run: ctest --test-dir ./build/test/bash

clang:
runs-on: 'ubuntu-latest'
env:
CXX: clang++
CC: clang
steps:
- uses: actions/checkout@v4
- name: CMake
run: |
sudo apt-get update
sudo apt-get install libhdf5-dev clang
cmake -B build
- name: Build
run: VERBOSE=true make -C build -j `nproc`
- name: Test
- name: Matrix Tests
run: ctest --test-dir ./build/test/bash
- name: Install Julia
run: curl -fsSL https://install.julialang.org | sh -s -- -y
- name: Disable Julia precompilation
run: julia -e 'using Pkg; Pkg.add(["PrecompileTools", "Preferences"]); using PrecompileTools, Preferences; set_preferences!(PrecompileTools, "precompile_workloads" => false; force=true)'
- name: Install Julia Packages
run: julia -e 'using Pkg; Pkg.add(["Finch", "HDF5"])'
- name: Tensor Tests
run: ctest --test-dir ./build/test/julia
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,6 @@
scripts
venv
build*
compile_flags.txt
._*
tensor_test_files
10 changes: 5 additions & 5 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,6 @@ target_include_directories(${PROJECT_NAME}
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
${HDF5_INCLUDE_DIRS})

if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME)
add_subdirectory(examples)
add_subdirectory(test)
endif()

# Installation rules - these are always needed when the library is built
install(TARGETS binsparse
EXPORT binsparse-targets
Expand Down Expand Up @@ -87,3 +82,8 @@ install(FILES
"${CMAKE_CURRENT_BINARY_DIR}/binsparse-config.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/binsparse-config-version.cmake"
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/binsparse)

if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME)
add_subdirectory(examples)
add_subdirectory(test)
endif()
1 change: 1 addition & 0 deletions examples/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,6 @@ add_example(bsp-ls)
add_example(benchmark_read)
add_example(benchmark_read_parallel)
add_example(benchmark_write)
add_example(tensor_test)

add_subdirectory(cpp)
1 change: 1 addition & 0 deletions examples/cpp/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,6 @@ add_example(mtx2bsp)
add_example(bsp2mtx)
add_example(check_equivalence)
add_example(bsp-ls)
add_example(tensor_test)
add_example(benchmark_read)
add_example(benchmark_write)
7 changes: 7 additions & 0 deletions examples/cpp/tensor_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/*
* SPDX-FileCopyrightText: 2024 Binsparse Developers
*
* SPDX-License-Identifier: BSD-3-Clause
*/

#include "../tensor_test.c"
2 changes: 1 addition & 1 deletion examples/simple_read.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
#include <binsparse/binsparse.h>

int main(int argc, char** argv) {
char* file_name = "test.hdf5";
char* file_name = (char*) "test.hdf5";

hid_t f = H5Fopen(file_name, H5F_ACC_RDWR, H5P_DEFAULT);

Expand Down
28 changes: 28 additions & 0 deletions examples/tensor_test.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* SPDX-FileCopyrightText: 2024 Binsparse Developers
*
* SPDX-License-Identifier: BSD-3-Clause
*/

#include <binsparse/read_tensor.h>
#include <binsparse/tensor.h>
#include <binsparse/write_tensor.h>

int main(int argc, char** argv) {
if (argc < 3) {
fprintf(stderr,
"usage: ./tensor_test [file_name.h5] [output_file_name.h5]\n");
return 1;
}
char* file_name = argv[1];
bsp_tensor_t tensor = bsp_read_tensor(argv[1], NULL);
printf("rank: %d\n", tensor.rank);
printf("dims:");
for (int i = 0; i < tensor.rank; i++) {
printf("%ld, ", tensor.dims[i]);
}
printf("\n");
bsp_write_tensor(argv[2], tensor, NULL, NULL, 9);
bsp_destroy_tensor_t(tensor);
return 0;
}
33 changes: 33 additions & 0 deletions include/binsparse/read_tensor.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* SPDX-FileCopyrightText: 2024 Binsparse Developers
*
* SPDX-License-Identifier: BSD-3-Clause
*/

#pragma once

#include <binsparse/tensor.h>

#ifndef __cplusplus
#include <stddef.h>
#else
#include <cstddef>
#endif

#ifdef __cplusplus
extern "C" {
#endif

char* key_with_index(const char* key, size_t index);

#ifdef BSP_USE_HDF5
#include <hdf5.h>

bsp_tensor_t bsp_read_tensor_from_group(hid_t f);
#endif

bsp_tensor_t bsp_read_tensor(const char* file_name, const char* group);

#ifdef __cplusplus
}
#endif
137 changes: 137 additions & 0 deletions include/binsparse/tensor.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
/*
* SPDX-FileCopyrightText: 2024 Binsparse Developers
*
* SPDX-License-Identifier: BSD-3-Clause
*/

#pragma once

#include <binsparse/array.h>
#include <binsparse/structure.h>

typedef enum {
BSP_TENSOR_SPARSE = 0,
BSP_TENSOR_DENSE = 1,
BSP_TENSOR_ELEMENT = 2,
} bsp_level_kind_t;

typedef struct {
bsp_level_kind_t kind;
// data here should be bsp_element_t*, bsp_sparse_t*, or bsp_dense_t*
void* data;
} bsp_level_t;

// corresponds to BSP_TENSOR_ELEMENT
typedef struct {
bsp_array_t values;
} bsp_element_t;

// corresponds to BSP_TENSOR_SPARSE
typedef struct {
int rank;
// pointers_to, while it will only ever point to one bsp_array_t, must be kept
// as a pointer (rather than a struct) because there are cases where it MUST
// be null.
bsp_array_t* pointers_to;
// indices is supposed to be an array of bsp_array_t's.
bsp_array_t* indices;
bsp_level_t* child;
} bsp_sparse_t;

// corresponds to BSP_TENSOR_DENSE
typedef struct {
int rank;
bsp_level_t* child;
} bsp_dense_t;

typedef struct {
int rank;
size_t* dims;
size_t* transpose;
size_t nnz;
bool is_iso;

bsp_level_t* level;
// don't think too much about this at the moment.
bsp_structure_t structure;
} bsp_tensor_t;

static inline bsp_tensor_t bsp_construct_default_tensor_t() {
bsp_tensor_t tensor;
tensor.structure = BSP_GENERAL;
tensor.is_iso = false;
tensor.nnz = tensor.rank = 0;
tensor.dims = NULL;
tensor.transpose = NULL;

tensor.level = NULL;
return tensor;
}

static void bsp_destroy_level_t(bsp_level_t* level) {
if (level == NULL)
return;
switch (level->kind) {
case BSP_TENSOR_ELEMENT: {
bsp_element_t* element = (bsp_element_t*) level->data;
bsp_destroy_array_t(element->values);
free(element);
break;
}
case BSP_TENSOR_DENSE: {
bsp_dense_t* dense = (bsp_dense_t*) level->data;
bsp_destroy_level_t(dense->child);
free(dense);
break;
}
case BSP_TENSOR_SPARSE: {
bsp_sparse_t* sparse = (bsp_sparse_t*) level->data;

if (sparse->pointers_to != NULL)
bsp_destroy_array_t(*sparse->pointers_to);
if (sparse->indices != NULL) {
for (int i = 0; i < sparse->rank; i++) {
bsp_destroy_array_t(sparse->indices[i]);
}
}
bsp_destroy_level_t(sparse->child);
free(sparse);
break;
}
default:;
}
}

static bsp_array_t bsp_get_tensor_values(bsp_tensor_t tensor) {
bsp_level_t* level = tensor.level;
while (level != NULL) {
switch (level->kind) {
case BSP_TENSOR_ELEMENT: {
bsp_element_t* element = (bsp_element_t*) level->data;
return element->values;
break;
}
case BSP_TENSOR_SPARSE: {
bsp_sparse_t* sparse = (bsp_sparse_t*) level->data;
level = sparse->child;
break;
}
case BSP_TENSOR_DENSE: {
bsp_dense_t* dense = (bsp_dense_t*) level->data;
level = dense->child;
break;
}
default:;
}
}
// this should never happen!
assert(false);
}

static inline void bsp_destroy_tensor_t(bsp_tensor_t tensor) {
bsp_destroy_level_t(tensor.level);
if (tensor.dims != NULL)
free(tensor.dims);
if (tensor.transpose != NULL)
free(tensor.transpose);
}
30 changes: 30 additions & 0 deletions include/binsparse/write_tensor.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* SPDX-FileCopyrightText: 2024 Binsparse Developers
*
* SPDX-License-Identifier: BSD-3-Clause
*/

#pragma once

#ifdef __cplusplus
extern "C" {
#endif

// TODO: make cJSON optional.

#include <binsparse/tensor.h>
#include <cJSON/cJSON.h>

#ifdef BSP_USE_HDF5
#include <hdf5.h>

int bsp_write_tensor_to_group(hid_t f, bsp_tensor_t tensor, cJSON* user_json,
int compression_level);
#endif

int bsp_write_tensor(const char* fname, bsp_tensor_t tensor, const char* group,
cJSON* user_json, int compression_level);

#ifdef __cplusplus
}
#endif
2 changes: 2 additions & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,7 @@

target_sources(binsparse PRIVATE
read_matrix.c
read_tensor.c
write_matrix.c
write_tensor.c
)
Loading