¡Haga la multiplicación matricial!


14

En matemáticas, la multiplicación matricial o el producto matricial es una operación binaria que produce una matriz a partir de dos matrices. La definición está motivada por ecuaciones lineales y transformaciones lineales en vectores, que tienen numerosas aplicaciones en matemática aplicada, física e ingeniería. Más detalladamente, si A es una matriz n × m y B es una matriz m × p, su producto matriz AB es una matriz n × p, en la cual las entradas m en una fila de A se multiplican con las entradas m hacia abajo columnas de B y sumadas para producir una entrada de AB. Cuando dos transformaciones lineales están representadas por matrices, el producto matriz representa la composición de las dos transformaciones.

Fuente: Wikipedia

En otras palabras, para multiplicar dos matrices, por ejemplo:

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

Primero, tome la fila número 1 en la primera matriz, la columna número 1 en la segunda matriz y multiplique 1por 1, 2por 3y 3por 4.

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

Ahora agréguelos para obtener su primer artículo:

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

Para el segundo número en la primera columna del resultado, deberá tomar la fila número 2 en lugar de la fila número 1 y hacer lo mismo.

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

Después de hacer toda la primera columna, el resultado se ve así:

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

Ahora, vuelva a hacer exactamente lo mismo, pero tome la segunda columna en lugar de la primera columna, resultando en:

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

Tu tarea

Dadas dos matrices (dimensiones máximas 200x200), que contienen números en el rango de -10000 a 10000, donde el número de columnas en el primero es igual al número de filas en el segundo, multiplique el primero por el segundo. (La multiplicación de matrices no es conmutativa).

Puede tomar entrada y dar salida como una matriz de matrices (o equivalente), una matriz (si su idioma tiene ese formato) o una cadena multilínea.

No puede usar ninguna función integrada para la multiplicación de matrices.

Casos de prueba

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

Recuerde, este es el , por lo que gana el código con la menor cantidad de bytes.


¿Podemos usar productos dot incorporados? Operan en vectores, no en matrices.
Dennis

1
¿Es fijo el orden de entrada o podemos tomar a y b en ese orden y generar b × a ?
Dennis

@Dennis Puede invertir la entrada, pero no productos de punto
Oliver Ni

44
Retos sobre hacer X sin Y están desanimados .
falla

¿Pueden las matrices de entrada contener números de coma flotante? Si es así, recomiendo agregar un caso de prueba con algunos.
R. Kap

Respuestas:


5

Jalea , 7 5 bytes

Z×þḅ1

Toma B y A como argumentos y devuelve A × B .

Pruébalo en línea!

Cómo 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.

3
Entonces, espere, ¿la forma incorporada y la forma manual de multiplicar matrices terminan siendo el mismo número de bytes en Jelly? Eso es confuso, pero genial.
Yodle

@Yodle El incorporado es æ×, que es de 2 bytes.
Erik the Outgolfer

@EriktheOutgolfer Eso fue en referencia a la revisión 2, que utilizó el æ.átomo.
Dennis

4

05AB1E , 13 bytes

vyU²øvyX*O})ˆ

Pruébalo en línea!

Explicación

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

Ahora puede tener 7 bytes con exactamente el mismo enfoque:εUøεX*O
Kevin Cruijssen

4

Python 2, 69 66 bytes

Esto solo sigue la fórmula estándar, pero lambda-d para ser concisos :) ¡El código no protegido es extremadamente sencillo!

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

¡Gracias a Alexi Torhamo por guardar 3 bytes! :)

Código sin golf:

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

Puede usar sum(map(int.__mul__,r,c))para guardar 3 bytes. (No funcionará con coma flotante, pero tampoco era necesario)
Aleksi Torhamo

3

J, 13 9 bytes

¡Guardado 4 bytes gracias a millas!

