Scala:重载方法值与替代方案融合:

Scala: overloaded method value converged with alternatives:

我对 Scala 还是个新手(还在学习)。我有以下作业,但由于错误“overloaded method value converged with alternatives:

而遇到问题 运行

完整错误:

\KMeans.scala:101:8: overloaded method value converged with alternatives:
(eta: Double,oldMeans: scala.collection.parallel.ParSeq[kmeans.Point],newMeans: scala.collection.parallel.ParSeq[kmeans.Point])Boolean <and>
(eta: Double,oldMeans: scala.collection.Seq[kmeans.Point],newMeans: scala.collection.Seq[kmeans.Point])Boolean
cannot be applied to (Double)
if (!converged(eta)(means, newMeans))

你能帮忙吗?

完整的 class 是:

package kmeans

import scala.annotation.tailrec
import scala.collection.{Map, Seq, mutable}
import scala.collection.parallel.CollectionConverters._
import scala.collection.parallel.{ParMap, ParSeq}
import scala.util.Random
import org.scalameter._

class KMeans extends KMeansInterface {

  def generatePoints(k: Int, num: Int): Seq[Point] = {
    val randx = new Random(1)
    val randy = new Random(3)
    val randz = new Random(5)
    (0 until num)
      .map({ i =>
        val x = ((i + 1) % k) * 1.0 / k + randx.nextDouble() * 0.5
        val y = ((i + 5) % k) * 1.0 / k + randy.nextDouble() * 0.5
        val z = ((i + 7) % k) * 1.0 / k + randz.nextDouble() * 0.5
        new Point(x, y, z)
      }).to(mutable.ArrayBuffer)
  }

  def initializeMeans(k: Int, points: Seq[Point]): Seq[Point] = {
    val rand = new Random(7)
    (0 until k).map(_ => points(rand.nextInt(points.length))).to(mutable.ArrayBuffer)
  }

  def findClosest(p: Point, means: IterableOnce[Point]): Point = {
    val it = means.iterator
    assert(it.nonEmpty)
    var closest = it.next()
    var minDistance = p.squareDistance(closest)
    while (it.hasNext) {
      val point = it.next()
      val distance = p.squareDistance(point)
      if (distance < minDistance) {
        minDistance = distance
        closest = point
      }
    }
    closest
  }

  def classify(points: Seq[Point], means: Seq[Point]): Map[Point, Seq[Point]] = {
    means.map{(_, Seq())}.toMap ++ points.groupBy(findClosest(_, means))
  }

  def classify(points: ParSeq[Point], means: ParSeq[Point]): ParMap[Point, ParSeq[Point]] = {
    means.map{(_, ParSeq())}.toMap ++ points.groupBy(findClosest(_, means))
  }

  def findAverage(oldMean: Point, points: Seq[Point]): Point = if (points.isEmpty) oldMean else {
    var x = 0.0
    var y = 0.0
    var z = 0.0
    points.foreach { p =>
      x += p.x
      y += p.y
      z += p.z
    }
    new Point(x / points.length, y / points.length, z / points.length)
  }

  def findAverage(oldMean: Point, points: ParSeq[Point]): Point = if (points.isEmpty) oldMean else {
    var x = 0.0
    var y = 0.0
    var z = 0.0
    points.seq.foreach { p =>
      x += p.x
      y += p.y
      z += p.z
    }
    new Point(x / points.length, y / points.length, z / points.length)
  }

  def update(classified: Map[Point, Seq[Point]], oldMeans: Seq[Point]): Seq[Point] = {
    oldMeans.par.map(oldMean => findAverage(oldMean, classified(oldMean)))
  }

