2014-09-29 54 views
0

我正在写一些代码作为非线性回归工具的一部分,我试图找出一种方法来返回给定函数的第n个偏导数,快速。函数(以及部分的分析表示)在运行时是已知的,可以对它们进行硬编码。这里是我到目前为止(工作):优化反复称为数学函数

let getPartials (paramVect: array<float>) idx = 
    let a = paramVect.[0] 
    let b = paramVect.[1] 
    let c = paramVect.[2] 
    match idx with 
    | 1 -> (fun x -> (1.0+b+c*x)**(-1.0/b)) // df(x)/da 
    | 2 -> (fun x -> ((a*(1.0+c*b*x)**(-(b+1.0)/b))*((b*c*x+1.0)*Math.Log(b*c*x+1.0)-b*c*x))/(b*b))  // df(x)/db 
    | 3 -> (fun x -> -a*x*(b*c*x+1.0)**(-(b+1.0)/b)) // df/dc 
    | _ -> (fun x -> 0.0) //everything else is zero 

我用这是先建立一个部分功能与参数向量所以,我尽量减少需要在传递次数的方式然后我重复地调用(getPartials(i)x_val)来构造一个jacobian。这个函数在程序的生命周期中被调用了很多次。

但是,我认为它可以得到改善,我得到了非常可以接受的性能。分析表明,对第二功能计算(长计算)的评估是一个cpu排放 - 可以优化吗?我不确定,如果匿名函数创建一个性能问题,为可读,因为它是...

全新到F#编程,所以请让你发现任何egregarious问题,我知道,无论是风格/形式或表演!

谢谢


更新:落实JohnPalmer和重构建议修改完成后,不用返回其接受x值作为参数的匿名功能,而不是做整个计算就地而言,我看到的速度大约提高了300%。能够返回部分功能更方便,但不值得花费。

let getPartials (paramVect: array<float>) idx x = 
let a = paramVect.[0] 
let b = paramVect.[1] 
let cbx = paramVect.[1] * paramVect.[2] * x 

match idx with 
| 1 -> (1.0+cbx)**(-1.0/b) // df(x)/da 
| 2 -> ((a*(1.0+cbx)**(-(b+1.0)/b))*((cbx+1.0)*Math.Log(cbx+1.0)-cbx))/(b**2.0) // df(x)/db 
| 3 -> -a*x*(cbx+1.0)**(-(b+1.0)/b)  // df/dc 
| _ -> 0.0        //everything else is zero 
+0

有,你可以转换为常数,这可能有助于一些公共子 - 例如'b * c * x'。如果您知道某些参数总是大或小,则可能会以牺牲准确性为代价简化某些表达式。另外,如果你可以接受精确度惩罚,float32比float更快。 – 2014-09-29 22:09:39

+0

@JohnPalmer我确定我读过float32通常比float更慢的原因,因为计算实际上是在FPU中以相同的精度完成的,但对于float32,在截断值时有更多的舍入操作。 – phoog 2014-09-29 22:27:59

+0

Profiler实际上是否表示速度增加是由于乘法的数量减少?检查你的GC统计数据 - 这使我更有可能获得改进的性能。 – phoog 2014-09-29 22:49:59

回答

1

匿名函数导致性能问题的最可能的原因是每次调用getPartials函数时都会创建一个新的堆对象。如果您只有少数不同的paramVect s,那么您可能通过缓存匿名函数获得一些性能优势。

至于第二个表达式的值,你可以试试这个(以约翰·帕尔默的建议,以消除常见的子表达式):

fun x -> let bcx = b * c * x 
      let bcx1 = bcx + 1.0 
      a * bcx1 ** (-(b+1.0)/b) * (bcx1 * Math.Log bcx1 - bcx)/(b*b) 
+0

感谢您的回复。我对OP进行了一些更改,以反映我尝试过的一些新更改(符合您的&JohnPalmers建议)。抛弃匿名函数最终将事情推上了很多倍。ParamVector改变了数千次,所以我无法缓存它。 – NMR 2014-09-29 22:51:44