Symbolische Matrixmultiplikation


26

Es gibt viele verschiedene Möglichkeiten, die Matrixmultiplikation zu erklären. Ich bleibe bei einer einzigen Figur, da ich glaube, dass die meisten Leute hier damit vertraut sind (und die Figur ist sehr beschreibend). Wenn Sie detailliertere Informationen wünschen, empfehle ich Ihnen, den Wikipedia-Artikel oder die Erklärung zu WolframMathWorld zu besuchen .

Einfache Erklärung:

Angenommen, Sie haben zwei Matrizen, A und B , wobei A 3 mal 2 und B 2 mal 3 ist. Wenn Sie eine Matrixmultiplikation mit diesen Matrizen durchführen, entweder AB oder BA, erhalten Sie die folgenden Ergebnisse:

Bildbeschreibung hier eingeben

Herausforderung:

Implementieren Sie die symbolische Matrixmultiplikation in Ihrer Sprache. Sie müssen zwei Matrizen als Eingabe verwenden, wobei jedes Element in den Matrizen durch ein Nicht-Leerzeichen-ASCII-Zeichen dargestellt wird (Codepunkte 33-126). Sie müssen das Produkt dieser Matrizen ausgeben.

Regeln zur Ausgabe:

Ein Produkt aus zwei Einträgen darf keine Symbole dazwischen haben. Es ist ab, nicht a*b, a·b, times(a,b)oder etwas ähnliches. Ist es aanicht a^2.

Die Summe der Begriffe sollte ein Leerzeichen (ASCII-Code Punkt 32) dazwischen haben. Es ist a b, nicht a+b, plus(a,b)oder etwas ähnliches.

Das Grundprinzip für diese beiden Regeln ist: Alle Zeichen, die keine Leerzeichen sind, dürfen als Symbole in der Matrix verwendet werden, daher wäre ihre Verwendung als mathematische Symbole unübersichtlich. Also, was du normalerweise schreiben könntest, wie a*b+c*des sein wird ab cd.

Sie können die Reihenfolge der Begriffe wählen. ab cd, dc abund cd basind mathematisch gesehen gleich, so dass Sie auch hier die Reihenfolge wählen können. Die Reihenfolge muss nicht konsistent sein, solange sie mathematisch korrekt ist.

Regeln zur Matrixformatierung:

Eine Matrix kann in einem beliebigen Format eingegeben werden, mit Ausnahme einer einzelnen Zeichenfolge ohne Trennzeichen zwischen den Zeilen (dies liegt daran, dass die Ausgabe vollständig durcheinander geraten würde). Beide Matrizen müssen im selben Format eingegeben werden. Alle folgenden Beispiele sind gültige Möglichkeiten zum Eingeben und Ausgeben einer Matrix.

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

"a,b\nc,d"

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

[a, b]
[c, d]

Ich bin mir bewusst, dass dies viele Formate zulässt, die unordentlich aussehen werden, aber die Herausforderung besteht darin, Matrizen zu multiplizieren und die Ausgabe nicht zu formatieren.

Allgemeine Regeln:

  • Sie können eine gültige Eingabe annehmen. Eine Matrixmultiplikation ist mit den angegebenen Dimensionen immer möglich.
  • Es gibt nur zwei Matrizen.
  • Sie können davon ausgehen, dass die Matrizen nicht leer sind
  • Eingebaute Funktionen werden akzeptiert (sind aber aufgrund der Formatierungsanforderungen wahrscheinlich etwas umständlich).
  • Sie können natürlich bei Bedarf ( \'anstelle von ') Escape-Zeichen in der Eingabe verwenden .
  • Jede Standard-Eingabe- und Ausgabemethode ist in Ordnung .

Testfälle:

Die beiden Eingangsmatrizen werden mit einer Leerzeile dazwischen angezeigt. Die Ausgabe wird nach angezeigt Output:. Wenn zwei Ausgangsmatrizen vorhanden sind, werden nur andere Ausgänge angezeigt, die akzeptiert würden.

Testfall Nr. 1

Inputs:
[a]

[b]

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

