@Override
    protected void sort() {
        // initialize fields
        mmfLengths = new int[project.size()];
        mmfPrecursors = new int[project.size()][];
        int initialCount[] = new int[project.getPeriods()];
        int initialPeriods[] = new int[project.size()];
        int initialNpv = 0;
        int unusedCount = project.size();
        sanpv = project.getSaNpvTable();
        maxMmfs = project.getMaxMmfsPerPeriod();
        maxPeriod = project.getPeriods();
        boolean mmfUsed[] = new boolean[project.size()];

        // find information about all mmfs in order to save work later
        // specifically we find the information for locked mmfs here, as these
        // can not be moved later anyway
        for (int i = 0; i < project.size(); i++) {
            Mmf mmf = project.get(i);

            // if the project has no revenue we can ignore it
            boolean hasRevenue = false;
            for (int p = 1; p <= mmf.getRevenueLength(); p++) {
                if (mmf.getRevenue(p) != 0) {
                    hasRevenue = true;
                    break;
                }
            }
            if (!hasRevenue) {
                initialPeriods[i] = maxPeriod + 1;
                mmfUsed[i] = true;
                unusedCount--;
                continue;
            }

            // find development length (minimum 1)
            mmfLengths[i] = mmf.getPeriodCount();

            // precursor matrix
            List<Mmf> pre = mmf.getPrecursors();
            if (pre.size() > 0) {
                mmfPrecursors[i] = new int[pre.size()];
                for (int j = 0; j < mmfPrecursors[i].length; j++) {
                    mmfPrecursors[i][j] = project.getMmfs().indexOf(pre.get(j));
                }
            }

            // locked MMFs are added directly to initial* and marked as used
            if (mmf.isLocked()) {
                initialPeriods[i] = mmf.getPeriod();
                for (int p = initialPeriods[i] - 1; p < initialPeriods[i]
                        + mmfLengths[i] - 1; p++) {
                    initialCount[p]++;
                }
                if (initialPeriods[i] <= maxPeriod) {
                    initialNpv += sanpv[i][initialPeriods[i] - 1];
                }
                mmfUsed[i] = true;
                unusedCount--;
            }
        }

        setProgressMax(alternativeCount(unusedCount));

        chooseNext(mmfUsed, unusedCount, new int[unusedCount], 0, initialCount,
                initialPeriods, new int[] { 1, initialNpv });
    }