I replaced the 1.0 in the upper off diagonal of the Cholesky lower decomposition with a zero and ran the MPSMatrixSolveCholesky. The solution is correct for a left hand side B matrix of:
1 0
0 0
The solution for X is:
2/3 0
-1/3 0
Guess what? If you just use the lower decomposition without the zero replacement ... or with the 1.0 you will get the same result!
In fact, you can put any number in the upper off diagonal and it will give you the correct result!
Apple just ignores the upper off diagonal. I should have thought of this before. (But if you were to use this 'Apple decomposition' in matrix multiplication I think you would need those zeros in the upper off diagonal.)
Still, haven't gotten the correct answer on my iMac ... only the MacBook Pro ... so far.
-----------------------------------------
// Metal_LA : Cholesky factorization and solver test
// Metal Linear Algebra solver via Cholesky factorization
// This code solves: A * X = B for a 2 x 2 test matrix
// where A is M x M, X is M x M, and B is M x M and M = 2
import MetalPerformanceShaders
let device = MTLCreateSystemDefaultDevice()!
let commandQueue = device.makeCommandQueue()
// memory layout and matrix descriptor
let M = 2
let row = M * MemoryLayout<Float>.stride
let matlength = M * row
let mdesc = MPSMatrixDescriptor(
dimensions: M, columns: M, rowBytes: row, dataType: MPSDataType.float32)
// assign arrays
let arrayA: [Float] = [ 2.0 , 1.0 , 1.0 , 2.0 ]
let buffA = device.makeBuffer(bytes: arrayA, length: matlength)
let matA = MPSMatrix(buffer: buffA!, descriptor: mdesc)
let arrayB: [Float] = [ 1.0 , 0.0 , 0.0 , 0.0 ]
let buffB = device.makeBuffer(bytes: arrayB, length: matlength)
let matB = MPSMatrix(buffer: buffB!, descriptor: mdesc)
let arrayX: [Float] = [ 0.0 , 0.0 , 0.0 , 0.0 ]
let buffX = device.makeBuffer(bytes: arrayX, length: matlength)
let matX = MPSMatrix(buffer: buffX!, descriptor: mdesc)
var arrayL: [Float] = [ 0.0 , 0.0 , 0.0 , 0.0 ]
var buffL = device.makeBuffer(bytes: arrayL, length: matlength)
var matL = MPSMatrix(buffer: buffL!, descriptor: mdesc)
// Create the device 'kernel' to perform decomposition.
let decomp = MPSMatrixDecompositionCholesky(device: device, lower: true, order: M )
// Create a command buffer in the queue.
let commandBuffer = commandQueue?.makeCommandBuffer()
// Encode the kernel to the command buffer.
decomp.encode(commandBuffer: commandBuffer!,
sourceMatrix: matA, resultMatrix: matL, status: buffX)
// Create the device 'kernel' to perform the Cholesky solution.
let solve = MPSMatrixSolveCholesky(device: device,
upper: false, order: M, numberOfRightHandSides: 1 )
// Encode the kernel to the command buffer.
solve.encode(commandBuffer: commandBuffer!,
sourceMatrix: matL, rightHandSideMatrix: matB, solutionMatrix: matX)
// Commit the buffer and wait for completion.
commandBuffer?.commit()
commandBuffer?.waitUntilCompleted()
// bind Metal matrices to pointers for printing
// all matrices are the same size
let count = matA.rows * matA.columns
let rawPointerA = matA.data.contents()
let typedPointerA = rawPointerA.bindMemory(to: Float.self, capacity: count)
let bufferA = UnsafeBufferPointer(start: typedPointerA, count: count)
print(" ")
print(" Solutions to: A * X = B ")
print(" ")
print(" A matrix")
print(" ",bufferA[0]," ",bufferA[1])
print(" ",bufferA[2]," ",bufferA[3])
print(" ")
let rawPointerB = matB.data.contents()
let typedPointerB = rawPointerB.bindMemory(to: Float.self, capacity: count)
let bufferB = UnsafeBufferPointer(start: typedPointerB, count: count)
print(" B matrix")
print(" ",bufferB[0])
print(" ",bufferB[2])
print(" ")
let rawPointerL = matL.data.contents()
let typedPointerL = rawPointerL.bindMemory(to: Float.self, capacity: count)
let bufferL = UnsafeBufferPointer(start: typedPointerL, count: count)
print(" Lower decomposition from MPSMatrixDecompositionCholesky ")
print(" ",bufferL[0]," ", bufferL[1])
print(" ",bufferL[2]," ", bufferL[3])
print(" ")
let rawPointerX = matX.data.contents()
let typedPointerX = rawPointerX.bindMemory(to: Float.self, capacity: count)
let bufferX = UnsafeBufferPointer(start: typedPointerX, count: count)
print(" Solutions from MPSMatrixSolveCholesky ")
print(" ",bufferX[0])
print(" ",bufferX[2])
print(" ")