Testfall Nr. 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]

Testfall 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]

Wenn Ihre Antwort auf die Regeln zum Anfordern ab cdstatt a*b+c*dlautet: Sie sollten umständliche Eingabe- / Ausgabeformate vermeiden , dann möchte ich darauf hinweisen, dass die Eingabe- und Ausgabeformate sehr flexibel sind. Die Tatsache, dass Sie nicht *und +für Produkte und Summen verwenden können, könnte es schwieriger machen, ein einfaches eingebautes zu verwenden, aber ich betrachte diese negative Sache nicht.


Ist es für eine Funktion akzeptabel, zwei 2D-Strings-Arrays zu verwenden und ein 2D-Strings-Array zurückzugeben?
Dennis

Ja, kein Problem. Die Abmessungen müssen jedoch übereinstimmen, da die zweite Eingabe nicht transponiert werden kann. Hat das Sinn ergeben?
Stewie Griffin

Es hat, danke für die Klärung. Eine letzte Frage: Kann ich auch ein 2D-Array von Zeichen als Eingabe verwenden und ein 2D-Array von Zeichenfolgen zurückgeben?
Dennis

@ Tennis, schrieb ich: "Beide Matrizen müssen im gleichen Format eingegeben werden." Ich habe vergessen, die Ausgabematrix dort zu erwähnen, daher werde ich sie einfach so beibehalten. Die Eingaben müssen dasselbe Format haben, aber möglicherweise haben Sie ein anderes Ausgabeformat. (Ich mag diese Lösung nicht wirklich, aber ich möchte jetzt nichts ändern. Ich glaube, es gibt bereits eine Antwort mit unterschiedlichen Eingabe- und Ausgabeformaten.)
Stewie Griffin

Wenn du die Ruby-Antwort meinst, habe ich überprüft, dass diese auch mit Zeichenketten anstelle von Zeichen funktioniert.
Dennis

Antworten:


9

Haskell , 62 61 Bytes

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

Probieren Sie es online! Anwendungsbeispiel:

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

Ich habe einen Weg gefunden, eine transposeFunktion in einem Byte kürzer als mit dem Import zu bekommen:

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

Alte Version mit Import: (62 Bytes)

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

Probieren Sie es online!

Das ist ganz ähnlich wie meine Antwort auf nicht-symbolische Matrix - Multiplikation : a!b=[sum.zipWith(*)r<$>transpose b|r<-a]die Multiplikation Substitution (*)mit String - Verkettung (++)und summit unwordsdenen verkettet eine Liste von Strings mit einem Raum dazwischen. Der Import wird für die transposeFunktion benötigt , so dass die Transposition der zweiten Matrix insgesamt die Hälfte der Bytes verbraucht ...


Alte Version ohne Import: (64 Bytes)

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

Probieren Sie es online!

Da der Import und die transposeFunktion so viele Bytes beanspruchen, habe ich versucht, die Aufgabe ohne Import zu lösen. Bisher hat sich herausgestellt, dass dieser Ansatz zwei Bytes länger ist, er ist jedoch möglicherweise besser geeignet. Edit: Der andere Ansatz oben schlägt jetzt den Import!

Beim Listenverständnis werden [s:t|_:s:t<-b]die nicht leeren Endpunkte der Listen berücksichtigt. Wenn bnur [t|_:t<-b]die Endpunkte verwendet werden, sind diese 4 Byte kürzer (sogar besser als bei der Importversion), es wird jedoch eine leere Zeile wie ["","",""]bei der Matrix angehängt, was meiner Meinung nach nicht zulässig ist.


6

Mathematica, 36 Bytes

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

Innerist eine Verallgemeinerung von Mathematica Dot(dh das übliche Matrix- / Vektorprodukt). Es verallgemeinert das Skalarprodukt von zwei Funktion lassen liefern fund g, die anstelle der üblichen Multiplikation und Addition verwendet wird, respectively. Wir ersetzen die Multiplikation mit #<>#2&(die die beiden Zeichen zu einer einzigen Zeichenfolge zusammenfügt) und die Addition mit StringRiffle@*List, die zuerst alle Summanden in eine Liste einschließt und sie dann StringRifflemit Leerzeichen zusammenfügt.

