use crate::{
domain::{
Activity, Backtrack, Domain, Extrapolator, Keyed, KeyedSpace, Keyring, PartialKeyed,
Reversible,
},
error::{StdError, ThisError},
graph::{Edge, Graph},
};
use std::borrow::Borrow;
#[derive(Debug, Clone)]
pub struct GraphMotion<S, G, E> {
pub space: S,
pub graph: G,
pub extrapolator: E,
}
impl<S, G, E> GraphMotion<S, G, E> {
fn update_state_waypoint(&self, waypoint: S::Waypoint, original_state: &S::State) -> S::State
where
S: KeyedSpace<G::Key>,
G: Graph,
G::Key: Clone,
{
let vertex = self
.space
.vertex_of(self.space.key_for(&original_state).borrow())
.clone();
self.space.make_keyed_state(vertex, waypoint)
}
}
impl<S, G, E> Domain for GraphMotion<S, G, E>
where
S: KeyedSpace<G::Key>,
G: Graph,
E: Extrapolator<S::Waypoint, G::Vertex, G::EdgeAttributes, G::Key>,
{
type State = S::State;
type Error = GraphMotionError<G::Key, E::ExtrapolationError>;
}
impl<S, G, E> Activity<S::State> for GraphMotion<S, G, E>
where
S: KeyedSpace<G::Key>,
S::Key: Borrow<G::Key>,
S::State: Clone,
G: Graph,
G::Key: Clone,
G::EdgeAttributes: Clone,
E: Extrapolator<S::Waypoint, G::Vertex, G::EdgeAttributes, G::Key>,
E::ExtrapolationError: StdError,
{
type Action = E::Extrapolation;
type ActivityError = GraphMotionError<G::Key, E::ExtrapolationError>;
type Choices<'a>
= GraphMotionChoices<'a, S, G, E>
where
Self: 'a,
Self::Action: 'a,
Self::ActivityError: 'a,
S::State: 'a,
G::EdgeAttributes: 'a,
G::Key: 'a,
S::State: 'a;
fn choices<'a>(&'a self, from_state: S::State) -> Self::Choices<'a>
where
Self: 'a,
Self::Action: 'a,
Self::ActivityError: 'a,
S::State: 'a,
G::Key: 'a,
{
let from_vertex = self.space.key_for(&from_state).borrow().borrow().clone();
let edges_from_vertex = self.graph.edges_from_vertex(&from_vertex).into_iter();
GraphMotionChoices {
current_iter: None,
edges_from_vertex,
motion: &self,
from_state,
}
}
}
impl<S, G, E> Keyed for GraphMotion<S, G, E>
where
S: Keyed,
{
type Key = S::Key;
}
impl<S, G, E> PartialKeyed for GraphMotion<S, G, E>
where
S: PartialKeyed,
{
type PartialKey = S::PartialKey;
}
impl<S, G, E> Keyring<S::State> for GraphMotion<S, G, E>
where
S: KeyedSpace<G::Key>,
G: Graph,
{
type KeyRef<'a>
= S::KeyRef<'a>
where
Self: 'a,
S::State: 'a;
fn key_for<'a>(&'a self, state: &'a S::State) -> Self::KeyRef<'a>
where
Self: 'a,
S::State: 'a,
{
self.space.key_for(state)
}
}
impl<S, G, E> Reversible for GraphMotion<S, G, E>
where
S: Reversible,
G: Reversible,
E: Reversible,
{
type ReversalError =
GraphMotionReversalError<S::ReversalError, G::ReversalError, E::ReversalError>;
fn reversed(&self) -> Result<Self, Self::ReversalError> {
Ok(GraphMotion {
space: self
.space
.reversed()
.map_err(GraphMotionReversalError::Space)?,
graph: self
.graph
.reversed()
.map_err(GraphMotionReversalError::Graph)?,
extrapolator: self
.extrapolator
.reversed()
.map_err(GraphMotionReversalError::Extrapolator)?,
})
}
}
impl<S, G, E> Backtrack<S::State, E::Extrapolation> for GraphMotion<S, G, E>
where
S: KeyedSpace<G::Key>,
G: Graph,
G::Key: Clone,
G::EdgeAttributes: Clone,
E: Extrapolator<S::Waypoint, G::Vertex, G::EdgeAttributes, G::Key>
+ Backtrack<S::Waypoint, E::Extrapolation>,
{
type BacktrackError = E::BacktrackError;
fn flip_endpoints(
&self,
initial_reverse_state: &S::State,
final_reverse_state: &S::State,
) -> Result<(S::State, S::State), Self::BacktrackError> {
self.extrapolator
.flip_endpoints(
self.space.waypoint(&initial_reverse_state).borrow(),
self.space.waypoint(&final_reverse_state).borrow(),
)
.map(|(initial_forward_waypoint, final_forward_waypoint)| {
(
self.update_state_waypoint(initial_forward_waypoint, final_reverse_state),
self.update_state_waypoint(final_forward_waypoint, initial_reverse_state),
)
})
}
fn backtrack(
&self,
parent_forward_state: &S::State,
parent_reverse_state: &S::State,
reverse_action: &E::Extrapolation,
child_reverse_state: &S::State,
) -> Result<(E::Extrapolation, S::State), Self::BacktrackError> {
self.extrapolator
.backtrack(
self.space.waypoint(&parent_forward_state).borrow(),
self.space.waypoint(&parent_reverse_state).borrow(),
reverse_action,
self.space.waypoint(&child_reverse_state).borrow(),
)
.map(|(action, waypoint)| {
let state = self.update_state_waypoint(waypoint, child_reverse_state);
(action, state)
})
}
}
pub struct GraphMotionChoices<'a, S, G, E>
where
S: KeyedSpace<G::Key>,
S::Key: Borrow<G::Key>,
S::State: Clone,
G: Graph,
G::Key: Clone,
G::EdgeAttributes: Clone,
E: Extrapolator<S::Waypoint, G::Vertex, G::EdgeAttributes, G::Key>,
E::ExtrapolationError: StdError,
{
current_iter:
Option<Extrapolations<G::Key, <E::ExtrapolationIter<'a> as IntoIterator>::IntoIter>>,
edges_from_vertex: <G::EdgeIter<'a> as IntoIterator>::IntoIter,
motion: &'a GraphMotion<S, G, E>,
from_state: S::State,
}
impl<'a, S, G, E> Iterator for GraphMotionChoices<'a, S, G, E>
where
S: KeyedSpace<G::Key>,
S::Key: Borrow<G::Key>,
S::State: Clone,
G: Graph,
G::Key: Clone,
G::EdgeAttributes: Clone,
E: Extrapolator<S::Waypoint, G::Vertex, G::EdgeAttributes, G::Key>,
E::ExtrapolationError: StdError,
{
type Item =
Result<(E::Extrapolation, S::State), GraphMotionError<G::Key, E::ExtrapolationError>>;
fn next(&mut self) -> Option<Self::Item> {
loop {
if let Some(current_iter) = self.current_iter.as_mut() {
if let Some(result) = current_iter.extrapolations.next() {
match result {
Ok((action, waypoint)) => {
let to_vertex = current_iter.to_vertex.clone();
let state = self.motion.space.make_keyed_state(to_vertex, waypoint);
return Some(Ok((action, state)));
}
Err(err) => {
return Some(Err(GraphMotionError::Extrapolator(err)));
}
}
}
}
self.current_iter = None;
if let Some(edge) = self.edges_from_vertex.next() {
let to_vertex = edge.to_vertex();
let Some(v) = self.motion.graph.vertex(to_vertex) else {
return Some(Err(GraphMotionError::MissingVertex(to_vertex.clone())));
};
let extrapolations = self.motion.extrapolator.extrapolate(
self.motion.space.waypoint(&self.from_state).borrow(),
v.borrow(),
&edge.attributes(),
(
Some(
self.motion
.space
.key_for(&self.from_state)
.borrow()
.borrow(),
),
Some(&to_vertex),
),
);
self.current_iter = Some(Extrapolations {
to_vertex: to_vertex.clone(),
extrapolations: extrapolations.into_iter(),
});
continue;
}
return None;
}
}
}
struct Extrapolations<K, E> {
to_vertex: K,
extrapolations: E,
}
#[derive(ThisError, Debug)]
pub enum GraphMotionError<K, E> {
#[error("The graph is missing the requested vertex [{0:?}]")]
MissingVertex(K),
#[error("The extrapolator experienced an error:\n{0:?}")]
Extrapolator(E),
}
#[derive(ThisError, Debug)]
pub enum GraphMotionReversalError<S, G, E> {
#[error("The space had a reversal error:\n{0:?}")]
Space(S),
#[error("The graph had a reversal error:\n{0:?}")]
Graph(G),
#[error("The extrapolator had a reversal error:\n{0:?}")]
Extrapolator(E),
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{
graph::SimpleGraph,
motion::r2::{DiscreteSpaceTimeR2, LineFollow, Position},
};
use std::sync::Arc;
#[test]
fn test_graph_motion_construction() {
let graph = SimpleGraph::from_iters(
[
Position::new(0.0, 0.0),
Position::new(1.0, 0.0),
Position::new(3.0, -1.0),
],
[(0, 1, ()), (1, 0, ()), (0, 2, ()), (2, 1, ())],
);
let graph = Arc::new(graph);
let motion = GraphMotion {
space: DiscreteSpaceTimeR2::<usize>::default(),
graph,
extrapolator: LineFollow::new(1.0),
};
println!("{motion:?}");
}
}