/// <summary> /// Осуществляет декодирование алгоритмом Левенштейна. /// </summary> /// <param name="Source"></param> /// <returns></returns> public static int Decode(ByteSet Source) { int c = 0; while (Source.Value[c] != 0) { c++; } if (c == 0) { return(0); } Source.Cut(0, c + 1); int N = 1; int P = c - 1; while (P != 0) { ByteSet buffer = Source.Cut(0, N); buffer.Put(0, 1); N = 0; for (int i = buffer.Value.Length - 1; i >= 0; i--) { if (buffer.Value[i] == 1) { N += (int)Math.Pow(2, buffer.Length - 1 - i); } } P--; } return(N); }
/// <summary> /// Осуществляет кодирование алгоритмом Левенштейна. /// </summary> /// <param name="Source"></param> /// <returns></returns> public static string Encode(int Source) { if (Source == 0) { return("0"); } ByteSet Result = new ByteSet(); int buffer = Source; int C = 1; while (buffer != 0) { bool[] Binary = Misc.GetBinaryArray(buffer).Skip(1).ToArray(); buffer = Binary.Length; if (buffer == 0) { break; } Result.Put(0, Binary.Select(bol => bol ? (byte)1 : (byte)0).ToArray()); C++; } Result.Put(0, Enumerable.Repeat((byte)1, C - 1).Concat(new[] { (byte)0 }).ToArray()); return(Result.ToString()); }
/// <summary> /// Осуществляет кодирование Шеннона. /// </summary> /// <param name="Probabilities">Массив вероятностей исходного алфавита, отсортированный в порядке убывания частот.</param> /// <param name="AverageLength">Средняя длина получаемых кодовых слов.</param> /// <returns>Массив кодов слов, поставленный в соответствие каждой букве исходного алфавита в порядке убывания частот</returns> public static ByteSet[] Encode(double[] Probabilities, out double AverageLength) { AverageLength = 0; ByteSet[] Result = new ByteSet[Probabilities.Length]; double[] Probs = Probabilities.OrderByDescending(val => val).ToArray(); double Sum = 0; for (int i = 0; i < Probs.Length; i++) { Result[i] = new ByteSet(Misc.DoubleFractToString(Sum, GetL(Probs[i]))); Sum += Probs[i]; } AverageLength += Probabilities.Select((t, i) => t * Result[i].Length).Sum(); return(Result); }
/// <summary> /// Вырезает бит на нужной позиции. /// </summary> /// <param name="TargetIndex">Индекс, по которому необходимо вырезать бит.</param> internal ByteSet CutAt(int TargetIndex) { ByteSet Result = new ByteSet(); byte[] buffer = new byte[Value.Length - 1]; for (int i = 0; i < TargetIndex; i++) { buffer[i] = Value[i]; } Result.Append(Value[TargetIndex]); for (int i = TargetIndex + 1; i < Value.Length; i++) { buffer[i - 1] = Value[i]; } Value = buffer; return(Result); }
/// <summary> /// Осуществляет кодирование алгоритмом Гилберта-Мура. /// </summary> /// <param name="Probabilities">Массив вероятностей исходного алфавита, отсортированный в порядке следования букв в исходном тексте.</param> /// <param name="AverageLength">Средняя длина получаемых кодовых слов.</param> /// <returns>Массив кодов слов, поставленный в соответствие каждой букве исходного алфавита в порядке следования букв в исходном тексте.</returns> public static ByteSet[] Encode(double[] Probabilities, out double AverageLength) { AverageLength = 0; double[] Q = new double[Probabilities.Length]; ByteSet[] Result = new ByteSet[Probabilities.Length]; for (int i = 0; i < Q.Length; i++) { Q[i] += Probabilities[i] / 2; Result[i] = new ByteSet(Misc.DoubleFractToString(Q[i], (int)Math.Ceiling(-Math.Log(Probabilities[i], 2)) + 1)); for (int j = i + 1; j < Probabilities.Length; j++) { Q[j] += Probabilities[i]; } } AverageLength = Result.Select((res, ind) => res.Length * Probabilities[ind]).Sum(); return(Result); }
/// <summary> /// Вырезает нужное число бит начиная с указанной позиции. /// </summary> /// <param name="StartIndex">Индекс, начиная с которого необходимо вырезать биты.</param> /// <param name="Length">Число вырезаемых бит.</param> internal ByteSet Cut(int StartIndex, int Length) { ByteSet Result = new ByteSet(); byte[] buffer = new byte[Value.Length - Length]; for (int i = 0; i < StartIndex; i++) { buffer[i] = Value[i]; } for (int i = 0; i < Length; i++) { Result.Append(Value[StartIndex + i]); } for (int i = StartIndex + Length; i < Value.Length; i++) { buffer[i - Length] = Value[i]; } Value = buffer; return(Result); }
/// <summary> /// Инициализирует копию указанного вектора. /// </summary> /// <param name="Other">Вектор ,от которого необходимо взять копию.</param> public ByteSet(ByteSet Other) : this(Other.Value) { }
/// <summary> /// Осуществляет генерацию кодов, подходящим заданным частотам так, чтобы добиться наименьшей средней длины сообщения. /// </summary> /// <param name="Probabilities">Массив - частотный анализ исходного алфавита.</param> /// <param name="k">Система счисления, в которой будет произведено кодирование.</param> /// <param name="AverageLength">Вычисленная в процессе генерации кодов средняя длина сообщения.</param> /// <returns> /// Массив <see cref="ByteSet" />[], содержащий в себе коды, расположенные в соответствии введенным частотам в /// порядке убывания. /// </returns> public static ByteSet[] GetCodes(double[] Probabilities, int k, out double AverageLength) { AverageLength = 0; if (k >= Probabilities.Length) { ByteSet[] answer = new ByteSet[Probabilities.Length]; for (int i = 0; i < Probabilities.Length; i++) { answer[i] = new ByteSet { Value = new[] { (byte)i } }; AverageLength += Probabilities[i]; } return(answer); } //k - это число частей, на которые нам необходимо разбивать вероятности double[] ProbCop = new double[Probabilities.Length]; Probabilities.CopyTo(ProbCop, 0); Array.Sort(ProbCop, (d, d1) => Math.Sign((d1 - d))); //отсортировали свою копию массива в порядке убывания вероятностей Stack <int> Insertions = new Stack <int>(); //n - мощность исходного алфавита (кол-во вероятностей, которое на вход дали) //k - мощность конечного алфавита (система счисления) //ПЕРВАЯ СВЕРТКА int FirstConvolutionLength; if (k == 2) { FirstConvolutionLength = 2; } else { Comparison.LinearComparison k0 = new Comparison.LinearComparison(ProbCop.Length, k - 1); if (k0.A == 0) { FirstConvolutionLength = k - 1; } else if (k0.A == 1) { FirstConvolutionLength = k; } else { FirstConvolutionLength = (int)k0.A; } } double Sum = ProbCop.Skip(ProbCop.Length - FirstConvolutionLength).Sum(); Sum = Math.Round(Sum, 3); int Index = 0; int ResultLength = ProbCop.Length - FirstConvolutionLength + 1; while (ProbCop[Index] >= Sum && Index < ResultLength) { Index++; } Insertions.Push(Index); List <double> bufferProb = new List <double>(ProbCop); bufferProb.Insert(Index, Sum); ProbCop = bufferProb.Take(ResultLength).ToArray(); //Последующие свертки while (ProbCop.Length != k) { Sum = ProbCop.Skip(ProbCop.Length - k).Sum(); Sum = Math.Round(Sum, 3); //вычислили сумму последних k элементов //надо определить, на какой индекс будем вставлять Index = 0; ResultLength = ProbCop.Length - k + 1; while (ProbCop[Index] >= Sum && Index < ResultLength) { Index++; } //нашли индекс, на который необходимо вставить полученную сумму Insertions.Push(Index); bufferProb = new List <double>(ProbCop); bufferProb.Insert(Index, Sum); ProbCop = bufferProb.Take(ResultLength).ToArray(); } List <ByteSet> Answer = new List <ByteSet>(); for (int i = 0; i < ProbCop.Length; i++) { Answer.Add(new ByteSet { Value = new[] { (byte)i } }); } int Moving; List <ByteSet> buffer; //Все восстановления, кроме последнего while (Insertions.Count != 1) { Moving = Insertions.Pop(); //узнали о перестановке buffer = new List <ByteSet>(Answer); buffer.RemoveAt(Moving); for (int i = 0; i < k; i++) { buffer.Add(new ByteSet(Answer[Moving])); buffer.Last().Append((byte)i); } Answer = buffer; } //ВОССТАНОВЛЕНИЕ ПОСЛЕДНЕЙ СВЕРТКИ Moving = Insertions.Pop(); //узнали о перестановке buffer = new List <ByteSet>(Answer); buffer.RemoveAt(Moving); for (int i = 0; i < FirstConvolutionLength; i++) { buffer.Add(new ByteSet(Answer[Moving])); buffer.Last().Append((byte)i); } Answer = buffer; AverageLength += Probabilities.Select((t, i) => t * Answer[i].Length).Sum(); return(Answer.ToArray()); }