Show HN: Advanced Mathematics Library for Node.js and JavaScript
github.com
github.com
A couple of observations:
1. You should probably go ahead and implement at least LU decomposition, QR factorization, and maybe some eigenvalue/eigenvector stuff if you want to claim "advanced".
2. You should use the recursive definition of the determinant in the >3x3 matrix case.
3. You should consider adding some vector methods of the form: ax+by (for scalar a & b, and vector x & y). This can be useful for doing linear interpolation and whatnot.
4. You should add cross products/outer products for vectors.
5. You should have a mechanism for generating a Gaussian or normal distribution, or at least supply some standard mappings from your (presumably uniform) random function to something more useful (Gaussian, Possoin, Weibull, whatever).
6. An FFT would be nice. :)
7. Quaternions would also be handy for graphics folks, or motion folks.
8. Complex number support would be cool.
9. Support for optimization, like integer programming, linear programming, or even least-squares or whatever would be nice.
~
Again, great work--I look forward to seeing how this project evolves!
Although, could someone clarify for me the floating point issues mentioned by Steve? I wasn't aware there were issues...
In your browser console, run: 0.3 + 0.544 You'll get back 0.8440000000000001
In practice (especially if in the browser), the difference is either irrelevant (in CSS 1px == 1.1px) or not significant. But in accumulation, it could be problematic.
$ erl
1> 0.2 + 0.1.
0.30000000000000004
2> 0.94 - 0.01.
0.9299999999999999
3> 0.3 + 0.544.
0.8440000000000001
$ irb
1.9.2-p290 :001 > 0.2 + 0.1
=> 0.30000000000000004
1.9.2-p290 :002 > 0.94 - 0.01
=> 0.9299999999999999
1.9.2-p290 :003 > 0.3 + 0.544
=> 0.8440000000000001
1.9.2-p290 :004 >You use something like:
fabs( a-b ) < epsilon
where epsilon is usually defined by the language as a very small quantity (example values in C are 1E-8 for a float, 1E-15 for double), or you can just use a hard coded value appropriate to the values you are comparing.x == y
and
|x - y| < epsilon
As I said, things get worse if your comparison is between larger numbers. For example, the smallest double larger than 1024 is 1024+1024 epsilon (IIRC; I am too lazy to double-check that now)
The epsilon used in numerical algorithms is an entirely different beast than the machine epsilon.
That epsilon you should pick as follows: make a numerical analysis of your problem, choose a good algorithm, and determine the desired accuracy of your answer. From those, derive a (relative, absolute, whatever) error you can live with.
Alternatively, pick a reasonable value from thin air and hope for the best/test your code to get confidence that it will return good values (do not do this when programming flight control software, pacemakers, etc). Oftentimes, it is not really hard to produce a reasonable value. For example, an iterative procedure that produces pixel coordinate likely can stop once the absolute error is less than .01 pixel, and possibly a lot earlier.
Finally, in the ideal world, you will use a good way to test for your accuracy, for example one from boost test: http://www.boost.org/doc/libs/1_52_0/libs/test/doc/html/utf/... (contains useful links to more in-depth discussions)
And, by the way, 1E-8 is lower than the machine epsilon for floats, and 1E-15 larger than that for doubles. http://en.wikipedia.org/wiki/Machine_epsilon gives them as 1.2E-7, respectively 2.2E-16.
It is the same as trying to store 1/3 = 0.333... as a finite decimal. Basically, a floating point number only has a finite space to put the component after the decimal point, so it gets truncated and made inaccurate, just like truncating 1/3 to 0.3333 will mean that calculations become wrong: 3*0.3333 = 0.9999 ≠ 1.
By the by, for typical MD processing, as long as you're using sensible units you shouldn't need to worry about floating point precision. Just don't use SI units, because then you might end up with some very very small numbers and that's when it'll start to bite you!
This is how easy that is:
(Note: it appears the horizontal scroll bar for this code is hidden by default for OS X browsers.)
eigenvalues = require 'eigenvalues.js'
regressCoordinatesToNormal = (coords) ->
min = (array) ->
array.reduce ((x, y, i) -> if x.val < y then x else {index: i, val: y}), {index: null, val: Infinity}
centerOfMass = (coords) ->
coords.reduce ((x, y) -> (x[i] + (y[i] / coords.length) for v, i in y)), [0, 0, 0]
normalUnitVector = (coords) ->
c = centerOfMass coords
matrix = for row in [0..2]
for col in [0..2]
((coord[row] - c[row]) * (coord[col] - c[col]) for coord in coords).reduce (x, y) -> x + y
results = eigenvalues.calculateEigenvalues matrix
results.eigenvectors[min(results.real).index]
normalUnitVector coords
This code just takes in a list of coordinates and performs a linear plane regression on them to return the normal vector of the plane. Then if I want the vertical distance between two planes of atoms (these are circular planes that kind of wobble around), then it's just: normals = (regressCoordinatesToNormal coords for coords in planes)
planeToPlaneVector = distanceVector planeCenterOfMass[0], planeCenterOfMass[1]
projectionDistance = dotProduct planeToPlaneVector, normals[0]
I left out some details, but you can get the gist of it.Seems to work for me, but I haven't had it reviewed by a real mathematician yet.
I speak for myself when I say a lot of us aren't that good at math.
I intend to contribute what I can in those areas.
Can you give an overview of how your library is different? Is it just a different set of math tools or is the architecture somehow different? Thanks!
When you drag and drop the shapes, the drawing changes in non-trivial ways. For example, try dragging a shape deep down in the recursion hierarchy.
In a normal drag-and-drop application, it's fairly easy to compute how to, say, adjust the left/top of a div in response to the mouse movement events. However, with Recursive Drawing, I knew that there were certain properties I'd have to adjust during a drag operation, but because of all the nested transformations, it was tricky to figure out the math of how exactly to adjust them.
So instead, I set up a constraint problem. I know that the exact spot I've mousedown'ed on needs to stay under my mouse no matter what. That's the fundamental constraint of the drag-and-drop gesture. Then I set the properties that I knew I could change (e.g. positions or scaling/rotation of a specific shape) and set them as free variables in an energy minimization function. I solved the problem numerically using numeric.js's uncmin (unconstrained minimization, an algorithm originally written in FORTRAN, I believe).
I probably could have figured out how to do this without numerical methods, but this approach was a god-send when rapid prototyping the interactions.
Another good use of constraint systems for UIs is Ivan Sutherland's Sketchpad. His paper on it is long but really worth at least skimming through if you're interested in developing next-generation UIs! http://www.cl.cam.ac.uk/techreports/UCAM-CL-TR-574.pdf
I also really like Rebecca Fiebrink's Wekinator, which is a framework for making musical instruments from arbitrary inputs. The approach is similar in that she uses numerical methods to solve for the constraints (the training data). http://wekinator.cs.princeton.edu/
I think there's a lot of potential in constraint-based UIs and for me it's the most compelling reason to have good numerical libraries in javascript.
-should support FFT/convolution
-could tie into http://sylvester.jcoglan.com/ for
vector/matrix stuff (excellent library!)
-I emailed jcoglan about the possibility of adding
complex number support to Sylvester, he encouraged me
to try but thought it might introduce too much function
call overhead (caching function results might help a
bit?)
-I didn't get to look at it too closely, but
https://github.com/jtobey/javascript-bignum looks
interesting, as does https://github.com/pr1001/MathPlus
-polynomial fit (least squares regression) and
interpolation stuff is in high demand
-it should be super easy to integrate output with d3.js
(like the equivalent of MATLAB plot function)
Honestly, I doubt I would have been able to pull it off, but I intend to contribute to this project as much as I can.EDIT: Formatting
Is there interest in some more advanced matrix algebra functions - specifically Gaussian reduction, simplex, sensitivity analysis, and maybe some transport/network problems and integer programming?
I present to you "Clique: A Javascript Linear Algebra Library with Applications to Spectral Analysis"
2. Canvas and WebGL pave the way for lots of cool graphical JS applications. Linear algebra and calculus are particularly useful for graphics.