private Matching bestMatchFrom(List<FeatureSet> featureSetSequence, int t,  Ranking[][] rankings, List<Matching> memo){
        /* Note!  As expected, bestMatchFrom(fss, t, mwl, r, m) returns the best matching starting at (and including) the t-to-last element element, and going
         * to the end.  However, the memo stores the best matching starting at (and including) the *t'th* element.  Be careful about that!
         */ 
        
        if (featureSetSequence.size() - t < memo.size()){
            
            return memo.get(featureSetSequence.size() - t);
        } else {
            float bestProbability = 0.0f;
            List<Ranking> bestRankings = new ArrayList<Ranking>();
            List<Integer> bestPartitioning = new ArrayList<Integer>();
            for (int length = 1; length <= maxWordLength && length <= featureSetSequence.size() - t; length++){
                
                Matching bestMatchFromHere = bestMatchFrom(featureSetSequence, t + length, rankings, memo);
                float bestProbFromHere;
                if (bestMatchFromHere == null ){
                    continue;
                } else {
                    bestProbFromHere = bestMatchFromHere.getBestProbability();
                }
                
                                
                if (!rankings[t][length].isEmpty()){
                    float currentProbability = rankings[t][length].bestProbability() * bestProbFromHere;
                    if (currentProbability >= bestProbability && currentProbability != 0){
                        bestProbability = currentProbability;
                        
                        bestRankings = new ArrayList<Ranking>();
                        bestRankings.add(rankings[t][length]);
                        bestRankings.addAll(bestMatchFrom(featureSetSequence, t + length, rankings, memo).getRankings());
                        
                        
                        bestPartitioning = new ArrayList<Integer>();
                        bestPartitioning.add(length);
                        bestPartitioning.addAll(bestMatchFrom(featureSetSequence, t + length,  rankings, memo).getPartitioning());
                    }
                }
            }
            
            if (memo.size() == featureSetSequence.size() - t){
                memo.add(new Matching(bestProbability, bestRankings, bestPartitioning));
                return memo.get(featureSetSequence.size() - t);
            } else {
                throw new RuntimeException("bestMatch memo is corrupt!  it must have size " + t + " but it has size " + memo.size());   
            } 
        }
    }