シンボリック行列乗算


26

行列の乗算を説明する方法はたくさんあります。ここのほとんどの人はそれに精通していると思うので、私は単一の図に固執します(そして図は非常に記述的です)。より詳細な情報が必要な場合は、ウィキペディアの記事、またはWolframMathWorldの説明をご覧になることをお勧めします。

簡単な説明:

あなたは二つの行列、持っていると仮定ABAが 3行2であり、Bは 2行3です。これらに対してABBAのいずれかの行列に行列乗算を実行すると、以下の結果が得られます。

ここに画像の説明を入力してください

チャレンジ:

言語にシンボリック行列乗算を実装します。入力として2つのマトリックスを使用します。ここで、マトリックス内の各要素は非空白ASCII文字(コードポイント33〜126)で表されます。これらの行列の積を出力する必要があります。

出力に関する規則:

2つのエントリの製品には、間に記号を入れてはなりません。それはだab、ではないa*ba·btimes(a,b)または類似した何か。でaaはありませんa^2

用語の合計には、間にスペース(ASCIIコードポイント32)が必要です。それa ba+b、ではなく、plus(a,b)または類似したものです。

これら2つのルールの理論的根拠は次のとおりです。すべての非空白文字は行列内の記号として許可されているため、数学記号として使用するのは面倒です。だから、あなたが普通に書くことができるものはそうa*b+c*dなりますab cd

条件の順序を選択できます。ab cddc 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]

これにより面倒に見える多くのフォーマットが可能になることは承知していますが、課題は出力のフォーマットではなく行列の乗算です。

一般的なルール:

  • 有効な入力を想定することができます。行列の乗算は、指定された次元で常に可能です。
  • マトリックスは2つしかありません。
  • 行列が空でないと仮定することができます
  • 組み込み関数が受け入れられます(ただし、書式設定の要件のため、おそらく少し面倒です)。
  • もちろん、必要に応じて(\'ではなく')入力にエスケープ文字を使用できます。
  • 標準の入出力方法はすべてOKです

テストケース:

2つの入力行列は、間に空の行が表示されています。出力はの後に表示されOutput:ます。2つの出力マトリックスがある場合、受け入れられる他の出力を表示するだけです。

テストケース#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が次のとおりである場合、面倒な入力/出力形式を避ける必要があります。入力および出力形式は非常に柔軟であることに注意してください。あなたが使用できないという事実*+製品との合計については、それが困難に内蔵されたシンプルなを使用することを作るかもしれませんが、私はその否定的なことを考慮していません。


関数の場合、2つの文字列の2D配列を取り、文字列の2D配列を返しますか?
デニス

はい、問題ありません。ただし、次元が一致する必要があります。2番目の入力を転置することはできません。それは理にかなっていますか?
スチューウィーグリフィン

明確にしてくれてありがとう。最後の質問:入力として文字の 2D配列を取り、文字列の2D配列を返すことはできますか?
デニス

@デニス、私は書いた:「両方の行列は同じ形式で入力する必要があります。」そこで出力マトリックスについて言及するのを忘れていたので、このままにしておきます。入力は同じ形式である必要がありますが、出力形式が異なる場合があります。(私は本当に、そのソリューション好きではないが、私は今の変化のものにしたくない、私は別の入力と出力のフォーマットがあり、すでに1つの答えはそこだと思う)
Stewieグリフィン

あなたがRubyの答えを意味するなら、私はチェックし、文字の代わりに文字列でも同様に機能することを確認しました。
デニス

回答:


9

Haskell62 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インポートを使用するよりも1バイト短い関数を取得する方法を見つけました。

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]、乗算を代入する(*)文字列の連結と(++)sumunwordsの間のスペースを持つ文字列のリストを連結しています。transpose関数にはインポートが必要なため、すべての2番目の行列の転置はバイトの半分を使用します...


インポートなしの古いバージョン:(64バイト)

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

オンラインでお試しください!

インポートとtranspose関数が非常に多くのバイトを占めるため、インポートなしでタスクを解決しようとしました。これまでのところ、このアプローチは2バイト長くなりましたが、よりゴルフに適しているかもしれません。編集:上部にある他のアプローチがインポートに勝りました!

リストの内包表記[s:t|_:s:t<-b]は、リストの空ではない末尾を取得します。末尾を取得するためbだけ[t|_:t<-b]に使用すると、4バイト短くなります(インポートバージョンを破る)が、["","",""]許可されていない行列のように空の行を追加します。


6

Mathematica、36バイト

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

InnerはMathematicaの一般化Dot(つまり通常の行列/ベクトル積)です。通常の乗算​​と加算の代わりにそれぞれ使用される2つの関数fとを提供することにより、内積を一般化しgます。乗算を#<>#2&(2つの文字を1つの文字列に結合する)で置き換え、加算をで置き換えます。これは、StringRiffle@*List最初にすべての被加数をリストにラップし、次にStringRiffleスペースで結合します。

潜在的にDot演算子.を使用して結果を変換することもできますが、問題は、次のよう"a"*"a"にすぐに変換される"a"^2(合計と同じ)ことであり、これは再び選択するのが面倒です。


6

Ruby、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は文字列を文字のリストとして表します。)

{∊⍺' '⍵}.,

TryAPLオンライン!

通常の内積はAPL +.×にありますが、加算と乗算は任意の関数、特に次の関数にできます:

追加は
{ 匿名関数に置き換えられました: 左引数、スペース、右引数で構成される
 フラット化された
⍺ ' ' ⍵リスト
}

乗算は連結に置き換えられ、 ,


2

ゼリー、7バイト

Z;"þK€€

これは、BAを(この順序で)引数として取り、ABを返す2 項リンクです。入力と出力は文字列の2D配列の形式であり、実際には文字の3D配列です。入力として文字の 2D配列を取得することにより、さらにバイトを節約できます。それが許可されているかどうかはわかりません。

オンラインでお試しください!

Jellyは、印刷する前に飛び散っているので、文字列が関係する場合、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(_)。これらはすべてis / 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) }.

余分な定義は前述の述語と非標準のためのより多くの番号、その確認> 256バイトよりも返すことができる/ 2です。


1

JavaScript(ES6)、65バイト

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

入力を2つの文字の2D配列として受け取り、文字列の2D配列を返します。10バイトを追加して、文字列の2つの1D配列としての入力をサポートします。


1

Pyth、14バイト

clQmj;sMCd*QCE

改行で区切られた2つの文字の2次元リストを入力し、文字列の2次元リストを出力するプログラム。

テストスイート

使い方

[後で説明する]


1

ピップ、17バイト

{Y Zb{a._JsMy}Ma}

これは、(単一文字の)文字列のネストされたリストを2つ受け取り、文字列のネストされたリストを返す関数です。オンラインでお試しください!(2つのテストケース)。

説明

{}区切られた関数の引数は、ローカル変数atoに割り当てられます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
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.