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 ya se hizo notar en el capítulo anterior, el uso de map, para resolver este tipo de problemas, no es eficiente, porque map genera una nueva matriz (con los resultados intermedios de la sumatoria) y no es ni lógico, ni eficiente, crear una matriz que al final no es empleada.
Empleando el método reduce, el problema se resuelve de la siguiente manera:
En este caso, el primer reduce itera para cada una de las filas "f" de la matriz, mientras que el segundo (que es llamado desde cada una de las filas "f") itera para cada uno de los elementos "e" de cada fila. Para que el primer reduce itere desde la primera fila de la matriz (y no directamente desde la segunda) se le manda un valor inicial "0" (que es guardado en el acumulador "s"). Para cada una de las iteraciones del reduce externo, el interno devuelve la sumatoria de los elementos "e" de la fila respectiva y ese resultado es añadido a la sumatoria de las filas de la matriz.
Es importante tomar en cuanta que, aunque se ha dado el mismo nombre ("s") tanto al acumulador interno, como al externo, son dos acumuladores diferentes (el interno devuelve la sumatoria de los elementos "e" de la fila "f", mientras que el externo devuelve la sumatoria de las filas "f" de la matriz "a").
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
La lógica es la misma que con forEach, sólo que para que every itere para todas las filas y para todos los elementos de cada fila, las funciones tanto interna, como externa, devuelven 1, que es uno de los valores equivalentes a true (por supuesto se puede devolver directamente true en lugar de 1).
De manera similar se pueden emplear los métodos filter, some, find, findLast, findIndex, findLastIndex, sin embargo, como ya se ha recalcado en el capítulo anterior, estos métodos no son adecuados para resolver este tipo de problemas. Se emplean en la asignatura, únicamente con el propósito de ayudar a comprender su lógica.
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 (u objeto), no los valores en si y esa dirección no cambia en todo el proceso (es constante).
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 esas las operaciones que se llevan a cabo en el tercer ciclo.:
Entonces, si "fa" es la fila de la matriz "a" y "cb" es la columna de la matriz "b", el elemento resultante, puede ser calculado en un ciclo:
var fa = [2, 3, 4]; var cb = [3, 4, 5]; var s = 0; for (let k=0; k<fa.length; k++) s += fa[k]*cb[k]; s
En consecuencia, para obtener la primera fila de la matriz resultante, se debe multiplicar la primera fila de la matriz "a", por cada una de las columnas de la matriz "b", luego, para la segunda fila, se multiplica la segunda fila de la matriz "a" por cada una de las columnas de la matriz "b" y así sucesivamente.
Como al multiplicar las matrices se trabaja con las columnas de la matriz "b", pero los métodos iteran a través de las filas (no las columnas), para resolver el problema, empleando los métodos iterativos, 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 cb of b) {
let ec = 0, k = 0;
for(const ea of fa) ec += ea*cb[k++];
fc.push(ec);
}
c.push(fc);
}
return c;
};
a.mulMat_c(b).show()
En esta solución, en el primer ciclo (el ciclo externo) se itera para cada una de las filas "fa" de la matriz "a". En el segundo ciclo (el primer ciclo anidado) se itera para cada una de las columnas "cb" de la matriz "b" (porque se está trabajando con la matriz transpuesta) y en el tercer ciclo (el ciclo más interno) se itera para cada uno de los elementos "ea" de cada una de las filas "fa" de la matriz "a".
Antes del primer ciclo se crea la matriz (vacía) resultante "c", en el priner ciclo se crea (en cada iteración) cada una de las filas (vacías) "fc" de la matriz resultante. En el segundo ciclo, se inicia en 0 cada uno de los elementos "ec" de la fila "fc" y se inicia en 0 el contador "k" de la columna "cb". En el tercer ciclo se calcula el valor del elemento "ec" (multiplicando los elementos "ea" de la fila "fa" por los elementos cb[k] de la columna "cb"). En este ciclo, se emplea el operador ++, para incrementar el valor del contador, inmediatamente después de recuperar el valor del elemento "b[k]".
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 cb of b) {
fc.push(fa.reduce((ec,ea,k)=>ec+=ea*cb[k],0));
}
c.push(fc);
}
return c;
};
a.mulMat_d(b).show()
En este caso no es necesario incrementar el contador "k" (pues la estructura "reduce" lo hace automáticamente).
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 = [].zeros(a.length, b.length);
a.forEach((fa,i)=>{
b.forEach((cb,j)=>{
fa.forEach((ea,k)=>c[i][j]+=ea*cb[k]);
});
});
return c;
};
a.mulMat_e(b).show()
En este caso, como la función forEach puede recibir también el contador (el índice de cada elemento) no es necesario declarar, iniciar, incrementar ni reiniciar los contadores.
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 = [].zeros(a.length, b.length);
a.some((fa,i)=>(
b.some((cb,j)=>(
fa.some((ea,k)=>(c[i][j]+=ea*cb[k], 0)), 0)),
0));
return c;
};
a.mulMat_f(b).show()
Donde las funciones de "some" devuelven un valor falso (en este caso 0) para garantizar que se itere con todos los elementos del array. Además, para evitar escribir el comando return, las instrucciones de las funciones se escriben entre paréntesis y se separan con comas, de manera que sean ejecutadas como si se tratara de una sola instrucción (tal como se explicó en el capítulo previo).
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) se 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(let _ 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 "_" de la fila "f", los elementos "_" en realidad no son utilizados en la función (siendo esa la razón por la se les da ese nombre). La estructura "for-of" se emplea únicamente para iterar un número de veces igual al número de elementos de cada fila (razón por la cual no es la estructura más adecuada para resolver este problema).
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((_,k)=>(f[m-k] = k===m ? aux : f[m-k-1], 1)), 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 entre paréntesis, sólo que ahora se devuelve un valor equivalente a true (1).
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.