加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

在Haskell中写这个Scala矩阵乘法

发布时间:2020-12-16 09:24:19 所属栏目:安全 来源:网络整理
导读:Possible Duplicate: 07000 你能实现一个Matrix类和一个可以在两个矩阵上运行的*运算符吗?: scala val x = Matrix(3,1,2,3,4,5,6) x: Matrix = [1.0,2.0,3.0] [4.0,5.0,6.0] scala x*x.transpose res0: Matrix = [14.0,32.0] [32.0,77.0] 只是让人们不说这

Possible Duplicate:
07000

你能实现一个Matrix类和一个可以在两个矩阵上运行的*运算符吗?:

scala> val x = Matrix(3,1,2,3,4,5,6)  
x: Matrix =   
[1.0,2.0,3.0]  
[4.0,5.0,6.0]  

scala> x*x.transpose  
res0: Matrix =   
[14.0,32.0]  
[32.0,77.0]

只是让人们不说这很难,这是Scala的实现(由Jonathan Merritt提供):

class Matrix(els: List[List[Double]]) {  

    /** elements of the matrix,stored as a list of  
      its rows */  
    val elements: List[List[Double]] = els  
    def nRows: Int = elements.length  
    def nCols: Int = if (elements.isEmpty) 0   
                     else elements.head.length  

    /** all rows of the matrix must have the same  
        number of columns */  
    require(elements.forall(_.length == nCols))  

    /* Add to each elem of matrix */
    private def addRows(a: List[Double],b: List[Double]):   
      List[Double] =   
        List.map2(a,b)(_+_)  

    private def subRows(a: List[Double],b: List[Double]):List[Double] =  
        List.map2(a,b)(_-_)  

    def +(other: Matrix): Matrix = {  
      require((other.nRows == nRows) &&   
              (other.nCols == nCols))  
      new Matrix(  
        List.map2(elements,other.elements)  
          (addRows(_,_))
      )  
    }  

    def -(other: Matrix): Matrix = {  
      require((other.nRows == nRows) &&   
              (other.nCols == nCols))  
      new Matrix(  
        List.map2(elements,other.elements)  
          (subRows(_,_))  
      )  
    }  

    def transpose(): Matrix = new Matrix(List.transpose(elements))    

    private def dotVectors(a: List[Double],b: List[Double]): Double = {  
      val multipliedElements =   
        List.map2(a,b)(_*_)  
      (0.0 /: multipliedElements)(_+_)  
    }  

    def *(other: Matrix): Matrix = {  
      require(nCols == other.nRows)  
      val t = other.transpose()  
      new Matrix(  
        for (row <- elements) yield {  
          for (otherCol <- t.elements)  
            yield dotVectors(row,otherCol)  
        }  
      )  

    override def toString(): String = {  
        val rowStrings =   
        for (row <- elements)   
          yield row.mkString("[",","]")  
        rowStrings.mkString("","n","n")  
    }  
}  

/* Matrix constructor from a bunch of numbers */
object Matrix {  
  def apply(nCols: Int,els: Double*):Matrix = {  
    def splitRowsWorker(  
      inList: List[Double],working: List[List[Double]]):  
    List[List[Double]] =  
      if (inList.isEmpty)  
        working  
      else {  
        val (a,b) = inList.splitAt(nCols)  
        splitRowsWorker(b,working + a)  
      }  
    def splitRows(inList: List[Double]) =  
      splitRowsWorker(inList,List[List[Double]]())  
    val rows: List[List[Double]] =   
      splitRows(els.toList)  
    new Matrix(rows)  
  }  
}

编辑我明白,严格来说答案是否定的:重载*不可能没有定义a和其他或特殊技巧的副作用. numeric-prelude package最佳描述:

In some cases,the hierarchy is not finely-grained enough: Operations
that are often defined independently are lumped together. For
instance,in a financial application one might want a type “Dollar”,
or in a graphics application one might want a type “Vector”. It is
reasonable to add two Vectors or Dollars,but not,in general,
reasonable to multiply them. But the programmer is currently forced to
define a method for ‘(*)’ when she defines a method for ‘(+)’.

解决方法

使用智能构造器和存储尺寸将非常安全.当然,对于操作signum和fromIntegral没有自然的实现(或者对角矩阵可能适用于后者).

module Matrix (Matrix(),matrix,matrixTranspose) where

import Data.List (transpose)

data Matrix a = Matrix {matrixN :: Int,matrixM :: Int,matrixElems :: [[a]]}
                deriving (Show,Eq)

matrix :: Int -> Int -> [[a]] -> Matrix a
matrix n m vals
  | length vals /= m            = error "Wrong number of rows"
  | any (/=n) $map length vals = error "Column length mismatch"
  | otherwise = Matrix n m vals

matrixTranspose (Matrix m n vals) = matrix n m (transpose vals)

instance Num a => Num (Matrix a) where

