Lakukan Penggandaan Matriks!

14

Dalam matematika, perkalian matriks atau produk matriks adalah operasi biner yang menghasilkan matriks dari dua matriks. Definisi ini dimotivasi oleh persamaan linear dan transformasi linear pada vektor, yang memiliki banyak aplikasi dalam matematika terapan, fisika, dan teknik. Secara lebih rinci, jika A adalah matriks n × m dan B adalah matriks m × p, produk matriks mereka AB adalah matriks n × p, di mana entri m melintasi baris A dikalikan dengan entri m ke bawah kolom B dan dijumlahkan untuk menghasilkan entri AB. Ketika dua transformasi linier diwakili oleh matriks, maka produk matriks mewakili komposisi dua transformasi.

Sumber: Wikipedia

Dengan kata lain, untuk mengalikan dua matriks, misalnya:

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

Pertama, ambil baris nomor 1 di matriks pertama, nomor kolom 1 di matriks kedua, dan kalikan 1dengan 1, 2oleh 3, dan 3oleh 4.

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

Sekarang tambahkan mereka bersama untuk mendapatkan item pertama Anda:

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

Untuk angka kedua di kolom pertama hasil, Anda harus mengambil nomor baris 2 daripada nomor baris 1 dan melakukan hal yang sama.

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

Setelah Anda melakukan seluruh kolom pertama, hasilnya terlihat seperti ini:

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

Sekarang, lakukan hal yang persis sama lagi, tetapi ambil kolom kedua alih-alih kolom pertama, menghasilkan:

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

Tugas Anda

Diberi dua matriks (dimensi maksimum 200x200), yang berisi angka dalam rentang -10000 hingga 10.000, di mana jumlah kolom pada yang pertama sama dengan jumlah baris pada yang kedua, kalikan yang pertama dengan yang kedua. (Perkalian matriks adalah non-komutatif.)

Anda dapat mengambil input dan memberikan output sebagai array array (atau setara), sebuah matriks (jika bahasa Anda memiliki format itu) atau string multiline.

Anda tidak boleh menggunakan bawaan untuk multiplikasi matriks.

Uji kasus

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

Ingat, ini adalah , jadi kode dengan byte paling sedikit menang.

Oliver Ni
sumber
Bisakah kita menggunakan produk dot bawaan? Mereka beroperasi pada vektor, bukan matriks.
Dennis
1
Apakah urutan input sudah diperbaiki atau bisakah kita mengambil a dan b dalam urutan dan output itu b × a ?
Dennis
@ Dennis Anda dapat membalikkan input, tetapi tidak ada produk titik
Oliver Ni
4
Tantangan melakukan X tanpa Y tidak disarankan .
flawr
Bisakah matriks input berisi angka floating point? Jika demikian, saya sarankan menambahkan beberapa test case.
R. Kap

Jawaban:

5

Jelly , 7 5 byte

Z×þḅ1

Membawa B dan A sebagai argumen dan mengembalikan A × B .

Cobalah online!

Bagaimana itu bekerja

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.
Dennis
sumber
3
Jadi tunggu, built-in dan cara manual untuk mengalikan matriks akhirnya menjadi jumlah byte yang sama di Jelly? Itu membingungkan, tapi keren.
Yodle
@Yodle Built-in adalah æ×, yaitu 2 byte.
Erik the Outgolfer
@EriktheOutgolfer Itu mengacu pada revisi 2, yang menggunakan æ.atom.
Dennis
4

05AB1E , 13 byte

vyU²øvyX*O})ˆ

Cobalah online!

Penjelasan

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
Emigna
sumber
Dapat 7 byte sekarang dengan pendekatan yang sama persis:εUøεX*O
Kevin Cruijssen
4

Python 2, 69 66 Bytes

Ini hanya mengikuti rumus standar, tetapi lambda-d untuk keringkasan :) Kode ungolfed sangat mudah!

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

Terima kasih kepada Alexi Torhamo karena telah menghemat 3 byte! :)

Kode tidak dikunci:

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
Kade
sumber
Anda bisa menggunakannya sum(map(int.__mul__,r,c))untuk menyimpan 3 byte. (Tidak akan bekerja dengan floating point, tapi itu juga tidak diperlukan)
Aleksi Torhamo
3

J, 13 9 byte

Disimpan 4 byte berkat mil!

