方案中的矩阵乘法,列表列表

时间:2018-09-05 11:30:32

标签: matrix scheme racket apply transpose

我开始研究Scheme,但我不了解其中的一些内容。我正在使用DrRacket。

我编写了以下代码:

(define mult_mat
  (λ (A B)
    (Trans_Mat (map (λ (x) (mul_Mat_vec A x))
                    (Trans_Mat B)))))

使用以下功能:

(define Trans_Mat
  (λ (A)
    (apply map (cons list A))))

(define mul_Mat_vec
  (λ (A v)
    (map (λ (x) (apply + (map * x v)))
         A)))

mult_mat中,我将矩阵A乘以转置矩阵B的每个向量。 很好。

我在网上找到了一个以我不了解的方式进行乘法的代码:

(define (matrix-multiply matrix1 matrix2)
  (map
   (λ (row)
     (apply map
       (λ column
         (apply + (map * row column)))
       matrix2))
   matrix1))

在这段代码中,row是矩阵A列表的列表,但我不知道column是如何更新的。

这部分代码:(apply + (map * row column))是向量row和向量column的点积

例如:A是矩阵2X3,B是矩阵3X2,如果我写的是(apply + (map * row column))而不是1,那么我将得到一个矩阵2X2,其条目值为1

我不知道它是如何工作的。

谢谢。

3 个答案:

答案 0 :(得分:3)

啊,旧的( apply map foo _a_list_ )窍门。非常聪明。

实际上(apply map (cons list A))(apply map list A)相同。这就是apply的定义工作方式。

尝试一些具体示例通常有助于“获取”:

