Умножение матриц в схеме, список списков - PullRequest
0 голосов
/ 05 сентября 2018

Я начал изучать Схему и не понимаю некоторых из них. Я использую 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

Я не понимаю, как это работает.

Спасибо.

1 Ответ

0 голосов
/ 05 сентября 2018

Ах, старый ( 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), когда вводится лямбда, 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 начинает работать с этими строками в качестве аргументов, лямбда функция применяется к последующим номерам каждой строки, соответственно, в унисон; таким образом, достигая того же эффекта, что и явное преобразование . Но теперь добавленный бонус заключается в том, что нам не нужно переводить результат обратно в правильную форму, как мы делаем с вашей первой версией.

Это очень умно и приятно.

...