En JavaScript las matrices son simplemente vectores de vectores, es decir son vectores donde cada elemento es a su vez un vector (una fila).
Por lo tanto una matriz se crea igual que un vector, es decir de manera formal con new Array o de manera abreviada (la forma recomendada) escribiendo las filas, separadas con comas, entre corchetes. Por ejemplo, la siguiente matriz:
var a = [[1, 2, 3, 4, 5], [2, 3, 4, 5, 6], [3, 4, 5, 6, 7], [4, 5, 6, 7, 8]]; a
Como se puede ver, por defecto, la matriz se muestra en una sola línea. Para ver cada fila en una línea diferente, se emplea el método show:
a.show()
Con la forma estándar (que no será empleada en la práctica) la matriz se crea con:
var b = new Array( new Array(1, 2, 3, 4, 5), new Array(2, 3, 4, 5, 6), new Array(3, 4, 5, 6, 7), new Array(4, 5, 6, 7, 8) ); b.show()
Como se mencionó al estudiar vectores, los métodos add, sub, mul, div y neg operan con vectores, matrices, números reales y complejos, por lo que son más generales que los operadores +, -, *, / y - (cuando es empleado como negación). Por ejemplo, dadas las siguientes matrices:
Puenden ser sumadas, restadas, multiplicadas y divididas:
var a = [[2, 8, 2, 3], [1, 6, -1, 4], [2, -1, 2, 5], [4, 2, 3, 5]]; var b = [[1, 4, -2, 3], [2, 2, 0, 4], [3, 0, -1, 2], [1, 2, 2, -3]];
a.add(b).show()
a.sub(b).show()
a.mul(b).show()
a.div(b).round(2).show()
Al ser las matrices vectores de vectores, se pueden emplear todas las propiedades y métodos disponibles para vectores. Adicionalmente, en la calculadora Javascript, se cuenta con los siguientes métodos (librería array):
Métodos de matrices
función
Descripción
identity(n,m)
Crea una matriz identidad con "n" filas y "m" columnas ("n" filas y columnas si sólo se manda "n"), o con las dimensiones de la matriz o vector desde el cual es llamado.
diagonal(k)
Crea una matriz con los elementos del vector desde el cual es llamado, en la diagonal principal o en la diagonal "k".
appendRows(b)
Añade al final de la matriz o vector desde el cual es llamado, las filas de la matriz o vector "b".
appendCols(b)
Añade al final de la matriz o vector desde el cual es llamado, las columnas de la matriz o vector "b"
insertRows(b,k)
Inserta al principio (o en la fila "k") de la matriz o vector desde el cual es llamado, la fila o filas de la matriz o vector "b".
insertCols(b,k)
Inserta al principio (o en la columna "k") de la matriz o vector desde el cual es llamado, la columna o columnas de la matriz o vector "b".
removeRows(k,l)
Quita la fila "k" o las filas "k" a "l" de la matriz o vector desde el cual es llamado, devolviendo la fila o filas removidas.
removeCols(k,l)
Quita la columna "k" o las columnas "k" a "l" de la matriz o vector desde el cual es llamado, devolviendo la columna o columnas removidas.
getRows(k,l)
Devuelve un vector o matriz con la fila "k", o las filas desde "k" hasta "l", de la matriz o vector desde el cual es llamado.
getCols(k,l)
Devuelve un vector o matriz con la columna "k", o las columnas desde "k" hasta "l", de la matriz o vector desde el cual es llamado.
getDiagonal(k)
Devuelve un vector con los elementos de la diagonal principal, o de la diagonal "k", de la matriz desde la cual es llamado.
replaceRows(b,k)
Reemplaza la fila "k", o la fila "k" y posteriores, de la matriz desde la cual es llamdo, con las filas de la matriz o vector "b".
replaceCols(b,k)
Reemplaza la columna "k", o la columna "k" y posteriores, de la matriz desde la cual es llamado, con las columnas de la matriz o vector "b".
rowSwap(i,j)
Intercambia las filas "i" y "j" de la matriz o vector desde el cual es llamado.
colSwap(i,j)
Intercambia las columnas "i" y "j" de la matriz o vector desde el cual es llamado.
det()
Devuelve el determinante de la matriz desde la cual es llamado.
inv()
Devuelve la inversa de la matriz desde la cual es llamado.
trace()
Devuelve el trazo de la matriz desde la cual es llamado.
transpose()
Devuelve una nueva matriz, con la transpuesta de la matriz desde la cual es llamado.
Con estos métodos se pueden llevar a cabo la mayoría de las operaciones requeridas en el trabajo con matrices, además, como se dijo, se pueden emplear también todos los métodos estudiados en vectores.
De estos métodos los que se utilizan con mayor frecuencia en la resolución de sistemas de ecuaciones lineales son inv, transpose y det. De los métodos estudiados previamente, son de mayor utilidad en el trabajo con matrices: rand, const y zeros, además de los métodos de carácter general: copy, round, precision, add, sub, etc.
Se recuerda que, el método rand, genera por defecto un vector o matriz con números realmente aleatorios, es decir con números que se generan en una secuencia no predecible, sin embargo, se pueden generar números pseudoaleatorios (secuencias que pueden volver a ser generadas) estableciendo un valor inicial o semilla (randseed).
Ejemplos
Mostrando las matrices con show:
Genere y guarde en "a" una matriz con 3 filas y 4 columnas de números enteros pseudoaleatorios comprendidos entre 1 y 9 (randseed=1):
randseed = 1; var a = [].rand(3, 4, 1, 9).round(); a.show()
Genere y guarde en "b" una matriz con 4 filas y 4 columnas de números enteros pseudoaleatorios comprendidos entre 1 y 9 (randseed=0):
randseed = 0; var b = [].rand(4, 4, 1, 9).round(); b.show()
Genere y guarde en la variable "c" una matriz con 4 filas y 5 columnas de números 6:
var c = [].const(4, 5, 6); c.show()
Obtenga la transpuesta de la matriz "a":
a.transpose().show()
Calcule la inversa de la matriz b, redondeando los resultados al segundo dígito después del punto:
b.inv().round(2).show()
Calcule la matriz resultante de multiplicar la matriz "a" por la matriz "b":
a.mul(b).show()
Divida la matriz "c" entre el número 2:
c.div(2).show()
Genere una matriz con 4 filas y 6 columnas de ceros:
[].zeros(4, 6).show()
Mostrando las matrices con show y tomando en cuenta las siguientes matrices:
Intercambia la segunda y tercera filas de la matriz "a1":
a1.rowSwap(1, 2).show()
Intercambie la primera y quinta columnas de la matriz "a1":
a1.colSwap(0, 4).show()
Cree el vector "v2" con los elementos de la segunda fila de la matriz "a1":
var v2 = a1.getRows(1); v2
Cree el vector "v3" con los elementos de la cuarta columna de la matriz "a1":
var v3 = a1.getCols(3); v3
Cree el vector "v4" con los elementos de la diagonal principal de la matriz "a1":
var v4 = a1.getDiagonal(); v4
Cree el vector "v5" con los elementos de la primera diagonal a la derecha de la diagonal principal de la matriz "a1":
var v5 = a1.getDiagonal(1); v5
Cree el vector "v6" con los elementos de la segunda diagonal a la izquierda de la diagonal principal de la matriz "a1":
var v6 = a1.getDiagonal(-2); v6
Trabajo con matrices
Al igual que ocurre con vectores, al trabajar con matrices, se llevan a cabo operaciones con todos o un subconjunto de sus elementos. La estructura más adecuada para ese fin (al igual que en vectores) es la estructura for, sólo que con las matrices generalmente se requieren dos estructuras for anidadas (porque tienen dos dimensiones).
Las expresiones matemáticas que involucran sumatorias (\(\sum\)) o productorias (\(\prod\)), pueden ser traducidas directamente a sus estructuras for equivalentes.
Ejemplos
Sumatoria de los elementos de una matriz
Para calcular la sumatoria de los elementos de una matriz, se aplica la siguiente expresión matemática:
\[
S = \sum_{i=1}^{n}\sum_{j=1}^{m}a_{i,j}
\]
Recordando que las matrices en JavaScript comienzan en 0, estas sumatorias pueden ser traducidas directamente en dos ciclos for: El primero (contador "i") desde 0 hasta n-1 y el segundo (contador "j") desde 0 hasta m-1.
Sólo para mayor claridad, se elabora el diagrama de flujo respectivo:
gojsGraph({divi, modelo: {"class":"go.GraphLinksModel","linkFromPortIdProperty":"fromPort","linkToPortIdProperty":"toPort","nodeDataArray":[{"category":"Start","text":"suma","key":-1,"loc":"197.00000000000003 -459.9999999999999"},{"category":"Input","text":"matriz de números: a","key":-3,"loc":"197 -410.46664276123033"},{"category":"Output","text":"s","key":-4,"loc":"197 130.336211034494"},{"category":"Process","text":"i = 0","key":-2,"loc":"197 -195.33321380615226"},{"category":"Process","text":"i=i+1","key":-7,"loc":"101.99999999999986 -140.9831869125365"},{"category":"Start","text":"fin","key":-9,"loc":"197.0000000000001 183.21402068618664"},{"category":"Process","text":"n = num. de filas en a","key":-11,"loc":"197 -358.9332855224608"},{"category":"Process","text":"m = num. de columnas en a","key":-12,"loc":"197 -304.3999282836913"},{"category":"Process","text":"s = 0","key":-13,"loc":"197 -249.86657104492178"},{"category":"For","text":"i<n","key":-6,"loc":"197 -140.9831869125365"},{"category":"Process","text":"j = 0","key":-14,"loc":"197 -74.63316001892078"},{"category":"Process","text":"j=j+1","key":-15,"loc":"108.99999999999986 -20.283133125305053"},{"category":"For","text":"j<m","key":-16,"loc":"197 -20.28313312530505"},{"category":"Process","text":"s = s+a[i][j]","key":-17,"loc":"197 46.06689376831068"},{"category":"Connector","text":"A","key":-8,"loc":"197 88.02932619494074"}],"linkDataArray":[{"from":-1,"to":-3,"fromPort":"B","toPort":"T","points":[197,-444.73332138061517,197,-434.73332138061517,197,-434.73332138061517,197,-434.73332138061517,197,-434.73332138061517,197,-424.73332138061517]},{"from":-3,"to":-11,"fromPort":"B","toPort":"T","points":[197,-396.1999641418456,197,-386.1999641418456,197,-386.1999641418456,197,-386.1999641418456,197,-386.1999641418456,197,-376.1999641418456]},{"from":-11,"to":-12,"fromPort":"B","toPort":"T","points":[197,-341.66660690307606,197,-331.66660690307606,197,-331.66660690307606,197,-331.66660690307606,197,-331.66660690307606,197,-321.66660690307606]},{"from":-12,"to":-13,"fromPort":"B","toPort":"T","points":[197,-287.1332496643065,197,-277.1332496643065,197,-277.1332496643065,197,-277.1332496643065,197,-277.1332496643065,197,-267.1332496643065]},{"from":-13,"to":-2,"fromPort":"B","toPort":"T","points":[197,-232.59989242553698,197,-222.59989242553698,197,-222.59989242553698,197,-222.59989242553698,197,-222.59989242553698,197,-212.59989242553698]},{"from":-2,"to":-6,"fromPort":"B","toPort":"T","points":[197,-178.06653518676745,197,-168.06653518676745,197,-168.06653518676745,197,-168.06653518676745,197,-168.06653518676745,197,-158.06653518676745]},{"from":-6,"to":-14,"fromPort":"B","toPort":"T","visible":true,"points":[197,-123.89983863830554,197,-113.89983863830554,197,-107.89983863830554,197,-107.89983863830554,197,-101.89983863830554,197,-91.89983863830554],"text":"Si"},{"from":-16,"to":-17,"fromPort":"B","toPort":"T","visible":true,"points":[197,-3.1997848510740923,197,6.800215148925908,197,12.800215148925908,197,12.800215148925908,197,18.800215148925908,197,28.800215148925908],"text":"Si"},{"from":-14,"to":-16,"fromPort":"B","toPort":"T","points":[197,-57.36648139953601,197,-47.36648139953601,197,-47.36648139953601,197,-47.36648139953601,197,-47.366481399536006,197,-37.366481399536006]},{"from":-17,"to":-15,"fromPort":"L","toPort":"B","points":[154.55481719970703,46.06689376831068,144.55481719970703,46.06689376831068,108.99999999999986,46.06689376831068,108.99999999999986,26.525219631195196,108.99999999999986,6.9835454940797135,108.99999999999986,-3.0164545059202865]},{"from":-15,"to":-16,"fromPort":"R","toPort":"L","points":[133.9778213500975,-20.283133125305053,143.9778213500975,-20.283133125305053,151.67333984374994,-20.283133125305053,151.67333984374994,-20.28313312530505,159.36885833740234,-20.28313312530505,169.36885833740234,-20.28313312530505]},{"from":-6,"to":-4,"fromPort":"R","toPort":"R","visible":true,"points":[222.7033462524414,-140.9831869125365,232.7033462524414,-141.49159345626825,281,-141.49159345626825,281,130.336211034494,226.5,130.336211034494,216.5,130.336211034494],"text":"No"},{"from":-4,"to":-9,"fromPort":"B","toPort":"T","points":[197,143.01622537775572,197,153.01622537775572,197,155.4817837222788,197,155.4817837222788,197,157.94734206680192,197,167.94734206680192]},{"from":-7,"to":-6,"fromPort":"R","toPort":"L","points":[127.00713348388658,-140.9831869125365,137.00713348388658,-140.9831869125365,149.1518936157226,-140.9831869125365,149.1518936157226,-140.9831869125365,161.2966537475586,-140.9831869125365,171.2966537475586,-140.9831869125365]},{"from":-16,"to":-8,"fromPort":"R","toPort":"R","visible":true,"points":[224.63114166259766,-20.28313312530505,234.63114166259766,-19.141566562652525,257,-19.141566562652525,257,88.02932619494074,221.6957538072453,88.02932619494074,211.6957538072453,88.02932619494074],"text":"No"},{"from":-8,"to":-7,"fromPort":"L","toPort":"L","points":[182.3042461927547,88.02932619494074,172.3042461927547,88.02932619494074,56,88.02932619494074,56,-140.9831869125365,66.99286651611314,-140.9831869125365,76.99286651611314,-140.9831869125365]}]} })
Siendo el código respectivo, implementado como un método getter de la clase "SM", que extiende a (hereda de) la clase Array, es:
var SM = class extends Array{
get suma() {
const a = this;
const n = a.length;
const m = a[0].length;
let s = 0;
for (let i=0; i<n; i++)
for (let j=0; j<m; j++)
s += a[i][j];
return s;
}
}
El número de filas "n" es el número de elementos del array (a.length), porque en una matriz cada fila es un elemento. El número de columnas es el número de elementos en la primera fila (a[0].length, por supuesto asumiendo que es una matriz regular).
var a = new SM([2, 8, 2, 3], [1, 6, -1, 4], [2, -1, 2, 5], [4, 2, 3, 5]);
var b = new SM([1, 4, -2, 3], [2, 2, 0, 4], [3, 0, -1, 2], [1, 2, 2, -3]);
a.suma
b.suma
Observe que para crear una matriz con la clase "SM", se manda (al constructor heredado de Array) las filas de las matrices, porque una matriz (en JavaScript) simplemente es un vector, donde cada uno de sus elementos es a su vez otro vector.
Para determinar si una matriz es regular (es decir determinar si todas las filas tienen el mismo número de elementos) se puede llamar al método isMatrixr, que devuelve true (verdadero) si la matriz es regular y false (falso) en caso contrario.
En lugar de la estructura for, el problema puede ser resuelto también empleando la estructura for-of:
Object.defineProperty(SM.prototype, "suma_a", {
get() {
const a = this;
let s = 0;
for (let f of a) for (let e of f) s+=e;
return s;
},
configurable: true
});
a.suma_a
b.suma_a
En este caso, en el ciclo externo se obtiene en "f", una por una las filas de la matriz "a", mientras que en el interno se obtienen y suman, uno por uno, los elementos "e" de cada fila "f".
Igualmente, el problema puede ser resulto con el método forEach:
Object.defineProperty(SM.prototype, "suma_b", {
get() {
const a = this;
let s = 0;
a.forEach(f=>f.forEach(e=>s+=e));
return s;
},
configurable: true
});
a.suma_b
b.suma_b
Donde, al igual que en la estructura for-of, en la llamada externa se obtiene en "f", una por una, las filas de la matriz "a", mientras que en la llamada interna se obtienen y suman, uno por uno, los elementos "e" de cada fila "f".
Igualmente, el problema puede ser resulto con el método map:
Object.defineProperty(SM.prototype, "suma_c", {
get() {
const a = this;
let s = 0;
a.map(f=>f.map(e=>s+=e));
return s;
},
configurable: true
});
a.suma_c
b.suma_c
Donde, al igual que en el método anterior, en la llamada externa se obtiene en "f", una por una las filas de la matriz "a", mientras que en la llamada interna se obtienen y suman, uno por uno, los elementos "e" de cada fila "f", sin embargo, como se recordará, map genera una nueva matriz (con las mismas dimensiones que la matriz original) donde cada elemento es igual al resultado de cada una de las llamadas (repeticiones), en este ejemplo las sumatorias parciales de cada una de las filas, sin embargo, en este caso, esa matriz es simplemente descartada (no es empleada), por lo que el método map no es un método eficiente para resolver este tipo de problemas, porque si bien permite calcular el resultado correcto, emplea recursos y tiempo en crear una matriz que en realidad no se requiere.
Empleando el método reduce, el problema se resuelve de la siguiente manera:
En la primera iteración del reduce externo, "s" recibe el número 0 (el valor inicial de la sumatoria) y "f" recibe la primera fila de la matriz. En las posteriores iteraciones del ciclo externo, "s" recibe el resultado de la iteración anterior (la sumatoria de las filas sumadas hasta esa iteración) y "f" recibe la siguiente fila de la matriz.
Por otra parte, en la primera iteración del reduce interno, "s" recibe el primer elemento de la fila "f" (porque el reduce interno no tiene un valor inicial) y "e" recibe el segundo elemento de la fila "f", el cual se suma al primero (a "s"). En las siguientes iteraciones del reduce interno, "s" recibe el resultado de la iteración anterior (la sumatoria de los elementos sumados hasta esa iteración) y "e" es el valor del siguiente elemento de la fila "f".
Es importante tener en mente que, aunque tienen el mismo nombre, el parámetro "s" del reduce interno es diferente al parámetro "s" del reduce externo.
Si no se asignaría el valor inicial 0, al reduce externo, "s" recibiría la primera fila de la matriz y "e" recibiría la sumatoria de la segunda fila, entonces como se debería sumar un vector y un escalar, JavaScript convertiría ambos valores a cadenas (strings) y las concatenaría, de manera que el resultado sería una cadena con los elementos de la primera fila, seguida de las sumatorias de las filas restantes (haga la prueba borrando el valor inicial 0 y llamando al método).
El problema, resuelto con el método every, es:
Object.defineProperty(SM.prototype, "suma_e", {
get() {
const a = this;
let s = 0;
a.every(f=>(f.every(e=>(s+=e,1)),1));
return s;
},
configurable: true
});
a.suma_e
b.suma_e
Donde la lógica es la misma que con forEach, pero, para que every itere para todos los elementos de cada una de las filas, la función interna debe devolver 1 (que es uno de los valores que equivalen a true, por supuesto también se puede devolver directamente true).
Igualmente, se puede emplear filter, así como los métodos some, find, findLast, findIndex, findLastIndex, haciendo que, en estos métodos, la función devuelva siempre el valor booleano false o un valor equivalente a false, por ejemplo "0". Sin embargo, como se recalcó en el capítulo anterior, estos métodos no deben ser empleados para resolver problemas reales de este tipo. Se emplean en este y en el anterior capítulo, solo con la finalidad de adquirir práctica en su uso.
Multiplicación de matrices
La siguiente expresión matemática, permite calcular la matriz "c" resultante de multiplicar de dos matrices: "a" y "b":
Donde "nfa" es el número de filas de la matriz "a", "ncb" es el número de columnas de la matriz "b" y "nca" es el número de columnas de la matriz "a". La condición para que dos matrices puedan ser multiplicadas es que el número de columnas de la matriz "a", sea igual al número de filas de la matriz "b".
Esta expresión, puede ser traducida y codificada directamente en tres ciclos for: El primero (contador "i") que va desde 0 hasta nfa-1, el segundo (contador "j") que va desde 0 hasta ncb-1 y el tercero (contador "k") que va desde 0 hasta nca-1.
El diagrama de flujo, es:
gojsGraph({divi, modelo: {"class":"go.GraphLinksModel","linkFromPortIdProperty":"fromPort","linkToPortIdProperty":"toPort","nodeDataArray":[{"category":"Start","text":"mulMat","key":-1,"loc":"197.00000000000003 -459.9999999999999"},{"category":"Input","text":"matrices a multiplicar: a, b","key":-3,"loc":"197 -410.46664276123033"},{"category":"Output","text":"s","key":-4,"loc":"73.00000000000006 565.9611296749854"},{"category":"Process","text":"i = 0","key":-2,"loc":"72.99999999999996 -38.333213806152244"},{"category":"Process","text":"i=i+1","key":-7,"loc":"-19.000000000000192 16.016813087463447"},{"category":"Start","text":"fin","key":-9,"loc":"197.38115692138683 608.8389393266784"},{"category":"Process","text":"nfa = num. de filas en a","key":-11,"loc":"197 -358.9332855224608"},{"category":"Process","text":"nca = num. de columnas en a","key":-12,"loc":"197 -249.39992828369134"},{"category":"Process","text":"c = []","key":-13,"loc":"73 -92.86657104492167"},{"category":"For","text":"i<nfa","key":-6,"loc":"73.00000000000003 16.01681308746347"},{"category":"Process","text":"j = 0","key":-14,"loc":"73.00000000000007 136.36683998107924"},{"category":"Process","text":"j=j+1","key":-15,"loc":"-19.000000000000185 190.71686687469503"},{"category":"For","text":"j<ncb","key":-16,"loc":"72.99999999999989 190.71686687469494"},{"category":"Process","text":"c[i][j] = c[i][j]+a[i][k]*b[k][j]","key":-17,"loc":"73.00000000000009 432.3003047943116"},{"category":"Process","text":"ncb = num. de columnas en b","key":-18,"loc":"197.38115692138678 -194.86657104492173"},{"category":"Conditional","text":"nca!=nfb","key":-19,"loc":"197.38115692138672 -140.00000000000009"},{"category":"Output","text":"lanzar error:\n\"matrices incompatibles\"","key":-5,"loc":"361.99999999999994 189.79999923706063"},{"category":"Process","text":"c[i] = []","key":-20,"loc":"73 82.36683998107921"},{"category":"Process","text":"c[i][j] = 0","key":-21,"loc":"72.99999999999997 257.0668937683107"},{"category":"For","text":"k<nca","key":-22,"loc":"72.99999999999997 365.95027790069616"},{"category":"Process","text":"k=k+1","key":-23,"loc":"-19.000000000000185 365.95027790069605"},{"category":"Process","text":"k = 0","key":-24,"loc":"72.99999999999999 311.6002510070801"},{"category":"Connector","text":"B","key":-27,"loc":"73.00000000000006 513.6542448354323"},{"category":"Connector","text":"A","key":-28,"loc":"73.00000000000006 474.26273722094174"},{"category":"Process","text":"nfb = num. de filas en b","key":-29,"loc":"197.76231384277344 -304.3999282836912"}],"linkDataArray":[{"from":-1,"to":-3,"fromPort":"B","toPort":"T","points":[196.99999999999997,-444.73332138061494,196.99999999999997,-434.73332138061494,197,-434.73332138061494,197,-434.7333213806152,197.00000000000006,-434.7333213806152,197.00000000000006,-424.7333213806152]},{"from":-3,"to":-11,"fromPort":"B","toPort":"T","points":[197.00000000000006,-396.19996414184567,197.00000000000006,-386.19996414184567,197.00000000000006,-386.1999641418456,197,-386.1999641418456,197,-386.1999641418455,197,-376.1999641418455]},{"from":-13,"to":-2,"fromPort":"B","toPort":"T","points":[72.99999999999997,-75.59989242553698,72.99999999999997,-65.59989242553698,72.99999999999999,-65.59989242553698,72.99999999999999,-65.59989242553708,73,-65.59989242553708,73,-55.59989242553708]},{"from":-2,"to":-6,"fromPort":"B","toPort":"T","points":[73,-21.066535186767545,73,-11.066535186767545,73,-11.066535186767517,73.00000000000003,-11.066535186767517,73.00000000000003,-11.066535186767489,73.00000000000003,-1.0665351867674886]},{"from":-14,"to":-16,"fromPort":"B","toPort":"T","points":[73.00000000000006,153.633518600464,73.00000000000006,163.633518600464,72.99999999999997,163.633518600464,72.99999999999997,163.633518600464,72.99999999999989,163.633518600464,72.99999999999989,173.633518600464]},{"from":-15,"to":-16,"fromPort":"R","toPort":"L","points":[5.9778213500974715,190.71686687469497,15.977821350097472,190.71686687469497,22.884281158447116,190.71686687469497,22.884281158447116,190.71686687469494,29.79074096679676,190.71686687469494,39.79074096679676,190.71686687469494]},{"from":-4,"to":-9,"fromPort":"B","toPort":"L","points":[73.00000000000006,578.6411440182472,73.00000000000006,588.6411440182472,73.00000000000006,588,73.00000000000006,588,73.00000000000006,608.8389393266782,163.82163408067493,608.8389393266782,173.82163408067493,608.8389393266782]},{"from":-7,"to":-6,"fromPort":"R","toPort":"L","points":[6.007133483886534,16.01681308746345,16.007133483886534,16.01681308746345,23.558635711669844,16.01681308746345,23.558635711669844,16.01681308746347,31.110137939453153,16.01681308746347,41.11013793945315,16.01681308746347]},{"from":-12,"to":-18,"fromPort":"B","toPort":"T","points":[197,-232.13324966430653,197,-222.13324966430653,197,-222.1332496643065,197.38115692138672,-222.1332496643065,197.38115692138672,-222.1332496643065,197.38115692138672,-212.1332496643065]},{"from":-19,"to":-13,"fromPort":"L","toPort":"T","visible":true,"points":[137.63391876220703,-140,127.63391876220703,-140,72.99999999999997,-140,72.99999999999997,-130.06662483215325,72.99999999999997,-120.1332496643065,72.99999999999997,-110.1332496643065],"text":"No"},{"from":-19,"to":-5,"fromPort":"R","toPort":"T","visible":true,"points":[257.1283950805664,-140,267.1283950805664,-140,362,-140,362,3.7888685862223213,362,147.57773717244464,362,157.57773717244464],"text":"Si"},{"from":-6,"to":-20,"fromPort":"B","toPort":"T","visible":true,"points":[73.00000000000003,33.100161361694425,73.00000000000003,43.100161361694425,73.00000000000003,49.10016136169445,73,49.10016136169445,73,55.10016136169446,73,65.10016136169446],"text":"Si"},{"from":-20,"to":-14,"fromPort":"B","toPort":"T","points":[73,99.63351860046399,73,109.63351860046399,73.00000000000003,109.63351860046399,73.00000000000003,109.10016136169446,73.00000000000006,109.10016136169446,73.00000000000006,119.10016136169446]},{"from":-16,"to":-21,"fromPort":"B","toPort":"T","visible":true,"points":[72.99999999999989,207.8002151489259,72.99999999999989,217.8002151489259,72.99999999999989,223.8002151489259,73,223.8002151489259,73,229.8002151489259,73,239.8002151489259],"text":"Si"},{"from":-23,"to":-22,"fromPort":"R","toPort":"L","points":[9.936027526855284,365.95027790069605,19.936027526855284,365.95027790069605,24.06441116332997,365.95027790069605,24.06441116332997,365.95027790069616,28.19279479980466,365.95027790069616,38.19279479980466,365.95027790069616]},{"from":-24,"to":-22,"fromPort":"B","toPort":"T","points":[72.99999999999999,328.86692962646487,72.99999999999999,338.86692962646487,72.99999999999999,338.86692962646504,72.99999999999997,338.86692962646504,72.99999999999997,338.8669296264652,72.99999999999997,348.8669296264652]},{"from":-21,"to":-24,"fromPort":"B","toPort":"T","points":[73,274.3335723876954,73,284.3335723876954,73,284.3335723876954,73,284.3335723876953,72.99999999999999,284.3335723876953,72.99999999999999,294.3335723876953]},{"from":-22,"to":-17,"fromPort":"B","toPort":"T","visible":true,"points":[72.99999999999997,383.0336261749271,72.99999999999997,393.0336261749271,72.99999999999997,399.033626174927,73.00000000000006,399.033626174927,73.00000000000006,405.0336261749269,73.00000000000006,415.0336261749269],"text":"Si"},{"from":-17,"to":-23,"fromPort":"L","toPort":"L","points":[-18.504814147949162,432.30030479431167,-28.504814147949162,432.30030479431167,-69,432.30030479431167,-69,365.95027790069605,-57.93602752685565,365.95027790069605,-47.93602752685565,365.95027790069605]},{"from":-5,"to":-9,"fromPort":"B","toPort":"R","points":[362,213.00002792358396,362,223.00002792358396,362,220,362,220,362,608.8389393266782,230.94067976209854,608.8389393266782,220.94067976209854,608.8389393266782]},{"from":-18,"to":-19,"fromPort":"B","toPort":"T","points":[197.38115692138672,-177.59989242553698,197.38115692138672,-167.59989242553698,197.38115692138672,-167.59989242553698,197.38115692138672,-170.03335723876953,197.38115692138672,-170.03335723876953,197.38115692138672,-160.03335723876953]},{"from":-11,"to":-29,"fromPort":"B","toPort":"T","points":[197,-341.666606903076,197,-331.666606903076,197.38115692138672,-331.666606903076,197.38115692138672,-331.666606903076,197.76231384277344,-331.666606903076,197.76231384277344,-321.666606903076]},{"from":-29,"to":-12,"fromPort":"B","toPort":"T","points":[197.76231384277344,-287.13324966430645,197.76231384277344,-277.13324966430645,197.76231384277344,-276.8999282836912,197,-276.8999282836912,197,-276.66660690307606,197,-266.66660690307606]},{"from":-22,"to":-28,"fromPort":"R","toPort":"R","visible":true,"points":[107.80720520019528,365.95027790069616,117.80720520019528,364.9751389503481,177,364.9751389503481,177,474.26273722094174,97.69575380724535,474.26273722094174,87.69575380724535,474.26273722094174],"text":"No"},{"from":-28,"to":-15,"fromPort":"L","toPort":"L","points":[58.30424619275475,474.26273722094174,48.30424619275475,474.26273722094174,52,474.26273722094174,52,474.26273722094174,-81,474.26273722094174,-81,190.71686687469497,-53.97782135009784,190.71686687469497,-43.97782135009784,190.71686687469497]},{"from":-16,"to":-27,"fromPort":"R","toPort":"R","visible":true,"points":[106.20925903320301,190.71686687469494,116.20925903320301,190.85843343734746,195,190.85843343734746,195,513.6542448354323,97.69575380724535,513.6542448354323,87.69575380724535,513.6542448354323],"text":"No"},{"from":-27,"to":-7,"fromPort":"L","toPort":"L","points":[58.30424619275475,513.6542448354323,48.30424619275475,513.8271224177162,-99,513.8271224177162,-99,16.01681308746345,-54.0071334838869,16.01681308746345,-44.0071334838869,16.01681308746345]},{"from":-6,"to":-4,"fromPort":"R","toPort":"R","visible":true,"points":[104.8898620605469,16.01681308746347,114.8898620605469,15.908415699005172,216,15.908415699005172,216,565.9611296749856,102.50000000000006,565.9611296749856,92.50000000000006,565.9611296749856],"text":"No"}]} })
Como se puede ver, antes de entrar a los ciclos, se crea la matriz vacía resultante "c". En el primer ciclo se añade, en cada iteración, una fila vacía a la matriz "c", en el segundo ciclo se añade, en cada iteración, un elemento ("c[i][j]"), inicialmente igual a cero, a la fila "i" de la matriz resultante "c" y en el tercer ciclo, se calcula y guarda (en c[i][j]) el valor final de ese elemento (el resultado de multiplicar la fila "i" de la matriz "a" por la columna "j" de la matriz "b").
El código respectivo, programado como un método estándar de la clase "MM", que hereda de la clase Array, es:
var MM = class extends Array {
mulMat(b) {
const a = this;
const nfa = a.length;
const nfb = b.length;
const nca = a[0].length;
const ncb = b[0].length;
if (nca!==nfb) throw new Error("matrices incompatibles");
const c = [];
for (let i=0; i<nfa; i++) {
c[i] = [];
for (let j=0; j<ncb; j++) {
c[i][j] = 0;
for (let k=0; k<nca; k++) c[i][j] += a[i][k]*b[k][j];
}
}
return c;
}
};
Observe que la matriz "c" se declara como constante, aunque en el proceso se generan y calculan los elementos de cada una de sus filas. Se procede así porque, como se recordará, las variables que almacenan un vector (y en general cualquier objeto) sólo guardan la dirección de memoria donde se encuentra el vector (o el objeto), no los datos en si y esa dirección es constante (lo que cambian son los datos).
Creando dos matrices de tipo MM:
var a = new MM([1, 2, 3], [2, 3, 4], [3, 4, 5]);
var b = new MM([1, 2, 3, 4, 5],[2, 3, 4, 5, 6], [3, 4, 5, 6, 7]);
Y llamando a "mulMat" desde la matria "a", se obtiene:
a.mulMat(b).show()
El algoritmo puede ser codificado también empleando el método push (en lugar de una sentencia de asignación):
MM.prototype.mulMat_a = function(b) {
const a = this;
const nfa = a.length;
const nfb = b.length;
const nca = a[0].length;
const ncb = b[0].length;
if (nca!==nfb) throw new Error("matrices incompatibles");
const c = [];
for (let i=0; i<nfa; i++) {
c.push([]);
for (let j=0; j<ncb; j++) {
c[i].push(0);
for (let k=0; k<nca; k++) c[i][j] += a[i][k]*b[k][j];
}
}
return c;
};
a.mulMat_a(b).show()
En lugar de iniciar la matriz resultante "c", como una matriz vacía y añadir las filas y elementos en cada ciclo, puede ser iniciada como una matriz de ceros, con el número de filas de la matriz "a" y el número de columnas de la matriz "b", siendo el diagrama de flujo correspondiente:
gojsGraph({divi, modelo: {"class":"go.GraphLinksModel","linkFromPortIdProperty":"fromPort","linkToPortIdProperty":"toPort","nodeDataArray":[{"category":"Start","text":"mulMat","key":-1,"loc":"197.00000000000003 -459.9999999999999"},{"category":"Input","text":"matrices a multiplicar: a, b","key":-3,"loc":"197 -410.46664276123033"},{"category":"Output","text":"s","key":-4,"loc":"73.00000000000006 457.9611296749852"},{"category":"Process","text":"i = 0","key":-2,"loc":"72.99999999999996 -38.333213806152244"},{"category":"Process","text":"i=i+1","key":-7,"loc":"-19.000000000000192 16.016813087463447"},{"category":"Start","text":"fin","key":-9,"loc":"197.38115692138675 500.8389393266784"},{"category":"Process","text":"nfa = num. de filas en a","key":-11,"loc":"197 -358.9332855224608"},{"category":"Process","text":"nca = num. de columnas en a","key":-12,"loc":"197 -249.39992828369134"},{"category":"Process","text":"c = [].zeros(nfa,ncb)","key":-13,"loc":"73 -92.86657104492167"},{"category":"For","text":"i<nfa","key":-6,"loc":"73.00000000000003 16.01681308746347"},{"category":"Process","text":"j = 0","key":-14,"loc":"73.00000000000003 82.36683998107924"},{"category":"Process","text":"j=j+1","key":-15,"loc":"-19.000000000000178 136.71686687469506"},{"category":"For","text":"j<ncb","key":-16,"loc":"72.99999999999991 136.71686687469497"},{"category":"Process","text":"c[i][j] = c[i][j]+a[i][k]*b[k][j]","key":-17,"loc":"73.00000000000009 324.30030479431196"},{"category":"Process","text":"ncb = num. de columnas en b","key":-18,"loc":"197.38115692138678 -194.86657104492173"},{"category":"Conditional","text":"nca!=nfb","key":-19,"loc":"197.38115692138672 -140.00000000000009"},{"category":"Output","text":"lanzar error:\n\"matrices incompatibles\"","key":-5,"loc":"361.99999999999994 189.79999923706063"},{"category":"For","text":"k<nca","key":-22,"loc":"72.99999999999994 257.9502779006959"},{"category":"Process","text":"k=k+1","key":-23,"loc":"-19.000000000000185 257.9502779006962"},{"category":"Process","text":"k = 0","key":-24,"loc":"73.00000000000001 203.60025100707998"},{"category":"Connector","text":"B","key":-27,"loc":"73.00000000000003 405.6542448354321"},{"category":"Connector","text":"A","key":-28,"loc":"73.00000000000003 366.2627372209418"},{"category":"Process","text":"nfb = num. de filas en b","key":-29,"loc":"197.76231384277344 -304.3999282836912"}],"linkDataArray":[{"from":-1,"to":-3,"fromPort":"B","toPort":"T","points":[196.99999999999997,-444.73332138061494,196.99999999999997,-434.73332138061494,197,-434.73332138061494,197,-434.7333213806152,197.00000000000006,-434.7333213806152,197.00000000000006,-424.7333213806152]},{"from":-3,"to":-11,"fromPort":"B","toPort":"T","points":[197.00000000000006,-396.19996414184567,197.00000000000006,-386.19996414184567,197.00000000000006,-386.1999641418456,197,-386.1999641418456,197,-386.1999641418455,197,-376.1999641418455]},{"from":-13,"to":-2,"fromPort":"B","toPort":"T","points":[73,-75.59989242553686,73,-65.59989242553686,72.99999999999997,-65.59989242553686,72.99999999999997,-65.599892425537,72.99999999999996,-65.599892425537,72.99999999999996,-55.59989242553701]},{"from":-2,"to":-6,"fromPort":"B","toPort":"T","points":[73,-21.066535186767545,73,-11.066535186767545,73,-11.066535186767517,73.00000000000003,-11.066535186767517,73.00000000000003,-11.066535186767489,73.00000000000003,-1.0665351867674886]},{"from":-14,"to":-16,"fromPort":"B","toPort":"T","points":[73.00000000000007,99.63351860046401,73.00000000000007,109.63351860046401,72.99999999999997,109.63351860046401,72.99999999999997,109.63351860046399,72.99999999999989,109.63351860046399,72.99999999999989,119.63351860046399]},{"from":-15,"to":-16,"fromPort":"R","toPort":"L","points":[5.9778213500974715,136.71686687469503,15.977821350097472,136.71686687469503,22.884281158447116,136.71686687469503,22.884281158447116,136.71686687469494,29.79074096679676,136.71686687469494,39.79074096679676,136.71686687469494]},{"from":-4,"to":-9,"fromPort":"B","toPort":"L","points":[73.00000000000009,470.64114401824725,73.00000000000009,480.64114401824725,73.00000000000009,500.83893932667826,118.4108170403375,500.83893932667826,163.82163408067493,500.83893932667826,173.82163408067493,500.83893932667826]},{"from":-7,"to":-6,"fromPort":"R","toPort":"L","points":[6.007133483886534,16.01681308746345,16.007133483886534,16.01681308746345,23.558635711669844,16.01681308746345,23.558635711669844,16.01681308746347,31.110137939453153,16.01681308746347,41.11013793945315,16.01681308746347]},{"from":-12,"to":-18,"fromPort":"B","toPort":"T","points":[197,-232.13324966430653,197,-222.13324966430653,197,-222.1332496643065,197.38115692138672,-222.1332496643065,197.38115692138672,-222.1332496643065,197.38115692138672,-212.1332496643065]},{"from":-19,"to":-13,"fromPort":"L","toPort":"T","visible":true,"points":[137.63391876220703,-140.00000000000009,127.63391876220703,-140.00000000000009,73,-140.00000000000009,73,-130.06662483215325,73,-120.1332496643064,73,-110.1332496643064],"text":"No"},{"from":-19,"to":-5,"fromPort":"R","toPort":"T","visible":true,"points":[257.1283950805664,-140,267.1283950805664,-140,362,-140,362,3.7888685862223213,362,147.57773717244464,362,157.57773717244464],"text":"Si"},{"from":-23,"to":-22,"fromPort":"R","toPort":"L","points":[9.936027526855284,257.95027790069605,19.936027526855284,257.95027790069605,24.06441116332997,257.95027790069605,24.06441116332997,257.95027790069616,28.19279479980466,257.95027790069616,38.19279479980466,257.95027790069616]},{"from":-24,"to":-22,"fromPort":"B","toPort":"T","points":[72.99999999999999,220.86692962646484,72.99999999999999,230.86692962646484,72.99999999999999,230.86692962646504,72.99999999999997,230.86692962646504,72.99999999999997,230.8669296264652,72.99999999999997,240.8669296264652]},{"from":-22,"to":-17,"fromPort":"B","toPort":"T","visible":true,"points":[72.99999999999997,275.0336261749271,72.99999999999997,285.0336261749271,72.99999999999997,291.033626174927,73.00000000000009,291.033626174927,73.00000000000009,297.03362617492684,73.00000000000009,307.03362617492684],"text":"Si"},{"from":-17,"to":-23,"fromPort":"L","toPort":"L","points":[-18.504814147949133,324.3003047943116,-28.504814147949133,324.3003047943116,-57.93602752685565,324.3003047943116,-57.93602752685565,291.12529134750383,-57.93602752685565,257.95027790069605,-47.93602752685565,257.95027790069605]},{"from":-5,"to":-9,"fromPort":"B","toPort":"R","points":[361.99999999999994,213.00002792358407,361.99999999999994,223.00002792358407,361.99999999999994,220,361.99999999999994,220,361.99999999999994,500.83893932667826,230.94067976209854,500.83893932667826,220.94067976209854,500.83893932667826]},{"from":-18,"to":-19,"fromPort":"B","toPort":"T","points":[197.38115692138672,-177.59989242553698,197.38115692138672,-167.59989242553698,197.38115692138672,-167.59989242553698,197.38115692138672,-170.03335723876953,197.38115692138672,-170.03335723876953,197.38115692138672,-160.03335723876953]},{"from":-11,"to":-29,"fromPort":"B","toPort":"T","points":[197,-341.666606903076,197,-331.666606903076,197.38115692138672,-331.666606903076,197.38115692138672,-331.666606903076,197.76231384277344,-331.666606903076,197.76231384277344,-321.666606903076]},{"from":-29,"to":-12,"fromPort":"B","toPort":"T","points":[197.76231384277344,-287.13324966430645,197.76231384277344,-277.13324966430645,197.76231384277344,-276.8999282836912,197,-276.8999282836912,197,-276.66660690307606,197,-266.66660690307606]},{"from":-6,"to":-14,"fromPort":"B","toPort":"T","visible":true,"points":[73.00000000000003,33.100161361694425,73.00000000000003,43.100161361694425,73.00000000000003,49.10016136169445,73.00000000000007,49.10016136169445,73.00000000000007,55.100161361694475,73.00000000000007,65.10016136169448],"text":"Si"},{"from":-16,"to":-24,"fromPort":"B","toPort":"T","visible":true,"points":[72.99999999999989,153.8002151489259,72.99999999999989,163.8002151489259,72.99999999999989,170.0668937683106,72.99999999999999,170.0668937683106,72.99999999999999,176.3335723876953,72.99999999999999,186.3335723876953],"text":"Si"},{"from":-22,"to":-28,"fromPort":"R","toPort":"R","visible":true,"points":[107.80720520019528,257.95027790069616,117.80720520019528,257.3751481056215,172,257.3751481056215,172,366.2627372209417,97.69575380724538,366.2627372209417,87.69575380724538,366.2627372209417],"text":"No"},{"from":-28,"to":-15,"fromPort":"L","toPort":"L","points":[58.30424619275478,366.2627372209417,48.30424619275478,365.0313777657443,-71,365.0313777657443,-71,136.71686687469503,-53.97782135009784,136.71686687469503,-43.97782135009784,136.71686687469503]},{"from":-16,"to":-27,"fromPort":"R","toPort":"R","visible":true,"points":[106.20925903320301,136.71686687469494,116.20925903320301,136.7584425926209,186,136.7584425926209,186,405.6542448354323,97.69575380724538,405.6542448354323,87.69575380724538,405.6542448354323],"text":"No"},{"from":-27,"to":-7,"fromPort":"L","toPort":"L","points":[58.30424619275478,405.6542448354323,48.30424619275478,405.4271285212318,-87,405.4271285212318,-87,16.016813087463447,-54.00713348388691,16.016813087463447,-44.00713348388691,16.016813087463447]},{"from":-6,"to":-4,"fromPort":"R","toPort":"R","visible":true,"points":[104.8898620605469,16.01681308746347,114.8898620605469,17.20840349197392,205,17.20840349197392,205,457.9611296749855,102.50000000000009,457.9611296749855,92.50000000000009,457.9611296749855],"text":"No"}]} })
Y el código respectivo, programado como un método estándar de la clase "MM", es:
MM.prototype.mulMat_b = function(b) {
const a = this;
const nfa = a.length;
const nfb = b.length;
const nca = a[0].length;
const ncb = b[0].length;
if (nca!==nfb) throw new Error("matrices incompatibles");
const c = [].zeros(nfa,ncb);
for (let i=0; i<nfa; i++) {
for (let j=0; j<ncb; j++) {
for (let k=0; k<nca; k++) c[i][j] += a[i][k]*b[k][j];
}
}
return c;
};
a.mulMat_b(b).show()
Aunque no es la estructura más adecuada para este caso, el problema puede ser resuelto, también, con la estructura for-of.
Para resolver el problema con otras estructuras iterativas, es importante recordar que al multiplicar dos matrices, se multiplica cada una de las filas de la matriz "a" por cada una de las columnas de la matriz "b". Con ese propósito, el primer ciclo (el más externo) recorre cada una de las filas de la matriz "a", el segundo recorre cada una de las columnas de la matriz "b" y el tercero (el más interno) simplemente multiplica los elementos de la fila "a" por los elementos de la columa "b".
Por ejemplo, para obtener el tercer elemento de la segunda fila (el elemento c[1][2]), se multiplica la segunda fila de la matriz "a" ([2, 3, 4l) por la tercera columna de la matriz "b" ([3, 4, 5]), es decir:
2*3+3*4+4*5
Siendo estas operaciones que se deben realizar en el tercer ciclo.:
Entonces, como al multiplicar las matrices se trabaja con las columnas de la matriz "b", pero los métodos iteran por las filas (no las columnas), se debe trabajar con la transpuesta de la matriz "b".
Una vez comprendido el procedimiento, se puede resolver el problema con la estructura for-of:
MM.prototype.mulMat_c = function(b) {
const a = this;
b = b.transpose();
if (a[0].length!==b[0].length) throw new Error("matrices incompatibles");
const c = [];
for (const fa of a) {
let fc = [];
for (const fb of b) {
let s = 0, k = 0;
for(const e of fa) s += e*fb[k++];
fc.push(s);
}
c.push(fc);
}
return c;
};
a.mulMat_c(b).show()
Donde la matriz resultante "c" se incia en una matriz vacía. En el primer ciclo se obtienen las filas "fa" de la matriz "a" y se crean las filas "fc" de la matriz "c" resultante. En el segundo ciclo se obtienen las filas "fb" de la matriz invertida "b" y se inician el caumulador "s" y el contador "k", que son necesarios para calcular los elementos "s" del vector "fc". En el tercer ciclo se calculan los elementos "s" de la fila "fc", multiplicando y añadiendo a "s", los elementos "k" del vector "fa" por los elementos "k" del vector "fb", luego se añaden esos elementos a la fila "fc" y finalmente, se añaden las filas "fc" a la matriz resultante "c".
Se pueden lograr soluciones más compactas, si en el ciclo más interno, se emplea otra estructura iterativa. Por ejemplo, con "reduce" se tiene la siguiente solución:
MM.prototype.mulMat_d = function(b) {
const a = this;
b = b.transpose();
if (a[0].length!==b[0].length) throw new Error("matrices incompatibles");
const c = [];
for (const fa of a) {
let fc = [];
for (const fb of b) {
fc.push(fa.reduce((s,e,k)=>s+=fa[k]*fb[k],0));
}
c.push(fc);
}
return c;
};
a.mulMat_d(b).show()
En este caxo no es necesario incrementar el contador "k" (pues la estructura "reduce" lo hace automáticamente). Por supuesto, en lugar de "fa[k]" se puede emplear la variable "e", pero se emplea "fa[k]", para que la lógica resulte más clara.
Siguiendo un razonamiento similar, el problema puede ser resuelto, igualmente, con los métodos iterativos disponibles para arrays. Así, empleando el método forEach, el problema se resuelve con:
MM.prototype.mulMat_e = function(b) {
const a = this;
b = b.transpose();
if (a[0].length!==b[0].length) throw new Error("matrices incompatibles");
const c = [];
a.forEach(fa=>{
let fc = [];
b.forEach(fb=>{
let s = 0;
fa.forEach((e,k)=>s+=fa[k]*fb[k]);
fc.push(s);
});
c.push(fc);
});
return c;
};
a.mulMat_e(b).show()
En este caso, como la función forEach puede recibir también el contador (el índice del elemento) no es necesario iniciar, ni incrementar (en el ciclo más interno) el contador "k". Además, como las funciones de forEach son relativamente complejas, son declaradas de la manera tradicional, es decir empleando llaves y puntos y comas en lugar de paréntesis y comas.
De manera similar, se pueden emplear los otros métodos, por ejemplo, con el método some, el código, es:
MM.prototype.mulMat_f = function(b) {
const a = this;
b = b.transpose();
if (a[0].length!==b[0].length) throw new Error("matrices incompatibles");
const c = [];
a.some(fa=>{
let fc = [];
b.some(fb=>{
let s = 0;
fa.some((e,k)=>{s+=fa[k]*fb[k]; return 0;});
fc.push(s);
return 0;
});
c.push(fc);
return 0;
});
return c;
};
a.mulMat_f(b).show()
Donde, como ya se vio en el capítulo anterior, las funciones de "some" devuelven un valor falso (en este caso 0), para garantizar que se itere con todos los elementos del array. Al igual que el canso anterior, dado que las funciones son relativamente complejas, las funciones se crean de la forma tradicional.
Rotar las columnas de una matriz
En este ejemplo se elabora un método que rota, hacia la derecha, las columnas de la matriz desde la cual es llamado.
Para rotar las columnas de una matriz hacia la derecha, dado que las matrices están conformadas por vectores fila (no vectores columna) es deben recorrer los elementos de cada fila (desde la primer hasta la última fila) una posición hacia la derecha. Para ello simplemente el último elemento toma el valor del penúltimo, el penúltimo del antepenúltimo y así sucesivamente hasta que el segundo elemento toma el valor del primero.
Sin embargo, en este proceso se pierde el valor del último elemento (porque es reemplazado por el penúltimo). Por esta razón, es necesario guardar ese elemento en una variable auxiliar y una vez rotados los elementos, asignar ese valor al primer elemento.
El diagrama de flujo correspondiente al algoritmo explicado, es:
gojsGraph({divi, modelo: {"class":"go.GraphLinksModel","linkFromPortIdProperty":"fromPort","linkToPortIdProperty":"toPort","nodeDataArray":[{"category":"Start","text":"rotarcd","key":-1,"loc":"197.00000000000003 -459.9999999999999"},{"category":"Input","text":"matriz de números: a","key":-3,"loc":"197 -410.46664276123033"},{"category":"Output","text":"a","key":-4,"loc":"197.00000000000014 156.47806065877288"},{"category":"Process","text":"i = 0","key":-2,"loc":"196.99999999999997 -249.33321380615226"},{"category":"Process","text":"i=i+1","key":-7,"loc":"101.99999999999983 -194.98318691253647"},{"category":"Start","text":"fin","key":-9,"loc":"197.00000000000028 209.35587031046575"},{"category":"Process","text":"n = num. de filas en a","key":-11,"loc":"197 -358.9332855224608"},{"category":"Process","text":"m = num. de columnas en a","key":-12,"loc":"197 -304.3999282836913"},{"category":"For","text":"i<n","key":-6,"loc":"197.00000000000003 -194.98318691253652"},{"category":"Process","text":"aux = a[i][m-1]","key":-14,"loc":"197 -128.63316001892082"},{"category":"Process","text":"j=j-1","key":-15,"loc":"108.99999999999987 -19.283133125305064"},{"category":"For","text":"j>0","key":-16,"loc":"196.99999999999994 -19.28313312530505"},{"category":"Process","text":"a[i][j] = a[i][j-1]","key":-17,"loc":"197.00000000000014 47.066893768310656"},{"category":"Process","text":"j = m-1","key":-19,"loc":"197 -75.63316001892082"},{"category":"Process","text":"a[i][0] = aux","key":-20,"loc":"197.00000000000014 101.60025100708019"}],"linkDataArray":[{"from":-1,"to":-3,"fromPort":"B","toPort":"T","points":[197.00000000000006,-444.7333213806148,197.00000000000006,-434.7333213806148,197.00000000000003,-434.7333213806148,197.00000000000003,-434.7333213806151,197,-434.7333213806151,197,-424.7333213806151]},{"from":-3,"to":-11,"fromPort":"B","toPort":"T","points":[197,-396.1999641418456,197,-386.1999641418456,197,-386.1999641418456,197,-386.1999641418456,197,-386.1999641418456,197,-376.1999641418456]},{"from":-11,"to":-12,"fromPort":"B","toPort":"T","points":[197,-341.66660690307606,197,-331.66660690307606,197,-331.66660690307606,197,-331.66660690307606,197,-331.66660690307606,197,-321.66660690307606]},{"from":-2,"to":-6,"fromPort":"B","toPort":"T","points":[197,-232.06653518676754,197,-222.06653518676754,197,-222.0665351867675,197,-222.0665351867675,197,-222.06653518676745,197,-212.06653518676745]},{"from":-6,"to":-14,"fromPort":"B","toPort":"T","visible":true,"points":[197,-177.89983863830554,197,-167.89983863830554,197,-161.89983863830557,197.00000000000006,-161.89983863830557,197.00000000000006,-155.8998386383056,197.00000000000006,-145.8998386383056],"text":"Si"},{"from":-16,"to":-17,"fromPort":"B","toPort":"T","visible":true,"points":[196.99999999999994,-2.1997848510740923,196.99999999999994,7.800215148925908,196.99999999999994,13.800215148925899,197.00000000000014,13.800215148925899,197.00000000000014,19.80021514892589,197.00000000000014,29.80021514892589],"text":"Si"},{"from":-17,"to":-15,"fromPort":"L","toPort":"B","points":[142.12315368652358,47.066893768310656,132.12315368652358,47.066893768310656,108.99999999999987,47.066893768310656,108.99999999999987,27.525219631195178,108.99999999999987,7.983545494079699,108.99999999999987,-2.0164545059203007]},{"from":-15,"to":-16,"fromPort":"R","toPort":"L","points":[132.2699279785155,-19.283133125305067,142.2699279785155,-19.283133125305067,151.7026596069335,-19.283133125305067,151.7026596069335,-19.28313312530505,161.1353912353515,-19.28313312530505,171.1353912353515,-19.28313312530505]},{"from":-6,"to":-4,"fromPort":"R","toPort":"R","visible":true,"points":[222.7033462524414,-194.9831869125365,232.7033462524414,-195.99159345626825,299,-195.99159345626825,299,156.4780606587729,226.50000000000014,156.4780606587729,216.50000000000014,156.4780606587729],"text":"No"},{"from":-4,"to":-9,"fromPort":"B","toPort":"T","points":[197.00000000000014,169.15807500203462,197.00000000000014,179.15807500203462,197.00000000000014,181.6236333465577,197.00000000000014,181.6236333465577,197.00000000000014,184.08919169108083,197.00000000000014,194.08919169108083]},{"from":-7,"to":-6,"fromPort":"R","toPort":"L","points":[127.00713348388658,-194.9831869125365,137.00713348388658,-194.9831869125365,149.1518936157226,-194.9831869125365,149.1518936157226,-194.9831869125365,161.2966537475586,-194.9831869125365,171.2966537475586,-194.9831869125365]},{"from":-12,"to":-2,"fromPort":"B","toPort":"T","points":[197,-287.1332496643065,197,-277.1332496643065,197,-276.8665710449218,197,-276.8665710449218,197,-276.59989242553706,197,-266.59989242553706]},{"from":-14,"to":-19,"fromPort":"B","toPort":"T","points":[197,-111.36648139953607,197,-101.36648139953607,197,-101.36648139953607,197,-102.89983863830558,197,-102.89983863830558,197,-92.89983863830558]},{"from":-19,"to":-16,"fromPort":"B","toPort":"T","points":[197,-58.36648139953604,197,-48.36648139953604,197,-47.36648139953603,196.99999999999994,-47.36648139953603,196.99999999999994,-46.366481399536006,196.99999999999994,-36.366481399536006]},{"from":-16,"to":-20,"fromPort":"R","toPort":"R","visible":true,"points":[222.86460876464838,-19.28313312530505,232.86460876464838,-20.141566562652525,276,-20.141566562652525,276,101.60025100708019,252.70703887939467,101.60025100708019,242.70703887939467,101.60025100708019],"text":"No"},{"from":-20,"to":-7,"fromPort":"L","toPort":"L","points":[151.2929611206056,101.60025100708019,141.2929611206056,101.60025100708019,56,101.60025100708019,56,-194.9831869125365,66.99286651611314,-194.9831869125365,76.99286651611314,-194.9831869125365]}]} })
Siendo el código respectivo, implementado como un método getter de la clase "RC", que hereda de (extiende a) la clase Array:
var RC = class extends Array {
get rotarcd() {
const a = this;
const n = a.length;
const m = a[0].length;
for (let i=0; i<n; i++) {
const aux = a[i][m-1];
for (let j=m-1; j>0; j--) a[i][j] = a[i][j-1];
a[i][0] = aux;
}
return a;
};
};
Que puede ser probada, por ejemplo, rotando 2 veces una matriz pseudoaleatoria (semilla = 1) de 5 filas y 7 columnas de números enteros comprendidos entre 10 y 30:
randseed = 1;
var a = new RC(...[].rand(5, 7, 20, 30).round());
a.show()
a.rotarcd.show()
a.rotarcd.show()
El problema puede ser resuelto, igualmente, empleando la estructura for-of
Object.defineProperty(RC.prototype, "rotarcd_a", {
get() {
const a = this;
const m = a[0].length-1;
let aux, k;
for(const f of a) {
aux = f[m]; k = m;
for(const e of f) f[k] = k===0 ? aux : f[--k];
}
return a;
},
configurable: true
});
randseed = 1;
var a = new RC(...[].rand(3, 4, 1, 9).round());
a.show()
a.rotarcd_a.show()
a.rotarcd_a.show()
En este caso, el ciclo externo itera para cada una de las filas "f" de la matriz "a". Dentro del ciclo se guarda (en "aux") el último elemento de la fila ("f[m]") y en "k" el índice del último elemento (m). En el ciclo interno, se itera para cada uno de los elementos "e" de la fila "f", los elementos "e" en realidad no son utilizados en la función, porque, la estructura "for-of" se emplea únicamente para iterar un número de veces igual al número de elementos de cada fila.
En cada iteración del ciclo interno, se recorre un elmeento hacia la derecha, hasta que se llega al primer elemento (k===0), donde se le asigna el valor del último elemento.
Con un razonamiento similar, se pueden emplear también otros métodos iterativos. Por ejemplo con el método every, el código que resuelve el problema, es:
Object.defineProperty(RC.prototype, "rotarcd_b", {
get() {
const a = this;
const m = a[0].length-1;
let aux;
a.every(f=>{
aux = f[m],
f.every((e,k)=>{f[m-k] = k===m ? aux : f[m-k-1]; return 1});
return 1;
});
return a;
},
configurable: true
});
randseed = 1;
var a = new RC(...[].rand(3, 4, 1, 9).round());
a.show()
a.rotarcd_a.show()
a.rotarcd_a.show()
Donde, al igual que con some y por la misma razón, las funciones se escriben en la forma tradicional (empleando llaves), pero al ser el método "every", las funciones devuelven un valor verdadero (en este caso 1) para garantizar que se itere con todos los elementos del array.
En el ciclo interno, como el contador "k" inicia en 0 y se requiere al último elemento (no al primero), los índices se calculan con m-k, para que en la primera iteración sea el último elemento: m-0 = m, en la siguiente el penúltimo: m-1 y así sucesivamente. Pero, cuando se llega al primer elemento (cuando "k" es igual a "m": m-m = 0), se asigna el valor del último elemento (guardado en la variable auxiliar), por eso en la función se pregunta si "m" es igual a "k" y de ser así, se le asigna el valor de "aux".
Cuando lo que se quiere se rotar las filas de la matriz, no las columnas, solo es neceario un ciclo (no dos) porque en una matriz, las filas son simplemente elementos de la matriz, en consecuencia, el problema se reduce a rotar esos elementos.