use std::marker::PhantomData;
use cugraph_sys::{
cugraph_similarity_result_get_similarity, cugraph_similarity_result_get_vertex_pairs, cugraph_similarity_result_t,
cugraph_type_erased_device_array_view_t,
};
use crate::{
array::RawDeviceArrayView,
cuda::{DeviceResourceKind, drop_device_resource},
error::{Error, Result, require_non_null},
handle::ResourceHandleLease,
similarity::VertexPairs,
structure::typed_results::{ScoreValues, VertexIds},
};
pub(crate) struct SimilarityResultInner {
raw: *mut cugraph_similarity_result_t,
pairs: VertexPairs,
device: i32,
_resource_handle_lease: Option<ResourceHandleLease>,
_nosend_nosync: PhantomData<*mut ()>,
}
impl SimilarityResultInner {
pub(crate) unsafe fn from_pairwise_raw(
raw: *mut cugraph_similarity_result_t,
pairs: VertexPairs,
device: i32,
operation: &'static str,
resource_handle_lease: Option<ResourceHandleLease>,
) -> Result<Self> {
let raw = require_non_null(raw, operation, "similarity_result")?;
Ok(Self { raw, pairs, device, _resource_handle_lease: resource_handle_lease, _nosend_nosync: PhantomData })
}
pub(crate) unsafe fn from_all_pairs_raw(
raw: *mut cugraph_similarity_result_t,
device: i32,
operation: &'static str,
resource_handle_lease: Option<ResourceHandleLease>,
) -> Result<Self> {
let raw = require_non_null(raw, operation, "similarity_result")?;
let pairs_raw = match require_non_null(
unsafe { cugraph_similarity_result_get_vertex_pairs(raw) },
operation,
"vertex_pairs",
) {
Ok(pairs_raw) => pairs_raw,
Err(error) => {
let mut raw = raw;
drop_device_resource(&mut raw, device, operation, DeviceResourceKind::SimilarityResult);
return Err(error);
},
};
let pairs = unsafe { VertexPairs::from_raw(pairs_raw, device, operation, resource_handle_lease.clone()) }?;
Ok(Self { raw, pairs, device, _resource_handle_lease: resource_handle_lease, _nosend_nosync: PhantomData })
}
fn raw_view(
&self,
getter: unsafe extern "C" fn(*mut cugraph_similarity_result_t) -> *mut cugraph_type_erased_device_array_view_t,
operation: &'static str,
pointer_name: &'static str,
) -> Result<RawDeviceArrayView<'_>> {
let view_ptr = require_non_null(
unsafe { getter(self.raw) },
operation,
pointer_name,
)?;
unsafe { RawDeviceArrayView::from_owned_view(view_ptr, Some(self.device), operation, pointer_name) }
}
fn scores(&self, operation: &'static str) -> Result<ScoreValues<'_>> {
ScoreValues::from_raw(self.raw_view(cugraph_similarity_result_get_similarity, operation, "similarity")?)
}
fn vertex_pairs(&self) -> &VertexPairs {
&self.pairs
}
}
impl Drop for SimilarityResultInner {
fn drop(&mut self) {
drop_device_resource(
&mut self.raw,
self.device,
"SimilarityResultInner::drop",
DeviceResourceKind::SimilarityResult,
);
}
}
macro_rules! define_similarity_result {
($name:ident, $score_op:literal, $df_fn:ident) => {
pub struct $name(pub(crate) SimilarityResultInner);
impl std::fmt::Debug for $name {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct(stringify!($name)).finish_non_exhaustive()
}
}
impl $name {
pub(crate) fn from_inner(inner: SimilarityResultInner) -> Self {
Self(inner)
}
pub fn first(&self) -> Result<VertexIds<'_>> {
self.0.vertex_pairs().first()
}
pub fn second(&self) -> Result<VertexIds<'_>> {
self.0.vertex_pairs().second()
}
pub fn scores(&self) -> Result<ScoreValues<'_>> {
self.0.scores($score_op)
}
pub fn vertex_pairs(&self) -> &VertexPairs {
self.0.vertex_pairs()
}
pub fn to_dataframe(&self, runtime: &cudf::Runtime) -> Result<cudf::DataFrame> {
crate::cudf_interop::$df_fn(self, runtime)
.map_err(|error: Error| error.with_operation(concat!(stringify!($name), "::to_dataframe")))
}
}
};
}
define_similarity_result!(
JaccardSimilarityResult,
"JaccardSimilarityResult::scores",
jaccard_similarity_result_to_dataframe
);
define_similarity_result!(
SorensenSimilarityResult,
"SorensenSimilarityResult::scores",
sorensen_similarity_result_to_dataframe
);
define_similarity_result!(
OverlapSimilarityResult,
"OverlapSimilarityResult::scores",
overlap_similarity_result_to_dataframe
);
define_similarity_result!(
CosineSimilarityResult,
"CosineSimilarityResult::scores",
cosine_similarity_result_to_dataframe
);
#[cfg(test)]
mod tests {
use std::ptr;
use super::*;
use crate::error::ErrorKind;
#[test]
fn similarity_result_from_raw_rejects_null() {
let err =
match unsafe { SimilarityResultInner::from_all_pairs_raw(ptr::null_mut(), 0, "test_similarity", None) } {
Err(err) => err,
Ok(_) => panic!("null must be rejected"),
};
assert_eq!(err.kind(), ErrorKind::Unexpected);
assert_eq!(err.operation(), "test_similarity");
}
}