back to list

Regular temperament JS library

🔗Mike Battaglia <battaglia01@...>

12/27/2011 11:07:30 AM

A few months ago, I mentioned I was interested in writing a JavaScript
library to handle a lot of the aspects of regular temperament theory.
I now feel like I know enough of the math involved to actually start
doing that.

So now the question is: what branches of "pure" math should this
library cover so that I can implement regular temperament stuff as
instances of that? This is what seems to be necessary

1) Linear Algebra
a) Basic matrix algebra
b) Vectors
c) Pseudoinverse

2) Exterior Algebra
a) Exterior products
b) Interior products
c) Hodge star operator

What other specific features and subroutines should I have to handle the basics?

-Mike

🔗genewardsmith <genewardsmith@...>

12/27/2011 11:09:21 AM

--- In tuning@yahoogroups.com, Mike Battaglia <battaglia01@...> wrote:

> What other specific features and subroutines should I have to handle the basics?

Hermite normal form, saturation.

🔗Mike Battaglia <battaglia01@...>

12/27/2011 11:25:18 AM

On Tue, Dec 27, 2011 at 2:09 PM, genewardsmith
<genewardsmith@...> wrote:
>
> --- In tuning@yahoogroups.com, Mike Battaglia <battaglia01@...> wrote:
>
> > What other specific features and subroutines should I have to handle the basics?
>
> Hermite normal form, saturation.

Oh right, can't forget those.

With the addition of those two things, does that handle 100% of
everything on this page?

http://xenharmonic.wikispaces.com/Mathematical+Theory

In other words, can everything on these pages be constructed by making
use of those subroutines?

Also, how should I organize this? Should I put it on sourceforge?

-Mike

🔗gbreed@...

12/27/2011 12:00:00 PM

You don't need exterior algebra. You need to be able to solve a least squares problem but that needn't involve a pseudoinverse. You will need determinants to go beyond low rank special cases.
Hermite normal form is useful as Gene said.

Graham

------Original message------
From: Mike Battaglia <battaglia01@...>
To: <tuning@yahoogroups.com>
Date: Tuesday, December 27, 2011 2:07:30 PM GMT-0500
Subject: [tuning] Regular temperament JS library

A few months ago, I mentioned I was interested in writing a JavaScript
library to handle a lot of the aspects of regular temperament theory.
I now feel like I know enough of the math involved to actually start
doing that.

So now the question is: what branches of "pure" math should this
library cover so that I can implement regular temperament stuff as
instances of that? This is what seems to be necessary

1) Linear Algebra
a) Basic matrix algebra
b) Vectors
c) Pseudoinverse

2) Exterior Algebra
a) Exterior products
b) Interior products
c) Hodge star operator

What other specific features and subroutines should I have to handle the basics?

-Mike

------------------------------------

You can configure your subscription by sending an empty email to one
of these addresses (from the address at which you receive the list):
tuning-subscribe@yahoogroups.com - join the tuning group.
tuning-unsubscribe@yahoogroups.com - leave the group.
tuning-nomail@yahoogroups.com - turn off mail from the group.
tuning-digest@yahoogroups.com - set group to send daily digests.
tuning-normal@yahoogroups.com - set group to send individual emails.
tuning-help@yahoogroups.com - receive general help information.
Yahoo! Groups Links

🔗Carl Lumma <carl@...>

12/27/2011 12:20:56 PM

--- In tuning@yahoogroups.com, Mike Battaglia <battaglia01@...> wrote:

> Also, how should I organize this? Should I put it on sourceforge?

github > sourceforge -C.

🔗Mike Battaglia <battaglia01@...>

1/28/2012 11:31:02 PM

OK, coming back to this, there doesn't seem to be a "basic matrix
algebra" library for JS that has all the stuff I want. So a lot of my
time will be spent implementing algorithms, unfortunately.

I've thought about this a bit and it seems like the exterior algebra
stuff ought to be significantly easier to do. Is this correct? For
example, I have no idea how to compute the null space of a matrix just
yet, but if I use only monzos and vals, I can always do this:

1) take a set of vals
2) wedge them together and compute the multival and remove contorsion
3) get their dual exactly as Gene's defined it on the wiki
4) take interior products with the resulting multimonzo
5) transpose and put into Hermite normal form (how?) and transpose again

