将此类扩展为具有将矩阵提升为n次幂的幂方法的最佳方法是什么。
我想要做的是使用矩阵计算大的斐波纳契数。
这些是我到目前为止对原始代码所做的更改。我收到了StackOverflow异常。
File Row.scala
/*
* Copyright (c) 2010 Eamonn O'Brien-Strain, eob@well.com
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which is available at http://www.eclipse.org/legal/epl-v10.html
*/
package org.eamonn.published_matrix
import Row._
/** Methods that are added to List[BigInt] by an implicit conversion */
case class RichRow(v:Row){
/** dot product */
def *(that:RichRow) = dotProd( this.v, that.v )
/** vector addition */
def add(that:RichRow) = vPlusV( this.v, that.v )
/** convert to column vector */
def T = v.map{ List(_) }
/** As row matrix */
def asMatrix = List( v )
}
object Row{
/** A convenient alias */
type Row = List[BigInt]
def dotProd(v1:Row,v2:Row) =
v1.zip( v2 ).map{ t:(BigInt,BigInt) => t._1 * t._2 }.reduceLeft(_ + _)
def vPlusV(v1:Row,v2:Row) =
v1.zip( v2 ).map{ t:(BigInt,BigInt) => t._1 + t._2 }
/** effectively add RichRow methods to List[Double] */
implicit def pimp(v:Row) = new RichRow(v)
}
File Matrix.scala
/*
* Copyright (c) 2010 Eamonn O'Brien-Strain, eob@well.com
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which is available at http://www.eclipse.org/legal/epl-v10.html
*/
package org.eamonn.published_matrix
import Matrix._
import Row._
import Seq.Projection
/** Methods that are added to List[List[BigInt]] by an implicit conversion */
case class RichMatrix(m:Matrix){
def T = transpose(m)
def *(that:RichMatrix) = mXm( this.m, that.m )
def power (exp:Int) = recPower(this.m, exp)
def recPower(m:Matrix, exp:BigInt) : Matrix =
if (exp == 1) m else mXm(m, recPower(m, exp - 1))
def apply(i:Int,j:Int) = m(i)(j)
def rowCount = m.length
def colCount = m.head.length
def toStr = "\n" + m.map { _.map{"\t" + _}.reduceLeft(_ + _) + "\n" }.reduceLeft(_ + _)
}
object Matrix{
/** A convenient alias */
type Matrix = List[Row]
def apply( rowCount:Int, colCount:Int )( f:(Int,Int) => BigInt ) = (
for(i <- 1 to rowCount) yield
( for( j <- 1 to colCount) yield f(i,j) ).toList
).toList
def transpose(m:Matrix):Matrix =
if(m.head.isEmpty) Nil else m.map(_.head) :: transpose(m.map(_.tail))
def mXv(m:Matrix, v:Row) = m.map{ dotProd(_,v) } reduceLeft ( _ + _ )
def mXm( m1:Matrix, m2:Matrix ) =
for( m1row <- m1 ) yield
for( m2col <- transpose(m2) ) yield
dotProd( m1row, m2col )
def rowCount(m:Matrix) = m.length
def colCount(m:Matrix) = m.head.length
/** effectively add RichMatrix methods to List[List[BigInt]] */
implicit def pimp1(m:Matrix) = new RichMatrix(m)
implicit def pimp2(m:List[Projection[BigInt]]) = new RichMatrix(m.map{_.toList})
implicit def pimp1(m:Projection[List[BigInt]]) = new RichMatrix(m.toList)
implicit def pimp2(m:Projection[Projection[BigInt]]) = new RichMatrix(m.map{_.toList}.toList)
// Suggested by Travis Brown - Not working
// implicit def toRichMatrixWithPower(m: Matrix) = new {
// val matrix = new RichMatrix(m)
// def power(n: Int) = {
// require(matrix.rowCount == matrix.colCount)
// Iterator.iterate(matrix)(_ * matrix).drop(n - 1).next
// }
// }
def main(args: Array[String]): Unit =
{
val m = List(List[BigInt](1, 1), List[BigInt](1, 0))
println((m power 9999)(0)(1)) //java.lang.StackOverflowError
}
}
答案 0 :(得分:4)
在这里扩展类似案例类RichMatrix
是一个坏主意,并且在最新版本的Scala中已弃用。但是,您可以遵循作者的模式并使用pimp-my-library方法:
import org.eamonn.published_matrix._
import org.eamonn.published_matrix.Matrix._
implicit def toRichMatrixWithPower(m: Matrix) = new {
val matrix = new RichMatrix(m)
def power(n: Int) = {
require(matrix.rowCount == matrix.colCount)
Iterator.iterate(matrix)(_ * matrix).drop(n - 1).next
}
}
现在List(List(2.0, 0.0), List(0.0, 2.0)).power(3)
例如应该提供以下内容:
RichMatrix(List(List(8.0, 0.0), List(0.0, 8.0)))
答案 1 :(得分:0)
这是最终的工作代码。谢谢@travis-brown
File Matrix.scala
/*
* Copyright (c) 2010 Eamonn O'Brien-Strain, eob@well.com
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which is available at http://www.eclipse.org/legal/epl-v10.html
*/
package org.eamonn.published_matrix
import Matrix._
import Row._
/** Methods that are added to List[List[Double]] by an implicit conversion */
case class RichMatrix(m:Matrix){
def T = transpose(m)
def *(that:RichMatrix) = mXm( this.m, that.m )
def apply(i:Int,j:Int) = m(i)(j)
def rowCount = m.length
def colCount = m.head.length
def toStr = "\n" + m.map { _.map{"\t" + _}.reduceLeft(_ + _) + "\n" }.reduceLeft(_ + _)
}
object Row{
/** A convenient alias */
type Row = List[BigInt]
def dotProd(v1:Row,v2:Row) = v1.zip( v2 ).map{ t:(BigInt,BigInt) => t._1 * t._2 }.reduceLeft(_ + _)
}
object Matrix{
/** A convenient alias */
type Matrix = List[Row]
def transpose(m:Matrix):Matrix =
if(m.head.isEmpty) Nil else m.map(_.head) :: transpose(m.map(_.tail))
def mXm( m1:Matrix, m2:Matrix ) =
for( m1row <- m1 ) yield
for( m2col <- transpose(m2) ) yield
dotProd( m1row, m2col )
def rowCount(m:Matrix) = m.length
def colCount(m:Matrix) = m.head.length
/** effectively add RichMatrix methods to List[List[Double]] */
implicit def pimp1(m:Matrix) = new RichMatrix(m)
implicit def matrixPower(m: Matrix) = new {
//val matrix = new RichMatrix(m)
def power(n: Int) = {
require(m.rowCount == m.colCount)
Iterator.iterate(m)(_ * m).drop(n - 1).next
}
}
def main(args: Array[String]): Unit =
{
val m = List(List[BigInt](1, 1), List[BigInt](1, 0))
println(m.power(9)(1)(0))
}
}
答案 2 :(得分:0)
以下是我对这个问题的观点:
def fibonacci(n: Int): Int = {
def loop(a: Int, b: Int, c: Int, d: Int, n: Int,
e: Int, f: Int, g: Int, h: Int): Int =
if (n == 0) f
else if (n % 2 != 0)
loop(a * a + b * c, a * b + b * d, c * a + d * c, c * b + d * d, n / 2,
e * a + g * b, f * a + h * b, e * c + g * d, f * c + h * d)
else
loop(a * a + b * c, a * b + b * d, c * a + d * c, c * b + d * d, n / 2,
e, f, g, h)
loop(1, 1, 1, 0, n + 1, 1, 0, 0, 1)
}
这是纯功能解决方案,没有可变数组和副作用,它们使用尾递归。在我的收藏集here中查看此类代码的更多示例。