Skip to content

Commit a8c3ee3

Browse files
implement tensors in binsparse (#21)
* dev environment * read tensor implemented * segfault debugging * tensor writer implemented TODO: you need to apparently set the format key. * tensor reader/writer successfully bootstrapped * testing framework for tensor read/write implemented * tests fixed * parse transposes too * json reading/writing adjusted for binsparse compliance * change to shared library * so it turns out that we need int32 indices * change everything to int32 * make ready for pr * Fix formatting * add cmakelists back in * Add Tensor tests to CI --------- Co-authored-by: Benjamin Brock <[email protected]>
1 parent 00eb7cc commit a8c3ee3

File tree

17 files changed

+767
-28
lines changed

17 files changed

+767
-28
lines changed

.github/workflows/ci.yml

Lines changed: 21 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -24,36 +24,35 @@ jobs:
2424
- name: Checks
2525
uses: pre-commit/[email protected]
2626

27-
gcc:
27+
build:
2828
runs-on: 'ubuntu-latest'
29+
strategy:
30+
matrix:
31+
include:
32+
- cc: gcc-12
33+
cxx: g++-12
34+
- cc: clang
35+
cxx: clang++
36+
name: ${{ matrix.cc }}
2937
env:
30-
CXX: g++-12
31-
CC: gcc-12
38+
CC: ${{ matrix.cc }}
39+
CXX: ${{ matrix.cxx }}
3240
steps:
3341
- uses: actions/checkout@v4
3442
- name: CMake
3543
run: |
3644
sudo apt-get update
37-
sudo apt-get install libhdf5-dev $CXX $CC
45+
sudo apt-get install libhdf5-dev gcc-12 g++-12 clang
3846
cmake -B build
3947
- name: Build
4048
run: VERBOSE=true make -C build -j `nproc`
41-
- name: Test
42-
run: ctest --test-dir ./build/test/bash
43-
44-
clang:
45-
runs-on: 'ubuntu-latest'
46-
env:
47-
CXX: clang++
48-
CC: clang
49-
steps:
50-
- uses: actions/checkout@v4
51-
- name: CMake
52-
run: |
53-
sudo apt-get update
54-
sudo apt-get install libhdf5-dev clang
55-
cmake -B build
56-
- name: Build
57-
run: VERBOSE=true make -C build -j `nproc`
58-
- name: Test
49+
- name: Matrix Tests
5950
run: ctest --test-dir ./build/test/bash
51+
- name: Install Julia
52+
run: curl -fsSL https://install.julialang.org | sh -s -- -y
53+
- name: Disable Julia precompilation
54+
run: julia -e 'using Pkg; Pkg.add(["PrecompileTools", "Preferences"]); using PrecompileTools, Preferences; set_preferences!(PrecompileTools, "precompile_workloads" => false; force=true)'
55+
- name: Install Julia Packages
56+
run: julia -e 'using Pkg; Pkg.add(["Finch", "HDF5"])'
57+
- name: Tensor Tests
58+
run: ctest --test-dir ./build/test/julia

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,6 @@
55
scripts
66
venv
77
build*
8+
compile_flags.txt
89
._*
10+
tensor_test_files

CMakeLists.txt

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,6 @@ target_include_directories(${PROJECT_NAME}
4646
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
4747
${HDF5_INCLUDE_DIRS})
4848

49-
if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME)
50-
add_subdirectory(examples)
51-
add_subdirectory(test)
52-
endif()
53-
5449
# Installation rules - these are always needed when the library is built
5550
install(TARGETS binsparse
5651
EXPORT binsparse-targets
@@ -87,3 +82,8 @@ install(FILES
8782
"${CMAKE_CURRENT_BINARY_DIR}/binsparse-config.cmake"
8883
"${CMAKE_CURRENT_BINARY_DIR}/binsparse-config-version.cmake"
8984
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/binsparse)
85+
86+
if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME)
87+
add_subdirectory(examples)
88+
add_subdirectory(test)
89+
endif()