So the only thing I'd need to implement requiring any real work is
Hermite form, which seems like it'll have to be done no matter what I
do really. Now I have a set of monzos tempered out by those vals. I
can do the same thing in reverse to get the vals tempering out a set
of monzos. I'd have to remove contorsion throughout this process
though, but OK. If it weren't for the fact that all contorted versions
of the same temperament have the same multival, I could probably use
this to actually compute the null space of a matrix.

In contrast, this is how it seems it'll work out for the matrix-based approach
1) take a set of vals, concatenate them into a matrix
2) find the null space... how?
3) put this null space into a reduced form that somehow makes sense as
a set of column vectors representing monzos... how?
4) ok, now you're done

How do I do any of this? Do I need to program everything using
rational arithmetic? That might be a dealbreaker...

-Mike

🔗gbreed@...

1/29/2012 6:54:36 AM

I don't know why you say there isn't a suitable javascript library when I thought we found two. You can find answers to your questions in my Python code anyway

----------
Sent from my Nokia phone

------Original message------
From: Mike Battaglia <battaglia01@...>
To: <tuning@yahoogroups.com>
Date: Sunday, January 29, 2012 2:31:02 AM GMT-0500
Subject: [tuning] Re: Regular temperament JS library

OK, coming back to this, there doesn't seem to be a "basic matrix
algebra" library for JS that has all the stuff I want. So a lot of my
time will be spent implementing algorithms, unfortunately.

I've thought about this a bit and it seems like the exterior algebra
stuff ought to be significantly easier to do. Is this correct? For
example, I have no idea how to compute the null space of a matrix just
yet, but if I use only monzos and vals, I can always do this:

1) take a set of vals
2) wedge them together and compute the multival and remove contorsion
3) get their dual exactly as Gene's defined it on the wiki
4) take interior products with the resulting multimonzo
5) transpose and put into Hermite normal form (how?) and transpose again

So the only thing I'd need to implement requiring any real work is
Hermite form, which seems like it'll have to be done no matter what I
do really. Now I have a set of monzos tempered out by those vals. I
can do the same thing in reverse to get the vals tempering out a set
of monzos. I'd have to remove contorsion throughout this process
though, but OK. If it weren't for the fact that all contorted versions
of the same temperament have the same multival, I could probably use
this to actually compute the null space of a matrix.

In contrast, this is how it seems it'll work out for the matrix-based approach
1) take a set of vals, concatenate them into a matrix
2) find the null space... how?
3) put this null space into a reduced form that somehow makes sense as
a set of column vectors representing monzos... how?
4) ok, now you're done

How do I do any of this? Do I need to program everything using
rational arithmetic? That might be a dealbreaker...

-Mike

------------------------------------

You can configure your subscription by sending an empty email to one
of these addresses (from the address at which you receive the list):
tuning-subscribe@yahoogroups.com - join the tuning group.
tuning-unsubscribe@yahoogroups.com - leave the group.
tuning-nomail@yahoogroups.com - turn off mail from the group.
tuning-digest@yahoogroups.com - set group to send daily digests.
tuning-normal@yahoogroups.com - set group to send individual emails.
tuning-help@yahoogroups.com - receive general help information.
Yahoo! Groups Links

🔗Mike Battaglia <battaglia01@...>

1/30/2012 4:12:51 PM

On Sun, Jan 29, 2012 at 9:54 AM, gbreed@... <gbreed@...> wrote:
>
> I don't know why you say there isn't a suitable javascript library when I thought we found two. You can find answers to your questions in my Python code anyway

We found Sylvester and glMatrix. The latter limits itself to 3x3 and
4x4 matrices only, because it's deliberately designed to be really
fast for JS computer graphics applications, which tend to use those
matrices. There are a lot of similarly limited matrix JS libraries
I've found that only use matrices of a certain size, because there's
been a lot of focus in this area because of an emergent interest 3D
web programming. As far as I know, the only library out there which
can actually do basic matrix algebra on matrices of an arbitrary size
is Sylvester.

Sylvester has four classes: Matrix, Vector, Line, and Plane. The last
two only exist in three dimensions, and as such I don't really have
much general use for them, so I assume the first two classes will take
up the majority of my time. I was wrong about the Matrix class though,
I thought it was pretty weakly featured, but it does have some useful
stuff. There's just a lot of stuff it doesn't have, like an rref
function. It doesn't have adjoint either. It does have
toUpperTriangular though, which might be sort of helpful, maybe.

