Optimization 总体性和对流中元素的搜索

Optimization 总体性和对流中元素的搜索,optimization,stream,idris,lazy-sequences,finite-group-theory,Optimization,Stream,Idris,Lazy Sequences,Finite Group Theory,我想要一个用于大小有界类型流的find函数,它类似于用于列表和向量的find函数 total find : MaxBound a => (a -> Bool) -> Stream a -> Maybe a 挑战在于如何做到: 全部 消耗的空间不超过常量log_2 N,其中N是编码最大a所需的位数 在编译时检查不超过一分钟 不增加运行时成本 一般来说,流的总find实现听起来很荒谬。流是无限的,一个const False谓词将使搜索永远进行下去。处理这种一般情况的一个好方

我想要一个用于大小有界类型流的
find
函数,它类似于用于列表和向量的find函数

total
find : MaxBound a => (a -> Bool) -> Stream a -> Maybe a
挑战在于如何做到:

  • 全部
  • 消耗的空间不超过常量log_2 N,其中N是编码最大
    a
    所需的位数
  • 在编译时检查不超过一分钟
  • 不增加运行时成本
  • 一般来说,流的总find实现听起来很荒谬。流是无限的,一个
    const False
    谓词将使搜索永远进行下去。处理这种一般情况的一个好方法是无限燃料技术

    data Fuel = Dry | More (Lazy Fuel)
    
    partial
    forever : Fuel
    forever = More forever
    
    total
    find : Fuel -> (a -> Bool) -> Stream a -> Maybe a
    find Dry _ _ = Nothing
    find (More fuel) f (value :: xs) = if f value
                                       then Just value
                                       else find fuel f xs
    
    这对我的用例很有效,但我想知道在某些特殊情况下,是否可以不使用
    永久
    而说服总体检查器。否则,有些人可能会经历一段无聊的生活,等待
    find ever?谓词始终返回false(迭代sz)
    完成

    考虑一种特殊情况,
    a
    Bits32

    find32 : (Bits32 -> Bool) -> Stream Bits32 -> Maybe Bits32
    find32 f (value :: xs) = if f value then Just value else find32 f xs
    
    两个问题:它不是总的,并且它不可能返回
    Nothing
    ,即使有有限数量的
    位32
    居民要尝试。也许我可以使用
    take(pow 2 32)
    建立一个列表,然后使用List的find…呃,等等…单是列表就需要占用GBs的空间

    原则上,这似乎并不难。有有限多的居民可以尝试,现代计算机可以在几秒钟内迭代所有32位排列。是否有办法让总体检查器验证(流位32)$iterate(+1)0
    最终循环回
    0
    ,一旦它断言所有元素都已尝试过,因为
    (+1)
    是纯的

    这是一个开始,尽管我不确定如何填补这些漏洞,如何专门化
    找到足够的
    ,使之成为完整的。也许界面会有帮助

    total
    IsCyclic : (init : a) -> (succ : a -> a) -> Type
    
    data FinStream : Type -> Type where
      MkFinStream : (init : a) ->
                    (succ : a -> a) ->
                    {prf : IsCyclic init succ} ->
                    FinStream a
    
    partial
    find : Eq a => (a -> Bool) -> FinStream a -> Maybe a
    find pred (MkFinStream {prf} init succ) = if pred init
                                              then Just init
                                              else find' (succ init)
      where
        partial
        find' : a -> Maybe a
        find' x = if x == init
                  then Nothing
                  else
                    if pred x
                    then Just x
                    else find' (succ x)
    
    total
    all32bits : FinStream Bits32
    all32bits = MkFinStream 0 (+1) {prf=?prf}
    

    有没有办法告诉全集检查器使用无限燃料来验证对特定流的搜索是否为全集?

    让我们定义循环序列的含义:

    %default total
    
    iter : (n : Nat) -> (a -> a) -> (a -> a)
    iter Z f = id
    iter (S k) f = f . iter k f
    
    isCyclic : (init : a) -> (next : a -> a) -> Type
    isCyclic init next = DPair (Nat, Nat) $ \(m, n) => (m `LT` n, iter m next init = iter n next init)
    
    上述情况意味着我们的情况可以描述如下:

    --   x0 -> x1 -> ... -> xm -> ... -> x(n-1) --
    --                      ^                     |
    --                      |---------------------
    
    其中
    m
    严格小于
    n
    (但是
    m
    可以等于零)
    n
    是一些步骤,在这些步骤之后,我们将获得之前遇到的序列元素

    data FinStream : Type -> Type where
      MkFinStream : (init : a) ->
                    (next : a -> a) ->
                    {prf : isCyclic init next} ->
                    FinStream a
    
    接下来,让我们定义一个helper函数,它使用一个名为
    fuel
    的上限来打破循环:

    findLimited : (p : a -> Bool) -> (next : a -> a) -> (init : a) -> (fuel : Nat) -> Maybe a
    findLimited p next x Z = Nothing
    findLimited p next x (S k) = if p x then Just x
                                    else findLimited pred next (next x) k
    
    现在可以这样定义
    find

    find : (a -> Bool) -> FinStream a -> Maybe a
    find p (MkFinStream init next {prf = ((_,n) ** _)}) =
      findLimited p next init n
    
    以下是一些测试:

    -- I don't have patience to wait until all32bits typechecks
    all8bits : FinStream Bits8
    all8bits = MkFinStream 0 (+1) {prf=((0, 256) ** (LTESucc LTEZero, Refl))}
    
    exampleNothing : Maybe Bits8
    exampleNothing = find (const False) all8bits               -- Nothing
    
    exampleChosenByFairDiceRoll : Maybe Bits8
    exampleChosenByFairDiceRoll = find ((==) 4) all8bits       -- Just 4
    
    exampleLast : Maybe Bits8
    exampleLast = find ((==) 255) all8bits                     -- Just 255
    

    isCyclic
    find
    是否可以在不依赖线性空间
    Nat
    s的情况下实现?我甚至没有足够的耐心让
    所有16位
    在我的机器上完成,我认为
    Nat
    是罪魁祸首。在我的机器上,迭代所有
    无符号int
    s的未优化C程序需要10秒多一点的时间,我的目标是在恒定空间消耗的情况下获得与之相当的性能。你是对的,这是一个长期存在的问题。二进制数可以减轻痛苦。github上有一个项目,旨在将Coq的二进制数移植到IdrisAre,这些二进制数是不是一个未优化的归纳定义?我想这会有帮助,但是可以使用优化的任意精度无符号整数来实现吗?(无可否认,这两种解决方案都会消耗$\log_2 n$而不是常量空间。)无论如何,谢谢您的回答。看到一种实现
    isCyclic
    @JakeMitchell的方法很有启发性,是的,这只是一个归纳定义,回购协议就在这里,我们有一些计划从
    位n
    到这些,但还没有什么具体的,欢迎您在问题/PR部分提出一些建议:)