examples/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,6 @@ add_example(bsp-ls)
1919
add_example(benchmark_read)
2020
add_example(benchmark_read_parallel)
2121
add_example(benchmark_write)
22+
add_example(tensor_test)
2223

2324
add_subdirectory(cpp)

examples/cpp/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,6 @@ add_example(mtx2bsp)
1515
add_example(bsp2mtx)
1616
add_example(check_equivalence)
1717
add_example(bsp-ls)
18+
add_example(tensor_test)
1819
add_example(benchmark_read)
1920
add_example(benchmark_write)

examples/cpp/tensor_test.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
/*
2+
* SPDX-FileCopyrightText: 2024 Binsparse Developers
3+
*
4+
* SPDX-License-Identifier: BSD-3-Clause
5+
*/
6+
7+
#include "../tensor_test.c"

examples/simple_read.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
#include <binsparse/binsparse.h>
88

99
int main(int argc, char** argv) {
10-
char* file_name = "test.hdf5";
10+
char* file_name = (char*) "test.hdf5";
1111

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

examples/tensor_test.c

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/*
2+
* SPDX-FileCopyrightText: 2024 Binsparse Developers
3+
*
4+
* SPDX-License-Identifier: BSD-3-Clause
5+
*/
6+
7+
#include <binsparse/read_tensor.h>
8+
#include <binsparse/tensor.h>
9+
#include <binsparse/write_tensor.h>
10+
11+
int main(int argc, char** argv) {
12+
if (argc < 3) {
13+
fprintf(stderr,
14+
"usage: ./tensor_test [file_name.h5] [output_file_name.h5]\n");
15+
return 1;
16+
}
17+
char* file_name = argv[1];
18+
bsp_tensor_t tensor = bsp_read_tensor(argv[1], NULL);
19+
printf("rank: %d\n", tensor.rank);
20+
printf("dims:");
21+
for (int i = 0; i < tensor.rank; i++) {
22+
printf("%ld, ", tensor.dims[i]);
23+
}
24+
printf("\n");
25+
bsp_write_tensor(argv[2], tensor, NULL, NULL, 9);
26+
bsp_destroy_tensor_t(tensor);
27+
return 0;
28+
}

include/binsparse/read_tensor.h

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*
2+
* SPDX-FileCopyrightText: 2024 Binsparse Developers
3+
*
4+
* SPDX-License-Identifier: BSD-3-Clause
5+
*/
6+
7+
#pragma once
8+
9+
#include <binsparse/tensor.h>
10+
11+
#ifndef __cplusplus
12+
#include <stddef.h>
13+
#else
14+
#include <cstddef>
15+
#endif
16+
17+
#ifdef __cplusplus
18+
extern "C" {
19+
#endif
20+
21+
char* key_with_index(const char* key, size_t index);
22+
23+
#ifdef BSP_USE_HDF5
24+
#include <hdf5.h>
25+
26+
bsp_tensor_t bsp_read_tensor_from_group(hid_t f);
27+
#endif
28+
29+
bsp_tensor_t bsp_read_tensor(const char* file_name, const char* group);
30+
31+
#ifdef __cplusplus
32+
}
33+
#endif

include/binsparse/tensor.h

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
/*
2+
* SPDX-FileCopyrightText: 2024 Binsparse Developers
3+
*
4+
* SPDX-License-Identifier: BSD-3-Clause
5+
*/
6+
7+
#pragma once
8+
9+
#include <binsparse/array.h>
10+
#include <binsparse/structure.h>
11+
12+
typedef enum {
13+
BSP_TENSOR_SPARSE = 0,
14+
BSP_TENSOR_DENSE = 1,
15+
BSP_TENSOR_ELEMENT = 2,
16+
} bsp_level_kind_t;
17+
18+
typedef struct {
19+
bsp_level_kind_t kind;
20+
// data here should be bsp_element_t*, bsp_sparse_t*, or bsp_dense_t*
21+
void* data;
22+
} bsp_level_t;
23+
24+
// corresponds to BSP_TENSOR_ELEMENT
25+
typedef struct {
26+
bsp_array_t values;
27+
} bsp_element_t;
28+
29+
// corresponds to BSP_TENSOR_SPARSE
30+
typedef struct {
31+
int rank;
32+
// pointers_to, while it will only ever point to one bsp_array_t, must be kept
33+
// as a pointer (rather than a struct) because there are cases where it MUST
34+
// be null.
35+
bsp_array_t* pointers_to;
36+
// indices is supposed to be an array of bsp_array_t's.
37+
bsp_array_t* indices;
38+
bsp_level_t* child;
39+
} bsp_sparse_t;
40+
41+
// corresponds to BSP_TENSOR_DENSE
42+
typedef struct {
43+
int rank;
44+
bsp_level_t* child;
45+
} bsp_dense_t;
46+
47+
typedef struct {
48+
int rank;
49+
size_t* dims;
50+
size_t* transpose;
51+
size_t nnz;
52+
bool is_iso;
53+
54+
bsp_level_t* level;
55+
// don't think too much about this at the moment.
56+
bsp_structure_t structure;
57+
} bsp_tensor_t;
58+
59+
static inline bsp_tensor_t bsp_construct_default_tensor_t() {
60+
bsp_tensor_t tensor;
61+
tensor.structure = BSP_GENERAL;
62+
tensor.is_iso = false;
63+
tensor.nnz = tensor.rank = 0;
64+
tensor.dims = NULL;
65+
tensor.transpose = NULL;
66+
67+
tensor.level = NULL;
68+
return tensor;
69+
}
70+
71+
static void bsp_destroy_level_t(bsp_level_t* level) {
72+
if (level == NULL)
73+
return;
74+
switch (level->kind) {
75+
case BSP_TENSOR_ELEMENT: {
76+
bsp_element_t* element = (bsp_element_t*) level->data;
77+
bsp_destroy_array_t(element->values);
78+
free(element);
79+
break;
80+
}
81+
case BSP_TENSOR_DENSE: {
82+
bsp_dense_t* dense = (bsp_dense_t*) level->data;
83+
bsp_destroy_level_t(dense->child);
84+
free(dense);
85+
break;
86+
}
87+
case BSP_TENSOR_SPARSE: {
88+
bsp_sparse_t* sparse = (bsp_sparse_t*) level->data;
89+
90+
if (sparse->pointers_to != NULL)
91+
bsp_destroy_array_t(*sparse->pointers_to);
92+
if (sparse->indices != NULL) {
93+
for (int i = 0; i < sparse->rank; i++) {
94+
bsp_destroy_array_t(sparse->indices[i]);
95+
}
96+
}
97+
bsp_destroy_level_t(sparse->child);
98+
free(sparse);
99+
break;
100+
}
101+
default:;
102+
}
103+
}
104+
105+
static bsp_array_t bsp_get_tensor_values(bsp_tensor_t tensor) {
106+
bsp_level_t* level = tensor.level;
107+
while (level != NULL) {
108+
switch (level->kind) {
109+
case BSP_TENSOR_ELEMENT: {
110+
bsp_element_t* element = (bsp_element_t*) level->data;
111+
return element->values;
112+
break;
113+
}
114+
case BSP_TENSOR_SPARSE: {
115+
bsp_sparse_t* sparse = (bsp_sparse_t*) level->data;
116+
level = sparse->child;
117+
break;
118+
}
119+
case BSP_TENSOR_DENSE: {
120+
bsp_dense_t* dense = (bsp_dense_t*) level->data;
121+
level = dense->child;
122+
break;
123+
}
124+
default:;
125+
}
126+
}
127+
// this should never happen!
128+
assert(false);
129+
}
130+
131+
static inline void bsp_destroy_tensor_t(bsp_tensor_t tensor) {
132+
bsp_destroy_level_t(tensor.level);
133+
if (tensor.dims != NULL)
134+
free(tensor.dims);
135+
if (tensor.transpose != NULL)
136+
free(tensor.transpose);
137+
}

0 commit comments

Comments
 (0)