Anyway, so point is, Sylvester isn't fantastic, but it's not as dismal
as I thought. I'd like to start organizing and setting up some more
obvious matrix functions, like the two I mentioned, an isInteger
function, etc. All really simple stuff for now. There's a lot of
obvious and really simple functions I'd like to add to the matrix set
to extend Sylvester in addition to the more complicated nontrivial
stuff.

I also feel like in the process of working out regular temperament
stuff that there will be certain new abstractions which will make
things easier. At some point it'd be nice to have a sister class to
Vector called Covector, which does everything Vector does but stuffs
its results into a row matrix instead of a column matrix. Simple
things like that.

So I guess my question is, what's the best way to do this? Do I fork
it? Do I release this as a library for Sylvester? Do I just throw it
into the existing product? I don't know what the proper etiquette is
because I'm new to open source development.

-Mike

🔗Mike Battaglia <battaglia01@...>

1/30/2012 5:01:02 PM

Actually, there's a damn lot of stuff it doesn't have which I need. It
doesn't have pointwise multiplication, for one, nor pointwise
anything. I wish it did. I think I'm going to end up contributing more
code to this than it currently has. Also, this appears to be
abandoned, as development on this hasn't taken place since 2007. Also,
he doesn't have a github or repo of any kind to do anything.

Given that the entire blogosphere is abuzz with how much JavaScript
linear algebra sucks, I'm just going to scrap this whole thing and
start over, starting with Sylvester and building on that.

-Mike

On Mon, Jan 30, 2012 at 7:12 PM, Mike Battaglia <battaglia01@...> wrote:
> There's just a lot of stuff it doesn't have, like an rref
> function. It doesn't have adjoint either. It does have
> toUpperTriangular though, which might be sort of helpful, maybe.

🔗genewardsmith <genewardsmith@...>

1/30/2012 5:37:58 PM

--- In tuning@yahoogroups.com, Mike Battaglia <battaglia01@...> wrote:

> Given that the entire blogosphere is abuzz with how much JavaScript
> linear algebra sucks, I'm just going to scrap this whole thing and
> start over, starting with Sylvester and building on that.

My code for music stuff in Maple has a big library it can access, but I don't use it directly because I don't like the proliferation of data types and constructors. I suggest making everything a list, including lists of lists, makes life easier.

🔗Mike Battaglia <battaglia01@...>

1/30/2012 5:58:16 PM

On Mon, Jan 30, 2012 at 8:37 PM, genewardsmith
<genewardsmith@...> wrote:
>
> --- In tuning@yahoogroups.com, Mike Battaglia <battaglia01@...> wrote:
>
> > Given that the entire blogosphere is abuzz with how much JavaScript
> > linear algebra sucks, I'm just going to scrap this whole thing and
> > start over, starting with Sylvester and building on that.
>
> My code for music stuff in Maple has a big library it can access, but I don't use it directly because I don't like the proliferation of data types and constructors. I suggest making everything a list, including lists of lists, makes life easier.

Yes, I thought you'd like the way JavaScript handles that, actually.
In JavaScript, the "list" datatype is called an Array, and it looks
like this:

var A = [1, 2, 3, 4, 5, 6]

Note that there's no semicolon on the end as with C; you can put one
if you want but it's optional. Arrays can be multidimensional just by
putting them inside one another, as follows:

var A = [[1, 2, 3], [4, 5, 6]]

This is a 2x3 multidimensional array. By itself, though, an Array
isn't a matrix, it's just a primitive data type that holds stuff. You
don't even have to put numbers in it:

var A = [[1, "two", "shoe"], ["blah", "blah", 17]]

So it's rather flexible - and a bit too flexible, in fact. Also, it
doesn't come with any methods and it's a bit strange to override the
existing ones, as that might cause some problems integrating with
other JavaScript libraries. The best way to handle this is to come up
with a Matrix class which takes an multidimensional Array, or an Array
of Arrays, or alternately, a "list of lists" as input, which would
look something like this:

