【问题标题】:complexity compression string复杂度压缩字符串
【发布时间】:2012-08-24 18:55:53
【问题描述】:

我有一个大型理论字符串(104 个字符长)数据库生成程序,它返回以 PB 为单位的结果。我没有那么多的计算能力,所以我想从数据库中过滤出低复杂度的字符串。

我的语法是英文字母表的修改形式,没有数字字符。我读到了Kolmogorov Complexity 以及theoretically impossible to calculate 的内容,但我只需要使用压缩的 C# 基本知识。

使用这两个链接

我想出了这个:

MemoryStream ms = new MemoryStream();

GZipStream gzip2 = new GZipStream(ms, CompressionMode.Compress, true);

byte[] raw = Encoding.UTF8.GetBytes(element);
gzip2.Write(raw, 0, raw.Length);
gzip2.Close();

byte[] zipped = ms.ToArray(); // as a BLOB
string smallstring = Convert.ToString(zipped); // as a string
// store zipped or base64
byte[] raw2 = Encoding.UTF8.GetBytes(smallstring);
int startsize = raw.Length;
int finishsize = raw2.Length;
double percent = Convert.ToDouble(finishsize) / Convert.ToDouble(startsize);
if (percent > .75)
{
    ///output
}

我的第一个元素是:

啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊!

它会压缩到 13 个字符的大小,但这是另一个字符集

mlcllltlgvalvcgvpamdipqtkqdellplagtwhsmamatnnislmatlkaplrvhitsllptpednleivlhrwennscvekkvlgektenpkkfkinytvaneatlldtdydnflflclqdtttpiqsmmcqylarvlveddeimqgfirafrplprhlwylldlkqmeepcrf

也计算为 13。有一个错误,但我不知道如何修复它。

【问题讨论】:

  • 压缩后的缓冲区是否解压为原始字符串?如果是这样,那么它可能适用于“作品”的某些定义。
  • 你也可以试试#ziplib中的其他压缩算法——特别是bzip2应该比gzip获得更好的压缩比,从而更准确地估计信息内容。 (从通用算法来看,LZMA 应该会更好,7zip SDK 中提供了 C# 实现。)也就是说,压缩效果越好(估计越准确),所需的资源就越多。跨度>
  • 另外,为什么要将压缩流转换为字符串,然后再转换为数组?看来您应该将 raw.Length 与 zipped.Length 进行比较。
  • 最后但同样重要的是,gzip 流可能包含某种标题。如果您只想要压缩有效负载的大小,您应该查看相关规范以查看是否需要将其剥离。
  • @millimoose 谢谢,我觉得有些东西看起来不对,让我检查一下

标签: c# string compression complexity-theory


【解决方案1】:

您的错误是将数组转换为字符串的以下部分:

byte[] zipped = ms.ToArray(); // as a BLOB
string smallstring = Convert.ToString(zipped); // as a string
// store zipped or base64
byte[] raw2 = Encoding.UTF8.GetBytes(smallstring);

在数组上调用Convert.ToString() 将返回一些调试输出,在本例中为字符串System.Byte[]。 (请参阅ideone 上的以下示例。)

你应该直接比较未压缩和压缩字节数组的长度:

int startsize = raw.Length;
int finishsize = zipped.Length;

【讨论】:

    【解决方案2】:

    这是我使用的代码

    /// <summary>
    /// Defines an interface to calculate relevant 
    /// to the input complexity of a string
    /// </summary>
    public interface IStringComplexity
    {
        double GetCompressionRatio(string input);
        double GetRelevantComplexity(double min, double max, double current);
    }
    

    以及实现它的类

    public class GZipStringComplexity : IStringComplexity
    {
        public double GetCompressionRatio(string input)
        {
            if (string.IsNullOrEmpty(input))
                throw new ArgumentNullException();
    
            byte[] inputBytes = Encoding.UTF8.GetBytes(input);
            byte[] compressed;
    
            using (MemoryStream outStream = new MemoryStream())
            {
                using (var zipStream = new GZipStream(
                    outStream, CompressionMode.Compress))
                {
                    using (var memoryStream = new MemoryStream(inputBytes))
                    {
                        memoryStream.CopyTo(zipStream);
                    }
                }
                compressed = outStream.ToArray();
            }
    
            return (double)inputBytes.Length / compressed.Length;
        }
    
        /// <summary>
        /// Returns relevant complexity of a string on a scale [0..1], 
        /// where <value>0</value> has very low complexity
        /// and <value>1</value> has maximum complexity
        /// </summary>
        /// <param name="min">minimum compression ratio observed</param>
        /// <param name="max">maximum compression ratio observed</param>
        /// <param name="current">the value of compression ration
        /// for which complexity is being calculated</param>
        /// <returns>A relative complexity of a string</returns>
        public double GetRelevantComplexity(double min, double max, double current)
        {
            return 1 - current / (max - min);
        }
    }
    

    这里是你如何使用它

    class Program
    {
        static void Main(string[] args)
        {
            IStringComplexity c = new GZipStringComplexity();
    
            string input1 = "HHHFHHFFHHFHHFFHHFHHHFHAAAAHHHFHHFFHHFHHFFHHFHHHFHAAAAHHHFHHFFHHFHHFFHHFHHHFHAAAAHHHFHHFFHHFHHFFHHFHHHFH";
            string input2 = "mlcllltlgvalvcgvpamdipqtkqdlelpklagtwhsmamatnnislmatlkaplrvhitsllptpednleivlhrwennscvekkvlgektenpkkfkinytvaneatlldtdydnflflclqdtttpiqsmmcqylarvlveddeimqgfirafrplprhlwylldlkqmeepcrf";
            string inputMax = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
    
            double ratio1 = c.GetCompressionRatio(input1); //2.9714285714285715
            double ratio2 = c.GetCompressionRatio(input2); //1.3138686131386861
            double ratioMax = c.GetCompressionRatio(inputMax); //7.5
    
            double complexity1 = c.GetRelevantComplexity(1, ratioMax, ratio1); // ~ 0.54
            double complexity2 = c.GetRelevantComplexity(1, ratioMax, ratio2); // ~ 0.80
        }
    }
    

    一些我认为有用的附加信息。

    您可以尝试使用来自7zip library 的 LZMA、LZMA2 或 PPMD​​。这些相对容易设置,并且提供您可以实现多种压缩算法的接口。我发现这些算法的压缩性能比 GZip 好得多,但是如果你把压缩比放在一个比例上,这并不重要。

    如果您需要一个归一化的值,例如从 0 到 1,则需要首先计算所有序列的压缩比。这是因为您无法确定可能的 max 压缩率是多少。

    【讨论】:

      【解决方案3】:

      当然可以。只要你只是比较大小,你使用什么压缩算法并不重要。您主要关心的是密切关注您用于压缩字符串的处理能力。

      【讨论】:

      • 啊。好吧,您的方法是一个不错的方法(检查压缩长度)-我想我没有注意到您那里有错误。 :)
      猜你喜欢
      • 1970-01-01
      • 2018-08-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多