0

Many numerical problems are of the form:

initialize:  x_0 = ...
iterate:     x_i+1 = function(x_i) until convergence, e.g., 
             || x_i+1 - x_i || < epsilon

I'm wondering whether there is a nice way to write such an algorithm using idiomatic Scala. The nature of the problem calls for an Iterator or Stream. However, my current take on this looks really ugly:

val xFinal = Iterator.iterate(xInit) { x_i =>
  // update x_i+1
}.toList      // necessary to pattern match within takeWhile
 .sliding(2)  // necessary since takeWhile needs pair-wise comparison
 .takeWhile{ case x_i :: x_iPlus1 :: Nil => /* convergence condition */ }
 .toList      // since the outer container is still an Iterator
 .last        // to get the last element of the iteration
 .last        // to get x_iPlus1

This is not only ugly, the pattern matching in takeWhile also causes a warning. Obviously I do not have to pattern-match here, but I would love to keep a strong resemblance to the mathematical original.

Any ideas to make this look more beautiful?

bluenote10
  • 23,414
  • 14
  • 122
  • 178
  • Doesn't converting it to a List first mean the whole list gets constructed in memory when you are only really interested in the converged solution? – Lindon Sep 03 '16 at 14:31

2 Answers2

1

The following minimalist (silly) example may illustrate none the less a useful framework to adapt,

def function (i:Int): Int = i+1

def iter (x0: Int): Int = {
  val x1 = function(x0)
  if (x1 - x0 == 1) x1 else iter(x1)
}
elm
  • 20,117
  • 14
  • 67
  • 113
  • No doubt a perfectly valid solution. I was just looking for a more beautiful solution while using `Iterator` specifically. – bluenote10 Apr 09 '14 at 19:47
1

Here is my solution for the example of finding the square root using Newton's method, which reduces in this case to the Babylonian method:

import math.abs                                                                                                                                                                                                    

val tol=0.00001                                                                                                                                                                                                    
val desiredSqRoot=256                                                                                                                                                                                              
val xFinal = Iterator.iterate(1.0) { x => 0.5*(x+desiredSqRoot/x) }                                                                                                                                                

def converged(l: Seq[Double]): Boolean = l match{
  case x_old :: x_new :: Nil => if( abs(x_old-x_new)/x_old < tol ) true else false                                                                                                                                 
  case _ => true                                                                                                                                                                                                  
}                                                                                                                                                                                                                  

xFinal.sliding(2).dropWhile( x=> !converged(x) ).next.last 

which results as:

scala> xFinal.sliding(2).dropWhile( x=> !converged(x) ).next.last
res23: Double = 16.00000000000039

In this example we know the value it should converge to, yet I've written the convergence criterion without this knowledge, because in general we don't know this.

Lindon
  • 1,292
  • 1
  • 10
  • 21