我正在玩CRF-ish工作的一些想法,我知道我需要帮助.
最小的问题
我有一堆函数对象(想想像神经网络一样昂贵的东西).它们被应用到线性缓冲区(想象一个浮点数或字节数组),但是以不同的间隔.所以它们看起来像那样(将Start和End视为“将对象应用于buf [Start:End]”:
| Object | Start | End |
|--------|-------|-----|
| A | 0 | 4 |
| B | 4 | 10 |
| C | 13 | 15 |
区间特征
>可能会有一些跳过(例如,看到C的开头与B的结尾)
>间隔肯定会有变化,无论是正面还是负面(例如,B可能会从[4:10]变为[4:12].
>当发生这种情况时,可能必须重新应用与间隔相关联的对象.
>如果间隔更改与另一个间隔重叠,则必须重新应用这两个对象.例如,如果B从[4:10]变为[3:12],则必须将A应用于范围[0:3],并且必须将B应用于范围[3:12]
>根据操作,下游间隔也必须更新,但不一定必须重新应用对象.例如,如果它是一个插入更改了B的间隔范围,那么C的间隔范围也将增加2,但不会触发重新应用C.
计划特色
>间隔变化很大(这是一个机器学习训练循环).
>支持的间隔更新形式有:insert,delete,shiftleft,shiftright.后两者与插入/删除相同,但应用于间隔的末尾.
>间隔的更改通常以元组(索引和大小)或单个索引的形式出现.
>功能的应用是相当昂贵的操作并且是CPU限制的.
>然而,由于我正在使用Go,一些互斥量gorxine解决了大部分问题(有一些更好的点,但大的swarths可以忽略).
>一个纪元可以有5-60个间隔 – 对象对.
>缓冲区是线性的,但不一定是连续的.
任务
任务可归纳如下:
>按索引查询:返回间隔和与间隔关联的对象
>更新间隔:必要时还必须更新下游(这是大多数情况)
>插入新的间隔:还必须更新下游
我试过的
>以间隔作为关键字映射.这是一个坏主意,因为我必须知道改变的给定索引是否在一个区间内
>线性结构,以跟踪开始.当我意识到可能会跳过时,立即发现了一个错误.
>带有“孔”的线性结构,用于跟踪启动.事实证明这与绳索相似.
>绳索和跳过列表.结束重构我用于字符串的skiprope包中的内容.更多牦牛剃须.好极了.
>间隔/段树.实施是一个婊子.我还尝试了gods/augmentedtree的具体变体,但实际上无法让呼叫支持正常工作来评估它.
问题
是否有任何我错过的良好数据结构会使这些任务变得更容易?
我错过了一些令人眼花缭乱的事情吗?
一位朋友建议我查找渐进式编译方法,因为它类似.使用的类比是Roslyn将以远程方式解析/重新分析文本片段.这与我的问题非常相似 – 只需用令牌的线性缓冲区替换浮点数的线性缓冲区.
问题是我找不到任何有关Roslyn如何做的有用信息.
最佳答案 这个解决方案不是特别节省内存,但如果我理解正确,它应该允许相对简单地实现您想要的功能.
>保留所有函数对象的数组或切片函数,以便它们各自具有规范整数索引,并且可以通过该索引查找.
>保留一片与浮子缓冲区大小相同的整数;它将缓冲区中的特定索引映射到函数片中的“函数索引”.您可以使用-1表示不属于任何间隔的数字.
>保持一对(int,int)对的间隔,使得interval [i]包含存储在funcs [i]中的函数的起始端索引.
我相信这使您能够实现所需的功能而不会有太多麻烦.例如,要通过索引i查询,请查找s [i],然后返回funcs [s [i]]和interval [s [i]].当缓冲区发生更改时,也要更改s,在s和间隔切片之间进行交叉引用,以确定相邻间隔是否受到影响.我很乐意更详细地解释这一部分,但我并不完全理解间隔更新的要求. (当您执行间隔插入时,它是否对应于底层缓冲区中的插入?或者您只是更改哪些缓冲区元素与哪些函数相关联?在这种情况下,插入是否会在下一个间隔开始时导致删除?大多数方案应该有效,但它会改变程序.)