我运行了一些有机化学模型。通过生成的ModelData.fs
文件来描述模型,例如:https://github.com/kkkmail/ClmFSharp/blob/master/Clm/Model/ModelData.fs。该文件具有非常简单的结构,并且使用生成的模型文件是可能的唯一途径。
参考文件仅用于测试,但实际模型非常庞大,可能接近60-70 MB / 1.5M LOC。当我尝试编译此类文件时,F#编译器fsc.exe
只会挂断,永远不会回来。它“吞噬”了约1.5 GB的内存,然后以接近100%的处理能力永远做某事。它可以清楚地处理较小的模型,这些模型在不到一分钟的时间内会占用大约10 MB的空间。因此,fsc
中10到70 MB之间的某个地方发生了严重损坏。
我想知道是否可以对fsc
编译项目的方式进行一些参数调整,以使其能够处理如此庞大的模型。
我要引用的大型模型的一个参数设置如下:let numberOfSubstances = 65643
。这将导致生成各种大小的数组。我想知道这是否可能是问题的根源。
非常感谢!
答案 0 :(得分:3)
我认为您不需要自动生成所有这些内容。
从您的评论中,我了解到d0
,d1
,...函数是从大型稀疏矩阵生成的,其总和为所有输入数组x
(具有系数),但关键是跳过对零系数求和,这会给您带来很大的性能提升,因为矩阵很大。那是正确的评估吗?
如果是这样,我仍然认为您不需要生成代码即可做到这一点。
让我们看看。我将假设您的巨型稀疏矩阵具有用于获取单元格值的接口,并且看起来像这样:
let getMatrixCell (i: int) (j: int) : double
let maxI: int
let maxJ: int
然后您的自动生成代码可能看起来像这样:
let generateDFunction (i: int) =
printfn "let d%d (x: double[]) =" i
printfn " [|"
for j in 0..maxJ do
let cell = getMatrixCell i j
if cell <> 0 then
printfn " %f * x.[%d]" cell j
printfn " |]"
printfn " |> Array.sum"
这将导致如下结果:
let d25 (x : array<double>) =
[|
-1.0 * x.[25]
1.0 * x.[3]
|]
|> Array.sum
请注意,我在这里进行了简化:在您的示例文件中,函数看起来也将负系数乘以x.[i]
。但是也许我也太复杂了,因为看起来所有系数始终都是1
或-1
。但这与我的观点无关。
现在,在注释中,建议您不要生成函数d0
,d1
,...,而是直接使用矩阵。例如,这将是这种建议的幼稚实现:
let calculateDFunction (i: int) (x: double[]) =
[| for j in 0..maxJ -> (getMatrixCell i j) * x.[j] |] |> Array.sum
然后,您认为该解决方案的速度将令人望而却步,因为它总是在整个数组x
上进行迭代,该数组很大,但是大多数系数为零,因此不必这样做。
然后,解决此问题的方法是使用生成代码的中间步骤:您生成仅涉及非零索引的函数,然后编译并使用这些函数。
但这是重点:是的,您确实需要中间步骤来摆脱非零指数,但不必生成并编译代码!
>相反,您可以提前准备非零索引的列表/数组:
let indicies =
[| for i in 0..maxI ->
[ for j in 0..maxJ do
let cell = getMatrixCell i j
if cell <> 0 then yield (j, cell)
]
|]
这将产生一个数组indicies : Array<int list>
,其中每个索引k
对应于您的自动生成的函数dk
,并且它包含一个非零矩阵索引列表以及它们在值中的值。矩阵。例如,我上面给出的功能d22
将由indicies
的第22个元素表示:
indicies.[22] = [ (25, -1.0), (3, 1.0) ]
基于此中间结构,然后可以计算任何函数dk
:
let calculateDFunction (k: int) (x: double[]) =
[| for (j, coeff) in indicies.[k] -> coeff * x.[j] |] |> Array.sum
实际上,如果性能对您至关重要(似乎来自注释),则您可能应该取消所有这些中间数组:每次迭代中成百上千个堆分配绝对无济于事。您可以使用可变变量求和:
let calculateDFunction (k: int) (x: double[]) =
let sum = 0.0
for (j, coeff) in indicies.[k] do
sum <- sum + coeff * x.[j]
sum