Behaviour of objects

R

RobG

I was playing with matrices and wrote a routine to return the minor
matrix if given a matrix and index. The minor is the matrix given by
removing the first row and i-th column.

e.g. using JavaScript indices and a 3x3 matrix:

if A = | 1 2 3 |
| 4 5 6 |
| 7 8 9 |

then minor(A,0) = | 5 6 |
| 8 9 |

minor(A,1) = | 4 6 |
| 7 9 |

minor(A,2) = | 4 5 |
| 7 8 |

Here's my routine to do it:

// A is a square matrix
// i is the minor index
function minor(A, i) {
A.shift()
var j = A.length;
while (j--) {
A[j].splice(i,1);
}
return A;
}

But when I pass it a matrix (object with arrays) the original object is
modified as well. Kinda sux because the alternative is to copy the
elements across individually. What's going on?

Here's a test case that shows ob3 before being passed to the routine,
what is returned and then the state of ob3 afterward. The minor matrix
is correct, but the original ob3 has been modified.

<input type="button" value="minor test" onclick="
var ob3 = [];
ob3[0] = [ 1, 2, 3 ];
ob3[1] = [ 4, 5, 6 ];
ob3[2] = [ 7, 8, 9 ];

alert('ob3 before:\n' + ob3.join('\n'));
alert('minor(0): \n' + minor(ob3, 0).join('\n'));
alert('ob3 after: \n' + ob3.join('\n'));
">

<script type="text/javascript">
function minor(A, i) {
A.shift()
var j = A.length;
while (j--) {
A[j].splice(i,1);
}
return A;
}
</script>
 
M

Michael Winter

I was playing with matrices [...]

Ughh. Useful, but I hate them.

[snip]
// A is a square matrix
// i is the minor index
function minor(A, i) {
A.shift()
var j = A.length;
while (j--) {
A[j].splice(i,1);
}
return A;
}

But when I pass it a matrix (object with arrays) the original object is
modified as well. Kinda sux because the alternative is to copy the
elements across individually. What's going on?

Though assigning directly to A won't alter the matrix, modifying
properties of A, or calling methods which modify their objects (which
both shift and splice do) will. Objects are referenced; you don't get
copies. I think you have little option but to alter your algorithm to
extract the data, or copy the object yourself, first.

Mike
 
R

RobG

Michael said:
I was playing with matrices [...]

Ughh. Useful, but I hate them.

[snip]
// A is a square matrix
// i is the minor index
function minor(A, i) {
A.shift()
var j = A.length;
while (j--) {
A[j].splice(i,1);
}
return A;
}

But when I pass it a matrix (object with arrays) the original object is
modified as well. Kinda sux because the alternative is to copy the
elements across individually. What's going on?

Though assigning directly to A won't alter the matrix, modifying
properties of A, or calling methods which modify their objects (which
both shift and splice do) will. Objects are referenced; you don't get
copies. I think you have little option but to alter your algorithm to
extract the data, or copy the object yourself, first.

I tried:

var A = ob3;

But that seems to just create a new reference to the same object. Also
tried copying this way:

var A = [];
var i=0;
while ( ob3 ) {
A = ob3;
i++;
}

But same issue - each row is just a reference to a row in ob3. A
pleasant bonus is mangling of the matrix by minor(). Final attempt:

var A = [];
var j, i=0;
do {
j=0;
A = [];
do {
A[j] = ob3[j];
} while ( undefined != ob3[++j] )
} while ( ob3[++i] )

The 'copy' is now done inside the minor() function with the appropriate
elements omitted during the process - pity, splice(), shift() et al are
such cool methods.
 
M

Mick White

RobG said:
I was playing with matrices and wrote a routine to return the minor
matrix if given a matrix and index. The minor is the matrix given by
removing the first row and i-th column.

e.g. using JavaScript indices and a 3x3 matrix:

if A = | 1 2 3 |
| 4 5 6 |
| 7 8 9 |

then minor(A,0) = | 5 6 |
| 8 9 |

minor(A,1) = | 4 6 |
| 7 9 |

minor(A,2) = | 4 5 |
| 7 8 |

Here's my routine to do it:

// A is a square matrix
// i is the minor index
function minor(A, i) {
A.shift()
var j = A.length;
while (j--) {
A[j].splice(i,1);
}
return A;
}