(apply map       list '((1 2 3)  (10 20 30)) )
=
(apply map (cons list '((1 2 3)  (10 20 30))))
=
(apply map (list list  '(1 2 3) '(10 20 30) ))
=
(      map       list  '(1 2 3) '(10 20 30)  )
=
'((1 10) (2 20) (3 30))

矩阵转置。 (实际上是列表列表。)

所以你有

(define (mult_mat A B)
    (Trans_Mat (map (λ (B_column) (mul_Mat_vec A B_column))
                    (Trans_Mat B))))

(define (Trans_Mat A)
    (apply map list A))

(define (mul_Mat_vec A v)
    (map (λ (A_row) (apply + (map * A_row v)))
         A))

(define (matrix-multiply A B)
  (map
    (λ (A_row)
      (apply map
             (λ B_column
               (apply + (map * A_row B_column)))
             B))
    A))

请注意,它是(λ B_column ...,没有括号。在((λ args ...) x y z)中,当输入lambda时,args获得打包在列表中的所有参数:

((λ args ...) x y z)
=
(let ([args (list x y z)])
  ...)

也请注意

      (apply map
             (λ B_column
               (apply + (map * A_row B_column)))
             B)

遵循相同的“棘手”模式。实际上与

相同
      (apply map (cons
             (λ B_column
               (apply + (map * A_row B_column)))
             B    ) )
=
      (      map
             (λ B_column
                (apply + (map * A_row B_column)))
             B_row1
             B_row2
             ....
             B_rowN )
=
     (cons (let ([B_column_1 (map car B)])
                (apply + (map * A_row B_column_1)))
           (map (λ B_column
                    (apply + (map * A_row B_column)))
             (map cdr B_row1)
             (map cdr B_row2)
             ....
             (map cdr B_rowN) )
=
     (cons 
       (apply (λ B_column (apply + (map * A_row B_column)))
              (map car B))
       (apply map
              (λ B_column
                 (apply + (map * A_row B_column)))
              (map cdr B)))

map定义。

因此,通过应用 map,矩阵被“打开”到其行的列表中,然后当map开始处理这些行时, lambda函数将其参数相应地统一应用于每行的后续数字;从而达到与显式换位相同的效果。但是现在增加的好处是,我们不需要将结果转回正确的格式,因为我们需要处理您的第一个版本。

这个很聪明

答案 1 :(得分:0)

如果您喜欢使用while循环(对于初学者可能更容易),建议将问题分为7个主要的辅助函数(以及一些其他简单函数):

(到目前为止)这不是最有效的方法,但是很容易理解

  1. getRow mat i:获取矩阵mat的第i行(列表列表)

     (define (getRow mat i)
        (nthElement mat i))
    
    (define (nthElement lisT n)
        (if (= n 0)
            (car lisT)                                                 
            (nthElement (cdr lisT) (- n 1))))
    
  2. getCol mat i:获取矩阵mat的第i列(列表列表)

    (define (getCol mat i)
        (define col (list))
        (define row 0)
        (while (< row (length mat))
            (set! col (append col (list (valueAtIJ mat row i))))
            (set! row (+ row 1)))
         col)
    
    (define (valueAtIJ mat i j)
        (nthElement (nthElement mat i) j))
    
  3. listMult list1 list2:对两个列表执行逐元素乘法

    (define (listMult list1 list2)
        (if (not (null? list1))
            (cons (* (car list1) (car list2)) (listMult (cdr list1) (cdr list2)))
            null))
    
  4. sum aList:计算列表中所有元素的总和

    (define (sum aList)
        (if (null? aList)
            0
            (+ (car aList) (sum (cdr aList)))))
    
  5. length aList:查找列表的长度

    (define (length lisT)
        (if (null? lisT)                                               
            0
            (+ 1 (length (cdr lisT)))))
    
  6. newMatrix m n val:创建一个由val填充的n×n矩阵

    (define (newMatrix m n val)                        
        (define i 0)
        (define row (list val))
        (define mat (list))
        (if (= n 0)
            (list)                                          
            (begin 
                (while (< i (- n 1))
                    (set! row (append row (list val))) 
                    (set! i (+ i 1)))
                (set! i 0)
                (while (< i m)
                    (set! mat (append mat (list row)))     
                    (set! i (+ i 1)))
        mat)))
    
  7. setValueAtIJ mat i j val:在mat中的位置i,j处设置值val(基于0)

    (define (setValueAtIJ mat i j val)
        (set! mat (setNthElementFinal mat i (setNthElementFinal (nthElement mat i) j val)))
        mat) 
    
    

这些都可以组合起来以创建矩阵乘法功能

(define (matrixMult mat1 mat2)
    (define mat1Dim (list (length mat1) (length (nthElement mat1 0))))      
    (define mat2Dim (list (length mat2) (length (nthElement mat2 0))))      
    (define i 0)
    (define j 0)
    (define newMat (newMatrix (car mat1Dim) (car (cdr mat2Dim)) 0))        
    (if (not (= (car (cdr mat1Dim)) (car mat2Dim)))
        null                                                                
        (begin
            (while (< i (length newMat))
                (while (< j (length (nthElement newMat 0)))
                    (set! newMat (setValueAtIJ newMat i j (sum (listMult (getRow mat1 i) (getCol mat2 j)))))
                    (set! j (+ j 1)))
                (set! j 0)
                (set! i (+ i 1)))
        newMat)))

答案 2 :(得分:0)

这个解决方案可能不是最好的编写方式,但很容易理解:

(define (matrixMultiply matrix1 matrix2)
    (define matrix2Transpose (matrixTranspose matrix2) ) ; Calculate matrix2 transpose to prevent recalculation in future
    (map 
        (lambda (row) ; Step1. Iterate through matrix1 rows
            (map
                (lambda (column) ; Step3. Iterate through matrix2 columns
                    (apply + (map * row column)) ; Step4. Multiply rows and columns by peer to peer and add them
                    ; Example: 
                    ; If row be (1 2) and column be (5 7) then:
                    ; Map part does: ((1 * 5) (2 * 7)) -> (5 14)
                    ; Apply part does: 5 + 14 -> 19
                )
                matrix2Transpose ; Step2. Use matrix2 transpose to get columns for every iteration
            )
        )
        matrix1
    )
)

(define (matrixTranspose matrix)
    (apply map (lambda _ _) matrix)
)

(display 
    (matrixMultiply '((1 2) (3 4)) '((5 6) (7 8)) )
)
<块引用>

输出:((19 22) (43 50))