package no.ntnu.mmfplanner.model; import java.util.ArrayList; import java.util.Collections; import java.util.List; /** * This class uses the IFM heuristic, also known as the weighted look-ahead * approach, to find the optimal NPV of a project. */ public class HeuristicProjectSorter extends ProjectSorter { /** * @param project */ public HeuristicProjectSorter(Project project) { super(project); } @Override protected void sort() { setProgressMax(1); // Initialize variables List<Mmf> mmfs = project.getMmfs(); int[] periods = new int[project.size()]; List<Mmf> finalStrand = new ArrayList<Mmf>(); int finalPeriod = 0; int finalNpv = 0; List<Mmf> unusedMmfs = new ArrayList<Mmf>(mmfs); // repeatedly find the most profitable MMF using the look-ahead // approach, and add this to the final strand while (unusedMmfs.size() > 0) { List<List<Mmf>> strands = generateStrands(unusedMmfs, finalStrand); int maxNpv = Integer.MIN_VALUE; Mmf maxMmf = null; // Calculate npvs for all strands, and add the most profitable to the final strand for (List<Mmf> strand : strands) { int period = finalPeriod; int npv = 0; for (Mmf mmf : strand) { npv += mmf.getSaNpv(project.getInterestRate(), period); period += mmf.getPeriodCount(); } if (npv >= maxNpv) { maxNpv = npv; maxMmf = strand.get(0); } } // we found the most profitable MMF, add it and remove it from // unusedMmfs unusedMmfs.remove(maxMmf); finalStrand.add(maxMmf); finalNpv += maxMmf.getSaNpv(project.getInterestRate(), finalPeriod); ; periods[project.getMmfs().indexOf(maxMmf)] = finalPeriod + 1; finalPeriod += maxMmf.getPeriodCount(); } addResult(finalNpv, periods); setProgress(1); } /** * Generates all MMF-strands from the given MMFs. * * @param usedMmfs * * @param usedMmfs * @return */ private List<List<Mmf>> generateStrands(List<Mmf> availableMmfs, List<Mmf> usedMmfs) { List<List<Mmf>> strands = new ArrayList<List<Mmf>>(); List<Mmf> mmfs = new ArrayList<Mmf>(availableMmfs); // repeat until no more mmfs are available while (mmfs.size() > 0) { for (int i = mmfs.size() - 1; i >= 0; i--) { Mmf mmf = mmfs.get(i); List<Mmf> precursors = new ArrayList<Mmf>(mmf.getPrecursors()); precursors.removeAll(usedMmfs); // if this mmf has no precursors, add it to the strands if (precursors.size() == 0) { strands.add(Collections.singletonList(mmf)); mmfs.remove(mmf); continue; } // go over all the existing strands, if all precursors are // available in a strand, and the strand contain only these // precursors: add the given mmf and remove it from // the available mmfs. for (int j = 0; j < strands.size(); j++) { List<Mmf> strand = strands.get(j); if ((strand.size() == precursors.size()) && strand.containsAll(precursors)) { ArrayList<Mmf> newStrand = new ArrayList<Mmf>(strand); newStrand.add(mmf); strands.add(newStrand); mmfs.remove(mmf); } } } } return strands; } }