public static CipherPredictionDictionary PairFrequencyPrediction(int[] data, IEnumerable <int> codelist, CipherPair eof = null)
        {
            const double PROBABILITY_COEFFICIENT = 0.3;
            const int    PRED_DISTANCE           = 6;

            ulong[] freqs = CalcPairFreqs(data, codelist.ToArray(), eof);
            var     dict  = new CipherPredictionDictionary(freqs.Length + 1);

            for (int i = 0; i < freqs.Length; i++)
            {
                CipherPossibilities poss1 = dict.Add((int)(freqs[i] >> 32));           //first char
                CipherPossibilities poss2 = dict.Add((int)(freqs[i] & uint.MaxValue)); //second char
                //loop over indexes from (i - PRED_DISTANCE) to (i + PRED_DISTANCE), within the bounds of the array
                for (int j = Math.Max(i - PRED_DISTANCE, 0); j < Math.Min(i + PRED_DISTANCE + 1, pairFreqOrder.Length); j++)
                {
                    double prob = (PRED_DISTANCE - Math.Abs(i - j)) / (double)PRED_DISTANCE * PROBABILITY_COEFFICIENT;
                    poss1.Assimilate(pairFreqOrder[j][0], prob);
                    poss2.Assimilate(pairFreqOrder[j][1], prob);
                }
            }
            return(dict);
        }
        public static CipherPredictionDictionary KnownWordPrediction(int[] data, string word)
        {
            const double PROBABILITY_PER_CHAR = 0.0625;

            var pd     = new CipherPredictionDictionary();
            int wstart = FindWord(data, word);

            if (wstart == -1)
            {
                return(pd);
            }
            for (int i = wstart; i - wstart < word.Length; i++)
            {
                pd.Add(data[i]).Add(word[i - wstart], PROBABILITY_PER_CHAR * word.Length);
            }
            return(pd);
        }
        public static CipherPredictionDictionary AggregateProbabilities(IEnumerable <CipherPredictionDictionary> dicts, IEnumerable <int> codelist)
        {
            CipherPredictionDictionary final = new CipherPredictionDictionary(codelist.Count());

            foreach (int code in codelist) //for all possible codes
            {
                //initialize a new entry for this code
                CipherPossibilities curP = final.Add(code);
                foreach (CipherPredictionDictionary dict in dicts)              //for all available dictionaries
                {
                    CipherPossibilities p = dict.GetPossibilitiesForCode(code); //check if it contains possibilities for the code we're looking for
                    if (p != null)
                    {
                        curP.Assimilate(p); //if so, assimilate it
                    }
                }
            }

            return(final);
        }
        public static CipherPredictionDictionary FirstLetterPrediction(int[] data, int spaceCode)
        {
            const double PROBABILITY_COEFFICIENT = 0.6;
            const int    PRED_DISTANCE           = 3;

            int[] freqs = CalcFirstFreqs(data, spaceCode);
            var   dict  = new CipherPredictionDictionary(freqs.Length + 1);

            for (int i = 0; i < freqs.Length; i++)
            {
                CipherPossibilities poss = dict.Add(freqs[i]);
                //loop over indexes from (i - PRED_DISTANCE) to (i + PRED_DISTANCE), within the bounds of the array
                for (int j = Math.Max(i - PRED_DISTANCE, 0); j < Math.Min(i + PRED_DISTANCE + 1, firstFreqOrder.Length); j++)
                {
                    poss.Add(singleFreqOrder[j], (PRED_DISTANCE - Math.Abs(i - j)) / (double)PRED_DISTANCE * PROBABILITY_COEFFICIENT);
                }
            }

            return(dict);
        }
        public static CipherPredictionDictionary SingleFrequencyPrediction(int[] data, CipherPair eof = null)
        {
            const double PROBABILITY_COEFFICIENT = 0.2;
            const int    PRED_DISTANCE           = 4;

            int[] freqs = CalcSingleFreqs(data, eof);
            var   dict  = new CipherPredictionDictionary(freqs.Length + 1);

            for (int i = 0; i < freqs.Length; i++)
            {
                CipherPossibilities poss = dict.Add(freqs[i]);
                //loop over indexes from (i - PRED_DISTANCE) to (i + PRED_DISTANCE), within the bounds of the array
                for (int j = Math.Max(i - PRED_DISTANCE, 0); j < Math.Min(i + PRED_DISTANCE + 1, singleFreqOrder.Length); j++)
                {
                    poss.Add(singleFreqOrder[j], (PRED_DISTANCE - Math.Abs(i - j)) / (double)PRED_DISTANCE * PROBABILITY_COEFFICIENT);
                }
            }
            dict.Insert(dict.Count, new CipherPossibilities(eof, 1.0));

            return(dict);
        }