[:+/*"#:~

Este es un tenedor con tapa:

[: +/ *"#:~

Lo que es equivalente a:

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

Que realiza la multiplicación deseada; estos se resumen a continuación.

Con un producto dot incorporado, 5 bytes: +/ .*

Casos de prueba

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

Me topé con [:+/*"#:~9 bytes
millas

@miles espectaculares!
Conor O'Brien

3

Haskell , 57 56 54 bytes

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

Pruébalo en línea!

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(:))econ e=[]:ees una forma más corta de transpose.



2

R, 66 bytes

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

Función sin nombre que toma dos matrices R como entrada y devuelve el producto. Utiliza el applyque se usa para aplicar funciones a través de los márgenes de las matrices. Funciona como un forbucle doble en este caso: para cada columna de By para cada fila de A, devuelve la suma de los productos (vectorizados).

Compare con el enfoque de bucle puro ( 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}

No en mi escritorio en este momento, pero ¿no podrías hacer algo outer(A,B,`*`)más que las applyllamadas incrustadas ?
rturnbull

@rturnbull No estoy seguro de cómo funciona externamente junto con las matrices, pero en este caso produciría una matriz 4-D.
Billywob

Ah sí, eso es un poco problemático. La linealización de las matrices probablemente tomaría más bytes que su enfoque aquí
rturnbull

2

Mathematica, 20 bytes

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

Función anónima. Toma dos listas de números de rango 2 como entrada y devuelve una lista de números de rango 2 como salida. Para los curiosos, Inneres una función que hace una aplicación de multiplicación matricial de dos funciones a dos tensores.


Creo que Inner[1##&,##]&es equivalente a Inner[1##&,##,Plus]&...? Y así 1##&~Inner~##&sería aún mejor.
Greg Martin el

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

Gracias @Mukul Kumar por guardar 1 byte, el ciclo while fue más corto esta vez: P

Programa completo con casos de prueba:

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

Puede recortar algunos bytes utilizando bucles while ....
Mukul Kumar

@MukulKumar Espera, no lo creo. A lo sumo, se equilibran, ¿verdad? for(;i<n;)-> while(i<n)son ambos 10 bytes.
Yodle

1
for (;i <n;i++) -> while (i++<n)ahorra 1 byte
Mukul Kumar

No estoy seguro de la etiqueta cuando tengo una respuesta bastante diferente, pero mi alternativa definitivamente se inspiró en esto.
Kirk Broadhurst

2

MATL , 12 11 bytes

7L&!*Xs6Be!

Las matrices se ingresan utilizando ;como separador de filas.

Pruébalo en línea!

La multiplicación de matrices sin la función integrada fue parte de mi respuesta a Showcase of languages . Sin embargo, al intentar reutilizar el código original para esta respuesta, me di cuenta de que tenía un error (la salida del vector de fila se convirtió incorrectamente en un vector de columna). Esto ahora está corregido, tanto aquí como allá. Para obtener una explicación de cómo funciona el código, consulte la publicación mencionada (fragmento de longitud 11).


2

C ++ 14, 173 168 156 146 bytes

  • -5 bytes para regresar a través del parámetro de referencia
  • -12 bytes para usar foreach y en su C.back()lugar contar coni
  • -10 bytes para soltar C.clear() y requerir Cestar vacío al inicio

Como lambda sin nombre:

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

Requiere entrada y salida ya que la vector<vector<int>>salida debe estar vacía de antemano.

Sin golf:

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

Muestra:

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

¿Por qué no usar en push_back()lugar de emplace_back()?
G. Sliepen

2

Casco , 7 6 bytes

mMδṁ*T

Tenga en cuenta el orden de los argumentos, ¡ pruébelo en línea!

-1 byte gracias a @Zgarb!

Explicación

Básicamente solo haciendo lo que dice la definición de multiplicación de matrices:

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Σzpuede 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)))

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

Robé solución de Yodle con la suposición de que podría escribir esto utilizando más eficientemente LINQ (a diferencia de los bucles). Hizo algunos intentos pero lo aplastó un poco.

Aquí se desglosa un poco:

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

La única verdadera 'truco' aquí es la transpuesta de la matriz, B.First().Select((f, i) => B.Select(r => r.ElementAt(i))). Una vez que transponemos la segunda matriz, tenemos dos matrices A[i,x]y B[j,x]. Tome el producto cartesiano ( i*j) y comprima cada uno de esosx matrices de longitud juntas.

Código de prueba:

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

}

Agradable: P Realmente nunca he usado tanto Linq, así que no estoy completamente consciente de todas sus capacidades, así que tiendo a usar solo bucles estándar y demás. Sin embargo, creo que debe incluir el uso de System.Linq; en su recuento de bytes, no estoy seguro de cuánto lo afecta.
Yodle

@Yodle sí, tendría que incluir using System.Linq; No estoy seguro de si las soluciones aquí deben incluir repeticiones como using Systemystatic void Main()
Kirk Broadhurst

He estado respondiendo por un momento ahora, y por lo que he visto, básicamente su respuesta (lo que sea que esté incluyendo en su conteo de bytes) tiene que funcionar si lo pega en un programa. Para C # específicamente, si está escribiendo solo una función, entonces no necesita incluir definiciones de clase o el material Main () estático vacío, pero si su solución usa cualquier material de biblioteca como Console.WriteLine (), entonces tiene que hacer System.Console.WriteLine () o usando System; ya que uno puede ser más corto.
Yodle

1

Haskell , 49 bytes

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

Pruébalo en línea!

Entrada y salida son listas de columnas. Asigna cada columna de la segunda matriz a esa fila, comprimida con las columnas de la primera matriz y escalando cada una, sumada como un vector.

Siento que debe haber una buena manera de hacer que este punto sea libre y guardar un puñado de bytes, pero aún no lo veo.


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

Obtiene el resultado simplemente marcando $: es un poco engañoso, pero bueno, ahorró algunos bytes.


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

Tres bucles para las matrices élficas. Esto es muy sencillo ... pero no hay mucho para jugar al golf.


0

Realmente , 14 bytes

Sugerencias de golf bienvenidas! Pruébalo en línea!

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

No golfista

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

Una función con nombre y con mucho la presentación más larga aquí, en parte debido al hecho de que convertir las entradas de la matriz de caracteres en matrices enteras bidimensionales C ocupa la mayor cantidad de bytes, y también porque no he jugado golf en C en el tiempo más largo. Todavía estoy trabajando en acortar esto tanto como puedo, y cualquier consejo al respecto es muy apreciado.

Ahora, con eso fuera del camino, esto toma información a través de la línea de comando con las dos matrices representadas por dos cadenas, cada una con las filas separadas por comas y cada fila representada por enteros separados por espacios. Por ejemplo, las matrices:

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

sería ingresado como:

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

La matriz resultante se envía a STDOUT como una cadena multilínea. Por ejemplo, la salida para la entrada anterior sería:

 427 164 
1009 353 
1591 542 

TIO 539 bytes
girobuz

0

Clojure, 60 bytes

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

Muchos bytes gastados en la transposición del segundo argumento.


Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.