gpt4 book ai didi

f# - F#中矩阵计算的改进

转载 作者:行者123 更新时间:2023-12-03 23:08:25 26 4
gpt4 key购买 nike

我编写了一个代码来使用 F# 执行一些基本的矩阵计算。我想知道此代码是否有一些可能的改进以减少计算时间。
实际上,执行的操作非常基本(主要是 2 个矩阵的乘法和转置),但是矩阵的大小很高(大约 10000 * 100000)导致计算持续时间巨大(几个小时)。

我的问题/评论如下:

  • 有没有办法改进以下代码?有很多“为
    循环”,这可能会导致算法严重减慢,但我
    不知道如何避免这些“for 循环”。
  • 我创建了一些初始值为 0 的初始矩阵,并在第二次用结果填充它们的元素。也许可以避免初始化的第一步。

  • 这是算法:
    // I use the #time function to calculate the calculation duration of the algorithm
    #time

    #r "Microsoft.Office.Interop.Excel"
    #r "FSharp.PowerPack.dll"

    open System
    open System.IO

    open Microsoft.FSharp.Math
    open System.Collections.Generic

    // Algorithm
    let matrixCalculation (matA : matrix) (matB : matrix) (matC : matrix) =

    // First step : Renamed the matrix A and B size to initialize the matrix "matrixCalcul"
    let nbrOfElementsA = matA.NumRows
    let nbrOfElementsB = matB.NumRows
    let nbrOfCaracteristicsA = matA.NumCols
    let nbrOfCaracteristicsB = matB.NumCols

    // Second step : MatB has to be transposed
    let tmatB = matB.Transpose

    // Initialisation of the final output named matrixCalcul. A weighted vector is also initialised
    let mutable matrixCalcul = Matrix.create (nbrOfElementsA + 1) (nbrOfElementsB + 1) 0.
    let mutable weightedVector = Matrix.create nbrOfCaracteristicsA 1 0.

    // The first column of matA and matB represents IDs, and are "copy/past" in matrixCalcul's first colum and first row respectively
    matrixCalcul.[1.. ,0..0] <- matA.[0..,0..0]
    matrixCalcul.[0..0,1 ..] <- matB.[0..,0..0].Transpose

    // Then the core of the matrix named "matrixCalcul" can be calculated
    for j = 0 to (nbrOfElementsB - 1) do
    weightedVector <- matC * tmatB.[1..(nbrOfCaracteristicsB - 1),0..(nbrOfElementsB-1)].Columns(j,1)
    for i = 0 to (nbrOfElementsA - 1) do
    let mutable acc = matA.[0..(nbrOfElementsA - 1),1..(nbrOfCaracteristicsA-1)].Rows(i,1) * weightedVector
    matrixCalcul.[i+1,j+1] <- (acc.[0,0])
    matrixCalcul


    // Two matrix generators (one for matA and matB and another one for matC)

    let matrixTestGeneratorAandB nbrOfElements nbrOfCaracteristics =
    let matrixTestGeneratedAandB = Matrix.create nbrOfElements nbrOfCaracteristics 0.
    |> Matrix.mapi (fun i j value -> if j = 0 then float(i + 1) elif j % 2 = 0 then 1. else 0.)
    matrixTestGeneratedAandB

    let matrixTestGeneratorC nbrOfElements nbrOfCaracteristics =
    let matrixTestGeneratedC = Matrix.create nbrOfElements nbrOfCaracteristics 0.
    |> Matrix.mapi (fun i j value -> if j = 0 then 0. elif j % 2 = 0 then 1. else 0.)
    matrixTestGeneratedC


    // Generation of matrixA, matrixB and matrixC

    let matrixA = matrixTestGeneratorAandB 100 179

    let matrixB = matrixTestGeneratorAandB 100 639

    let matrixC = matrixTestGeneratorC 178 638

    // Calculation
    matrixCalculation matrixA matrixB matrixC

    基本上计算持续时间约为 2 秒,但如果您更改 matrixA 的数量和 matrixB高达 10000 ,这可能需要一个小时。仅供引用,在我的算法中, matrixC的大小将保持不变,只有矩阵 A 和 B 的行数可以增加。

    如果你有任何改进的想法,我接受。

    最佳答案

    从您的代码中,很难理解您要实现的目标。我认为您的意思是计算矩阵 d[0..m, 0..n]如下:

      +---------+-------------------------+
    | 0.0 | b00 b10 ...... b(n-1)0 |
    +---------+-------------------------+
    | a00 | d11 d12 ...... d1n |
    | a10 | d21 d22 ...... d2n |
    | ... | ... ... ...... ... |
    | ... | ... ... ...... ... |
    | ... | ... ... ...... ... |
    | a(m-1)0 | dm1 dm2 ...... dmn |
    +---------+-------------------------+

    其中核心部分(内部矩阵 d[1..m, 1..n] )是三个矩阵的乘积 matA1 ( matA 修剪第一列后), matCmatB1 ( matB 修剪第一列并转置后)。

    要理解矩阵运算,一个很好的方法是推理矩阵大小。让 ra , ca , rb , cb , rccc表示 matA中的行数和列数, matBmatC分别。乘法在三个大小为 ra x (ca-1) 的矩阵之间进行, rc x cc(cb-1) x rb ;这仅在 rc = ca-1 时才有意义和 cc = cb-1 .我们有结果矩阵 d尺寸 (ra+1) x (rb+1) .

    这是我的尝试,不使用任何 for环形:
    let calculate (matA : matrix) (matB : matrix) (matC : matrix) = 
    let ra = matA.NumRows
    let ca = matA.NumCols
    let rb = matB.NumRows
    let cb = matB.NumCols
    let matrixCalcul = Matrix.zero (ra+1) (rb+1)

    matrixCalcul.[1.., 0..0] <- matA.[0.., 0..0]
    matrixCalcul.[0..0, 1..] <- matB.[0.., 0..0].Transpose

    matrixCalcul.[1.., 1..] <- (matA.Columns(1, ca-1) * matC) * matB.Columns(1, cb-1).Transpose
    matrixCalcul

    我已经用 matA 测试过了, matBmatC大小分别为 200x279、200x1279 和 278x1238。两个版本产生相同的结果,我的函数是 40x比原来的快。造成这种情况的原因有很多,但总的来说,向量化版本在矩阵计算方面具有更好的性能。

    关于f# - F#中矩阵计算的改进,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8565489/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com