// // Math.seedrandom('yipee'); Sets Math.random to a function that is // initialized using the given explicit seed. // // Math.seedrandom(); Sets Math.random to a function that is // seeded using the current time, dom state, // and other accumulated local entropy. // The generated seed string is returned. // // Math.seedrandom('yowza', true); // Seeds using the given explicit seed mixed // together with accumulated entropy. // // // Seeds using physical random bits downloaded // from random.org. // // Seeds using urandom bits from call.jsonlib.com, // which is faster than random.org. // // Examples: // // Math.seedrandom("hello"); // Use "hello" as the seed. // document.write(Math.random()); // Always 0.5463663768140734 // document.write(Math.random()); // Always 0.43973793770592234 // var rng1 = Math.random; // Remember the current prng. // // var autoseed = Math.seedrandom(); // New prng with an automatic seed. // document.write(Math.random()); // Pretty much unpredictable. // // Math.random = rng1; // Continue "hello" prng sequence. // document.write(Math.random()); // Always 0.554769432473455 // // Math.seedrandom(autoseed); // Restart at the previous seed. // document.write(Math.random()); // Repeat the 'unpredictable' value. // // Notes: // // Each time seedrandom('arg') is called, entropy from the passed seed // is accumulated in a pool to help generate future seeds for the // zero-argument form of Math.seedrandom, so entropy can be injected over // time by calling seedrandom with explicit data repeatedly. // // On speed - This javascript implementation of Math.random() is about // 3-10x slower than the built-in Math.random() because it is not native // code, but this is typically fast enough anyway. Seeding is more expensive, // especially if you use auto-seeding. Some details (timings on Chrome 4): // // Our Math.random() - avg less than 0.002 milliseconds per call // seedrandom('explicit') - avg less than 0.5 milliseconds per call // seedrandom('explicit', true) - avg less than 2 milliseconds per call // seedrandom() - avg about 38 milliseconds per call // // LICENSE (BSD): // // Copyright 2010 David Bau, all rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // 1. Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // // 2. Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // // 3. Neither the name of this module nor the names of its contributors may // be used to endorse or promote products derived from this software // without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // /** * All code is in an anonymous closure to keep the global namespace clean. * * @param {number=} overflow * @param {number=} startdenom */ // Patched by Seb so that seedrandom.js does not pollute the Math object. // My tests suggest that doing Math.trouble = 1 makes Math lookups about 5% // slower. numeric.seedrandom = { pow:Math.pow, random:Math.random }; (function (pool, math, width, chunks, significance, overflow, startdenom) { // // seedrandom() // This is the seedrandom function described above. // math['seedrandom'] = function seedrandom(seed, use_entropy) { var key = []; var arc4; // Flatten the seed string or build one from local entropy if needed. seed = mixkey(flatten( use_entropy ? [seed, pool] : arguments.length ? seed : [new Date().getTime(), pool, window], 3), key); // Use the seed to initialize an ARC4 generator. arc4 = new ARC4(key); // Mix the randomness into accumulated entropy. mixkey(arc4.S, pool); // Override Math.random // This function returns a random double in [0, 1) that contains // randomness in every bit of the mantissa of the IEEE 754 value. math['random'] = function random() { // Closure to return a random double: var n = arc4.g(chunks); // Start with a numerator n < 2 ^ 48 var d = startdenom; // and denominator d = 2 ^ 48. var x = 0; // and no 'extra last byte'. while (n < significance) { // Fill up all significant digits by n = (n + x) * width; // shifting numerator and d *= width; // denominator and generating a x = arc4.g(1); // new least-significant-byte. } while (n >= overflow) { // To avoid rounding up, before adding n /= 2; // last byte, shift everything d /= 2; // right using integer math until x >>>= 1; // we have exactly the desired bits. } return (n + x) / d; // Form the number within [0, 1). }; // Return the seed that was used return seed; }; // // ARC4 // // An ARC4 implementation. The constructor takes a key in the form of // an array of at most (width) integers that should be 0 <= x < (width). // // The g(count) method returns a pseudorandom integer that concatenates // the next (count) outputs from ARC4. Its return value is a number x // that is in the range 0 <= x < (width ^ count). // /** @constructor */ function ARC4(key) { var t, u, me = this, keylen = key.length; var i = 0, j = me.i = me.j = me.m = 0; me.S = []; me.c = []; // The empty key [] is treated as [0]. if (!keylen) { key = [keylen++]; } // Set up S using the standard key scheduling algorithm. while (i < width) { me.S[i] = i++; } for (i = 0; i < width; i++) { t = me.S[i]; j = lowbits(j + t + key[i % keylen]); u = me.S[j]; me.S[i] = u; me.S[j] = t; } // The "g" method returns the next (count) outputs as one number. me.g = function getnext(count) { var s = me.S; var i = lowbits(me.i + 1); var t = s[i]; var j = lowbits(me.j + t); var u = s[j]; s[i] = u; s[j] = t; var r = s[lowbits(t + u)]; while (--count) { i = lowbits(i + 1); t = s[i]; j = lowbits(j + t); u = s[j]; s[i] = u; s[j] = t; r = r * width + s[lowbits(t + u)]; } me.i = i; me.j = j; return r; }; // For robust unpredictability discard an initial batch of values. // See http://www.rsa.com/rsalabs/node.asp?id=2009 me.g(width); } // // flatten() // Converts an object tree to nested arrays of strings. // /** @param {Object=} result * @param {string=} prop * @param {string=} typ */ function flatten(obj, depth, result, prop, typ) { result = []; typ = typeof(obj); if (depth && typ == 'object') { for (prop in obj) { if (prop.indexOf('S') < 5) { // Avoid FF3 bug (local/sessionStorage) try { result.push(flatten(obj[prop], depth - 1)); } catch (e) {} } } } return (result.length ? result : obj + (typ != 'string' ? '\0' : '')); } // // mixkey() // Mixes a string seed into a key that is an array of integers, and // returns a shortened string seed that is equivalent to the result key. // /** @param {number=} smear * @param {number=} j */ function mixkey(seed, key, smear, j) { seed += ''; // Ensure the seed is a string smear = 0; for (j = 0; j < seed.length; j++) { key[lowbits(j)] = lowbits((smear ^= key[lowbits(j)] * 19) + seed.charCodeAt(j)); } seed = ''; for (j in key) { seed += String.fromCharCode(key[j]); } return seed; } // // lowbits() // A quick "n mod width" for width a power of 2. // function lowbits(n) { return n & (width - 1); } // // The following constants are related to IEEE 754 limits. // startdenom = math.pow(width, chunks); significance = math.pow(2, significance); overflow = significance * 2; // // When seedrandom.js is loaded, we immediately mix a few bits // from the built-in RNG into the entropy pool. Because we do // not want to intefere with determinstic PRNG state later, // seedrandom will not call math.random on its own again after // initialization. // mixkey(math.random(), pool); // End anonymous scope, and pass initial values. }( [], // pool: entropy pool starts empty numeric.seedrandom, // math: package containing random, pow, and seedrandom 256, // width: each RC4 output is 0 <= x < 256 6, // chunks: at least six RC4 outputs for each double 52 // significance: there are 52 significant digits in a double )); /* This file is a slightly modified version of quadprog.js from Alberto Santini. * It has been slightly modified by Sébastien Loisel to make sure that it handles * 0-based Arrays instead of 1-based Arrays. * License is in resources/LICENSE.quadprog */ (function(exports) { function base0to1(A) { if(typeof A !== "object") { return A; } var ret = [], i,n=A.length; for(i=0;i meq) { work[l] = sum; } else { work[l] = -Math.abs(sum); if (sum > 0) { for (j = 1; j <= n; j = j + 1) { amat[j][i] = -amat[j][i]; } bvec[i] = -bvec[i]; } } } for (i = 1; i <= nact; i = i + 1) { work[iwsv + iact[i]] = 0; } nvl = 0; temp = 0; for (i = 1; i <= q; i = i + 1) { if (work[iwsv + i] < temp * work[iwnbv + i]) { nvl = i; temp = work[iwsv + i] / work[iwnbv + i]; } } if (nvl === 0) { return 999; } return 0; } function fn_goto_55() { for (i = 1; i <= n; i = i + 1) { sum = 0; for (j = 1; j <= n; j = j + 1) { sum = sum + dmat[j][i] * amat[j][nvl]; } work[i] = sum; } l1 = iwzv; for (i = 1; i <= n; i = i + 1) { work[l1 + i] = 0; } for (j = nact + 1; j <= n; j = j + 1) { for (i = 1; i <= n; i = i + 1) { work[l1 + i] = work[l1 + i] + dmat[i][j] * work[j]; } } t1inf = true; for (i = nact; i >= 1; i = i - 1) { sum = work[i]; l = iwrm + (i * (i + 3)) / 2; l1 = l - i; for (j = i + 1; j <= nact; j = j + 1) { sum = sum - work[l] * work[iwrv + j]; l = l + j; } sum = sum / work[l1]; work[iwrv + i] = sum; if (iact[i] < meq) { // continue; break; } if (sum < 0) { // continue; break; } t1inf = false; it1 = i; } if (!t1inf) { t1 = work[iwuv + it1] / work[iwrv + it1]; for (i = 1; i <= nact; i = i + 1) { if (iact[i] < meq) { // continue; break; } if (work[iwrv + i] < 0) { // continue; break; } temp = work[iwuv + i] / work[iwrv + i]; if (temp < t1) { t1 = temp; it1 = i; } } } sum = 0; for (i = iwzv + 1; i <= iwzv + n; i = i + 1) { sum = sum + work[i] * work[i]; } if (Math.abs(sum) <= vsmall) { if (t1inf) { ierr[1] = 1; // GOTO 999 return 999; } else { for (i = 1; i <= nact; i = i + 1) { work[iwuv + i] = work[iwuv + i] - t1 * work[iwrv + i]; } work[iwuv + nact + 1] = work[iwuv + nact + 1] + t1; // GOTO 700 return 700; } } else { sum = 0; for (i = 1; i <= n; i = i + 1) { sum = sum + work[iwzv + i] * amat[i][nvl]; } tt = -work[iwsv + nvl] / sum; t2min = true; if (!t1inf) { if (t1 < tt) { tt = t1; t2min = false; } } for (i = 1; i <= n; i = i + 1) { sol[i] = sol[i] + tt * work[iwzv + i]; if (Math.abs(sol[i]) < vsmall) { sol[i] = 0; } } crval[1] = crval[1] + tt * sum * (tt / 2 + work[iwuv + nact + 1]); for (i = 1; i <= nact; i = i + 1) { work[iwuv + i] = work[iwuv + i] - tt * work[iwrv + i]; } work[iwuv + nact + 1] = work[iwuv + nact + 1] + tt; if (t2min) { nact = nact + 1; iact[nact] = nvl; l = iwrm + ((nact - 1) * nact) / 2 + 1; for (i = 1; i <= nact - 1; i = i + 1) { work[l] = work[i]; l = l + 1; } if (nact === n) { work[l] = work[n]; } else { for (i = n; i >= nact + 1; i = i - 1) { if (work[i] === 0) { // continue; break; } gc = Math.max(Math.abs(work[i - 1]), Math.abs(work[i])); gs = Math.min(Math.abs(work[i - 1]), Math.abs(work[i])); if (work[i - 1] >= 0) { temp = Math.abs(gc * Math.sqrt(1 + gs * gs / (gc * gc))); } else { temp = -Math.abs(gc * Math.sqrt(1 + gs * gs / (gc * gc))); } gc = work[i - 1] / temp; gs = work[i] / temp; if (gc === 1) { // continue; break; } if (gc === 0) { work[i - 1] = gs * temp; for (j = 1; j <= n; j = j + 1) { temp = dmat[j][i - 1]; dmat[j][i - 1] = dmat[j][i]; dmat[j][i] = temp; } } else { work[i - 1] = temp; nu = gs / (1 + gc); for (j = 1; j <= n; j = j + 1) { temp = gc * dmat[j][i - 1] + gs * dmat[j][i]; dmat[j][i] = nu * (dmat[j][i - 1] + temp) - dmat[j][i]; dmat[j][i - 1] = temp; } } } work[l] = work[nact]; } } else { sum = -bvec[nvl]; for (j = 1; j <= n; j = j + 1) { sum = sum + sol[j] * amat[j][nvl]; } if (nvl > meq) { work[iwsv + nvl] = sum; } else { work[iwsv + nvl] = -Math.abs(sum); if (sum > 0) { for (j = 1; j <= n; j = j + 1) { amat[j][nvl] = -amat[j][nvl]; } bvec[nvl] = -bvec[nvl]; } } // GOTO 700 return 700; } } return 0; } function fn_goto_797() { l = iwrm + (it1 * (it1 + 1)) / 2 + 1; l1 = l + it1; if (work[l1] === 0) { // GOTO 798 return 798; } gc = Math.max(Math.abs(work[l1 - 1]), Math.abs(work[l1])); gs = Math.min(Math.abs(work[l1 - 1]), Math.abs(work[l1])); if (work[l1 - 1] >= 0) { temp = Math.abs(gc * Math.sqrt(1 + gs * gs / (gc * gc))); } else { temp = -Math.abs(gc * Math.sqrt(1 + gs * gs / (gc * gc))); } gc = work[l1 - 1] / temp; gs = work[l1] / temp; if (gc === 1) { // GOTO 798 return 798; } if (gc === 0) { for (i = it1 + 1; i <= nact; i = i + 1) { temp = work[l1 - 1]; work[l1 - 1] = work[l1]; work[l1] = temp; l1 = l1 + i; } for (i = 1; i <= n; i = i + 1) { temp = dmat[i][it1]; dmat[i][it1] = dmat[i][it1 + 1]; dmat[i][it1 + 1] = temp; } } else { nu = gs / (1 + gc); for (i = it1 + 1; i <= nact; i = i + 1) { temp = gc * work[l1 - 1] + gs * work[l1]; work[l1] = nu * (work[l1 - 1] + temp) - work[l1]; work[l1 - 1] = temp; l1 = l1 + i; } for (i = 1; i <= n; i = i + 1) { temp = gc * dmat[i][it1] + gs * dmat[i][it1 + 1]; dmat[i][it1 + 1] = nu * (dmat[i][it1] + temp) - dmat[i][it1 + 1]; dmat[i][it1] = temp; } } return 0; } function fn_goto_798() { l1 = l - it1; for (i = 1; i <= it1; i = i + 1) { work[l1] = work[l]; l = l + 1; l1 = l1 + 1; } work[iwuv + it1] = work[iwuv + it1 + 1]; iact[it1] = iact[it1 + 1]; it1 = it1 + 1; if (it1 < nact) { // GOTO 797 return 797; } return 0; } function fn_goto_799() { work[iwuv + nact] = work[iwuv + nact + 1]; work[iwuv + nact + 1] = 0; iact[nact] = 0; nact = nact - 1; iter[2] = iter[2] + 1; return 0; } go = 0; while (true) { go = fn_goto_50(); if (go === 999) { return; } while (true) { go = fn_goto_55(); if (go === 0) { break; } if (go === 999) { return; } if (go === 700) { if (it1 === nact) { fn_goto_799(); } else { while (true) { fn_goto_797(); go = fn_goto_798(); if (go !== 797) { break; } } fn_goto_799(); } } } } } function solveQP(Dmat, dvec, Amat, bvec, meq, factorized) { Dmat = base0to1(Dmat); dvec = base0to1(dvec); Amat = base0to1(Amat); var i, n, q, nact, r, crval = [], iact = [], sol = [], work = [], iter = [], message; meq = meq || 0; factorized = factorized ? base0to1(factorized) : [undefined, 0]; bvec = bvec ? base0to1(bvec) : []; // In Fortran the array index starts from 1 n = Dmat.length - 1; q = Amat[1].length - 1; if (!bvec) { for (i = 1; i <= q; i = i + 1) { bvec[i] = 0; } } for (i = 1; i <= q; i = i + 1) { iact[i] = 0; } nact = 0; r = Math.min(n, q); for (i = 1; i <= n; i = i + 1) { sol[i] = 0; } crval[1] = 0; for (i = 1; i <= (2 * n + (r * (r + 5)) / 2 + 2 * q + 1); i = i + 1) { work[i] = 0; } for (i = 1; i <= 2; i = i + 1) { iter[i] = 0; } qpgen2(Dmat, dvec, n, n, sol, crval, Amat, bvec, n, q, meq, iact, nact, iter, work, factorized); message = ""; if (factorized[1] === 1) { message = "constraints are inconsistent, no solution!"; } if (factorized[1] === 2) { message = "matrix D in quadratic function is not positive definite!"; } return { solution: base1to0(sol), value: base1to0(crval), unconstrained_solution: base1to0(dvec), iterations: base1to0(iter), iact: base1to0(iact), message: message }; } exports.solveQP = solveQP; }(numeric)); /* Shanti Rao sent me this routine by private email. I had to modify it slightly to work on Arrays instead of using a Matrix object. It is apparently translated from http://stitchpanorama.sourceforge.net/Python/svd.py */ numeric.svd= function svd(A) { var temp; //Compute the thin SVD from G. H. Golub and C. Reinsch, Numer. Math. 14, 403-420 (1970) var prec= numeric.epsilon; //Math.pow(2,-52) // assumes double prec var tolerance= 1.e-64/prec; var itmax= 50; var c=0; var i=0; var j=0; var k=0; var l=0; var u= numeric.clone(A); var m= u.length; var n= u[0].length; if (m < n) throw "Need more rows than columns" var e = new Array(n); var q = new Array(n); for (i=0; i b) return a*Math.sqrt(1.0+(b*b/a/a)) else if (b == 0.0) return a return b*Math.sqrt(1.0+(a*a/b/b)) } //Householder's reduction to bidiagonal form var f= 0.0; var g= 0.0; var h= 0.0; var x= 0.0; var y= 0.0; var z= 0.0; var s= 0.0; for (i=0; i < n; i++) { e[i]= g; s= 0.0; l= i+1; for (j=i; j < m; j++) s += (u[j][i]*u[j][i]); if (s <= tolerance) g= 0.0; else { f= u[i][i]; g= Math.sqrt(s); if (f >= 0.0) g= -g; h= f*g-s u[i][i]=f-g; for (j=l; j < n; j++) { s= 0.0 for (k=i; k < m; k++) s += u[k][i]*u[k][j] f= s/h for (k=i; k < m; k++) u[k][j]+=f*u[k][i] } } q[i]= g s= 0.0 for (j=l; j < n; j++) s= s + u[i][j]*u[i][j] if (s <= tolerance) g= 0.0 else { f= u[i][i+1] g= Math.sqrt(s) if (f >= 0.0) g= -g h= f*g - s u[i][i+1] = f-g; for (j=l; j < n; j++) e[j]= u[i][j]/h for (j=l; j < m; j++) { s=0.0 for (k=l; k < n; k++) s += (u[j][k]*u[i][k]) for (k=l; k < n; k++) u[j][k]+=s*e[k] } } y= Math.abs(q[i])+Math.abs(e[i]) if (y>x) x=y } // accumulation of right hand gtransformations for (i=n-1; i != -1; i+= -1) { if (g != 0.0) { h= g*u[i][i+1] for (j=l; j < n; j++) v[j][i]=u[i][j]/h for (j=l; j < n; j++) { s=0.0 for (k=l; k < n; k++) s += u[i][k]*v[k][j] for (k=l; k < n; k++) v[k][j]+=(s*v[k][i]) } } for (j=l; j < n; j++) { v[i][j] = 0; v[j][i] = 0; } v[i][i] = 1; g= e[i] l= i } // accumulation of left hand transformations for (i=n-1; i != -1; i+= -1) { l= i+1 g= q[i] for (j=l; j < n; j++) u[i][j] = 0; if (g != 0.0) { h= u[i][i]*g for (j=l; j < n; j++) { s=0.0 for (k=l; k < m; k++) s += u[k][i]*u[k][j]; f= s/h for (k=i; k < m; k++) u[k][j]+=f*u[k][i]; } for (j=i; j < m; j++) u[j][i] = u[j][i]/g; } else for (j=i; j < m; j++) u[j][i] = 0; u[i][i] += 1; } // diagonalization of the bidiagonal form prec= prec*x for (k=n-1; k != -1; k+= -1) { for (var iteration=0; iteration < itmax; iteration++) { // test f splitting var test_convergence = false for (l=k; l != -1; l+= -1) { if (Math.abs(e[l]) <= prec) { test_convergence= true break } if (Math.abs(q[l-1]) <= prec) break } if (!test_convergence) { // cancellation of e[l] if l>0 c= 0.0 s= 1.0 var l1= l-1 for (i =l; i= itmax-1) throw 'Error: no convergence.' // shift from bottom 2x2 minor x= q[l] y= q[k-1] g= e[k-1] h= e[k] f= ((y-z)*(y+z)+(g-h)*(g+h))/(2.0*h*y) g= pythag(f,1.0) if (f < 0.0) f= ((x-z)*(x+z)+h*(y/(f-g)-h))/x else f= ((x-z)*(x+z)+h*(y/(f+g)-h))/x // next QR transformation c= 1.0 s= 1.0 for (i=l+1; i< k+1; i++) { g= e[i] y= q[i] h= s*g g= c*g z= pythag(f,h) e[i-1]= z c= f/z s= h/z f= x*c+g*s g= -x*s+g*c h= y*s y= y*c for (j=0; j < n; j++) { x= v[j][i-1] z= v[j][i] v[j][i-1] = x*c+z*s v[j][i] = -x*s+z*c } z= pythag(f,h) q[i-1]= z c= f/z s= h/z f= c*g+s*y x= -s*g+c*y for (j=0; j < m; j++) { y= u[j][i-1] z= u[j][i] u[j][i-1] = y*c+z*s u[j][i] = -y*s+z*c } } e[l]= 0.0 e[k]= f q[k]= x } } //vt= transpose(v) //return (u,q,vt) for (i=0;i= 0; j--) { if (q[j] < q[i]) { // writeln(i,'-',j) c = q[j] q[j] = q[i] q[i] = c for(k=0;k