Matris Çarpımı Yapın!


14

Matematikte, matris çarpımı veya matris ürünü, iki matristen bir matris üreten bir ikili işlemdir. Tanım, uygulamalı matematik, fizik ve mühendislikte çok sayıda uygulamaya sahip olan doğrusal denklemler ve vektörler üzerindeki doğrusal dönüşümler tarafından motive edilir. Daha ayrıntılı olarak, eğer A bir n × m matrisi ve B bir m × p matrisi ise, onların matris ürünü AB bir n × p matrisidir, burada A satırındaki m girişleri a girişleri ile m girişleri ile çarpılır. B sütunları ve AB girişi üretmek için toplandı. İki doğrusal dönüşüm matrislerle temsil edildiğinde, matris ürünü iki dönüşümün bileşimini temsil eder.

Kaynak: Wikipedia

Başka bir deyişle, iki matrisi çarpmak için, örneğin:

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

Birinci, ikinci matris içinde ilk matris içinde satır numarası 1, sütun 1 nolu ve çarpma 1ile 1, 2ile 3, ve 3ile 4.

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

Şimdi ilk öğenizi almak için bunları ekleyin:

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

Sonucun ilk sütunundaki ikinci sayı için, 1 numaralı satır yerine 2 numaralı satırı almanız ve aynı işlemi yapmanız gerekir.

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

İlk sütunun tamamını yaptıktan sonra sonuç şöyle görünür:

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

Şimdi, aynı şeyi tekrar yapın, ancak ilk sütun yerine ikinci sütunu alın ve bunun sonucunda:

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

Senin görevin

-10000 ila 10000 aralığındaki sayıları içeren iki matris (maksimum boyutlar 200x200) verildiğinde, birincideki sütun sayısının ikincideki satır sayısına eşit olması, birincisini ikincisi ile çarpın. (Matris çarpımı değişmeli değildir.)

Girdileri alabilir ve diziler dizisi (veya eşdeğeri), bir matris (diliniz bu biçime sahipse) veya çok satırlı bir dize olarak verebilirsiniz.

Matris çarpımı için herhangi bir yerleşik kullanamazsınız.

Test senaryoları

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

Unutmayın, bu , bu yüzden en az baytlık kod kazanır.


Yerleşik nokta ürünlerini kullanabilir miyiz? Matrisler üzerinde değil vektörler üzerinde çalışırlar.
Dennis

1
Giriş sırası sabit mi yoksa a ve b'yi bu sırayla alabilir ve b × a çıktısını alabilir miyiz ?
Dennis

@Dennis Girdiyi tersine çevirebilirsiniz, ancak nokta ürün yok
Oliver Ni

4
Hakkında Zorluklar Y olmadan X'i yapıyor olan cesareti .
flawr

Giriş matrisleri kayan nokta sayıları içerebilir mi? Öyleyse, bazılarıyla test senaryosu eklemenizi öneririm.
R. Kap

Yanıtlar:


5

Jöle , 7 5 bayt

Z×þḅ1

Alır B ve A , bağımsız değişken olarak ve döner bir x B .

Çevrimiçi deneyin!

Nasıl çalışır

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
Öyleyse bekleyin, matrisleri çarpmanın yerleşik ve manuel yolu Jelly'de aynı sayıda bayt olur mu? Bu kafa karıştırıcı, ama havalı.
Yodle

@Yodle Yerleşik æ×, 2 bayttır.
Outgolfer Erik

@EriktheOutgolfer Bu, æ.atomu kullanan revizyon 2'ye referanstı .
Dennis

4

05AB1E , 13 bayt

vyU²øvyX*O})ˆ

Çevrimiçi deneyin!

açıklama

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

Aynı yaklaşımla şimdi 7 bayt olabilir:εUøεX*O
Kevin Cruijssen

4

Python 2, 69 66 Bayt

Bu sadece standart formülü takip eder, ancak kısalık için lambda-d :) Çözülmemiş kod son derece basittir!

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

3 bayt kazandığı için Alexi Torhamo'ya teşekkürler! :)

Kod çözülmemiş kod:

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 bayt kaydetmek için kullanabilirsiniz . (Kayan nokta ile çalışmaz, ancak bu da gerekli değildi)
Aleksi Torhamo

3

J, 13 9 bayt

