StackGenVis: Alignment of Data, Algorithms, and Models for Stacking Ensemble Learning Using Performance Metrics https://doi.org/10.1109/TVCG.2020.3030352
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
StackGenVis/frontend/node_modules/ndarray-gradient/fdg.js

297 lines
7.2 KiB

'use strict'
module.exports = gradient
var dup = require('dup')
var cwiseCompiler = require('cwise-compiler')
var TEMPLATE_CACHE = {}
var GRADIENT_CACHE = {}
var EmptyProc = {
body: "",
args: [],
thisVars: [],
localVars: []
}
var centralDiff = cwiseCompiler({
args: [ 'array', 'array', 'array' ],
pre: EmptyProc,
post: EmptyProc,
body: {
args: [ {
name: 'out',
lvalue: true,
rvalue: false,
count: 1
}, {
name: 'left',
lvalue: false,
rvalue: true,
count: 1
}, {
name: 'right',
lvalue: false,
rvalue: true,
count: 1
}],
body: "out=0.5*(left-right)",
thisVars: [],
localVars: []
},
funcName: 'cdiff'
})
var zeroOut = cwiseCompiler({
args: [ 'array' ],
pre: EmptyProc,
post: EmptyProc,
body: {
args: [ {
name: 'out',
lvalue: true,
rvalue: false,
count: 1
}],
body: "out=0",
thisVars: [],
localVars: []
},
funcName: 'zero'
})
function generateTemplate(d) {
if(d in TEMPLATE_CACHE) {
return TEMPLATE_CACHE[d]
}
var code = []
for(var i=0; i<d; ++i) {
code.push('out', i, 's=0.5*(inp', i, 'l-inp', i, 'r);')
}
var args = [ 'array' ]
var names = ['junk']
for(var i=0; i<d; ++i) {
args.push('array')
names.push('out' + i + 's')
var o = dup(d)
o[i] = -1
args.push({
array: 0,
offset: o.slice()
})
o[i] = 1
args.push({
array: 0,
offset: o.slice()
})
names.push('inp' + i + 'l', 'inp' + i + 'r')
}
return TEMPLATE_CACHE[d] = cwiseCompiler({
args: args,
pre: EmptyProc,
post: EmptyProc,
body: {
body: code.join(''),
args: names.map(function(n) {
return {
name: n,
lvalue: n.indexOf('out') === 0,
rvalue: n.indexOf('inp') === 0,
count: (n!=='junk')|0
}
}),
thisVars: [],
localVars: []
},
funcName: 'fdTemplate' + d
})
}
function generateGradient(boundaryConditions) {
var token = boundaryConditions.join()
var proc = GRADIENT_CACHE[token]
if(proc) {
return proc
}
var d = boundaryConditions.length
var code = ['function gradient(dst,src){var s=src.shape.slice();' ]
function handleBoundary(facet) {
var cod = d - facet.length
var loStr = []
var hiStr = []
var pickStr = []
for(var i=0; i<d; ++i) {
if(facet.indexOf(i+1) >= 0) {
pickStr.push('0')
} else if(facet.indexOf(-(i+1)) >= 0) {
pickStr.push('s['+i+']-1')
} else {
pickStr.push('-1')
loStr.push('1')
hiStr.push('s['+i+']-2')
}
}
var boundStr = '.lo(' + loStr.join() + ').hi(' + hiStr.join() + ')'
if(loStr.length === 0) {
boundStr = ''
}
if(cod > 0) {
code.push('if(1')
for(var i=0; i<d; ++i) {
if(facet.indexOf(i+1) >= 0 || facet.indexOf(-(i+1)) >= 0) {
continue
}
code.push('&&s[', i, ']>2')
}
code.push('){grad', cod, '(src.pick(', pickStr.join(), ')', boundStr)
for(var i=0; i<d; ++i) {
if(facet.indexOf(i+1) >= 0 || facet.indexOf(-(i+1)) >= 0) {
continue
}
code.push(',dst.pick(', pickStr.join(), ',', i, ')', boundStr)
}
code.push(');')
}
for(var i=0; i<facet.length; ++i) {
var bnd = Math.abs(facet[i])-1
var outStr = 'dst.pick(' + pickStr.join() + ',' + bnd + ')' + boundStr
switch(boundaryConditions[bnd]) {
case 'clamp':
var cPickStr = pickStr.slice()
var dPickStr = pickStr.slice()
if(facet[i] < 0) {
cPickStr[bnd] = 's[' + bnd + ']-2'
} else {
dPickStr[bnd] = '1'
}
if(cod === 0) {
code.push('if(s[', bnd, ']>1){dst.set(',
pickStr.join(), ',', bnd, ',0.5*(src.get(',
cPickStr.join(), ')-src.get(',
dPickStr.join(), ')))}else{dst.set(',
pickStr.join(), ',', bnd, ',0)};')
} else {
code.push('if(s[', bnd, ']>1){diff(', outStr,
',src.pick(', cPickStr.join(), ')', boundStr,
',src.pick(', dPickStr.join(), ')', boundStr,
');}else{zero(', outStr, ');};')
}
break
case 'mirror':
if(cod === 0) {
code.push('dst.set(', pickStr.join(), ',', bnd, ',0);')
} else {
code.push('zero(', outStr, ');')
}
break
case 'wrap':
var aPickStr = pickStr.slice()
var bPickStr = pickStr.slice()
if(facet[i] < 0) {
aPickStr[bnd] = 's[' + bnd + ']-2'
bPickStr[bnd] = '0'
} else {
aPickStr[bnd] = 's[' + bnd + ']-1'
bPickStr[bnd] = '1'
}
if(cod === 0) {
code.push('if(s[', bnd, ']>2){dst.set(',
pickStr.join(), ',', bnd, ',0.5*(src.get(',
aPickStr.join(), ')-src.get(',
bPickStr.join(), ')))}else{dst.set(',
pickStr.join(), ',', bnd, ',0)};')
} else {
code.push('if(s[', bnd, ']>2){diff(', outStr,
',src.pick(', aPickStr.join(), ')', boundStr,
',src.pick(', bPickStr.join(), ')', boundStr,
');}else{zero(', outStr, ');};')
}
break
default:
throw new Error('ndarray-gradient: Invalid boundary condition')
}
}
if(cod > 0) {
code.push('};')
}
}
//Enumerate ridges, facets, etc. of hypercube
for(var i=0; i<(1<<d); ++i) {
var faces = []
for(var j=0; j<d; ++j) {
if(i & (1<<j)) {
faces.push(j+1)
}
}
for(var k=0; k<(1<<faces.length); ++k) {
var sfaces = faces.slice()
for(var j=0; j<faces.length; ++j) {
if(k & (1<<j)) {
sfaces[j] = -sfaces[j]
}
}
handleBoundary(sfaces)
}
}
code.push('return dst;};return gradient')
//Compile and link routine, save cached procedure
var linkNames = [ 'diff', 'zero' ]
var linkArgs = [ centralDiff, zeroOut ]
for(var i=1; i<=d; ++i) {
linkNames.push('grad' + i)
linkArgs.push(generateTemplate(i))
}
linkNames.push(code.join(''))
var link = Function.apply(void 0, linkNames)
var proc = link.apply(void 0, linkArgs)
TEMPLATE_CACHE[token] = proc
return proc
}
function gradient(out, inp, bc) {
if(Array.isArray(bc)) {
if(bc.length !== inp.dimension) {
throw new Error('ndarray-gradient: invalid boundary conditions')
}
} else if(typeof bc === 'string') {
bc = dup(inp.dimension, bc)
} else {
bc = dup(inp.dimension, 'clamp')
}
if(out.dimension !== inp.dimension + 1) {
throw new Error('ndarray-gradient: output dimension must be +1 input dimension')
}
if(out.shape[inp.dimension] !== inp.dimension) {
throw new Error('ndarray-gradient: output shape must match input shape')
}
for(var i=0; i<inp.dimension; ++i) {
if(out.shape[i] !== inp.shape[i]) {
throw new Error('ndarray-gradient: shape mismatch')
}
}
if(inp.size === 0) {
return out
}
if(inp.dimension <= 0) {
out.set(0)
return out
}
var cached = generateGradient(bc)
return cached(out, inp)
}