在Swift中使用Accelerate Framework进行矩阵求逆

4

按照我在这里找到的好的指示:https://github.com/haginile/SwiftAccelerate,我验证了矩阵求逆的工作。实际上,它对于给定的示例确实有效。

但是,对于任何其他大于2x2的矩阵(例如转换为1D数组的以下2D矩阵),我会收到EXC_BAD_ACCESS错误,并已在matlab和python中进行了测试并成功运行。

m = [0.55481645013013, -1.15522603580724, 0.962090414322894, -0.530226035807236, 0.168545207161447, -0.38627124296868, 0.93401699437494, -0.999999999999995, 0.684016994374945, -0.23176274578121, 0.123606797749979, -0.323606797749979, 0.432893622827287, -0.323606797749979, 0.123606797749979, 0.231762745781211, -0.684016994374948, 1.0, -0.934016994374947, 0.386271242968684, 0.168545207161448, -0.530226035807237, 0.962090414322895, -1.15522603580724, 0.554816450130132]

它的逆矩阵应该是

inv(AA)

ans =

  Columns 1 through 3

          -262796763616197          -656991909040516          4.90007819375216
          -162417332048282          -406043330120712          14.6405748712708
         0.718958226823704          7.87760147961979          30.4010295628018
           162417332048287           406043330120730          46.1614842543337
           262796763616208           656991909040536          55.9019809318537

  Columns 4 through 5

          -656991909040528           262796763616211
          -406043330120721           162417332048287
         -4.28281034550088        -0.718958226823794
           406043330120704          -162417332048283
           656991909040497          -262796763616196

您能否给我另一种在Swift中进行矩阵求逆的方法?或者解释一下如何修复这个问题?

2个回答

10

这段代码无法正常工作,因为你找到的指令不太妥当。具体来说,旋转轴和工作空间都需要是数组而不是标量值;之前只能以随机的方式处理二乘二矩阵。

下面是修改后的invert函数,可以正确地分配工作空间:

func invert(matrix : [Double]) -> [Double] {
  var inMatrix = matrix
  var N = __CLPK_integer(sqrt(Double(matrix.count)))
  var pivots = [__CLPK_integer](count: Int(N), repeatedValue: 0)
  var workspace = [Double](count: Int(N), repeatedValue: 0.0)
  var error : __CLPK_integer = 0
  dgetrf_(&N, &N, &inMatrix, &N, &pivots, &error)
  dgetri_(&N, &inMatrix, &N, &pivots, &workspace, &N, &error)
  return inMatrix
}

我应该指出,你的5x5矩阵非常病态,因此即使你可以计算“反转”,该计算的误差也会非常大,并且反转真的不应该被使用。
一个Swift 4版本:
func invert(matrix : [Double]) -> [Double] {
    var inMatrix = matrix
    var N = __CLPK_integer(sqrt(Double(matrix.count)))
    var pivots = [__CLPK_integer](repeating: 0, count: Int(N))
    var workspace = [Double](repeating: 0.0, count: Int(N))
    var error : __CLPK_integer = 0

    withUnsafeMutablePointer(to: &N) {
        dgetrf_($0, $0, &inMatrix, $0, &pivots, &error)
        dgetri_($0, &inMatrix, $0, &pivots, &workspace, $0, &error)
    }
    return inMatrix
}

天才!非常感谢!我的矩阵病态,因为它只有5x5。我会进行其他测试,但是我的计算需要使用至少21x21的矩阵。 - Nicholas
Xcode 9出现“同时访问变量'N',但修改需要独占访问;考虑复制到本地变量”的错误。这是Xcode 9的bug还是我们应该以不同的方式编写代码? - Guig
1
@Guig:这是https://github.com/apple/swift-evolution/blob/master/proposals/0176-enforce-exclusive-access-to-memory.md的结果,尽管它并不明显地旨在适用于类似LAPACK的C风格的不安全指针API。您可以通过复制“N”来解决此问题。 - Stephen Canon
谢谢提供链接。 dgetrf_dgetri_ 不会修改任何 &N,对吗? - Guig
@Guig: LAPACK 库将这些参数声明为 __CLPK_integer *__n 而不是 const __CLPK_integer *__n,即使它们不会被修改。这可能有历史原因,但作为后果,它们以 UnsafeMutablePointer<...> 的形式导入到 Swift 中,而 Swift 编译器会抱怨可能的同时访问。 - Martin R
4
@StephenCanon: 我已经擅自添加了一个Swift 4版本,希望你不介意。 - Martin R

2

我在哪里可以获取这个库? - Nicholas
哦天啊,我添加了源代码和文档的链接。 - Scott
天才!在Github上比较Swift和Matlab/Python的链接无法使用,你能修复一下吗?我很快会尝试你的库来满足我的需求。 - Nicholas
你的样例项目运行得非常好,但是无法将你的库包含在一个全新的项目中!你的说明不完整! - Nicholas
另一个用户遇到了相同的问题,我已经通过 Github 的问题#24 更新了安装说明。这些是轻微的修改;今年夏天,我将为 Swift 包管理器进行改进。 - Scott

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接