  (+) (Matrix m n vals) (Matrix m' n' vals')
    | m/=m' = error "Row number mismatch"
    | n/=n' = error "Column number mismatch"
    | otherwise = Matrix m n (zipWith (zipWith (+)) vals vals')

  abs (Matrix m n vals) = Matrix m n (map (map abs) vals)

  negate (Matrix m n vals) = Matrix m n (map (map negate) vals)

  (*) (Matrix m n vals) (Matrix n' p vals')
    | n/=n' = error "Matrix dimension mismatch in multiplication"
    | otherwise = let tvals' = transpose vals'
                      dot x y = sum $zipWith (*) x y
                      result = map (col -> map (dot col) tvals') vals
                  in Matrix m p result

在ghci中测试它:

*Matrix> let a = matrix 3 2 [[1,2],[-1,1]]
*Matrix> let b = matrix 2 3 [[3,1],[2,[1,0]]
*Matrix> a*b
Matrix {matrixN = 3,matrixM = 3,matrixElems = [[5,[4,2]]}

由于我的Num实例是通用的,它甚至适用于开箱即用的复杂矩阵:

Prelude Data.Complex Matrix> let c = matrix 2 2 [[0:+1,1:+0],[5:+2,4:+3]]
Prelude Data.Complex Matrix> let a = matrix 2 2 [[0:+1,4:+3]]
Prelude Data.Complex Matrix> let b = matrix 2 3 [[3:+0,0]]
Prelude Data.Complex Matrix> a
Matrix {matrixN = 2,matrixM = 2,matrixElems = [[0.0 :+ 1.0,1.0 :+ 0.0],[5.0 :+ 2.0,4.0 :+ 3.0]]}
Prelude Data.Complex Matrix> b
Matrix {matrixN = 2,matrixElems = [[3.0 :+ 0.0,[2.0 :+ 0.0,[1.0 :+ 0.0,0.0 :+ 0.0]]}
Prelude Data.Complex Matrix> a*b
Matrix {matrixN = 2,matrixElems = [[2.0 :+ 3.0,1.0 :+ 1.0],[23.0 :+ 12.0,9.0 :+ 5.0]]}

编辑:新材料

哦,你想要在没有任何Num的情况下覆盖(*)函数.这可能是o但你必须记住Haskell标准库已保留(*)以便在Num类中使用.

module Matrix where

import qualified Prelude as P
import Prelude hiding ((*))
import Data.List (transpose)

class Multiply a where
  (*) :: a -> a -> a

data Matrix a = Matrix {matrixN :: Int,Eq)

matrix :: Int -> Int -> [[a]] -> Matrix a
matrix n m vals
  | length vals /= m            = error "Wrong number of rows"
  | any (/=n) $map length vals = error "Column length mismatch"
  | otherwise = Matrix n m vals

matrixTranspose (Matrix m n vals) = matrix n m (transpose vals)

instance P.Num a => Multiply (Matrix a) where
  (*) (Matrix m n vals) (Matrix n' p vals')
    | n/=n' = error "Matrix dimension mismatch in multiplication"
    | otherwise = let tvals' = transpose vals'
                      dot x y = sum $zipWith (P.*) x y
                      result = map (col -> map (dot col) tvals') vals
                  in Matrix m p result


a = matrix 3 2 [[1,3],6]]
b = a * matrixTranspose

在ghci中测试:

*Matrix> b
Matrix {matrixN = 3,matrixElems = [[14,32],[32,77]]}

那里.现在,如果第三个模块想要同时使用Matrix版本的(*)和Prelude版本的(*),它当然必须导入一个或另一个合格的.但这只是照常营业.

我可以在没有Multiply类型类的情况下完成所有这些,但是这个实现使我们新的闪亮(*)在其他模块中打开以进行扩展.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读