use crate::graph::GraphStorage;
use crate::traversal::step::map_steps::temporal::{describe, held_value};
use crate::value::VectorError;
use crate::value::vector::similarity::MeanAccumulator;
use crate::value::vector::vector_error;
use crate::*;
#[derive(Default, Clone)]
struct StepVectorMean;
impl fmt::Display for StepVectorMean {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str("vector_mean()")
}
}
fn not_a_vector(found: String) -> Box<TraverserError> {
vector_error("vector_mean", VectorError::NotAVector { found })
}
fn add_value<S: GraphStorage>(
context: &TraverserContext<'_, S>,
mean: &mut MeanAccumulator,
value: &TraverserValue<S>,
bulk: u64,
) -> TraverserResult<()> {
let add_property = |mean: &mut MeanAccumulator, property: &ElementProperty| match property {
ElementProperty::Null => Ok(()),
ElementProperty::Vector(vector) => mean
.add(vector, bulk)
.map_err(|error| vector_error("vector_mean", error)),
other => Err(not_a_vector(describe(other))),
};
match value {
TraverserValue::Array(items) => {
for item in items.iter() {
match held_value(context, item)? {
Ok(held) => add_property(mean, held.as_ref())?,
Err(kind) => return Err(not_a_vector(format!("a {kind}"))),
}
}
Ok(())
}
_ => match held_value(context, value)? {
Ok(held) => match held.as_ref() {
ElementProperty::Array(items) => {
items.iter().try_for_each(|item| add_property(mean, item))
}
other => add_property(mean, other),
},
Err(kind) => Err(not_a_vector(format!("a {kind}"))),
},
}
}
impl<'g, S: GraphStorage + 'g> GraphStepBarrier<'g, S> for StepVectorMean {
fn materializes(&self) -> bool {
true
}
fn process(
&self,
context: &mut TraverserContext<'_, S>,
source: Vec<Traverser<S>>,
) -> TraverserResult<Option<Traverser<S>>> {
let mut mean = MeanAccumulator::new();
for traverser in &source {
context.tick()?;
add_value(context, &mut mean, &traverser.value, traverser.bulk)?;
}
let vector = mean
.finish()
.map_err(|error| vector_error("vector_mean", error))?;
Ok(vector.map(|vector| {
Traverser::start(
context,
TraverserValue::Computed(ElementProperty::Vector(vector), None),
)
}))
}
fn clone_box(&self) -> Box<dyn GraphStepBarrier<'g, S> + 'g> {
Box::new(self.clone())
}
}
impl<'g, S: GraphStorage + 'g> GraphTraversalSource<'g, S> {
pub fn vector_mean(self) -> Self {
self.push_step(GraphStep::Barrier("vector_mean", Box::new(StepVectorMean)))
}
}
impl __ {
pub fn vector_mean<'g, S: GraphStorage + 'g>() -> AnonymousTraversal<'g, S> {
AnonymousTraversal::new().vector_mean()
}
}
impl<'g, S: GraphStorage + 'g> AnonymousTraversal<'g, S> {
pub fn vector_mean(self) -> Self {
self.push_step(GraphStep::Barrier("vector_mean", Box::new(StepVectorMean)))
}
}