我正在写一些信号处理软件,我开始写一个 discrete convolution function.

这适用于前一万个左右的值列表,但随着它们变大(例如,100k),我开始得到StackOverflow错误,当然.

不幸的是,我在将命令式卷积算法转换为递归和放大器方面遇到了很多麻烦.懒惰的版本实际上足够快(至少有一点优雅也很好).

我也不是100%确定我完全没有这个功能,但是 – 如果我错过了什么/做错了什么,请告诉我.我认为这是正确的.

(defn convolve
  "
    Convolves xs with is.

    This is a discrete convolution.

    'xs  :: list of numbers
    'is  :: list of numbers
  "
  [xs is]
  (loop [xs xs finalacc () acc ()]
    (if (empty? xs)
      (concat finalacc acc)
      (recur (rest xs)
             (if (empty? acc)
               ()
               (concat finalacc [(first acc)]))
             (if (empty? acc)
               (map #(* (first xs) %) is)
               (vec-add
                (map #(* (first xs) %) is)
                (rest acc)))))))

我将不得不寻求任何帮助:我仍然在Clojure中获得优势,并且使这个优雅,懒惰和/或递归会非常棒.

我有点惊讶的是,表达一种很容易用Lisp中的命令式语言表达的算法是多么困难.但也许我做错了!

编辑:
只是为了表明在命令式语言中表达是多么容易,并且为人们提供了运行良好且易于阅读的算法,这里是Python版本.除了更短,更简洁,更容易推理之外,它比Clojure代码执行的速度快几个数量级:甚至是使用Java数组的命令式Clojure代码.

from itertools import repeat

def convolve(ns,ms):
    y = [i for i in repeat(0,len(ns)+len(ms)-1)]
    for n in range(len(ns)):
        for m in range(len(ms)):
            y[n+m] = y[n+m] + ns[n]*ms[m]
    return y

另一方面,这是命令式Clojure代码.它还会从卷积中删除最后一个未完全浸入的值.因此除了缓慢和丑陋之外,它不是100%功能性的.也没有功能.

(defn imp-convolve-1
  [xs is]
  (let [ys (into-array Double (repeat (dec (+ (count xs) (count is))) 0.0))
        xs (vec xs)
        is (vec is)]
     (map #(first %)
          (for [i (range (count xs))]
            (for [j (range (count is))]
              (aset ys (+ i j)
                    (+ (* (nth xs i) (nth is j))
                       (nth ys (+ i j)))))))))

这太令人沮丧了.拜托,有人告诉我,我错过了一些明显的东西.

编辑3:

这是我昨天想到的另一个版本,展示了我希望如何能够表达它(虽然其他解决方案非常优雅;我只是在那里放另一个!)

(defn convolve-2
  [xs is]
  (reduce #(vec-add %1 (pad-l %2 (inc (count %1))))
         (for [x xs]
           (for [i is]
             (* x i)))))

它使用这个实用功能vec-add:

(defn vec-add
  ([xs] (vec-add xs []))
  ([xs ys]
     (let [lxs (count xs)
           lys (count ys)
           xs (pad-r xs lys)
           ys (pad-r ys lxs)]
       (vec (map #(+ %1 %2) xs ys))))
  ([xs ys & more]
     (vec (reduce vec-add (vec-add xs ys) more))))
     (vec (reduce vec-add (vec-add xs ys) more))))

解决方法

(defn ^{:static true} convolve ^doubles [^doubles xs ^doubles is]
  (let [xlen (count xs)
        ilen (count is)
        ys   (double-array (dec (+ xlen ilen)))]
    (dotimes [p xlen]
      (dotimes [q ilen]
        (let [n (+ p q),x (aget xs p),i (aget is q),y (aget ys n)]
          (aset ys n (+ (* x i) y)))))
    ys))

如果我在Clojure equiv分支中这样做的话,重复j-g-faustus的版本.适合我.在i7 Mackbook Pro上,1,000,000点约为400毫秒,在100,000点上约为25毫秒.

函数式编程 – Clojure中的惰性卷积fn问题的更多相关文章

  1. Swift40/90Days - 用函数式编程解决逻辑难题

    Swift90Days-用函数式编程解决逻辑难题这篇翻译的文章,用两种方法解决了同一个逻辑难题。第二种方法利用了Swift的一些语言特性,实现了函数式编程的解决方案。这样的代码对于指令式编程来说再平常不过,接下来我们就来看下如何用函数式编程解决这个问题。Swift中函数已经是一等公民,这让高阶函数变成可能,也就是说,一个函数可以是通过其它函数组装构成的。思考Swift对于函数式编程的支持让我感觉的兴奋,Excited!

  2. [连载]Swift开发入门06--- 函数式编程

    面向对象编程和函数式编程是目前最主流的两种编程范式,而关于这两种范式孰优孰劣的讨论一直都没有停止过。明显,函数式编程有如下一些特性:-高阶函数:函数可以作为函数的参数传给函数。用函数式编程的方式重新编写上面的代码,如下所示。使用函数式编程,可以将代码改写为如下所示的样子。先传入一个参数,稍后再传入另一个参数来实现完整的功能,这其实就是所谓的函数的柯里化。

  3. 最通俗易懂的 Swift 函数式编程

    善用函数式编程思路,可以对我们的开发工作有很大的帮助和启发,今天我们就来讨论一下吧。这种方式就是函数式编程的一个例子。First-Classfunction谈到函数式编程就会提到FirstClassFunction。首先定义了一个filterZhang函数,接着将这个函数作为参数传递给filter。就这么简单,这也是Swift函数式编程的一个体现。函数式编程的另一大特性就是curry。结语到这里,函数式编程的基本思路就都给大家介绍完了。总之呢函数式编程的主要特性就是声明式思维以及curry传递思维。

  4. Swift:函数式编程学习之Thinking Functionally

    ThinkingFunctionally借用《functionalprogramminginswift》中第二章的标题,开始我的摸索之路。简而言之,Swift中的函数和Swift中Int、String、Bool是完全一样的!《functionalprogramminginswift》的ThinkingFunctionally章节便是通过一个战舰的例子来解释这一特征。我们的战舰位置和射击的范围为了实现目标,引入了一个Ship结构,它拥有position属性、firingRange以及unsafeRange。

  5. “ 函数式”编程 vs 编程写个函数——“函数式”编程和编程写个函数的区别

    通过这种关系,确定的一个参数将总是有固定的返回值。“这也正是Mathematicalfunction这个名字的来源,它并不是指使用数学公式的函数,而是遵从数学中对于函数理解的函数。”myOwnFilter同样接受一个closure参数,用来指定过滤的条件。我们把“在数组中过滤特定条件的元素”,这个事情用函数封装了起来,而filter本身,实际上什么也没做,它只描述了一个输入数组和输出数组之间的关系;

  6. Python函数式编程之返回函数实例详解

    函数式编程的一个特点就是,允许把函数本身作为参数传入另一个函数,还允许返回一个函数,下面这篇文章主要给大家介绍了关于Python函数式编程之返回函数的相关资料,需要的朋友可以参考下

  7. JavaScript函数式编程实现介绍

    函数式编程是一种编程范式,将整个程序都由函数调用以及函数组合构成。 可以看成一条流水线,数据可以不断地从一个函数的输出流入另一个函数的输入,最后输出结果

  8. Kotlin函数式编程超详细介绍

    一个函数式应用通常由三大类函数构成:变换transform、过滤filters合并combineo每类函数都针对集合数据类型设计,目标是产生一个最终结果。函数式编程用到的函数生来都是可组合的,也就是说,你可以组合多个简单函数来构建复杂的计算行为

  9. php函数式编程简单示例

    这篇文章主要介绍了php函数式编程,结合简单实例形式分析了php函数式编程相关实现方法及数组排序、闭包操作使用技巧,需要的朋友可以参考下

  10. Clojure 与Java对比少数据结构多函数胜过多个单独类的优点

    这篇文章主要介绍了Clojure 与Java对比少数据结构多函数胜过多个单独类的优点,在Clojure中,我们一次又一次地使用相同的数据结构,并在其上运行许多函,更多相关介绍需要的朋友可以参考一下下面文章内容

随机推荐

  1. 基于EJB技术的商务预订系统的开发

    用EJB结构开发的应用程序是可伸缩的、事务型的、多用户安全的。总的来说,EJB是一个组件事务监控的标准服务器端的组件模型。基于EJB技术的系统结构模型EJB结构是一个服务端组件结构,是一个层次性结构,其结构模型如图1所示。图2:商务预订系统的构架EntityBean是为了现实世界的对象建造的模型,这些对象通常是数据库的一些持久记录。

  2. Java利用POI实现导入导出Excel表格

    这篇文章主要为大家详细介绍了Java利用POI实现导入导出Excel表格,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  3. Mybatis分页插件PageHelper手写实现示例

    这篇文章主要为大家介绍了Mybatis分页插件PageHelper手写实现示例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  4. (jsp/html)网页上嵌入播放器(常用播放器代码整理)

    网页上嵌入播放器,只要在HTML上添加以上代码就OK了,下面整理了一些常用的播放器代码,总有一款适合你,感兴趣的朋友可以参考下哈,希望对你有所帮助

  5. Java 阻塞队列BlockingQueue详解

    本文详细介绍了BlockingQueue家庭中的所有成员,包括他们各自的功能以及常见使用场景,通过实例代码介绍了Java 阻塞队列BlockingQueue的相关知识,需要的朋友可以参考下

  6. Java异常Exception详细讲解

    异常就是不正常,比如当我们身体出现了异常我们会根据身体情况选择喝开水、吃药、看病、等 异常处理方法。 java异常处理机制是我们java语言使用异常处理机制为程序提供了错误处理的能力,程序出现的错误,程序可以安全的退出,以保证程序正常的运行等

  7. Java Bean 作用域及它的几种类型介绍

    这篇文章主要介绍了Java Bean作用域及它的几种类型介绍,Spring框架作为一个管理Bean的IoC容器,那么Bean自然是Spring中的重要资源了,那Bean的作用域又是什么,接下来我们一起进入文章详细学习吧

  8. 面试突击之跨域问题的解决方案详解

    跨域问题本质是浏览器的一种保护机制,它的初衷是为了保证用户的安全,防止恶意网站窃取数据。那怎么解决这个问题呢?接下来我们一起来看

  9. Mybatis-Plus接口BaseMapper与Services使用详解

    这篇文章主要为大家介绍了Mybatis-Plus接口BaseMapper与Services使用详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  10. mybatis-plus雪花算法增强idworker的实现

    今天聊聊在mybatis-plus中引入分布式ID生成框架idworker,进一步增强实现生成分布式唯一ID,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

返回
顶部