/* * JFLAP - Formal Languages and Automata Package * * * Susan H. Rodger * Computer Science Department * Duke University * August 27, 2009 * Copyright (c) 2002-2009 * All rights reserved. * JFLAP is open source software. Please see the LICENSE for terms. * */ package automata.graph; import automata.*; import java.util.*; /** * The disjoint sets detector can be used to determine the disjoint sets of * states in a given automaton. Two sets of states are determined to be disjoint * if there are no transitions from one set to the other. Also, given a state, * the disjoint sets detector can return the set of states that are connected to * that state. * * @author Ryan Cavalcante */ public class DisjointSetsDetector { /** * Instantiates a DisjointSetsDetector. */ public DisjointSetsDetector() { STATES_IN_A_SET = new ArrayList(); } /** * Adds the states in the set states to the set of states * accounted for in the determination of the disjoint sets. * * @param states * the set of states to account for */ private void accountForStates(HashSet states) { Iterator it = states.iterator(); while (it.hasNext()) { State state = (State) it.next(); if (!STATES_IN_A_SET.contains(state)) STATES_IN_A_SET.add(state); } } /** * Returns true if s1 and s2 from automaton * are directly connected. (i.e. there is either a transition from s1 * to s2 or a transition from s2 to s1. * * @param s1 * a state * @param s2 * a state * @param automaton * the automaton * @return true if s1 and s2 from automaton * are directly connected. (i.e. there is either a transition from * s1 to s2 or a transition from * s2 to s1. */ private boolean areDirectlyConnected(State s1, State s2, Automaton automaton) { if (s1 == s2) return false; if (automaton.getTransitionsFromStateToState(s1, s2).length == 0 && automaton.getTransitionsFromStateToState(s2, s1).length == 0) return false; return true; } /** * Returns a list of states in automaton that are connected * directly to state. * * @param state * the state * @param automaton * the automaton * @return a list of states in automaton that are connected * directly to state. */ private ArrayList getStatesConnectedToState(State state, Automaton automaton) { ArrayList list = new ArrayList(); State[] states = automaton.getStates(); for (int k = 0; k < states.length; k++) { if (areDirectlyConnected(state, states[k], automaton)) { list.add(states[k]); } } return list; } /** * Adds all contents of toAdd that are not in set * to list. * * @param toAdd * a list of states * @param set * a set of states * @param list * a list of states */ private void addAllNotInSetToList(ArrayList toAdd, HashSet set, ArrayList list) { Iterator it = toAdd.iterator(); while (it.hasNext()) { State state = (State) it.next(); if (!set.contains(state)) list.add(state); } } /** * Returns a set containing all states in automaton, * including state, that are connected to state. * * @param state * the state * @param automaton * the automaton * @return a set containing all states in automaton, * including state, that are connected to state. */ public HashSet getSetIncludingState(State state, Automaton automaton) { HashSet set = new HashSet(); ArrayList list = new ArrayList(); list.add(state); while (!list.isEmpty()) { ArrayList toAdd = new ArrayList(); Iterator it = list.iterator(); while (it.hasNext()) { State s = (State) it.next(); toAdd.addAll(getStatesConnectedToState(s, automaton)); set.add(s); it.remove(); } addAllNotInSetToList(toAdd, set, list); } return set; } /** * Returns true if state has been accounted for in the * determination of disjoint sets * * @param state * the state */ private boolean isAccountedFor(State state) { if (STATES_IN_A_SET.contains(state)) return true; return false; } /** * Returns true if all states in automaton have been * accounted for in the determination of disjoint sets. * * @param automaton * the automaton * @return true if all states in automaton have been * accounted for in the determination of disjoint sets. */ private boolean accountedForAllStates(Automaton automaton) { if (getUnaccountedForState(automaton) == null) return true; return false; } /** * Returns a state in automaton that has not yet been * accounted for in the determination of disjoint sets. * * @param automaton * the automaton * @return a state in automaton that has not yet been * accounted for in the determination of disjoint sets. */ public State getUnaccountedForState(Automaton automaton) { State[] states = automaton.getStates(); for (int k = 0; k < states.length; k++) { if (!isAccountedFor(states[k])) return states[k]; } return null; } /** * Returns an array of all the disjoint sets of states in automaton. * * @param automaton * the automaton * @return an array of all the disjoint sets of states in automaton. */ public HashSet[] getDisjointSets(Automaton automaton) { ArrayList list = new ArrayList(); STATES_IN_A_SET = new ArrayList(); while (!accountedForAllStates(automaton)) { State state = getUnaccountedForState(automaton); HashSet set = getSetIncludingState(state, automaton); accountForStates(set); list.add(set); } return (HashSet[]) list.toArray(new HashSet[0]); } /** the states accounted for in the determination of disjoint sets. */ protected ArrayList STATES_IN_A_SET; }