行列の乗算を行う!


14

数学では、行列乗算または行列積は、2つの行列から行列を生成する2項演算です。この定義は、線形方程式とベクトルの線形変換によって動機付けられています。これらは、応用数学、物理学、および工学で多くの用途があります。より詳細には、Aがn×m行列で、Bがm×p行列である場合、それらの行列積ABはn×p行列です。 Bの列と合計してABのエントリを生成します。2つの線形変換が行列で表される場合、行列積は2つの変換の構成を表します。

出典:ウィキペディア

言い換えると、2つの行列を乗算するには、たとえば:

1 2 3   1 4
2 3 4 × 3 1 = 
3 4 5   4 6

第一、第二のマトリックス中に第1の行列における行番号1、列番号1を取り、乗算1によって12によって3、そして3による4

1 × 1 = 1
2 × 3 = 6
3 × 4 = 12

それらを一緒に追加して、最初のアイテムを取得します。

1 2 3   1 4   19
2 3 4 × 3 1 = 
3 4 5   4 6

結果の最初の列の2番目の番号については、行番号1の代わりに行番号2を使用して同じことを行う必要があります。

1 × 2 = 2
3 × 3 = 9
4 × 4 = 16
      = 27

最初の列全体を実行すると、結果は次のようになります。

1 2 3   1 4   19
2 3 4 × 3 1 = 27
3 4 5   4 6   35

ここで、まったく同じことをもう一度行いますが、最初の列ではなく2番目の列を取得します。

1 2 3   1 4   19 24
2 3 4 × 3 1 = 27 35
3 4 5   4 6   35 46

あなたのタスク

-10000から10000の範囲の数値を含む2つの行列(最大次元200x200)があり、最初の行の列数が2番目の行の数と等しい場合、最初の行列に2番目の行列を掛けます。(行列の乗算は非可換です。)

入力を受け取り、配列の配列(または同等のもの)、行列(言語にその形式がある場合)、または複数行の文字列として出力を与えることができます。

行列の乗算に組み込み関数を使用することはできません。

テストケース

1 2   1 2 3 4 5    13 16 19 22 25
3 4 × 6 7 8 9 10 = 27 34 41 48 55
5 6                41 52 63 74 85

2 3   3 5   15 13
3 4 × 3 1 = 21 19

5 3            11    27
1 3      1 3   7     15
9 3    × 2 4 = 15    39
1 -1000        -1999 -3997

これはであるため、バイト数が最も少ないコードが優先されることに注意してください。


組み込みのドット製品を使用できますか?それらは行列ではなくベクトルに作用します。
デニス

1
入力の順序は固定されてますかそれともabをその順序で取りb×aを出力できますか?
デニス

@デニス入力を逆にすることはできますが、ドット積はありません
オリバーNi

4
YなしでXを実行することに関する課題は推奨されません
flawr

入力行列に浮動小数点数を含めることはできますか?その場合は、いくつかのテストケースを追加することをお勧めします。
R.ガプス

回答:


5

ゼリー7 5 バイト

Z×þḅ1

引数としてBAを取り、A ×Bを返します。

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

使い方

Z×þḅ1  Main link. Left argument: B. Right argument: A

Z      Zip; transpose B's rows and columns.
 ×þ    Table multiplication; multiply all columns of B (rows of B's transpose) by
       all rows of A, element by element. Results are grouped by the rows of A.
   ḅ1  Unbase 1; compute the sum of all flat arrays in the result.

3
それでは、行列を乗算する組み込みおよび手動の方法は、最終的にJellyの同じバイト数になりますか?わかりにくいですが、クールです。
Yodle

@Yodleビルトインはæ×、2バイトです。
エリックアウトゴルファー

@EriktheOutgolferこれは、æ.アトムを使用したリビジョン2を参照していました。
デニス

4

05AB1E、13バイト

vyU²øvyX*O})ˆ

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

説明

v               # for each row in the first matrix
 yU             # save the row in X
   ²øv          # for each row in the transposition of the second matrix
      yX*       # multiply the rows
         O      # sum the elements of the resulting row
          }     # end inner loop
           )    # wrap elements of the new row in a list
            ˆ   # push to global list
                # implicitly output global list

まったく同じアプローチで、今7バイトにすることができますεUøεX*O
ケビンCruijssen

4

Pythonの2、69の 66バイト