But when I pass it a matrix (object with arrays) the original object is
modified as well. Kinda sux because the alternative is to copy the
elements across individually. What's going on?

Here's a test case that shows ob3 before being passed to the routine,
what is returned and then the state of ob3 afterward. The minor matrix
is correct, but the original ob3 has been modified.

<input type="button" value="minor test" onclick="
var ob3 = [];
ob3[0] = [ 1, 2, 3 ];
ob3[1] = [ 4, 5, 6 ];
ob3[2] = [ 7, 8, 9 ];

alert('ob3 before:\n' + ob3.join('\n'));
alert('minor(0): \n' + minor(ob3, 0).join('\n'));
alert('ob3 after: \n' + ob3.join('\n'));
">

<script type="text/javascript">
function minor(A, i) {
A.shift()
var j = A.length;
while (j--) {
A[j].splice(i,1);
}
return A;
}
</script>
You need to copy "A", B=A.slice(0);Mick
 
R

RobG

Mick said:
RobG said:
I was playing with matrices and wrote a routine to return the minor
matrix if given a matrix and index. The minor is the matrix given by
removing the first row and i-th column. [...]

<script type="text/javascript">
function minor(A, i) {
A.shift()
var j = A.length;
while (j--) {
A[j].splice(i,1);
}
return A;
}
</script>
You need to copy "A", B=A.slice(0);Mick

Nope, doesn't work. It's effectively the same as copying the rows to
the new matrix, then slicing them - the original matrix is mangled.

if have:
var ob3 = [];
ob3[0] = [ 1, 2, 3 ];
ob3[1] = [ 4, 5, 6 ];
ob3[2] = [ 0, 0, 0 ];

minor(ob3,0) becomes:

[ 5, 6 ]
[ 0, 0 ]

which is correct, but ob3 becomes:

[ 1, 2, 3 ]
[ 4, 5 ]
[ 0, 0 ]

which no longer represents anything useful - as soon as I try for the
next minor matrix, the script bombs.

For the record, I was doing this to play with an algorithm to produce
the determinant of an n_x_n matrix. Full solution below - please test
to your heart's content, I'd love to know of errors or optimisations.
I've tested a few manual examples, plus the standard few for zero
results.

Seems to work OK in Safari, Firefox (Windows & Mac) and IE.


*************** Sample stuff ***************

<table style="border-collapse: collapse;">
<tr>
<td style="background-color: #D8DFE0; text-align: center;
vertical-align: top;">
<input type="button" onclick="
document.getElementById('result').innerHTML = showObj(2);
" value="Determinant 2x2"><br>
<input type="button" onclick="
document.getElementById('result').innerHTML = showObj(3);
" value="Determinant 3x3"><br>
<input type="button" onclick="
document.getElementById('result').innerHTML = showObj(4);
" value="Determinant 4x4"><br>
<input type="button" onclick="
document.getElementById('result').innerHTML = showObj(5);
" value="Determinant 5x5"><br>
<input type="button" onclick="
document.getElementById('result').innerHTML = showObj('5a');
" value="Determinant 5x5 a"><br>
<input type="button" onclick="
document.getElementById('result').innerHTML = showObj('5b');
" value="Determinant 5x5 b"><br>
<input type="button" onclick="
document.getElementById('result').innerHTML = showObj('5c');
" value="Determinant 5x5 c"><br>
</td>
<td style="width: 20em; height: 15em; background-color: #D8DFE0;
text-align: center; vertical-align: top;">
<span id="result" style="vertical-align: top;"></span>
</td>
</tr>
</table>


******** SCRIPT *******

// Just for testing

