I want to fit a circle to given 2D points in Scala.
Apache commons math has an example for this in java, which I am trying to translate to scala (without success, because my knowledge of Java is almost non existent).
I took the example code from "http://commons.apache.org/proper/commons-math/userguide/leastsquares.html", (see end of page) which I tried to translate into scala:
import org.apache.commons.math3.linear._
import org.apache.commons.math3.fitting._
import org.apache.commons.math3.fitting.leastsquares._
import org.apache.commons.math3.fitting.leastsquares.LeastSquaresOptimizer._
import org.apache.commons.math3._
import org.apache.commons.math3.geometry.euclidean.twod.Vector2D
import org.apache.commons.math3.util.Pair
import org.apache.commons.math3.fitting.leastsquares.LeastSquaresOptimizer.Optimum
def circleFitting: Unit = {
val radius: Double = 70.0
val observedPoints = Array(new Vector2D(30.0D, 68.0D), new Vector2D(50.0D, -6.0D), new Vector2D(110.0D, -20.0D), new Vector2D(35.0D, 15.0D), new Vector2D(45.0D, 97.0D))
// the model function components are the distances to current estimated center,
// they should be as close as possible to the specified radius
val distancesToCurrentCenter = new MultivariateJacobianFunction() {
//def value(point: RealVector): (RealVector, RealMatrix) = {
def value(point: RealVector): Pair[RealVector, RealMatrix] = {
val center = new Vector2D(point.getEntry(0), point.getEntry(1))
val value: RealVector = new ArrayRealVector(observedPoints.length)
val jacobian: RealMatrix = new Array2DRowRealMatrix(observedPoints.length, 2)
for (i <- 0 to observedPoints.length) {
var o = observedPoints(i)
var modelI: Double = Vector2D.distance(o, center)
value.setEntry(i, modelI)
// derivative with respect to p0 = x center
jacobian.setEntry(i, 0, (center.getX() - o.getX()) / modelI)
// derivative with respect to p1 = y center
jacobian.setEntry(i, 1, (center.getX() - o.getX()) / modelI)
}
new Pair(value, jacobian)
}
}
// the target is to have all points at the specified radius from the center
val prescribedDistances = Array.fill[Double](observedPoints.length)(radius)
// least squares problem to solve : modeled radius should be close to target radius
val problem:LeastSquaresProblem = new LeastSquaresBuilder().start(Array(100.0D, 50.0D)).model(distancesToCurrentCenter).target(prescribedDistances).maxEvaluations(1000).maxIterations(1000).build()
val optimum:Optimum = new LevenbergMarquardtOptimizer().optimize(problem) //LeastSquaresOptimizer.Optimum
val fittedCenter: Vector2D = new Vector2D(optimum.getPoint().getEntry(0), optimum.getPoint().getEntry(1))
println("circle fitting wurde aufgerufen!")
println("CIRCLEFITTING: fitted center: " + fittedCenter.getX() + " " + fittedCenter.getY())
println("CIRCLEFITTING: RMS: " + optimum.getRMS())
println("CIRCLEFITTING: evaluations: " + optimum.getEvaluations())
println("CIRCLEFITTING: iterations: " + optimum.getIterations())
}
This gives no compile errors, but crashes with:
Exception in thread "main" java.lang.NullPointerException
at org.apache.commons.math3.linear.EigenDecomposition.<init>(EigenDecomposition.java:119)
at org.apache.commons.math3.fitting.leastsquares.LeastSquaresFactory.squareRoot(LeastSquaresFactory.java:245)
at org.apache.commons.math3.fitting.leastsquares.LeastSquaresFactory.weightMatrix(LeastSquaresFactory.java:155)
at org.apache.commons.math3.fitting.leastsquares.LeastSquaresFactory.create(LeastSquaresFactory.java:95)
at org.apache.commons.math3.fitting.leastsquares.LeastSquaresBuilder.build(LeastSquaresBuilder.java:59)
at twoDhotScan.FittingFunctions$.circleFitting(FittingFunctions.scala:49)
at twoDhotScan.Main$.delayedEndpoint$twoDhotScan$Main$1(hotScan.scala:14)
at twoDhotScan.Main$delayedInit$body.apply(hotScan.scala:11)
at scala.Function0.apply$mcV$sp(Function0.scala:34)
at scala.Function0.apply$mcV$sp$(Function0.scala:34)
at scala.runtime.AbstractFunction0.apply$mcV$sp(AbstractFunction0.scala:12)
at scala.App.$anonfun$main$1$adapted(App.scala:76)
at scala.collection.immutable.List.foreach(List.scala:389)
at scala.App.main(App.scala:76)
at scala.App.main$(App.scala:74)
at twoDhotScan.Main$.main(hotScan.scala:11)
at twoDhotScan.Main.main(hotScan.scala)
I guess the problem is somewhere in the definition of the function distancesToCurrentCenter. I don't even know if this MultivariateJacobianFunction is supposed to be a real function or an object or what ever.
After some long fiddeling with the code, I got it running
The NullPointerException was gone after I updated apache-commons-math3 from version 3.3 to version 3.6.1 in my build.sbt file. Don't know if I forgot a paramater of if it was a bug. There were also 2 bugs in the example on the apache-commons-math website: They had two times a .getX operator where should have been an .getY.
So here is a running example for a circle fit with known radius:
import org.apache.commons.math3.analysis.{ MultivariateVectorFunction, MultivariateMatrixFunction }
import org.apache.commons.math3.fitting.leastsquares.LeastSquaresOptimizer.Optimum
import org.apache.commons.math3.fitting.leastsquares.{ MultivariateJacobianFunction, LeastSquaresProblem, LeastSquaresBuilder, LevenbergMarquardtOptimizer }
import org.apache.commons.math3.geometry.euclidean.twod.Vector2D
import org.apache.commons.math3.linear.{ Array2DRowRealMatrix, RealMatrix, RealVector, ArrayRealVector }
object Main extends App {
val radius: Double = 20.0
val pointsList: List[(Double, Double)] = List(
(18.36921795, 10.71416674),
(0.21196357, -22.46528791),
(-4.153845171, -14.75588526),
(3.784114125, -25.55910336),
(31.32998899, 2.546924253),
(34.61542186, -12.90323269),
(19.30193011, -28.53185596),
(16.05620863, 10.97209111),
(31.67011956, -20.05020878),
(19.91175561, -28.38748712))
/*******************************************************************************
***** Random values on a circle with centerX=15, centerY=-9 and radius 20 *****
*******************************************************************************/
val observedPoints: Array[Vector2D] = (pointsList map { case (x, y) => new Vector2D(x, y) }).toArray
val vectorFunktion: MultivariateVectorFunction = new MultivariateVectorFunction {
def value(variables: Array[Double]): Array[Double] = {
val center = new Vector2D(variables(0), variables(1))
observedPoints map { p: Vector2D => Vector2D.distance(p, center) }
}
}
val matrixFunction = new MultivariateMatrixFunction {
def value(variables: Array[Double]): Array[Array[Double]] = {
val center = new Vector2D(variables(0), variables(1))
(observedPoints map { p: Vector2D => Array((center.getX - p.getX) / Vector2D.distance(p, center), (center.getY - p.getY) / Vector2D.distance(p, center)) })
}
}
// the target is to have all points at the specified radius from the center
val prescribedDistances = Array.fill[Double](observedPoints.length)(radius)
// least squares problem to solve : modeled radius should be close to target radius
val problem = new LeastSquaresBuilder().start(Array(100.0D, 50.0D)).model(vectorFunktion, matrixFunction).target(prescribedDistances).maxEvaluations(25).maxIterations(25).build
val optimum: Optimum = new LevenbergMarquardtOptimizer().optimize(problem)
val fittedCenter: Vector2D = new Vector2D(optimum.getPoint.getEntry(0), optimum.getPoint.getEntry(1))
println("Ergebnisse des LeastSquareBuilder:")
println("CIRCLEFITTING: fitted center: " + fittedCenter.getX + " " + fittedCenter.getY)
println("CIRCLEFITTING: RMS: " + optimum.getRMS)
println("CIRCLEFITTING: evaluations: " + optimum.getEvaluations)
println("CIRCLEFITTING: iterations: " + optimum.getIterations + "\n")
}
Tested on Scala version 2.12.6, compiled with sbt version 1.2.8
Does anabody know how to do this without a fixed radius?
After some reasearch on circle fitting I've found a wonderful algorith in the paper: "Error alalysis for circle fitting algorithms" by H. Al-Sharadqah and N. Chernov (available here: http://people.cas.uab.edu/~mosya/cl/ )
I implemented it in scala:
import org.apache.commons.math3.linear.{ Array2DRowRealMatrix, RealMatrix, RealVector, LUDecomposition, EigenDecomposition }
object circleFitFunction {
def circleFit(dataXY: List[(Double, Double)]) = {
def square(x: Double): Double = x * x
def multiply(pair: (Double, Double)): Double = pair._1 * pair._2
val n: Int = dataXY.length
val (xi, yi) = dataXY.unzip
//val S: Double = math.sqrt(((xi map square) ++ yi map square).sum / n)
val zi: List[Double] = dataXY map { case (x, y) => x * x + y * y }
val x: Double = xi.sum / n
val y: Double = yi.sum / n
val z: Double = ((xi map square) ++ (yi map square)).sum / n
val zz: Double = (zi map square).sum / n
val xx: Double = (xi map square).sum / n
val yy: Double = (yi map square).sum / n
val xy: Double = ((xi zip yi) map multiply).sum / n
val zx: Double = ((zi zip xi) map multiply).sum / n
val zy: Double = ((zi zip yi) map multiply).sum / n
val N: RealMatrix = new Array2DRowRealMatrix(Array(
Array(8 * z, 4 * x, 4 * y, 2),
Array(4 * x, 1, 0, 0),
Array(4 * y, 0, 1, 0),
Array(2.0D, 0, 0, 0)))
val M: RealMatrix = new Array2DRowRealMatrix(Array(
Array(zz, zx, zy, z),
Array(zx, xx, xy, x),
Array(zy, xy, yy, y),
Array(z, x, y, 1.0D)))
val Ninverse = new LUDecomposition(N).getSolver().getInverse()
val eigenValueProblem = new EigenDecomposition(Ninverse.multiply(M))
// Get all eigenvalues
// As we need only the smallest positive eigenvalue, all negative eigenvalues are replaced by Double.MaxValue
val eigenvalues: Array[Double] = eigenValueProblem.getRealEigenvalues() map (lambda => if (lambda < 0) Double.MaxValue else lambda)
// Now get the index of the smallest positive eigenvalue, to get the associated eigenvector
val i: Int = eigenvalues.zipWithIndex.min._2
val eigenvector: RealVector = eigenValueProblem.getEigenvector(3)
val A = eigenvector.getEntry(0)
val B = eigenvector.getEntry(1)
val C = eigenvector.getEntry(2)
val D = eigenvector.getEntry(3)
val centerX: Double = -B / (2 * A)
val centerY: Double = -C / (2 * A)
val Radius: Double = math.sqrt((B * B + C * C - 4 * A * D) / (4 * A * A))
val RMS: Double = (dataXY map { case (x, y) => (Radius - math.sqrt((x - centerX) * (x - centerX) + (y - centerY) * (y - centerY))) } map square).sum / n
(centerX, centerY, Radius, RMS)
}
}
I kept all the Names form the paper (see Chaper 4 and 8 and look for the Hyperfit-Algorithm) and I tried to limit the Matrix operations.
It's still not what I need, cause this sort of algorithm (algebraic fit) has known issues with fitting partially circles (arcs) and maybe big circles.
With my data, I had once the situation that it spit out completly wrong results, and I found out that I had an Eigenvalue of -0.1...
The Eigenvector of this Value produced the right result, but it was sorted out because of the negative Eigenvalue. So this one is not always stable (as so many other circle fitting algorithms)
But what a nice Algorithm!!!
Looks a bit like dark magic to me.
If someone needs not to much precision and a lot of speed (and has data from a full circle not to big) this would be my choice.
Next thing I will try is to implement a Levenberg Marquardt Algorithm form the same page I mentioned above.
Can anybody help me understand what's wrong with the code below?
case class Point(x: Double, y: Double)
def centroid(points: IndexedSeq[Point]): Point = {
val x = points.reduce(_.x + _.x)
val y = points.reduce(_.y + _.y)
val len = points.length
Point(x/len, y/len)
}
I get the error when I run it:
Error:(10, 30) type mismatch;
found : Double
required: A$A145.this.Point
val x = points.reduce(_.x + _.x)
^
reduce, in this case, takes a function of type (Point, Point) => Point and returns a Point.
One way to calculate the centroid:
case class Point(x: Double, y: Double)
def centroid(points: IndexedSeq[Point]): Point = {
val x = points.map(_.x).sum
val y = points.map(_.y).sum
val len = points.length
Point(x/len, y/len)
}
If you want to use reduce you need to reduce both x and y in a single pass like this
def centroid(points: IndexedSeq[Point]): Point = {
val p = points.reduce( (s, p) => Point(s.x + p.x, s.y + p.y) )
val len = points.length
Point(p.x/len, p.y/len)
}
If you want to compute x and y independently then use foldLeft rather than reduce like this
def centroid(points: IndexedSeq[Point]): Point = {
val x = points.foldLeft(0.0)(_ + _.x)
val y = points.foldLeft(0.0)(_ + _.y)
val len = points.length
Point(x/len, y/len)
}
This is perhaps clearer but does process the points twice so it may be marginally less efficient.
I am trying to convert this recursive function into a tail recursive function
def sumOfFractions(n: Int): Double = {
require(n > 0, "Parameter n has to be greater than 0");
if (n==1)
1.0
else
1.0 / n + sumOfFractions(n - 1)
}
I thought that this solution would work but when it runs it just returns 1.0
def sumOfFractions(n:Int):Double = {
def inner(acc:Int, n:Int): Double={
if(n <= 1)1.0
else
{
inner(acc+(1/n),n-1)
}
}
inner(0,n)
}
I think this is because the accumulator is not being updated correctly but I don't understand why. The code is in Scala but an example in any language would be helpful.
You need the base case (n <= 1) to return the accumulator, not 1.0. You'll also run into problems because the accumulator is an Int instead of a Double, which means that + (1 / n) is just adding 0 (the result of dividing 1: Int by any n: Int greater than one).
You can fix this by changing acc's type and making the numerator of the reciprocal a literal double:
def sumOfFractions(n: Int):Double = {
def inner(acc: Double, n: Int): Double =
if (n <= 1) acc else inner(acc + (1.0 / n), n - 1)
inner(0, n)
}
This should work.
Correct your code
1) Return acc (accumulator) when n <= 1
2) Your acc should be Double type
3) Division should be floating point division
def sumOfFractions(n: Int): Double = {
def inner(acc: Double, n:Int): Double = if(n <= 1) acc
else inner(acc + (1.0 / n), n - 1)
inner(0,n)
}
Using foldLeft
def sumOfFractions(n: Int): Double =
(1 to n).foldLeft(0.0)((r, c) => r + (1.0 / c))
I need a function that will translate and scale a complex number, i.e if z is complex, the fuction should return ( z - translate ) * scale
The function is to be parametrized by the dimensions of the screen and the scaling factor, here is what I have:
def affTransform(width: Int, height: Int, scaleFactor: Double)(z: Complex): Complex = {
val scale: Double = 4.0 / width
val translate = Complex(width / 2, height / 2)
(z - translate) * scale
}
With this in place, the following works as expected:
val transform: Complex => Complex = affTransform(W, H, 4)
...
val zz: Complex = transform(z)
The problem is that the calculation:
val scale: Double = 4.0 / width
val translate = Complex(width / 2, height / 2)
is performed every time transform is applied which is conceptually redundant. This is also the case when affTransform is not curried and transform is defined as partially applied.
Is there a way to define affTransform and\or transform so that scale and translate are calculated only once?
Simply take away the last of the argument lists and return a function instead:
case class Complex(re: Double, im: Double) {
def - (that: Complex) = Complex(this.re - that.re, this.im - that.im)
def * (scalar: Double) = Complex(re * scalar, im * scalar)
}
def aff(width: Int, height: Int, scaleFactor: Double): Complex => Complex = {
println("Heavy calculation here...")
val scale: Double = 4.0 / width
val translate = Complex(width / 2, height / 2)
z: Complex => (z - translate) * scale
}
val transform: Complex => Complex = aff(640, 480, 4)
transform(Complex(12, 34))
I'm currently attempting to learn functional programming (and Scala) together. I'm porting some code from a FORTRAN routine for calculating a particular modified normalisation of the associated Legendre polynomials. My direct imperative translation of the original code is modpLgndr1 (which I have checked against the original algorithm). My initial attempt at writing the code in a functional form is in modpLgdnr2.
import math.pow, abs, sqrt, Pi
def xfact(m: Int): Double = {
if (m <= 1) 1.0
else {
if (m % 2 == 1) m.toDouble / sqrt(m.toDouble) * xfact(m - 1)
else 1.0 / sqrt(m.toDouble) * xfact(m - 1)
}
}
//this is a very un-scala function....
def modpLgndr1(l: Int, m: Int, x: Double): Double = {
assert(0 <= m && m <= l && abs(x) <= 1.0)
val dl = l.toDouble
val dm = m.toDouble
val norm = sqrt(2.0 * dl + 1.0) / sqrt(4.0 * Pi)
var pmm = norm
if (m != 0) pmm = (pow(-1, m)).toDouble * pmm * xfact(2 * m) * pow((1.0-x * x), (dm / 2.0))
if (l == m) pmm
else {
var pmmp1 = x * pmm * sqrt(2.0 * m + 1.0)
if (l == m + 1) pmmp1
else {
var pll = 0.0
var dll = 0.0
for (ll <- m + 2 to l) {
dll = ll.toDouble
pll = (x * (2.0 * dll - 1.0) * pmmp1 - sqrt(pow((dll - 1.0), 2.0) - dm * dm) * pmm) / sqrt(pow(dll, 2.0) - pow(dm, 2.0))
pmm = pmmp1
pmmp1 = pll
}
pll
}
}
}
def modpLgndr2(l: Int, m: Int, x: Double): Double = {
assert(0 <= m && m <= l && abs(x) <= 1.0)
val dl = l.toDouble
val dm = m.toDouble
val norm = sqrt(2.0 * dl + 1.0) / sqrt(4.0 * Pi)
val pmm = if (m == 0) norm else (pow(-1, m)).toDouble * norm * xfact(2 * m) * pow((1.0-x * x), (dm / 2.0))
if (l == m) pmm
else {
val pmmp1 = x * pmm * sqrt(2.0 * m + 1.0)
if (l == m + 1) pmmp1
else {
def mplacc(ll: Int, acc1: Double, acc2: Double): Double = {
val dll = ll.toDouble
val pll = (x * (2.0 * dll - 1.0) * acc2 - sqrt(pow((dll - 1.0), 2.0) - dm * dm) * acc1) / sqrt(pow(dll, 2.0) - pow(dm, 2.0))
if (ll == m + 2) pll
else mplacc(ll - 1, acc2, pll)
}
mplacc(l, pmm, pmmp1)
}
}
}
If I call the two functions I get output like this:
scala> for (i <- 0 to 10) println(modpLgndr1(10,i,0.2))
0.16685408398957746
-0.2769345073769805
-0.1575129272628402
0.2948210515201088
0.12578847877176355
-0.3292975894931367
-0.058267280378036426
0.37448134558730417
-0.08024600262585084
-0.40389602261165075
0.4424459249420354
scala> for (i <- 0 to 10) println(modpLgndr2(10,i,0.2))
0.16685408398957752
-0.2772969351441124
-0.1578618478786792
0.29654926805696474
0.1349402872678466
-0.33707342609134694
-0.06901634276825179
0.38912154672892657
-0.08024600262585084
-0.40389602261165075
0.4424459249420354
Essentially, for m = 0, l-2, l-1, l the code agrees; otherwise there is a significant discrepancy. That seems to tell me that the problem is in calling the mplacc function. To me, mplacc just looks like a recursive form of the for loop in modpLgndr1. Why am I wrong?