Faça multiplicação de matrizes!

14

Em matemática, a multiplicação da matriz ou o produto da matriz é uma operação binária que produz uma matriz a partir de duas matrizes. A definição é motivada por equações lineares e transformações lineares em vetores, que têm inúmeras aplicações em matemática aplicada, física e engenharia. Mais detalhadamente, se A é uma matriz n × m e B é uma matriz m × p, o produto da matriz AB é uma matriz n × p, na qual as entradas m em uma linha de A são multiplicadas pelas entradas m em uma colunas de B e somadas para produzir uma entrada de AB. Quando duas transformações lineares são representadas por matrizes, o produto da matriz representa a composição das duas transformações.

Fonte: Wikipedia

Em outras palavras, multiplicar duas matrizes, por exemplo:

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

Primeiro, pegue o número da linha 1 na primeira matriz, o número da coluna 1 na segunda matriz e multiplique 1por 1, 2por 3e 3por4 .

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

Agora adicione-os para obter o seu primeiro item:

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

Para o segundo número na primeira coluna do resultado, você precisará pegar o número da linha 2 em vez da linha 1 e fazer a mesma coisa.

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

Depois de fazer a primeira coluna inteira, o resultado fica assim:

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

Agora, faça a mesma coisa exata novamente, mas pegue a segunda coluna em vez da primeira, resultando em:

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

Sua tarefa

Dadas duas matrizes (dimensões máximas 200x200), contendo números no intervalo -10000 a 10000, em que o número de colunas na primeira é igual ao número de linhas na segunda, multiplique a primeira pela segunda. (A multiplicação de matrizes não é comutativa.)

Você pode receber e fornecer saída como uma matriz de matrizes (ou equivalente), uma matriz (se o seu idioma tiver esse formato) ou uma sequência de linhas múltiplas.

Você não pode usar nenhum componente interno para multiplicação de matrizes.

Casos de teste

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

Lembre-se, isso é , então o código com o menor número de bytes vence.

Oliver Ni
fonte
Podemos usar produtos pontuais incorporados? Eles operam em vetores, não em matrizes.
Dennis
1
É a ordem de entrada fixo ou podemos tomar um e b por essa ordem e saída b × a ?
Dennis
@Dennis Você pode inverter a entrada, mas não há produtos com pontos #
Oliver Ni
4
Desafios sobre fazer X sem Y são desencorajados .
flawr
As matrizes de entrada podem conter números de ponto flutuante? Nesse caso, recomendo adicionar um caso de teste a alguns.
R. Kap

Respostas:

5

Geléia , 7 5 bytes

Z×þḅ1

Pega B e A como argumentos e retorna A × B .

Experimente online!

Como funciona

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
fonte
3
Então, espere, a maneira integrada e manual de multiplicar matrizes acaba sendo o mesmo número de bytes no Jelly? Isso é confuso, mas legal.
Yodle
@Yodle O built-in æ×é de 2 bytes.
Erik the Outgolfer
@EriktheOutgolfer Isso foi em referência à revisão 2, que usou o æ.átomo.
Dennis19 /
4

05AB1E , 13 bytes

vyU²øvyX*O})ˆ

Experimente online!

Explicaçã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
Emigna
fonte
Agora podem ter 7 bytes com a mesma abordagem:εUøεX*O
Kevin Cruijssen
4

Python 2, 69 66 bytes

Isso apenas segue a fórmula padrão, mas lambda-d por concisão :) O código não-bloqueado é extremamente direto!

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

Obrigado a Alexi Torhamo por salvar 3 bytes! :)

Código não destruído:

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
fonte
Você pode usar sum(map(int.__mul__,r,c))para salvar 3 bytes. (Não funciona com ponto flutuante, mas que não foi necessário, qualquer um)
Aleksi Torhamo
3

J, 13 9 bytes

Economizou 4 bytes graças a milhas!

