Swiftの行列計算など

使用頻度の高い計算を簡単にできるようにしました。
行列式の算出のためにLU分解についても書きましたが、ピボットの実装をしていません。
行列の対角要素に0が含まれている場合に不安定になります。

いつかはピボットを実装して、より汎用的に使えるようにしたいと思います。

import Foundation

class Calc {
    //ベクトルの総和
    func vsum(vector: [Double]) -> Double {
        var v_sum: Double = 0
        for i in 0..<vector.count{
            v_sum = v_sum + vector[i]
        }
        return v_sum
    }
    
    //平均
    func vmean(vector:[Double]) -> Double {
        let mean = self.vsum(vector: vector)/Double(vector.count)
        return mean
    }
    
    //標準偏差
    func std(vector:[Double]) -> Double {
        var std_temp = [Double](repeating:0, count: vector.count)
        for i in 0..<vector.count{
            std_temp[i] = pow(vector[i]-self.vmean(vector: vector), 2)
        }
        let std: Double = sqrt(self.vmean(vector: std_temp))
        return std
    }
    
    //zsocre正規化
    func zscore(vector: [Double]) -> [Double] {
        var z = [Double](repeating:0, count: vector.count)
        for i in 0..<vector.count{
            z[i] = (vector[i]-self.vmean(vector: vector))/self.std(vector: vector)
        }
        return z
    }
    
    //行列の転置
    func transpose(matrix: [[Double]]) -> [[Double]]{
        var matrix_T = [[Double]](repeating: [Double](repeating: 0, count: matrix.count), count: matrix[0].count)
        for i in 0..<matrix[0].count{
            for j in 0..<matrix.count{
                matrix_T[i][j] = matrix[j][i]
            }
        }
        return matrix_T
    }

    //ベクトルの内積
    func vdot(vector: [Double], _vector:[Double]) -> Double {
        var vv: Double = 0
        for i in 0..<vector.count{
            let vv_temp: Double = vector[i] * _vector[i]
            vv += vv_temp
        }
        return vv
    }
    
    //スカラー掛けるベクトル
    func sxv(scalar: Double, vector: [Double]) -> [Double] {
        var sv = [Double](repeating:0, count: vector.count)
        for i in 0..<vector.count{
            sv[i] = scalar * vector[i]
        }
        return sv
    }
    
    //スカラー足すベクトル
    func spv(scalar: Double, vector: [Double]) -> [Double] {
        var sv = [Double](repeating:0, count: vector.count)
        for i in 0..<vector.count{
            sv[i] = scalar + vector[i]
        }
        return sv
    }
    
    //ベクトル足すベクトル
    func vpv(vector: [Double], vector_: [Double]) -> [Double] {
        var vv = [Double](repeating:0, count: vector.count)
        for i in 0..<vector.count{
            vv[i] = vector[i] + vector_[i]
        }
        return vv
    }
    
    //ベクトル引くベクトル
    func vmv(vector: [Double], vector_: [Double]) -> [Double] {
        var vv = [Double](repeating:0, count: vector.count)
        for i in 0..<vector.count{
            vv[i] = vector[i] - vector_[i]
        }
        return vv
    }
    
    //ベクトルの平方根
    func vsqrt(vector: [Double]) -> [Double] {
        var sv = [Double](repeating:0, count: vector.count)
        for i in 0..<vector.count{
            sv[i] = sqrt(vector[i])
        }
        return sv
    }
    
    //ベクトルの累乗
    func vpow(vector: [Double], power: Double) -> [Double] {
        var pv = [Double](repeating:0, count: vector.count)
        for i in 0..<vector.count{
            pv[i] = pow(vector[i], power)
        }
        return pv
    }
    
    //ベクトルの指数
    func vexp(vector: [Double]) -> [Double] {
        var ev = [Double](repeating:0, count: vector.count)
        for i in 0..<vector.count{
            ev[i] = exp(vector[i])
        }
        return ev
    }
    
    //スカラー掛ける行列
    func sxm(scalar: Double, matrix: [[Double]]) -> [[Double]] {
        var sm = [[Double]](repeating: [Double](repeating: 0, count: matrix[0].count), count: matrix.count)
        for i in 0..<matrix.count{
            for j in 0..<matrix[0].count{
                sm[i][j] = scalar * matrix[i][j]
            }
        }
        return sm
    }
    
    //スカラー足す行列
    func spm(scalar: Double, matrix: [[Double]]) -> [[Double]] {
        var sm = [[Double]](repeating: [Double](repeating: 0, count: matrix[0].count), count: matrix.count)
        for i in 0..<matrix.count{
            for j in 0..<matrix[0].count{
                sm[i][j] = scalar + matrix[i][j]
            }
        }
        return sm
    }
    
    
    //行列引く行列
    func mmm(matrix: [[Double]], matrix_: [[Double]]) -> [[Double]] {
        var mm = [[Double]](repeating: [Double](repeating: 0, count: matrix[0].count), count: matrix.count)
        for i in 0..<matrix.count{
            for j in 0..<matrix[0].count{
                mm[i][j] = matrix[i][j] - matrix_[i][j]
            }
        }
        return mm
    }