Mil sayesinde 4 bayt kaydedildi!

[:+/*"#:~

Bu kapaklı bir çatal:

[: +/ *"#:~

Şuna eşittir:

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

Hangi istenen çarpımı gerçekleştirir; bunlar toplanır.

Yerleşik bir nokta ürünü ile 5 bayt: +/ .*

Test senaryoları

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

Sadece [:+/*"#:~9 bayt için tökezledim
mil

@miles muhteşem!
Conor O'Brien

3

Haskell , 57 56 54 bayt

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

Çevrimiçi deneyin!

Kullanımı:

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(:))eile e=[]:edaha kısa bir biçimidir transpose.



2

R, 66 bayt

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

Adsız işlev, iki R matrisini girdi olarak alır ve ürünü döndürür. Bu yararlanır applyDizilerin marjlar karşısında fonksiyonlarını uygulamak için kullanıldığı. forBu durumda sadece bir çift döngü olarak çalışır : her bir sütunun Bve her bir satır Aiçin (vectorized) ürünlerin toplamını döndürün.

Saf döngü için yaklaşımla ( 101bayt) karşılaştırın:

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}

Şu anda masaüstümde değil outer(A,B,`*`), katıştırılmış applyaramalar yerine böyle bir şey yapamaz mıydınız?
rturnbull

@rturnbull Dış matrislerle birlikte nasıl çalıştığından emin değilim ama bu durumda 4 boyutlu bir dizi üretecekti.
Billywob

Ah evet, bu biraz sorunlu. Matrislerin
doğrusallaştırılması

2

Mathematica, 20 bayt

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

Anonim işlev. Giriş olarak iki rütbe-2 sayı listesi alır ve çıktı olarak rütbe-2 sayı listesi döndürür. Bu merak için, Innerbir matris çarpımını gibi iki tansörlerine iki fonksiyonun uygulanması yapan bir fonksiyonudur.


Inner[1##&,##]&Eşdeğer olduğuna inanıyorum Inner[1##&,##,Plus]&...? Ve böylece 1##&~Inner~##&daha da iyi olurdu.
Greg Martin

2

C #, 168 167 bayt

(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'a 1 bayt kaydettiğiniz için teşekkür ederiz, while döngüsü bu sefer aslında daha kısaydı: P

Test senaryolarıyla birlikte tam program:

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

While döngülerini kullanarak birkaç bayt kırpabilirsiniz ....
Mukul Kumar

@MukulKumar Bekle, sanmıyorum. En fazla kırıldılar değil mi? for(;i<n;)-> while(i<n)her ikisi de 10 bayttır.
Yodle

1
for (;i <n;i++) -> while (i++<n)1 bayt kurtardı
Mukul Kumar

Oldukça farklı bir cevabım olduğunda görgü kuralından emin değilim, ama alternatifim kesinlikle bundan ilham aldı.
Kirk Broadhurst

2

MATL , 12 11 bayt

7L&!*Xs6Be!

Matrisler, ;satır ayırıcı olarak girilir .

Çevrimiçi deneyin!

Yerleşik olmadan matris çarpımı , dillerin Vitrini'ne verdiğim cevabın bir parçasıydı . Ancak, bu yanıt için orijinal kodu yeniden kullanmaya çalışırken bir hata olduğunu fark ettim (satır vektör çıktısı yanlış bir sütun vektörüne dönüştürüldü). Bu hem burada hem de orada düzeltildi. Kodun nasıl çalıştığına ilişkin açıklama için, atıfta bulunulan gönderiye (uzunluk-11 snippet'i) bakın.


2

C ++ 14, 173 168 156 146 bayt

  • Referans parametresi ile geri dönüş için -5 bayt
  • Foreach kullanmak ve C.back()bunun yerine güvenmek için -12 bayti
  • Düşürme C.clear()ve Cbaşlangıçta boş bırakılması gereken -10 bayt

İsimsiz lambda olarak:

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

Gibi giriş ve çıkış gerektirir ve çıkış vector<vector<int>>önceden boş olmalıdır.

Ungolfed:

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

Örneklem:

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

Neden push_back()yerine kullanmıyorsunuz emplace_back()?
G. Sliepen

2

Kabuk , 7 6 bayt

mMδṁ*T

Lütfen argüman sırasını not edin, çevrimiçi deneyin!

@Zgarb sayesinde -1 bayt!

açıklama

Temel olarak sadece matris çarpma sais tanımının ne yaptığını:

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Σzolabilirδṁ
Zgarb

1

JavaScript (ES6), 66 bayt

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

1

C #, 131 bayt

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

Lodq kullanarak (döngüler yerine) bunu daha verimli yazabileceğim varsayımı ile Yodle'ın çözümünü çaldım . Birkaç girişimde bulunmuş, ancak bir şekilde çıtırdamıştır.

Burada biraz parçalanmış:

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

Buradaki tek gerçek 'hile' matriks devrik B.First().Select((f, i) => B.Select(r => r.ElementAt(i))),. İkinci matrisi devraldığımızda, iki dizimiz var A[i,x]ve B[j,x]. Kartezyen ürünü ( i*j) alın ve bu xuzunluk dizilerinin her birini Sıkıştırın .

Test kodu:

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'i hiç bu kadar çok kullanmadım, bu yüzden tüm yeteneklerinin tam olarak farkında değilim, bu yüzden sadece standart döngüler ve şeyler kullanma eğilimindeyim. Ancak, ben System.Linq kullanarak eklemeniz gerektiğini düşünüyorum; bayt sayınızdaki satırı, bunun ne kadar etkilediğinden emin değilim.
Yodle

@Yodle evet dahil etmek gerekir using System.Linq; Burada çözümler Demirbaş gibi eklemeniz gereken değilim emin eğer using Systemvestatic void Main()
Kirk Broadhurst

Şimdi bir süredir cevap veriyorum ve gördüklerimden, temelde cevabınız (bayt sayınıza ne eklerseniz ekleyin) bir programa yapıştırdıysanız çalışması gerekir. Özellikle C # için, sadece bir işlev yazıyorsanız, sınıf tanımlarını veya statik void Main () öğelerini eklemeniz gerekmez, ancak çözümünüz Console.WriteLine () gibi herhangi bir kütüphane öğesi kullanıyorsa, yapmanız gerekir System.Console.WriteLine () veya System kullanarak; çünkü biri daha kısa olabilir.
Yodle

1

Haskell , 49 bayt

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

Çevrimiçi deneyin!

Girdi ve çıktı sütun listeleridir. İkinci matrisin her bir sütununu, ilk matrisin sütunlarıyla sıkıştırılmış ve her biri ölçeklendirilerek, bir vektör olarak toplanan bu satıra eşler.

Bu noktayı serbest bırakmanın ve bir avuç bayt kaydetmenin güzel bir yolu olması gerektiğini hissediyorum, ama henüz görmüyorum.


0

Javascript, 128 bayt

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

Sadece $ 'ı kontrol ederek sonucu elde edersiniz - biraz hile yapar, ama hey, birkaç bayt kurtardı.


0

PHP, 110 bayt

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

Elf dizileri için üç döngü. Bu çok basit ... ama golf için fazla bir şey yok.


0

Aslında 14 bayt

Golf önerileri hoş geldiniz! Çevrimiçi deneyin!

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

Ungolfing

         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 bayt

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

Bir adlandırılmış işlevi ve tarafından çok kısmen C2 boyutlu tamsayı diziler içine karakter dizisi girdileri dönüştürme çoğu bayt kaplıyor gerçeğine burada en uzun sunulması, ve ayrıca ben uzun zamandır C golfed değil çünkü. Hala bu kadar olabildiğince kısaltmak için çalışıyorum ve bunu yapmak için herhangi bir ipucu çok takdir edilmektedir.

Şimdi, bu çıkış yolu ile, bu, her biri virgülle ayrılmış satırları içeren ve her satır boşlukla ayrılmış tamsayılarla temsil edilen iki dizeyle temsil edilen iki matrisle komut satırından girdi alır. Örneğin, matrisler:

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

şu şekilde girilir:

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

Elde edilen matris STDOUT'a çok satırlı bir dize olarak çıkarılır. Örneğin, yukarıdaki giriş için çıkış:

 427 164 
1009 353 
1591 542 

TIO 539 bytes
girobuz

0

Clojure, 60 bayt

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

İkinci argümanın aktarılması için çok sayıda bayt harcandı.


Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.