Man könnte möglicherweise den DotOperator verwenden .und dann das Ergebnis transformieren, aber das Problem ist, dass Dinge wie "a"*"a"sofort transformiert werden "a"^2(dasselbe für Summen), was ärgerlich wäre, wenn man sie wieder auseinander nimmt.


6

Ruby, 61 Bytes

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

Probelauf:

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 Bytes

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

Läuft mit Argumenten [["a" "b"]["c" "e"]]und [["f" "g"]["h" "i"]]kehrt zurück ((("af" "bh") ("ag" "bi")) (("cf" "eh") ("cg" "ei"))). Dies ist tatsächlich kürzer als die numerische Version .


3

Dyalog APL , 10 Bytes

Nimmt Matrizen von Zeichen als linkes und rechtes Argument. Gibt eine Matrix mit Listen von Zeichen zurück. (APL stellt Zeichenfolgen als Liste von Zeichen dar.)

{∊⍺' '⍵}.,

TryAPL online!

Normales inneres Produkt ist in APL +.× , aber die Addition und Multiplikation kann eine beliebige Funktion sein, insbesondere:

Die Hinzufügung wurde durch
{ eine anonyme Funktion ersetzt:
 die abgeflachte
⍺ ' ' ⍵ Liste, die aus dem linken Argument, einem Leerzeichen und dem rechten Argument besteht
}

Die Multiplikation wurde durch Verkettung ersetzt. ,


2

Gelee , 7 Bytes

Z;"þK€€

Dies ist eine dyadische Verknüpfung, die B und A als Argumente (in dieser Reihenfolge) verwendet und AB zurückgibt . Eingabe und Ausgabe erfolgen in Form von 2D-Arrays von Zeichenfolgen, bei denen es sich tatsächlich um 3D-Arrays von Zeichen handelt. Ein weiteres Byte könnte durch die Verwendung von 2D- Zeichenfeldern gespeichert werden als Eingabe verwendet werden. Ich bin mir nicht sicher, ob das erlaubt ist.

Probieren Sie es online!

Es ist ein bisschen schwierig zu bestimmen, was Jelly unter der Haube macht, wenn es um Schnüre geht, da es vor dem Drucken viel plätschert. So repräsentiert Jelly intern Input und Output.

Wie es funktioniert

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

Prolog,> 256 Bytes

Ich benutze {_ | _} ist ein Findall / 3, _ [_, _] ist ein Arg / 3 und sum (_) ist ein Aggregat. Sie können alle in is / 2 verwendet werden:

*(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) }.

Zusammen mit den zusätzlichen Definitionen für die oben genannten Prädikate und die Nicht-Standard ist / 2, die mehr als Zahlen zurückgeben kann, sicher> 256 Byte.


1

JavaScript (ES6), 65 Byte

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

Übernimmt die Eingabe als zwei 2D-Zeichenfelder und gibt ein 2D-Zeichenfeld zurück. Fügen Sie 10 Bytes hinzu, um die Eingabe als zwei 1D-Strings zu unterstützen.


1

Pyth, 14 Bytes

clQmj;sMCd*QCE

Ein Programm, das zwei durch Zeilenumbrüche getrennte zweidimensionale Listen von Zeichen eingibt und eine zweidimensionale Liste von Zeichenfolgen ausgibt.

Testsuite

Wie es funktioniert

[Erklärung kommt später]


1

Pip , 17 Bytes

{Y Zb{a._JsMy}Ma}

Dies ist eine Funktion, die zwei verschachtelte Listen von (Einzelzeichen-) Zeichenfolgen verwendet und eine verschachtelte Liste von Zeichenfolgen zurückgibt. Probieren Sie es online!(mit zwei Testfällen).

Erläuterung

Argumente für eine {}-begrenzte Funktion werden den lokalen Variablen abis zugewiesen e. Das erste Argument einer Lambda-Funktion wird durch dargestellt _.

{               }  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
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.