docs: def strings(self):
  		'''
  			Generate strings (lists of symbols) that this FSM accepts. Since there may
  			be infinitely many of these we use a generator instead of constructing a
  			static list. Strings will be sorted in order of length and then lexically.
  			This procedure uses arbitrary amounts of memory but is very fast. There
  			may be more efficient ways to do this, that I haven't investigated yet.
  			You can use this in list comprehensions.
  		'''
  
  		# Many FSMs have "dead states". Once you reach a dead state, you can no
  		# longer reach a final state. Since many strings may end up here, it's
  		# advantageous to constrain our search to live states only.
  		livestates = set(state for state in self.states if self.islive(state))
  
  		# We store a list of tuples. Each tuple consists of an input string and the
  		# state that this input string leads to. This means we don't have to run the
  		# state machine from the very beginning every time we want to check a new
  		# string.
  		strings = []
  
  		# Initial entry (or possibly not, in which case this is a short one)
  		cstate = self.initial
  		cstring = []
  		if cstate in livestates:
  			if cstate in self.finals:
  				yield cstring
  			strings.append((cstring, cstate))
  
  		# Fixed point calculation
  		i = 0
  		while i < len(strings):
  			(cstring, cstate) = strings[i]
  			if cstate in self.map:
  				for symbol in sorted(self.map[cstate], key=key):
  					nstate = self.map[cstate][symbol]
  					nstring = cstring + [symbol]
  					if nstate in livestates:
  						if nstate in self.finals:
  							yield nstring
  						strings.append((nstring, nstate))
  			i += 1