    //行列足す行列
    func mpm(matrix: [[Double]], matrix_: [[Double]]) -> [[Double]] {
        var mm = [[Double]](repeating: [Double](repeating: 0, count: matrix[0].count), count: matrix.count)
        for i in 0..<matrix.count{
            for j in 0..<matrix[0].count{
                mm[i][j] = matrix[i][j] + matrix_[i][j]
            }
        }
        return mm
    }

    //行列の内積
    func mdot(matrix: [[Double]], _matrix: [[Double]]) -> [[Double]] {
        var mm = [[Double]](repeating: [Double](repeating: 0, count: _matrix[0].count), count: matrix.count)
        let _matrix_T = self.transpose(matrix: _matrix)
        for i in 0..<matrix.count{
            for j in 0..<_matrix[0].count{
                mm[j][i] = self.vdot(vector: matrix[j], _vector: _matrix_T[i])
            }
        }
        return mm
    }
        
    //単位行列
    func eye(n: Int) -> [[Double]] {
        var eye = [[Double]](repeating: [Double](repeating: 0, count: n), count: n)
        for i in 0..<eye.count{
            for j in 0..<eye.count{
                if i == j {
                    eye[i][j] = 1
                }
            }
        }
        return eye
    }
    
    //トレース
    func trace(matrix: [[Double]]) -> Double {
        var tr: Double = 0
        for i in 0..<matrix.count {
            tr += matrix[i][i]
        }
        return tr
    }
 
    //LU分解
    func LU(matrix: [[Double]]) -> (L: [[Double]], U: [[Double]]) {
        //ピボット選択は行わない
        //係数行列の対角要素のいずれかが0(または非常に小さいor他の要素に比べ非常に小さい)のとき不安定
        //下三角行列Lの対角要素は1
        var A: [[Double]] = matrix
        for i in 0..<A.count {
            for j in i+1..<A.count {
                A[j][i] = A[j][i] / A[i][i]
                for k in i+1..<A.count {
                    A[j][k] = A[j][k] - A[j][i] * A[i][k]
                }
            }
        }
        var L = self.eye(n: A.count)
        var U = [[Double]](repeating: [Double](repeating: 0, count: A[0].count), count: A.count)
        for i in 0..<A.count {
            for j in 0..<A.count {
                if i>j {
                    L[i][j] = A[i][j]
                } else {
                    U[i][j] = A[i][j]
                }
            }
        }
        return (L, U)
    }
    
    //行列式
    func det(matrix: [[Double]]) -> Double {
        //LU分解を使うため、対角要素が全て0以上であることを仮定
        let U = self.LU(matrix: matrix).U
        var det: Double = 1
        for i in 0..<U.count{
            det *= U[i][i]
        }
        return det
    }
    
    //逆行列
    func inv(matrix: [[Double]]) -> [[Double]] {
        //掃き出し法
        var m: [[Double]] = matrix
        var m_inv = self.eye(n: m.count)
        
        for i in 0..<m.count{
            var temp: Double = 1/m[i][i]
            for j in 0..<m.count{
                m[i][j] *= temp
                m_inv[i][j] *= temp
            }
            
            for j in 0..<m.count{
                if i != j{
                    temp = m[j][i]
                    for k in 0..<m.count{
                        m[j][k] -= m[i][k] * temp
                        m_inv[j][k] -= m_inv[i][k]*temp
                    }
                }
            }
        }
        return m_inv
    }
    
    //擬似弱行列
    func pinv(matrix: [[Double]]) -> [[Double]] {
        let m_pinv: [[Double]] = self.mdot(matrix: self.inv(matrix: self.mdot(matrix: self.transpose(matrix: matrix), _matrix: matrix)), _matrix: self.transpose(matrix: matrix))
        return m_pinv
    }
}


let calc = Calc()

let x: [Double] = [170, 16, 175, 15]

let y_mean = calc.vmean(vector: x)
let y_std = calc.std(vector: x)
let y_norm = calc.zscore(vector: x)
print("平均:", y_mean)
print("標準偏差:", y_std)
print("zscore正規化:", y_norm)

let a: [[Double]] = [[1,2],[3,4],[5,6]]
let b: [[Double]] = [[7,8,9],[10,11,12]]
let c = calc.mdot(matrix:a, _matrix:b)
print("行列の内積:",c)

let d: [Double] = [1,2,3]
let e: [Double] = [4,5,6]
let f = calc.vdot(vector:d, _vector:e)
print("ベクトルの内積:",f)

let g = calc.sxv(scalar: 2, vector: d)
print("スカラー掛けるベクトル:",g)

let h = calc.sxm(scalar: 2, matrix: a)
print("スカラー掛ける行列:",h)

let l: [[Double]] = [[1,2,0,-1],[-1,1,2,0],[2,0,1,1],[1,-2,-1,1]]
let m = calc.det(matrix: l)
print("行列式:",m)
let o = calc.inv(matrix: l)
print("逆行列:",o)
let p = calc.pinv(matrix: l)
print("擬似逆行列:",p)