Skip to content

Commit

Permalink
DFA should include tolerance ranges
Browse files Browse the repository at this point in the history
This is so we can merge DFA edges which have overlapping ranges.

Signed-off-by: Sean Young <[email protected]>
  • Loading branch information
seanyoung committed Apr 1, 2024
1 parent 6fd2aa0 commit 4c1036c
Show file tree
Hide file tree
Showing 10 changed files with 233 additions and 59 deletions.
2 changes: 1 addition & 1 deletion irp/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ fn main() {
{36k,msb,889}<1,-1|-1,1>((1,~F:1:6,T:1,D:5,F:6,^114m)*,T=1-T)
[D:0..31,F:0..127,T@:0..1=0]"#)
.expect("parse should succeed");
let dfa = irp.compile().expect("build dfa should succeed");
let dfa = irp.compile(100, 3).expect("build dfa should succeed");
// Create a decoder with 100 microsecond tolerance, 30% relative tolerance,
// and 20000 microseconds maximum gap.
let mut decoder = Decoder::new(100, 30, 20000);
Expand Down
68 changes: 48 additions & 20 deletions irp/src/build_dfa.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use super::{
build_nfa::{Action, Edge, Vertex, NFA},
build_nfa::{Action, Edge, Length, Vertex, NFA},
expression::clone_filter,
Expression, Irp,
};
Expand All @@ -24,18 +24,20 @@ struct Path {
struct DfaEdge {
from: usize,
flash: bool,
length: Rc<Expression>,
length: Length,
}

impl NFA {
/// Build the DFA from the NFA
pub fn build_dfa(&self) -> DFA {
pub fn build_dfa(&self, aeps: u32, eps: u32) -> DFA {
let mut builder = Builder {
verts: Vec::new(),
nfa_to_dfa: HashMap::new(),
edges: HashMap::new(),
nfa: self,
visited: Vec::new(),
aeps,
eps,
};

builder.build();
Expand All @@ -55,10 +57,10 @@ impl DFA {

impl Irp {
/// Generate an DFA decoder state machine for this IRP
pub fn compile(&self) -> Result<DFA, String> {
pub fn compile(&self, aeps: u32, eps: u32) -> Result<DFA, String> {
let nfa = self.build_nfa()?;

Ok(nfa.build_dfa())
Ok(nfa.build_dfa(aeps, eps))
}
}

Expand All @@ -68,6 +70,8 @@ struct Builder<'a> {
edges: HashMap<DfaEdge, usize>,
verts: Vec<Vertex>,
visited: Vec<usize>,
aeps: u32,
eps: u32,
}

impl<'a> Builder<'a> {
Expand Down Expand Up @@ -109,15 +113,30 @@ impl<'a> Builder<'a> {
fn add_input_path_to_dfa(&mut self, flash: bool, path: &[Path]) {
let from = self.nfa_to_dfa[&path[0].from];
let nfa_to = path[path.len() - 1].to;
let length = self.path_length(path);
let length = self.length_to_range(self.path_length(path));

let dfa_edge = DfaEdge {
from,
flash,
length: length.clone(),
};

let actions = self.path_actions(path, flash, length);
let mut actions = self.path_actions(path);

actions.insert(
0,
if flash {
Action::Flash {
length,
complete: true,
}
} else {
Action::Gap {
length,
complete: true,
}
},
);

if let Some(to) = self.edges.get(&dfa_edge) {
if self.verts[from]
Expand Down Expand Up @@ -156,6 +175,11 @@ impl<'a> Builder<'a> {
{
match action {
Action::Gap { length, .. } | Action::Flash { length, .. } => {
let length = match length {
Length::Expression(expr) => expr,
Length::Range(..) => unreachable!(),
};

let length = replace_vars(length, &vars);

if let Some(prev) = len {
Expand Down Expand Up @@ -184,21 +208,9 @@ impl<'a> Builder<'a> {
len.unwrap()
}

fn path_actions(&self, path: &[Path], flash: bool, length: Rc<Expression>) -> Vec<Action> {
fn path_actions(&self, path: &[Path]) -> Vec<Action> {
let mut res: Vec<Action> = Vec::new();

res.push(if flash {
Action::Flash {
length,
complete: true,
}
} else {
Action::Gap {
length,
complete: true,
}
});

for elem in path {
res.extend(self.nfa.verts[elem.to].entry.iter().cloned());
res.extend(
Expand Down Expand Up @@ -294,6 +306,22 @@ impl<'a> Builder<'a> {

node
}

fn length_to_range(&self, length: Rc<Expression>) -> Length {
if let Expression::Number(length) = length.as_ref() {
let length = *length as u32;
let min = std::cmp::min(
length.saturating_sub(self.aeps),
(length * (100 - self.eps)) / 100,
);

let max = std::cmp::min(length + self.aeps, (length * (100 + self.eps)) / 100);

Length::Range(min, max)
} else {
Length::Expression(length)
}
}
}

fn replace_vars(expr: &Rc<Expression>, vars: &HashMap<&str, Rc<Expression>>) -> Rc<Expression> {
Expand Down
38 changes: 28 additions & 10 deletions irp/src/build_nfa.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use super::{
use log::trace;
use std::{
collections::HashMap,
fmt,
ops::{Add, BitAnd, BitOr, BitXor, Neg, Not, Rem, Shl, Shr, Sub},
rc::Rc,
};
Expand All @@ -18,14 +19,20 @@ pub(crate) struct Edge {
pub actions: Vec<Action>,
}

#[derive(PartialEq, Debug, Clone)]
#[derive(PartialEq, Debug, Hash, Eq, Clone)]
pub enum Length {
Expression(Rc<Expression>),
Range(u32, u32),
}

#[derive(PartialEq, Debug, Hash, Eq, Clone)]
pub(crate) enum Action {
Flash {
length: Rc<Expression>,
length: Length,
complete: bool,
},
Gap {
length: Rc<Expression>,
length: Length,
complete: bool,
},
Set {
Expand Down Expand Up @@ -101,12 +108,12 @@ impl NFA {
let length = Rc::new(Expression::Number((*raw).into()));
let actions = vec![if flash {
Action::Flash {
length,
length: Length::Expression(length),
complete: true,
}
} else {
Action::Gap {
length,
length: Length::Expression(length),
complete: true,
}
}];
Expand Down Expand Up @@ -1144,7 +1151,7 @@ impl<'a> Builder<'a> {
self.add_edge(Edge {
dest: node,
actions: vec![Action::Flash {
length: Rc::new(Expression::Number(len)),
length: Length::Expression(Rc::new(Expression::Number(len))),
complete: last,
}],
});
Expand All @@ -1163,7 +1170,7 @@ impl<'a> Builder<'a> {
self.add_edge(Edge {
dest: node,
actions: vec![Action::Gap {
length: Rc::new(Expression::Number(len)),
length: Length::Expression(Rc::new(Expression::Number(len))),
complete: last,
}],
});
Expand Down Expand Up @@ -1193,7 +1200,7 @@ impl<'a> Builder<'a> {
self.add_edge(Edge {
dest: node,
actions: vec![Action::Flash {
length: expr,
length: Length::Expression(expr),
complete: last,
}],
});
Expand Down Expand Up @@ -1232,7 +1239,7 @@ impl<'a> Builder<'a> {
self.add_edge(Edge {
dest: node,
actions: vec![Action::Gap {
length: expr,
length: Length::Expression(expr),
complete: last,
}],
});
Expand Down Expand Up @@ -1263,7 +1270,9 @@ impl<'a> Builder<'a> {
self.add_edge(Edge {
dest: node,
actions: vec![Action::Gap {
length: Rc::new(Expression::Identifier("$extent".into())),
length: Length::Expression(Rc::new(Expression::Identifier(
"$extent".into(),
))),
complete: last,
}],
});
Expand Down Expand Up @@ -1570,3 +1579,12 @@ impl<'a> Builder<'a> {
new.unwrap_or_else(|| expr.clone())
}
}

impl fmt::Display for Length {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Length::Expression(e) => write!(f, "{e}"),
Length::Range(min, max) => write!(f, "{min}..{max}"),
}
}
}
Loading

0 comments on commit 4c1036c

Please sign in to comment.