use std::{fmt::Debug, ptr};
use cugraph_sys::{cugraph_error_t, cugraph_paths_result_t, cugraph_sssp};
use crate::{
cudf_interop::sssp_result_to_dataframe,
error::{Error, ErrorKind, Result, check_error},
graph::{Forward, Graph},
handle::EnteredContext,
params::NonNegativeF64,
structure::{
VertexSelection,
typed_results::{Distances, VertexIds},
},
traversal::paths::{ExtractPathsResult, PathsResult, extract_paths},
types::{CugraphElement, to_bool_t},
};
#[derive(Debug, Clone, Copy, Default)]
#[must_use]
pub struct SsspParams {
pub cutoff: Option<NonNegativeF64>,
pub compute_predecessors: bool,
pub do_expensive_check: bool,
}
impl SsspParams {
pub fn with_predecessors(mut self) -> Self {
self.compute_predecessors = true;
self
}
pub fn with_cutoff(mut self, cutoff: NonNegativeF64) -> Self {
self.cutoff = Some(cutoff);
self
}
pub fn with_expensive_check(mut self) -> Self {
self.do_expensive_check = true;
self
}
pub fn cutoff(&self) -> Option<NonNegativeF64> {
self.cutoff
}
pub fn compute_predecessors(&self) -> bool {
self.compute_predecessors
}
pub fn do_expensive_check(&self) -> bool {
self.do_expensive_check
}
}
pub(crate) fn sssp<V>(
handle: &EnteredContext<'_>,
graph: &mut Graph<Forward>,
source: V,
params: &SsspParams,
) -> Result<SsspResult>
where
V: CugraphElement + TryInto<usize> + Copy + Debug,
{
let source = source.try_into().map_err(|_| {
Error::new(ErrorKind::InvalidInput, "sssp")
.with_message(format!("SSSP source vertex {source:?} is negative; SSSP requires a non-negative vertex id"))
.with_context("source", format!("{source:?}"))
})?;
let cutoff = params.cutoff.map(f64::from).unwrap_or(f64::MAX);
let mut result: *mut cugraph_paths_result_t = ptr::null_mut();
let mut error: *mut cugraph_error_t = ptr::null_mut();
let graph_ptr = graph.as_ptr(handle, "sssp")?;
unsafe {
let code = cugraph_sssp(
handle.handle_ptr(),
graph_ptr,
source,
cutoff,
to_bool_t(params.compute_predecessors),
to_bool_t(params.do_expensive_check),
&mut result,
&mut error,
);
check_error(code, error, handle.device(), "sssp")?;
}
let paths = unsafe { PathsResult::from_raw(result, handle.device(), "sssp", handle.runtime_bound_lease()) }?;
Ok(SsspResult { paths })
}
pub struct SsspResult {
pub(crate) paths: PathsResult,
}
impl std::fmt::Debug for SsspResult {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("SsspResult").finish_non_exhaustive()
}
}
impl SsspResult {
pub fn vertex_ids(&self) -> Result<VertexIds<'_>> {
self.paths.vertex_ids("SsspResult::vertex_ids")
}
pub fn distances(&self) -> Result<Distances<'_>> {
self.paths.distances("SsspResult::distances")
}
pub fn predecessors(&self) -> Result<Option<VertexIds<'_>>> {
self.paths.predecessors("SsspResult::predecessors")
}
pub fn extract_paths<'a, V>(
&self,
handle: &EnteredContext<'_>,
graph: &mut Graph<Forward>,
sources: impl Into<VertexSelection<'a, V>>,
destinations: impl Into<VertexSelection<'a, V>>,
) -> Result<ExtractPathsResult>
where
V: CugraphElement + TryInto<i64> + Copy + Debug + 'a,
<V as TryInto<i64>>::Error: Debug,
{
extract_paths(handle, graph, &self.paths, sources, destinations, "SsspResult::extract_paths")
}
pub fn to_dataframe(&self, runtime: &cudf::Runtime) -> Result<cudf::DataFrame> {
sssp_result_to_dataframe(self, runtime).map_err(|e: Error| e.with_operation("SsspResult::to_dataframe"))
}
}