protected static PairResult MatchOneRow(T todo, object objshr)
        {
            MatchShared   shared     = (MatchShared)objshr;
            BestScore <T> one_to_all = new BestScore <T>();

            // start by looking at all results for one's row
            foreach (T two in shared.twos)
            {
                double score = shared.comparisons.Evaluate(new TwoTuple <T, T>(todo, two), shared);
                one_to_all.Improve(score, two);
            }

            if (one_to_all.payload == null || one_to_all.payload.Equals(default(T)))
            {
                // no more results!  Return empty match.
                shared.ones = new SkipEnumerable <T>(shared.ones, todo);
                return(new PairResult(double.NegativeInfinity, todo, default(T)));
            }

            // Now look at all other entries in that column
            BestScore <T> match_to_others = new BestScore <T>(one_to_all.score, todo);

            foreach (T one in shared.ones)
            {
                if (!one.Equals(todo))
                {
                    double score = shared.comparisons.Evaluate(new TwoTuple <T, T>(one, one_to_all.payload), shared);
                    match_to_others.Improve(score, one);
                }
            }

            if (match_to_others.payload.Equals(todo))
            {
                // remove this row and column
                shared.ones = new SkipEnumerable <T>(shared.ones, todo);
                shared.twos = new SkipEnumerable <T>(shared.twos, one_to_all.payload);
                return(new PairResult(one_to_all.score, todo, one_to_all.payload));
            }
            else
            {
                // First do the row we found!
                shared.matches.Evaluate(match_to_others.payload, shared);
                // Then do this one again!
                return(MatchOneRow(todo, shared));
            }
        }
        // Find the best matches, ensuring one entry for every element in ones
        public static IEnumerable <PairResult> LeftMatch(IEnumerable <T> ones, IEnumerable <T> twos, MatchScorer scorer, object objshr)
        {
            MatchShared shared = new MatchShared();

            shared.objshr      = objshr;
            shared.matches     = new Memoizer <T, PairResult>(MatchOneRow);
            shared.comparisons = new Memoizer <TwoTuple <T, T>, double>(MatchComparison);
            shared.scorer      = scorer;

            shared.ones = ones;
            shared.twos = twos;

            foreach (T one in ones)
            {
                shared.matches.Evaluate(one, shared);
            }

            return(shared.matches.Results.Values);
        }
        protected static double MatchComparison(TwoTuple <T, T> onetwo, object objshr)
        {
            MatchShared shared = (MatchShared)objshr;

            return(shared.scorer(onetwo.one, onetwo.two, shared.objshr));
        }