Символьная матрица умножения


26

Есть много разных способов объяснить матричное умножение. Я буду придерживаться одной фигуры, так как считаю, что большинство людей здесь знакомы с ней (и эта цифра очень наглядна). Если вам нужна более подробная информация, я предлагаю вам посетить статью в Википедии или пояснение к WolframMathWorld .

Простое объяснение:

Предположим, у вас есть две матрицы, A и B , где A - 3 на 2, а B - 2 на 3. Если вы выполните умножение матриц на эти матрицы, либо AB , либо BA, вы получите следующие результаты:

введите описание изображения здесь

Вызов:

Реализуйте умножение символьных матриц на вашем языке. В качестве входных данных вы должны взять две матрицы, где каждый элемент в матрицах представлен непробельным символом ASCII (кодовые точки 33-126). Вы должны вывести произведение этих матриц.

Правила относительно вывода:

Произведение двух записей не должно иметь никаких символов между ними. Это ab, не a*b, a·b, times(a,b)или что - то подобное. Это aaне так a^2.

Сумма терминов должна иметь пробел (кодовая точка 32 ASCII) между ними. Это a b, не a+b, plus(a,b)или что - то подобное.

Обоснование этих двух правил таково: все символы, не являющиеся пробелами, допускаются в качестве символов в матрицах, поэтому их использование в качестве математических символов будет беспорядочным. Итак, что вы могли бы нормально написать как a*b+c*dбудет ab cd.

Вы можете выбрать порядок условий. ab cd, dc abиcd ba математически говоря то же самое, так что вы можете выбрать порядок здесь. Порядок не обязательно должен быть последовательным, если он математически правильный.

Правила относительно матричного форматирования:

Матрица может быть введена в любом формате, который вам нравится, кроме одной строки без разделителей между строками (это потому, что выходные данные будут полностью испорчены). Обе матрицы должны быть введены в одном формате. Все приведенные ниже примеры являются допустимыми способами ввода и вывода матрицы.

"ab;cd"     <- This will look awful, but it's still accepted.

"a,b\nc,d"

[[a,b],[c,d]] 

[a, b]
[c, d]

Я знаю, что это допускает множество форматов, которые будут выглядеть беспорядочно, но проблема заключается в умножении матриц, а не в форматировании вывода.

Основные правила:

  • Вы можете принять верный ввод. Умножение матриц всегда будет возможно с заданными размерами.
  • Там будет только две матрицы.
  • Вы можете предположить, что матрицы не пустые
  • Встроенные функции принимаются (но, вероятно, немного громоздко из-за требований к форматированию).
  • Вы можете, конечно, использовать escape-символы на входе, если это необходимо ( \'вместо' ).
  • Любой стандартный метод ввода и вывода в порядке .

Тестовые случаи:

Две входные матрицы показаны пустой строкой между ними. Вывод отображается после Output:. Когда есть две выходные матрицы, это просто показать другие выходные данные, которые будут приняты.

Тестовый пример № 1

Inputs:
[a]

[b]

Output:
[ab]
[ba]      <- Also OK

Тестовый пример № 2

