Last active
November 14, 2016 19:06
-
-
Save valtih1978/dc20ff861cc3981772a1aa8f02ce9fe9 to your computer and use it in GitHub Desktop.
javascript unils
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const log = console.log ; const assert = console.assert | |
//Object.prototype.trace = function(format) {format = format || (data => data); log(format(this)); return this} // prints something wrong | |
const trace = (data, format) => {format = format || (data => data); log(format(data)); return data} | |
const tracejs = (ms, data) => trace(data, data => [ms, data.json()]) | |
function range (len, begin) {begin = begin || 0 | |
return Array.apply(null, Array(len)).map((_, i) => {return begin+i;})} | |
//Array.prototype.fill = function(filler) {return this.map(_ => filler)} // startard func | |
Array.prototype.equals = function(that) {return this.every((my, i) => my == that[i] )} ; [1,2].equals([1,2]) | |
Array.prototype.sum = function() {return this.reduce((acc, el) => acc + el,0)} | |
Array.prototype.product = function() {return this.reduce((acc, el) => acc * el,1)} | |
Object.prototype.json = function() {return JSON.stringify(this)} | |
Array.prototype.last = function() {return this[this.length-1]} | |
Array.prototype.mapField = function(key, f){ return this.map( o=>Object.assign({},o,{[key]:f(o.key)}) ) } | |
Array.prototype.sliceIndex = function(i) {return this.map(e => e[i])} | |
Array.prototype.mapIndex = function(i, f){ return this.map( child =>Object.assign([], child, {[i]:f(child[i])} ) )} | |
Array.prototype.equals = function(that) {return this.length == that.length && this.every((v,i)=> v === that[i])} | |
Array.prototype.zip = function(...those) {return this.map((my, i) => those.reduce((acc, that) => [...acc, that[i]],[my])) } //; [11,22,33].zip([1,2,3]).json() | |
String.prototype.toArray = function() {return range(this.length).map(i => this.charAt(i))} | |
Array.prototype.unzip = function() {return this[0].map((_, i) => this.map(sub => sub[i]))} | |
Array.prototype.partition = function(filter) {return this.reduce(([passed, failed], el) => {(filter(el) ? passed : failed).push(el); return [passed, failed]}, [[],[]])} ; [1,2,3,4].partition(el => el > 3).json() | |
//http://stackoverflow.com/a/40573648/6267925 | |
Map.prototype.getOrElse = function(key, value) { return this.has(key) ? this.get(key) : value} | |
Map.prototype.withDefaultValue = function(defaultValue) { | |
const result = new Map([...this.entries()]); | |
const getWas = result.get; result.get = (key) => | |
result.has(key) ? getWas.call(this, key) : defaultValue; | |
return result | |
} | |
merge = (f, ...trees) => { | |
const [head, ...tail] = trees | |
return (typeof head == "object") ? | |
head.zip(...tail).map(trees => merge(f, ...trees)) : f(...trees) | |
} ; merge((a,b) => a+b , [1,2,3], [11,22,33]) | |
Math.fact = (k) => k == 0 ? 1 : k * Math.fact(k-1) | |
Math.choose = (n, k) => Math.fact(n) / Math.fact(n-k) / Math.fact(k) | |
RegExp.prototype.execAllGen = function*(input) { | |
for (let match; (match = this.exec(input)) !== null;) | |
yield [match, this.lastIndex]; | |
} ; RegExp.prototype.execAll = function(input) { | |
return [...this.execAllGen(input)]}; | |
/^\s*(\w+)\s*=.*/gm.execAll(" a=b\n d = ef ").map(([match, index]) => [match[1], index]) | |
Array.prototype.flatten = function() {return this.reduce((acc, e) => [...acc, ...e],[])} | |
Array.prototype.flatMap = function(f) {return this.map(e => f(e)).flatten()}; | |
//my sucks http://cs.stackexchange.com/questions/65962/anatomy-of-representing-of-cartesian-product-in-sw | |
// http://eddmann.com/posts/cartesian-product-in-javascript/ | |
const cartesian = (...sets) => sets.reduce((acc, set) => | |
acc.flatMap(x => set.map(y => [ ...x, y ])), [[]]); | |
const applyNtimes = (seed, increment, times) => range(times).reduce((acc, _) => increment(acc), seed) | |
Array.prototype.pow = function(n) {return applyNtimes([[]], acc => cartesian(acc, this) | |
.reduce((acc, [path, lastStep]) => [...acc, [...path, lastStep]], []), n); } | |
cartesian( | |
['small', 'medium', 'large'], | |
['red', 'green', 'blue'], | |
['shirt', 'jeans', 'shoes']); | |
// [["small", "red", "shirt"], ["small", "red", "jeans"] ... | |
const percent = p => Math.round(p * 100) | |
Distributions = {Binomial: (n,p) => range(n+1).map(i => Math.choose(n, i) * Math.pow(p, i) * Math.pow(1-p, n-i) )} | |
Distributions = function(family, ...params) {const result = {binomial: (n,p) => range(n+1).map(i => Math.choose(n, i) * Math.pow(p, i) * Math.pow(1-p, n-i) )}[family](...params); result.cum = (filter) => result.reduce((acc, p,v) => filter(v) ? Object.assign(acc, {[v]:p}) : acc, []).sum(); return result} | |
bin = Distributions("binomial", 2, 1/2); log(bin, bin.cum(n => n > 0)) | |
const cartStr = (str, n) => { | |
return range(n).reduce((lowerdim, _) => | |
range(str.length).map(li => lowerdim.map(ld => | |
ld + str.charAt(li))).flatten(), [""]) | |
} | |
Array.prototype.isAscending = function(strict) {const greater = (a,b) => strict ? a > b : a >= b; return this.length == 0 ? true : this.reduce(([result, max], a) => [result && greater(a, max), a], [true, this[0]-1])[0]} ; [false, true].forEach(strict => log([1,2,3,3].isAscending(strict), [1,2,3].isAscending(strict), [1,3, 2].isAscending(strict))) | |
const inclExcl = (...probs) => range(probs.length, 1).map(len => range(probs.length).pow(len).filter(a => a.isAscending(true)).map(a => a.map(i => probs[i]).product()).sum()).map((nsum, i) => nsum * Math.pow(-1, i)).sum() ; | |
[1,2,3,5].map(n => inclExcl(...range(n).map(_ => 1/n))) | |
var Some = function(value) { this.value = value;}; | |
Some.prototype.get = function() {return this.value} | |
Some.prototype.map = function(f) {return new Some(f(this.value))} | |
Some.prototype.isEmpty = function() {return false} | |
var None = function() { }; | |
None.prototype.get = function() {throw "attempt to get value from None"} | |
None.prototype.map = function(f) {return this} | |
None.prototype.isEmpty = function() {return true} | |
success = (value) => new Success(value); | |
var Success = function(value) { this.success = value;}; | |
Success.prototype = { | |
isFailure: () => false, isSuccess: () => true, | |
map: function(f) {return success(f(this.success));}, | |
flatMap: function(f) {return f(this.success);}, | |
getOrElse: function(value) {return this.success;}, | |
get: function() {return this.success;}, | |
recover: function(f) {return this} | |
} | |
fail = (error) => new Failure(error); | |
var Failure = function(error) { this.error = error} | |
Failure.prototype = { | |
isSuccess: () => false, isFailure: () => true, | |
map: function(f) {return this}, | |
flatMap: function(f) {return this}, | |
getOrElse: function(value) {return value}, | |
getError: function() {return this.error}, | |
get: function() {throw this.error}, | |
recover: function(f) {return f(this.error)} | |
} | |
// Integration | |
integrateLeft = (f, a,b, intervals) => {const dx = (b-a)/intervals ; return range(intervals).map(i => f(a + dx * i) ).sum()} ; | |
[10, 100, 1000].map(intervals => integrateLeft ((x) => x * Math.exp(-x), 0,1000, intervals)) | |
// we see that result is poor is even with 1000 intervals | |
//[3.7200759760208363e-42, 0.00045404052350475404, 0.9206735942077925] | |
sampleMid = (a,b, intervals) => {const dx = (b-a)/(intervals+1) ; return range(intervals,1).map(i => a + i*dx)} ; | |
[1,2,3].map(intervals => sampleMid(0,1, intervals)).json() // gives "[[0.5],[0.3333333333333333,0.6666666666666666],[0.25,0.5,0.75]]" | |
integrateLeft = (f, a,b, intervals) => integrate (f, a,b,intervals, sampleLeft) | |
integrate = (f, a,b, intervals, sampleProc) => {const lefts = sampleProc(a,b,intervals); const all = [...lefts, b]; return lefts.map((x1, i) => {const x2 = all[i+1]; return f((x2+x1)/2) * (x2-x1)} ).sum()} | |
sampleLeft = (a,b,intervals) => range(intervals).map(i => a + i*(b-a)/intervals) | |
integrateLeft = (f, a,b, intervals) => integrate (f, a,b,intervals, sampleLeft) | |
// The following displays that sampleMid improvement is marginsl | |
//[sampleMid, sampleLeft].forEach(sampleProc => console.log(sampleProc.name, ":", [10, 100, 1000].map(intervals => | |
// integrate ((x) => x * Math.exp(-x), 0,1000, intervals, sampleProc)).json())) | |
// sampleLeft : [3.7200759760208365e-40, 0.00454040523504754, 0.9206735942077925] | |
// sampleMid : [3.001171255175747e-36, 0.004963371698308279, 0.9217451547681337] | |
SigmaDelta = (deltas, initialSigma) => deltas.reduce(([sigma, intsAt], delta, i) => {const nextSigma = sigma+delta; range(Math.floor(nextSigma)-intsAt.length).forEach(_ => intsAt.push([i, intsAt.length+1-sigma])); return [nextSigma, intsAt]}, [initialSigma, []]) | |
a = [2, .9, .3+.8]; log(SigmaDelta(a, 0).json(), a.sum()) // response [4,[[0,1],[0,2],[2,0.10000000000000009],[2,1.1]]] 4 says that total len is 4 | |
// and we have two integer marks in the first interval, at offests 1 and 2 within it. We also have two intger marks in the last interval .3+.8, | |
// at offests .1 and 1.1 within it. The offsets are caused by previous, .9, interval that lacks .1 to complete the integer. | |
resample = (f, convergence, iterations) => (a,b,intervals) => {const iteration = (xes) => {const sl = [...xes, b] ; const diffs = sl.slice(0,-1).map((x,i) => Math.abs(f(sl[i+1]) - f(x))); const totalDiff = diffs.sum(); const spi = diffs.map(df => convergence * df/totalDiff* intervals + (1-convergence)); log("spi", spi.map(spi=>spi.toFixed(3))); const sd = SigmaDelta(spi, 1)[1]; if (sd.length > intervals) sd.pop() ; const sd2 = sd.map(([i, offset]) => {return sl[i]+(sl[i+1]-sl[i]) * offset/intervals}); return sd2} ; return range(iterations).reduce((was, _) => {log("resampling", was); return iteration(was)}, sampleLeft(a,b,intervals)) } | |
a = resample(x => 1/x, 0.00001, 1, 5, 10, .05) | |
integrateRes = (f, a,b, intervals, conv, iterations) => integrate (f, a,b,intervals, resample(f, conv, iterations)) | |
// The following demo suggests that resample-based integral performs good with as much as 5 sample points whereas dumb uniform sampling needs 500 | |
;[5, 50, 500].map(sp => [sp, "bars:", [integrateLeft, integrateRes].map(integrator => [integrator.name, ":", integrator(x => x*Math.exp(-x), .0000, 1000, sp, .1, 10)])]) .forEach(res => log(res.json())) | |
// Results | |
//[5,"bars:",[["integrateLeft",":",7.440151952041673e-40],["integrateRes",":",1.0636014628796828]]] | |
//[50,"bars:",[["integrateLeft",":",0.009079986008642706],["integrateRes",":",0.9667958117606238]]] | |
//[500,"bars:",[["integrateLeft",":",1.1172855274492746],["integrateRes",":",1.03947913790368]]] | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment