压缩:异或,递推,
通过记录一个基准值,然后记录后续值在其上的变化,相当于只记录那些变化的部分,然后要用的时候就再逆推求回去
1.值在不断变化
2.要记录那些变化的值
问题(why):异或策略实际上包含很少的尾随零
什么时候会出现这种情况:如111111,再加1,就会成1000000,这时尾随零就很少,而会变得有很多中心位;所以,这种策略往往会因为这样的原因使中心位(即不同的数字)很多而达不到预期的压缩效果,
所以改进,使其尽量变为不进位,或者与之最接近的最好压缩效果的数字
就是图像效果不平均,方差很大,通过优化使方差变小,从而更接近平均的预期效果
值发生改变时,尾随零很少,多的是前导零
策略是擦除后面几位,对值影响很小,但是可以增加尾随零,从而提升压缩空间,又不至于牺牲很多信息
擦除:设置为0
为什么是0
如果位数发生大规模变化,可能是+1,进位导致的
原值减去一个策略找到的数(b),得到一个好的值(v’),这个值可以让elf压缩效果很好,解压时先得到这个好的值,再加上之前减去的值,得到原值
这个策略找到的数(b)介于0与10-a之间,即先确定a,再确定b
文里是直接加10-a,得到的结果会大一点,但是直接把后面多余的都擦除掉(?),从而得到原值
1。异或为0,即v减去后得到的v’和变化后的值一摸一样
2.异或不为0,即减去后不一样,中心位(不一样的数,即发生改变的部分)小于16(是期待的结果)
3.大于16
?C是什么
C是一种标志,
是前导0相同,且发生变化后的尾随0多于变化前的尾随0(说明发生了连续进位)
比如变化之前是11 1100,变化后成100 0000,即只改变了4,但是使变化后的值进位,多了很多尾随零,会增加压缩成本,这时就要打上C标志
即C标志是用来针对那些地位发生连续进位的情况
要想连续进位,首先需要一串连续的1,或者其之间间隔很小
并且位置在低位,可以付出很小的改变代价来改变很多的位数
?关注尾随0,是因为后面几位的数要发生改变代价很小,很容易发生改变,从0到1或从1到0,从而使后面几位发生连续的变化
如果变化较小,那么不会到达连续进位的阈值(即使一串连续的1变为0)尾随0
这里,存在一种阈值,就是这串连续的1的最低位1到第一位的位数,这个位数越低,改变需要付出的代价越小,越容易发生变化,使尾随0激增;位数越高,改变需要付出的代价越大,即只有显著的改变才会使到达这一位1,从而使其发生0的大规模增加;
如果达不到阈值,就是在这个最低位1之前的位数做变化,变化会产生1,其会不断与最低为1连接,使连续的1越来越长,位数越来越低,阈值变小,直到到第一位,再增加就引发进位
如果没有C,就说明没有通过付出小代价使一串1变化,C就是针对一串1连接在一起并发生进位的情况(也不一定)
0010 1110,只需变化2,就可0011 0000,
?还有其他情况是1并没有很长的连续,或者1,0分布比较均匀,很参差
这时也会有与之互补对应的小代价使其发生变化
0010 0101,变化3,就可 0010 1000,这里就不是一串连续的1,打上C标志
但C是标记那些通过小代价发生大改变的标识(主要通过进位,把1变成0来实现)
C并不包含全部情况,因为如果改变(在发生进位)后,又做出小的改变,打断了尾随0的连续,甚至使其与变化前的尾随0位数一致,C就检测不出来
还如0010 1110,变化2为0011 0000
但再变化2就为0011 0010,尾随0一致,就检测不出来,甚至只需再变化1,就可0011 0001,尾随0甚至比原值还小,C就检测不出来,即C可以很好的检测出临界状况,即恰好使其发生进位时的大规模变化,但如果变化之后,又发生细小的变化,打断了变化后的尾随0长序列,C就无法检测出
这时就需要2,3情况的检测,
2主要是那些平常的小改变,即在前面的基础上没有进位,只是在进位前的位数做一些小改变,中心位变化较小
3就是来针对在进位后的小改变,使C无法检测出的情况,即中心位发生了大规模变化,但是因为小改变打断了尾随0的连续,使检测不到中间部分中心位的变化,打不上C标识的情况
?01是什么意思,代表什么
说还有很大的改进空间
因为1.不考虑不同数据集中前导0的不同分布(部分3)?
2.而且还用了额外的标识来区分情况2和3,说用了5个或7个字节来记录那些变化的中心位(0 0000(16位)-000 0000(64位)),增大了开销(因为不管有没有发生都要记录)(部分四)
3.说用标识C可能节约的字节并不比其额外的开销多(部分五)
说文章改进了这个方法,就前导0提出了一种新方式去记录,从而使它可以自适应这个时间序列里的前导零
?不仅如此,还取代了解码中心位的方法,通过前导0和尾随0来计算中心位?
自适应状况来决定是否利用前一项的异或结果
用动态规划和剪枝策略,可以保证这个方法是全局最优的
Elf是原来的,SElf是改良过的
流动场景的压缩算法和块的压缩算法
第三到五节给出优化方法(前导0,中心位,共享条件?)
六节给出实验
七节给出结果
?dp(vi)是啥
通过一种方式得到a,从而确定最优的删除位数,以达到最好的效果
小数点后的数位a
Significand为有效数字
DP说的是小数点后的位数
DS说的是有效数字的位数
?什么方法
得到小数点后位数,然后通过一个函数计算得到要置为0的位数长度
克赛是计算出来的,目的是要把长为a的地位全置为0,即克赛就是原数从最低位到a位的数据,说它不会超过10^-a这么多(应该是擦除位数的函数保证的)
擦除后的新数保证尾随0比原数的尾随0多
β是原数的有效数字长度,保证擦除的操作可以擦除掉从原数中来的和x一样多的位数(保证这个方法的效果)x介于一个范围,由一个函数得到
α是原数的小数点后位数,其代表的是原数最小的单元,说减去的克赛不超过它,就是说让原数最小的单元减点,但是介于减一个最小的单元之间,即扩展原数的位数,使其最小单元不再是阿尔法,而比阿尔法小
这样就可以保证,新数和改变后的数异或后,尾随0的位数有保障,而且逆推解码时,再把原数最小单元后的所有位数(借用的更小单元,比阿尔法小)都舍弃掉,这样就相当于是在原数上减去一个最小单元,如今解码加上一个最小单元,就可以得到原数
即思路是,原数->擦除后的新数->和改变的数异或得到的变化序列->新数->原数
第一步是通过利用原数小数点后的位数(最小单元),通过一个函数确定要擦除的位数,然后进行擦除得到新数
第二步,改变的数不变,变的是改变前的数,即不让原数据间运算,而是经过第一步预处理后再进行运算,这样就可以保证压缩的处理效果最好
至此完成压缩
第三步,让改变后的数和压缩得到的异或序列做运算得到新数
第四步,让新数舍弃掉利用的更小最小单元(即阿尔法后的位数),使其变为在原数基础上直接减掉一个最小单元后的数,然后再上这一个最小单元,就可以由新数得到原数
至此完成解压缩
原时间序列->异或序列->原时间序列
异或序列得到并不是由前一个新数得到的,其数据都是在原时间序列基础上得到的,即新数并不保存,只是作为得到异或序列的一种方法(这个异或序列并不是由原时间序列间的两个数直接异或得到,利用了擦除方式,在解压缩时也要再加回去才能得到)异或序列就是
原文的思路是,由原时间序列得到擦除后的新数时间序列,在新数时间序列的基础上得到异或序列,解码也是逆过程,就是第一个顺序表
想的是,将擦除作为一种得到时间序列的方式,不建立额外空间保存,直接得到时间序列,即包装在方法中,从而化简缩短链表
定义五:逼近策略,逼近开销
有顺序的整数序列,里面所有的数都介于0-63之间,用一个数来记录前导零,如果在序列中存在下标为i的数,可以让前导零插在其之后(依然构成一个有序列),那么就说leadt前导零逼近(近似于)ai,记为app(leadt)=ai
App()就是在这个序列中找到对应的位置,并返回其所对应的前一个数(逼近值)
如果队列里面找不到,前导0比已经记录的所有a值都大,那就把它放到队尾,作为最后一个元素,az-1,
把app(leadt)叫做最接近的前导0的数量(leadt>=app(leadt)),把leadt-app(leadt)叫做最接近的开销。
z=8,展示开销是3,前导0有13个,app后得到的是12
(在先前已有数据的基础上)
说elf把前导0的13个训练为(视为)12,并且把第13个0作为中心数的一个
结果就是它会额外用一个位数的代价来储存这个中心数(即0,是需要用空间来额外存储那些过匹配的0,所以叫逼近的最接近开销)
即rule是用来整块地存储那些前导0,不再一个一个计,进行匹配取余,rule就是匹配数组
需要把第一个计为0,以避免出现leadt 总开销: 有异或时间序列(压缩信息序列),它每一项都可以映射出一个前导0序列cd(ci) 注意,这里的下标和异或数列的下标并不是一一对应的,i并非表序号,而是说异或序列中前导0的数量,即如果异或序列有n项,那么cd序列(前导0序列)就不一定有N项(不是说数组中没有n项,cd序列中恒定有64项,而是不是n项都有值) 哈希表就是记录这个坑里装着异或数据的数量 之所以是64项,是因为数据流肯定不止于64项,如果说是要让下标和原数据做一一对应,那么就是需要和原数据等长的一个存储结构,而如果用哈希表,就可以把数据流都给映射到这64种有限情况中 I是什么?ai是匹配数组的数据,i-aj是什么? I是前导0的数量,aj是与其匹配的数据,那么i-aj就是占用中心位的0的开销 Ci是什么?i从0加到63?63是什么?累加起来是什么意思? I是前导0的数量,它是有限情况,这里是做遍历,把所有情况及其对应的花销都计算,再加起来,ci是这个前导0数量的异或项的数量,i-aj是在rule数组的基础上所需要的额外中心位花销(用于记录被算在中心位里的0的数量),所以要乘起来,表示这个前导0数量下所有这个异或项的中心位额外开销,如果异或序列没有前导0数量为i的,那么ci就是0,累加中这一项就是0 ?把全长折半的字节叫做展示开销? ?为了代表,呈现一个接近的数字,它要求至少一个全长折半的字节? ?怎么理解approximate? ?rule是什么? Rule是说的整数列表,Z是说的这个列表的长度,取个对数就是演示开销 ?为什么取对数?演示开销是什么?干什么? j最大是64,就是浮点数的位数,如果j是64,那就是穷举出了所有前导0的可能情况 找匹配数时的复杂度吗?二分查找? P是什么? 这是在干什么?这个代价是什么?什么的代价? 存储(压缩)的代价,还是解压缩的代价?时间还是空间的代价? 应该是空间代价,是说由原数列得到一个异或序列(每一项都是一个数据的映射),然后这个异或序列再映射出一个前置0序列(来记录每一项的异或串中的前导0数量) 就是在干,遇到一个数据(其自身在键为记录前导0数量为0~63的哈希表中,本身与rule无关,是在获得初始异或数据时干的事),就在rule匹配数组中找到最匹配的数据,然后计算开销(这是在压缩) 应该是二分,就是遇到一个异或数据,得到它的前导数量,就让它在rule匹配数组中进行匹配,由于是有序的,就采用二分查找,z是最大数组下标,每次查找都平均要logz次,然后把所有异或数据的数量都加上这个查找次数,就是数据数量*平均查找次数; 前者是在计算占据进中心位里的0(没有匹配进前导0)所需要的全部空间代价 后者是说数据进坑的查找次数,所需要的时间代价? 单位不一样? 这个开销是时间还是空间? ? 这个表是想说对于不同的数据集(在不同的应用场景下),数据的分布,其前导 如AP,它的数据的前导0就主要在1~2个以及27个左右,所以针对这种数据,rule数组就记录a0=0,a1=20左右就可发挥很好的压缩效果,不需要在rule数组中添加如ai=12,14等元素,即使添加了,这种元素也很少被访问到,反而增加查找匹配归类的代价 所以说对于不同的数据集,采用与之特定的rule匹配数组才可以最大化压缩效率 j是最大下标,i是前导0数量 即目的是根据数据找到一个产生最小总成本的rule数组,一个简单的方法是枚举,即rule数组最多64项(因为前导0最多64个),然后每项可以有也可以没有,所以共有2^64种rule数组 需注意,优化的是z,即rule数组长度,不包括最大下标存储的最大前导0数量(i),即保证az=64,最后返回结果就是返回dp[63][z] 说最大下标为j(即rule数组中最多只有j项),其记录的最大前置0为i,而且假设所有的异或序列的前置0都不超过i,这样就确定了一个范围,然后给你j次机会,在0~i内插值,从而使最后匹配后储存的总代价最小,dp就是记录这个限定限制下的最小代价 不考虑查找代价是因为确定是要找数组长度为z的情况下的最小成本,z既然已经确定,那么每个数据的查找代价就已经确定,唯一变的就是数据的总匹配成本(没有匹配到,用中心位去记录的前导0) ?怎么区分不同数据集? 第一种情况是说rule数组没有元素,dp数组的初始化 第二种是说rule匹配数组中只有一个数据,而且记录的是i,那么数据在这个rule数组中的总开销就是所有不超过i的前导0的数量的异或数据乘以其所需要的中心位数, 由于a1=i,而每个异或数据的前导0长度都不超过i,所以匹配到的都是a0=0,那么每个数据的中心位数都是p,即这个数据自身的前导0数量(前导0数量都记录到中心位中,匹配不到后面那个i,因为都小于) 第三种,如果数组最大下标比其记录的前导0数量还大,那是不可能的,最次就是相等,即下标和其一一对应,没有跳间隔,还小就只能说明不同下标对应到了一个值,要舍弃,就是遍历的时候应该直接con掉,即打表应该是让i从j开始, For(int i=j;i<=64;i++) 至此就完成dp的初始化,然后开始打表,即普遍情况 第四种: Dp[i][j]= i,j确定一种rule数组状态,打表顺序确定为自左上到右下,即由先前数组的状态确定i,j时的最优解(最小代价), 尝试在j-1与i-1之间找到一个k使dp[k][j-1]+增量 最小 dp[k][j-1]是说rule数组里有j-1个标杆,然后标杆范围为0~k,第j-1个标杆是k dp[i][j]就是在(k,j-1)的基础上插入了一个新标杆,使标杆数量加了1,而且这个新标杆的范围大,比原来的标杆都大,不仅增加了标杆数量,还增加了标杆划定的范围 ?就不能插入一个新标杆,比之前的最大值小吗,就是在之前的范围内插值,不在其范围外插值? 这样,你总能把当前j个标杆里最高的那个标杆当作最后加入的,这是没有次序的,即i,j只是描述状态,对每一种状态,都可以认为最后一个即第j个标杆是最新加入(由j-1来)的,而且其高度为i,那么没插入之前的状态就是(k,j-1,),j-1<=k<=i-1,即之前标杆的高度不能比标杆数量低,不能高于新插入的第j个标杆的高度,对应很多前置状态 打表自上而下,初始化完第一行,就从第二行开始一直打表到最后一行(第z-1行,共有z个标杆)(每一行从左到右打)因为最后一个标杆注定是63的高度,所以如果z为最后一行则只需要打一个格子(即dp[63][z]),那干脆直接用z-1作为最后一行,然后在z-1的所有可能基础上选一个最小的,还能省空间 即 那么现在的代价就是,在前置状态的基础上,加上新增的前置0范围的数据所需要的代价(之前只到k,现在到了I,i是上界,匹配不到,新扩大的范围(即介于j-1的标杆高度k与j的标杆高度i)里的数据,都会匹配到k,其间长度为i-1-(k+1),所以增量为从k+1到i-1(向下匹配,匹配不到i),累加每个新范围内坑里对应数量的所有萝卜(cp)的所有被计为中心位的前导0数量(即p-k),为 如果k比较小,即标杆高度整体都很小,那么前置代价就很小,那么取而代之就是增量会大,即累加下界从很小开始;反之亦然,所以理论存在最优解 就是遍历(I,j)之前的所以可能状态,从中择取这个总代价最小的成本作为现在状态最小的成本 Dp表的情况应该是呈三角矩阵的样式,即i 怎么保证的全局最优解? 这里,有限制是不让前置0多于i的去进行匹配,就是不算进那些不在当前标杆划定范围内的数据(它们要匹配是匹配到i上),这个思路是什么?是逐渐线性划分数据,每次插针都是在之前的基础上,之前算过的就不算了,算就算新解锁的,直到一直到63,就可以找到一个最优的 是向下匹配,即就算把所有数据直接全部给你,那也是大的匹配大的,小的匹配小,小的数据怎么匹配不会影响大的怎么匹配,那就先让小的去匹配,再逐渐扩大范围,让大的既可以选择去匹配之前那个小的,也可以选择插入新标杆去匹配新的标杆 至此,是算出了(I,j)即在(k,j-1)的状态基础下,插入一个高为i的第j个标杆后的最小成本,是占据中心位存储前导0的最小成本,dp[63][z]所选择的之前每个前置状态都是rule数组中的对应标杆,即如果用上(I,j),那么rule数组中就有aj=i这个元素 接下来就是在说用一种方式来翻译dp数组,得到rule数组 Pre[i][1]=0,只有一个标杆,那么这一个标杆必须是0的高度,不然没办法匹配 Pre[i][j]=k,是说有j个标杆,最高的标杆高i,划定了j-1到i-1的范围,这里选的不是第j个标杆,而是第j-1个? ?但是dp数组只到了z-1,如果选的是j-1,那么z-1就没法选? 不对,这里的i就不能理解成是选出来的,即不再是遍历了,而是说假设我这样划定范围,把范围划定成j-1到i-1,那么 不对 这里pre不应该开二维数组,而是开一位数组,就是说一共z个元素,z个标杆高度递增,然后记录每个标杆的高度(自小到大) 不对,这样的话 都不对,其实就是再重复一遍dp过程,想复杂了,只不过说记录一下到底是选的那个前置状态到的现在的(I,j)状态,可以直接在dp中完成,记录路径而已,只需要一次过程。那么pre[i][j]数组就和它名字一样,记录的是前驱结点。Z-1就单独的由z得到(就是在dp时完成) Pre不是记录的每个j最后该是哪个高度,而是在记录上一个到这个区间内匹配到的前导零数量,它和求最值没关系,只是记录这段区间内匹配到的前导0数量,确定rule 直接dp是四重循环,打表一重,然后每层要打一重循环,接着就是这个位置怎么打,从上一行哪个位置来(区间内匹配到的前导0)是一重,求出哪个位置来的代价(区间内的成本sum和)是一重,共四重 然后说提供一个剪枝策略 说的是如果在异或序列中,对应i,即前导0的数量为i的数据没有,=0的时候,就该剪枝,rule数组中就不该存这个数据,应该直接跳过 j是rule数组中的元素下标,其对应的值是前导0的数量,是下个增量区间到的匹配到的前导0数量,即rule数组确定了ci的一个划分 Nzf,里的元素是ci<=j,(ci是前导0数量,j是数组长度,这俩有啥关系?) ci>j时,不一定能有标杆与之匹配 ci 即nzf中的元素一定可以匹配上 Nzr里的元素是ci>j, 说是局部最优解,如果说rule数组长度比异或前导0序列中非0的数量小,那么对任意的前导0数量i,以及rule数组中任意的元素j,如果都有这个前导0数量比数组长度小(就一定可以匹配上),或者 nzr,rj=)ci>j,j是这个数组里的下标,不是rule数组里的,j单调增,那么这个数组里的元素(即每个前导0的数量)也单调增 那就是说nzr数组其实就是在nz数组上排了个序,是数列呈单调增 Nzf是降序,不对,不一定严格单调减,只是说这个数组里元素可以在标杆高度大于j时可以匹配 Ci是数量,是前导0为i时的异或数据的数量,一个统计量 F1是说ci<=1,即那些数量小于1的前导0. f52是ci<=52,即那些数量不超过52个的元素, r32就是说那些前导0数量大于32的异或项 fj,fj是集合,不是一个元素,是框住了所有数量小于j的异或项,构成了一个序列,fj框的范围越来越大,再取绝对值,就是说这个框住范围内的元素数量,rj也是 rj是说那些数量多于j的异或项构成的序列,rj框的范围越来越小 这有什么意义?异或项可能很多,怎么能被j给限制住? Fj,rj就是按照坑里的数量做记录,类似于分布函数,fj逐渐囊括所有数量不大于63的元素,其项值(fj)呈单调增,rj是逐渐剔除那些数量不大于j的所有前置项,只保留数量大于j的元素,直到只记录那些数量大于63的元素 通过rj做差分(rj是数量大于j,rj+1是数量大于j+1,那么rj+1-rj就可以求出数量为j时的元素的数量)那么应该可以求出这个区间内的元素数量,fj就相当于一个前缀和 Fi+ri应该等于cd所有元素的和,J依据数量,把cd序列完成了一次划分(划了一条分界线,左边的所有和是fj,右边的所有和为rj,前提是cd先按照值的大小完成排序) Rj的第一项,r0应该等于nz,即记录cd数组中所有数量大于0,即有值的元素的和 剪枝2就是说,如果在1,63内取i,定为数量的限制,那么fi就是cd序列中值不大于i的元素和,ri是cd序列中值大于i的元素和,取j为rule数组中的下标,说如果对任意的I,j,都有前面所有的值不大于i的数量和小于数组 既然是任意,就优先考虑极端情况,前一个不等式是让fi最大,就是说cd数组中所有值(数量)不大于63的元素和,j最小就是1,就是第一个标杆,都有 如果不满足,那么第j个标杆就不应该被记录为i, Fi 正常情况下,应该是z-1的rule数组中每一个元素都会占在cd上的非0位置 I还是cd下标,不是说数量,是说在cd中划一条分界线i,然后前面一个和为fi,后面一个和为ri 不对,之前的想法都有偏颇,fi应该是说里面有元素的坑的数量,就是cd数组,以i为分界线,fi是记录左边坑里有元素的坑的数量,ri是右边坑里有元素的坑的数量 Fi的极端是前i个每个坑都只有一个元素,那么最多需要i个可以插值 如果fi 就是期望,对任意的标杆,都期望在前面还是在后面,都有机会可以把剩下的标杆都用完,使其得到有效的利用,从而节约成本 在程序中,是需要保证后续的标杆可以得到有效利用,即剩下的标杆不多于后面的非零坑数量,就可以继续,不然就是前面太省插值机会了,后面用不完,就需要剪枝。 这个策略就是,前面用的不要太多(小于前面的非零坑数量),后面用的不要太多(小于后面非零坑的数量) 就是说在打表,每次都可以视为选一个i来定范围,定的是1~z-1间 怎么落实剪枝2? 剪枝1,2都是要求z-1 这就是剪枝3,就是如果允许的插值机会比较多,或者数据集分布很集中,那么直接构造,都不需要遍历搜索了 复杂度分析: Min(z,nz+1),z是期望,允许的插值机会,nz+1是实际的数据集分布情况,取最小值,作为最后插值机会,取后者时就是无间隔,可以实现无额外成本,不然就是在有限的插值机会中构造一个额外成本最小的 空间复杂度为64*nz,64是说列有64个,nz是说极端情况为允许插这么多,那么共有这么多行,的一个二维数组 实际应该如果允许插这么多次的话可以直接构造,不需要再调用dp查找, 时间复杂度,i从1到63(列),j从i到min(I,z-1),就是一个三角状,k是确定增量区间左端点,p是遍历增量区间元素, 文中打表顺序为让i作为最外层,就是64行(想的是让j作为最外层),自上而下,自左到右,思路是说让接下来插入的标杆高度为I,然后逐渐遍历标杆序号(就是让第j个标杆的高度为i) 先初始化,重点是求nzf,nzr,就是把以每个i选为分界线时,左右区间所允许的最多的使用的标杆数量(超过了一定不是最优解) 那么剪枝2的落实就是,由i确定当下的划分区间,此时j就代表之前已经用过的标杆数量,z-1-j是后面区间可以使用的标杆数量,要求j 然后就是打表 最后求出rule数组,链查找 说要得到全局最优解,就是遍历所有z,然后最低的,Minmin 思路就是限定rule数组长度,然后在每个z下,调用dp找这个z下的最小额外成本,然后取最小,这时应该要考虑到二分查找的成本 由于二分查找是对2取对数,所以介于两个2的整数次指数之间的数,其求完对数的结果是一样,这就允许在不增加二分查找的基础上,使其扩大允许插值的次数, 那么对于每个不增加二分查找的2指数区间内,都可以构造一个在其基础上指数增加一次的插值次数序列,使其查找成本保持上一个,但是插值次数可以保有下一个, 所以只需要遍历k=1,2,3,4,5,6,z=2^k-1的情况, Z=2^6=64时即完全rule数组,不必要 对于z=2^k,可以使在查找成本不增加的基础上,对其中的所有元素都可以有最多2^(k+1)-1次的插值机会,那么对每个区间,区间的最后一个z一定是这个区间所能达到的最好效果,即令z=2^k-1,为每个查找成本区间不增的最后一个元素 这是在找全局最优解的第一次优化 参考剪枝3,考虑到如果允许插值机会多于异或序列的值可能情况时,那么后续的所有z都满足,都可以构造出完全匹配的rule数组,都不需要额外成本,此时再增加只会增加查找成本,那么就不需要全遍历完,就是先求出异或序列的情况对2取对数的值,那么z遍历上界就是它,刚好到它时就可以完全构造 这里是在证明,完全匹配rule数组一定不是最优解,即使它能无额外成本匹配所有数据集的异或项;前者每个数据要平均找6次,无额外成本,共为总数*6 后者平均找5次,需要考虑到2^6-2^5这么多元素的额外成本, 做差就是一个总数再减去那些没有完全匹配掉的元素,即肯定还剩下大于0的项,这里是不准确的预估计算,但能说明问题,就是完全匹配数组一定不是最优解 至此是优化2,是优化缩短上界 优化3是说如果rule2的查找成本比rule1总成本大时,那么rule2一定不是最好的,也就不需要再继续向后拓展z,是及时减后继的优化 6是优化3,就是说如果当前的查找成本已经大于记录的额外成本了,那么后续的一定都不是最优解,就不需要再遍历了,后面一定都比现在大,已经找到了,break掉就0k.全局最优匹配rule数组。复杂度还是建立在dp上,只是多调用了几次 至此,就是找出这个数据集下的最好rule匹配数组,可以实现前导0压缩成本的最小,同时也可以实现尾随0的压缩成本最小 由LN确定允许插值的最大次数 再看 C标识,就是说在前压缩状态数据的基础上,再增加尾随0,可以检测出来,直接记录中心位就行,解压缩时就是先写前导0,然后在前导0不变的基础上写中心位,剩下的都是尾随0 如果说尾随0不单调,又变了,或者数据发生剧变,前导0都变了,那就需要重新记录,记录当下的前导0,尾随0数量,另起一个,后续的如果有C标识,就是建立在当下这个数据的格式基础(相当于连续的数据的相同版式的基石)上,就只中心位就0k. 前标识(01,00,1)就是说记录一下这个压缩数据的类型,在解压缩时采用相应的策略恢复数据,如果遇到01,就保持上一个数据,如果遇到00,1,都是先写前导0,然后写中心位,最后都是尾随0,只是1的时候在记中心位的基础上,多记了前导0和尾随0的数量(实际上压缩最开始应该都是记一些常出现的序列(连续0序列),然后进行匹配化简,elf就是把这个序列记为连续的0,然后说去记录那些前面出现连续0的长度以及后面出现的次数,每个数据都是这样,再然后就是说连续的数据改变比较小,前导0的数量都一样,就可以省略掉去记录前导0和尾随0,只需要记录中心位就可以在前面压缩数据的基础上解码出原数据,即要想有00标识,前面必须有1标识,形如 1xx 00xx 00x 00x 00x 1xx 00x……不可能在前面没有1标识的情况下出现00标识) 为什么需要尾随0?只记录前导0,写完前导0就写中心位就行,尾随0有什么用? 如果不记录尾随0,那么尾随0都被记录在中心位里,无疑增大了中心位成本,所以用尾随0去记录那些重复的0(尾随0也只是常出现的一种数据序列,记成尾随1,尾随10,也都是可行的,应该是在序列中尾随0最常出现(如果有一种数据1最常出现且连续,那么就是要用前导1来记录),所以采用尾随0统一记录,不把尾随0记在中心位里) 说存在两个问题,一是用三个不同的标识编码去区分三种情况,但可能不是最优的,因为它忽略了每种情况可能出现的频率,二是采用了原版的C,可能并不适合改良后的elf,就是重新定义一下这个C,说在通过共享之前的值(前导0数量)省下的位数可能还比不过额外的开销(为什么?) 原版C怎么不行? 没有说不行,是又加了个限制条件,是让前导0的变化量(基本不变)和尾随0的变化量(减小了)的和小于1+前导0和尾随0的数量(?什么意思,为什么要这样做) 说是为了保证一个正收益,应该是说要保证这样做确实可以节省空间 前导0和尾随0的数量是要通过rule匹配数组(这个数组让记录在中心位数的0的额外成本最小)确定的,有几个0就有几个字节吗?(想的是只用一个数去记录数量,这个数量是rule数组中的数,也不至于有几个就占几个字节,不对,ln,tn不是说0的数量,而是说在rule数组中匹配出这么多0后的前导0的数量后,又对2取了个对数(为什么是2,求对数是什么,rule(lead)是求出与这么多前导0所匹配的数量,这个取对数2和之前确定z完全不是一个东西,完全不沾边,就是记录前导0的数量,然后取对数转化为2进制,就是转为2进制存储,所以对2取对数,占这么多字节) 还改了说前导0增加的情况(前导0增加说明数据在递减,之前说前导0不变是认为变化微小或者数据本就是递增的,这里拓展到了所有变化方向)但是如果这样,前导0在原来基础上增加了,那就意味着要写的前导0数量要变了,这就不能在原来基础上说先写前导0再写中心位来获得了,因为前导0数量变了,又没记录,那么怎么解压缩? 那么多这一个条件就是说,不仅判断这个元素是否是在先前元素的格式上发生了变化,还要判断如果是通过这种模式存储,是不是能真正地节省空间,就比如,如果前导0尾随0数量很少,变化也不大 Trailt-trailt-1是说变化后可以少记录的0,即中心位 情况2是记录中心位a,情况3是记录ln+tn+中心位b,,要想2好过3,就要3-2=ln+tn+中心位b-中心位a>0,中心位a是少记录了,少记录了那些原格式基础上新连续的0,即中心位a=中心位a-1-(ln-ln-1)-(tn-tn-1); 做差为 采用第二种存储方式是要建立在先前数据的格式基础上,在原来的基础上就是说,尾随0和前导0都不少于原来,那么在先前数据的基础上,中心位的位数不多于其,即中心位位数为先前数据的中心位数-前导0和尾随0的增量 总之1+ln+tn就是采用朴素方式的压缩存储 第一种情况说观察序列,发现大多满足C标识,即数据变化大多符合原数据的格式基础,那就让它的前缀名短一点,用一位来记录这种情况 ?为什么是2个2,1个1?不能2个1字节,1个2字节吗?这也不是哈夫曼编码 或许这多出来的一个字节就是C标识,有两个参数,一个是异或是不是0,一个是有没有C,组合起来4种情况,2字节 需要用1+ln+tn来记录,当没有满足C’时, 即记录数据格式,以及C‘没有满足的标识(C’不应该每个数据都有吗?或者说是作为程序的一个全局变量,在遍历数据集的时候不断覆盖更新吗) 00 xx xx x x 对于每一个数据,和前一位做异或,得到结果后通过rule数组匹配到最合适的前导0和尾随0数量,没有匹配上的就作为中心位记录,然后就是压缩,按三种情况去递推压缩,如果一摸一样,就不记录,如果不一样,看有没有C标识,来确定具体该怎么存储。 为什么要匹配?直接记录不行吗? 直接记录就是说得到前导0和尾随0数量,然后直接看和前面尾随0数量的关系来确定记录方式 匹配的话,可能说对于连续变化的细小数据,其最后匹配到的前导0尾随0数量和上一个一样,比如a1=3,a2=6,对于有4个尾随0和5个尾随0的数据,都会匹配到a1=3,被认为有着同样的尾随0(这时就会在中心位开辟额外空间来存储这个5个尾随0的数据),只有说有7个尾随0的数据时,才会被匹配到a2=6,并被判为二情况,即在原来数据的格式基础上增加了尾随0 也就是说由于匹配数组的存在,使数据的前导0和尾随0会被统一赋值,那么原来的C标识,说只要尾随0>=前一个,可能就不是那么敏感(是说如果尾随0只增加了一位,那也会被视为没有增加,但是如果才有原C,就会被检测出来,所以说相比原来有一个额外成本的概念),因为只有增量达到变化的阈值,才会变到新的台阶,否则就不会被打上C标识 那为什么要用匹配数组?好像没什么好处 说要提前直到数据集前导0尾随0的分布情况,但是在流动场景中并不适用 划分出不同的时间窗口,意思就是说数据集有自己的特点,可以根据同一个数据集的先前数据来计算后继的数据 在i时间内数据取样,得出一个rule数组,然后导入i+1时间的数据,比较一下在同一个rule数组下两个时间点里的压缩率,如果压缩率几乎不变甚至还大了,就保持原rule数组,不然,就更新rule数组,表示随着时间改变数据特征发生了更新 三个指标,压缩率(节约的空间),压缩时间,解压缩时间 比猩猩算法表现次点,因为是建立在elf算法之上,elf在β(有效数字位数)比较大时只能删掉很少的位数来匹配,导致一个不太满意的压缩结果 压缩时间多一点因为擦除和重新存储的步骤 用了剪枝在计算rule数组和适配rule数组时 解压缩逻辑是一样的 首先是说,连续变化的数据变化很小,那么异或数据就有很多前导0和尾随0,就记录它们的数量和中心位,就能起到压缩的作用 然后说实际情况下只有很少的尾随0,那就人工干预一下,通过一种方法确定可以置0的位数,然后从后面把这么多位都置0,就可以达到预期的效果,在这样的基础上进行压缩,在解压缩时就再加上减去的数就可以 至于压缩的策略,朴素的就是记录前导0,尾随0数量(转为二进制),以及中心位 后面又发现可能记录的数据(前导0尾随0数量)很多都是重复的,所以就改进,用C标识去标记那些前导0相同,尾随0在原来格式基础上还多的数,对于这样的数只需要记录中心位就可以了,因为它们共享前导0数量 Elf就无C标识的情况依据中心位的长度划分了两种,一种是用4个字节(2^4=16)的长度储存中心位长度,一种是6个(2^6=64)(什么?,, Centert是什么?怎么把中心位划分出了两部分?是说统一只记录3个字节前导0,其他数量的前导0都记到中心位里吗) ELF应该是说只管前导0,然后就记录中心位,不再记录尾随0(这里是依然检测尾随0的长度,但是不记录,就是防止把尾随0给算进中心位里,尾随0,前导0,中心位长度,这三,任意知两个就可以确定中心位的位置与长度) 应该形如10 xxx yyyy zzz(x是用3个字节来记录那些不超过8个数量的前导0,y是记录不超过16的中心位长度,这俩是,不管到没到,都统一用这么长来记录(目的应该是为了解码时有一个统一标准,即识别时该怎么识别,哪些位就该是哪些,不能缩短或记录其他的,不然就会有解码时的歧义),z就是对应长度的实际中心位) 然后就指出有问题,第一是说前导零用3个字节(就是说最多只管8个前导0,再多就直接算进中心位里了),但没有考虑到不同数据集下前导0的分布不同,二是说区分情况实际用了5和7个字节,很浪费。三是用了C,但是可能并不是说用了C就是最优的 为此,说用逼近的rule数组来记录那些前导0; 而且用记录尾随0来代替掉记录centert(centert应该不是真正的中心位,应该是说中心位的长度,即有尾随0和前导0的数量就可以计算出中心位的长度) 每个数据,前导0,尾随0,中心位,目的是让字节数尽可能少,那就是要去缩短前导0(尾随0的策略一致)的字节长度,文章是,缩短前导0字节长度(从原elf所容忍的最大8个,3字节改良为最大不限,log2z(将长度转为2进制)字节,记录的是rule数组里的下标),改记录中心位长度为尾随0长度(elf依据中心位位数划分出两种编码方式,一种用4个字节记录长度,一种用6个字节,改良后不再记录中心位位数,而是记录尾随0的长度,与前导0的策略相同,变长度为log2z个字节) 编码前导0,一个基础的方式就是用6个字节来存储,但考虑到前导0很少大于31,所以就用5个字节来存储,大于的就直接把它视为31,并支付额外成本(让其算进中心位里) 这里文章就在此基础上进一步把逼近的策略扩展,提出了说针对数据集自身分布特点的一种策略,那么用几个字节来存储前导0? 对于每个前导0的长度,需要用log2z的代价来匹配(二分),z是rule数组长度 如果说匹配上了,那就不记录前导0的数量,而是记录其在rule匹配数组中的下标,下标最大就是长度,也就是说将0~63(6个字节存储)的前导0数量映射到0~z(log2z个字节存储)的rule数组上,那么接下来问题就是怎么确定z,以及rule数组怎么确定 这里,log2z就是所谓呈现代价,即将最大下标(即长度)转为二进制之后,确定到底应该用多少位来记录前导0的信息,这就是所谓presentation,之前的centert,3,6,4都是presentation cost,即呈现的标准,呈现所需的标准字节,用log2z来确定对这样的数据集,到底该用几个字节来存储前导0信息,只是用匹配数组的话,还会多出额外的成本,这个成本是把没有匹配进前导0里的前导0记到了中心位里,也就是让中心位的字节数增加了,增加的长度就是异或序列中前导0数量为这么多的项的数量*(异或序列中前导0的数量-匹配到的前导0数量),那么采用这种方式存储前导0,所需要的字节就是这些 单位是字节 然后文章用dp和剪枝,去求怎么在确定z(即rule数组的长度,确定了z就是确定了呈现字节数,那么目标就是让额外成本最小,即让rule数组最适配这个数据集,让每个rule数组中的元素都放在最恰当的位置)的情况下求出这个数据集(哈希表记录了这个数据集的特征)存储的最小额外成本,这样就算是前导0的存储策略确定了 一个dp是求出了当前这个z的最优解,是局部的,问题是怎么确定到底该让z等于多少才可以使全局最优,即存储所需的总字节数最小,这里是遍历,首先确定cd数组中非0项的数量,这是作为z的一个上界,还有就是,对于不同的z,就是确定不同的rule数组长度,呈现字节和数组长度有关,数组越长,所需要的字节数来记录也就越长,但这种增长是阶梯式的,即字节数越多,每个字节所能拓展的rule下标也就越大, 所谓z,即是rule数组的长度,也是最后确定的存储前导0的字节位数,所以确定z,就是在确定该用多少字节来表示前导0,不能说直接越小越好,因为如果前导0的呈现字节数小了,那不完全匹配(因为小于情况总数,所以必定存在不完全匹配情况)时被记录在中心位里的0字节总数就多了,被算在中心位里可就是一个0一个字节,所以理论存在一种最中和的方式,使前导0的记录成本最小(最最好的就是实际有多少前导0就记录多少的二进制,但这样会出现译码歧义,所以需要统一位数来记录所有的前导0情况) 怎么保证这样存储前导0效率确实提高了?即怎么保证省下来的呈现字节数多于额外开销的中心位数? 前导0最多有64个,用二进制存储是6位,那么rule数组极限长度就是6,最简单的存储就是极限长度6,没有额外开销,可以视为rule数组的一种情况,不为极限长度6时,最大就是5,那么就是说用5个字节来储存rule数组长度,省下来和数据总量一致的字节数,额外开销的字节数为那些没有匹配进中心位的0的数量,怎么保证它比数据总量小?5个字节长度就是说有32个长度,可以对任意的数据集构造一个0,2,4,6偶数下标的rule数组,那么对于原数据集中前导0数量为偶数的项,其额外开销为0,只需记录其rule数组的下标,对于间隔在其中的奇数项,其额外开销均为1(即注定有一个0被视为中心位),那么额外开销为原数据集总量的一半,比总数小,这是z=5时对任意数据集都可以构造的一个rule数组,效果比直接存储前导0(同时也是rule数组长度为6)效果好,也就是说确定前导0的存储结构,z=6枚举全部情况必不为最优解,只要z=5就一定可以更好(偶数间隔的rule都不一定是最好的,可以通过dp确定z=5时的前导0记录最小成本),所以要想让前导0存储成本最小,就是遍历z可能的情况,用dp求出每种情况的最小存储成本,然后从中选最小值,就是最佳的前导0存储字节数 剪枝3,额外成本一定不是负的,如果说z=n+1的呈现成本已经大于通过dp(z=n)求出来的总成本,那么就不需要再往后求,直接break掉就行 至此,至此就是确定了前导0的整体最优存储策略,同时也是尾随0的最优存储策略, 就是对于这个数据集前导0整体这样的情况,到底该怎么选rule存储方式,才能使它们的整体压缩成本最小,是从整体和的最优化角度 接下来,是单个、具体的数据的存储策略, 每个数据的压缩存储,要前导0和尾随0的rule数组长度取对数的字节数,这是每个数据所必须的,再加上中心位的字节数(为64-匹配掉的前导0和尾随0) 同elf,在格式基本一致时,可以采用共享的策略来只存储中心位, Ln+tn+1(ln,tn是根据数据集特点所选出的最优存储数组的长度)是直接存储,不共享时的字节数(不包括中心位) 一般情况下应该是匹配到的尾随0前导0数量一致(即相等),即变化不大,没到阈值,那么就在前面的基础上只记录中心位 可以共享也可以不共享,共享就是实际中心位(有小数量的不匹配0)+新匹配上的前导0(原前项前导0+与后项前导0的差值,即后项前导0)+新匹配上的尾随0,实际只记录实际中心位+1个字节,不共享就是原前项前导0+前项尾随0+2(情况3的额外一个字节)+中心位(有不匹配的达到阈值的0),存储下来就是(不管多少,采取3就是都要这么多来存储前导尾随0的量)ln+tn+2+中心位,要想策略最优,就是取最小值,如果共享是最优策略,那么做差有1+ln+tn-匹配量变化差值 这个C的新条件是在原来的基础上做进一步判断,不变或变化较小时,可以选择共享,是最优的,但如果达到阈值了,就是说中心位两侧的0积累很多了(尾随0都被记录进中心位里了,那本可以被记录在基础里,现在在基础格式上中心位所积累的新尾随0越来越多),那是更新格式,还是说接着在原格式上,容忍中心位尾端记录更多的尾随0,就需要判断了,判断的依据就是两者的字节数,继续容忍的话,那依然是记录原来的中心位数,只不过这个中心数两端实际上包括了很多0,不容忍,要更新的话,就是再用一个ln,tn,+2,+新中心位数的码来记录格式,让容忍(策略1)和不容忍的策略(策略00)的字节数做差就是前导0的区间变化量和尾随0的区间变化量(即中心位两端变0的长度和)-1-ln-tn,如果容忍策略(1)好,拿结果就是小于0的,就采取容忍,在老格式上继续记录,不然,就新起格式,用策略00,新记录这种格式下的状态 原C没这个烦恼是因为原C的尾随0序列是连续的,可以只记录除去前导0后的中心位,改良后前导0,尾随0的序列变离散了,只能说一块一块地变动 如果到阈值了,中心位里连着好多都变成了0,即leadt!=leadt-1.leadt>leadt-1,那么就是说要更新格式,记录位数更小的实际中心位 采用01,00,1的编码策略应该也是为了防止歧义,即互不包容,如果是包括1,0,那么就有歧义,如01,可以视为01型情况,也可以视为0情况,所以一个字节的数只能用一个,好像还是哈夫曼编码,用了1,那么两个字节的就要用00,01,用了0,两个字节的就要用11,10,即不能重叠包容有歧义,要明确的表示出一个压缩项
就是说cd序列就是一个哈希表,键有64种有限情况,它的下标就是记录前导零数量的键,它的值就是这个前导零数量是这么多的异或项的个数,一个萝卜一个坑,坑里装着很多萝卜
重点是理解开销,什么开销?怎么求开销?为什么是乘的关系
0数量的分布(主要原因应该是数据变化的特点(幅度,频率)导致)不同
aj是有序列,所以可以二分法,有一个查找代价,所以平均代价为logj,j为最大的下标
rule是一个自适应的匹配序列,如果里面元素很多,那么查找代价就高,如果里面元素比较少,可能匹配后的额外开销代价就大一些,即找不到一个合适的匹配量
所以理论上存在一个最优解,使查找代价低而且对元素的匹配效果好
所以这里就用dp动态规划去找这样一个最优序列,
其中有两个重要的参数,一个是最大下标,一个是最大下标所存储的值,即记录的最大前导零
最大下标j决定查找代价,最大下标j所存储的值i(即记录的最大前导零数量)决定匹配的程度与效果
那么,dp(j)(i)就是说在最大下标为j,其存储的最大前导零数量为i的情况下,什么?dp记录的是什么?P是什么?p=k+1,i-1是什么?
dp记录的是总的匹配代价,
打表是自上而下(由rule数组的期望位数长度确定),自左到右(即每行新插入的更大标杆,划定上界)
第一种剪枝是说自左到右访问64个元素时,如果说原异或数列里这么多(k)前导0数量的数据一个也没有,那么就不应该尝试把这个作为rule数组中一员进行尝试,因为一个完全匹配上的都没有,只会增加额外开销,还浪费了一次插值机会(两点原因,一是如果确定出的范围内有元素,那就会增加额外开销,二是,没有和有时,都会浪费掉这一次插值机会)
如果插到划定范围内(上界不动)有数值的地方,那是肯定能节约成本的,所以第一种剪枝,是在自左而右的过程中,在确定i和k(二三重循环)时都要直接跳过
用nz记录原异或序列中出现前导0位数的可能情况,不包含那些没出现的情况
如果期望的rule数列长度比nz小,那么对rule数组中的任意下标,其对应匹配前导零位数上的出现次数一定不为零,即一定可以完全匹配掉一些异或序列中元素,从而节约开销