class EquitablePartitionRefiner {

    public Partition refine(Partition coarser) {
        Partition finer = new Partition(coarser);

        // start the queue with the blocks of a in reverse order
        blocksToRefine = new LinkedList<Set<Integer>>();
        for (int i = 0; i < finer.size(); i++) {
            blocksToRefine.add(finer.copyBlock(i));
        }

        int numberOfVertices = refinable.getVertexCount();
        while (!blocksToRefine.isEmpty()) {
            Set<Integer> t = blocksToRefine.remove();
            currentBlockIndex = 0;
            while (currentBlockIndex < finer.size() && finer.size() < numberOfVertices) {
                if (!finer.isDiscreteCell(currentBlockIndex)) {

                    // get the neighbor invariants for this block
                    Map<Invariant, SortedSet<Integer>> invariants = getInvariants(finer, t);

                    // split the block on the basis of these invariants
                    split(invariants, finer);
                }
                currentBlockIndex++;
            }

            // the partition is discrete
            if (finer.size() == numberOfVertices) {
                return finer;
            }
        }
        return finer;
    }

    public  EquitablePartitionRefiner(Refinable refinable);

}