Inputs:
[a, b]
[1, 4] 
[y, {]

[%, 4, 1] 
[a, b, c]

Output:    
[a% ba, a4 bb, a1 bc] 
[1% 4a, 14 4b, 11 4c] 
[y% {a, y4 {b, y1 {c]

Тестовый пример № 3:

Inputs:
[1, 2, 3, 4]
[5, 6, 7, 8]
[9, 1, 2, 3]
[4, 5, 6, 7]

[a]
[b]
[c]
[d]

Output:
[1a 2b 3c 4d]
[5a 6b 7c 8d]
[9a 1b 2c 3d]
[4a 5b 6c 7d]

[d4 c3 b2 a1]      <-- Also OK
[d8 c7 b6 a5]
[1b 9a c2 3d]
[a4 b5 d7 6c]

Если ваш ответ на правила о требовании ab cdвместо a*b+c*d: вы должны избегать громоздких форматов ввода / вывода , то я хотел бы отметить, что форматы ввода и вывода очень гибкие. Тот факт, что вы не можете использовать *и +для продуктов и сумм, может усложнить использование простого встроенного, но я не считаю это отрицательным моментом.


Для функции допустимо ли брать два 2D-массива строк и возвращать 2D-массив строк?
Деннис

Да нет проблем. Но размеры должны совпадать, второй вход не может быть транспонирован. Это имело смысл?
Стьюи Гриффин

Это так, спасибо за разъяснения. Последний вопрос: могу ли я также взять двумерный массив символов в качестве входных данных и вернуть двумерный массив строк?
Деннис

@ Денис, я написал: «Обе матрицы должны быть введены в одном формате». Я забыл упомянуть выходную матрицу там, так что я просто буду держать это так. Входные данные должны быть в одном формате, но у вас может быть другой выходной формат. (Мне не очень нравится это решение, но я не хочу сейчас что-то менять, я думаю, что уже есть один ответ, который имеет разные форматы ввода и вывода)
Stewie Griffin

Если вы имеете в виду ответ Ruby, я проверил, и он работает так же хорошо со строками вместо символов.
Деннис

Ответы:


9

Haskell , 62 61 байт

e=[]:e
a!b=[unwords.zipWith(++)r<$>foldr(zipWith(:))e b|r<-a]

Попробуйте онлайн! Пример использования:

Prelude> [["a","b"],["c","e"]] ! [["f","g"],["h","i"]]
[["af bh","ag bi"],["cf eh","cg ei"]]

Я нашел способ получить transposeфункцию на один байт короче, чем с помощью импорта:

import Data.List;transpose
e=[]:e;foldr(zipWith(:))e

Старая версия с импортом: (62 байта)

import Data.List
a!b=[unwords.zipWith(++)r<$>transpose b|r<-a]

Попробуйте онлайн!

Это очень похоже на мой ответ на несимвольное матричное умножение : a!b=[sum.zipWith(*)r<$>transpose b|r<-a]замена умножения (*)на конкатенацию строк (++)и sumна unwordsкоторую конкатенируется список строк с пробелом между ними. Импорт необходим для transposeфункции, так что в целом транспонирование второй матрицы занимает половину байтов ...


Старая версия без импорта: (64 байта)

a![]=[];a!b=(unwords.zipWith(++)[h|h:_<-b]<$>a):a![s:t|_:s:t<-b]

Попробуйте онлайн!

Поскольку импорт и transposeфункция занимают столько байтов, я попытался решить задачу без импорта. До сих пор этот подход оказался на два байта длиннее, но он мог бы быть более пригодным для игры в гольф. Изменить: другой подход в верхней части теперь превосходит импорт!

Понимание списка [s:t|_:s:t<-b]получает непустые хвосты списков b, используя только, [t|_:t<-b]чтобы получить хвосты, которые были бы на 4 байта короче (даже превосходя версию импорта), но добавляли пустую строку, как ["","",""]в матрицу, которая, я полагаю, не разрешена.


6

Mathematica, 36 байт

Inner[#<>#2&,##,StringRiffle@*List]&

Innerявляется обобщением Mathematica's Dot(т.е. обычное матричное / векторное произведение). Он обобщает скалярное произведение, позволяя вам предоставить две функции fи g, которые будут использоваться вместо обычного умножения и сложения соответственно. Мы заменяем умножение на #<>#2&(которое объединяет два символа в одну строку) и сложение StringRiffle@*List, которое сначала оборачивает все слагаемые в списке, а затем StringRiffleсоединяет их вместе с пробелами.

Можно потенциально использовать Dotоператор, .а затем преобразовать результат, но проблема в том, что подобные вещи "a"*"a"немедленно преобразуются в "a"^2(то же самое для сумм), что было бы неприятно снова разбирать.


6

Рубин, 61 байт

->a,b{a.map{|x|b.transpose.map{|y|x.zip(y).map(&:join)*' '}}}

Образец прогона:

main(0):007> ->a,b{a.map{|x|b.transpose.map{|y|x.zip(y).map(&:join)*' '}}}[[[?a, ?b], [?1, ?4], [?y, ?{]], [[?%, ?4, ?1], [?a, ?b, ?c]]]
=> [["a% ba", "a4 bb", "a1 bc"], ["1% 4a", "14 4b", "11 4c"], ["y% {a", "y4 {b", "y1 {c"]]
->a,b{
a.map{|x|            # for each row of a
b.transpose.map{|y|  # and for each column of b
x.zip(y)             # match up corresponding elements
.map(&:join)         # join each pair together
*' '                 # join the entire thing on space
}}}

4

Clojure, 53 байта

#(for[a %](for[b(apply map vector %2)](map str a b)))

Запуск с аргументами [["a" "b"]["c" "e"]]и [["f" "g"]["h" "i"]]возвратами ((("af" "bh") ("ag" "bi")) (("cf" "eh") ("cg" "ei"))). Это на самом деле короче, чем числовая версия .


3

Dyalog APL , 10 байт

Принимает матрицы символов в качестве левого и правого аргументов. Возвращает матрицу списков символов. (APL представляет строки в виде списков символов.)

{∊⍺' '⍵}.,

Попробуй APL онлайн!

Нормальный внутренний продукт в APL +.× , но сложение и умножение могут быть любыми функциями, в частности:

Добавление было заменено
{ анонимной функцией:
 плоский
⍺ ' ' ⍵ список, состоящий из левого аргумента, пробела и правого аргумента
}

Умножение было заменено конкатенацией, ,


2

Желе , 7 байт

Z;"þK€€

Это диадическая ссылка, которая принимает B и A в качестве аргументов (в указанном порядке) и возвращает AB . Ввод и вывод выполняются в виде двумерных массивов строк, которые на самом деле являются трехмерными массивами символов. Еще один байт можно сохранить, взяв в качестве входных данных двумерные массивы символов . Я не уверен, разрешено ли это.

Попробуйте онлайн!

Трудно определить, что делает Jelly под капотом, когда задействованы струны, так как он делает много брызг перед печатью. Вот как Jelly представляет ввод и вывод внутри.

Как это работает

Z;"þK€€  Dyadic link. Left argument: B. Right argument: A

Z        Zip/transpose B.
 ;"þ     Table vectorized concatenation; for each row in B' and each row in A,
         concatenate the corresponding strings.
    K€€  Join the arrays that correspond to the rows of A by spaces.

2

Пролог,> 256 байт

Я использую {_ | _}, который является findall / 3, _ [_, _], который является некоторым arg / 3, и sum (_), который является некоторой совокупностью. Все они могут быть использованы внутри / 2:

*(X, Y, Z) :- functor(Y, matrice, _), L is len(X[1]), L =:= len(Y), !,
   M is len(X), N is len(Y[1]),
   Z is { { sum({ X[J,K] * Y[K,I] | between(1,L,K) })
                                  | between(1,N,I) }
                                  | between(1,M,J) }.

Вместе с дополнительными определениями для вышеупомянутых предикатов и нестандартным является / 2, который может возвращать больше, чем числа, его уверенность> 256 байтов.


1

JavaScript (ES6), 65 байт

(a,b)=>a.map(c=>b[0].map((_,j)=>c.map((e,i)=>e+b[i][j]).join` `))

Принимает ввод как два двумерных массива символов и возвращает двумерный массив строк. Добавьте 10 байтов для поддержки ввода в виде двух одномерных массивов строк.


1

Pyth, 14 байт

clQmj;sMCd*QCE

Программа, которая принимает ввод двух разделенных новой строкой двухмерных списков символов и печатает двумерный список строк.

Тестирование

Как это работает

[Объяснение будет позже]


1

Пип , 17 байт

{Y Zb{a._JsMy}Ma}

Это функция, которая принимает два вложенных списка (односимвольных) строк и возвращает вложенный список строк. Попробуйте онлайн! (с двумя тестами).

объяснение

Аргументы в {}-delimited функции возложены на локальные переменные aв e. Первый аргумент лямбда-функции представлен как _.

{               }  Define a function:
   Zb              Zip rows of b, transposing it
 Y                 Yank into global variable y for access in nested function
     {       }Ma   To the rows of a, map this function:
           My       To the rows of y (i.e. columns of b), map this function:
      a._           Concatenate, itemwise, the current row of a and row of y
         Js         Join the resulting list on space
                   The result of the outer map operation is returned
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.