Символічне матричне множення


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.

Сума термінів повинна мати пробіл (ASCII код, точка 32) між ними. Це 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]

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

Загальні правила:

  • Ви можете припустити дійсний ввід. Матричне множення завжди буде можливим із заданими розмірами.
  • Буде лише дві матриці.
  • Ви можете припустити, що матриці не порожні
  • Вбудовані функції приймаються (але, ймовірно, трохи громіздкими через вимоги до форматування).
  • Ви, звичайно, можете використовувати знаки втечі, якщо це необхідно ( \'замість ').
  • Будь-який стандартний метод введення та виведення в порядку .

Тестові приклади:

Дві вхідні матриці показані порожнім рядком між ними. Вихід відображається після 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 масив символів як вхід і повернути 2D масив рядків?
Денніс

@Dennis, я писав: "Обидві матриці потрібно вводити в одному форматі". Я забув згадати там вихідну матрицю, тому я просто зберігаю її так. Входи повинні бути в одному форматі, але у вас може бути інший формат виводу. (Мені не дуже подобається це рішення, але я не хочу зараз змінювати речі. Я думаю, є вже одна відповідь, що має різні формати введення та виведення)
Стюі Гріффін

Якщо ви маєте на увазі відповідь на 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

Математика, 36 байт

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

Innerє узагальненням Mathematica 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

Діалог APL , 10 байт

Приймає матриці символів як аргументи зліва та справа. Повертає матрицю списків символів. (APL представляє рядки як списки символів.)

{∊⍺' '⍵}.,

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

Звичайний внутрішній продукт є в APL +.×, але додавання та множення можуть бути будь-якими функціями, зокрема:

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

Множення було замінено конкатенацією, ,


2

Желе , 7 байт

Z;"þK€€

Це діадичне посилання, яке приймає B і A в якості аргументів (у тому порядку) і повертає AB . Введення та вихід у вигляді двовимірних масивів рядків, які фактично є 3D-масивами символів. Подальший байт можна зберегти, взявши за вхід 2D-масиви символів . Я не впевнений, чи це дозволено.

Спробуйте в Інтернеті!

Трохи важко визначити, що робить 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, і сума (_), яка є деякою сукупністю. Всі вони можуть використовуватися всередині / 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` `))

Приймає дані як два двовимірних масиви символів і повертає 2D масив рядків. Додайте 10 байт для підтримки введення у вигляді двох 1D масивів рядків.


1

Піт, 14 байт

clQmj;sMCd*QCE

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

Тестовий набір

Як це працює

[Пояснення, що надходить пізніше]


1

Піп , 17 байт

{Y Zb{a._JsMy}Ma}

Це функція, яка бере два вкладені списки (односимвольних) рядків і повертає вкладений список рядків. Спробуйте в Інтернеті! (з двома тестовими випадками).

Пояснення

Аргументи до {}-розмежованої функції присвоюються локальним змінним 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.