[orx-math] Add matrix and sparse matrix implementations with Cholesky and QR decompositions
This commit is contained in:
65
orx-math/src/jvmDemo/kotlin/matrix/DemoLeastSquares01.kt
Normal file
65
orx-math/src/jvmDemo/kotlin/matrix/DemoLeastSquares01.kt
Normal file
@@ -0,0 +1,65 @@
|
||||
package matrix
|
||||
|
||||
import org.openrndr.application
|
||||
import org.openrndr.color.ColorRGBa
|
||||
import org.openrndr.extra.math.matrix.Matrix
|
||||
import org.openrndr.extra.math.matrix.invertMatrixCholesky
|
||||
import org.openrndr.extra.noise.uniform
|
||||
import org.openrndr.extra.noise.uniformRing
|
||||
import org.openrndr.math.Vector2
|
||||
import kotlin.math.cos
|
||||
import kotlin.random.Random
|
||||
|
||||
/**
|
||||
* Demonstrate least squares method to find a regression line through noisy points
|
||||
* Line drawn in red is the estimated line, in green is the ground-truth line
|
||||
*
|
||||
* Ax = b => x = A⁻¹b
|
||||
* because A is likely inconsistent, we look for an approximate x based on AᵀA, which is consistent.
|
||||
* x̂ = (AᵀA)⁻¹ Aᵀb
|
||||
*/
|
||||
fun main() {
|
||||
application {
|
||||
configure {
|
||||
width = 720
|
||||
height = 720
|
||||
}
|
||||
program {
|
||||
extend {
|
||||
val ls = drawer.bounds.horizontal(0.5).rotateBy(cos(seconds)*45.0)
|
||||
|
||||
val r = Random((seconds*10).toInt())
|
||||
|
||||
val pointCount = 100
|
||||
val A = Matrix(pointCount, 2)
|
||||
val b = Matrix(pointCount, 1)
|
||||
for (i in 0 until pointCount) {
|
||||
|
||||
val p = ls.position(Double.uniform(0.0, 1.0, r))
|
||||
val pr = p + Vector2.uniformRing(0.0, 130.0, r)
|
||||
|
||||
A[i, 0] = 1.0
|
||||
A[i, 1] = pr.x
|
||||
b[i, 0] = pr.y
|
||||
|
||||
drawer.circle(pr, 5.0)
|
||||
}
|
||||
val At = A.transposed()
|
||||
val AtA = At * A
|
||||
val Atb = At * b
|
||||
|
||||
val AtAI = invertMatrixCholesky(AtA)
|
||||
val x = AtAI * Atb
|
||||
|
||||
val p0 = Vector2(0.0, x[0, 0])
|
||||
val p1 = Vector2(720.0, x[0, 0] + x[1, 0] * 720.0)
|
||||
|
||||
drawer.stroke = ColorRGBa.RED
|
||||
drawer.lineSegment(p0, p1)
|
||||
|
||||
drawer.stroke = ColorRGBa.GREEN
|
||||
drawer.lineSegment(ls)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user