var A = Matrix([[1, 2, 3], [4, 5, 6])

And this is roughly the way Maple does it as well. The syntax won't
always sync up perfectly like that, but for the most part it'll be
very close. Thought you might like that.

The real question facing me now is rational vs floating point
arithmetic. I assume that as a mathematician you'll probably like the
former, but as an engineer the scope of this project will balloon so
ridiculously if I tackle that that I don't want to have to do it
unless I really have to. Thoughts?

-Mike

🔗Mike Battaglia <battaglia01@...>

1/30/2012 5:58:57 PM

On Mon, Jan 30, 2012 at 8:58 PM, Mike Battaglia <battaglia01@...> wrote:
>
> var A = Matrix([[1, 2, 3], [4, 5, 6])

Sorry, syntax error here - I left off a bracket at the end. Should be this:

var A = Matrix([[1, 2, 3], [4, 5, 6]])

-Mike

🔗genewardsmith <genewardsmith@...>

1/30/2012 8:40:59 PM

--- In tuning@yahoogroups.com, Mike Battaglia <battaglia01@...> wrote:

The best way to handle this is to come up
> with a Matrix class which takes an multidimensional Array, or an Array
> of Arrays, or alternately, a "list of lists" as input

Why is that the best way? Why not simply write functions such that if the list of lists is a matrix, does what you want it to do, and to hell with all the friggin data types?

> The real question facing me now is rational vs floating point
> arithmetic. I assume that as a mathematician you'll probably like the
> former, but as an engineer the scope of this project will balloon so
> ridiculously if I tackle that that I don't want to have to do it
> unless I really have to. Thoughts?

Rational arithmetic is very useful, but a lot can be done just with integer arithmetic. How hard would it be to implement rational arithmetic? Also, how well does JavaScript handle bignums?

🔗gbreed@...

1/31/2012 1:26:11 AM

Javascript uses 54 bit integers but some operations are limited to 32 bit. There are arbitrary precision libraries for encryption but I don't know them. Rational numbers may not be that difficult but they're unlikely to be worth any effort they require. You don't get operator overloading.
Oh, and arrays most certainly do have methods.

----------
Sent from my Nokia phone

------Original message------
From: genewardsmith <genewardsmith@sbcglobal.net>
To: <tuning@yahoogroups.com>
Date: Tuesday, January 31, 2012 4:40:59 AM GMT-0000
Subject: [tuning] Re: Regular temperament JS library

--- In tuning@yahoogroups.com, Mike Battaglia <battaglia01@...> wrote:

The best way to handle this is to come up
> with a Matrix class which takes an multidimensional Array, or an Array
> of Arrays, or alternately, a "list of lists" as input

Why is that the best way? Why not simply write functions such that if the list of lists is a matrix, does what you want it to do, and to hell with all the friggin data types?

> The real question facing me now is rational vs floating point
> arithmetic. I assume that as a mathematician you'll probably like the
> former, but as an engineer the scope of this project will balloon so
> ridiculously if I tackle that that I don't want to have to do it
> unless I really have to. Thoughts?

Rational arithmetic is very useful, but a lot can be done just with integer arithmetic. How hard would it be to implement rational arithmetic? Also, how well does JavaScript handle bignums?

------------------------------------

You can configure your subscription by sending an empty email to one
of these addresses (from the address at which you receive the list):
tuning-subscribe@yahoogroups.com - join the tuning group.
tuning-unsubscribe@yahoogroups.com - leave the group.
tuning-nomail@yahoogroups.com - turn off mail from the group.
tuning-digest@yahoogroups.com - set group to send daily digests.
tuning-normal@yahoogroups.com - set group to send individual emails.
tuning-help@yahoogroups.com - receive general help information.
Yahoo! Groups Links

🔗Mike Battaglia <battaglia01@...>

1/31/2012 1:48:23 AM

On Mon, Jan 30, 2012 at 11:40 PM, genewardsmith
<genewardsmith@...> wrote:
>
> --- In tuning@yahoogroups.com, Mike Battaglia <battaglia01@...> wrote:
>
> The best way to handle this is to come up
> > with a Matrix class which takes an multidimensional Array, or an Array
> > of Arrays, or alternately, a "list of lists" as input
>
> Why is that the best way? Why not simply write functions such that if the list of lists is a matrix, does what you want it to do, and to hell with all the friggin data types?

JavaScript is loosely typed, so there's no strict data types in the
same sense that there is in C. The difference in your end user
experience is mainly one of syntactic sugar. For example, here's the
way you suggest:

var meantone = [[1, 1, 0], [0, 1, 4]];
var syntonic = nullspace(meantone);

Here's the object-based way:

var meantone = [[1, 1, 0], [0, 1, 4]];
var syntonic = meantone.nullspace();

The difference has been entirely reduced to the syntax involved. The
reason I'd like to do it the second way is that I find it easier to
code, and I think it'll make it easier to integrate with other web
technologies. For example, let's say I have a function called
"diagonal" which returns the diagonal of a matrix, and I call it by
saying

var contortedJI = [[1,0,0],[0,2,0],[0,0,1]];
var d = diagonal(contortedJI);

Now let's say someone wants to use my library, but they have a
function called diagonal which draws a diagonal line. Which diagonal
is called? Now you have a naming conflict, which is bad. If you want
to keep things entirely procedural and avoid OOP, the solution is to
do this:

var d = Matrix.diagonal(contortedJI)

But is there really any difference between that and this?

var d = contortedJI.diagonal()

You tell me.

> > The real question facing me now is rational vs floating point
> > arithmetic. I assume that as a mathematician you'll probably like the
> > former, but as an engineer the scope of this project will balloon so
> > ridiculously if I tackle that that I don't want to have to do it
> > unless I really have to. Thoughts?
>
> Rational arithmetic is very useful, but a lot can be done just with integer arithmetic. How hard would it be to implement rational arithmetic? Also, how well does JavaScript handle bignums?

Integer arithmetic is much easier. It's easy for me to program a bunch
of functions which assume the matrix is an integer matrix. If the user
tries to do something stupid like pass a floating point matrix into an
integer routine, like calling HermiteForm on a floating point matrix,
there's plenty of ways to handle that - I could provide functions like
isIntegerMatrix() so the user can check before doing anything stupid,
or I could baby the user and return an error, etc. That part's easy.

Rational stuff is not. The problem is that there's no primitive
Rational datatype. So I'd either have to make or find one, which is
partly why rational arithmetic is more difficult to implement. It's
not the end of the world, but I want to avoid it if possible, because
it complicates the hell out of everything. Worst of all, it makes the
syntax ugly as hell, because JS has no operator overloading, so you'd
have to do stuff like

var fifth = Rational("3/2")
var fourth = Rational("4/3")

Then to multiply things, you'd have to do something like

var result = multiply(fifth,fourth)

or

var result = fifth.times(fourth)

the best I can do is

var result = fifth.x(fourth)

It just sucks.

Bignums are pretty good in JavaScript; it can get integers up to +/-
2^53 without a problem. Floating points let you go much larger, but
then you lose precision in the least significant digits. I know of at
least one BigDecimal library out there, but even that still sucks,
because it's still prone to the same operator issues. I really,
really, really want to avoid this unless I absolutely have to.

I'm asking because Keenan proposed that linear algebra is
significantly more sensitive to rounding error than the other usual
engineering disciplines that I'm familiar with, and linked me to some
papers on numerical stability, so now I'm not sure how to proceed. I
want to make sure I build this right from the ground up before I go
program rref and pseudoinverse and so on functions and find out that
they don't work. So if it's really necessary to build it in, I'll do
it, but I won't like it.

-Mike

🔗Mike Battaglia <battaglia01@...>

1/31/2012 1:54:43 AM

On Tue, Jan 31, 2012 at 4:26 AM, gbreed@... <gbreed@...> wrote:
>
> Javascript uses 54 bit integers but some operations are limited to 32 bit.

What operations are limited to 32 bit?

> There are arbitrary precision libraries for encryption but I don't know them. Rational numbers may not be that difficult but they're unlikely to be worth any effort they require. You don't get operator overloading.

One thing I was thinking about doing was sneaking the BigDecimal class
in there under the hood just for operations that require extra
precision. For example, I hear rref is prone to roundoff error
problems, except linear algebra people like to call those "numerical
stability" problems. So what I could do is just, in my rref routine,
convert all of the entries in the matrix to BigDecimal entries, get
the exact rref value beyond whatever JS's floating point resolution
is, round it off under the hood, and convert back to a Number at the
end without the user ever knowing what's happened.

Stuff using BigDecimal stuff would still be slow and hence suck
tremendously for any of the cooler applications of an actual linear
algebra library in JavaScript, but it'd get the job done, hide all of
the messy syntactic stuff from the user, and avoid stability problems.
I'd probably still want to make a fast_rref() function though.

> Oh, and arrays most certainly do have methods.

["typo", "a", "was", "it"].reverse()

-Mike

🔗Mike Battaglia <battaglia01@...>

1/31/2012 2:03:52 AM

On Tue, Jan 31, 2012 at 4:48 AM, Mike Battaglia <battaglia01@...> wrote:
>
> Here's the object-based way:
>
> var meantone = [[1, 1, 0], [0, 1, 4]];
> var syntonic = meantone.nullspace();

Sorry, I made a typo here. These are your three options:

==PROCEDURAL WAY THAT IS UNWISE FOR ME TO DO==
var meantone = [[1, 1, 0], [0, 1, 4]];
var syntonic = nullspace(meantone);

==PROCEDURAL WAY THAT I ACTUALLY CAN DO==
var meantone = [[1, 1, 0], [0, 1, 4]];
var syntonic = Matrix.nullspace(meantone);

==OOP WAY THAT I WANT TO DO IT==
var meantone = Matrix([[1, 1, 0], [0, 1, 4]]);
var syntonic = meantone.nullspace();

Those are the three options. At the end of it, syntonic will be set to
the list corresponding to the nullspace, which will be reducible to
[[-4], [4], [-1]], which is a column vector. If I do it the third way,
syntonic will be set to the same thing, wrapped in a Matrix object.

I don't really think there's too much difference between any of these,
so it might be bikeshedding. If you have any serious objections
though, now's the time. The options are #2 and #3 though, and not #1,
because I'm not going to flood the global namespace with names like
"diag" and "det" and "nullspace," as that's a bad idea. (You can
always use with(Matrix) { ... } anyway though, same as with Maple.)

And it might just boil down to that #3 will be easiest to code anyway,
which is what I suspect :)

