Skip to content

Commit a0898df

Browse files
committed
Update Matlab bindings, fine-tune .gitignore.
1 parent 70426d4 commit a0898df

13 files changed

+757
-344
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44

55
scripts
66
venv
7-
build*
7+
build/
8+
build-*/
89
compile_flags.txt
910
._*
1011
tensor_test_files

CMakeLists.txt

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,12 @@ find_package(HDF5 REQUIRED COMPONENTS C)
2828
target_link_libraries(binsparse PUBLIC ${HDF5_C_LIBRARIES})
2929

3030
include(FetchContent)
31+
32+
# Force cJSON to build as static library for MEX compatibility
33+
set(BUILD_SHARED_LIBS_BACKUP ${BUILD_SHARED_LIBS})
34+
set(BUILD_SHARED_LIBS OFF CACHE INTERNAL "Build cJSON as static library")
35+
set(ENABLE_CJSON_TEST OFF CACHE INTERNAL "Disable cJSON tests")
36+
3137
FetchContent_Declare(
3238
cJSON
3339
# GIT_REPOSITORY https://github.com/DaveGamble/cJSON.git
@@ -36,8 +42,11 @@ FetchContent_Declare(
3642
)
3743
FetchContent_MakeAvailable(cJSON)
3844

45+
# Restore original BUILD_SHARED_LIBS setting
46+
set(BUILD_SHARED_LIBS ${BUILD_SHARED_LIBS_BACKUP})
47+
3948
configure_file(${cJSON_SOURCE_DIR}/cJSON.h ${CMAKE_BINARY_DIR}/include/cJSON/cJSON.h)
40-
target_link_libraries(${PROJECT_NAME} PUBLIC cjson)
49+
target_link_libraries(${PROJECT_NAME} PRIVATE cjson)
4150

4251
# Set up include directories properly for both build and install
4352
target_include_directories(${PROJECT_NAME}

bindings/matlab/binsparse_read.c

Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
/*
2+
* SPDX-FileCopyrightText: 2024 Binsparse Developers
3+
*
4+
* SPDX-License-Identifier: BSD-3-Clause
5+
*/
6+
7+
/**
8+
* binsparse_read.c - Read Binsparse matrices into MATLAB
9+
*
10+
* This MEX function reads Binsparse format matrices and returns them
11+
* as MATLAB structs compatible with bsp_matrix_create.
12+
*
13+
* Usage in MATLAB/Octave:
14+
* matrix = binsparse_read(filename)
15+
* matrix = binsparse_read(filename, group)
16+
*/
17+
18+
#include "mex.h"
19+
#include <binsparse/binsparse.h>
20+
#include <string.h>
21+
22+
/**
23+
* Convert bsp_array_t to MATLAB array
24+
*/
25+
mxArray* bsp_array_to_matlab(const bsp_array_t* array) {
26+
if (array->data == NULL || array->size == 0) {
27+
// Return empty array
28+
return mxCreateDoubleMatrix(0, 1, mxREAL);
29+
}
30+
31+
mxArray* mx_array = NULL;
32+
33+
switch (array->type) {
34+
case BSP_FLOAT64:
35+
mx_array = mxCreateDoubleMatrix(array->size, 1, mxREAL);
36+
memcpy(mxGetPr(mx_array), array->data, array->size * sizeof(double));
37+
break;
38+
39+
case BSP_FLOAT32: {
40+
mx_array = mxCreateDoubleMatrix(array->size, 1, mxREAL);
41+
double* out_data = mxGetPr(mx_array);
42+
float* in_data = (float*) array->data;
43+
for (size_t i = 0; i < array->size; i++) {
44+
out_data[i] = (double) in_data[i];
45+
}
46+
break;
47+
}
48+
49+
case BSP_UINT64: {
50+
mx_array = mxCreateNumericMatrix(array->size, 1, mxUINT64_CLASS, mxREAL);
51+
memcpy(mxGetData(mx_array), array->data, array->size * sizeof(uint64_t));
52+
break;
53+
}
54+
55+
case BSP_UINT32: {
56+
mx_array = mxCreateNumericMatrix(array->size, 1, mxUINT64_CLASS, mxREAL);
57+
uint64_t* out_data = (uint64_t*) mxGetData(mx_array);
58+
uint32_t* in_data = (uint32_t*) array->data;
59+
for (size_t i = 0; i < array->size; i++) {
60+
out_data[i] = (uint64_t) in_data[i];
61+
}
62+
break;
63+
}
64+
65+
case BSP_UINT16: {
66+
mx_array = mxCreateNumericMatrix(array->size, 1, mxUINT64_CLASS, mxREAL);
67+
uint64_t* out_data = (uint64_t*) mxGetData(mx_array);
68+
uint16_t* in_data = (uint16_t*) array->data;
69+
for (size_t i = 0; i < array->size; i++) {
70+
out_data[i] = (uint64_t) in_data[i];
71+
}
72+
break;
73+
}
74+
75+
case BSP_UINT8: {
76+
mx_array = mxCreateNumericMatrix(array->size, 1, mxUINT64_CLASS, mxREAL);
77+
uint64_t* out_data = (uint64_t*) mxGetData(mx_array);
78+
uint8_t* in_data = (uint8_t*) array->data;
79+
for (size_t i = 0; i < array->size; i++) {
80+
out_data[i] = (uint64_t) in_data[i];
81+
}
82+
break;
83+
}
84+
85+
default:
86+
// Fallback: create empty array
87+
mx_array = mxCreateDoubleMatrix(0, 1, mxREAL);
88+
mexWarnMsgIdAndTxt("BinSparse:UnsupportedType",
89+
"Unsupported array type %d, returning empty array",
90+
(int) array->type);
91+
break;
92+
}
93+
94+
return mx_array;
95+
}
96+
97+
/**
98+
* Convert bsp_matrix_t to MATLAB struct
99+
*/
100+
mxArray* bsp_matrix_to_matlab_struct(const bsp_matrix_t* matrix) {
101+
const char* field_names[] = {
102+
"values", "indices_0", "indices_1", "pointers_to_1", "nrows",
103+
"ncols", "nnz", "is_iso", "format", "structure"};
104+
105+
mxArray* mx_struct = mxCreateStructMatrix(1, 1, 10, field_names);
106+
107+
// Convert arrays
108+
mxSetField(mx_struct, 0, "values", bsp_array_to_matlab(&matrix->values));
109+
mxSetField(mx_struct, 0, "indices_0",
110+
bsp_array_to_matlab(&matrix->indices_0));
111+
mxSetField(mx_struct, 0, "indices_1",
112+
bsp_array_to_matlab(&matrix->indices_1));
113+
mxSetField(mx_struct, 0, "pointers_to_1",
114+
bsp_array_to_matlab(&matrix->pointers_to_1));
115+
116+
// Convert scalar fields
117+
mxSetField(mx_struct, 0, "nrows",
118+
mxCreateDoubleScalar((double) matrix->nrows));
119+
mxSetField(mx_struct, 0, "ncols",
120+
mxCreateDoubleScalar((double) matrix->ncols));
121+
mxSetField(mx_struct, 0, "nnz", mxCreateDoubleScalar((double) matrix->nnz));
122+
mxSetField(mx_struct, 0, "is_iso", mxCreateLogicalScalar(matrix->is_iso));
123+
124+
// Convert format string
125+
mxSetField(mx_struct, 0, "format",
126+
mxCreateString(bsp_get_matrix_format_string(matrix->format)));
127+
128+
// Convert structure string
129+
mxSetField(mx_struct, 0, "structure",
130+
mxCreateString(bsp_get_structure_string(matrix->structure)));
131+
132+
return mx_struct;
133+
}
134+
135+
/**
136+
* Main MEX function entry point
137+
*/
138+
void mexFunction(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) {
139+
char* filename = NULL;
140+
char* group = NULL;
141+
bsp_matrix_t matrix;
142+
bsp_error_t error;
143+
144+
// Check input arguments
145+
if (nrhs < 1 || nrhs > 2) {
146+
mexErrMsgIdAndTxt("BinSparse:InvalidArgs",
147+
"Usage: matrix = binsparse_read(filename [, group])");
148+
}
149+
150+
if (nlhs > 1) {
151+
mexErrMsgIdAndTxt("BinSparse:TooManyOutputs", "Too many output arguments");
152+
}
153+
154+
// Get filename
155+
if (!mxIsChar(prhs[0])) {
156+
mexErrMsgIdAndTxt("BinSparse:InvalidFilename", "Filename must be a string");
157+
}
158+
159+
filename = mxArrayToString(prhs[0]);
160+
if (!filename) {
161+
mexErrMsgIdAndTxt("BinSparse:MemoryError",
162+
"Failed to convert filename string");
163+
}
164+
165+
// Get optional group name
166+
if (nrhs == 2) {
167+
if (!mxIsChar(prhs[1])) {
168+
mxFree(filename);
169+
mexErrMsgIdAndTxt("BinSparse:InvalidGroup",
170+
"Group name must be a string");
171+
}
172+
173+
group = mxArrayToString(prhs[1]);
174+
if (!group) {
175+
mxFree(filename);
176+
mexErrMsgIdAndTxt("BinSparse:MemoryError",
177+
"Failed to convert group string");
178+
}
179+
}
180+
181+
// Read the matrix using Binsparse
182+
error = bsp_read_matrix(&matrix, filename, group);
183+
184+
if (error != BSP_SUCCESS) {
185+
// Clean up
186+
if (filename)
187+
mxFree(filename);
188+
if (group)
189+
mxFree(group);
190+
191+
mexErrMsgIdAndTxt("BinSparse:ReadError", "Failed to read matrix: %s",
192+
bsp_get_error_string(error));
193+
}
194+
195+
// Convert to MATLAB struct
196+
plhs[0] = bsp_matrix_to_matlab_struct(&matrix);
197+
198+
// Clean up
199+
bsp_destroy_matrix_t(&matrix);
200+
if (filename)
201+
mxFree(filename);
202+
if (group)
203+
mxFree(group);
204+
}

bindings/matlab/bsp_hello.c

Lines changed: 0 additions & 103 deletions
This file was deleted.

0 commit comments

Comments
 (0)