これは標準の公式にちょうど従いますが、簡潔さのためにlambda-d :)改変されていないコードは非常に簡単です!

lambda x,y:[[sum(map(int.__mul__,r,c))for c in zip(*y)]for r in x]

3バイトを節約してくれたAlexi Torhamoに感謝します!:)

ゴルフされていないコード:

x = [[1,2],[3,4],[5,6]]
y = [[1,2,3,4,5],[6,7,8,9,10]]

output = []
for row in x:
    nrow = []
    for col in zip(*y):                             # zip(*[]) transposes a matrix
        nrow += [sum(a*b for a,b in zip(row,col))]  # multiplication for each pair summed
    output += [nrow]

print output

sum(map(int.__mul__,r,c))3バイトを節約するために使用できます。(浮動小数点では動作しませんが、それも必須ではありませんでした)
Aleksi Torhamo

3

J、13 9バイト

マイルのおかげで4バイト節約できました!

[:+/*"#:~

これはキャップ付きフォークです:

[: +/ *"#:~

次と同等です:

[: +/ (*"#:)~
[: +/ (*"_ 1 0)~

目的の乗算を実行します。これらは合計されます。

組み込みのドット積では、5バイト: +/ .*

テストケース

   f =: [: +/ *"#:~
   (3 3$1 2 3 2 3 4 3 4 5)f(3 2$1 4 3 1 4 6)
19 24
27 35
35 46
   (3 3$1 2 3 2 3 4 3 4 5);(3 2$1 4 3 1 4 6)
+-----+---+
|1 2 3|1 4|
|2 3 4|3 1|
|3 4 5|4 6|
+-----+---+
   (2 2$2 3 3 4)f(2 2$3 5 3 1)
15 13
21 19
   (2 2$2 3 3 4);(2 2$3 5 3 1)
+---+---+
|2 3|3 5|
|3 4|3 1|
+---+---+

私はちょうどつまずいた[:+/*"#:~9バイトのために
マイル

@マイルズ壮観!
コナーオブライエン



2

R、66バイト

function(A,B)apply(B,2,function(i)apply(A,1,function(j)sum(j*i)))

入力として2つのR行列を使用し、製品を返す名前のない関数。それはで利用可能apply配列の余白全体に機能を適用するために使用されているが。forこの場合、ダブルループとして機能します。の各列Bとの各行に対してA、(ベクトル化された)積の合計を返します。

純粋なforループアプローチ(101バイト)と比較してください。

function(A,B){M=matrix(NA,m<-nrow(A),n<-ncol(B));for(i in 1:n)for(j in 1:m)M[j,i]=sum(A[j,]*B[,i]);M}

現時点では私のデスクトップではありませんがouter(A,B,`*`)、埋め込みapply呼び出しではなく何かをすることはできませんか?
-rturnbull

@rturnbullマトリックスと組み合わせてアウターがどのように機能するかはわかりませんが、この場合は4次元配列を生成します。
ビリーウォブ

ああ、それは少し問題です。マトリックスの線形化には、ここでのアプローチよりも多くのバイトが必要になる可能性があります
-rturnbull

2

Mathematica、20バイト

Inner[1##&,##,Plus]&

無名関数。2つのランク2の数値リストを入力として受け取り、ランク2の数値リストを出力として返します。好奇心For盛なInner人のために、2つのテンソルに2つの関数を行列乗算のように適用する関数です。


私は... Inner[1##&,##]&と同等だと思いInner[1##&,##,Plus]&ますか?そして、1##&~Inner~##&さらに良いでしょう。
グレッグマーティン

2

C#、168 167バイト

(A,B)=>{int n=A.Length,p=B[0].Length,i=0,j=0,k=0,s;var R=new int[n,p];while(i++<n)for(j=0;j<p;){s=0;for(k=0;k<A[0].Length;)s+=A[i][k]*B[k++][j];R[i,j++]=s;}return R;};

@Mukul Kumarに1バイトを節約してくれてありがとう、whileループは実際には今回より短くなりました:P

テストケースを含む完全なプログラム:

using System;
class Matrix
{
    static void Main()
    {
        Func<int[][], int[][], int[,]> a = null;

        a = (A,B)=>
        {
            int n=A.Length,p=B[0].Length,i=0,j=0,k=0,s;
            var R=new int[n,p];
            while(i++<n)
                for(j=0;j<p;)
                {
                    s=0;
                    for(k=0;k<A[0].Length;)
                        s+=A[i][k]*B[k++][j];
                    R[i,j++]=s;
                }
            return R;
        };

        int[,] t1 = a(new int[][] { new int[] { 1, 2 }, new int[] { 3, 4 }, new int[] { 5, 6 } },
            new int[][] { new int[] { 1, 2, 3, 4, 5 }, new int[] { 6, 7, 8, 9, 10 } } );
        int[,] t2 = a(new int[][] { new int[] { 2, 3 }, new int[] { 3, 4 } },
            new int[][] { new int[] { 3, 5 }, new int[] { 3, 1 } });
        int[,] t3 = a(new int[][] { new int[] { 5, 3 }, new int[] { 1, 3 }, new int[] { 9, 3 }, new int[] { 1, -1000 } },
            new int[][] { new int[] { 1, 3 }, new int[] { 2, 4 } });

        Console.WriteLine(IsCorrect(t1, new int[,] { { 13, 16, 19, 22, 25 }, { 27, 34, 41, 48, 55 }, { 41, 52, 63, 74, 85 } } ));
        Console.WriteLine(IsCorrect(t2, new int[,] { { 15, 13 }, { 21, 19 } } ));
        Console.WriteLine(IsCorrect(t3, new int[,] { { 11, 27 }, { 7, 15 }, { 15, 39 }, { -1999, -3997 } } ));

        Console.Read();
    }

    static bool IsCorrect(int[,] answer, int[,] valid)
    {
        if (answer.Length != valid.Length)
            return false;
        for (int i = 0; i < answer.GetLength(0); i++)
            for (int j = 0; j < answer.GetLength(1); j++)
                if (answer[i, j] != valid[i, j])
                    return false;
        return true;
    }
}

あなたは....ループしながら使用していくつかのバイトをトリミングすることができます
Mukulクマール

@MukulKumar待って、私はそうは思わない。せいぜい、彼らは右に壊れますか? for(;i<n;)-> while(i<n)は両方とも10バイトです。
ヨドル

1
for (;i <n;i++) - > while (i++<n)1バイトの節約
Mukulクマール

私がかなり異なる答えを持っているときのエチケットはわかりませんが、私の代替案は間違いなくこれに触発されました。
カークブロードハースト

2

MATL12 11バイト

7L&!*Xs6Be!

行列は;、行セパレータとして使用して入力されます。

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

組み込みなしの行列乗算は言語のショーケースに対する私の答えの一部でした。ただし、この回答で元のコードを再利用しようとすると、バグがあることがわかりました(行ベクトル出力が列ベクトルに誤って変換されました)。これは、こことそこの両方で修正されました。コードの仕組みの説明については、参照記事(長さ11のスニペット)を参照してください。


2

C ++ 14、173の 168 156 146バイト

  • 参照パラメーター経由で返す場合は-5バイト
  • foreachを使用してC.back()代わりにカウントする場合は-12バイトi
  • ドロップして開始時に空にするC.clear()必要Cがある場合は-10バイト

名前のないラムダとして:

[](auto A,auto B,auto&C){int j,k,s=B[0].size();for(auto a:A){C.emplace_back(s);for(j=-1;++j<s;)for(k=-1;++k<B.size();C.back()[j]+=a[k]*B[k][j]);}}

入出力が必要です vector<vector<int>>、出力は事前に空である必要があります。

ゴルフをしていない:

auto f=
[](auto A, auto B, auto&C){
 int j,k,s=B[0].size();
 for (auto a:A){
  C.emplace_back(s);
  for (j=-1;++j<s;)
   for (k=-1;++k<B.size();
    C.back()[j]+=a[k]*B[k][j]
   );
 }
}
;

サンプル:

int main() {
 using M=std::vector<std::vector<int>>;
 M a = {
  {1,2,3},
  {2,3,4},
  {3,4,5},
 };
 M b = {
  {1,4},
  {3,1},
  {4,6},
 };
 M c;
 f(a,b,c);
 for (auto&r:c){
  for (auto&i:r) std::cout << i << ", ";
  std::cout << "\n";
 }
}

push_back()代わりに使用しないのはなぜemplace_back()ですか?
G. Sliepen

2

7 6バイト

mMδṁ*T

引数の順序に注意してください、オンライン試してください!

@Zgarbのおかげで-1バイト!

説明

基本的には、行列乗算の定義が意味することを行うだけです:

mMδṁ*T  -- takes arguments in reverse order, eg: [[1],[0],[-1]] [[1,2,3],[4,5,6]]
     T  -- transpose the first argument: [[1,0,-1]] [[1,2,3],[4,5,6]]
m       -- map the following function (example element [1,0,-1])
 M      --   map the following function applied to [1,0,-1] (example element [1,2,3])
  δṁ    --     accumulate a sum of element-wise..
    *    --    ..multiplication: -2
          -- [[-2],[-2]]

1
oΣzすることができδṁ
Zgarb

1

JavaScript(ES6)、66バイト

(a,b)=>a.map(c=>b[0].map((_,i)=>b.reduce((s,d,j)=>s+d[i]*c[j],0)))

1

C#、131バイト

(A,B)=>new List<List<int>>(A.Select(x=>new List<int>
    (B[0].Select((f,i)=>B.Select(r=>r[i])).Select(y=>x.Zip(y,(p,q)=>p*q).Sum()))));

Yodleのソリューションを盗みましたを、LINQを使用して(forループとは対照的に)より効率的に記述できると仮定して。いくつかの試みをしましたが、それを幾分圧縮しました。

ここでそれはいくらか分解されます:

a = (A, B) => new List<List<int>>(
            from x in A
            select new List<int>(
                from y in B.First().Select((f, i) => B.Select(r => r.ElementAt(i)))
                select x.Zip(y, (p, q) => p * q).Sum()));

ここでの唯一の本当の「トリック」は、行列の転置ですB.First().Select((f, i) => B.Select(r => r.ElementAt(i)))。2番目の行列を転置すると、2つの配列A[i,x]とができB[j,x]ます。デカルト積(i*j)を取得し、それぞれをZipしますx長さの配列を一緒に圧縮します。

テストコード:

using System;
class Matrix
{
    static void Main()
    {
        Func<int[][], int[][], List<List<int>>> a = null;
        a = (A, B) => new List<List<int>>(A.Select(x => new List<int>(B[0].Select((f, i) => B.Select(r => r[i])).Select(y => x.Zip(y, (p, q) => p * q).Sum()))));

        List<List<int>> t1 = a(new int[][] { new int[] { 1, 2 }, new int[] { 3, 4 }, new int[] { 5, 6 } },
            new int[][] { new int[] { 1, 2, 3, 4, 5 }, new int[] { 6, 7, 8, 9, 10 } });
        List<List<int>> t2 = a(new int[][] { new int[] { 2, 3 }, new int[] { 3, 4 } },
            new int[][] { new int[] { 3, 5 }, new int[] { 3, 1 } });
        List<List<int>> t3 = a(new int[][] { new int[] { 5, 3 }, new int[] { 1, 3 }, new int[] { 9, 3 }, new int[] { 1, -1000 } },
            new int[][] { new int[] { 1, 3 }, new int[] { 2, 4 } });

        Console.WriteLine(IsCorrect(t1, new int[,] { { 13, 16, 19, 22, 25 }, { 27, 34, 41, 48, 55 }, { 41, 52, 63, 74, 85 } }));
        Console.WriteLine(IsCorrect(t2, new int[,] { { 15, 13 }, { 21, 19 } }));
        Console.WriteLine(IsCorrect(t3, new int[,] { { 11, 27 }, { 7, 15 }, { 15, 39 }, { -1999, -3997 } }));

        Console.Read();
    }

    static bool IsCorrect(List<List<int>> answer, int[,] valid)
    {
        if (answer.Count*answer[0].Count != valid.Length)
            return false;
        for (int i = 0; i < answer.Count; i++)
            for (int j = 0; j < answer[0].Count; j++)
                if (answer[i][j] != valid[i, j])
                    return false;
        return true;
    }

}

Nice:P Linqをそれほど使用したことがないので、Linqのすべての機能を十分に認識していないので、標準のループなどを使用する傾向があります。ただし、System.Linqの使用を含める必要があると思います。あなたのバイト数の行、それがどれだけそれに影響するかわからない。
ヨドル

@Yodleはい、含める必要がありusing System.Linqます。私はここでの解決策は次のように定型文を含める必要がある場合はわからないusing Systemし、static void Main()
カーク・ブロードハースト

私は今少し答えていますが、私が見たところから、プログラムに貼り付けた場合、基本的にあなたの答え(バイト数に含まれるものは何でも)が機能しなければなりません。特にC#の場合、関数のみを記述している場合は、クラス定義や静的なvoid Main()を含める必要はありませんが、ソリューションでConsole.WriteLine()などのライブラリを使用する場合は、 System.Console.WriteLine()またはusing System; 短いかもしれないからです。
ヨドル

1

Haskell、49バイト

z=zipWith
m a=map(\x->foldr1(z(+))$z(map.(*))x a)

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

入力と出力は列のリストです。2番目の行列の各列をその行にマッピングし、最初の行列の列で圧縮し、それぞれをスケーリングし、ベクトルとして合計します。

このポイントフリーを実現し、数バイトを節約する良い方法があるはずだと思いますが、まだ見ていません。


0

Javascript、128バイト

m=(a,b)=>{$=[];q=0;for(x in b){c=[];j=0;for(y in a[0]){_=i=0;for(z in b[0]){_+=a[i][j]*b[q][i];i++}c.push(_);j++}$.push(c);q++}}

$をチェックするだけで結果が得られます-ちょっとごまかしていますが、ちょっと、数バイト節約できました。


0

PHP、110バイト

function f($a,$b){foreach($a as$n=>$x)foreach($b as$m=>$y)foreach($y as$p=>$v)$z[$n][$p]+=$v*$x[$m];return$z;}

elven配列用の3つのループ。これは非常に簡単です...しかし、ゴルフにはあまりありません。


0

実は、14バイト

ゴルフの提案を歓迎します!オンラインでお試しください!

┬@;l)∙`i♀*Σ`M╡

アンゴルフ

         Implicit input A, then B.
┬        Transpose B's rows and columns. Call it B_T.
@        Swap A to TOS.
;l)      Get len(A) and move to BOS for later.
∙        Push the Cartesian product of A and B_T. Call it cart_prod.
`...`M   Map the following function over cart_prod. Variable xs.
  i        Flatten xs onto the stack, getting a row of A and column of B.
  ♀*       Multiply each element of A_row by each element of B_column.
  Σ        Sum the resulting list to get an element of A*B.
         The result of the map returns every element of A*B, but in one flat list.
╡        Push a list containing len(A) non-overlapping sublists of A*B.
         This separates A*B into rows.
         Implicit return.

0

C、618バイト

M(char*a,char*b){char*P[2];P[0]=malloc(strlen(a));P[1]=malloc(strlen(b));for(int A=0;A<strlen(a);A++){P[0][A]=a[A];};for(int B=0;B<strlen(b);B++){P[1][B]=b[B];};int H[200][200],B[200][200];int O,N,m,J;for(int Y=0;Y<2;Y++){int y=0,z=0,r=0;char j[7];int p=strlen(P[Y]);for(int i=0;i<=p;i++){if(P[Y][i]==' '||P[Y][i]==','||i==p){(Y<1)?H[y][z]=atoi(j):(B[y][z]=atoi(j));memset(j,'\0',4);(P[Y][i]==' ')?z++:y++;z=(P[Y][i]==',')?0:z;r=0;}else{j[r]=P[Y][i];r++;};};(Y<1)?O=z+1,N=y:(m=y,J=z+1);};for(int U=0;U<N;U++){for(int F=0;F<J;F++){int T=0;for(int d=0;d<O;d++){T+=H[U][d]*B[d][F];};printf("%d ",T);T=0;};printf("\n");};}

名前付き関数と断然部分的にC 2次元整数配列に文字列の入力を変換すると、ほとんどのバイトを取っているという事実に、ここで最長の提出、そしてまた私が最も長い時間にCにgolfedていないため。私はできる限りこれを短縮する作業を続けており、そのためのヒントは大歓迎です。

さて、これは邪魔にならないので、コマンドラインから入力を受け取り、2つの行列は2つの文字列で表され、各行にはコンマで区切られた行が含まれ、各行はスペースで区切られた整数で表されます。たとえば、行列は次のとおりです。

   1 2 3     44 52
A= 4 5 6  B= 67 -79
   7 8 9     83 90

次のように入力されます。

./a.out "1 2 3,4 5 6,7 8 9" "44 52,67 -79,83 90"

結果の行列は、複数行の文字列としてSTDOUTに出力されます。たとえば、上記の入力の出力は次のようになります。

 427 164 
1009 353 
1591 542 

TIO 539バイト
girobuz

0

Clojure、60バイト

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

2番目の引数の転置に多くのバイトが費やされました。


弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.