我开始研究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
我不知道它是如何工作的。
谢谢。
答案 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个主要的辅助函数(以及一些其他简单函数):
(到目前为止)这不是最有效的方法,但是很容易理解
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))))
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))
listMult list1 list2:对两个列表执行逐元素乘法
(define (listMult list1 list2)
(if (not (null? list1))
(cons (* (car list1) (car list2)) (listMult (cdr list1) (cdr list2)))
null))
sum aList:计算列表中所有元素的总和
(define (sum aList)
(if (null? aList)
0
(+ (car aList) (sum (cdr aList)))))
length aList:查找列表的长度
(define (length lisT)
(if (null? lisT)
0
(+ 1 (length (cdr lisT)))))
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)))
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))