public static IEnumerable <PidAndHlaSet> GetEnumerationSparse(TextReader inputTextReader)
        {
            string previousPid = null;
            Dictionary <string, List <HlaMsr1> > classToHlaList = null;
            HashSet <string> warningSet = null;

            foreach (var pidAndHlaRecord in SpecialFunctions.ReadDelimitedFile(inputTextReader, new { pid = "", hla = "" }, new char[] { '\t' }, true))
            {
                string pid = pidAndHlaRecord.pid;
                if (previousPid != pid)
                {
                    if (previousPid != null)
                    {
                        PidAndHlaSet pidAndHlaSet = CreatePidAndHlaSet(previousPid, classToHlaList, warningSet);
                        yield return(pidAndHlaSet);
                    }
                    previousPid    = pid;
                    classToHlaList = new Dictionary <string, List <HlaMsr1> >();
                    warningSet     = new HashSet <string>();
                }
                HlaMsr1        hlaMsr1 = (HlaMsr1)HlaMsr1Factory444.GetGroundOrAbstractInstance(pidAndHlaRecord.hla, ref warningSet);
                List <HlaMsr1> hlaList = classToHlaList.GetValueOrDefault(hlaMsr1.ClassName);
                hlaList.Add(hlaMsr1);
            }
            if (previousPid != null)
            {
                PidAndHlaSet pidAndHlaSet = CreatePidAndHlaSet(previousPid, classToHlaList, warningSet);
                yield return(pidAndHlaSet);
            }
        }
        internal void Prenormalize(PidAndHlaSet pidAndHlaSet, Linkdis linkdis)
        {
            PhaseToLogProb       = new Dictionary <UOPair <LinkedList1 <HlaMsr1> >, double>();
            UnphaseToLogProb     = new Dictionary <LinkedList1 <UOPair <HlaMsr1> >, double>();
            LogTotal             = double.NegativeInfinity;
            BadHlaMsr1NameOrNull = null;
            UsedLowerResModel    = false;

            //CounterWithMessages abstractPhaseCounter = CounterWithMessages.GetInstance("\tabstract phase index = {0}", 1, null);

            try
            {
                foreach (var phaseAbstract in pidAndHlaSet.GetPhasedEnumeration())
                {
                    //abstractPhaseCounter.Increment();

                    var firstHlaListToProb  = linkdis.CreateHlaListToProb(phaseAbstract.First);
                    var secondHlaListToProb = linkdis.CreateHlaListToProb(phaseAbstract.Second);
                    if (firstHlaListToProb.Count * secondHlaListToProb.Count > linkdis.CombinationLimit)
                    {
                        throw new CombinationLimitException("The combinationLimit was exceeded. " + linkdis.CombinationLimit.ToString());
                    }

                    CounterWithMessages groundPhaseCounter = CounterWithMessages.GetInstance("\t\tground phase index = {0}", 1000, null);
                    foreach (var firstHlaListAndProb in firstHlaListToProb)
                    {
                        foreach (var secondHlaListAndProb in secondHlaListToProb)
                        {
                            groundPhaseCounter.Increment();

                            var phaseGrounded = UOPair <LinkedList1 <HlaMsr1> > .GetInstance(firstHlaListAndProb.Key, secondHlaListAndProb.Key);

                            var unphasedGrounded = MakeUnphased(phaseGrounded);

                            double prob = firstHlaListAndProb.Value.Key * secondHlaListAndProb.Value.Key;
                            UsedLowerResModel |= firstHlaListAndProb.Value.Value || secondHlaListAndProb.Value.Value;
                            double logProb = Math.Log(prob);


                            LogSum(PhaseToLogProb, phaseGrounded, logProb);
                            LogSum(UnphaseToLogProb, unphasedGrounded, logProb);
                            LogTotal = SpecialFunctions.LogSum(LogTotal, logProb);
                        }
                    }
                }
            }
            catch (HlaNotInModelException e)
            {
                CreateNoAnswerAnswer(pidAndHlaSet, e);
            }
        }
        public ExpansionCollection ExpandOrNullIfTooMany(PidAndHlaSet pidAndHlaSet)
        {
            try
            {
                ExpansionCollection expansionCollection = new ExpansionCollection();
                expansionCollection.Prenormalize(pidAndHlaSet, this);
                //expansionCollection.LogTotal = Prenormalize(pidAndHlaSet, out expansionCollection.PhaseToLogProb, out expansionCollection.UnphaseToLogProb);


                return(expansionCollection);
            }
            catch (CombinationLimitException)
            {
            }
            return(null);
        }
        public static IEnumerable <PidAndHlaSet> GetEnumerationDense(TextReader inputTextReader)
        {
            foreach (var pidAndHlaRecord in SpecialFunctions.ReadDelimitedFile(inputTextReader, new { pid = "", A1 = "", A2 = "", B1 = "", B2 = "", C1 = "", C2 = "" }, new char[] { '\t' }, true))
            {
                PidAndHlaSet pidAndHlaSet = new PidAndHlaSet();
                pidAndHlaSet.Pid           = pidAndHlaRecord.pid;
                pidAndHlaSet.WarningSet    = new HashSet <string>();
                pidAndHlaSet.HlaUopairList = LinkedList1 <UOPair <HlaMsr1> > .GetInstance(
                    UOPair <HlaMsr1> .GetInstance(CreateHla(pidAndHlaRecord.C1, ref pidAndHlaSet.WarningSet), CreateHla(pidAndHlaRecord.C2, ref pidAndHlaSet.WarningSet)),
                    UOPair <HlaMsr1> .GetInstance(CreateHla(pidAndHlaRecord.B1, ref pidAndHlaSet.WarningSet), CreateHla(pidAndHlaRecord.B2, ref pidAndHlaSet.WarningSet)),
                    UOPair <HlaMsr1> .GetInstance(CreateHla(pidAndHlaRecord.A1, ref pidAndHlaSet.WarningSet), CreateHla(pidAndHlaRecord.A2, ref pidAndHlaSet.WarningSet)));

                pidAndHlaSet.ClassList = new List <string> {
                    "C", "B", "A"
                };
                yield return(pidAndHlaSet);
            }
        }
        private void CreateNoAnswerAnswer(PidAndHlaSet pidAndHlaSet, HlaNotInModelException e)
        {
            PhaseToLogProb   = new Dictionary <UOPair <LinkedList1 <HlaMsr1> >, double>();
            UnphaseToLogProb = new Dictionary <LinkedList1 <UOPair <HlaMsr1> >, double>();

            BadHlaMsr1NameOrNull = e.HlaName;
            UsedLowerResModel    = true;

            var phaseGrounded = UOPair <LinkedList1 <HlaMsr1> > .GetInstance(
                LinkedList1 <HlaMsr1> .GetInstanceFromList(pidAndHlaSet.HlaUopairList.Select(pair => pair.First).ToList()),
                LinkedList1 <HlaMsr1> .GetInstanceFromList(pidAndHlaSet.HlaUopairList.Select(pair => pair.Second).ToList())
                );

            var unphasedGrounded = pidAndHlaSet.HlaUopairList;

            double logProb = double.NaN;

            LogSum(PhaseToLogProb, phaseGrounded, logProb);
            LogSum(UnphaseToLogProb, unphasedGrounded, logProb);
        }
        private static PidAndHlaSet CreatePidAndHlaSet(string previousPid, Dictionary <string, List <HlaMsr1> > classToHlaList, HashSet <string> warningSet)
        {
            SpecialFunctions.CheckCondition(new HashSet <string>(classToHlaList.Keys).SetEquals(new HashSet <string> {
                "A", "B", "C"
            }), "Expect Hla's for exactly classes A,B, & C. " + previousPid);
            SpecialFunctions.CheckCondition(classToHlaList.Values.All(list => list.Count == 2), "Expect two hla lines for each Hla class. " + previousPid);
            PidAndHlaSet pidAndHlaSet = new PidAndHlaSet();

            pidAndHlaSet.Pid           = previousPid;
            pidAndHlaSet.WarningSet    = warningSet;
            pidAndHlaSet.HlaUopairList = LinkedList1 <UOPair <HlaMsr1> > .GetInstance(
                UOPair <HlaMsr1> .GetInstance(classToHlaList["C"][0], classToHlaList["C"][1]),
                UOPair <HlaMsr1> .GetInstance(classToHlaList["B"][0], classToHlaList["B"][1]),
                UOPair <HlaMsr1> .GetInstance(classToHlaList["A"][0], classToHlaList["A"][1]));

            pidAndHlaSet.ClassList = new List <string> {
                "C", "B", "A"
            };
            return(pidAndHlaSet);
        }
        static void Main(string[] args)
        {
            //HlaMsr1Factory.UnitTest();

            try
            {
                ArgCollection argCollection = ArgCollection.GetInstance(args);

                string ethnicityName = argCollection.ExtractOptional <string>("ethnicity", "").ToLowerInvariant();
                SpecialFunctions.CheckCondition(Linkdis.EthnicityNameLowerList().Contains(ethnicityName), string.Format("'-ethnicity ETHNICITY' is required, where ETHNICITY is " + Linkdis.EthnicityNameMixedList().StringJoin(", ")));
                int  outputLineLimit  = argCollection.ExtractOptional <int>("outputLineLimit", 100000);
                int  combinationLimit = argCollection.ExtractOptional <int>("combinationLimit", 10000);
                bool isSparse         = argCollection.ExtractOptionalFlag("sparse");

                argCollection.CheckNoMoreOptions(3);

                string inputFileName          = argCollection.ExtractNext <string>("inputFile");
                string phasedOutputFileName   = argCollection.ExtractNext <string>("phasedOutputFile");
                string unphasedOutputFileName = argCollection.ExtractNext <string>("unphasedOutputFile");
                argCollection.CheckThatEmpty();

                Linkdis linkdis = Linkdis.GetInstance(ethnicityName, combinationLimit);

                string versionName = string.Format("MSCompBio HLA Completion v. {0}", GetVersionString());


                CounterWithMessages pidCounter = CounterWithMessages.GetInstance("Pid index = {0}", 1, null);

                int outputLineIndex = -1;
                using (TextWriter phasedTextWriter = File.CreateText(phasedOutputFileName),
                       unphasedTextWriter = File.CreateText(unphasedOutputFileName))
                {
                    phasedTextWriter.WriteLine(versionName + "\n");
                    unphasedTextWriter.WriteLine(versionName + "\n");

                    phasedTextWriter.WriteLine("pid" + "\t" + PhasedExpansion.Header);
                    unphasedTextWriter.WriteLine("pid" + "\t" + UnphasedExpansion.Header);
                    outputLineIndex += 6;

                    HashSet <string> warningSet = new HashSet <string>();
                    using (TextReader textReader = File.OpenText(inputFileName))
                    {
                        foreach (PidAndHlaSet pidAndHlaSet in isSparse ? PidAndHlaSet.GetEnumerationSparse(textReader) : PidAndHlaSet.GetEnumerationDense(textReader))
                        {
                            pidCounter.Increment();
                            warningSet.UnionWith(pidAndHlaSet.WarningSet);

                            ExpansionCollection expansionCollectionOrNull = linkdis.ExpandOrNullIfTooMany(pidAndHlaSet);

                            if (null == expansionCollectionOrNull)
                            {
                                phasedTextWriter.WriteLine(pidAndHlaSet.Pid + "\t" + PhasedExpansion.TooManyCombinationsMessage());
                                unphasedTextWriter.WriteLine(pidAndHlaSet.Pid + "\t" + UnphasedExpansion.TooManyCombinationsMessage());
                                warningSet.Add(string.Format("Error: Too many combinations, case {0} skipped", pidAndHlaSet.Pid));
                                outputLineIndex += 2;
                                if (outputLineIndex > outputLineLimit)
                                {
                                    goto TOOMANYLINES;
                                }
                            }
                            else
                            {
                                foreach (PhasedExpansion phasedExpansion in expansionCollectionOrNull.Phased())
                                {
                                    string phasedLine = pidAndHlaSet.Pid + "\t" + phasedExpansion.ToString();
                                    phasedTextWriter.WriteLine(phasedLine);
                                    if (phasedExpansion.BadHlaNameOrNull != null)
                                    {
                                        warningSet.Add(phasedLine);
                                    }
                                    ++outputLineIndex;
                                    if (outputLineIndex > outputLineLimit)
                                    {
                                        goto TOOMANYLINES;
                                    }
                                }

                                foreach (UnphasedExpansion unphasedExpansion in expansionCollectionOrNull.Unphased())
                                {
                                    string unphasedLine = pidAndHlaSet.Pid + "\t" + unphasedExpansion.ToString();
                                    unphasedTextWriter.WriteLine(unphasedLine);
                                    if (unphasedExpansion.BadHlaNameOrNull != null)
                                    {
                                        warningSet.Add(unphasedLine);
                                    }

                                    ++outputLineIndex;
                                    if (outputLineIndex > outputLineLimit)
                                    {
                                        goto TOOMANYLINES;
                                    }
                                }
                            }
                        }
                    }

                    goto INANYCASE;
TOOMANYLINES:
                    string tooManyLinesMessage = string.Format("ERROR: The line limit of {0} was reached and output was ended early", outputLineLimit);
                    phasedTextWriter.WriteLine(tooManyLinesMessage);
                    unphasedTextWriter.WriteLine(tooManyLinesMessage);
                    warningSet.Add(tooManyLinesMessage);
INANYCASE:
                    Console.Error.WriteLine(warningSet.StringJoin("\n"));
                }
            }
            catch (Exception exception)
            {
                Console.WriteLine(exception.Message);
                if (exception.InnerException != null)
                {
                    Console.WriteLine(exception.InnerException.Message);
                }

                Console.Error.WriteLine(@"
 
USAGE 

HlaCompletion -ethnicity ETHNICITY [-outputLineLimit 100000] [-sparse] [-combinationLimit 10000] inputFile phaseFile unphaseFile 
where ETHNICITY is {0}
'outputLineLimit' limits the total lines of output. If it is reached, a warning message is written as the last line of the output.
'combinationLimit' limits the number of combinations of HLAs consider in one phase for one case.
        It is is reached, an error message is output for that case in place of results.
'-sparse' reads files in sparse format
 
", Linkdis.EthnicityNameMixedList().StringJoin(", "));

                System.Environment.Exit(-1);
            }
        }