Функция, возвращающая решение наименьших квадратов в линейное матричное уравнение
Я должен переписать код с Python на Swift, но я застрял на функции, которая должна вернуть решение наименьших квадратов в линейное матричное уравнение. Кто-нибудь из вас знает библиотеку, написанную в Swift, которая имеет эквивалентный метод numpy.linalg.lstsq
? Буду благодарен за помощь.
Python-кода:
a = numpy.array([[p2.x-p1.x,p2.y-p1.y],[p4.x-p3.x,p4.y-p3.y],[p4.x-p2.x,p4.y-p2.y],[p3.x-p1.x,p3.y-p1.y]])
b = numpy.array([number1,number2,number3,number4])
res = numpy.linalg.lstsq(a,b)
result = [float(res[0][0]),float(res[0][1])]
return result
SWIFT код до сих пор:
var matrix1 = [[p2.x-p1.x, p2.y-p1.y],[p4.x-p3.x, p4.y-p3.y], [p4.x-p2.x, p4.y-p2.y], [p3.x-p1.x, p3.y-p1.y]]
var matrix2 = [number1, number2, number3, number4]
1 ответов
рамки ускорения включали LAPACK пакет линейной алгебры , который имеет DGELS функции для решения недо - или переопределенной линейной системы. Из документации:
DGELS решает переопределенные или недетерминированные реальные линейные системы вовлечение матрицы M-by-N A или ее транспонирование с использованием QR или LQ факторизация A. предполагается, что A имеет полный ранг.
вот пример того, как эту функцию можно использовать из Swift. Это по сути перевод этот пример кода C.
func solveLeastSquare(A A: [[Double]], B: [Double]) -> [Double]? {
precondition(A.count == B.count, "Non-matching dimensions")
var mode = Int8(bitPattern: UInt8(ascii: "N")) // "Normal" mode
var nrows = CInt(A.count)
var ncols = CInt(A[0].count)
var nrhs = CInt(1)
var ldb = max(nrows, ncols)
// Flattened columns of matrix A
var localA = (0 ..< nrows * ncols).map {
A[Int( % nrows)][Int( / nrows)]
}
// Vector B, expanded by zeros if ncols > nrows
var localB = B
if ldb > nrows {
localB.appendContentsOf([Double](count: ldb - nrows, repeatedValue: 0.0))
}
var wkopt = 0.0
var lwork: CInt = -1
var info: CInt = 0
// First call to determine optimal workspace size
dgels_(&mode, &nrows, &ncols, &nrhs, &localA, &nrows, &localB, &ldb, &wkopt, &lwork, &info)
lwork = Int32(wkopt)
// Allocate workspace and do actual calculation
var work = [Double](count: Int(lwork), repeatedValue: 0.0)
dgels_(&mode, &nrows, &ncols, &nrhs, &localA, &nrows, &localB, &ldb, &work, &lwork, &info)
if info != 0 {
print("A does not have full rank; the least squares solution could not be computed.")
return nil
}
return Array(localB.prefix(Int(ncols)))
}
некоторые замечания:
-
dgels_()
изменяет переданные матричные и векторные данные и ожидает матрица, как "плоский" массив, содержащий столбцыA
. Также правая сторона ожидается в виде массива с длинойmax(M, N)
. По этой причине входные данные сначала копируются в локальные переменные. - все аргументы должны быть передан ссылка на
dgels_()
, вот почему все они хранятся вvar
s. - целое число C является 32-разрядным целым числом, которое делает некоторые преобразования между
Int
иCInt
надо.
Пример 1: Переопределенная система, от http://www.seas.ucla.edu / ~vandenbe / 103 / лекции / общ. pdf.
let A = [[ 2.0, 0.0 ],
[ -1.0, 1.0 ],
[ 0.0, 2.0 ]]
let B = [ 1.0, 0.0, -1.0 ]
if let x = solveLeastSquare(A: A, B: B) {
print(x) // [0.33333333333333326, -0.33333333333333343]
}
Пример 2: Недетерминированная система, минимальная норма
решение x_1 + x_2 + x_3 = 1.0
.
let A = [[ 1.0, 1.0, 1.0 ]]
let B = [ 1.0 ]
if let x = solveLeastSquare(A: A, B: B) {
print(x) // [0.33333333333333337, 0.33333333333333337, 0.33333333333333337]
}
обновление Swift 3 и Swift 4:
func solveLeastSquare(A: [[Double]], B: [Double]) -> [Double]? {
precondition(A.count == B.count, "Non-matching dimensions")
var mode = Int8(bitPattern: UInt8(ascii: "N")) // "Normal" mode
var nrows = CInt(A.count)
var ncols = CInt(A[0].count)
var nrhs = CInt(1)
var ldb = max(nrows, ncols)
// Flattened columns of matrix A
var localA = (0 ..< nrows * ncols).map { (i) -> Double in
A[Int(i % nrows)][Int(i / nrows)]
}
// Vector B, expanded by zeros if ncols > nrows
var localB = B
if ldb > nrows {
localB.append(contentsOf: [Double](repeating: 0.0, count: Int(ldb - nrows)))
}
var wkopt = 0.0
var lwork: CInt = -1
var info: CInt = 0
// First call to determine optimal workspace size
var nrows_copy = nrows // Workaround for SE-0176
dgels_(&mode, &nrows, &ncols, &nrhs, &localA, &nrows_copy, &localB, &ldb, &wkopt, &lwork, &info)
lwork = Int32(wkopt)
// Allocate workspace and do actual calculation
var work = [Double](repeating: 0.0, count: Int(lwork))
dgels_(&mode, &nrows, &ncols, &nrhs, &localA, &nrows_copy, &localB, &ldb, &work, &lwork, &info)
if info != 0 {
print("A does not have full rank; the least squares solution could not be computed.")
return nil
}
return Array(localB.prefix(Int(ncols)))
}