function showObj(x){

var ob2 = []
ob2[0] = [ 1, 2 ]
ob2[1] = [ 3, 4 ]

var ob3 = []
ob3[0] = [ 1, 2, 3 ]
ob3[1] = [ 4, 5, 6 ]
ob3[2] = [ 7, 8, 9 ]

var ob4 = []
ob4[0] = [ 1, 2, 3, 3 ]
ob4[1] = [ 4, 5, 6, 1 ]
ob4[2] = [ 7, 8, 9, 2 ]
ob4[3] = [ 1, 1, 2, 3 ]

var ob5 = []
ob5[0] = [ 1, 0, 4, -2, 0 ]
ob5[1] = [ 4, 1, 6, -2, 0 ]
ob5[2] = [ 0, 7, 1, 0, -7 ]
ob5[3] = [ 0, -6, 8, 1, 0 ]
ob5[4] = [ -9, 0, 0, 5, 1 ]

// 5x5 with column of zeros: - det = 0
var ob5a = []
ob5a[0] = [ 1, 0, 0, 6, 0 ]
ob5a[1] = [ 4, 1, 0, -2, 0 ]
ob5a[2] = [ 0, 7, 0, 0, -7 ]
ob5a[3] = [ 0, -6, 0, 1, 0 ]
ob5a[4] = [ -9, 0, 0, 5, 1 ]

var ob5b = []
ob5b[0] = [ 1, 0, 4, -2, 0 ]
ob5b[1] = [ 4, 1, 6, -2, 0 ]
ob5b[2] = [ 0, 0, 0, 0, 0 ] // row of zeros: - det = 0
ob5b[3] = [ 0, -6, 8, 1, 0 ]
ob5b[4] = [ -9, 0, 0, 5, 1 ]

var ob5c = []
ob5c[0] = [ 1, 0, 4, -2, 0 ]
ob5c[1] = [ 4, 1, 6, -2, 0 ]
ob5c[2] = [ 0, 7, 1, 0, -7 ]
ob5c[3] = [ 0, -6, 8, 1, 0 ]
ob5c[4] = [ 0, -6, 8, 1, 0 ] // identical row: det = 0


if ( 2 == x ) {
return '<b>2x2</b><br>'+ob2.join('<br>')+'<br>'+det(ob2);

} else if ( 3 == x) {
return '<b>3x3</b><br>'+ob3.join('<br>')+'<br>'+det(ob3);
} else if ( 4 == x) {
return '<b>4x4</b><br>'+ob4.join('<br>') +'<br>'+det(ob4);
} else if ( 5 == x) {
return '<b>5x5</b><br>'+ob5.join('<br>') +'<br>'+det(ob5);
} else if ( '5a' == x) {
return '<b>5x5 (column of zeros)</b><br>'
+ ob5a.join('<br>') + '<br>' + det(ob5a);
} else if ( '5b' == x) {
return '<b>5x5 (row of zeros)</b><br>'
+ ob5b.join('<br>') + '<br>' + det(ob5b);
} else if ( '5c' == x) {
return '<b>5x5 (identical row)</b><br>'
+ ob5c.join('<br>') + '<br>' + det(ob5c);
}
}

<script type="text/javascript">
/* det()
Finds the determinant of a square matrix using determinant
expansion by minors (or "Laplacian expansion by minors,"
or sometimes "Laplacian expansion")

if A = | a1 a2 |
| b1 b2 |

detA = a1.b2 - a2.b1

if A = | a1 a2 a3 |
| b1 b2 b3 |
| c1 c2 c3 |

detA = a1(b2.c3 - b3.c2) - a2(b1.c3 - b3.c1) + a3(b1.c2 - b2.c1)
= a1.b2.c3 - a1.b3.c2 - a2.b1.c3 + a2.b3.c1
+ a3.b1.c2 - a3.b2.c1
etc.

Information derived from the Wolfram site:
http://mathworld.wolfram.com/Determinant.html
*/

// Doesn't check squareness or size
function det(a) {
var i = a[0].length;
if ( 2 == i ) { // det of 2x2
return +a[0][0]*a[1][1] - +a[0][1]*a[1][0];
} else {
var x=0;
var j=0;
do {
if ( 0 != +a[0][j] ) { // Speed opt - don't do if factor is 0
if (j%2) { // add even columns, subtract odd
x -= a[0][j] * det( minor(a, j) );
} else {
x += a[0][j] * det( minor(a, j) );
}
}
} while ( ++j < i )
return x;
}
}

// Returns the i-th minor of square matrix b
// remove top row, remove i-th element of remaining rows
// Doesn't check squareness or size
function minor(A, i){
var B = [];
var k, n, j=1; // Skip first row of A
do {
k=0; // A column
n=0; // B column
B[j-1] = []; // New row for B
do {
if ( k != i ) { // Skip i-th element
B[j-1][n++] = A[j][k];
}
} while ( undefined != A[j][++k] )
} while ( A[++j] )
return B;
}
</script>
 
M

Mick White

RobG said:

I'll check ot out, Rob.
Mick
<script type="text/javascript">
function minor(A, i) {
A.shift()
var j = A.length;
while (j--) {
A[j].splice(i,1);
}
return A;
}
</script>
You need to copy "A", B=A.slice(0);Mick


