Function which returns the least-squares solution to a linear matrix equation

2024/9/28 17:34:40

I have been trying to rewrite the code from Python to Swift but I'm stuck on the function which should return the least-squares solution to a linear matrix equation. Does anyone know a library written in Swift which has an equivalent method to the numpy.linalg.lstsq? I'd be grateful for your help.

Python code:

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 code so far:

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]
Answer

The Accelerate framework included the LAPACK linear algebra package, which has a DGELS function to solve under- or overdetermined linear systems. From the documentation:

DGELS solves overdetermined or underdetermined real linear systemsinvolving an M-by-N matrix A, or its transpose, using a QR or LQfactorization of A. It is assumed that A has full rank.

Here is an example how that function can be used from Swift. It is essentially a translation of this C sample code.

func solveLeastSquare(A A: [[Double]], B: [Double]) -> [Double]? {precondition(A.count == B.count, "Non-matching dimensions")var mode = Int8(bitPattern: UInt8(ascii: "N")) // "Normal" modevar nrows = CInt(A.count)var ncols = CInt(A[0].count)var nrhs = CInt(1)var ldb = max(nrows, ncols)// Flattened columns of matrix Avar localA = (0 ..< nrows * ncols).map {A[Int($0 % nrows)][Int($0 / nrows)]}// Vector B, expanded by zeros if ncols > nrowsvar localB = Bif ldb > nrows {localB.appendContentsOf([Double](count: ldb - nrows, repeatedValue: 0.0))}var wkopt = 0.0var lwork: CInt = -1var info: CInt = 0// First call to determine optimal workspace sizedgels_(&mode, &nrows, &ncols, &nrhs, &localA, &nrows, &localB, &ldb, &wkopt, &lwork, &info)lwork = Int32(wkopt)// Allocate workspace and do actual calculationvar 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)))
}

Some notes:

  • dgels_() modifies the passed matrix and vector data, and expects the matrix as "flat" array containing the columns of A. Also the right-hand side is expected as an array with length max(M, N). For this reason, the input data is copied to local variables first.
  • All arguments must be passed by reference to dgels_(), that's why they are all stored in vars.
  • A C integer is a 32-bit integer, which makes some conversions between Int and CInt necessary.

Example 1: Overdetermined system, from http://www.seas.ucla.edu/~vandenbe/103/lectures/ls.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]
}

Example 2: Underdetermined system, minimum norm solution to 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]
}

Update for Swift 3 and 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" modevar nrows = CInt(A.count)var ncols = CInt(A[0].count)var nrhs = CInt(1)var ldb = max(nrows, ncols)// Flattened columns of matrix Avar localA = (0 ..< nrows * ncols).map { (i) -> Double inA[Int(i % nrows)][Int(i / nrows)]}// Vector B, expanded by zeros if ncols > nrowsvar localB = Bif ldb > nrows {localB.append(contentsOf: [Double](repeating: 0.0, count: Int(ldb - nrows)))}var wkopt = 0.0var lwork: CInt = -1var info: CInt = 0// First call to determine optimal workspace sizevar nrows_copy = nrows // Workaround for SE-0176dgels_(&mode, &nrows, &ncols, &nrhs, &localA, &nrows_copy, &localB, &ldb, &wkopt, &lwork, &info)lwork = Int32(wkopt)// Allocate workspace and do actual calculationvar 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)))
}
https://en.xdnf.cn/q/71311.html

Related Q&A

Divide .csv file into chunks with Python

I have a large .csv file that is well over 300 gb. I would like to chunk it into smaller files of 100,000,000 rows each (each row has approximately 55-60 bytes).I wrote the following code:import panda…

Why cant I use operator.itemgetter in a multiprocessing.Pool?

The following program:import multiprocessing,operator f = operator.itemgetter(0) # def f(*a): return operator.itemgetter(0)(*a) if __name__ == __main__:multiprocessing.Pool(1).map(f, ["ab"])f…

Writing a compiler for a DSL in python

I am writing a game in python and have decided to create a DSL for the map data files. I know I could write my own parser with regex, but I am wondering if there are existing python tools which can do …

How to setup Celery to talk ssl to Azure Redis Instance

Using the great answer to "How to configure celery-redis in django project on microsoft azure?", I can configure Celery to use Azure Redis Cache using the non-ssl port, 6379, using the follo…

Cant save data from yfinance into a CSV file

I found library that allows me to get data from yahoo finance very efficiently. Its a wonderful library.The problem is, I cant save the data into a csv file.Ive tried converting the data to a Panda Da…

silhouette coefficient in python with sklearn

Im having trouble computing the silhouette coefficient in python with sklearn. Here is my code :from sklearn import datasets from sklearn.metrics import * iris = datasets.load_iris() X = pd.DataFrame(i…

Force dask to_parquet to write single file

When using dask.to_parquet(df, filename) a subfolder filename is created and several files are written to that folder, whereas pandas.to_parquet(df, filename) writes exactly one file. Can I use dasks t…

Unable to get python embedded to work with zipd library

Im trying to embed python, and provide the dll and a zip of the python libraries and not use any installed python. That is, if a user doesnt have python, I want my code to work using the provided dll/…

Convert integer to a random but deterministically repeatable choice

How do I convert an unsigned integer (representing a user ID) to a random looking but actually a deterministically repeatable choice? The choice must be selected with equal probability (irrespective o…

Using python opencv to load image from zip

I am able to successfully load an image from a zip:with zipfile.ZipFile(test.zip, r) as zfile:data = zfile.read(test.jpg)# how to open this using imread or imdecode?The question is: how can I open thi…