-Mike

🔗Keenan Pepper <keenanpepper@...>

1/31/2012 11:55:59 AM

--- In tuning@yahoogroups.com, Mike Battaglia <battaglia01@...> wrote:
> One thing I was thinking about doing was sneaking the BigDecimal class
> in there under the hood just for operations that require extra
> precision. For example, I hear rref is prone to roundoff error
> problems, except linear algebra people like to call those "numerical
> stability" problems. So what I could do is just, in my rref routine,
> convert all of the entries in the matrix to BigDecimal entries, get
> the exact rref value beyond whatever JS's floating point resolution
> is, round it off under the hood, and convert back to a Number at the
> end without the user ever knowing what's happened.

This seems like the worst of both worlds to me. Why not simply use numerically stable algorithms with floating point?

Keenan

🔗gbreed@...

1/31/2012 12:13:14 PM

Bitwise operations work on 32 bit integers. Array indices are 32 bit integers. It looks like any function that requires an integer casts it to 32 bits.
The floating point model should be good enough for tuning theory. Some least squares calculations can underflow so be careful there.
A lot of the work can be done with integers. Vals and monzos shouldn't overflow. Hermite reduction generally makes the numbers smaller. You might want big integers for ratios.

----------
Sent from my Nokia phone

------Original message------
From: Mike Battaglia <battaglia01@...>
To: <tuning@yahoogroups.com>
Date: Tuesday, January 31, 2012 4:54:43 AM GMT-0500
Subject: Re: [tuning] Re: Regular temperament JS library

