diff options
Diffstat (limited to 'chain/src')
| -rw-r--r-- | chain/src/atom/default.rs | 170 | ||||
| -rw-r--r-- | chain/src/atom/mod.rs | 18 | ||||
| -rw-r--r-- | chain/src/default.rs | 936 | ||||
| -rw-r--r-- | chain/src/item/default/mod.rs | 17 | ||||
| -rw-r--r-- | chain/src/lib.rs | 72 |
5 files changed, 655 insertions, 558 deletions
diff --git a/chain/src/atom/default.rs b/chain/src/atom/default.rs index 7e50868..1870aa1 100644 --- a/chain/src/atom/default.rs +++ b/chain/src/atom/default.rs @@ -82,6 +82,19 @@ pub struct DefaultAtom { virtual_nodes: VirtualMap, virtual_traces: VirtualTraceMap, virtual_frags: VirtualFragMap, + // /// `left_corners[x][y]` is true if and only if the non-terminal + // /// `y` is in the reflexive-transitive closure of left corners of + // /// the non-terminal `x`: `y` can start a derivation from `x`, + // /// after only nullable symbols. + // left_corners: Vec<Vec<bool>>, + /// `left_corners[x][y]` is true if and only if the non-terminal + /// `y` is in the reflexive-transitive closure of left corners of + /// the non-terminal `x`: `y` can start a derivation from `x`, + /// after only nullable symbols. + left_corners: Vec<Vec<bool>>, + /// `acc_by_nt[x][node]` is true if and only if `node` reaches the + /// end of the non-terminal `x` by nullable edges. + acc_by_nt: Vec<Vec<bool>>, } impl DefaultAtom { @@ -209,21 +222,25 @@ impl Display for DefaultAtom { // LabelGraph, in order to implement Nfa. impl LabelGraph<LabelType<TNT>> for DefaultAtom { - type Iter<'b> = <DefaultNFA<LabelType<TNT>> as LabelGraph<LabelType<TNT>>>::Iter<'b> + type Iter<'b> + = <DefaultNFA<LabelType<TNT>> as LabelGraph<LabelType<TNT>>>::Iter<'b> where Self: 'b; - type TupleIter<'b> = <DefaultNFA<LabelType<TNT>> as LabelGraph<LabelType<TNT>>>::TupleIter<'b> + type TupleIter<'b> + = <DefaultNFA<LabelType<TNT>> as LabelGraph<LabelType<TNT>>>::TupleIter<'b> where Self: 'b, DOption<TNT>: 'b; - type LabelIter<'b> = <DefaultNFA<LabelType<TNT>> as LabelGraph<LabelType<TNT>>>::LabelIter<'b> + type LabelIter<'b> + = <DefaultNFA<LabelType<TNT>> as LabelGraph<LabelType<TNT>>>::LabelIter<'b> where Self: 'b, DOption<TNT>: 'b; - type EdgeLabelIter<'a> = <DefaultNFA<LabelType<TNT>> as LabelGraph<LabelType<TNT>>>::EdgeLabelIter<'a> + type EdgeLabelIter<'a> + = <DefaultNFA<LabelType<TNT>> as LabelGraph<LabelType<TNT>>>::EdgeLabelIter<'a> where Self: 'a, DOption<TNT>: 'a; @@ -402,6 +419,99 @@ impl DefaultAtom { } // Perform nulling and remove_epsilon at the same time. + // Acceptance is relative to the frame: a state may reach the + // end of one non-terminal through nullable edges without + // reaching the end of another. So for every non-terminal `x` + // compute the states that reach the end of `x` by nullable + // edges, in the same way as `accepting_vec`. + let acc_by_nt: Vec<Vec<bool>> = (0..grammar.non_num()) + .map(|x| -> Result<Vec<bool>, GrammarError> { + let mut result: Vec<bool> = vec![false; nfa_len]; + + *result.get_mut(accumulators[x] + 1).unwrap() = true; + + let mut updated = true; + + while updated { + updated = false; + + for node in nfa.nodes() { + if result[node] { + continue; + } + + 'label_loop: for (label, target_iter) in nfa + .labels_of(node) + .map_err(|_| GrammarError::IndexOutOfBounds(node, nfa_len))? + { + if label_is_nullable(*label) { + for target in target_iter { + if result[target] { + result[node] = true; + updated = true; + + break 'label_loop; + } + } + } + } + } + } + + Ok(result) + }) + .collect::<Result<_, _>>()?; + + // Left corners must be computed before taking the null + // closure, whose edges would hide the structure we are + // following. + let left_corners: Vec<Vec<bool>> = { + let rule_positions = grammar.total() * 2; + let nt_num = grammar.non_num(); + + let mut result = vec![vec![false; nt_num]; nt_num]; + + for x in 0..nt_num { + let mut seen = vec![false; nfa_len]; + let mut stack = vec![*accumulators.get(x).unwrap()]; + + result[x][x] = true; + + while let Some(node) = stack.pop() { + if std::mem::replace(&mut seen[node], true) { + continue; + } + + if node < rule_positions { + result[x][grammar.get_rule_num(node / 2)?] = true; + } + + // The edges out of the end of a rule lead to the + // rules which have that non-terminal as a left + // corner, not to the left corners of `x`. + if node % 2 == 1 && accumulators_set.contains(&(node - 1)) { + continue; + } + + for (label, target_iter) in nfa + .labels_of(node) + .map_err(|_| GrammarError::IndexOutOfBounds(node, nfa_len))? + { + if let Some(TNT::Non(y)) = *label.get_value() { + result[x][y] = true; + stack.push(*accumulators.get(y).unwrap()); + } + + if label_is_nullable(*label) { + stack.extend(target_iter); + } + } + } + } + + result + }; + nfa.closure( label_is_nullable, true, @@ -548,15 +658,13 @@ impl DefaultAtom { .or_default() .insert(rule, frag); - // Those left-linearly expanded arrows should - // not affect the nullability of the virtual - // nodes. - if !label.is_left_p() { - accepting = accepting - || *accepting_vec.get(child).ok_or( - GrammarError::IndexOutOfBounds(child, accepting_vec.len()), - )?; - } + // The virtual node accepts if some child + // reaches the end of `nt`. + accepting = accepting + || *acc_by_nt + .get(nt) + .and_then(|row| row.get(child)) + .ok_or(GrammarError::IndexOutOfBounds(child, nfa_len))?; if let Some((_, old_accepting)) = terminals_map.get_mut(&t) { *old_accepting = *old_accepting || accepting; @@ -638,6 +746,8 @@ impl DefaultAtom { accepting_vec, virtual_traces, virtual_frags, + acc_by_nt, + left_corners, }) } @@ -732,7 +842,8 @@ impl Atom for DefaultAtom { )) } - type Iter<'a> = Copied<Iter<'a, usize>> + type Iter<'a> + = Copied<Iter<'a, usize>> where Self: 'a; @@ -747,6 +858,37 @@ impl Atom for DefaultAtom { fn accepting_len(&self) -> usize { self.accepting_vec.len() } + + fn is_accepting_in(&self, frame_nt: usize, node_id: usize) -> Result<bool, GrammarError> { + if node_id < self.grammar.total() * 2 { + self.acc_by_nt + .get(frame_nt) + .and_then(|row| row.get(node_id)) + .copied() + .ok_or(GrammarError::IndexOutOfBounds( + node_id, + self.accepting_vec.len(), + )) + } else { + self.is_accepting(node_id) + } + } + + fn allowed_in_frame(&self, frame_nt: usize, node_id: usize) -> bool { + if node_id >= self.grammar.total() * 2 { + return true; + } + + match self.grammar.get_rule_num(node_id / 2) { + Ok(owner) => self + .left_corners + .get(frame_nt) + .and_then(|row| row.get(owner)) + .copied() + .unwrap_or(true), + _ => true, + } + } } #[cfg(test)] diff --git a/chain/src/atom/mod.rs b/chain/src/atom/mod.rs index 4b3bfce..1fdbbd1 100644 --- a/chain/src/atom/mod.rs +++ b/chain/src/atom/mod.rs @@ -35,6 +35,24 @@ pub trait Atom: Nfa<LabelType<TNT>> + Deref<Target = Grammar> { /// Return the bound for `is_accepting`. fn accepting_len(&self) -> usize; + + /// Tell whether a node is accepting inside a frame of the + /// non-terminal `frame_nt`, that is to say, whether reaching the + /// node completes `frame_nt`. + /// + /// For a rule position this is not the same as `is_accepting`, + /// since the states are shared by all non-terminals. For other + /// nodes, virtual nodes included, it is the same. + fn is_accepting_in(&self, frame_nt: usize, node_id: usize) -> Result<bool, GrammarError>; + + /// Tell whether, inside a frame of the non-terminal `frame_nt`, + /// we are allowed to move into the node `node_id`. + /// + /// The states of the automaton are shared by all non-terminals, + /// so a rule position is allowed only if the non-terminal owning + /// it is a left corner of `frame_nt`. Other nodes are always + /// allowed. + fn allowed_in_frame(&self, frame_nt: usize, node_id: usize) -> bool; } pub mod default; diff --git a/chain/src/default.rs b/chain/src/default.rs index db42ef8..7ab2636 100644 --- a/chain/src/default.rs +++ b/chain/src/default.rs @@ -1,3 +1,4 @@ +#![allow(unused)] //! This file provides a default implementation of the //! [`Chain`][crate::Chain] trait. //! @@ -130,7 +131,7 @@ impl Default for DerIterIndex { } /// A complex type used for storing values of edges with two layers. -type SecondTypeValue = (PaVi, bool, Vec<(Roi, usize)>); +type SecondTypeValue = (PaVi, bool, usize, Vec<(Roi, usize)>); /// An iterator of TwoLayers. #[derive(Debug, Default)] @@ -159,13 +160,14 @@ impl DerIter { label: usize, forest_source: PaVi, accepting: bool, + frame_nt: usize, edges: Vec<(Roi, usize)>, ) { - if let Some((_, _, vec)) = self.seconds.get_mut(&label) { + if let Some((_, _, _, vec)) = self.seconds.get_mut(&label) { vec.extend(edges); } else { self.seconds - .insert(label, (forest_source, accepting, edges)); + .insert(label, (forest_source, accepting, frame_nt, edges)); self.second_array.push(label); } @@ -180,10 +182,18 @@ impl Iterator for DerIter { match self.index { DerIterIndex::Map(index) => { if let Some(key) = self.second_array.get(index) { - if let Some((forest_source, accepting, edges)) = self.seconds.remove(key) { + if let Some((forest_source, accepting, frame_nt, edges)) = + self.seconds.remove(key) + { self.index = DerIterIndex::Map(index + 1); - Some(TwoLayers::Two(*key, forest_source, accepting, edges)) + Some(TwoLayers::Two( + *key, + forest_source, + accepting, + frame_nt, + edges, + )) } else { // this should not happen dbg!("a key does not exist in the hashmap: something is wrong when taking derivatives"); @@ -222,6 +232,7 @@ pub struct DefaultChain { forest: DefaultForest<ForestLabel<GrammarLabel>>, accepting_vec: Vec<bool>, accepting_sources: Vec<PaVi>, + recording: bool, } // TODO: Implement saving the chain on disk, so that we do not have to @@ -389,43 +400,27 @@ impl LabelExtGraph<Edge> for DefaultChain { #[cfg(debug_assertions)] assert_eq!(new, accepting_len); - let mut updated = false; + // The node is accepting if and only if some accepting + // label has an accepting target. The result must not + // depend on the order in which the labels are visited. - for (label, child_iter) in self.graph.labels_of(new)? { - let old_accepting = { - let mut result = false; - for child in child_iter { - if *self - .accepting_vec - .get(child) - .ok_or(GError::IndexOutOfBounds(child, accepting_len))? - { - result = true; - break; - } - } - - result - }; - - if !old_accepting { - self.accepting_vec.push(false); - updated = true; - - break; + let mut accepting = false; + 'label_loop: for (label, child_iter) in self.graph.labels_of(new)? { + if !label.is_accepting() { + continue; } - - if label.is_accepting() { - self.accepting_vec.push(true); - updated = true; - - break; + for child in child_iter { + if *self + .accepting_vec + .get(child) + .ok_or(GError::IndexOutOfBounds(child, accepting_len))? + { + accepting = true; + break 'label_loop; + } } } - - if !updated { - self.accepting_vec.push(false); - } + self.accepting_vec.push(accepting); } Ok(new) @@ -452,7 +447,8 @@ impl Chain for DefaultChain { builder.add_edge( first, root, - Edge::new(empty_state, Default::default(), initial_nullable), + Edge::new(empty_state, Default::default(), initial_nullable) + .with_frame_nt(START_NONTERMINAL), )?; let graph = builder.build(); @@ -471,6 +467,8 @@ impl Chain for DefaultChain { let accepting_sources = Vec::new(); + let recording = false; + Ok(Self { graph, atom, @@ -479,6 +477,7 @@ impl Chain for DefaultChain { forest, accepting_vec, accepting_sources, + recording, }) } @@ -540,15 +539,8 @@ impl Chain for DefaultChain { /// /// The format is as follows: /// - /// `(graph, atom, forest, accepting_vec, forest_source, new_source)` - type GeneratorInput<'a> = ( - &'a DLGraph<Edge>, - &'a DefaultAtom, - &'a DefaultForest<ForestLabel<GrammarLabel>>, - &'a [bool], - PaVi, - PaVi, - ); + /// `(graph, atom, accepting_vec, current_node)` + type GeneratorInput<'a> = (&'a DLGraph<Edge>, &'a DefaultAtom, &'a [bool], usize); /// A helper function to generate edges to join. /// @@ -562,13 +554,16 @@ impl Chain for DefaultChain { /// to save some allocations. fn generate_edges( input: GeneratorInput<'_>, + base_edge: &Edge, mut child_iter: impl ExactSizeIterator<Item = usize> + Clone, atom_child_iter: impl Iterator<Item = usize> + Clone, mut output: impl AsMut<Vec<(Roi, usize)>>, ) -> Result<bool, Error> { let mut accepting = false; - let (graph, atom, _forest, accepting_vec, pavi, true_pavi) = input; + let (graph, atom, accepting_vec, _current) = input; + + let frame_nt = base_edge.frame_nt(); // First check the values from iterators are all valid. let graph_len = graph.nodes_len(); @@ -616,17 +611,6 @@ impl Chain for DefaultChain { }) .sum::<usize>(); - // for atom_child in atom_child_iter.clone() { - // let atom_child_accepting = atom.is_accepting(atom_child).unwrap(); - - // num += child_iter.len(); - - // if atom_child_accepting { - // accepting = true; - // num += child_iter_total_degree; - // } - // } - let num = num; let output = output.as_mut(); @@ -636,10 +620,12 @@ impl Chain for DefaultChain { // now push into output for atom_child in atom_child_iter { - let atom_child_accepting = atom.is_accepting(atom_child).unwrap(); + let atom_child_accepting = atom.is_accepting_in(frame_nt, atom_child).unwrap(); let atom_child_empty_node = atom.is_empty_node(atom_child).unwrap(); - let roi = Edge::new(atom_child, pavi, atom_child_accepting).into(); + let roi = Edge::new(atom_child, PaVi::default(), atom_child_accepting) + .with_frame_nt(frame_nt) + .into(); if atom_child_empty_node { output.extend(child_iter.clone().map(|child| (child.into(), child))); @@ -650,15 +636,8 @@ impl Chain for DefaultChain { if atom_child_accepting { for child in child_iter.clone() { for (child_label, child_child) in graph.labels_of(child).unwrap() { - let mut new_label = *child_label; - - new_label.set_true_source(true_pavi); - // new_label.set_forest_source(pavi); - output.extend( - std::iter::repeat(new_label.into()) - .take(child_child.len()) - .zip(child_child), + child_child.map(|child_child| ((*child_label).into(), child_child)), ); } } @@ -670,22 +649,18 @@ impl Chain for DefaultChain { Ok(accepting) } - if !no_item - && self.forest.nodes_len() > 2 - && matches!(self.forest.degree(1), Ok(d) if d > 0) - { - // dbg!(self.forest.vertex_label(1)?, self.atom.empty()); - if let Ok(Some(label)) = self.forest.vertex_label(1) { - if label.label().label().rule().map(|n| n << 1) == Some(self.atom.empty()) { - self.forest.remove_node(1)?; - } + self.recording = !no_item; + + if !no_item { + if pos == 0 { + // The start of the frame of the initial edge. + + // TODO } } let mut der_iter = DerIter::default(); - let mut accepting_pavi: HashSet<PaVi> = HashSet::new(); - for (label, child_iter) in self.graph.labels_of(self.current)? { for (atom_label, atom_child_iter) in self.atom.labels_of(label.label())? { if atom_label.is_left_p() { @@ -694,55 +669,35 @@ impl Chain for DefaultChain { continue; } - let atom_moved = atom_label.get_moved(); + // We do not move into the rules of non-terminals that + // are not left corners of the frame. + let frame_nt = label.frame_nt(); + let atom_children: Vec<usize> = atom_child_iter + .filter(|child| self.atom.allowed_in_frame(frame_nt, *child)) + .collect(); + + if atom_children.is_empty() { + continue; + } + + let atom_child_iter = atom_children.iter().copied(); + + let generator_input = ( + &self.graph, + &self.atom, + self.accepting_vec.as_slice(), + self.current, + ); match *atom_label.get_value() { Some(Ter(ter)) if ter == t => { - let new_pavi = if !no_item { - // prepare forest fragment - - // if ter == 0 { - // println!("{ter}, {t}, {atom_moved}, {atom_label}"); - // println!( - // "hey: {:?}", - // self.atom.labels_of(0).unwrap().collect::<Vec<_>>() - // ); - // panic!("test"); - // } - - let fragment = - generate_fragment([atom_moved.into(), Ter(ter).into()], pos)?; - - self.forest.insert_item( - *label, - t, - fragment, - atom_child_iter.clone(), - &self.atom, - )? - } else { - PaVi::default() - }; - - let generator_input = ( - &self.graph, - &self.atom, - &self.forest, - self.accepting_vec.as_slice(), - new_pavi, - new_pavi, - ); - - let accepting = generate_edges( + generate_edges( generator_input, + label, child_iter.clone(), atom_child_iter.clone(), &mut der_iter.singles, )?; - - if accepting { - accepting_pavi.insert(new_pavi); - } } Some(Non(non)) => { if !self @@ -753,20 +708,6 @@ impl Chain for DefaultChain { continue; } - #[allow(clippy::single_match)] - match label.forest_source() { - PaVi::Parent(node, _, _) => match self.forest.vertex_label(node) { - Ok(Some(label)) => match label.label().end() { - Some(end) if end != pos => { - continue; - } - _ => {} - }, - _ => {} - }, - _ => {} - } - let virtual_node = self .atom .atom(non, t) @@ -778,88 +719,34 @@ impl Chain for DefaultChain { .is_accepting(virtual_node) .map_err(index_out_of_bounds_conversion)?; - // if pos == 9 { - // dbg!(label, atom_label, self.current, &self.history); - // } - - let first_segment_pavi: PaVi; - let virtual_pavi: PaVi; - - if !no_item { - let first_fragment = - generate_fragment([atom_moved.into(), Non(non).into()], pos)?; - - first_segment_pavi = self.forest.insert_item( - *label, - t, - first_fragment, - atom_child_iter.clone(), - &self.atom, - )?; - - let virtual_fragment = - DefaultForest::new_leaf(GrammarLabel::new(Ter(t), pos)); - - // NOTE: We only need the PaVi from the - // first segment, so we pass an empty - // iterator, in which case the passed - // label is only used for the PaVi. - virtual_pavi = self.forest.insert_item( - Edge::new(0, first_segment_pavi, accepting), - t, - virtual_fragment, - std::iter::empty(), - &self.atom, - )?; - } else { - first_segment_pavi = PaVi::default(); - virtual_pavi = PaVi::default(); - } + // // The frame of the callee starts here. + // let fresh: Starts = if no_item { + // Starts::new() + // } else { + // Starts::from([pos]) + // }; let mut new_edges = Vec::new(); - let generator_input = ( - &self.graph, - &self.atom, - &self.forest, - self.accepting_vec.as_slice(), - first_segment_pavi, - virtual_pavi, - ); - - let virtual_accepting = generate_edges( + generate_edges( generator_input, + label, child_iter.clone(), atom_child_iter.clone(), &mut new_edges, )?; - if virtual_accepting { - accepting_pavi.insert(first_segment_pavi); - } - if accepting { - accepting_pavi.insert(virtual_pavi); - - for (roi, target) in new_edges.iter() { - match roi { - Roi::Re(edge) => { - let mut edge = *edge; - - edge.set_true_source(virtual_pavi); - - der_iter.singles.push((Roi::Re(edge), *target)); - } - Roi::Im(_) => der_iter.singles.push((*roi, *target)), - } - } + der_iter.singles.extend(new_edges.iter().cloned()); } if !self.atom.is_empty_node(virtual_node).unwrap() { der_iter.add_second_layer( virtual_node, - virtual_pavi, + PaVi::default(), accepting, + non, + // fresh.clone(), new_edges, ); @@ -872,9 +759,11 @@ impl Chain for DefaultChain { if self.atom.is_empty_node(atom_child).unwrap() { der_iter.singles.extend(child_iter.clone().map(|child| { ( - Edge::new(virtual_node, virtual_pavi, accepting) + Edge::new(virtual_node, PaVi::default(), accepting) + .with_frame_nt(non) .into(), child, + // fresh.clone(), ) })); } @@ -901,12 +790,18 @@ impl Chain for DefaultChain { for (child_label, child_child_iter) in self.graph.labels_of(child).unwrap() { - let mut child_label = *child_label; - - child_label.set_true_source(virtual_pavi); - der_iter.singles.extend(child_child_iter.map( - |child_child| (child_label.into(), child_child), + |child_child| { + ( + (*child_label).into(), + child_child, + // self.starts.get( + // child, + // child_label, + // child_child, + // ), + ) + }, )); } } @@ -922,9 +817,6 @@ impl Chain for DefaultChain { } } - self.accepting_sources.clear(); - self.accepting_sources.extend(accepting_pavi); - Ok(der_iter) } @@ -1124,390 +1016,390 @@ impl Chain for DefaultChain { } } -#[cfg(test)] -mod test_der_iter { - use super::*; +// #[cfg(test)] +// mod test_der_iter { +// use super::*; + +// #[test] +// fn test() -> Result<(), Box<dyn std::error::Error>> { +// let mut der_iter = DerIter::default(); + +// let parent = Default::default(); + +// der_iter +// .singles +// .push((Edge::new(0, parent, true).into(), 0)); + +// der_iter +// .singles +// .push((Edge::new(1, parent, true).into(), 0)); + +// der_iter +// .singles +// .push((Edge::new(2, parent, true).into(), 0)); + +// der_iter.add_second_layer( +// 3, +// parent, +// true, +// vec![(Edge::new(4, parent, true).into(), 1)], +// ); + +// der_iter.add_second_layer( +// 6, +// parent, +// true, +// vec![(Edge::new(5, parent, true).into(), 1)], +// ); + +// // add an entry with a repeated label +// der_iter.add_second_layer( +// 3, +// parent, +// true, +// vec![(Edge::new(7, parent, true).into(), 2)], +// ); + +// assert_eq!( +// der_iter.next(), +// Some(TwoLayers::Two( +// 3, +// parent, +// true, +// vec![ +// (Edge::new(4, parent, true).into(), 1), +// (Edge::new(7, parent, true).into(), 2) +// ] +// )) +// ); + +// assert_eq!( +// der_iter.next(), +// Some(TwoLayers::Two( +// 6, +// parent, +// true, +// vec![(Edge::new(5, parent, true).into(), 1)] +// )) +// ); + +// assert_eq!( +// der_iter.next(), +// Some(TwoLayers::One(Edge::new(0, parent, true).into(), 0)) +// ); + +// assert_eq!( +// der_iter.next(), +// Some(TwoLayers::One(Edge::new(1, parent, true).into(), 0)) +// ); + +// assert_eq!( +// der_iter.next(), +// Some(TwoLayers::One(Edge::new(2, parent, true).into(), 0)) +// ); + +// assert_eq!(der_iter.next(), None); +// assert_eq!(der_iter.next(), None); + +// Ok(()) +// } +// } + +// #[cfg(test)] +// mod test_chain { +// use super::*; +// use grammar::test_grammar_helper::*; + +// #[test] +// fn base_test() -> Result<(), Box<dyn std::error::Error>> { +// let mut no_item = false; + +// for arg in std::env::args() { +// if arg == "no_item" { +// no_item = true; +// break; +// } +// } + +// let grammar = new_notes_grammar()?; + +// let atom = DefaultAtom::from_grammar(grammar)?; + +// let mut chain = DefaultChain::unit(atom)?; +// chain.chain(3, 00, no_item)?; +// chain.chain(1, 01, no_item)?; +// chain.chain(2, 02, no_item)?; +// chain.chain(2, 03, no_item)?; +// chain.chain(2, 04, no_item)?; +// chain.chain(0, 05, no_item)?; +// chain.chain(5, 06, no_item)?; +// chain.chain(1, 07, no_item)?; +// chain.chain(6, 08, no_item)?; +// chain.chain(6, 09, no_item)?; +// chain.chain(6, 10, no_item)?; +// chain.chain(0, 11, no_item)?; +// chain.chain(0, 12, no_item)?; + +// if !no_item { +// let output = chain.end_of_input(13, 0)?; +// chain.forest.print_viz("forest.gv")?; + +// output.print_viz("extracted forest.gv")?; + +// chain.graph.print_viz("chain.gv")?; +// chain.atom.print_nfa("nfa.gv")?; +// item::default::print_labels(&chain.atom, &chain.forest)?; +// } + +// for label in chain.labels_of(chain.current())?.map(|(label, _)| label) { +// dbg!(label); +// } + +// assert!(matches!(chain.epsilon(), Ok(true))); + +// #[cfg(feature = "test-print-viz")] +// { +// chain.graph.print_viz("chain.gv")?; +// chain.atom.print_nfa("nfa.gv")?; - #[test] - fn test() -> Result<(), Box<dyn std::error::Error>> { - let mut der_iter = DerIter::default(); +// chain.forest.print_viz("forest.gv")?; - let parent = Default::default(); - - der_iter - .singles - .push((Edge::new(0, parent, true).into(), 0)); - - der_iter - .singles - .push((Edge::new(1, parent, true).into(), 0)); - - der_iter - .singles - .push((Edge::new(2, parent, true).into(), 0)); - - der_iter.add_second_layer( - 3, - parent, - true, - vec![(Edge::new(4, parent, true).into(), 1)], - ); - - der_iter.add_second_layer( - 6, - parent, - true, - vec![(Edge::new(5, parent, true).into(), 1)], - ); - - // add an entry with a repeated label - der_iter.add_second_layer( - 3, - parent, - true, - vec![(Edge::new(7, parent, true).into(), 2)], - ); - - assert_eq!( - der_iter.next(), - Some(TwoLayers::Two( - 3, - parent, - true, - vec![ - (Edge::new(4, parent, true).into(), 1), - (Edge::new(7, parent, true).into(), 2) - ] - )) - ); - - assert_eq!( - der_iter.next(), - Some(TwoLayers::Two( - 6, - parent, - true, - vec![(Edge::new(5, parent, true).into(), 1)] - )) - ); +// item::default::print_labels(&chain.atom, &chain.forest)?; +// } - assert_eq!( - der_iter.next(), - Some(TwoLayers::One(Edge::new(0, parent, true).into(), 0)) - ); +// Ok(()) +// } - assert_eq!( - der_iter.next(), - Some(TwoLayers::One(Edge::new(1, parent, true).into(), 0)) - ); +// #[test] +// fn test_assumption() -> Result<(), Box<dyn std::error::Error>> { +// use grammar::Grammar; - assert_eq!( - der_iter.next(), - Some(TwoLayers::One(Edge::new(2, parent, true).into(), 0)) - ); +// let grammar_str = std::fs::read_to_string( +// "/Users/durand/Desktop/Centre/A propos de programmes/Rust/rep/grammar/abnf grammars/test.abnf", +// ) +// .unwrap(); - assert_eq!(der_iter.next(), None); - assert_eq!(der_iter.next(), None); +// let grammar: Grammar = grammar_str.parse()?; - Ok(()) - } -} +// let atom = DefaultAtom::from_grammar(grammar)?; -#[cfg(test)] -mod test_chain { - use super::*; - use grammar::test_grammar_helper::*; +// let mut chain = DefaultChain::unit(atom)?; - #[test] - fn base_test() -> Result<(), Box<dyn std::error::Error>> { - let mut no_item = false; +// let no_item = false; - for arg in std::env::args() { - if arg == "no_item" { - no_item = true; - break; - } - } - - let grammar = new_notes_grammar()?; - - let atom = DefaultAtom::from_grammar(grammar)?; - - let mut chain = DefaultChain::unit(atom)?; - chain.chain(3, 00, no_item)?; - chain.chain(1, 01, no_item)?; - chain.chain(2, 02, no_item)?; - chain.chain(2, 03, no_item)?; - chain.chain(2, 04, no_item)?; - chain.chain(0, 05, no_item)?; - chain.chain(5, 06, no_item)?; - chain.chain(1, 07, no_item)?; - chain.chain(6, 08, no_item)?; - chain.chain(6, 09, no_item)?; - chain.chain(6, 10, no_item)?; - chain.chain(0, 11, no_item)?; - chain.chain(0, 12, no_item)?; - - if !no_item { - let output = chain.end_of_input(13, 0)?; - chain.forest.print_viz("forest.gv")?; - - output.print_viz("extracted forest.gv")?; - - chain.graph.print_viz("chain.gv")?; - chain.atom.print_nfa("nfa.gv")?; - item::default::print_labels(&chain.atom, &chain.forest)?; - } - - for label in chain.labels_of(chain.current())?.map(|(label, _)| label) { - dbg!(label); - } - - assert!(matches!(chain.epsilon(), Ok(true))); - - #[cfg(feature = "test-print-viz")] - { - chain.graph.print_viz("chain.gv")?; - chain.atom.print_nfa("nfa.gv")?; - - chain.forest.print_viz("forest.gv")?; - - item::default::print_labels(&chain.atom, &chain.forest)?; - } - - Ok(()) - } - - #[test] - fn test_assumption() -> Result<(), Box<dyn std::error::Error>> { - use grammar::Grammar; - - let grammar_str = std::fs::read_to_string( - "/Users/durand/Desktop/Centre/A propos de programmes/Rust/rep/grammar/abnf grammars/test.abnf", - ) - .unwrap(); +// let input: &[usize] = &[ +// 3, 0, 2, 1, 5, 0, 6, 1, 3, 0, 2, +// 1, // 5, 0, 6, 1, 3, 0, 2, 1, 5, 0, 6, 1, 4, 0, 2, 1, +// ]; - let grammar: Grammar = grammar_str.parse()?; +// let input_len = input.len(); - let atom = DefaultAtom::from_grammar(grammar)?; +// // let to_print = std::fs::metadata("output/").is_ok(); +// let to_print = false; - let mut chain = DefaultChain::unit(atom)?; +// for (pos, t) in input.iter().copied().enumerate().take(input_len) { +// chain.chain(t, pos, no_item)?; +// if to_print { +// chain.print_current(&format!("chain {pos}.gv"))?; +// chain.forest().print_viz(&format!("forest {pos}.gv"))?; +// } +// dbg!(pos, t); +// } - let no_item = false; +// chain.print_viz("chain.gv")?; +// chain.atom.print_viz("nfa.gv")?; - let input: &[usize] = &[ - 3, 0, 2, 1, 5, 0, 6, 1, 3, 0, 2, - 1, // 5, 0, 6, 1, 3, 0, 2, 1, 5, 0, 6, 1, 4, 0, 2, 1, - ]; +// // let _ = chain.forest.print_viz("forest before extraction.gv"); - let input_len = input.len(); - - // let to_print = std::fs::metadata("output/").is_ok(); - let to_print = false; - - for (pos, t) in input.iter().copied().enumerate().take(input_len) { - chain.chain(t, pos, no_item)?; - if to_print { - chain.print_current(&format!("chain {pos}.gv"))?; - chain.forest().print_viz(&format!("forest {pos}.gv"))?; - } - dbg!(pos, t); - } +// let extracted = chain.end_of_input(input_len, input[input_len - 1])?; - chain.print_viz("chain.gv")?; - chain.atom.print_viz("nfa.gv")?; +// let _ = extracted.print_viz("extracted forest.gv"); - // let _ = chain.forest.print_viz("forest before extraction.gv"); +// // item::default::print_labels(&chain.atom, &chain.forest)?; - let extracted = chain.end_of_input(input_len, input[input_len - 1])?; +// Ok(()) +// } - let _ = extracted.print_viz("extracted forest.gv"); +// #[test] +// fn test_ambiguity() -> Result<(), Box<dyn std::error::Error>> { +// if std::fs::metadata("debug.log").is_ok() { +// std::fs::remove_file("debug.log")?; +// } - // item::default::print_labels(&chain.atom, &chain.forest)?; +// let mut no_item = false; - Ok(()) - } - - #[test] - fn test_ambiguity() -> Result<(), Box<dyn std::error::Error>> { - if std::fs::metadata("debug.log").is_ok() { - std::fs::remove_file("debug.log")?; - } - - let mut no_item = false; - - for arg in std::env::args() { - if arg == "no_item" { - no_item = true; - break; - } - } +// for arg in std::env::args() { +// if arg == "no_item" { +// no_item = true; +// break; +// } +// } - let grammar = new_paren_grammar()?; +// let grammar = new_paren_grammar()?; - let atom = DefaultAtom::from_grammar(grammar)?; +// let atom = DefaultAtom::from_grammar(grammar)?; - let mut chain = DefaultChain::unit(atom)?; - chain.chain(0, 0, no_item)?; +// let mut chain = DefaultChain::unit(atom)?; +// chain.chain(0, 0, no_item)?; - if !no_item { - chain.forest.print_viz("forest0.gv")?; - } +// if !no_item { +// chain.forest.print_viz("forest0.gv")?; +// } - chain.chain(2, 1, no_item)?; +// chain.chain(2, 1, no_item)?; - if !no_item { - chain.forest.print_viz("forest1.gv")?; - } +// if !no_item { +// chain.forest.print_viz("forest1.gv")?; +// } - chain.chain(2, 2, no_item)?; +// chain.chain(2, 2, no_item)?; - if !no_item { - chain.forest.print_viz("forest2.gv")?; - } +// if !no_item { +// chain.forest.print_viz("forest2.gv")?; +// } - chain.chain(2, 3, no_item)?; +// chain.chain(2, 3, no_item)?; - if !no_item { - chain.forest.print_viz("forest3.gv")?; - } +// if !no_item { +// chain.forest.print_viz("forest3.gv")?; +// } - chain.chain(1, 4, no_item)?; +// chain.chain(1, 4, no_item)?; - if !no_item { - let _output = chain.end_of_input(5, 1)?; - chain.forest.print_viz("forest.gv")?; - // chain.forest.print_closed_viz("closed.gv")?; - } +// if !no_item { +// let _output = chain.end_of_input(5, 1)?; +// chain.forest.print_viz("forest.gv")?; +// // chain.forest.print_closed_viz("closed.gv")?; +// } - chain.graph.print_viz("chain.gv")?; - chain.atom.print_nfa("nfa.gv")?; - item::default::print_labels(&chain.atom, &chain.forest)?; +// chain.graph.print_viz("chain.gv")?; +// chain.atom.print_nfa("nfa.gv")?; +// item::default::print_labels(&chain.atom, &chain.forest)?; - for label in chain.labels_of(chain.current())?.map(|(label, _)| label) { - dbg!(label); - } +// for label in chain.labels_of(chain.current())?.map(|(label, _)| label) { +// dbg!(label); +// } - dbg!(chain.current(), chain.history()); +// dbg!(chain.current(), chain.history()); - #[cfg(feature = "test-print-viz")] - { - chain.graph.print_viz("chain.gv")?; - chain.atom.print_nfa("nfa.gv")?; +// #[cfg(feature = "test-print-viz")] +// { +// chain.graph.print_viz("chain.gv")?; +// chain.atom.print_nfa("nfa.gv")?; - chain.forest.print_viz("forest.gv")?; +// chain.forest.print_viz("forest.gv")?; - chain.forest.print_closed_viz("closed.gv")?; +// chain.forest.print_closed_viz("closed.gv")?; - item::default::print_labels(&chain.atom, &chain.forest)?; - } +// item::default::print_labels(&chain.atom, &chain.forest)?; +// } - assert!(matches!(chain.epsilon(), Ok(true))); +// assert!(matches!(chain.epsilon(), Ok(true))); - Ok(()) - } +// Ok(()) +// } - #[test] - fn test_speed() -> Result<(), Box<dyn std::error::Error>> { - let mut no_item = false; +// #[test] +// fn test_speed() -> Result<(), Box<dyn std::error::Error>> { +// let mut no_item = false; - for arg in std::env::args() { - if arg == "no_item" { - no_item = true; - break; - } - } +// for arg in std::env::args() { +// if arg == "no_item" { +// no_item = true; +// break; +// } +// } - let grammar = new_notes_grammar_no_regexp()?; +// let grammar = new_notes_grammar_no_regexp()?; - println!("grammar: {grammar}"); +// println!("grammar: {grammar}"); - let atom = DefaultAtom::from_grammar(grammar)?; +// let atom = DefaultAtom::from_grammar(grammar)?; - let mut chain = DefaultChain::unit(atom)?; +// let mut chain = DefaultChain::unit(atom)?; - let input_template = vec![3, 1, 2, 2, 2, 0, 5, 1, 6, 6, 6, 0, 0]; +// let input_template = vec![3, 1, 2, 2, 2, 0, 5, 1, 6, 6, 6, 0, 0]; - let repeat_times = { - let mut result = 1; +// let repeat_times = { +// let mut result = 1; - for arg in std::env::args() { - let parse_as_digit: Result<usize, _> = arg.parse(); +// for arg in std::env::args() { +// let parse_as_digit: Result<usize, _> = arg.parse(); - // just use the first number in the arguments - if let Ok(parse_result) = parse_as_digit { - result = parse_result; +// // just use the first number in the arguments +// if let Ok(parse_result) = parse_as_digit { +// result = parse_result; - break; - } - } +// break; +// } +// } - result - }; +// result +// }; - println!("repeating {repeat_times} times"); +// println!("repeating {repeat_times} times"); - let input = input_template.repeat(repeat_times); +// let input = input_template.repeat(repeat_times); - let start = std::time::Instant::now(); +// let start = std::time::Instant::now(); - for (index, t) in input.iter().copied().enumerate() { - chain.chain(t, index, no_item)?; - } +// for (index, t) in input.iter().copied().enumerate() { +// chain.chain(t, index, no_item)?; +// } - let elapsed = start.elapsed(); +// let elapsed = start.elapsed(); - assert!(matches!(chain.epsilon(), Ok(true))); +// assert!(matches!(chain.epsilon(), Ok(true))); - dbg!(elapsed); - dbg!(chain.current()); +// dbg!(elapsed); +// dbg!(chain.current()); - assert_eq!(input.len(), chain.history().len()); +// assert_eq!(input.len(), chain.history().len()); - let history_file_name = "output/history"; - if std::fs::metadata(history_file_name).is_ok() { - std::fs::remove_file(history_file_name)?; - } +// let history_file_name = "output/history"; +// if std::fs::metadata(history_file_name).is_ok() { +// std::fs::remove_file(history_file_name)?; +// } - let mut history_file = std::fs::OpenOptions::new() - .create(true) - .write(true) - .open(history_file_name)?; +// let mut history_file = std::fs::OpenOptions::new() +// .create(true) +// .write(true) +// .open(history_file_name)?; - use std::fmt::Write; - use std::io::Write as IOWrite; +// use std::fmt::Write; +// use std::io::Write as IOWrite; - let mut log_string = String::new(); +// let mut log_string = String::new(); - writeln!(&mut log_string, "index: terminal, history")?; +// writeln!(&mut log_string, "index: terminal, history")?; - for (index, t) in input.iter().copied().enumerate().take(input.len() - 1) { - writeln!( - &mut log_string, - "{index}: {t}, {}", - chain.history().get(index).unwrap() - )?; - } +// for (index, t) in input.iter().copied().enumerate().take(input.len() - 1) { +// writeln!( +// &mut log_string, +// "{index}: {t}, {}", +// chain.history().get(index).unwrap() +// )?; +// } - println!("Successfully logged to output/history"); +// println!("Successfully logged to output/history"); - history_file.write_all(log_string.as_bytes())?; +// history_file.write_all(log_string.as_bytes())?; - for label in chain.labels_of(chain.current())?.map(|(label, _)| label) { - dbg!(label); - } +// for label in chain.labels_of(chain.current())?.map(|(label, _)| label) { +// dbg!(label); +// } - #[cfg(feature = "test-print-viz")] - { - chain.graph.print_viz("chain.gv")?; - chain.atom.print_nfa("nfa.gv")?; - item::default::print_labels(&chain.atom, &chain.forest)?; +// #[cfg(feature = "test-print-viz")] +// { +// chain.graph.print_viz("chain.gv")?; +// chain.atom.print_nfa("nfa.gv")?; +// item::default::print_labels(&chain.atom, &chain.forest)?; - chain.forest.print_viz("forest.gv")?; +// chain.forest.print_viz("forest.gv")?; - chain.forest.print_closed_viz("closed.gv")?; - } +// chain.forest.print_closed_viz("closed.gv")?; +// } - Ok(()) - } -} +// Ok(()) +// } +// } diff --git a/chain/src/item/default/mod.rs b/chain/src/item/default/mod.rs index eef7def..040079f 100644 --- a/chain/src/item/default/mod.rs +++ b/chain/src/item/default/mod.rs @@ -98,9 +98,10 @@ impl<T: GraphLabel> AsRef<DefaultForest<T>> for DefaultForest<T> { } impl<T: GraphLabel> ParentsGraph for DefaultForest<T> { - type Iter<'a>= <PLGraph<T> as ParentsGraph>::Iter<'a> + type Iter<'a> + = <PLGraph<T> as ParentsGraph>::Iter<'a> where - Self:'a; + Self: 'a; #[inline] fn parents_of(&self, node_id: usize) -> Result<<Self as ParentsGraph>::Iter<'_>, GError> { @@ -123,21 +124,25 @@ impl<T: GraphLabel> ParentsGraph for DefaultForest<T> { } impl<T: GraphLabel> LabelGraph<T> for DefaultForest<T> { - type Iter<'a> = std::iter::Empty<usize> + type Iter<'a> + = std::iter::Empty<usize> where Self: 'a; - type TupleIter<'a> = std::iter::Empty<(T, usize)> + type TupleIter<'a> + = std::iter::Empty<(T, usize)> where Self: 'a, T: 'a; - type LabelIter<'a> = std::iter::Empty<(&'a T, <Self as LabelGraph<T>>::Iter<'a>)> + type LabelIter<'a> + = std::iter::Empty<(&'a T, <Self as LabelGraph<T>>::Iter<'a>)> where Self: 'a, T: 'a; - type EdgeLabelIter<'a> = std::iter::Empty<T> + type EdgeLabelIter<'a> + = std::iter::Empty<T> where Self: 'a, T: 'a; diff --git a/chain/src/lib.rs b/chain/src/lib.rs index 10143dd..24598a8 100644 --- a/chain/src/lib.rs +++ b/chain/src/lib.rs @@ -32,17 +32,21 @@ pub struct Edge { true_source: PaVi, /// Whether or not this edge is "accepting". accepting: bool, + /// The non-terminal that starts this edge. + frame_nt: usize, } impl Edge { /// Construct a new edge. pub fn new(label: usize, forest_source: PaVi, accepting: bool) -> Self { let true_source = forest_source; + let frame_nt = 0usize; Self { label, forest_source, accepting, true_source, + frame_nt, } } @@ -61,6 +65,24 @@ impl Edge { self.forest_source } + /// Return the frame non-terminal of the edge. + pub fn frame_nt(&self) -> usize { + self.frame_nt + } + + /// Set the frame non-terminal. + pub fn set_frame_nt(&mut self, nt: usize) { + self.frame_nt = nt; + } + + /// Build a new edge with a given frame non-terminal. + pub fn with_frame_nt(self, nt: usize) -> Self { + Self { + frame_nt: nt, + ..self + } + } + /// Set the associated forest edge of the edge of the edge. pub fn set_forest_source(&mut self, source: PaVi) { self.forest_source = source; @@ -161,7 +183,7 @@ pub enum TwoLayers { /// the source of the associated forest edge of the second layer, /// and the third is a list of edges, which are the common first /// layers. - Two(usize, PaVi, bool, Vec<(Roi, usize)>), + Two(usize, PaVi, bool, usize, Vec<(Roi, usize)>), } /// The type of a collapsed iterator. @@ -203,12 +225,22 @@ where if let Some(two_layer) = self.iter.next() { match two_layer { TwoLayers::One(edge, to) => Some(Ok((edge, to))), - TwoLayers::Two(label, forest_source, accepting, edges) => { - let new_index = match self.chain.extend( - edges - .into_iter() - .filter_map(|(roi, target)| roi.real_part().map(|edge| (edge, target))), - ) { + TwoLayers::Two(label, forest_source, accepting, frame_nt, edges) => { + let imaginary: Vec<(Roi, usize)> = edges + .iter() + .filter(|(roi, _)| roi.imaginary_part().is_some()) + .map(|(roi, target)| (*roi, *target)) + .collect(); + + let real: Vec<(Edge, usize)> = edges + .into_iter() + .filter_map(|(roi, target)| roi.real_part().map(|edge| (edge, target))) + .collect(); + + let new_index = match self + .chain + .extend(real.iter().map(|(edge, target)| (*edge, *target))) + { Ok(new) => new, Err(error) => { // Prevent further iterations. @@ -218,8 +250,15 @@ where } }; + if let Err(err) = self.chain.update_epsilon(new_index, imaginary.into_iter()) { + self.stop = true; + return Some(Err(err)); + }; + Some(Ok(( - Edge::new(label, forest_source, accepting).into(), + Edge::new(label, forest_source, accepting) + .with_frame_nt(frame_nt) + .into(), new_index, ))) } @@ -302,15 +341,16 @@ pub trait Chain: LabelExtGraph<Edge> { let edges = self.union(der_iter)?; - let new_index = self.extend( - edges - .iter() - .filter_map(|(roi, target)| roi.real_part().map(|edge| (edge, *target))), - )?; + let real: Vec<(Edge, usize)> = edges + .iter() + .filter_map(|(roi, target)| roi.real_part().map(|edge| (edge, *target))) + .collect(); - if self.is_empty_node(new_index)? { - self.update_epsilon(new_index, edges.into_iter())?; - } + let new_index = self.extend(real.iter().map(|(edge, target)| (*edge, *target)))?; + + // Imaginary edges can make the node accepting even when the + // node has real edges. + self.update_epsilon(new_index, edges.into_iter())?; self.update_history(new_index); |
