def create_partitions(aut, partition_list, state_function, obs_events):
    """
    Compute the fixed point of the partioning.

    @param aut: Automaton being partioned.
    @type  aut: L{BaseAutomaton}

    @param partition_list: Initial state partitions.
    @type  partition_list: C{list} of C{set} of L{State}

    @param state_function: Mapping of state to partition number.
    @type  state_function: C{dict} of L{State} to C{int}

    @param obs_events: Events relevant for the partitioning.
    @type  obs_events: C{set} of L{Event}

    @return: Fixed point partitioning of the states of L{aut}.
    @rtype: C{list} of C{set} of L{State}

    @invariant: state in partition_list[i] <=> state_function[state] == i
    """
    nonobs_events = aut.alphabet.difference(obs_events)

    changed_partitions = []

    # Perform partitioning of the states iteratively
    unfinished = True
    while unfinished:
        unfinished = False
        for evt in obs_events:

            for partition in partition_list:

                # Compute set of ancestor states from partition that have
                # outgoing 'evt'
                if len(nonobs_events) > 0:
                    p_start = aut.coreachable_states_set(partition,
                                                         nonobs_events)
                else:
                    # No events to extend the set, use the original set.
                    p_start = partition

                ancestor_set = set(edge.pred
                                   for state in p_start
                                   for edge in state.get_incoming(evt))

                if len(ancestor_set) == 0:
                    continue

                if len(nonobs_events) > 0:
                    ancestor_set = aut.coreachable_states_set(ancestor_set,
                                                              nonobs_events)

                # Clear existing changed_partitions sets, and optionally
                # extend the list to the new set of partitions
                for partition in changed_partitions:
                    partition.clear()
                while len(changed_partitions) < len(partition_list):
                    changed_partitions.append(set([]))

                # Add successors of all ancestors into the current partitioning
                for state in ancestor_set:
                    changed_partitions[state_function[state]].add(state)

                for i, changed_subset in enumerate(changed_partitions):
                    if len(changed_subset) == 0:
                        continue

                    # If a changed_partitions[] entry has changed (and is
                    # used), we have found a new point to partition on
                    if changed_subset != partition_list[i]:
                        partition_list[i].difference_update(changed_subset)

                        partition_list.append(changed_subset.copy())
                        new_partition_number = len(partition_list) - 1
                        for state in changed_subset:
                            state_function[state] = new_partition_number
                        unfinished = True

                    else:
                        changed_partitions[i].clear()

    return partition_list