Minimization Algorithm

 avatar
unknown
rust
2 years ago
5.6 kB
5
Indexable
pub fn minimize(&self) -> Self {
        // table filling algorithm

        // 1. Remove unreachable states
        let mut reachable_states = HashSet::new();
        reachable_states.insert(self.starting_state.clone());

        for state in &self.states {
            for symbol in &self.alphabet {
                if let Some(out_state) = (self.transition_function)(state.clone(), symbol.clone()) {
                    reachable_states.insert(out_state);
                }
            }
        }

        // 2. Mark final AND non-final states
        let mut mark_table = Table::new();
        for state1 in &reachable_states {
            for state2 in &reachable_states {
                let is_final1 = self.final_states.contains(state1);
                let not_is_final2 = !self.final_states.contains(state2);
                mark_table.set(state1.id, state2.id, is_final1 && not_is_final2);
            }
        }

        // Some states in the upper triangle maybe marked, could potentially be harmful to the algorithm
        mark_table.drop(|key1, key2, _| {
            key2 >= key1
        });

        // 3. Mark pairs of states
        loop {
            let mut has_marked = false;

            // for all pairs of states (p, q) in reachable_states X alphabet
            for state1 in &reachable_states {
                for state2 in &reachable_states {
                    if *mark_table.get(&state1.id, &state2.id).unwrap() {
                        continue;
                    }

                    for symbol in &self.alphabet {
                        // if (s1, s2) where s1 = delta(p, a) and s2 = delta(q, a) is marked
                        // then mark (p, q)

                        let out_state1 = (self.transition_function)(state1.clone(), symbol.clone());
                        let out_state2 = (self.transition_function)(state2.clone(), symbol.clone());

                        if let (Some(out_state1), Some(out_state2)) = (out_state1, out_state2) {
                            if *mark_table.get(&out_state1.id, &out_state2.id).unwrap() {
                                mark_table.set(state1.id, state2.id, true);
                                has_marked = true;
                            }
                        }
                    }
                }
            }

            mark_table.drop(|key1, key2, _| {
                key2 >= key1
            });

            if !has_marked {
                break;
            }
        }

        // 4. Create equivalence classes
        let mut equivalence_classes = Vec::new();
        let mut available_states = reachable_states.clone();

        while !available_states.is_empty() {
            let state = available_states.iter().next().unwrap().clone();

            let mut equivalence_class = HashSet::new();
            equivalence_class.insert(state.clone());

            for state2 in &available_states {
                if !mark_table.get(&state.id, &state2.id).unwrap() {
                    equivalence_class.insert(state2.clone());
                }
            }

            equivalence_classes.push(equivalence_class.clone());
            available_states = available_states.difference(&equivalence_class).cloned().collect();
        }

        let dfa_states = st_range_hash!(0..(equivalence_classes.len() as u32));
        let dfa_initial_state = equivalence_classes
            .iter()
            .position(|equivalence_class| equivalence_class.contains(&self.starting_state))
            .unwrap();
        let dfa_final_states = equivalence_classes
            .iter()
            .enumerate()
            .filter(|(_, equivalence_class)| 
                equivalence_class
                .iter()
                .any(|state| self.final_states.contains(state)))
            .map(|(i, _)| State::new(i as u32))
            .collect::<HashSet<_>>();

        let mut dfa_transition_function = Table::new();
        
        for equivalence_class in &equivalence_classes {
            for symbol in &self.alphabet {
                // pick a state from the equivalence class
                let state = equivalence_class.iter().next().unwrap().clone();

                // find delta[state, symbol]
                let out_state = (self.transition_function)(state.clone(), symbol.clone());
                // ? is it guaranteed that out_state is always a Some()?
                let out_state = out_state.unwrap();

                // find the equivalence class of out_state
                let out_equivalence_class = equivalence_classes
                    .iter()
                    .find(|equivalence_class| equivalence_class.contains(&out_state))
                    .unwrap();

                // find the index of the equivalence class
                let out_equivalence_class_index = equivalence_classes
                    .iter()
                    .position(|equivalence_class| equivalence_class == out_equivalence_class)
                    .unwrap();

                // set the transition function
                dfa_transition_function.set(state.id, symbol.symbol.clone(), Some(out_equivalence_class_index as u32));
            }
        }

        Self {
            states: dfa_states,
            alphabet: self.alphabet.clone(),
            starting_state: State::new(dfa_initial_state as u32),
            final_states: dfa_final_states,
            transition_function: transition_function_from_table(dfa_transition_function),
        }
    }
Editor is loading...