UNPKG

battleship-search

Version:

maximize an n-dimensional landscape using the battleship search algorithm

1,484 lines (1,372 loc) 179 kB
(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){ var search = require('../../'); var viewer = require('./viewer')(); viewer.appendTo('#viewer'); var maxLabel = document.querySelector('#max'); var q = search([ [ 0, 5 ], [ 0, 5 ] ], function (pt) { var x = pt[0], y = pt[1]; return Math.sin(5 * x + 3) - Math.cos(x) + Math.sin(3 * y - 4) - 1 / 5 * Math.cos(x * y + 3 * y) + 1/4 * Math.sin(3 * x - 1) - 2 * Math.cos(x) ; }); var shapes = {}; q.on('region', function (r) { var key = r.points.join(' '); shapes[key] = viewer.bound(r.points) }); q.on('divide', function (r) { var key = r.points.join(' '); shapes[key].parentNode.removeChild(shapes[key]); }); q.on('max', function (pt, x) { maxLabel.textContent = x + ' on iteration ' + q.iteration; }); var next = document.querySelector('#next'); next.addEventListener('click', function () { var t = q.next(); console.log('TEST', t.point, t.value); viewer.plot(t.point); }); },{"../../":3,"./viewer":2}],2:[function(require,module,exports){ module.exports = Viewer; var mr = require('mrcolor')(); function Viewer () { if (!(this instanceof Viewer)) return new Viewer; this.element = createElement('svg'); this.scale = 80; } Viewer.prototype.plot = function (pt) { var c = createElement('circle'); c.setAttribute('cx', pt[0] * this.scale + 5); c.setAttribute('cy', pt[1] * this.scale + 5); c.setAttribute('fill', 'blue'); c.setAttribute('r', 2); this.element.appendChild(c); return c; }; Viewer.prototype.bound = function (rpts) { var self = this; var pts = rpts.map(function (pt) { return pt.map(function (p) { return p * self.scale + 5 }); }); var p = createElement('polygon'); p.setAttribute('points', pts.join(' ')); var color = mr().rgb(); p.setAttribute('fill', 'rgba(' + color.join(',') + ',0.5)'); this.element.appendChild(p); return p; }; Viewer.prototype.appendTo = function (target) { if (typeof target === 'string') target = document.querySelector(target); target.appendChild(this.element); }; function createElement (name) { return document.createElementNS('http://www.w3.org/2000/svg', name); } },{"mrcolor":13}],3:[function(require,module,exports){ var expandBounds = require('./lib/expand_bounds.js'); var Region = require('./lib/region.js'); var mean = require('./lib/mean.js'); var dist = require('./lib/dist.js'); var inherits = require('inherits'); var EventEmitter = require('events').EventEmitter; module.exports = Search; inherits(Search, EventEmitter); function Search (range, opts, fn) { var self = this; if (!(this instanceof Search)) return new Search(range, opts, fn); if (typeof opts === 'function') { fn = opts; opts = {}; } if (!opts) opts = {}; this.range = range; this.corners = expandBounds(range); this.fn = fn; this.center = range.map(mean); this.regions = []; this.k = range.map(function () { return 0 }); this.smooth = range.map(function () { return 1 }); this.tansum = range.map(function () { return 1 }); this._pointMap = {}; this._pending = []; this.max = -Infinity; this.iteration = 0; } Search.prototype.next = function () { var self = this; if (this._pending.length > 0) { var previously = false; var c = this._pending[0].next(function (pt) { previously = self.has(pt); return self.test(pt); }); if (previously) return this.next(); if (c === null) { this._pending.shift(); return this.next(); } this.iteration ++; return c; } if (this.iteration === 0) { var first = true; this._pending.push({ next: function (fn) { if (!first) return null; first = false; var value = fn(self.center); return { point: self.center, value: value }; } }); } else if ((this.iteration - 1) / 2 < this.corners.length) { var i = (this.iteration - 1) / 2; var pts = [ this.center ]; for (var j = 0; j < 2; j++) { pts.push(this.corners[(i+j) % this.corners.length]); } var r = Region(pts); this._pending.push(r); this.regions.push(r); this.emit('region', r); } else { var best = this.best(); var subRegions = best.region.divide(); this.emit('divide', best.region); var xs = [ best.index, 1 ].concat(subRegions); this.regions.splice.apply(this.regions, xs); for (var i = 0; i < subRegions.length; i++) { var r = subRegions[i]; this._pending.push(r); this.emit('region', r); } } return this.next(); }; Search.prototype.best = function () { var max = this.regions[0]; var score = max.getScore(this.regions, this.max); var index = 0; for (var i = 1; i < this.regions.length; i++) { var r = this.regions[i]; var v = r.getScore(this.regions, this.max); if (v > score) { max = r; index = i; score = v; } } this.emit('best', r, score); return { region: max, index: index }; }; Search.prototype.has = function (pt) { var key = pt.join(','); return this._pointMap[key] !== undefined; }; Search.prototype.test = function (pt) { var key = pt.join(','); if (this._pointMap[key] !== undefined) return this._pointMap[key]; var value = this.fn(pt); this._pointMap[key] = value; var sm = this._smooth(pt, value); this.regions.forEach(function (r) { r.setSmooth(sm); }); this.emit('test', pt, value); if (value > this.max) { this.max = value; this.emit('max', pt, value); } return value; }; Search.prototype._smooth = function (pt, value) { var pcoords = pt.concat(value); var epsilon = []; var ptKeys = Object.keys(this._pointMap); var key = pt.join(','); if (ptKeys.length < 2) return this.smooth; for (var i = 0; i < this.range.length; i++) { epsilon[i] = 0; var csum = 0; for (var j = 0; j < ptKeys.length; j++) { if (key === ptKeys[j]) continue; var otherPt = ptKeys[j].split(','); var otherValue = this._pointMap[ptKeys[j]]; var projMag = Math.sqrt( Math.pow(otherPt[i] - pt[i], 2) + Math.pow(otherValue - value, 2) ); var c = projMag / dist(pt, ptKeys[j].split(',').map(parseFloat)); epsilon[i] += c; csum += Math.atan2(otherValue - value, otherPt[i] - pt[i]) * c; } this.tansum[i] = (this.k[i] / (this.k[i] + epsilon[i])) * this.tansum[i] + csum / (this.k[i] + epsilon[i]) ; this.k[i] += epsilon[i]; this.smooth[i] = Math.tan(this.tansum[i]); } return this.smooth; }; },{"./lib/dist.js":4,"./lib/expand_bounds.js":5,"./lib/mean.js":6,"./lib/region.js":7,"events":16,"inherits":11}],4:[function(require,module,exports){ module.exports = function dist (a, b) { var sum = 0; for (var i = 0; i < a.length; i++) { var d = a[i] - b[i]; sum += d * d; } return Math.sqrt(sum); } },{}],5:[function(require,module,exports){ var gray = require('gray-code'); module.exports = function (ranges) { var bounds = [ [ ranges[0][0] ], [ ranges[0][1] ] ]; var indexes = gray(ranges.length); return indexes.map(function (ix) { return ix.map(function (i, j) { return ranges[j][i]; }); }); }; },{"gray-code":10}],6:[function(require,module,exports){ module.exports = function (xs) { var sum = 0; for (var i = 0; i < xs.length; i++) sum += xs[i]; return sum / xs.length; } },{}],7:[function(require,module,exports){ //var computeCenter = require('./center.js'); var computeCenter = require('circumcenter'); var isTriangle = require('is-triangle'); var mean = require('./mean.js'); var distF = require('./dist.js'); function dist (a, b, sm) { var d = distF(a, b); for (var i = 0; i < d.length; i++) { d[i] *= sm[i]; } return d; } module.exports = Region; function Region (points) { var self = this; if (!(this instanceof Region)) return new Region(points); this.points = points; this.a = points[0]; this.b = points[1]; this.c = computeCenter(points); this.smooth = points[0].map(function () { return 1 }); this._queue = [ [ 'a', 'fa' ], [ 'b', 'fb' ], [ 'c', 'fc' ] ]; } Region.prototype.next = function (fn) { var q = this._queue.shift(); if (q) { var pt = this[q[0]]; var value = fn(pt); this[q[1]] = value; return { point: pt, value: value }; } this.centerMean = (this.fa + this.fb) / 2; this.range = [ Math.min(this.centerMean, this.fc), Math.max(this.centerMean, this.fc) ]; this.distAC = dist(this.a, this.c, this.smooth); this.slope = (this.fa - this.fc) / this.distAC; return null; }; Region.prototype.setSmooth = function (sm) { this.smooth = sm; this.distAC = dist(this.a, this.c, sm); this.slope = (this.fa - this.fc) / this.distAC; }; Region.prototype.getScore = function (regions, max) { var self = this; var slopes = regions.map(function (r) { return r.slope }); var thresh = (max - this.fa) / this.distAC; var appliedSlopes = regions.filter(function (r) { return r.range[0] >= self.centerMean && r.range[1] <= self.centerMean ; }); if (appliedSlopes.length === 0) appliedSlopes = slopes; if (appliedSlopes.length === 0) return 0; var projected = appliedSlopes.map(function (s) { return self.distAC * s + self.centerMean; }); var highEnough = projected.filter(function (s) { return s > thresh; }); var portion = highEnough.length / appliedSlopes.length; return portion > 0 ? mean(highEnough) / portion : 0; }; Region.prototype.recompute = function () { if (this.fc !== undefined) this.setValue(this.fc); }; Region.prototype.divide = function () { var subRegions = []; var len = this.points.length; for (var i = 0; i < len; i++) { var pts = [ this.c ]; for (var j = 0; j < len - 1; j++) { pts.push(this.points[(i+j) % len]); } if (isTriangle(pts.map(rounder))) { subRegions.push(new Region(pts)); } } return subRegions; function rounder (pts) { return pts.map(function (x) { return Math.round(x * 1e7) / 1e7; }); } }; },{"./dist.js":4,"./mean.js":6,"circumcenter":8,"is-triangle":12}],8:[function(require,module,exports){ "use strict" var numeric = require("numeric") function barycentricCircumcenter(points) { var N = points.length if(N === 0) { return [] } var D = points[0].length var A = numeric.rep([points.length+1, points.length+1], 1.0) var b = numeric.rep([points.length+1], 1.0) A[N][N] = 0.0 for(var i=0; i<N; ++i) { for(var j=0; j<=i; ++j) { A[j][i] = A[i][j] = 2.0 * numeric.dot(points[i], points[j]) } b[i] = numeric.dot(points[i], points[i]) } var x = numeric.solve(A, b) x.length = N return x } function cricumcenter(points) { if(points.length === 0) { return [] } var D = points[0].length var result = numeric.rep([D], 0.0) var weights = barycentricCircumcenter(points) for(var i=0; i<points.length; ++i) { for(var j=0; j<D; ++j) { result[j] += points[i][j] * weights[i] } } return result } cricumcenter.barycenetric = barycentricCircumcenter module.exports = cricumcenter },{"numeric":9}],9:[function(require,module,exports){ (function (global){ "use strict"; var numeric = (typeof exports === "undefined")?(function numeric() {}):(exports); if(typeof global !== "undefined") { global.numeric = numeric; } numeric.version = "1.2.6"; // 1. Utility functions numeric.bench = function bench (f,interval) { var t1,t2,n,i; if(typeof interval === "undefined") { interval = 15; } n = 0.5; t1 = new Date(); while(1) { n*=2; for(i=n;i>3;i-=4) { f(); f(); f(); f(); } while(i>0) { f(); i--; } t2 = new Date(); if(t2-t1 > interval) break; } for(i=n;i>3;i-=4) { f(); f(); f(); f(); } while(i>0) { f(); i--; } t2 = new Date(); return 1000*(3*n-1)/(t2-t1); } numeric._myIndexOf = (function _myIndexOf(w) { var n = this.length,k; for(k=0;k<n;++k) if(this[k]===w) return k; return -1; }); numeric.myIndexOf = (Array.prototype.indexOf)?Array.prototype.indexOf:numeric._myIndexOf; numeric.Function = Function; numeric.precision = 4; numeric.largeArray = 50; numeric.prettyPrint = function prettyPrint(x) { function fmtnum(x) { if(x === 0) { return '0'; } if(isNaN(x)) { return 'NaN'; } if(x<0) { return '-'+fmtnum(-x); } if(isFinite(x)) { var scale = Math.floor(Math.log(x) / Math.log(10)); var normalized = x / Math.pow(10,scale); var basic = normalized.toPrecision(numeric.precision); if(parseFloat(basic) === 10) { scale++; normalized = 1; basic = normalized.toPrecision(numeric.precision); } return parseFloat(basic).toString()+'e'+scale.toString(); } return 'Infinity'; } var ret = []; function foo(x) { var k; if(typeof x === "undefined") { ret.push(Array(numeric.precision+8).join(' ')); return false; } if(typeof x === "string") { ret.push('"'+x+'"'); return false; } if(typeof x === "boolean") { ret.push(x.toString()); return false; } if(typeof x === "number") { var a = fmtnum(x); var b = x.toPrecision(numeric.precision); var c = parseFloat(x.toString()).toString(); var d = [a,b,c,parseFloat(b).toString(),parseFloat(c).toString()]; for(k=1;k<d.length;k++) { if(d[k].length < a.length) a = d[k]; } ret.push(Array(numeric.precision+8-a.length).join(' ')+a); return false; } if(x === null) { ret.push("null"); return false; } if(typeof x === "function") { ret.push(x.toString()); var flag = false; for(k in x) { if(x.hasOwnProperty(k)) { if(flag) ret.push(',\n'); else ret.push('\n{'); flag = true; ret.push(k); ret.push(': \n'); foo(x[k]); } } if(flag) ret.push('}\n'); return true; } if(x instanceof Array) { if(x.length > numeric.largeArray) { ret.push('...Large Array...'); return true; } var flag = false; ret.push('['); for(k=0;k<x.length;k++) { if(k>0) { ret.push(','); if(flag) ret.push('\n '); } flag = foo(x[k]); } ret.push(']'); return true; } ret.push('{'); var flag = false; for(k in x) { if(x.hasOwnProperty(k)) { if(flag) ret.push(',\n'); flag = true; ret.push(k); ret.push(': \n'); foo(x[k]); } } ret.push('}'); return true; } foo(x); return ret.join(''); } numeric.parseDate = function parseDate(d) { function foo(d) { if(typeof d === 'string') { return Date.parse(d.replace(/-/g,'/')); } if(!(d instanceof Array)) { throw new Error("parseDate: parameter must be arrays of strings"); } var ret = [],k; for(k=0;k<d.length;k++) { ret[k] = foo(d[k]); } return ret; } return foo(d); } numeric.parseFloat = function parseFloat_(d) { function foo(d) { if(typeof d === 'string') { return parseFloat(d); } if(!(d instanceof Array)) { throw new Error("parseFloat: parameter must be arrays of strings"); } var ret = [],k; for(k=0;k<d.length;k++) { ret[k] = foo(d[k]); } return ret; } return foo(d); } numeric.parseCSV = function parseCSV(t) { var foo = t.split('\n'); var j,k; var ret = []; var pat = /(([^'",]*)|('[^']*')|("[^"]*")),/g; var patnum = /^\s*(([+-]?[0-9]+(\.[0-9]*)?(e[+-]?[0-9]+)?)|([+-]?[0-9]*(\.[0-9]+)?(e[+-]?[0-9]+)?))\s*$/; var stripper = function(n) { return n.substr(0,n.length-1); } var count = 0; for(k=0;k<foo.length;k++) { var bar = (foo[k]+",").match(pat),baz; if(bar.length>0) { ret[count] = []; for(j=0;j<bar.length;j++) { baz = stripper(bar[j]); if(patnum.test(baz)) { ret[count][j] = parseFloat(baz); } else ret[count][j] = baz; } count++; } } return ret; } numeric.toCSV = function toCSV(A) { var s = numeric.dim(A); var i,j,m,n,row,ret; m = s[0]; n = s[1]; ret = []; for(i=0;i<m;i++) { row = []; for(j=0;j<m;j++) { row[j] = A[i][j].toString(); } ret[i] = row.join(', '); } return ret.join('\n')+'\n'; } numeric.getURL = function getURL(url) { var client = new XMLHttpRequest(); client.open("GET",url,false); client.send(); return client; } numeric.imageURL = function imageURL(img) { function base64(A) { var n = A.length, i,x,y,z,p,q,r,s; var key = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; var ret = ""; for(i=0;i<n;i+=3) { x = A[i]; y = A[i+1]; z = A[i+2]; p = x >> 2; q = ((x & 3) << 4) + (y >> 4); r = ((y & 15) << 2) + (z >> 6); s = z & 63; if(i+1>=n) { r = s = 64; } else if(i+2>=n) { s = 64; } ret += key.charAt(p) + key.charAt(q) + key.charAt(r) + key.charAt(s); } return ret; } function crc32Array (a,from,to) { if(typeof from === "undefined") { from = 0; } if(typeof to === "undefined") { to = a.length; } var table = [0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D]; var crc = -1, y = 0, n = a.length,i; for (i = from; i < to; i++) { y = (crc ^ a[i]) & 0xFF; crc = (crc >>> 8) ^ table[y]; } return crc ^ (-1); } var h = img[0].length, w = img[0][0].length, s1, s2, next,k,length,a,b,i,j,adler32,crc32; var stream = [ 137, 80, 78, 71, 13, 10, 26, 10, // 0: PNG signature 0,0,0,13, // 8: IHDR Chunk length 73, 72, 68, 82, // 12: "IHDR" (w >> 24) & 255, (w >> 16) & 255, (w >> 8) & 255, w&255, // 16: Width (h >> 24) & 255, (h >> 16) & 255, (h >> 8) & 255, h&255, // 20: Height 8, // 24: bit depth 2, // 25: RGB 0, // 26: deflate 0, // 27: no filter 0, // 28: no interlace -1,-2,-3,-4, // 29: CRC -5,-6,-7,-8, // 33: IDAT Chunk length 73, 68, 65, 84, // 37: "IDAT" // RFC 1950 header starts here 8, // 41: RFC1950 CMF 29 // 42: RFC1950 FLG ]; crc32 = crc32Array(stream,12,29); stream[29] = (crc32>>24)&255; stream[30] = (crc32>>16)&255; stream[31] = (crc32>>8)&255; stream[32] = (crc32)&255; s1 = 1; s2 = 0; for(i=0;i<h;i++) { if(i<h-1) { stream.push(0); } else { stream.push(1); } a = (3*w+1+(i===0))&255; b = ((3*w+1+(i===0))>>8)&255; stream.push(a); stream.push(b); stream.push((~a)&255); stream.push((~b)&255); if(i===0) stream.push(0); for(j=0;j<w;j++) { for(k=0;k<3;k++) { a = img[k][i][j]; if(a>255) a = 255; else if(a<0) a=0; else a = Math.round(a); s1 = (s1 + a )%65521; s2 = (s2 + s1)%65521; stream.push(a); } } stream.push(0); } adler32 = (s2<<16)+s1; stream.push((adler32>>24)&255); stream.push((adler32>>16)&255); stream.push((adler32>>8)&255); stream.push((adler32)&255); length = stream.length - 41; stream[33] = (length>>24)&255; stream[34] = (length>>16)&255; stream[35] = (length>>8)&255; stream[36] = (length)&255; crc32 = crc32Array(stream,37); stream.push((crc32>>24)&255); stream.push((crc32>>16)&255); stream.push((crc32>>8)&255); stream.push((crc32)&255); stream.push(0); stream.push(0); stream.push(0); stream.push(0); // a = stream.length; stream.push(73); // I stream.push(69); // E stream.push(78); // N stream.push(68); // D stream.push(174); // CRC1 stream.push(66); // CRC2 stream.push(96); // CRC3 stream.push(130); // CRC4 return 'data:image/png;base64,'+base64(stream); } // 2. Linear algebra with Arrays. numeric._dim = function _dim(x) { var ret = []; while(typeof x === "object") { ret.push(x.length); x = x[0]; } return ret; } numeric.dim = function dim(x) { var y,z; if(typeof x === "object") { y = x[0]; if(typeof y === "object") { z = y[0]; if(typeof z === "object") { return numeric._dim(x); } return [x.length,y.length]; } return [x.length]; } return []; } numeric.mapreduce = function mapreduce(body,init) { return Function('x','accum','_s','_k', 'if(typeof accum === "undefined") accum = '+init+';\n'+ 'if(typeof x === "number") { var xi = x; '+body+'; return accum; }\n'+ 'if(typeof _s === "undefined") _s = numeric.dim(x);\n'+ 'if(typeof _k === "undefined") _k = 0;\n'+ 'var _n = _s[_k];\n'+ 'var i,xi;\n'+ 'if(_k < _s.length-1) {\n'+ ' for(i=_n-1;i>=0;i--) {\n'+ ' accum = arguments.callee(x[i],accum,_s,_k+1);\n'+ ' }'+ ' return accum;\n'+ '}\n'+ 'for(i=_n-1;i>=1;i-=2) { \n'+ ' xi = x[i];\n'+ ' '+body+';\n'+ ' xi = x[i-1];\n'+ ' '+body+';\n'+ '}\n'+ 'if(i === 0) {\n'+ ' xi = x[i];\n'+ ' '+body+'\n'+ '}\n'+ 'return accum;' ); } numeric.mapreduce2 = function mapreduce2(body,setup) { return Function('x', 'var n = x.length;\n'+ 'var i,xi;\n'+setup+';\n'+ 'for(i=n-1;i!==-1;--i) { \n'+ ' xi = x[i];\n'+ ' '+body+';\n'+ '}\n'+ 'return accum;' ); } numeric.same = function same(x,y) { var i,n; if(!(x instanceof Array) || !(y instanceof Array)) { return false; } n = x.length; if(n !== y.length) { return false; } for(i=0;i<n;i++) { if(x[i] === y[i]) { continue; } if(typeof x[i] === "object") { if(!same(x[i],y[i])) return false; } else { return false; } } return true; } numeric.rep = function rep(s,v,k) { if(typeof k === "undefined") { k=0; } var n = s[k], ret = Array(n), i; if(k === s.length-1) { for(i=n-2;i>=0;i-=2) { ret[i+1] = v; ret[i] = v; } if(i===-1) { ret[0] = v; } return ret; } for(i=n-1;i>=0;i--) { ret[i] = numeric.rep(s,v,k+1); } return ret; } numeric.dotMMsmall = function dotMMsmall(x,y) { var i,j,k,p,q,r,ret,foo,bar,woo,i0,k0,p0,r0; p = x.length; q = y.length; r = y[0].length; ret = Array(p); for(i=p-1;i>=0;i--) { foo = Array(r); bar = x[i]; for(k=r-1;k>=0;k--) { woo = bar[q-1]*y[q-1][k]; for(j=q-2;j>=1;j-=2) { i0 = j-1; woo += bar[j]*y[j][k] + bar[i0]*y[i0][k]; } if(j===0) { woo += bar[0]*y[0][k]; } foo[k] = woo; } ret[i] = foo; } return ret; } numeric._getCol = function _getCol(A,j,x) { var n = A.length, i; for(i=n-1;i>0;--i) { x[i] = A[i][j]; --i; x[i] = A[i][j]; } if(i===0) x[0] = A[0][j]; } numeric.dotMMbig = function dotMMbig(x,y){ var gc = numeric._getCol, p = y.length, v = Array(p); var m = x.length, n = y[0].length, A = new Array(m), xj; var VV = numeric.dotVV; var i,j,k,z; --p; --m; for(i=m;i!==-1;--i) A[i] = Array(n); --n; for(i=n;i!==-1;--i) { gc(y,i,v); for(j=m;j!==-1;--j) { z=0; xj = x[j]; A[j][i] = VV(xj,v); } } return A; } numeric.dotMV = function dotMV(x,y) { var p = x.length, q = y.length,i; var ret = Array(p), dotVV = numeric.dotVV; for(i=p-1;i>=0;i--) { ret[i] = dotVV(x[i],y); } return ret; } numeric.dotVM = function dotVM(x,y) { var i,j,k,p,q,r,ret,foo,bar,woo,i0,k0,p0,r0,s1,s2,s3,baz,accum; p = x.length; q = y[0].length; ret = Array(q); for(k=q-1;k>=0;k--) { woo = x[p-1]*y[p-1][k]; for(j=p-2;j>=1;j-=2) { i0 = j-1; woo += x[j]*y[j][k] + x[i0]*y[i0][k]; } if(j===0) { woo += x[0]*y[0][k]; } ret[k] = woo; } return ret; } numeric.dotVV = function dotVV(x,y) { var i,n=x.length,i1,ret = x[n-1]*y[n-1]; for(i=n-2;i>=1;i-=2) { i1 = i-1; ret += x[i]*y[i] + x[i1]*y[i1]; } if(i===0) { ret += x[0]*y[0]; } return ret; } numeric.dot = function dot(x,y) { var d = numeric.dim; switch(d(x).length*1000+d(y).length) { case 2002: if(y.length < 10) return numeric.dotMMsmall(x,y); else return numeric.dotMMbig(x,y); case 2001: return numeric.dotMV(x,y); case 1002: return numeric.dotVM(x,y); case 1001: return numeric.dotVV(x,y); case 1000: return numeric.mulVS(x,y); case 1: return numeric.mulSV(x,y); case 0: return x*y; default: throw new Error('numeric.dot only works on vectors and matrices'); } } numeric.diag = function diag(d) { var i,i1,j,n = d.length, A = Array(n), Ai; for(i=n-1;i>=0;i--) { Ai = Array(n); i1 = i+2; for(j=n-1;j>=i1;j-=2) { Ai[j] = 0; Ai[j-1] = 0; } if(j>i) { Ai[j] = 0; } Ai[i] = d[i]; for(j=i-1;j>=1;j-=2) { Ai[j] = 0; Ai[j-1] = 0; } if(j===0) { Ai[0] = 0; } A[i] = Ai; } return A; } numeric.getDiag = function(A) { var n = Math.min(A.length,A[0].length),i,ret = Array(n); for(i=n-1;i>=1;--i) { ret[i] = A[i][i]; --i; ret[i] = A[i][i]; } if(i===0) { ret[0] = A[0][0]; } return ret; } numeric.identity = function identity(n) { return numeric.diag(numeric.rep([n],1)); } numeric.pointwise = function pointwise(params,body,setup) { if(typeof setup === "undefined") { setup = ""; } var fun = []; var k; var avec = /\[i\]$/,p,thevec = ''; var haveret = false; for(k=0;k<params.length;k++) { if(avec.test(params[k])) { p = params[k].substring(0,params[k].length-3); thevec = p; } else { p = params[k]; } if(p==='ret') haveret = true; fun.push(p); } fun[params.length] = '_s'; fun[params.length+1] = '_k'; fun[params.length+2] = ( 'if(typeof _s === "undefined") _s = numeric.dim('+thevec+');\n'+ 'if(typeof _k === "undefined") _k = 0;\n'+ 'var _n = _s[_k];\n'+ 'var i'+(haveret?'':', ret = Array(_n)')+';\n'+ 'if(_k < _s.length-1) {\n'+ ' for(i=_n-1;i>=0;i--) ret[i] = arguments.callee('+params.join(',')+',_s,_k+1);\n'+ ' return ret;\n'+ '}\n'+ setup+'\n'+ 'for(i=_n-1;i!==-1;--i) {\n'+ ' '+body+'\n'+ '}\n'+ 'return ret;' ); return Function.apply(null,fun); } numeric.pointwise2 = function pointwise2(params,body,setup) { if(typeof setup === "undefined") { setup = ""; } var fun = []; var k; var avec = /\[i\]$/,p,thevec = ''; var haveret = false; for(k=0;k<params.length;k++) { if(avec.test(params[k])) { p = params[k].substring(0,params[k].length-3); thevec = p; } else { p = params[k]; } if(p==='ret') haveret = true; fun.push(p); } fun[params.length] = ( 'var _n = '+thevec+'.length;\n'+ 'var i'+(haveret?'':', ret = Array(_n)')+';\n'+ setup+'\n'+ 'for(i=_n-1;i!==-1;--i) {\n'+ body+'\n'+ '}\n'+ 'return ret;' ); return Function.apply(null,fun); } numeric._biforeach = (function _biforeach(x,y,s,k,f) { if(k === s.length-1) { f(x,y); return; } var i,n=s[k]; for(i=n-1;i>=0;i--) { _biforeach(typeof x==="object"?x[i]:x,typeof y==="object"?y[i]:y,s,k+1,f); } }); numeric._biforeach2 = (function _biforeach2(x,y,s,k,f) { if(k === s.length-1) { return f(x,y); } var i,n=s[k],ret = Array(n); for(i=n-1;i>=0;--i) { ret[i] = _biforeach2(typeof x==="object"?x[i]:x,typeof y==="object"?y[i]:y,s,k+1,f); } return ret; }); numeric._foreach = (function _foreach(x,s,k,f) { if(k === s.length-1) { f(x); return; } var i,n=s[k]; for(i=n-1;i>=0;i--) { _foreach(x[i],s,k+1,f); } }); numeric._foreach2 = (function _foreach2(x,s,k,f) { if(k === s.length-1) { return f(x); } var i,n=s[k], ret = Array(n); for(i=n-1;i>=0;i--) { ret[i] = _foreach2(x[i],s,k+1,f); } return ret; }); /*numeric.anyV = numeric.mapreduce('if(xi) return true;','false'); numeric.allV = numeric.mapreduce('if(!xi) return false;','true'); numeric.any = function(x) { if(typeof x.length === "undefined") return x; return numeric.anyV(x); } numeric.all = function(x) { if(typeof x.length === "undefined") return x; return numeric.allV(x); }*/ numeric.ops2 = { add: '+', sub: '-', mul: '*', div: '/', mod: '%', and: '&&', or: '||', eq: '===', neq: '!==', lt: '<', gt: '>', leq: '<=', geq: '>=', band: '&', bor: '|', bxor: '^', lshift: '<<', rshift: '>>', rrshift: '>>>' }; numeric.opseq = { addeq: '+=', subeq: '-=', muleq: '*=', diveq: '/=', modeq: '%=', lshifteq: '<<=', rshifteq: '>>=', rrshifteq: '>>>=', bandeq: '&=', boreq: '|=', bxoreq: '^=' }; numeric.mathfuns = ['abs','acos','asin','atan','ceil','cos', 'exp','floor','log','round','sin','sqrt','tan', 'isNaN','isFinite']; numeric.mathfuns2 = ['atan2','pow','max','min']; numeric.ops1 = { neg: '-', not: '!', bnot: '~', clone: '' }; numeric.mapreducers = { any: ['if(xi) return true;','var accum = false;'], all: ['if(!xi) return false;','var accum = true;'], sum: ['accum += xi;','var accum = 0;'], prod: ['accum *= xi;','var accum = 1;'], norm2Squared: ['accum += xi*xi;','var accum = 0;'], norminf: ['accum = max(accum,abs(xi));','var accum = 0, max = Math.max, abs = Math.abs;'], norm1: ['accum += abs(xi)','var accum = 0, abs = Math.abs;'], sup: ['accum = max(accum,xi);','var accum = -Infinity, max = Math.max;'], inf: ['accum = min(accum,xi);','var accum = Infinity, min = Math.min;'] }; (function () { var i,o; for(i=0;i<numeric.mathfuns2.length;++i) { o = numeric.mathfuns2[i]; numeric.ops2[o] = o; } for(i in numeric.ops2) { if(numeric.ops2.hasOwnProperty(i)) { o = numeric.ops2[i]; var code, codeeq, setup = ''; if(numeric.myIndexOf.call(numeric.mathfuns2,i)!==-1) { setup = 'var '+o+' = Math.'+o+';\n'; code = function(r,x,y) { return r+' = '+o+'('+x+','+y+')'; }; codeeq = function(x,y) { return x+' = '+o+'('+x+','+y+')'; }; } else { code = function(r,x,y) { return r+' = '+x+' '+o+' '+y; }; if(numeric.opseq.hasOwnProperty(i+'eq')) { codeeq = function(x,y) { return x+' '+o+'= '+y; }; } else { codeeq = function(x,y) { return x+' = '+x+' '+o+' '+y; }; } } numeric[i+'VV'] = numeric.pointwise2(['x[i]','y[i]'],code('ret[i]','x[i]','y[i]'),setup); numeric[i+'SV'] = numeric.pointwise2(['x','y[i]'],code('ret[i]','x','y[i]'),setup); numeric[i+'VS'] = numeric.pointwise2(['x[i]','y'],code('ret[i]','x[i]','y'),setup); numeric[i] = Function( 'var n = arguments.length, i, x = arguments[0], y;\n'+ 'var VV = numeric.'+i+'VV, VS = numeric.'+i+'VS, SV = numeric.'+i+'SV;\n'+ 'var dim = numeric.dim;\n'+ 'for(i=1;i!==n;++i) { \n'+ ' y = arguments[i];\n'+ ' if(typeof x === "object") {\n'+ ' if(typeof y === "object") x = numeric._biforeach2(x,y,dim(x),0,VV);\n'+ ' else x = numeric._biforeach2(x,y,dim(x),0,VS);\n'+ ' } else if(typeof y === "object") x = numeric._biforeach2(x,y,dim(y),0,SV);\n'+ ' else '+codeeq('x','y')+'\n'+ '}\nreturn x;\n'); numeric[o] = numeric[i]; numeric[i+'eqV'] = numeric.pointwise2(['ret[i]','x[i]'], codeeq('ret[i]','x[i]'),setup); numeric[i+'eqS'] = numeric.pointwise2(['ret[i]','x'], codeeq('ret[i]','x'),setup); numeric[i+'eq'] = Function( 'var n = arguments.length, i, x = arguments[0], y;\n'+ 'var V = numeric.'+i+'eqV, S = numeric.'+i+'eqS\n'+ 'var s = numeric.dim(x);\n'+ 'for(i=1;i!==n;++i) { \n'+ ' y = arguments[i];\n'+ ' if(typeof y === "object") numeric._biforeach(x,y,s,0,V);\n'+ ' else numeric._biforeach(x,y,s,0,S);\n'+ '}\nreturn x;\n'); } } for(i=0;i<numeric.mathfuns2.length;++i) { o = numeric.mathfuns2[i]; delete numeric.ops2[o]; } for(i=0;i<numeric.mathfuns.length;++i) { o = numeric.mathfuns[i]; numeric.ops1[o] = o; } for(i in numeric.ops1) { if(numeric.ops1.hasOwnProperty(i)) { setup = ''; o = numeric.ops1[i]; if(numeric.myIndexOf.call(numeric.mathfuns,i)!==-1) { if(Math.hasOwnProperty(o)) setup = 'var '+o+' = Math.'+o+';\n'; } numeric[i+'eqV'] = numeric.pointwise2(['ret[i]'],'ret[i] = '+o+'(ret[i]);',setup); numeric[i+'eq'] = Function('x', 'if(typeof x !== "object") return '+o+'x\n'+ 'var i;\n'+ 'var V = numeric.'+i+'eqV;\n'+ 'var s = numeric.dim(x);\n'+ 'numeric._foreach(x,s,0,V);\n'+ 'return x;\n'); numeric[i+'V'] = numeric.pointwise2(['x[i]'],'ret[i] = '+o+'(x[i]);',setup); numeric[i] = Function('x', 'if(typeof x !== "object") return '+o+'(x)\n'+ 'var i;\n'+ 'var V = numeric.'+i+'V;\n'+ 'var s = numeric.dim(x);\n'+ 'return numeric._foreach2(x,s,0,V);\n'); } } for(i=0;i<numeric.mathfuns.length;++i) { o = numeric.mathfuns[i]; delete numeric.ops1[o]; } for(i in numeric.mapreducers) { if(numeric.mapreducers.hasOwnProperty(i)) { o = numeric.mapreducers[i]; numeric[i+'V'] = numeric.mapreduce2(o[0],o[1]); numeric[i] = Function('x','s','k', o[1]+ 'if(typeof x !== "object") {'+ ' xi = x;\n'+ o[0]+';\n'+ ' return accum;\n'+ '}'+ 'if(typeof s === "undefined") s = numeric.dim(x);\n'+ 'if(typeof k === "undefined") k = 0;\n'+ 'if(k === s.length-1) return numeric.'+i+'V(x);\n'+ 'var xi;\n'+ 'var n = x.length, i;\n'+ 'for(i=n-1;i!==-1;--i) {\n'+ ' xi = arguments.callee(x[i]);\n'+ o[0]+';\n'+ '}\n'+ 'return accum;\n'); } } }()); numeric.truncVV = numeric.pointwise(['x[i]','y[i]'],'ret[i] = round(x[i]/y[i])*y[i];','var round = Math.round;'); numeric.truncVS = numeric.pointwise(['x[i]','y'],'ret[i] = round(x[i]/y)*y;','var round = Math.round;'); numeric.truncSV = numeric.pointwise(['x','y[i]'],'ret[i] = round(x/y[i])*y[i];','var round = Math.round;'); numeric.trunc = function trunc(x,y) { if(typeof x === "object") { if(typeof y === "object") return numeric.truncVV(x,y); return numeric.truncVS(x,y); } if (typeof y === "object") return numeric.truncSV(x,y); return Math.round(x/y)*y; } numeric.inv = function inv(x) { var s = numeric.dim(x), abs = Math.abs, m = s[0], n = s[1]; var A = numeric.clone(x), Ai, Aj; var I = numeric.identity(m), Ii, Ij; var i,j,k,x; for(j=0;j<n;++j) { var i0 = -1; var v0 = -1; for(i=j;i!==m;++i) { k = abs(A[i][j]); if(k>v0) { i0 = i; v0 = k; } } Aj = A[i0]; A[i0] = A[j]; A[j] = Aj; Ij = I[i0]; I[i0] = I[j]; I[j] = Ij; x = Aj[j]; for(k=j;k!==n;++k) Aj[k] /= x; for(k=n-1;k!==-1;--k) Ij[k] /= x; for(i=m-1;i!==-1;--i) { if(i!==j) { Ai = A[i]; Ii = I[i]; x = Ai[j]; for(k=j+1;k!==n;++k) Ai[k] -= Aj[k]*x; for(k=n-1;k>0;--k) { Ii[k] -= Ij[k]*x; --k; Ii[k] -= Ij[k]*x; } if(k===0) Ii[0] -= Ij[0]*x; } } } return I; } numeric.det = function det(x) { var s = numeric.dim(x); if(s.length !== 2 || s[0] !== s[1]) { throw new Error('numeric: det() only works on square matrices'); } var n = s[0], ret = 1,i,j,k,A = numeric.clone(x),Aj,Ai,alpha,temp,k1,k2,k3; for(j=0;j<n-1;j++) { k=j; for(i=j+1;i<n;i++) { if(Math.abs(A[i][j]) > Math.abs(A[k][j])) { k = i; } } if(k !== j) { temp = A[k]; A[k] = A[j]; A[j] = temp; ret *= -1; } Aj = A[j]; for(i=j+1;i<n;i++) { Ai = A[i]; alpha = Ai[j]/Aj[j]; for(k=j+1;k<n-1;k+=2) { k1 = k+1; Ai[k] -= Aj[k]*alpha; Ai[k1] -= Aj[k1]*alpha; } if(k!==n) { Ai[k] -= Aj[k]*alpha; } } if(Aj[j] === 0) { return 0; } ret *= Aj[j]; } return ret*A[j][j]; } numeric.transpose = function transpose(x) { var i,j,m = x.length,n = x[0].length, ret=Array(n),A0,A1,Bj; for(j=0;j<n;j++) ret[j] = Array(m); for(i=m-1;i>=1;i-=2) { A1 = x[i]; A0 = x[i-1]; for(j=n-1;j>=1;--j) { Bj = ret[j]; Bj[i] = A1[j]; Bj[i-1] = A0[j]; --j; Bj = ret[j]; Bj[i] = A1[j]; Bj[i-1] = A0[j]; } if(j===0) { Bj = ret[0]; Bj[i] = A1[0]; Bj[i-1] = A0[0]; } } if(i===0) { A0 = x[0]; for(j=n-1;j>=1;--j) { ret[j][0] = A0[j]; --j; ret[j][0] = A0[j]; } if(j===0) { ret[0][0] = A0[0]; } } return ret; } numeric.negtranspose = function negtranspose(x) { var i,j,m = x.length,n = x[0].length, ret=Array(n),A0,A1,Bj; for(j=0;j<n;j++) ret[j] = Array(m); for(i=m-1;i>=1;i-=2) { A1 = x[i]; A0 = x[i-1]; for(j=n-1;j>=1;--j) { Bj = ret[j]; Bj[i] = -A1[j]; Bj[i-1] = -A0[j]; --j; Bj = ret[j]; Bj[i] = -A1[j]; Bj[i-1] = -A0[j]; } if(j===0) { Bj = ret[0]; Bj[i] = -A1[0]; Bj[i-1] = -A0[0]; } } if(i===0) { A0 = x[0]; for(j=n-1;j>=1;--j) { ret[j][0] = -A0[j]; --j; ret[j][0] = -A0[j]; } if(j===0) { ret[0][0] = -A0[0]; } } return ret; } numeric._random = function _random(s,k) { var i,n=s[k],ret=Array(n), rnd; if(k === s.length-1) { rnd = Math.random; for(i=n-1;i>=1;i-=2) { ret[i] = rnd(); ret[i-1] = rnd(); } if(i===0) { ret[0] = rnd(); } return ret; } for(i=n-1;i>=0;i--) ret[i] = _random(s,k+1); return ret; } numeric.random = function random(s) { return numeric._random(s,0); } numeric.norm2 = function norm2(x) { return Math.sqrt(numeric.norm2Squared(x)); } numeric.linspace = function linspace(a,b,n) { if(typeof n === "undefined") n = Math.max(Math.round(b-a)+1,1); if(n<2) { return n===1?[a]:[]; } var i,ret = Array(n); n--; for(i=n;i>=0;i--) { ret[i] = (i*b+(n-i)*a)/n; } return ret; } numeric.getBlock = function getBlock(x,from,to) { var s = numeric.dim(x); function foo(x,k) { var i,a = from[k], n = to[k]-a, ret = Array(n); if(k === s.length-1) { for(i=n;i>=0;i--) { ret[i] = x[i+a]; } return ret; } for(i=n;i>=0;i--) { ret[i] = foo(x[i+a],k+1); } return ret; } return foo(x,0); } numeric.setBlock = function setBlock(x,from,to,B) { var s = numeric.dim(x); function foo(x,y,k) { var i,a = from[k], n = to[k]-a; if(k === s.length-1) { for(i=n;i>=0;i--) { x[i+a] = y[i]; } } for(i=n;i>=0;i--) { foo(x[i+a],y[i],k+1); } } foo(x,B,0); return x; } numeric.getRange = function getRange(A,I,J) { var m = I.length, n = J.length; var i,j; var B = Array(m), Bi, AI; for(i=m-1;i!==-1;--i) { B[i] = Array(n); Bi = B[i]; AI = A[I[i]]; for(j=n-1;j!==-1;--j) Bi[j] = AI[J[j]]; } return B; } numeric.blockMatrix = function blockMatrix(X) { var s = numeric.dim(X); if(s.length<4) return numeric.blockMatrix([X]); var m=s[0],n=s[1],M,N,i,j,Xij; M = 0; N = 0; for(i=0;i<m;++i) M+=X[i][0].length; for(j=0;j<n;++j) N+=X[0][j][0].length; var Z = Array(M); for(i=0;i<M;++i) Z[i] = Array(N); var I=0,J,ZI,k,l,Xijk; for(i=0;i<m;++i) { J=N; for(j=n-1;j!==-1;--j) { Xij = X[i][j]; J -= Xij[0].length; for(k=Xij.length-1;k!==-1;--k) { Xijk = Xij[k]; ZI = Z[I+k]; for(l = Xijk.length-1;l!==-1;--l) ZI[J+l] = Xijk[l]; } } I += X[i][0].length; } return Z; } numeric.tensor = function tensor(x,y) { if(typeof x === "number" || typeof y === "number") return numeric.mul(x,y); var s1 = numeric.dim(x), s2 = numeric.dim(y); if(s1.length !== 1 || s2.length !== 1) { throw new Error('numeric: tensor product is only defined for vectors'); } var m = s1[0], n = s2[0], A = Array(m), Ai, i,j,xi; for(i=m-1;i>=0;i--) { Ai = Array(n); xi = x[i]; for(j=n-1;j>=3;--j) { Ai[j] = xi * y[j]; --j; Ai[j] = xi * y[j]; --j; Ai[j] = xi * y[j]; --j; Ai[j] = xi * y[j]; } while(j>=0) { Ai[j] = xi * y[j]; --j; } A[i] = Ai; } return A; } // 3. The Tensor type T numeric.T = function T(x,y) { this.x = x; this.y = y; } numeric.t = function t(x,y) { return new numeric.T(x,y); } numeric.Tbinop = function Tbinop(rr,rc,cr,cc,setup) { var io = numeric.indexOf; if(typeof setup !== "string") { var k; setup = ''; for(k in numeric) { if(numeric.hasOwnProperty(k) && (rr.indexOf(k)>=0 || rc.indexOf(k)>=0 || cr.indexOf(k)>=0 || cc.indexOf(k)>=0) && k.length>1) { setup += 'var '+k+' = numeric.'+k+';\n'; } } } return Function(['y'], 'var x = this;\n'+ 'if(!(y instanceof numeric.T)) { y = new numeric.T(y); }\n'+ setup+'\n'+ 'if(x.y) {'+ ' if(y.y) {'+ ' return new numeric.T('+cc+');\n'+ ' }\n'+ ' return new numeric.T('+cr+');\n'+ '}\n'+ 'if(y.y) {\n'+ ' return new numeric.T('+rc+');\n'+ '}\n'+ 'return new numeric.T('+rr+');\n' ); } numeric.T.prototype.add = numeric.Tbinop( 'add(x.x,y.x)',