[:+/*"#:~

Ini adalah garpu tertutup:

[: +/ *"#:~

Yang setara dengan:

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

Yang melakukan perkalian yang diinginkan; ini kemudian disimpulkan.

Dengan produk titik bawaan, 5 byte: +/ .*

Uji kasus

   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|
+---+---+
Conor O'Brien
sumber
Saya baru saja menemukan [:+/*"#:~9 byte
mil
@miles spektakuler!
Conor O'Brien
3

Haskell , 57 56 54 byte

e=[]:e
z=zipWith
a!b=[sum.z(*)r<$>foldr(z(:))e b|r<-a]

Cobalah online!

Pemakaian:

Prelude> [[1,2],[3,4],[5,6]] ! [[1,2,3,4,5],[6,7,8,9,10]]
[[13,16,19,22,25],[27,34,41,48,55],[41,52,63,74,85]]

foldr(zipWith(:))edengan e=[]:eadalah bentuk yang lebih pendek dari transpose.

Laikoni
sumber
3

Haskell , 45 byte

map.(foldr1(z(+)).).flip(z$map.(*))
z=zipWith

Cobalah online!

Membawa argumen dalam urutan terbalik.

Tidak
sumber
2

R, 66 byte

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

Fungsi tanpa nama mengambil dua matriks R sebagai input dan mengembalikan produk. Itu memanfaatkan applyyang digunakan untuk menerapkan fungsi di seluruh margin array. Ini berfungsi seperti forloop ganda dalam kasus ini: untuk setiap kolom Bdan untuk setiap baris A, kembalikan jumlah produk (yang di-vektor-kan).

Bandingkan dengan pendekatan pure for loop ( 101bytes):

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}
Billywob
sumber
Tidak di desktop saya saat ini, tetapi tidak bisakah Anda melakukan sesuatu seperti panggilan outer(A,B,`*`)tertanam apply?
rturnbull
@ Artbullull Saya tidak yakin bagaimana luar bekerja bersama dengan matriks tetapi akan menghasilkan array 4-D dalam kasus ini.
Billywob
Ah ya, itu agak bermasalah. Linearisasi matriks kemungkinan akan membutuhkan lebih banyak byte daripada pendekatan Anda di sini
rturnbull
2

Mathematica, 20 byte

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

Fungsi anonim. Mengambil dua daftar nomor-2 angka sebagai input, dan mengembalikan daftar nomor-2 angka sebagai output. Bagi mereka yang penasaran, Inneradalah fungsi yang melakukan aplikasi seperti dua-perkalian-matriks dari dua fungsi ke dua tensor.

LegionMammal978
sumber
Saya percaya Inner[1##&,##]&setara dengan Inner[1##&,##,Plus]&...? Dan 1##&~Inner~##&akan lebih baik lagi.
Greg Martin
2

C #, 168 167 byte

(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;};

Terima kasih @Mukul Kumar untuk menghemat 1 byte, loop sementara sebenarnya lebih pendek kali ini: P

Program lengkap dengan uji kasus:

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;
    }
}
Yodle
sumber
Anda dapat memotong beberapa byte dengan menggunakan while ...
Mukul Kumar
@MukulKumar Tunggu, kurasa tidak. Paling-paling, mereka impas kan? for(;i<n;)-> while(i<n)keduanya 10 byte.
Yodle
1
for (;i <n;i++) -> while (i++<n)menghemat 1 byte
Mukul Kumar
Tidak yakin dengan etiket ketika saya memiliki jawaban yang cukup berbeda, tetapi alternatif saya sangat terinspirasi oleh ini.
Kirk Broadhurst
2

MATL , 12 11 byte

7L&!*Xs6Be!

Matriks adalah input yang digunakan ;sebagai pemisah baris.

Cobalah online!

Perkalian matriks tanpa builtin adalah bagian dari jawaban saya untuk Showcase of languages . Namun, ketika mencoba untuk menggunakan kembali kode asli untuk jawaban ini saya menyadari itu memiliki bug (output vektor baris salah dikonversi ke vektor kolom). Ini sekarang diperbaiki, baik di sana-sini. Untuk penjelasan tentang bagaimana kode bekerja, lihat posting yang dirujuk (panjang-11 cuplikan).

Luis Mendo
sumber
2

C ++ 14, 173 168 156 146 byte

  • -5 byte untuk kembali melalui parameter referensi
  • -12 byte untuk menggunakan foreach dan C.back()bukannya mengandalkani
  • -10 byte untuk dijatuhkan C.clear()dan Charus kosong di awal

Sebagai lambda yang tidak disebutkan namanya:

[](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]);}}

Membutuhkan input dan output karena vector<vector<int>>dan output harus kosong sebelumnya.

Tidak Disatukan:

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]
   );
 }
}
;

Sampel:

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";
 }
}
Karl Napf
sumber
Mengapa tidak menggunakan push_back()bukan emplace_back()?
G. Sliepen
2

Sekam , 7 6 byte

mMδṁ*T

Harap perhatikan urutan argumen, coba online!

-1 byte terima kasih kepada @Zgarb!

Penjelasan

Pada dasarnya hanya melakukan apa definisi sais matrix-multiplikasi:

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]]
ბიმო
sumber
1
oΣzbisaδṁ
Zgarb
1

JavaScript (ES6), 66 byte

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

C #, 131 byte

(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()))));

aku mencuri solusi Yodle dengan asumsi bahwa saya bisa menulis ini lebih efisien menggunakan LINQ (bukan untuk loop). Mengambil beberapa upaya tetapi agak meremehkannya.

Di sini agak rusak:

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()));

Satu-satunya 'trik' nyata di sini adalah matriks transpos B.First().Select((f, i) => B.Select(r => r.ElementAt(i))),. Setelah kami memindahkan matriks kedua, kami memiliki dua array A[i,x]danB[j,x] . Ambil produk kartesius ( i*j) dan Zip masing-masing xarray panjang itu bersama-sama.

Kode uji:

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;
    }

}
Kirk Broadhurst
sumber
Nice: P Saya belum pernah benar-benar menggunakan Linq sebanyak itu, jadi saya tidak sepenuhnya menyadari semua kemampuannya sehingga saya cenderung hanya menggunakan loop dan hal-hal standar. Namun, saya pikir Anda harus memasukkan menggunakan System.Linq; baris dalam jumlah byte Anda, tidak yakin seberapa besar pengaruhnya.
Yodle
@Yodle ya saya harus memasukkan using System.Linq; Saya tidak yakin apakah solusi di sini perlu menyertakan boilerplate like using Systemdanstatic void Main()
Kirk Broadhurst
Saya telah menjawab sedikit sekarang, dan dari apa yang saya lihat, pada dasarnya jawaban Anda (apa pun yang termasuk dalam jumlah byte Anda) harus berfungsi jika Anda hanya menempelkannya ke dalam sebuah program. Khusus untuk C #, jika Anda hanya menulis fungsi maka Anda tidak perlu menyertakan definisi kelas atau hal-hal statis (), tetapi jika solusi Anda menggunakan hal-hal perpustakaan seperti Console.WriteLine () maka Anda harus melakukan System.Console.WriteLine () atau menggunakan System; karena seseorang mungkin lebih pendek.
Yodle
1

Haskell , 49 byte

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

Cobalah online!

Input dan output adalah daftar kolom. Memetakan setiap kolom dari matriks kedua ke baris itu, di-zip dengan kolom-kolom dari matriks pertama dan menskalakan masing-masing, dijumlahkan sebagai vektor.

Saya merasa bahwa pasti ada cara yang bagus untuk membuat pointfree ini dan menghemat beberapa byte, tetapi saya belum melihatnya.

Khuldraeseth na'Barya
sumber
0

Javascript, 128 byte

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++}}

Anda mendapatkan hasilnya hanya dengan memeriksa $ - ini agak curang, tapi hei, ini menghemat beberapa byte.

Marcus Dirr
sumber
0

PHP, 110 byte

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;}

Tiga loop untuk array elf. Ini sangat lurus ke depan ... tapi tidak banyak golf.

Titus
sumber
0

Sebenarnya , 14 byte

Selamat datang saran bermain golf! Cobalah online!

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

Tidak melakukanolf

         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.
Sherlock9
sumber
0

C, 618 byte

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");};}

Fungsi bernama dan sejauh ini pengajuan terpanjang di sini, sebagian karena fakta bahwa mengubah input array karakter menjadi array integer C 2-dimensi adalah yang paling banyak byte, dan juga karena saya belum bermain golf di C dalam waktu yang lama. Saya masih berusaha memperpendek ini sebanyak yang saya bisa, dan setiap tips dalam melakukannya sangat dihargai.

Sekarang, dengan keluar dari jalan, ini mengambil input melalui baris perintah dengan dua matriks diwakili oleh dua string, dengan masing-masing berisi baris yang dipisahkan oleh koma dan setiap baris diwakili oleh spasi yang dipisahkan bilangan bulat. Misalnya, matriks:

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

akan dimasukkan sebagai:

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

Matriks yang dihasilkan adalah output ke STDOUT sebagai string multiline. Misalnya, output untuk input di atas adalah:

 427 164 
1009 353 
1591 542 
R. Kap
sumber
TIO 539 bytes
girobuz
0

Clojure, 60 byte

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

Banyak byte yang dihabiskan untuk mentransposisi argumen ke-2.

NikoNyrh
sumber