Nope, doesn't work. It's effectively the same as copying the rows to
the new matrix, then slicing them - the original matrix is mangled.

if have:
var ob3 = [];
ob3[0] = [ 1, 2, 3 ];
ob3[1] = [ 4, 5, 6 ];
ob3[2] = [ 0, 0, 0 ];

minor(ob3,0) becomes:

[ 5, 6 ]
[ 0, 0 ]

which is correct, but ob3 becomes:

[ 1, 2, 3 ]
[ 4, 5 ]
[ 0, 0 ]

which no longer represents anything useful - as soon as I try for the
next minor matrix, the script bombs.

For the record, I was doing this to play with an algorithm to produce
the determinant of an n_x_n matrix. Full solution below - please test
to your heart's content, I'd love to know of errors or optimisations.
I've tested a few manual examples, plus the standard few for zero
results.

Seems to work OK in Safari, Firefox (Windows & Mac) and IE.


*************** Sample stuff ***************

<table style="border-collapse: collapse;">
<tr>
<td style="background-color: #D8DFE0; text-align: center;
vertical-align: top;">
<input type="button" onclick="
document.getElementById('result').innerHTML = showObj(2);
" value="Determinant 2x2"><br>
<input type="button" onclick="
document.getElementById('result').innerHTML = showObj(3);
" value="Determinant 3x3"><br>
<input type="button" onclick="
document.getElementById('result').innerHTML = showObj(4);
" value="Determinant 4x4"><br>
<input type="button" onclick="
document.getElementById('result').innerHTML = showObj(5);
" value="Determinant 5x5"><br>
<input type="button" onclick="
document.getElementById('result').innerHTML = showObj('5a');
" value="Determinant 5x5 a"><br>
<input type="button" onclick="
document.getElementById('result').innerHTML = showObj('5b');
" value="Determinant 5x5 b"><br>
<input type="button" onclick="
document.getElementById('result').innerHTML = showObj('5c');
" value="Determinant 5x5 c"><br>
</td>
<td style="width: 20em; height: 15em; background-color: #D8DFE0;
text-align: center; vertical-align: top;">
<span id="result" style="vertical-align: top;"></span>
</td>
</tr>
</table>


******** SCRIPT *******

// Just for testing

function showObj(x){

var ob2 = []
ob2[0] = [ 1, 2 ]
ob2[1] = [ 3, 4 ]

var ob3 = []
ob3[0] = [ 1, 2, 3 ]
ob3[1] = [ 4, 5, 6 ]
ob3[2] = [ 7, 8, 9 ]

var ob4 = []
ob4[0] = [ 1, 2, 3, 3 ]
ob4[1] = [ 4, 5, 6, 1 ]
ob4[2] = [ 7, 8, 9, 2 ]
ob4[3] = [ 1, 1, 2, 3 ]

var ob5 = []
ob5[0] = [ 1, 0, 4, -2, 0 ]
ob5[1] = [ 4, 1, 6, -2, 0 ]
ob5[2] = [ 0, 7, 1, 0, -7 ]
ob5[3] = [ 0, -6, 8, 1, 0 ]
ob5[4] = [ -9, 0, 0, 5, 1 ]

// 5x5 with column of zeros: - det = 0
var ob5a = []
ob5a[0] = [ 1, 0, 0, 6, 0 ]
ob5a[1] = [ 4, 1, 0, -2, 0 ]
ob5a[2] = [ 0, 7, 0, 0, -7 ]
ob5a[3] = [ 0, -6, 0, 1, 0 ]
ob5a[4] = [ -9, 0, 0, 5, 1 ]

var ob5b = []
ob5b[0] = [ 1, 0, 4, -2, 0 ]
ob5b[1] = [ 4, 1, 6, -2, 0 ]
ob5b[2] = [ 0, 0, 0, 0, 0 ] // row of zeros: - det = 0
ob5b[3] = [ 0, -6, 8, 1, 0 ]
ob5b[4] = [ -9, 0, 0, 5, 1 ]

var ob5c = []
ob5c[0] = [ 1, 0, 4, -2, 0 ]
ob5c[1] = [ 4, 1, 6, -2, 0 ]
ob5c[2] = [ 0, 7, 1, 0, -7 ]
ob5c[3] = [ 0, -6, 8, 1, 0 ]
ob5c[4] = [ 0, -6, 8, 1, 0 ] // identical row: det = 0


if ( 2 == x ) {
return '<b>2x2</b><br>'+ob2.join('<br>')+'<br>'+det(ob2);

} else if ( 3 == x) {
return '<b>3x3</b><br>'+ob3.join('<br>')+'<br>'+det(ob3);
} else if ( 4 == x) {
return '<b>4x4</b><br>'+ob4.join('<br>') +'<br>'+det(ob4);
} else if ( 5 == x) {
return '<b>5x5</b><br>'+ob5.join('<br>') +'<br>'+det(ob5);
} else if ( '5a' == x) {
return '<b>5x5 (column of zeros)</b><br>'
+ ob5a.join('<br>') + '<br>' + det(ob5a);
} else if ( '5b' == x) {
return '<b>5x5 (row of zeros)</b><br>'
+ ob5b.join('<br>') + '<br>' + det(ob5b);
} else if ( '5c' == x) {
return '<b>5x5 (identical row)</b><br>'
+ ob5c.join('<br>') + '<br>' + det(ob5c);
}
}

