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-extract-contour/contour.js

415 lines
10 KiB

"use strict"
var pool = require("typedarray-pool")
module.exports = createSurfaceExtractor
//Helper macros
function array(i) {
return "a" + i
}
function data(i) {
return "d" + i
}
function cube(i,bitmask) {
return "c" + i + "_" + bitmask
}
function shape(i) {
return "s" + i
}
function stride(i,j) {
return "t" + i + "_" + j
}
function offset(i) {
return "o" + i
}
function scalar(i) {
return "x" + i
}
function pointer(i) {
return "p" + i
}
function delta(i,bitmask) {
return "d" + i + "_" + bitmask
}
function index(i) {
return "i" + i
}
function step(i,j) {
return "u" + i + "_" + j
}
function pcube(bitmask) {
return "b" + bitmask
}
function qcube(bitmask) {
return "y" + bitmask
}
function pdelta(bitmask) {
return "e" + bitmask
}
function vert(i) {
return "v" + i
}
var VERTEX_IDS = "V"
var PHASES = "P"
var VERTEX_COUNT = "N"
var POOL_SIZE = "Q"
var POINTER = "X"
var TEMPORARY = "T"
function permBitmask(dimension, mask, order) {
var r = 0
for(var i=0; i<dimension; ++i) {
if(mask & (1<<i)) {
r |= (1<<order[i])
}
}
return r
}
//Generates the surface procedure
function compileSurfaceProcedure(vertexFunc, faceFunc, phaseFunc, scalarArgs, order, typesig) {
var arrayArgs = typesig.length
var dimension = order.length
if(dimension < 2) {
throw new Error("ndarray-extract-contour: Dimension must be at least 2")
}
var funcName = "extractContour" + order.join("_")
var code = []
var vars = []
var args = []
//Assemble arguments
for(var i=0; i<arrayArgs; ++i) {
args.push(array(i))
}
for(var i=0; i<scalarArgs; ++i) {
args.push(scalar(i))
}
//Shape
for(var i=0; i<dimension; ++i) {
vars.push(shape(i) + "=" + array(0) + ".shape[" + i + "]|0")
}
//Data, stride, offset pointers
for(var i=0; i<arrayArgs; ++i) {
vars.push(data(i) + "=" + array(i) + ".data",
offset(i) + "=" + array(i) + ".offset|0")
for(var j=0; j<dimension; ++j) {
vars.push(stride(i,j) + "=" + array(i) + ".stride[" + j + "]|0")
}
}
//Pointer, delta and cube variables
for(var i=0; i<arrayArgs; ++i) {
vars.push(pointer(i) + "=" + offset(i))
vars.push(cube(i,0))
for(var j=1; j<(1<<dimension); ++j) {
var ptrStr = []
for(var k=0; k<dimension; ++k) {
if(j & (1<<k)) {
ptrStr.push("-" + stride(i,k))
}
}
vars.push(delta(i,j) + "=(" + ptrStr.join("") + ")|0")
vars.push(cube(i,j) + "=0")
}
}
//Create step variables
for(var i=0; i<arrayArgs; ++i) {
for(var j=0; j<dimension; ++j) {
var stepVal = [ stride(i,order[j]) ]
if(j > 0) {
stepVal.push(stride(i, order[j-1]) + "*" + shape(order[j-1]) )
}
vars.push(step(i,order[j]) + "=(" + stepVal.join("-") + ")|0")
}
}
//Create index variables
for(var i=0; i<dimension; ++i) {
vars.push(index(i) + "=0")
}
//Vertex count
vars.push(VERTEX_COUNT + "=0")
//Compute pool size, initialize pool step
var sizeVariable = ["2"]
for(var i=dimension-2; i>=0; --i) {
sizeVariable.push(shape(order[i]))
}
//Previous phases and vertex_ids
vars.push(POOL_SIZE + "=(" + sizeVariable.join("*") + ")|0",
PHASES + "=mallocUint32(" + POOL_SIZE + ")",
VERTEX_IDS + "=mallocUint32(" + POOL_SIZE + ")",
POINTER + "=0")
//Create cube variables for phases
vars.push(pcube(0) + "=0")
for(var j=1; j<(1<<dimension); ++j) {
var cubeDelta = []
var cubeStep = [ ]
for(var k=0; k<dimension; ++k) {
if(j & (1<<k)) {
if(cubeStep.length === 0) {
cubeDelta.push("1")
} else {
cubeDelta.unshift(cubeStep.join("*"))
}
}
cubeStep.push(shape(order[k]))
}
var signFlag = ""
if(cubeDelta[0].indexOf(shape(order[dimension-2])) < 0) {
signFlag = "-"
}
var jperm = permBitmask(dimension, j, order)
vars.push(pdelta(jperm) + "=(-" + cubeDelta.join("-") + ")|0",
qcube(jperm) + "=(" + signFlag + cubeDelta.join("-") + ")|0",
pcube(jperm) + "=0")
}
vars.push(vert(0) + "=0", TEMPORARY + "=0")
function forLoopBegin(i, start) {
code.push("for(", index(order[i]), "=", start, ";",
index(order[i]), "<", shape(order[i]), ";",
"++", index(order[i]), "){")
}
function forLoopEnd(i) {
for(var j=0; j<arrayArgs; ++j) {
code.push(pointer(j), "+=", step(j,order[i]), ";")
}
code.push("}")
}
function fillEmptySlice(k) {
for(var i=k-1; i>=0; --i) {
forLoopBegin(i, 0)
}
var phaseFuncArgs = []
for(var i=0; i<arrayArgs; ++i) {
if(typesig[i]) {
phaseFuncArgs.push(data(i) + ".get(" + pointer(i) + ")")
} else {
phaseFuncArgs.push(data(i) + "[" + pointer(i) + "]")
}
}
for(var i=0; i<scalarArgs; ++i) {
phaseFuncArgs.push(scalar(i))
}
code.push(PHASES, "[", POINTER, "++]=phase(", phaseFuncArgs.join(), ");")
for(var i=0; i<k; ++i) {
forLoopEnd(i)
}
for(var j=0; j<arrayArgs; ++j) {
code.push(pointer(j), "+=", step(j,order[k]), ";")
}
}
function processGridCell(mask) {
//Read in local data
for(var i=0; i<arrayArgs; ++i) {
if(typesig[i]) {
code.push(cube(i,0), "=", data(i), ".get(", pointer(i), ");")
} else {
code.push(cube(i,0), "=", data(i), "[", pointer(i), "];")
}
}
//Read in phase
var phaseFuncArgs = []
for(var i=0; i<arrayArgs; ++i) {
phaseFuncArgs.push(cube(i,0))
}
for(var i=0; i<scalarArgs; ++i) {
phaseFuncArgs.push(scalar(i))
}
code.push(pcube(0), "=", PHASES, "[", POINTER, "]=phase(", phaseFuncArgs.join(), ");")
//Read in other cube data
for(var j=1; j<(1<<dimension); ++j) {
code.push(pcube(j), "=", PHASES, "[", POINTER, "+", pdelta(j), "];")
}
//Check for boundary crossing
var vertexPredicate = []
for(var j=1; j<(1<<dimension); ++j) {
vertexPredicate.push("(" + pcube(0) + "!==" + pcube(j) + ")")
}
code.push("if(", vertexPredicate.join("||"), "){")
//Read in boundary data
var vertexArgs = []
for(var i=0; i<dimension; ++i) {
vertexArgs.push(index(i))
}
for(var i=0; i<arrayArgs; ++i) {
vertexArgs.push(cube(i,0))
for(var j=1; j<(1<<dimension); ++j) {
if(typesig[i]) {
code.push(cube(i,j), "=", data(i), ".get(", pointer(i), "+", delta(i,j), ");")
} else {
code.push(cube(i,j), "=", data(i), "[", pointer(i), "+", delta(i,j), "];")
}
vertexArgs.push(cube(i,j))
}
}
for(var i=0; i<(1<<dimension); ++i) {
vertexArgs.push(pcube(i))
}
for(var i=0; i<scalarArgs; ++i) {
vertexArgs.push(scalar(i))
}
//Generate vertex
code.push("vertex(", vertexArgs.join(), ");",
vert(0), "=", VERTEX_IDS, "[", POINTER, "]=", VERTEX_COUNT, "++;")
//Check for face crossings
var base = (1<<dimension)-1
var corner = pcube(base)
for(var j=0; j<dimension; ++j) {
if((mask & ~(1<<j))===0) {
//Check face
var subset = base^(1<<j)
var edge = pcube(subset)
var faceArgs = [ ]
for(var k=subset; k>0; k=(k-1)&subset) {
faceArgs.push(VERTEX_IDS + "[" + POINTER + "+" + pdelta(k) + "]")
}
faceArgs.push(vert(0))
for(var k=0; k<arrayArgs; ++k) {
if(j&1) {
faceArgs.push(cube(k,base), cube(k,subset))
} else {
faceArgs.push(cube(k,subset), cube(k,base))
}
}
if(j&1) {
faceArgs.push(corner, edge)
} else {
faceArgs.push(edge, corner)
}
for(var k=0; k<scalarArgs; ++k) {
faceArgs.push(scalar(k))
}
code.push("if(", corner, "!==", edge, "){",
"face(", faceArgs.join(), ")}")
}
}
//Increment pointer, close off if statement
code.push("}",
POINTER, "+=1;")
}
function flip() {
for(var j=1; j<(1<<dimension); ++j) {
code.push(TEMPORARY, "=", pdelta(j), ";",
pdelta(j), "=", qcube(j), ";",
qcube(j), "=", TEMPORARY, ";")
}
}
function createLoop(i, mask) {
if(i < 0) {
processGridCell(mask)
return
}
fillEmptySlice(i)
code.push("if(", shape(order[i]), ">0){",
index(order[i]), "=1;")
createLoop(i-1, mask|(1<<order[i]))
for(var j=0; j<arrayArgs; ++j) {
code.push(pointer(j), "+=", step(j,order[i]), ";")
}
if(i === dimension-1) {
code.push(POINTER, "=0;")
flip()
}
forLoopBegin(i, 2)
createLoop(i-1, mask)
if(i === dimension-1) {
code.push("if(", index(order[dimension-1]), "&1){",
POINTER, "=0;}")
flip()
}
forLoopEnd(i)
code.push("}")
}
createLoop(dimension-1, 0)
//Release scratch memory
code.push("freeUint32(", VERTEX_IDS, ");freeUint32(", PHASES, ");")
//Compile and link procedure
var procedureCode = [
"'use strict';",
"function ", funcName, "(", args.join(), "){",
"var ", vars.join(), ";",
code.join(""),
"}",
"return ", funcName ].join("")
var proc = new Function(
"vertex",
"face",
"phase",
"mallocUint32",
"freeUint32",
procedureCode)
return proc(
vertexFunc,
faceFunc,
phaseFunc,
pool.mallocUint32,
pool.freeUint32)
}
function createSurfaceExtractor(args) {
function error(msg) {
throw new Error("ndarray-extract-contour: " + msg)
}
if(typeof args !== "object") {
error("Must specify arguments")
}
var order = args.order
if(!Array.isArray(order)) {
error("Must specify order")
}
var arrays = args.arrayArguments||1
if(arrays < 1) {
error("Must have at least one array argument")
}
var scalars = args.scalarArguments||0
if(scalars < 0) {
error("Scalar arg count must be > 0")
}
if(typeof args.vertex !== "function") {
error("Must specify vertex creation function")
}
if(typeof args.cell !== "function") {
error("Must specify cell creation function")
}
if(typeof args.phase !== "function") {
error("Must specify phase function")
}
var getters = args.getters || []
var typesig = new Array(arrays)
for(var i=0; i<arrays; ++i) {
if(getters.indexOf(i) >= 0) {
typesig[i] = true
} else {
typesig[i] = false
}
}
return compileSurfaceProcedure(
args.vertex,
args.cell,
args.phase,
scalars,
order,
typesig)
}