diff --git a/graphblas-java/src/main/c/unsafe.c b/graphblas-java/src/main/c/unsafe.c index c08bc05..c14bf2a 100644 --- a/graphblas-java/src/main/c/unsafe.c +++ b/graphblas-java/src/main/c/unsafe.c @@ -26,6 +26,41 @@ JNIEXPORT jint JNICALL JNI_OnLoad (JavaVM *jvm, void *reserved) { return check_grb_error(GrB_init(GrB_NONBLOCKING) ); } + JNIEXPORT jlong JNICALL Java_com_github_fabianmurariu_unsafe_GRBCORE_initBlocking + (JNIEnv * env, jclass cls) { + return check_grb_error(GrB_init(GrB_BLOCKING) ); + } + + JNIEXPORT jint JNICALL Java_com_github_fabianmurariu_unsafe_GRBCORE_getGlobalInt + (JNIEnv * env, jclass cls, jint field) { + GxB_Option_Field global_field = (GxB_Option_Field) field; + int value; + check_grb_error(GxB_Global_Option_get(global_field, &value)); + + return (jint) value; + } + + JNIEXPORT jdouble JNICALL Java_com_github_fabianmurariu_unsafe_GRBCORE_getGlobalDouble + (JNIEnv * env, jclass cls, jint field) { + GxB_Option_Field global_field = (GxB_Option_Field) field; + double value; + check_grb_error(GxB_Global_Option_get(global_field, &value)); + + return (jdouble) value; + } + + JNIEXPORT jlong JNICALL Java_com_github_fabianmurariu_unsafe_GRBCORE_setGlobalInt + (JNIEnv * env, jclass cls, jint field, jint value) { + GxB_Option_Field global_field = (GxB_Option_Field) field; + return check_grb_error(GxB_Global_Option_set(global_field, value)); + } + + JNIEXPORT jlong JNICALL Java_com_github_fabianmurariu_unsafe_GRBCORE_setGlobalDouble + (JNIEnv * env, jclass cls, jint field, jdouble value) { + GxB_Option_Field global_field = (GxB_Option_Field) field; + return check_grb_error(GxB_Global_Option_set(global_field, value)); + } + JNIEXPORT jlong JNICALL Java_com_github_fabianmurariu_unsafe_GRBCORE_grbWait (JNIEnv * env, jclass cls) { return check_grb_error(GrB_wait()); diff --git a/graphblas-java/src/main/c/unsafe_gen.c b/graphblas-java/src/main/c/unsafe_gen.c index 296f160..0910209 100644 --- a/graphblas-java/src/main/c/unsafe_gen.c +++ b/graphblas-java/src/main/c/unsafe_gen.c @@ -1277,7 +1277,6 @@ long check_grb_error(GrB_Info info); // NON OPTIONAL STUFF GrB_Vector w = (GrB_Vector) (*env)->GetDirectBufferAddress(env, vec); - // !DIFFERENCE: ni == vector size -> GrB_ALL .. as no way to get pointer to GrB_ALL object in java GrB_Index* I = NULL; GrB_Index grb_ni = (GrB_Index) ni; jlong * java_is = (*env)->GetLongArrayElements(env, is, NULL); @@ -1318,7 +1317,6 @@ long check_grb_error(GrB_Info info); // NON OPTIONAL STUFF GrB_Vector w = (GrB_Vector) (*env)->GetDirectBufferAddress(env, vec); - // !DIFFERENCE: ni == vector size -> GrB_ALL .. as no way to get pointer to GrB_ALL object in java GrB_Index* I = NULL; GrB_Index grb_ni = (GrB_Index) ni; jlong * java_is = (*env)->GetLongArrayElements(env, is, NULL); @@ -1359,7 +1357,6 @@ long check_grb_error(GrB_Info info); // NON OPTIONAL STUFF GrB_Vector w = (GrB_Vector) (*env)->GetDirectBufferAddress(env, vec); - // !DIFFERENCE: ni == vector size -> GrB_ALL .. as no way to get pointer to GrB_ALL object in java GrB_Index* I = NULL; GrB_Index grb_ni = (GrB_Index) ni; jlong * java_is = (*env)->GetLongArrayElements(env, is, NULL); @@ -1400,7 +1397,6 @@ long check_grb_error(GrB_Info info); // NON OPTIONAL STUFF GrB_Vector w = (GrB_Vector) (*env)->GetDirectBufferAddress(env, vec); - // !DIFFERENCE: ni == vector size -> GrB_ALL .. as no way to get pointer to GrB_ALL object in java GrB_Index* I = NULL; GrB_Index grb_ni = (GrB_Index) ni; jlong * java_is = (*env)->GetLongArrayElements(env, is, NULL); @@ -1441,7 +1437,6 @@ long check_grb_error(GrB_Info info); // NON OPTIONAL STUFF GrB_Vector w = (GrB_Vector) (*env)->GetDirectBufferAddress(env, vec); - // !DIFFERENCE: ni == vector size -> GrB_ALL .. as no way to get pointer to GrB_ALL object in java GrB_Index* I = NULL; GrB_Index grb_ni = (GrB_Index) ni; jlong * java_is = (*env)->GetLongArrayElements(env, is, NULL); @@ -1482,7 +1477,6 @@ long check_grb_error(GrB_Info info); // NON OPTIONAL STUFF GrB_Vector w = (GrB_Vector) (*env)->GetDirectBufferAddress(env, vec); - // !DIFFERENCE: ni == vector size -> GrB_ALL .. as no way to get pointer to GrB_ALL object in java GrB_Index* I = NULL; GrB_Index grb_ni = (GrB_Index) ni; jlong * java_is = (*env)->GetLongArrayElements(env, is, NULL); @@ -1523,7 +1517,6 @@ long check_grb_error(GrB_Info info); // NON OPTIONAL STUFF GrB_Vector w = (GrB_Vector) (*env)->GetDirectBufferAddress(env, vec); - // !DIFFERENCE: ni == vector size -> GrB_ALL .. as no way to get pointer to GrB_ALL object in java GrB_Index* I = NULL; GrB_Index grb_ni = (GrB_Index) ni; jlong * java_is = (*env)->GetLongArrayElements(env, is, NULL); @@ -2713,3 +2706,44 @@ JNIEXPORT jobject JNICALL Java_com_github_fabianmurariu_unsafe_GRBMONOID_createM (JNIEnv * env, jclass cls){ return (*env)->NewDirectByteBuffer(env, GxB_EQ_BOOL_MONOID, 0); } + + JNIEXPORT jobject JNICALL Java_com_github_fabianmurariu_unsafe_GRAPHBLAS_selectOpTRIL + (JNIEnv * env, jclass cls){ + return (*env)->NewDirectByteBuffer(env, GxB_TRIL, 0); + } + JNIEXPORT jobject JNICALL Java_com_github_fabianmurariu_unsafe_GRAPHBLAS_selectOpTRIU + (JNIEnv * env, jclass cls){ + return (*env)->NewDirectByteBuffer(env, GxB_TRIU, 0); + } + JNIEXPORT jobject JNICALL Java_com_github_fabianmurariu_unsafe_GRAPHBLAS_selectOpDIAG + (JNIEnv * env, jclass cls){ + return (*env)->NewDirectByteBuffer(env, GxB_DIAG, 0); + } + JNIEXPORT jobject JNICALL Java_com_github_fabianmurariu_unsafe_GRAPHBLAS_selectOpOFFDIAG + (JNIEnv * env, jclass cls){ + return (*env)->NewDirectByteBuffer(env, GxB_OFFDIAG, 0); + } + JNIEXPORT jobject JNICALL Java_com_github_fabianmurariu_unsafe_GRAPHBLAS_selectOpNONZERO + (JNIEnv * env, jclass cls){ + return (*env)->NewDirectByteBuffer(env, GxB_NONZERO, 0); + } + JNIEXPORT jobject JNICALL Java_com_github_fabianmurariu_unsafe_GRAPHBLAS_selectOpEQ_ZERO + (JNIEnv * env, jclass cls){ + return (*env)->NewDirectByteBuffer(env, GxB_EQ_ZERO, 0); + } + JNIEXPORT jobject JNICALL Java_com_github_fabianmurariu_unsafe_GRAPHBLAS_selectOpGT_ZERO + (JNIEnv * env, jclass cls){ + return (*env)->NewDirectByteBuffer(env, GxB_GT_ZERO, 0); + } + JNIEXPORT jobject JNICALL Java_com_github_fabianmurariu_unsafe_GRAPHBLAS_selectOpGE_ZERO + (JNIEnv * env, jclass cls){ + return (*env)->NewDirectByteBuffer(env, GxB_GE_ZERO, 0); + } + JNIEXPORT jobject JNICALL Java_com_github_fabianmurariu_unsafe_GRAPHBLAS_selectOpLT_ZERO + (JNIEnv * env, jclass cls){ + return (*env)->NewDirectByteBuffer(env, GxB_LT_ZERO, 0); + } + JNIEXPORT jobject JNICALL Java_com_github_fabianmurariu_unsafe_GRAPHBLAS_selectOpLE_ZERO + (JNIEnv * env, jclass cls){ + return (*env)->NewDirectByteBuffer(env, GxB_LE_ZERO, 0); + } diff --git a/graphblas-java/src/main/c/unsafe_ops.c b/graphblas-java/src/main/c/unsafe_ops.c index 0945ef4..cd4a940 100644 --- a/graphblas-java/src/main/c/unsafe_ops.c +++ b/graphblas-java/src/main/c/unsafe_ops.c @@ -1,5 +1,6 @@ #include "com_github_fabianmurariu_unsafe_GRBCORE.h" #include "com_github_fabianmurariu_unsafe_GRBOPSMAT.h" +#include "com_github_fabianmurariu_unsafe_GRBOPSVEC.h" #include #include #include "GraphBLAS.h" @@ -74,6 +75,23 @@ JNIEXPORT jint JNICALL Java_com_github_fabianmurariu_unsafe_GRBOPSMAT_elemWiseMu } +JNIEXPORT jlong JNICALL Java_com_github_fabianmurariu_unsafe_GRBOPSVEC_elemWiseMulIntersectMonoid + (JNIEnv * env, jclass cls, jobject vec, jobject mask, jobject accum, jobject monoid, jobject u, jobject v, jobject desc) { + + GrB_Vector out = (GrB_Vector) (*env)->GetDirectBufferAddress(env, vec); + GrB_Vector first = (GrB_Vector) (*env)->GetDirectBufferAddress(env, u); + GrB_Vector second = (GrB_Vector) (*env)->GetDirectBufferAddress(env, v); + GrB_Monoid semi = (GrB_Monoid) (*env)->GetDirectBufferAddress(env, monoid); + + // Optionals + GrB_Vector m = mask != NULL ? (GrB_Vector) (*env)->GetDirectBufferAddress(env, mask) : NULL ; + GrB_BinaryOp acc = accum != NULL ? (GrB_BinaryOp) (*env)->GetDirectBufferAddress(env, accum) : NULL; + GrB_Descriptor d = desc != NULL ? (GrB_Descriptor) (*env)->GetDirectBufferAddress(env, desc) : NULL; + + return check_grb_error(GrB_eWiseMult(out, m, acc, semi, first, second, d)); + + } + JNIEXPORT jint JNICALL Java_com_github_fabianmurariu_unsafe_GRBOPSMAT_elemWiseAddUnionMonoid (JNIEnv * env, jclass cls, jobject mat, jobject mask, jobject accum, jobject monoid, jobject A, jobject B, jobject desc) { @@ -91,6 +109,23 @@ JNIEXPORT jint JNICALL Java_com_github_fabianmurariu_unsafe_GRBOPSMAT_elemWiseAd } +JNIEXPORT jlong JNICALL Java_com_github_fabianmurariu_unsafe_GRBOPSVEC_elemWiseAddUnionMonoid + (JNIEnv * env, jclass cls, jobject vec, jobject mask, jobject accum, jobject monoid, jobject u, jobject v, jobject desc) { + + GrB_Vector out = (GrB_Vector) (*env)->GetDirectBufferAddress(env, vec); + GrB_Vector first = (GrB_Vector) (*env)->GetDirectBufferAddress(env, u); + GrB_Vector second = (GrB_Vector) (*env)->GetDirectBufferAddress(env, v); + GrB_Monoid semi = (GrB_Monoid) (*env)->GetDirectBufferAddress(env, monoid); + + // Optionals + GrB_Vector m = mask != NULL ? (GrB_Vector) (*env)->GetDirectBufferAddress(env, mask) : NULL ; + GrB_BinaryOp acc = accum != NULL ? (GrB_BinaryOp) (*env)->GetDirectBufferAddress(env, accum) : NULL; + GrB_Descriptor d = desc != NULL ? (GrB_Descriptor) (*env)->GetDirectBufferAddress(env, desc) : NULL; + + return check_grb_error(GrB_eWiseAdd(out, m, acc, semi, first, second, d)); + + } + JNIEXPORT jint JNICALL Java_com_github_fabianmurariu_unsafe_GRBOPSMAT_elemWiseMulIntersectBinOp (JNIEnv * env, jclass cls, jobject mat, jobject mask, jobject accum, jobject monoid, jobject A, jobject B, jobject desc) { @@ -108,6 +143,23 @@ JNIEXPORT jint JNICALL Java_com_github_fabianmurariu_unsafe_GRBOPSMAT_elemWiseMu } +JNIEXPORT jlong JNICALL Java_com_github_fabianmurariu_unsafe_GRBOPSVEC_elemWiseMulIntersectBinOp + (JNIEnv * env, jclass cls, jobject vec, jobject mask, jobject accum, jobject bin_op, jobject u, jobject v, jobject desc) { + + GrB_Vector out = (GrB_Vector) (*env)->GetDirectBufferAddress(env, vec); + GrB_Vector first = (GrB_Vector) (*env)->GetDirectBufferAddress(env, u); + GrB_Vector second = (GrB_Vector) (*env)->GetDirectBufferAddress(env, v); + GrB_BinaryOp semi = (GrB_BinaryOp) (*env)->GetDirectBufferAddress(env, bin_op); + + // Optionals + GrB_Vector m = mask != NULL ? (GrB_Vector) (*env)->GetDirectBufferAddress(env, mask) : NULL ; + GrB_BinaryOp acc = accum != NULL ? (GrB_BinaryOp) (*env)->GetDirectBufferAddress(env, accum) : NULL; + GrB_Descriptor d = desc != NULL ? (GrB_Descriptor) (*env)->GetDirectBufferAddress(env, desc) : NULL; + + return check_grb_error(GrB_eWiseMult(out, m, acc, semi, first, second, d)); + + } + JNIEXPORT jint JNICALL Java_com_github_fabianmurariu_unsafe_GRBOPSMAT_elemWiseAddUnionBinOp (JNIEnv * env, jclass cls, jobject mat, jobject mask, jobject accum, jobject monoid, jobject A, jobject B, jobject desc) { @@ -125,6 +177,23 @@ JNIEXPORT jint JNICALL Java_com_github_fabianmurariu_unsafe_GRBOPSMAT_elemWiseAd } +JNIEXPORT jlong JNICALL Java_com_github_fabianmurariu_unsafe_GRBOPSVEC_elemWiseAddUnionBinOp + (JNIEnv * env, jclass cls, jobject vec, jobject mask, jobject accum, jobject bin_op, jobject u, jobject v, jobject desc) { + + GrB_Vector out = (GrB_Vector) (*env)->GetDirectBufferAddress(env, vec); + GrB_Vector first = (GrB_Vector) (*env)->GetDirectBufferAddress(env, u); + GrB_Vector second = (GrB_Vector) (*env)->GetDirectBufferAddress(env, v); + GrB_BinaryOp semi = (GrB_BinaryOp) (*env)->GetDirectBufferAddress(env, bin_op); + + // Optionals + GrB_Vector m = mask != NULL ? (GrB_Vector) (*env)->GetDirectBufferAddress(env, mask) : NULL ; + GrB_BinaryOp acc = accum != NULL ? (GrB_BinaryOp) (*env)->GetDirectBufferAddress(env, accum) : NULL; + GrB_Descriptor d = desc != NULL ? (GrB_Descriptor) (*env)->GetDirectBufferAddress(env, desc) : NULL; + + return check_grb_error(GrB_eWiseAdd(out, m, acc, semi, first, second, d)); + + } + JNIEXPORT jlong JNICALL Java_com_github_fabianmurariu_unsafe_GRBOPSMAT_extract (JNIEnv * env, jclass cls, jobject mat, jobject mask, jobject accum, jobject A, jlongArray is, jlong ni, jlongArray js, jlong nj, jobject desc) { long java_max = 9223372036854775807; @@ -204,6 +273,61 @@ JNIEXPORT jlong JNICALL Java_com_github_fabianmurariu_unsafe_GRBOPSMAT_extract } +JNIEXPORT jlong JNICALL Java_com_github_fabianmurariu_unsafe_GRBOPSVEC_extract + (JNIEnv * env, jclass cls, jobject vec, jobject mask, jobject accum, jobject u, jlongArray is, jlong ni, jobject desc) { + long java_max = 9223372036854775807; + GrB_Index grb_ni; + + grb_ni = ni == java_max ? GxB_RANGE : (GrB_Index) ni; + grb_ni = ni == java_max-1 ? GxB_STRIDE : (GrB_Index) ni; + grb_ni = ni == java_max-2 ? GxB_BACKWARDS : (GrB_Index) ni; + + GrB_Vector out = (GrB_Vector) (*env)->GetDirectBufferAddress(env, vec); + GrB_Vector first = (GrB_Vector) (*env)->GetDirectBufferAddress(env, u); + + jlong *java_is = (*env)->GetLongArrayElements(env, is, NULL); + GrB_Index *I = NULL; + + GrB_Index sizei; + + if (grb_ni == GxB_RANGE) { + sizei = 2; + } else if (grb_ni == GxB_BACKWARDS || grb_ni == GxB_STRIDE){ + sizei = 3; + } else { + sizei = grb_ni; + } + + long java_min = -9223372036854775808; + + if (java_is[0] == java_min) { + I = GrB_ALL; + } + else { + I = malloc (sizei * sizeof (GrB_Index)); + + for (int i = 0; i < sizei; i++) { + I[i] = (GrB_Index)java_is[i]; + } + + (*env)->ReleaseLongArrayElements(env, is, java_is, 0); + } + + // Optionals + GrB_Vector m = mask != NULL ? (GrB_Vector) (*env)->GetDirectBufferAddress(env, mask) : NULL ; + GrB_BinaryOp acc = accum != NULL ? (GrB_BinaryOp) (*env)->GetDirectBufferAddress(env, accum) : NULL; + GrB_Descriptor d = desc != NULL ? (GrB_Descriptor) (*env)->GetDirectBufferAddress(env, desc) : NULL; + + long res = check_grb_error(GrB_Vector_extract(out, m, acc, first, I, grb_ni, d)); + + if (I != GrB_ALL) { + free(I); + } + + return res; + + } + JNIEXPORT jlong JNICALL Java_com_github_fabianmurariu_unsafe_GRBOPSMAT_assign (JNIEnv * env, jclass cls, jobject mat, jobject mask, jobject accum, jobject A, jlongArray is, jlong ni, jlongArray js, jlong nj, jobject desc) { long java_max = 9223372036854775807; @@ -269,7 +393,7 @@ JNIEXPORT jlong JNICALL Java_com_github_fabianmurariu_unsafe_GRBOPSMAT_assign GrB_BinaryOp acc = accum != NULL ? (GrB_BinaryOp) (*env)->GetDirectBufferAddress(env, accum) : NULL; GrB_Descriptor d = desc != NULL ? (GrB_Descriptor) (*env)->GetDirectBufferAddress(env, desc) : NULL; - long res = check_grb_error(GrB_assign(out, m, acc, first, I, grb_nj, J, grb_nj, d)); + long res = check_grb_error(GrB_assign(out, m, acc, first, I, grb_ni, J, grb_nj, d)); (*env)->ReleaseLongArrayElements(env, is, java_is, 0); (*env)->ReleaseLongArrayElements(env, js, java_js, 0); @@ -284,6 +408,60 @@ JNIEXPORT jlong JNICALL Java_com_github_fabianmurariu_unsafe_GRBOPSMAT_assign } +JNIEXPORT jlong JNICALL Java_com_github_fabianmurariu_unsafe_GRBOPSVEC_assign + (JNIEnv * env, jclass cls, jobject vec, jobject mask, jobject accum, jobject u, jlongArray is, jlong ni, jobject desc) { + long java_max = 9223372036854775807; + GrB_Index grb_ni; + + grb_ni = ni == java_max ? GxB_RANGE : (GrB_Index) ni; + grb_ni = ni == java_max-1 ? GxB_STRIDE : (GrB_Index) ni; + grb_ni = ni == java_max-2 ? GxB_BACKWARDS : (GrB_Index) ni; + + GrB_Vector out = (GrB_Vector) (*env)->GetDirectBufferAddress(env, vec); + GrB_Vector first = (GrB_Vector) (*env)->GetDirectBufferAddress(env, u); + + GrB_Index *I = NULL; + jlong *java_is = (*env)->GetLongArrayElements(env, is, NULL); + + + long java_min = -9223372036854775808; + + if (java_is[0] == java_min) { + I = GrB_ALL; + } + else { + GrB_Index sizei; + if (grb_ni == GxB_RANGE) { + sizei = 2; + } else if (grb_ni == GxB_BACKWARDS || grb_ni == GxB_STRIDE){ + sizei = 3; + } else { + sizei = grb_ni; + } + + I = malloc (sizei * sizeof (GrB_Index)) ; + + for (int i = 0; i < sizei; i++) { + I[i] = (GrB_Index)java_is[i]; + } + + (*env)->ReleaseLongArrayElements(env, is, java_is, 0); + } + // Optionals + GrB_Vector m = mask != NULL ? (GrB_Vector) (*env)->GetDirectBufferAddress(env, mask) : NULL ; + GrB_BinaryOp acc = accum != NULL ? (GrB_BinaryOp) (*env)->GetDirectBufferAddress(env, accum) : NULL; + GrB_Descriptor d = desc != NULL ? (GrB_Descriptor) (*env)->GetDirectBufferAddress(env, desc) : NULL; + + long res = check_grb_error(GrB_assign(out, m, acc, first, I, grb_ni, d)); + + if(I != GrB_ALL) { + free(I); + } + + return res; + + } + JNIEXPORT jlong JNICALL Java_com_github_fabianmurariu_unsafe_GRBOPSMAT_subAssign (JNIEnv * env, jclass cls, jobject mat, jobject mask, jobject accum, jobject A, jlongArray is, jlong ni, jlongArray js, jlong nj, jobject desc) { // if we receive max java long we treat it as GxB_RANGE @@ -364,6 +542,68 @@ JNIEXPORT jlong JNICALL Java_com_github_fabianmurariu_unsafe_GRBOPSMAT_subAssign } +JNIEXPORT jlong JNICALL Java_com_github_fabianmurariu_unsafe_GRBOPSVEC_subAssign + (JNIEnv * env, jclass cls, jobject vec, jobject mask, jobject accum, jobject u, jlongArray is, jlong ni, jobject desc) { + // if we receive max java long we treat it as GxB_RANGE + long java_max = 9223372036854775807; + GrB_Index grb_ni; + + grb_ni = ni == java_max ? GxB_RANGE : (GrB_Index) ni; + grb_ni = ni == java_max-1 ? GxB_STRIDE : (GrB_Index) ni; + grb_ni = ni == java_max-2 ? GxB_BACKWARDS : (GrB_Index) ni; + + GrB_Vector out = (GrB_Vector) (*env)->GetDirectBufferAddress(env, vec); + GrB_Vector first = (GrB_Vector) (*env)->GetDirectBufferAddress(env, u); + + jlong *java_is; + GrB_Index *I = NULL; + + java_is = (*env)->GetLongArrayElements(env, is, NULL); + + GrB_Index sizei; + if (grb_ni == GxB_RANGE) { + sizei = 2; + } else if (grb_ni == GxB_BACKWARDS || grb_ni == GxB_STRIDE){ + sizei = 3; + } else { + sizei = grb_ni; + } + + I = malloc (sizei * sizeof (GrB_Index)) ; + + for (int i = 0; i < sizei; i++) { + I[i] = (GrB_Index)java_is[i]; + } + + // Optionals + GrB_Vector m = mask != NULL ? (GrB_Vector) (*env)->GetDirectBufferAddress(env, mask) : NULL ; + GrB_BinaryOp acc = accum != NULL ? (GrB_BinaryOp) (*env)->GetDirectBufferAddress(env, accum) : NULL; + GrB_Descriptor d = desc != NULL ? (GrB_Descriptor) (*env)->GetDirectBufferAddress(env, desc) : NULL; + + long res = check_grb_error(GxB_Vector_subassign(out, m, acc, first, I, grb_ni, d)); + + (*env)->ReleaseLongArrayElements(env, is, java_is, 0); + free(I); + + return res; + } + +JNIEXPORT jlong JNICALL Java_com_github_fabianmurariu_unsafe_GRBOPSMAT_select + (JNIEnv * env, jclass cls, jobject C, jobject mask, jobject accum, jobject op, jobject A, jobject Thunk, jobject desc) { + // Non-optionals + GrB_Matrix out = (GrB_Matrix) (*env)->GetDirectBufferAddress(env, C); + GrB_Matrix first = (GrB_Matrix) (*env)->GetDirectBufferAddress(env, A); + GxB_SelectOp grb_op = (GxB_SelectOp) (*env)->GetDirectBufferAddress(env, op); + + // Optionals + GrB_Vector m = mask != NULL ? (GrB_Vector) (*env)->GetDirectBufferAddress(env, mask) : NULL ; + GrB_BinaryOp acc = accum != NULL ? (GrB_BinaryOp) (*env)->GetDirectBufferAddress(env, accum) : NULL; + GrB_Descriptor d = desc != NULL ? (GrB_Descriptor) (*env)->GetDirectBufferAddress(env, desc) : NULL; + GxB_Scalar grb_thunk = NULL; + + return check_grb_error(GxB_Matrix_select(out, m, acc, grb_op, first, grb_thunk, d)); + } + JNIEXPORT jlong JNICALL Java_com_github_fabianmurariu_unsafe_GRBOPSMAT_matrixReduceBinOp (JNIEnv * env, jclass cls, jobject vec, jobject mask, jobject accum, jobject bin_op, jobject A, jobject desc) { GrB_Vector out = (GrB_Vector) (*env)->GetDirectBufferAddress(env, vec); diff --git a/graphblas-java/src/main/data.json b/graphblas-java/src/main/data.json index 8ee4a1b..16f18c4 100644 --- a/graphblas-java/src/main/data.json +++ b/graphblas-java/src/main/data.json @@ -92,5 +92,17 @@ "java_type": "double", "c_type": "double" } + ], + "select_ops": [ + "TRIL", + "TRIU", + "DIAG", + "OFFDIAG", + "NONZERO", + "EQ_ZERO", + "GT_ZERO", + "GE_ZERO", + "LT_ZERO", + "LE_ZERO" ] -} \ No newline at end of file +} diff --git a/graphblas-java/src/main/java/com/github/fabianmurariu/unsafe/GRAPHBLAS.java b/graphblas-java/src/main/java/com/github/fabianmurariu/unsafe/GRAPHBLAS.java index 34361f9..382168c 100644 --- a/graphblas-java/src/main/java/com/github/fabianmurariu/unsafe/GRAPHBLAS.java +++ b/graphblas-java/src/main/java/com/github/fabianmurariu/unsafe/GRAPHBLAS.java @@ -334,4 +334,17 @@ public final class GRAPHBLAS { public static native Buffer lorBinaryOp(); public static native Buffer landBinaryOp(); public static native Buffer lxorBinaryOp(); + +// SelectOps (GraphBLAS extension) +// TODO list all pre-defined select ops + public static native Buffer selectOpTRIL(); + public static native Buffer selectOpTRIU(); + public static native Buffer selectOpDIAG(); + public static native Buffer selectOpOFFDIAG(); + public static native Buffer selectOpNONZERO(); + public static native Buffer selectOpEQ_ZERO(); + public static native Buffer selectOpGT_ZERO(); + public static native Buffer selectOpGE_ZERO(); + public static native Buffer selectOpLT_ZERO(); + public static native Buffer selectOpLE_ZERO(); } diff --git a/graphblas-java/src/main/java/com/github/fabianmurariu/unsafe/GRBCORE.java b/graphblas-java/src/main/java/com/github/fabianmurariu/unsafe/GRBCORE.java index 67a8fb6..9860455 100644 --- a/graphblas-java/src/main/java/com/github/fabianmurariu/unsafe/GRBCORE.java +++ b/graphblas-java/src/main/java/com/github/fabianmurariu/unsafe/GRBCORE.java @@ -68,6 +68,7 @@ public final class GRBCORE { public static long NOT_REALLY_GRB_ALL = Long.MIN_VALUE; // placeholder for GrB_ALL public static long[] GrB_ALL = {NOT_REALLY_GRB_ALL}; public static native long initNonBlocking(); + public static native long initBlocking(); public static native long grbWait(); public static native long grbFinalize(); @@ -112,6 +113,42 @@ public final class GRBCORE { // Monoid public static native long freeMonoid(Buffer monoid); + // Global options + // Fields (get and set) + public static int GxB_HYPER = 0; + public static int GxB_FORMAT = 1; // defines CSR/CSC format: GxB_BY_ROW or GxB_BY_COL + public static int GxB_NTHREADS = 5; + public static int GxB_CHUNK = 7; + + // Fields only for get (only supporting the ones returning ints for now) + public static int GxB_MODE = 2; // mode passed to GrB_init (blocking or non-blocking) + public static int GxB_THREAD_SAFETY = 3; // thread library that allows GraphBLAS to be thread-safe for user threads. + public static int GxB_THREADING = 4; // thread library used for internal GraphBLAS threads + + // Values + // for GxB_FORMAT + public static int GxB_BY_ROW = 0; // CSR + public static int GxB_BY_COL = 1; // CSC + public static int GxB_NO_FORMAT = -1; // not defined + + // for GrB_Mode + public static int GrB_NONBLOCKING = 0; + public static int GrB_BLOCKING = 1; + + public static int GxB_THREAD_NONE = 0; // no threading + public static int GxB_THREAD_OPENMP = 1; // OpenMP + public static int GxB_THREAD_POSIX = 2; // POSIX pthreads + public static int GxB_THREAD_WINDOWS = 3; // Windows threads + public static int GxB_THREAD_ANSI = 4; // ANSI C11 threads + + + public static native long setGlobalInt(int field, int value); + // f.i. for hyper ratio or chunk + public static native long setGlobalDouble(int field, double value); + public static native int getGlobalInt(int field); + public static native double getGlobalDouble(int field); + // TODO return global string value or int array? f.i. version or library date + // Descriptor // Fields public static int GrB_OUTP = 0; // descriptor for output of a method diff --git a/graphblas-java/src/main/java/com/github/fabianmurariu/unsafe/GRBOPSMAT.java b/graphblas-java/src/main/java/com/github/fabianmurariu/unsafe/GRBOPSMAT.java index 1f37b0c..5619507 100644 --- a/graphblas-java/src/main/java/com/github/fabianmurariu/unsafe/GRBOPSMAT.java +++ b/graphblas-java/src/main/java/com/github/fabianmurariu/unsafe/GRBOPSMAT.java @@ -154,6 +154,21 @@ public class GRBOPSMAT { */ public static native long extract(Buffer C, Buffer mask, Buffer accum, Buffer A, long[] I, long ni, long[] J, long nj, Buffer desc); + /** + * {@code C = accum (C, op(A,k)) or op(A’,k)} + * + * @param C input/output matrix for results + * @param mask optional mask for C, unused if NULL + * @param accum optional accum for Z=accum(C,T) + * @param op operator to apply to the entries + * @param A first input: matrix A + * @param Thunk Optional .. not mapped yet! + * @param desc descriptor for C, mask, and A + * @return + */ + public static native long select(Buffer C, Buffer mask, Buffer accum, Buffer op, Buffer A, Buffer Thunk, Buffer desc); + + // w = accum (w,reduce(A)) // input/output vector for results // optional mask for w, unused if NULL diff --git a/graphblas-java/src/main/java/com/github/fabianmurariu/unsafe/GRBOPSVEC.java b/graphblas-java/src/main/java/com/github/fabianmurariu/unsafe/GRBOPSVEC.java new file mode 100644 index 0000000..3bad491 --- /dev/null +++ b/graphblas-java/src/main/java/com/github/fabianmurariu/unsafe/GRBOPSVEC.java @@ -0,0 +1,108 @@ +package com.github.fabianmurariu.unsafe; + +import java.nio.Buffer; + +public class GRBOPSVEC { + + static { + NarSystem.loadLibrary(); + } + + /** + * {@code w = accum (w, u.*v)} + * + * @param w input/output matrix for results + * @param mask optional mask for w, unused if NULL + * @param accum optional accum for Z=accum(w,T) + * @param monoid defines ’.*’ for T=u.*v + * @param u first input: vector u + * @param v second input: vector v + * @param desc descriptor for w, Mask, u, and v + * @return GrB_Info status + */ + public static native long elemWiseMulIntersectMonoid(Buffer w, Buffer mask, Buffer accum, Buffer monoid, Buffer u, Buffer v, Buffer desc); + + /** + * {@code w = accum (w, u.*v)} + * + * @param w input/output vector for results + * @param mask optional mask for w, unused if NULL + * @param accum optional accum for Z=accum(w,T) + * @param binOp defines ’.*’ for T=u.*v + * @param u first input: vector u + * @param v second input: vector v + * @param desc descriptor for w, Mask, u, and v + * @return GrB_Info status + */ + public static native long elemWiseMulIntersectBinOp(Buffer w, Buffer mask, Buffer accum, Buffer binOp, Buffer u, Buffer v, Buffer desc); + + /** + * {@code w = accum (w, u.+v)} + * + * @param w input/output vector for results + * @param mask optional mask for w, unused if NULL + * @param accum optional accum for Z=accum(w,T) + * @param monoid defines ’.+’ for T=u.+v + * @param u first input: vector u + * @param v second input: vector v + * @param desc descriptor for w, Mask, u, and v + * @return GrB_Info status + */ + public static native long elemWiseAddUnionMonoid(Buffer w, Buffer mask, Buffer accum, Buffer monoid, Buffer u, Buffer v, Buffer desc); + + /** + * {@code w = accum (w, u.+v)} + * + * @param w input/output vector for results + * @param mask optional mask for w, unused if NULL + * @param accum optional accum for Z=accum(w,T) + * @param binOp defines ’.+’ for T=u.+v + * @param u first input: vector u + * @param v second input: vector v + * @param desc descriptor for w, Mask, u, and v + * @return GrB_Info status + */ + public static native long elemWiseAddUnionBinOp(Buffer w, Buffer mask, Buffer accum, Buffer binOp, Buffer u, Buffer v, Buffer desc); + + /** + * {@code w(I,J) = accum (w(i),u)} + * + * @param w input/output vector for results + * @param mask optional mask for w, unused if NULL + * @param accum optional accum for Z=accum(w(I,J),T) + * @param u first input: vector u + * @param I row indices + * @param ni number of row indices + * @param desc descriptor for w, Mask, and u + * @return GrB_Info status + */ + public static native long assign(Buffer w, Buffer mask, Buffer accum, Buffer u, long[] I, long ni, Buffer desc); + + /** + * {@code w(I,J) = accum (w(i),u)} + * + * @param w input/output vector for results + * @param mask optional mask for w, unused if NULL + * @param accum optional accum for Z=accum(w(I,J),T) + * @param u first input: vector u + * @param I row indices + * @param ni number of row indices + * @param desc descriptor for w, Mask, and u + * @return GrB_Info status + */ + public static native long subAssign(Buffer w, Buffer mask, Buffer accum, Buffer u, long[] I, long ni, Buffer desc); + + /** + * {@code w = accum (w, u(i))} + * + * @param w input/output vector for results + * @param mask optional mask for w, unused if NULL + * @param accum optional accum for Z=accum(w(I,J),T) + * @param u first input: vector u + * @param I row indices + * @param ni number of row indices + * @param desc descriptor for w, Mask, and u + * @return GrB_Info status + */ + public static native long extract(Buffer w, Buffer mask, Buffer accum, Buffer u, long[] I, long ni, Buffer desc); +} diff --git a/graphblas-java/src/main/templates/c/unsafe_gen.c.ftl b/graphblas-java/src/main/templates/c/unsafe_gen.c.ftl index 2a9d418..f6dd32d 100644 --- a/graphblas-java/src/main/templates/c/unsafe_gen.c.ftl +++ b/graphblas-java/src/main/templates/c/unsafe_gen.c.ftl @@ -204,7 +204,6 @@ long check_grb_error(GrB_Info info); // NON OPTIONAL STUFF GrB_Vector w = (GrB_Vector) (*env)->GetDirectBufferAddress(env, vec); - // !DIFFERENCE: ni == vector size -> GrB_ALL .. as no way to get pointer to GrB_ALL object in java GrB_Index* I = NULL; GrB_Index grb_ni = (GrB_Index) ni; jlong * java_is = (*env)->GetLongArrayElements(env, is, NULL); @@ -303,3 +302,10 @@ JNIEXPORT jobject JNICALL Java_com_github_fabianmurariu_unsafe_GRBMONOID_createM return (*env)->NewDirectByteBuffer(env, ${op.grb_name}_BOOL_MONOID, 0); } + + <#list properties.select_ops as op> + JNIEXPORT jobject JNICALL Java_com_github_fabianmurariu_unsafe_GRAPHBLAS_selectOp${op} + (JNIEnv * env, jclass cls){ + return (*env)->NewDirectByteBuffer(env, GxB_${op}, 0); + } + diff --git a/graphblas-java/src/main/templates/data.json b/graphblas-java/src/main/templates/data.json index 8ee4a1b..16f18c4 100644 --- a/graphblas-java/src/main/templates/data.json +++ b/graphblas-java/src/main/templates/data.json @@ -92,5 +92,17 @@ "java_type": "double", "c_type": "double" } + ], + "select_ops": [ + "TRIL", + "TRIU", + "DIAG", + "OFFDIAG", + "NONZERO", + "EQ_ZERO", + "GT_ZERO", + "GE_ZERO", + "LT_ZERO", + "LE_ZERO" ] -} \ No newline at end of file +} diff --git a/graphblas-java/src/main/templates/java/com/github/fabianmurariu/unsafe/GRAPHBLAS.java.ftl b/graphblas-java/src/main/templates/java/com/github/fabianmurariu/unsafe/GRAPHBLAS.java.ftl index 1ba4c4d..0b96dc2 100644 --- a/graphblas-java/src/main/templates/java/com/github/fabianmurariu/unsafe/GRAPHBLAS.java.ftl +++ b/graphblas-java/src/main/templates/java/com/github/fabianmurariu/unsafe/GRAPHBLAS.java.ftl @@ -54,4 +54,10 @@ public final class GRAPHBLAS { <#list properties.binary_ops_bool_bool as op> public static native Buffer ${op.name}BinaryOp(); + +// SelectOps (GraphBLAS extension) +// TODO list all pre-defined select ops +<#list properties.select_ops as op> + public static native Buffer selectOp${op}(); + } diff --git a/graphblas-java/src/test/scala/com/github/fabianmurariu/unsafe/AssignExtractSpec.scala b/graphblas-java/src/test/scala/com/github/fabianmurariu/unsafe/AssignExtractSpec.scala index 55feecf..0f19309 100644 --- a/graphblas-java/src/test/scala/com/github/fabianmurariu/unsafe/AssignExtractSpec.scala +++ b/graphblas-java/src/test/scala/com/github/fabianmurariu/unsafe/AssignExtractSpec.scala @@ -1,7 +1,5 @@ package com.github.fabianmurariu.unsafe -import java.nio.Buffer - import org.scalacheck.Arbitrary import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.matchers.should.Matchers @@ -14,17 +12,17 @@ trait AssignExtractSpec { self: AnyFlatSpec with ScalaCheckDrivenPropertyChecks with Matchers => - behavior of "GrB_extract" + behavior of "GrB_Matrix_extract" - testGrBExtract[Boolean] - testGrBExtract[Byte] - testGrBExtract[Short] - testGrBExtract[Int] - testGrBExtract[Long] - testGrBExtract[Float] - testGrBExtract[Double] + testGrBMatrixExtract[Boolean] + testGrBMatrixExtract[Byte] + testGrBMatrixExtract[Short] + testGrBMatrixExtract[Int] + testGrBMatrixExtract[Long] + testGrBMatrixExtract[Float] + testGrBMatrixExtract[Double] - private def testGrBExtract[T: SparseMatrixHandler](implicit A: Arbitrary[MatrixTuples[T]], CT: ClassTag[T]): Unit = { + private def testGrBMatrixExtract[T: SparseMatrixHandler](implicit A: Arbitrary[MatrixTuples[T]], CT: ClassTag[T]): Unit = { it should s"call GrB_extract for GrB_Matrix of type ${CT.toString()}" in forAll { mt: MatrixTuples[T] => val mat = SparseMatrixHandler[T].buildMatrix(mt) @@ -60,7 +58,72 @@ trait AssignExtractSpec { } } - private def testGrBAssign[T: SparseMatrixHandler](implicit A: Arbitrary[MatrixTuples[T]], CT: ClassTag[T]): Unit = { + behavior of "GrB_Vector_extract" + + testGrBVectorExtract[Boolean] + testGrBVectorExtract[Byte] + testGrBVectorExtract[Short] + testGrBVectorExtract[Int] + testGrBVectorExtract[Long] + testGrBVectorExtract[Float] + testGrBVectorExtract[Double] + + private def testGrBVectorExtract[T: SparseVectorHandler](implicit A: Arbitrary[VectorVals[T]], CT: ClassTag[T]): Unit = { + it should s"call GrB_extract for GrB_Vector of type ${CT.toString()}" in forAll { mt: VectorVals[T] => + val vec = SparseVectorHandler[T].buildVector(mt) + + // pick half of the indices and extract them into another mat + val (_, right) = mt.vals.splitAt(mt.vals.size / 2) + val dRight = right.distinctBy(t => t._1 -> t._2) + val ni: Vector[Long] = dRight.map(_._1) + + val into = SparseVectorHandler[T].createVector(ni.size) + + val res = GRBOPSVEC.extract(into, null, null, vec, ni.toArray, ni.size, null) + assert(res == 0) + + val expected: immutable.IndexedSeq[T] = (for { + i <- ni.indices + } yield SparseVectorHandler[T].get(vec)(ni(i))).flatten + + SparseVectorHandler[T].extractTuples(into) should contain theSameElementsAs expected + } + + it should s"call GrB_extract all for GrB_Vector of type ${CT.toString()}" in forAll { mt: VectorVals[T] => + val vec = SparseVectorHandler[T].buildVector(mt) + + val into = SparseVectorHandler[T].createVector(mt.size) + + GRBOPSVEC.extract(into, null, null, vec, GRBCORE.GrB_ALL, mt.size, null) shouldBe GRBCORE.GrB_SUCCESS + + SparseVectorHandler[T].extractTuples(into) should contain theSameElementsAs SparseVectorHandler[T].extractTuples(vec) + } + } + + behavior of "GrB_Vector_assign" + + testGrBVectorAssign[Boolean] + testGrBVectorAssign[Byte] + testGrBVectorAssign[Short] + testGrBVectorAssign[Int] + testGrBVectorAssign[Long] + testGrBVectorAssign[Float] + testGrBVectorAssign[Double] + + private def testGrBVectorAssign[T: SparseVectorHandler](implicit A: Arbitrary[VectorVals[T]], CT: ClassTag[T]): Unit = { + it should s"call GrB_assign for GrB_Vector of type ${CT.toString()} and assign everything" in forAll { mt: VectorVals[T] => + val vec = SparseVectorHandler[T].buildVector(mt) + + val output = SparseVectorHandler[T].createVector(mt.size) + + GRBOPSVEC.assign(output, null, null, vec, GRBCORE.GrB_ALL, mt.size, null) + + SparseVectorHandler[T].extractTuples(output) should contain theSameElementsAs SparseVectorHandler[T].extractTuples(vec) + } + } + + // FIXME: somehow assign throws an GrB_DIMENSION_MISMATCH + private def testGrBMatrixAssign[T: SparseMatrixHandler](implicit A: Arbitrary[MatrixTuples[T]], CT: ClassTag[T]): Unit = { it should s"call GrB_assign for GrB_Matrix of type ${CT.toString()}" in forAll { mt: MatrixTuples[T] => val mat = SparseMatrixHandler[T].buildMatrix(mt) @@ -71,7 +134,7 @@ trait AssignExtractSpec { val ni: Vector[Long] = dRight.map(_._1) val nj: Vector[Long] = dRight.map(_._2) - val into = SparseMatrixHandler[T].createMatrix(ni.size, nj.size) + val into = SparseMatrixHandler[T].createMatrix(mt.dim.rows, mt.dim.cols) val res = GRBOPSMAT.assign(into, null, null, mat, ni.toArray, ni.size, nj.toArray, nj.size, null) assert(res == 0) diff --git a/graphblas-java/src/test/scala/com/github/fabianmurariu/unsafe/AssignScalarSpec.scala b/graphblas-java/src/test/scala/com/github/fabianmurariu/unsafe/AssignScalarSpec.scala index 9cf257b..1e9d70a 100644 --- a/graphblas-java/src/test/scala/com/github/fabianmurariu/unsafe/AssignScalarSpec.scala +++ b/graphblas-java/src/test/scala/com/github/fabianmurariu/unsafe/AssignScalarSpec.scala @@ -10,7 +10,7 @@ import scala.reflect.ClassTag trait AssignScalarSpec { self: AnyFlatSpec with ScalaCheckDrivenPropertyChecks with Matchers => - behavior of "GrB_Vector_assign" + behavior of "GrB_Vector_assignScalar" testVectorAssignScalar[Boolean] testVectorAssignScalar[Byte] @@ -20,7 +20,7 @@ trait AssignScalarSpec { testVectorAssignScalar[Float] testVectorAssignScalar[Double] - def testVectorAssignScalar[T: SparseVectorHandler](implicit A: Arbitrary[VectorVals[T]], CT: ClassTag[T]) = { + def testVectorAssignScalar[T: SparseVectorHandler](implicit A: Arbitrary[VectorVals[T]], CT: ClassTag[T]): Unit = { it should s"create a vector of type ${CT.toString()}, assign a scalar value" in forAll { mt: VectorVals[T] => val handler = SparseVectorHandler[T] diff --git a/graphblas-java/src/test/scala/com/github/fabianmurariu/unsafe/ElemWiseSpec.scala b/graphblas-java/src/test/scala/com/github/fabianmurariu/unsafe/ElemWiseSpec.scala index e3a5eec..2340884 100644 --- a/graphblas-java/src/test/scala/com/github/fabianmurariu/unsafe/ElemWiseSpec.scala +++ b/graphblas-java/src/test/scala/com/github/fabianmurariu/unsafe/ElemWiseSpec.scala @@ -13,14 +13,14 @@ trait ElemWiseSpec { behavior of "GrB_eWise*_Matrix" - eWiseMult[Byte] - eWiseMult[Short] - eWiseMult[Int] - eWiseMult[Long] - eWiseMult[Float] - eWiseMult[Double] - - def eWiseMult[T: SparseMatrixHandler: MonoidHandler:BinaryOpHandler](implicit A:Arbitrary[MatrixTuplesMul[T]], N: Numeric[T], CT: ClassTag[T]): Unit = { + eWiseMultMatrix[Byte] + eWiseMultMatrix[Short] + eWiseMultMatrix[Int] + eWiseMultMatrix[Long] + eWiseMultMatrix[Float] + eWiseMultMatrix[Double] + + def eWiseMultMatrix[T: SparseMatrixHandler : MonoidHandler : BinaryOpHandler](implicit A: Arbitrary[MatrixTuplesMul[T]], N: Numeric[T], CT: ClassTag[T]): Unit = { it should s"apply plus(A, B) for the intersection of all items on type ${CT.toString()}" in forAll { mt: MatrixTuplesMul[T] => val a = SparseMatrixHandler[T].buildMatrix(mt.left) @@ -63,4 +63,56 @@ trait ElemWiseSpec { ret2 shouldBe GRBCORE.GrB_SUCCESS } } + + + behavior of "GrB_eWise*_Vector" + + eWiseMultVector[Byte] + eWiseMultVector[Short] + eWiseMultVector[Int] + eWiseMultVector[Long] + eWiseMultVector[Float] + eWiseMultVector[Double] + + def eWiseMultVector[T: SparseVectorHandler : MonoidHandler : BinaryOpHandler](implicit A: Arbitrary[VectorValsMul[T]], N: Numeric[T], CT: ClassTag[T]): Unit = { + it should s"apply plus(A, B) for the intersection of all items on type ${CT.toString()}" in forAll { mt: VectorValsMul[T] => + + val a = SparseVectorHandler[T].buildVector(mt.left) + val b = SparseVectorHandler[T].buildVector(mt.right) + + val expectedSize = mt.left.vals.map(_._1).intersect(mt.right.vals.map(_._1)).size + + val c1 = SparseVectorHandler[T].createVector(mt.left.size) + val c2 = SparseVectorHandler[T].createVector(mt.left.size) + + val m = MonoidHandler[T].plus + val op = BinaryOpHandler[T].plus + + GRBOPSVEC.elemWiseMulIntersectMonoid(c1, null, null, m, a, b, null) shouldBe GRBCORE.GrB_SUCCESS + GRBOPSVEC.elemWiseMulIntersectBinOp(c2, null, null, op, a, b, null) shouldBe GRBCORE.GrB_SUCCESS + + GRBCORE.nvalsVector(c1) shouldBe expectedSize + GRBCORE.nvalsVector(c2) shouldBe expectedSize + } + + it should s"apply plus(A, B) for the union of all items on type ${CT.toString()}" in forAll { mt: VectorValsMul[T] => + + val a = SparseVectorHandler[T].buildVector(mt.left) + val b = SparseVectorHandler[T].buildVector(mt.right) + + val expectedSize = mt.left.vals.map(_._1).union(mt.right.vals.map(_._1)).toSet.size + + val c1 = SparseVectorHandler[T].createVector(mt.left.size) + val c2 = SparseVectorHandler[T].createVector(mt.left.size) + + val m = MonoidHandler[T].plus + val op = BinaryOpHandler[T].plus + + GRBOPSVEC.elemWiseAddUnionMonoid(c1, null, null, m, a, b, null) shouldBe GRBCORE.GrB_SUCCESS + GRBOPSVEC.elemWiseAddUnionBinOp(c2, null, null, op, a, b, null) shouldBe GRBCORE.GrB_SUCCESS + + GRBCORE.nvalsVector(c1) shouldBe expectedSize + GRBCORE.nvalsVector(c2) shouldBe expectedSize + } + } } diff --git a/graphblas-java/src/test/scala/com/github/fabianmurariu/unsafe/GRAPHBLASSpec.scala b/graphblas-java/src/test/scala/com/github/fabianmurariu/unsafe/GRAPHBLASSpec.scala index 18f5211..c16db20 100644 --- a/graphblas-java/src/test/scala/com/github/fabianmurariu/unsafe/GRAPHBLASSpec.scala +++ b/graphblas-java/src/test/scala/com/github/fabianmurariu/unsafe/GRAPHBLASSpec.scala @@ -16,7 +16,8 @@ class GRAPHBLASSpec extends AnyFlatSpec with ScalaCheckDrivenPropertyChecks with with MxmSpec with AssignExtractSpec with AssignScalarSpec - with ElemWiseSpec { + with ElemWiseSpec + with SelectSpec { behavior of "GrB_Matrix" @@ -98,6 +99,20 @@ class GRAPHBLASSpec extends AnyFlatSpec with ScalaCheckDrivenPropertyChecks with testSettersAndGettersVector[Double](GRAPHBLAS.doubleType()) { (vec, i, value) => GRAPHBLAS.setVectorElementDouble(vec, i, value) } { (vec, i) => GRAPHBLAS.getVectorElementDouble(vec, i).headOption } + behavior of "GxB_Global_Option_get/set" + + it should "get/set concurrency and hyper-ratio" in { + val concurrency = 7 + GRBCORE.setGlobalInt(GRBCORE.GxB_NTHREADS, concurrency) + GRBCORE.getGlobalInt(GRBCORE.GxB_NTHREADS) shouldBe concurrency + + val hyperRatio = 0.001337 + GRBCORE.setGlobalDouble(GRBCORE.GxB_HYPER, hyperRatio) + GRBCORE.getGlobalDouble(GRBCORE.GxB_HYPER) shouldBe hyperRatio + + GRBCORE.getGlobalInt(GRBCORE.GxB_MODE) shouldBe GRBCORE.GrB_NONBLOCKING + } + override protected def beforeAll(): Unit = { GRBCORE.initNonBlocking() } diff --git a/graphblas-java/src/test/scala/com/github/fabianmurariu/unsafe/SelectSpec.scala b/graphblas-java/src/test/scala/com/github/fabianmurariu/unsafe/SelectSpec.scala new file mode 100644 index 0000000..83c20a6 --- /dev/null +++ b/graphblas-java/src/test/scala/com/github/fabianmurariu/unsafe/SelectSpec.scala @@ -0,0 +1,33 @@ +package com.github.fabianmurariu.unsafe + +import java.nio.Buffer + +import org.scalacheck.Arbitrary +import org.scalatest.flatspec.AnyFlatSpec +import org.scalatest.matchers.should.Matchers +import org.scalatestplus.scalacheck.ScalaCheckDrivenPropertyChecks + +import scala.reflect.ClassTag + +trait SelectSpec { + self: AnyFlatSpec with ScalaCheckDrivenPropertyChecks with Matchers => + + behavior of "GrB_Matrix_select" + + testMatrixSelect[Boolean] + + private def testMatrixSelect[T: SparseMatrixHandler](implicit A:Arbitrary[MatrixTuples[T]], CT: ClassTag[T]): Unit = { + it should s"call GrB_select for GrB_Matrix of type ${CT.toString()}" in forAll { mt: MatrixTuples[T] => + val mat = SparseMatrixHandler[T].buildMatrix(mt) + val out = SparseMatrixHandler[T].createMatrix(mt.dim.rows, mt.dim.cols) + + val selectOp = GRAPHBLAS.selectOpDIAG() + GRBOPSMAT.select(out, null, null, selectOp, mat, null, null) shouldBe GRBCORE.GrB_SUCCESS + + // check could be improved + val actual = SparseMatrixHandler[T].extractAllTuples(out) + val expected = mt.vals.filter(p => (p._1 == p._2)) + actual should contain theSameElementsAs expected + } + } +} diff --git a/graphblas-java/src/test/scala/com/github/fabianmurariu/unsafe/SparseVectorHandler.scala b/graphblas-java/src/test/scala/com/github/fabianmurariu/unsafe/SparseVectorHandler.scala index ba26df3..25249e5 100644 --- a/graphblas-java/src/test/scala/com/github/fabianmurariu/unsafe/SparseVectorHandler.scala +++ b/graphblas-java/src/test/scala/com/github/fabianmurariu/unsafe/SparseVectorHandler.scala @@ -30,6 +30,7 @@ trait SparseVectorHandler[T] { def clear(vec: Buffer): Unit = GRBCORE.clearVec(vec) + def extractTuples(mat: Buffer): Array[T] } object SparseVectorHandler { @@ -44,6 +45,14 @@ object SparseVectorHandler { def assign(vec: Buffer)(v: Boolean): Unit = GRAPHBLAS.assignVectorBoolean(vec, null, null, v, GRBCORE.GrB_ALL, size(vec), null) + + def extractTuples(vec: Buffer): Array[Boolean] = { + val nvals = GRBCORE.nvalsVector(vec) + val vs = new Array[Boolean](nvals.toInt) + val is = new Array[Long](nvals.toInt) + GRAPHBLAS.extractVectorTuplesBoolean(vec, vs, is) + vs + } } implicit val byteVectorHandler: SparseVectorHandler[Byte] = new SparseVectorHandler[Byte] { @@ -55,6 +64,14 @@ object SparseVectorHandler { def assign(vec: Buffer)(v: Byte): Unit = GRAPHBLAS.assignVectorByte(vec, null, null, v, GRBCORE.GrB_ALL, size(vec), null) + + def extractTuples(vec: Buffer): Array[Byte] = { + val nvals = GRBCORE.nvalsVector(vec) + val vs = new Array[Byte](nvals.toInt) + val is = new Array[Long](nvals.toInt) + GRAPHBLAS.extractVectorTuplesByte(vec, vs, is) + vs + } } implicit val shortVectorHandler: SparseVectorHandler[Short] = new SparseVectorHandler[Short] { @@ -66,6 +83,14 @@ object SparseVectorHandler { def assign(vec: Buffer)(v: Short): Unit = GRAPHBLAS.assignVectorShort(vec, null, null, v, GRBCORE.GrB_ALL, size(vec), null) + + def extractTuples(vec: Buffer): Array[Short] = { + val nvals = GRBCORE.nvalsVector(vec) + val vs = new Array[Short](nvals.toInt) + val is = new Array[Long](nvals.toInt) + GRAPHBLAS.extractVectorTuplesShort(vec, vs, is) + vs + } } implicit val intVectorHandler: SparseVectorHandler[Int] = new SparseVectorHandler[Int] { @@ -77,6 +102,14 @@ object SparseVectorHandler { def assign(vec: Buffer)(v: Int): Unit = GRAPHBLAS.assignVectorInt(vec, null, null, v, GRBCORE.GrB_ALL, size(vec), null) + + def extractTuples(vec: Buffer): Array[Int] = { + val nvals = GRBCORE.nvalsVector(vec) + val vs = new Array[Int](nvals.toInt) + val is = new Array[Long](nvals.toInt) + GRAPHBLAS.extractVectorTuplesInt(vec, vs, is) + vs + } } implicit val longVectorHandler: SparseVectorHandler[Long] = new SparseVectorHandler[Long] { @@ -88,6 +121,14 @@ object SparseVectorHandler { def assign(vec: Buffer)(v: Long): Unit = GRAPHBLAS.assignVectorLong(vec, null, null, v, GRBCORE.GrB_ALL, size(vec), null) + + def extractTuples(vec: Buffer): Array[Long] = { + val nvals = GRBCORE.nvalsVector(vec) + val vs = new Array[Long](nvals.toInt) + val is = new Array[Long](nvals.toInt) + GRAPHBLAS.extractVectorTuplesLong(vec, vs, is) + vs + } } implicit val floatVectorHandler: SparseVectorHandler[Float] = new SparseVectorHandler[Float] { @@ -99,6 +140,14 @@ object SparseVectorHandler { def assign(vec: Buffer)(v: Float): Unit = GRAPHBLAS.assignVectorFloat(vec, null, null, v, GRBCORE.GrB_ALL, size(vec), null) + + def extractTuples(vec: Buffer): Array[Float] = { + val nvals = GRBCORE.nvalsVector(vec) + val vs = new Array[Float](nvals.toInt) + val is = new Array[Long](nvals.toInt) + GRAPHBLAS.extractVectorTuplesFloat(vec, vs, is) + vs + } } implicit val doubleVectorHandler: SparseVectorHandler[Double] = new SparseVectorHandler[Double] { @@ -110,5 +159,13 @@ object SparseVectorHandler { def assign(vec: Buffer)(v: Double): Unit = GRAPHBLAS.assignVectorDouble(vec, null, null, v, GRBCORE.GrB_ALL, size(vec), null) + + def extractTuples(vec: Buffer): Array[Double] = { + val nvals = GRBCORE.nvalsVector(vec) + val vs = new Array[Double](nvals.toInt) + val is = new Array[Long](nvals.toInt) + GRAPHBLAS.extractVectorTuplesDouble(vec, vs, is) + vs + } } } diff --git a/graphblas-java/src/test/scala/com/github/fabianmurariu/unsafe/VectorUtils.scala b/graphblas-java/src/test/scala/com/github/fabianmurariu/unsafe/VectorUtils.scala index 799e7c1..a2607c9 100644 --- a/graphblas-java/src/test/scala/com/github/fabianmurariu/unsafe/VectorUtils.scala +++ b/graphblas-java/src/test/scala/com/github/fabianmurariu/unsafe/VectorUtils.scala @@ -39,6 +39,10 @@ trait VectorUtils { case class VectorVals[T](size: Long, vals: Vector[(Long, T)]) +// tuples for multiplication +case class VectorValsMul[T](left: VectorVals[T], right: VectorVals[T]) + + object VectorVals { implicit def fakeChooseBoolean: Gen.Choose[Boolean] = (min: Boolean, max: Boolean) => { @@ -56,7 +60,7 @@ object VectorVals { } yield (i, t) val gen = for { - size <- Gen.posNum[Long] + size <- Gen.choose(1, 100) vals <- Gen.nonEmptyContainerOf[Vector, (Long, Boolean)](genVal(size)).map(_.distinctBy(_._1)) } yield VectorVals(size, vals) @@ -78,7 +82,24 @@ object VectorVals { } } +object VectorValsMul { + implicit def arbMul[T: Gen.Choose](implicit A: Arbitrary[VectorDimensions], N: Numeric[T]): Arbitrary[VectorValsMul[T]] = { + def genVal(size: Long): Gen[(Long, T)] = for { + i <- Gen.choose(0, size - 1) + t <- Gen.oneOf[T](Gen.posNum, Gen.negNum) + } yield (i, t) + + val gen = for { + size <- Gen.choose(1, 100) + vals <- Gen.nonEmptyContainerOf[Vector, (Long, T)](genVal(size)).map(_.distinctBy(_._1)) + otherVals <- Gen.nonEmptyContainerOf[Vector, (Long, T)](genVal(size)).map(_.distinctBy(_._1)) + } yield VectorValsMul(VectorVals[T](size, vals), VectorVals(size, otherVals)) + + Arbitrary(gen) + } +} + case class VectorDimensions(size: Int) object VectorDimensions{ implicit val arb:Arbitrary[VectorDimensions] = Arbitrary(Gen.posNum[Int].map(VectorDimensions(_))) -} \ No newline at end of file +}