On Tue, Jan 31, 2012 at 4:26 AM, gbreed@... <gbreed@...> wrote:
>
> Javascript uses 54 bit integers but some operations are limited to 32 bit.

What operations are limited to 32 bit?

> There are arbitrary precision libraries for encryption but I don't know them. Rational numbers may not be that difficult but they're unlikely to be worth any effort they require. You don't get operator overloading.

One thing I was thinking about doing was sneaking the BigDecimal class
in there under the hood just for operations that require extra
precision. For example, I hear rref is prone to roundoff error
problems, except linear algebra people like to call those "numerical
stability" problems. So what I could do is just, in my rref routine,
convert all of the entries in the matrix to BigDecimal entries, get
the exact rref value beyond whatever JS's floating point resolution
is, round it off under the hood, and convert back to a Number at the
end without the user ever knowing what's happened.

Stuff using BigDecimal stuff would still be slow and hence suck
tremendously for any of the cooler applications of an actual linear
algebra library in JavaScript, but it'd get the job done, hide all of
the messy syntactic stuff from the user, and avoid stability problems.
I'd probably still want to make a fast_rref() function though.

> Oh, and arrays most certainly do have methods.

["typo", "a", "was", "it"].reverse()

-Mike

------------------------------------

You can configure your subscription by sending an empty email to one
of these addresses (from the address at which you receive the list):
tuning-subscribe@yahoogroups.com - join the tuning group.
tuning-unsubscribe@yahoogroups.com - leave the group.
tuning-nomail@yahoogroups.com - turn off mail from the group.
tuning-digest@yahoogroups.com - set group to send daily digests.
tuning-normal@yahoogroups.com - set group to send individual emails.
tuning-help@yahoogroups.com - receive general help information.
Yahoo! Groups Links