<script type="text/javascript">
/* det()
Finds the determinant of a square matrix using determinant
expansion by minors (or "Laplacian expansion by minors,"
or sometimes "Laplacian expansion")

if A = | a1 a2 |
| b1 b2 |

detA = a1.b2 - a2.b1

if A = | a1 a2 a3 |
| b1 b2 b3 |
| c1 c2 c3 |

detA = a1(b2.c3 - b3.c2) - a2(b1.c3 - b3.c1) + a3(b1.c2 - b2.c1)
= a1.b2.c3 - a1.b3.c2 - a2.b1.c3 + a2.b3.c1
+ a3.b1.c2 - a3.b2.c1
etc.

Information derived from the Wolfram site:
http://mathworld.wolfram.com/Determinant.html
*/

// Doesn't check squareness or size
function det(a) {
var i = a[0].length;
if ( 2 == i ) { // det of 2x2
return +a[0][0]*a[1][1] - +a[0][1]*a[1][0];
} else {
var x=0;
var j=0;
do {
if ( 0 != +a[0][j] ) { // Speed opt - don't do if factor is 0
if (j%2) { // add even columns, subtract odd
x -= a[0][j] * det( minor(a, j) );
} else {
x += a[0][j] * det( minor(a, j) );
}
}
} while ( ++j < i )
return x;
}
}

// Returns the i-th minor of square matrix b
// remove top row, remove i-th element of remaining rows
// Doesn't check squareness or size
function minor(A, i){
var B = [];
var k, n, j=1; // Skip first row of A
do {
k=0; // A column
n=0; // B column
B[j-1] = []; // New row for B
do {
if ( k != i ) { // Skip i-th element
B[j-1][n++] = A[j][k];
}
} while ( undefined != A[j][++k] )
} while ( A[++j] )
return B;
}
</script>
 
T

Thomas 'PointedEars' Lahn

var a = [0, 1, 2, 3];
var b = a.slice(1);
alert(b); // 1,2,3
delete a[2];
alert([a, b].join("|")); // 0,1,,3|1,2,3

So:

function Matrix(A)
{
this.matrix = [0];

if (A)
{
for (var i = A.length; i--;)
{
var row = A;
this.matrix = [];
for (var j = row.length; j--;)
{
this.matrix[j] = row[j];
}
}
}
}

Matrix.prototype = {
toString: function matrix_toString(A)
{
if (!A)
{
A = this;
}

if ((A = A.matrix))
{
var as = [];

for (var i = 0, len = A.length; i < len; i++)
{
var row = A;
as = row.join(" ");
}
}

return as.join("\n");
},

minor: function matrix_minor(i, A)
{
if (!A)
{
A = this;
}

if ((A = A.matrix))
{
A = new Matrix(A);
A.matrix = A.matrix.slice(1);
for (var m, j = (m = A.matrix).length; j--;)
{
m[j].splice(i, 1);
}
}

return A;
}
};

var A = new Matrix([[0, 1, 2], [3, 4, 5], [6, 7, 8]]);
alert([A, A.minor(1)].join("\n___\n"));


PointedEars
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,768
Messages
2,569,575
Members
45,053
Latest member
billing-software

Latest Threads

Top