[:+/*"#:~

Este é um garfo com tampa:

[: +/ *"#:~

O que equivale a:

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

Qual realiza a multiplicação desejada; estes são então somados.

Com um produto escalar incorporado, 5 bytes: +/ .*

Casos de teste

   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
fonte
Eu apenas tropecei em [:+/*"#:~9 bytes
milhas
@miles espetacular!
Conor O'Brien
3

Haskell , 57 56 54 bytes

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

Experimente online!

Uso:

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(:))ecom e=[]:eé uma forma mais curta de transpose.

Laikoni
fonte
3

Haskell , 45 bytes

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

Experimente online!

Recebe argumentos em ordem inversa.

xnor
fonte
2

R, 66 bytes

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

Função sem nome, tendo duas matrizes R como entrada e retornando o produto. Utiliza o applyque é usado para aplicar funções nas margens das matrizes. Funciona exatamente como um forloop duplo neste caso: para cada coluna de Be para cada linha de A, retorne a soma dos produtos (vetorizados).

Compare com a abordagem pura para 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
fonte
Não na minha área de trabalho no momento, mas você não poderia fazer algo parecido com outer(A,B,`*`)as applychamadas incorporadas ?
rturnbull
@rturnbull Não tenho certeza de como o exterior funciona em conjunto com matrizes, mas isso produziria uma matriz 4-D nesse caso.
Billywob
Ah, sim, isso é um pouco problemático. Linearização das matrizes provavelmente levaria mais bytes do que a sua abordagem aqui
rturnbull
2

Mathematica, 20 bytes

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

Função anônima. Pega duas listas de números de classificação 2 como entrada e retorna uma lista de números de classificação 2 como saída. Para os curiosos, Inneré uma função que faz uma aplicação semelhante à multiplicação de matrizes de duas funções a dois tensores.

LegionMammal978
fonte
Eu acredito que Inner[1##&,##]&é equivalente a Inner[1##&,##,Plus]&...? E assim 1##&~Inner~##&seria ainda melhor.
Greg Martin
2

C #, 168 167 bytes

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

Obrigado @Mukul Kumar por economizar 1 byte, o loop while foi realmente mais curto desta vez: P

Programa completo com casos de teste:

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
fonte
Você pode aparar alguns bytes usando while ....
Mukul Kumar
@MukulKumar Espere, acho que não. No máximo, eles quebram mesmo, certo? for(;i<n;)-> while(i<n)são ambos 10 bytes.
Yodle
1
for (;i <n;i++) -> while (i++<n)salva 1 byte
Mukul Kumar
Não tenho certeza da etiqueta quando tenho uma resposta bastante diferente, mas minha alternativa foi definitivamente inspirada por isso.
precisa
2

MATL , 12 11 bytes

7L&!*Xs6Be!

As matrizes são inseridas usando ;como separador de linhas.

Experimente online!

A multiplicação de matrizes sem o builtin fazia parte da minha resposta ao Showcase of languages . No entanto, ao tentar reutilizar o código original para esta resposta, percebi que havia um erro (a saída do vetor de linha foi convertida incorretamente em um vetor de coluna). Isso agora está corrigido, aqui e ali. Para obter uma explicação de como o código funciona, consulte a publicação referida (trecho de comprimento 11).

Luis Mendo
fonte
2

C ++ 14, 173 168 156 146 bytes

  • -5 bytes para retornar via parâmetro de referência
  • -12 bytes para usar o foreach e, em C.back()vez disso, contar comi
  • -10 bytes para descartar C.clear()e exigir Cque esteja vazio no início

Como lambda sem nome:

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

Requer entrada e saída, pois a vector<vector<int>>saída deve estar vazia previamente.

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

Amostra:

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
fonte
Por que não usar em push_back()vez de emplace_back()?
G. Sliepen 10/10/19
2

Casca , 7 6 bytes

mMδṁ*T

Observe a ordem dos argumentos, tente online!

-1 byte graças a @Zgarb!

Explicação

Basicamente, apenas fazendo o que a definição de multiplicação de matrizes sais:

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]]
ბიმო
fonte
1
oΣzpode serδṁ
Zgarb
1

JavaScript (ES6), 66 bytes

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

C #, 131 bytes

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

eu roubei a solução de Yodle com a suposição de que eu poderia escrever isso de maneira mais eficiente usando o LINQ (em vez de loops). Tomou algumas tentativas, mas a triturou um pouco.

Aqui está dividido um pouco:

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

O único "truque" real aqui é a transposição da matriz B.First().Select((f, i) => B.Select(r => r.ElementAt(i))),. Depois de transpormos a segunda matriz, temos duas matrizes A[i,x]eB[j,x] . Pegue o produto cartesiano ( i*j) e feche cada uma dessas xmatrizes de comprimento.

Código do teste:

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
fonte
Bom: P Eu realmente nunca usei muito o Linq, então não estou totalmente ciente de todos os recursos, então costumo usar loops e coisas padrão. No entanto, acho que você precisa incluir o using System.Linq; linha na sua contagem de bytes, não tenho certeza de quanto isso afeta.
Yodle
@Yodle sim, eu teria que incluir using System.Linq; Não tenho certeza se as soluções aqui precisam incluir clichês como using Systemestatic void Main()
Kirk Broadhurst
Estou respondendo um pouco agora e, pelo que vi, basicamente sua resposta (o que você incluir na contagem de bytes) terá que funcionar se você a colou em um programa. Para C # especificamente, se você estiver escrevendo apenas uma função, não precisará incluir definições de classe ou o item estático void Main (), mas se sua solução usar qualquer item de biblioteca como Console.WriteLine (), será necessário System.Console.WriteLine () ou using System; já que um pode ser mais curto.
Yodle
1

Haskell , 49 bytes

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

Experimente online!

Entrada e saída são listas de colunas. Mapeia cada coluna da segunda matriz para essa linha, compactada com as colunas da primeira matriz e dimensionando cada uma, somada como um vetor.

Eu sinto que deve haver uma boa maneira de tornar isso livre de pontos e salvar um punhado de bytes, mas ainda não estou vendo.

Khuldraeseth na'Barya
fonte
0

Javascript, 128 bytes

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

Você obtém o resultado apenas verificando $ - é meio trapaça, mas ei, economizou alguns bytes.

Marcus Dirr
fonte
0

PHP, 110 bytes

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

Três voltas para os elfos. Isso é tão direto ... mas não há muito para jogar golfe.

Titus
fonte
0

Na realidade , 14 bytes

Sugestões de golfe são bem-vindas! Experimente online!

┬@;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.
Sherlock9
fonte
0

C, 618 bytes

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

Uma função nomeada e por longe, a submissão mais longa aqui, em parte devido ao fato de que converter as entradas da matriz de caracteres em matrizes inteiras bidimensionais em C está ocupando mais bytes, e também porque eu não pratico golfe em C há mais tempo. Ainda estou trabalhando para encurtar isso o máximo possível, e todas as dicas para isso são muito apreciadas.

Agora, com isso fora do caminho, isso leva a entrada através da linha de comando com as duas matrizes representadas por duas seqüências, cada uma contendo as linhas separadas por vírgulas e cada linha representada por números inteiros separados por espaço. Por exemplo, as matrizes:

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

seria inserido como:

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

A matriz resultante é enviada para STDOUT como uma sequência multilinha. Por exemplo, a saída para a entrada acima seria:

 427 164 
1009 353 
1591 542 
R. Kap
fonte
TIO 539 bytes
girobuz 11/10
0

Clojure, 60 bytes

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

Muitos bytes gastos na transposição do segundo argumento.

NikoNyrh
fonte