/*
* 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;
}