  def update(classified: ParMap[Point, ParSeq[Point]], oldMeans: ParSeq[Point]): ParSeq[Point] = {
    oldMeans.par.map(oldMean => findAverage(oldMean, classified(oldMean)))
  }

def converged(eta: Double, oldMeans: Seq[Point], newMeans: Seq[Point]): Boolean = {
  (oldMeans zip newMeans)
    .forall(entry => entry._1.squareDistance(entry._2) <= eta)
}

def converged(eta: Double, oldMeans: ParSeq[Point], newMeans: ParSeq[Point]): Boolean = {
  (oldMeans zip newMeans)
    .forall(entry => entry._1.squareDistance(entry._2) <= eta)
}

@tailrec
final def kMeans(points: Seq[Point], means: Seq[Point], eta: Double): Seq[Point] = {
  val meansClassification = classify(points, means)
  val newMeans = update(meansClassification, means)

  if (!converged(eta)(means, newMeans))
    kMeans(points, newMeans, eta)
  else
    newMeans
}

@tailrec
final def kMeans(points: ParSeq[Point], means: ParSeq[Point], eta: Double): ParSeq[Point] = {
  val meansClassification = classify(points, means)
  val newMeans = update(meansClassification, means)

  if (!converged(eta)(means, newMeans))
    kMeans(points, newMeans, eta)
  else
    newMeans
}
}

/** Describes one point in three-dimensional space.
*
*  Note: deliberately uses reference equality.
*/
class Point(val x: Double, val y: Double, val z: Double) {
private def square(v: Double): Double = v * v
def squareDistance(that: Point): Double = {
  square(that.x - x)  + square(that.y - y) + square(that.z - z)
}
private def round(v: Double): Double = (v * 100).toInt / 100.0
override def toString = s"(${round(x)}, ${round(y)}, ${round(z)})"
}


object KMeansRunner {

val standardConfig = config(
  Key.exec.minWarmupRuns -> 20,
  Key.exec.maxWarmupRuns -> 40,
  Key.exec.benchRuns -> 25,
  Key.verbose -> true
) withWarmer(new Warmer.Default)

def main(args: Array[String]): Unit = {
  val kMeans = new KMeans()

  val numPoints = 500000
  val eta = 0.01
  val k = 32
  val points = kMeans.generatePoints(k, numPoints)
  val means = kMeans.initializeMeans(k, points)

  val seqtime = standardConfig measure {
    kMeans.kMeans(points, means, eta)
  }

  val parPoints = points.par
  val parMeans = means.par

  val partime = standardConfig measure {
    kMeans.kMeans(parPoints, parMeans, eta)
  }

  // Additional `println` to avoid bad interaction with JLine output
  println()
  println()
  println()
  println()
  println(s"sequential time: $seqtime")
  println(s"parallel time: $partime")
  println(s"speedup: ${seqtime.value / partime.value}")
  println()
  println()
  println()
}

// Workaround Dotty's handling of the existential type KeyValue
implicit def keyValueCoerce[T](kv: (Key[T], T)): KeyValue = {
  kv.asInstanceOf[KeyValue]
}
}

界面:

package kmeans

import scala.collection.{Map, Seq}
import scala.collection.parallel.{ParMap, ParSeq}

/**
 * The interface used by the grading infrastructure. Do not change signatures
 * or your submission will fail with a NoSuchMethodError.
 */
trait KMeansInterface {
  def classify(points: Seq[Point], means: Seq[Point]): Map[Point, Seq[Point]]
  def classify(points: ParSeq[Point], means: ParSeq[Point]): ParMap[Point, ParSeq[Point]]
  def update(classified: Map[Point, Seq[Point]], oldMeans: Seq[Point]): Seq[Point]
  def update(classified: ParMap[Point, ParSeq[Point]], oldMeans: ParSeq[Point]): ParSeq[Point]
  def converged(eta: Double, oldMeans: Seq[Point], newMeans: Seq[Point]): Boolean
  def converged(eta: Double, oldMeans: ParSeq[Point], newMeans: ParSeq[Point]): Boolean
  def kMeans(points: Seq[Point], means: Seq[Point], eta: Double): Seq[Point]
  def kMeans(points: ParSeq[Point], means: ParSeq[Point], eta: Double): ParSeq[Point]
}

该方法应该被称为 converged(eta, means, newMeans) 而不是 converged(eta)(means, newMeans)。如果你看,def converged 都是用一个参数列表(有 3 个参数)定义的,而不是两个。

此错误中最相关的部分不是您引用的部分,而是

cannot be applied to (Double)