use vyre_foundation::ir::Program;
use vyre_primitives::bitset::zero::bitset_zero;
use vyre_primitives::graph::csr_frontier_queue::{
csr_queue_forward_traverse, frontier_queue_len_init, frontier_word_block_offsets_in_place,
frontier_word_block_offsets_to_queue_parallel, frontier_word_block_prefix_to_queue_parallel,
frontier_word_counts_scan_pass_a, frontier_words_to_queue_clear_out_parallel,
};
use vyre_primitives::graph::csr_queue_split::csr_queue_split_low_forward_traverse;
use vyre_primitives::graph::csr_queue_strided::csr_queue_strided_forward_traverse;
use crate::graph::csr_frontier_queue_scratch::{
ResidentCsrQueueMaterializer, ResidentCsrQueueTraverseKind, STRIDED_FORWARD_MIN_ROW_DEGREE,
};
#[cfg(test)]
mod tests;
const ACTIVE_QUEUE: &str = "active_queue";
const QUEUE_LEN: &str = "queue_len";
const HIGH_QUEUE: &str = "high_queue";
const HIGH_LEN: &str = "high_len";
const EDGE_OFFSETS: &str = "edge_offsets";
const EDGE_TARGETS: &str = "edge_targets";
const EDGE_KIND_MASK: &str = "edge_kind_mask";
const FRONTIER_OUT: &str = "frontier_out";
const WORD_PARTIALS: &str = "word_partials";
const BLOCK_TOTALS: &str = "block_totals";
pub(crate) fn resident_csr_queue_traverse_program(
node_count: u32,
edge_count: u32,
queue_capacity: u32,
allow_mask: u32,
kind: ResidentCsrQueueTraverseKind,
) -> Program {
match kind {
ResidentCsrQueueTraverseKind::RowSerial => csr_queue_forward_traverse(
ACTIVE_QUEUE,
QUEUE_LEN,
EDGE_OFFSETS,
EDGE_TARGETS,
EDGE_KIND_MASK,
FRONTIER_OUT,
node_count,
edge_count,
queue_capacity,
allow_mask,
),
ResidentCsrQueueTraverseKind::RowStrided => csr_queue_strided_forward_traverse(
ACTIVE_QUEUE,
QUEUE_LEN,
EDGE_OFFSETS,
EDGE_TARGETS,
EDGE_KIND_MASK,
FRONTIER_OUT,
node_count,
edge_count,
queue_capacity,
allow_mask,
),
ResidentCsrQueueTraverseKind::MixedSplit {
high_queue_capacity,
} => csr_queue_strided_forward_traverse(
HIGH_QUEUE,
HIGH_LEN,
EDGE_OFFSETS,
EDGE_TARGETS,
EDGE_KIND_MASK,
FRONTIER_OUT,
node_count,
edge_count,
high_queue_capacity,
allow_mask,
),
}
}
pub(crate) fn resident_csr_queue_split_low_program(
node_count: u32,
edge_count: u32,
queue_capacity: u32,
high_queue_capacity: u32,
allow_mask: u32,
) -> Program {
csr_queue_split_low_forward_traverse(
ACTIVE_QUEUE,
QUEUE_LEN,
EDGE_OFFSETS,
EDGE_TARGETS,
EDGE_KIND_MASK,
FRONTIER_OUT,
HIGH_QUEUE,
HIGH_LEN,
node_count,
edge_count,
queue_capacity,
high_queue_capacity,
STRIDED_FORWARD_MIN_ROW_DEGREE,
allow_mask,
)
}
pub(crate) fn resident_csr_queue_len_init_program(queue_len: &str) -> Program {
frontier_queue_len_init(queue_len)
}
pub(crate) fn resident_csr_queue_clear_frontier_out_program(words: u32) -> Program {
bitset_zero(FRONTIER_OUT, words)
}
pub(crate) fn resident_csr_queue_atomic_word_scan_program(
frontier_in: &str,
node_count: u32,
queue_capacity: u32,
) -> Program {
frontier_words_to_queue_clear_out_parallel(
frontier_in,
ACTIVE_QUEUE,
QUEUE_LEN,
FRONTIER_OUT,
node_count,
queue_capacity,
)
}
pub(crate) fn resident_csr_queue_word_counts_program(
frontier_in: &str,
node_count: u32,
) -> Program {
frontier_word_counts_scan_pass_a(frontier_in, WORD_PARTIALS, BLOCK_TOTALS, node_count)
}
pub(crate) fn resident_csr_queue_block_offsets_program(node_count: u32) -> Program {
frontier_word_block_offsets_in_place(BLOCK_TOTALS, node_count)
}
pub(crate) fn resident_csr_queue_word_prefix_queue_program(
frontier_in: &str,
node_count: u32,
queue_capacity: u32,
precomputed_block_offsets: bool,
) -> Program {
if precomputed_block_offsets {
frontier_word_block_offsets_to_queue_parallel(
frontier_in,
WORD_PARTIALS,
BLOCK_TOTALS,
ACTIVE_QUEUE,
QUEUE_LEN,
node_count,
queue_capacity,
)
} else {
frontier_word_block_prefix_to_queue_parallel(
frontier_in,
WORD_PARTIALS,
BLOCK_TOTALS,
ACTIVE_QUEUE,
QUEUE_LEN,
node_count,
queue_capacity,
)
}
}
pub(crate) struct ResidentCsrQueueMaterializerPrograms {
pub(crate) clear_frontier_out: Option<Program>,
pub(crate) queue_len_init: Option<Program>,
pub(crate) word_counts: Option<Program>,
pub(crate) word_block_offsets: Option<Program>,
pub(crate) queue: Program,
}
pub(crate) fn resident_csr_queue_materializer_programs(
frontier_in: &str,
node_count: u32,
words: u32,
queue_capacity: u32,
materializer: ResidentCsrQueueMaterializer,
precomputed_block_offsets: bool,
) -> ResidentCsrQueueMaterializerPrograms {
match materializer {
ResidentCsrQueueMaterializer::AtomicWordScan => ResidentCsrQueueMaterializerPrograms {
clear_frontier_out: None,
queue_len_init: Some(resident_csr_queue_len_init_program(QUEUE_LEN)),
word_counts: None,
word_block_offsets: None,
queue: resident_csr_queue_atomic_word_scan_program(
frontier_in,
node_count,
queue_capacity,
),
},
ResidentCsrQueueMaterializer::DeterministicWordPrefix => {
ResidentCsrQueueMaterializerPrograms {
clear_frontier_out: Some(resident_csr_queue_clear_frontier_out_program(words)),
queue_len_init: None,
word_counts: Some(resident_csr_queue_word_counts_program(
frontier_in,
node_count,
)),
word_block_offsets: precomputed_block_offsets
.then(|| resident_csr_queue_block_offsets_program(node_count)),
queue: resident_csr_queue_word_prefix_queue_program(
frontier_in,
node_count,
queue_capacity,
precomputed_block_offsets,
),
}
}
}
}