Files
PerspectiveTransform/Example/Tests/AccelerateSolvePerfTest.swift
2019-04-10 03:24:56 -07:00

108 lines
3.9 KiB
Swift

//
// AccelerateSolvePerfTest.swift
// PerspectiveTransform
//
// Created by Paul Zabelin on 2/23/16.
// Copyright © 2016 CocoaPods. All rights reserved.
//
import XCTest
import Accelerate
@testable import PerspectiveTransform
@discardableResult
func solve(_ A: [Double], _ B: [Double] ) -> [Double] {
var inMatrix: [Double] = A
var solution: [Double] = B
// Get the dimensions of the matrix. An NxN matrix has N^2
// elements, so sqrt( N^2 ) will return N, the dimension
var N: __CLPK_integer = __CLPK_integer( sqrt( Double( A.count ) ) )
// Number of columns on the RHS
var NRHS: __CLPK_integer = 1
// Leading dimension of A and B
var LDA: __CLPK_integer = N
var LDB: __CLPK_integer = N
// Initialize some arrays for the dgetrf_(), and dgetri_() functions
var pivots: [__CLPK_integer] = [__CLPK_integer](repeating: 0, count: Int(N))
var error: __CLPK_integer = -1
// Perform LU factorization
dgetrf_(&LDA, &LDB, &inMatrix, &N, &pivots, &error)
XCTAssertEqual(0, error, "should be successful")
// Calculate solution from LU factorization
_ = "T".withCString {
// Solves a general system of linear equations, after factorization
dgetrs_( UnsafeMutablePointer(mutating: $0), &N, &NRHS, &inMatrix, &LDA, &pivots, &solution, &LDB, &error )
}
XCTAssertEqual(0, error, "should be successful")
return solution
}
class AccelerateSolvePerfTest: XCTestCase {
static let reasonableTestDurationMs = 100
var repeatTimes = AccelerateSolvePerfTest.reasonableTestDurationMs * 200
var A: [Double]?
var B: [Double]?
func testSolveCorrectness() {
A = [ 1, 1, 4, 6 ]
B = [ 383, 2034 ]
XCTAssertEqual([ 132.0, 251.0 ], solve(A!, B!))
}
func preparePerspective() {
let start = Quadrilateral(CGRect(origin: CGPoint.zero, size: CGSize(width: 152, height: 122)))
let destination = Quadrilateral(
CGRect(
origin: CGPoint(x: 100, y: 100),
size: CGSize(width: 200, height: 200)
)
)
print(start.corners)
print(destination.corners)
func row1(p1: CGPoint, p2: CGPoint) -> [Double] {
return [p1.x, p1.y, 1, 0, 0, 0, -p2.x*p1.x, -p2.x*p1.y].map {Double($0)}
}
func row2(p1: CGPoint, p2: CGPoint) -> [Double] {
return [0, 0, 0, p1.x, p1.y, 1, -p2.y*p1.x, -p2.y*p1.y].map {Double($0)}
}
// let empty: [Double] = []
A = stride(from: 0, through: 3, by: 1).map {
row1(p1: start.corners[$0], p2: destination.corners[$0]) +
row2(p1: start.corners[$0], p2: destination.corners[$0])
}.reduce([], {$0! + $1})
B = stride(from: 0, through: 3, by: 1).map {[destination.corners[$0].x, destination.corners[$0].y]}.reduce([], +).map {Double($0)}
}
func testSolvePerspectiveCorrectness() {
preparePerspective()
let solution = solve(A!, B!)
let accuracy = 0.000000001
XCTAssertEqual(solution[0], 1.31578947368421, accuracy: accuracy)
XCTAssertEqual(solution[1], 0, accuracy: accuracy)
XCTAssertEqual(solution[2], 100, accuracy: accuracy)
XCTAssertEqual(solution[3], 0, accuracy: accuracy)
XCTAssertEqual(solution[4], 1.63934426229508, accuracy: accuracy)
XCTAssertEqual(solution[5], 100, accuracy: accuracy)
XCTAssertEqual(solution[6], 0, accuracy: accuracy)
XCTAssertEqual(solution[7], 0, accuracy: accuracy)
}
/** shows that accelerate is about 5-10 times slower then other methods
compare repeatTimes with PerformanceTest.repeatTimes
it's not surprising as it uses multiple iterations for approximate solution
*/
func testSolvePerformance() {
preparePerspective()
measure {
repeatTimes.times {
solve( self.A!, self.B! )
}
}
}
}