{"version":3,"sources":["node_modules/browserify/node_modules/browser-pack/_prelude.js","index.js","lib/globals.js","lib/pipeline.js","lib/sscalcalculator.js","lib/sgemmcalculator.js","lib/saxpycalculator.js","lib/sdwnscalculator.js","lib/sclmpcalculator.js","lib/tensor.js","lib/webgl.js","lib/slokncalculator.js"],"names":["createModule","gl","sgemm","M","N","K","alpha","A","B","beta","C","length","Error","texels1","texels0","texels2","transpose","texture0","createDataTexture","texture1","texture2","texture3","createOutputTexture","sgemmcalculator","calculate","rawBuffer","readData","context","deleteTexture","Float32Array","saxpy","a","X","Y","isFloat32Array","fill","saxpycalculator","obj","Object","prototype","toString","call","sscal","b","sscalcalculator","sstd","mu","sigma","sdwns","channels","factor","stride","N_out","Math","floor","M_out","sdwnscalculator","sclmp","Number","MIN_VALUE","MAX_VALUE","sclmpcalculator","fromArray","array","type","tranpose","data","c","shape","ii","jj","r","typedArray","result","constructor","i","j","SGEMMCalculator","SAXPYCalculator","SSCALCalculator","SDWNSCalculator","SCLMPCalculator","pipeline","gpu","bind","encode","util","globals","require","module","exports","WebGL","e","console","log","t0","tOut","Tensor","texture","t1","t2","slokn","margin","N_p","M_p","ceil","P_p","slokncalculator","SLOKNCalculator","webgl","standalone","this","s","p","program","createProgram","TEXTURE_UNIFORM_NAME_0","LENGTH_UNIFORM_NAME","ADD_UNIFORM_NAME","MUL_UNIFORM_NAME","out","pad","getPad","selectProgram","bindInputTexture","TEXTURE0","bindUniforms","bindOutputTexture","drawElements","TRIANGLES","UNSIGNED_SHORT","unbindInputTexture","textureUnit","name","activeTexture","bindTexture","TEXTURE_2D","sampler","getUniformLocation","uniform1i","N_gl","b_gl","a_gl","pad_gl","uniform1f","s_c","p_c","program_","program_c","TEXTURE_UNIFORM_NAME_1","TEXTURE_UNIFORM_NAME_2","SHARED_LENGTH_UNIFORM_NAME","COLUMN_COUNT_UNIFORM_NAME","PAD_UNIFORM_NAME","ALPHA_UNIFORM_NAME","BETA_UNIFORM_NAME","TEXTURE1","TEXTURE2","kPad","nPad","K_gl","alpha_gl","beta_gl","COEFFICIENT_UNIFORM_NAME","DownsampleCalculator","INPUT_ROW_COUNT_UNIFORM_NAME","INPUT_COLUMN_COUNT_UNIFORM_NAME","OUTPUT_ROW_COUNT_UNIFORM_NAME","OUTPUT_COLUMN_COUNT_UNIFORM_NAME","FACTOR_UNIFORM_NAME","STRIDE_UNIFORM_NAME","CHANNEL_COUNT_UNIFORM_NAME","COMPONENTS_PER_TEXEL","M_gl","M_out_gl","N_out_gl","factor_gl","stride_gl","channel_count_gl","LOWER_UNIFORM_NAME","UPPER_UNIFORM_NAME","Symbol","toStringTag","transfer","keep","reshape","tT","split","submatrix","combine","options","glOptions","ext","canvas","document","createElement","premultipliedAlpha","preserveDrawingBuffer","getContext","getExtension","hasFloat","highp","getShaderPrecisionFormat","FRAGMENT_SHADER","HIGH_FLOAT","hasHighPrecision","precision","passThrough","vertexShader","createShader","VERTEX_SHADER","shaderSource","compileShader","reshape_simple","encode_program","transpose_program","reshape_program","reshape_simple_program","submatrix_program","combine_program","POSITION_UNIFORM_NAME","TEXTURE_UNIFORM_NAME","npad","mpad","npad_gl","mpad_gl","pad_out","M_in_gl","N_in_gl","pad_in_gl","offset","offset_gl","fragmentShaderSource","fragmentShader","getShaderParameter","COMPILE_STATUS","getShaderInfoLog","attachShader","linkProgram","useProgram","bindVertices","renderer","position","getAttribLocation","vertexBuffer","createBuffer","bindBuffer","ARRAY_BUFFER","vertices","bufferData","STATIC_DRAW","vertexAttribPointer","FLOAT","enableVertexAttribArray","texCoords","textureCoords","indices","ELEMENT_ARRAY_BUFFER","vertexIndices","Uint16Array","h","w","texels","PAD_TEMPLATE","rem","createTexture","texImage2D","RGBA","row","remainder","full_texel_row_len","full_row_texture_width","row_start","last_texel","full_texel_row_end","buffer","BYTES_PER_ELEMENT","texSubImage2D","set","texParameteri","TEXTURE_WRAP_S","CLAMP_TO_EDGE","TEXTURE_WRAP_T","TEXTURE_MAG_FILTER","NEAREST","TEXTURE_MIN_FILTER","destTexture","UNSIGNED_BYTE","height","width","viewport","framebuffer","createFramebuffer","bindFramebuffer","FRAMEBUFFER","framebufferTexture2D","COLOR_ATTACHMENT0","checkFramebufferStatus","FRAMEBUFFER_COMPLETE","rawbuffer","ArrayBuffer","prod","Uint8Array","readPixels","KERNEL_WIDTH_UNIFORM_NAME","M_in","N_in","pad_in","c_gl","N_p_gl","margin_gl"],"mappings":"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","file":"bundle.js","sourcesContent":["(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);var f=new Error(\"Cannot find module '\"+o+\"'\");throw f.code=\"MODULE_NOT_FOUND\",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.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})","var globals = require(\"./lib/globals\"),\n\tpipeline = require(\"./lib/pipeline\"),\n\tSGEMMCalculator = require(\"./lib/sgemmcalculator\"),\n\tSAXPYCalculator = require(\"./lib/saxpycalculator\"),\n\tSSCALCalculator = require(\"./lib/sscalcalculator\"),\n\tSDWNSCalculator = require(\"./lib/sdwnscalculator\"),\n\tSCLMPCalculator = require(\"./lib/sclmpcalculator\");\n\n// do we have a WebGL context?\nif(globals.gl){\n\t// yes, load the library\n\tmodule.exports = createModule(globals.gl);\n} else {\n\t// no, abort and export null\n\tmodule.exports = null;\n}\n\nfunction createModule(gl){\n\n\tvar sgemmcalculator = new SGEMMCalculator(gl),\n\t\tsaxpycalculator = new SAXPYCalculator(gl),\n\t\tsscalcalculator = new SSCALCalculator(gl),\n\t\tsdwnscalculator = new SDWNSCalculator(gl),\n\t\tsclmpcalculator = new SCLMPCalculator(gl);\n\n\treturn {\n\t\t// level one\n\t\t\"saxpy\" : saxpy,\n\t\t\"sscal\" : sscal,   // single precision matrix scale\n\t\t// level two\n\t\t// level three\n\t\t\"sgemm\" : sgemm,   // single precision generalized matrix multiply\n\t\t// extra\n\t\t\"sstd\" : sstd,     // single precision Standard Score normalization\n\t\t\"sdwns\": sdwns,\n\t\t\"sclmp\": sclmp,\n\t\t// pipeline\n\t\t\"pipeline\" : pipeline,\n\t\t// internals\n\t\t\"gpu\" : {\n\t\t\t\t\t\"gl\" : gl,\n\t\t \t\t\t\"sgemm\": pipeline.sgemmcalculator.calculate.bind(pipeline.sgemmcalculator),\n\t\t\t\t\t\"sscal\" : pipeline.sscalcalculator.calculate.bind(pipeline.sscalcalculator),\n\t\t\t\t\t\"sclmp\" : pipeline.sclmpcalculator.calculate.bind(pipeline.sclmpcalculator),\n\t\t\t\t\t\"sdwns\" : pipeline.sdwnscalculator.calculate.bind(pipeline.sdwnscalculator),\n\t\t\t\t\t\"encode\" : gl.encode.bind(gl)\n\t\t\t\t},\n\t\t\"util\" : { \"fromArray\" : fromArray, \"transpose\" : transpose}\n\t};\n\n\n\t/* Wrap the GL calculation object in a (relatively) user friendly function that\n\t\taccepts TypedArrays\n\n\t\t* convert the data to (padded) textures in GPU memory\n\t\t* execute calculation\n\t\t* read result into an array, and return\n\t */\n\tfunction sgemm(M, N, K, alpha, A, B, beta, C){\n\n\t\tif(C != null && C.length != N){\n\t\t\tthrow new Error(\"Only vector C with length matching rows in A is currently supported.\");\n\t\t}\n\n\t\t// pack each matrix into a single RGBA texel array, with the second transposed\n\t\tvar texels0 = A,\n\t\t\ttexels1,\n\t\t\ttexels2 = C;\n\n\n\t\ttexels1 = transpose(K, N, B);\n\n\t\t// create input textures from data\n\t\tvar texture0 = gl.createDataTexture(M, K, texels0);\n\t\tvar texture1 = gl.createDataTexture(N, K, texels1);\n\t\tvar texture2 = null;\n\t\tif(texels2 != null){\n\t\t\ttexture2 = gl.createDataTexture(1, N, texels2);\n\t\t}\n\n\t\tvar texture3 = gl.createOutputTexture(M, N);\n\n\t\tsgemmcalculator.calculate(M, N, K, alpha, texture0, texture1, beta, texture2, texture3);\n\n\t\t// retrieve data\n\t\trawBuffer = gl.readData(M, N);\n\n\t\t// clean up\n\t\tgl.context.deleteTexture(texture0);\n\t\tgl.context.deleteTexture(texture1);\n\t\tif(texture2 != null){\n\t\t\tgl.context.deleteTexture(texture2);\n\t\t}\n\t\tgl.context.deleteTexture(texture3);\n\n\t\t// return result\n\t\treturn new Float32Array(rawBuffer);\n\n\t}\n\n\tfunction saxpy(N, a, X, Y){\n\n\t\tvar rawBuffer;\n\n\n\t\tvar texels0 = X,\n\t\t\ttexels1;\n\n\t\t// TODO: special shader for constant Y\n\t\tif(isFloat32Array(Y)){\n\t\t\ttexels1 = Y;\n\t\t} else {\n\t\t\ttexels1 = new Float32Array(N);\n\t\t\ttexels1.fill(Y);\n\t\t}\n\n\t\t// create input textures from data\n\t\tvar texture0 = gl.createDataTexture(1, N, texels0);\n\t\tvar texture1 = gl.createDataTexture(1, N, texels1);\n\n\t\tvar texture3 = gl.createOutputTexture(1, N);\n\n\t\tsaxpycalculator.calculate(N, a, texture0, texture1, texture3);\n\n\t\t// retrieve data\n\t\trawBuffer = gl.readData(1, N);\n\n\t\t// clean up\n\t\tgl.context.deleteTexture(texture0);\n\t\tgl.context.deleteTexture(texture1);\n\t\tgl.context.deleteTexture(texture3);\n\n\t\t// return result\n\t\treturn new Float32Array(rawBuffer);\n\n\t}\n\n\tfunction isFloat32Array(obj){\n\t\treturn Object.prototype.toString.call(obj) === \"[object Float32Array]\";\n\t}\n\t/* a more general version of the BLAS Level 1 scale, that works on matrices\n\t   and includes an elementwise scalar addition\n\n\t   a * X + b\n\n\t   a - multiplicative scalar\n\t   b - additive scalar\n\t   X - matrix (M x N)\n\n\t   to get the standard BLAS scal set M = 1 and b = 0\n\n\t   this function is generally only cost effective to use in a pipeline\n\t*/\n\tfunction sscal(M, N, a, b, X){\n\n\t\tvar rawBuffer;\n\n\t\tvar texels0 = X;\n\t\tvar texture0 = gl.createDataTexture(M, N, texels0);\n\n\t\tvar texture3 = gl.createOutputTexture(M, N);\n\n\t\tsscalcalculator.calculate(M, N, a, b, texture0, texture3);\n\n\t\t// retrieve data\n\t\trawBuffer = gl.readData(M, N);\n\n\t\t// clean up\n\t\tgl.context.deleteTexture(texture0);\n\t\tgl.context.deleteTexture(texture3);\n\n\t\t// return result\n\t\treturn new Float32Array(rawBuffer);\n\t}\n\n\t/* Calculate the Standard Score normalization (subtract mean\n\t   ,divide by standard deviation).\n\t */\n\tfunction sstd(M, N, mu, sigma, X){\n\n\t\tvar rawBuffer;\n\n\t\tvar texels0 = X;\n\t\tvar texture0 = gl.createDataTexture(M, N, texels0);\n\n\t\tvar texture3 = gl.createOutputTexture(M, N);\n\n\t\t// adjust the parameters (for inverse) and call the standard score normalization\n\t\tsscalcalculator.calculate(M, N, 1.0/sigma, -1.0 * mu/sigma, texture0, texture3);\n\n\t\t// retrieve data\n\t\trawBuffer = gl.readData(M, N);\n\n\t\t// clean up\n\t\tgl.context.deleteTexture(texture0);\n\t\tgl.context.deleteTexture(texture3);\n\n\t\t// return result\n\t\treturn new Float32Array(rawBuffer);\n\t}\n\n\t/* downsample an image (taking the max) for Pooling\n\n\t\tM - rows in input\n\t\tN - columns in input\n\t\tc - channels in input\n\t\tfactor - the downsample factor (width of patch to sample)\n\t\tstride - width between pooling regions\n\t\tX - input image\n\t */\n\tfunction sdwns(M, N, channels, factor, stride, X){\n\n\n\t\tvar texels0 = X;\n\n\t\tvar texture0 = gl.createDataTexture(M, N * channels, X);\n\n\t\tvar N_out = Math.floor((N - factor) / stride) + 1;\n\t\tvar M_out = Math.floor((M - factor) / stride) + 1;\n\n\t\tvar texture3 = gl.createOutputTexture(M_out, N_out * channels);\n\n\t\tsdwnscalculator.calculate(M, N, channels, factor, stride, texture0, texture3);\n\n\t\t// retrieve data\n\t\trawBuffer = gl.readData(M_out, N_out * channels);\n\n\t\t// clean up\n\t\tgl.context.deleteTexture(texture0);\n\t\tgl.context.deleteTexture(texture3);\n\n\t\t// return result\n\t\treturn new Float32Array(rawBuffer);\n\t}\n\t/*  Elementwise clamp function for matrices on the interval [a, b]. Can also be\n\t\tused for min or max, by passing Number.MIN_VALUE for the first parameter and\n\t\tNumber.MAX_VALUE for the second parameter, respectively.\n\n\t\tPassing `null` for either of these parameters will default to it's\n\t\trespective min or max value.\n\n\t\tM - number of rows in X\n\t\tN - number of columns in X\n\t\ta - lower bound (inclusize)\n\t\tb - upper bound (inclusive)\n\t\tX - matrix\n\n\t   to get the standard BLAS scal set M = 1 and b = 0\n\n\t   this function is generally only cost effective to use in a pipeline\n\t*/\n\tfunction sclmp(M, N, a, b, X){\n\n\t\ta = (a != null) ? a : Number.MIN_VALUE;\n\t\tb = (b != null) ? b : Number.MAX_VALUE;\n\n\t\tvar rawBuffer;\n\n\t\tvar texels0 = X;\n\t\tvar texture0 = gl.createDataTexture(M, N, texels0);\n\n\t\tvar texture3 = gl.createOutputTexture(M, N);\n\n\t\tsclmpcalculator.calculate(M, N, a, b, texture0, texture3);\n\n\t\t// retrieve data\n\t\trawBuffer = gl.readData(M, N);\n\n\t\t// clean up\n\t\tgl.context.deleteTexture(texture0);\n\t\tgl.context.deleteTexture(texture3);\n\n\t\t// return result\n\t\treturn new Float32Array(rawBuffer);\n\t}\n\t/*\n\tfunction saxpy(n, a, x, y){\n\t\tvar i = 0,\n\t\t\tresult = new Float32Array(n);\n\n\t\t// assert n = x.length\n\t\t// assert a is scalar\n\t\t// assert x is Float32Array\n\n\t\tif(isNumeric(y)){\n\t\t\t// shortcut for scalar y\n\t\t\tfor(; i < n; i++){\n\t\t\t\tresult[i] = a * x[i] + y;\n\t\t\t}\n\t\t} else {\n\n\t\t\tfor(; i < n; i++){\n\t\t\t\tresult[i] = a * x[i] + y[i];\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\n\t}*/\n\n\t// add a String.format method, if none exists\n\tif (!String.prototype.format) {\n\t  String.prototype.format = function() {\n\t\tvar args = arguments;\n\t\treturn this.replace(/{(\\d+)}/g, function(match, number) {\n\t\t  return typeof args[number] != 'undefined'\n\t\t\t? args[number]\n\t\t\t: match\n\t\t  ;\n\t\t});\n\t  };\n\t}\n\n\tfunction isNumeric( obj ) { return (obj - parseFloat( obj ) + 1) >= 0; }\n\n\t/* create a typed array from a 2D javascript array */\n\tfunction fromArray(array, type, tranpose) {\n\t\tvar shape = [],\n\t\t\t\tdata,\n\t\t\t\tc;   // number of columns\n\n\t\tif(!tranpose){\n\t\t\tshape[0] = array.length;\n\t\t\tshape[1] = array[0].length;\n\t\t} else {\n\t\t\tshape[1] = array.length;\n\t\t\tshape[0] = array[0].length;\n\t\t}\n\t\tc = shape[1];\n\n\t\ttype = type || Float32Array;\n\n\t\tdata = new type(shape[0]*shape[1]);\n\n\t\tfor (var ii = 0; ii < shape[0]; ++ii)\n\t\t\tfor (var jj = 0; jj < shape[1]; ++jj)\n\t\t\tif(!tranpose)\n\t\t\t\tdata[ii*c + jj] = array[ii][jj];\n\t\t\telse\n\t\t\t\tdata[ii*c + jj] = array[jj][ii];\n\n\t\treturn data;\n\t};\n\n\t// tranpose a typed array in row major order, with the given row and column\n\t// numers\n\tfunction transpose(r, c, typedArray){\n\t\tvar result = new typedArray.constructor(r*c);\n\n\t\tfor(var i = 0; i < r; i++){\n\t\t\tfor(var j = 0; j < c; j++){\n\t\t\t\tresult[j * r + i] = typedArray[i * c + j];\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n}\n","var WebGL = require(\"./webgl\");\n\nvar gl;\ntry{\n\tgl = new WebGL();\n} catch (e){\n\tgl = null;\n\tconsole.log('No support for WebGL!');\n}\n\nmodule.exports = {\n\t\"gl\" : gl\n}\n","var globals = require('./globals'),\n\tSGEMMCalculator = require(\"./sgemmcalculator\"),\n\tSAXPYCalculator = require(\"./saxpycalculator\"),\n\tSSCALCalculator = require(\"./sscalcalculator\"),\n\tSDWNSCalculator = require(\"./sdwnscalculator\"),\n\tSCLMPCalculator = require(\"./sclmpcalculator\"),\n\tSLOKNCalculator = require(\"./slokncalculator\"),\n\tTensor = require('./tensor');\n\n\n// do we have a WebGL context?\nif(globals.gl){\n\t// yes, load the library\n\tmodule.exports = createModule(globals.gl);\n} else {\n\t// no, abort and export null\n\tmodule.exports = null;\n}\n\nfunction createModule(gl){\n\n\tvar sgemmcalculator = new SGEMMCalculator(gl, false),\n\t\tsaxpycalculator = new SAXPYCalculator(gl, false),\n\t\tsscalcalculator = new SSCALCalculator(gl, false),\n\t\tsdwnscalculator = new SDWNSCalculator(gl, false),\n\t\tsclmpcalculator = new SCLMPCalculator(gl, false),\n\t\tslokncalculator = new SLOKNCalculator(gl, false);\n\n\treturn {\n\t\t\"Tensor\" : Tensor,\n\t\t\"sscal\" : sscal,\n\t\t\"sgemm\" : sgemm,\n\t\t\"sdwns\" : sdwns,\n\t\t\"sclmp\" : sclmp,\n\t\t\"slokn\" : slokn,\n\n\t\t\"sgemmcalculator\" : sgemmcalculator,\n\t\t\"saxpycalculator\" : saxpycalculator,\n\t\t\"sscalcalculator\" : sscalcalculator,\n\t\t\"sdwnscalculator\" : sdwnscalculator,\n\t\t\"sclmpcalculator\" : sclmpcalculator,\n\t\t\"slokncalculator\" : slokncalculator\n\t}\n\n\t/* scale (and optionally offset) a Tensor, elementwise\n\t */\n\tfunction sscal(a, b, t0){\n\n\t\tvar M = t0.shape[0],\n\t\t\tN = t0.shape[1];\n\n\t\t// create an empty output Tensor\n\t\tvar tOut = new Tensor([M, N], null);\n\n\t\tsscalcalculator.calculate(M, N, a, b, t0.texture, tOut.texture);\n\n\t\treturn tOut;\n\t}\n\n\t/* matrix multiply on t0 and t1 with additive t2. t1 must be transposed\n\t */\n\tfunction sgemm(alpha, t0, t1, beta, t2){\n\n\t\tif(t1.shape[1] !== t0.shape[1])\n\t\t\tthrow new Error(\"Second dimension must be of same size for input Tensors (second Tensor is transposed).\");\n\n\t\tvar M = t0.shape[0],\n\t\t\tN = t1.shape[0],\n\t\t\tK = t0.shape[1];\n\n\t\tvar texture2;\n\n\t\tif(t2){\n\t\t\ttexture2 = t2.texture;\n\t\t} else {\n\t\t\ttexture2 = null;\n\t\t}\n\n\t\t// create an empty output Tensor\n\t\tvar tOut = new Tensor([M, N], null);\n\n\t\tsgemmcalculator.calculate(M, N, K, alpha, t0.texture, t1.texture, beta, texture2, tOut.texture);\n\n\t\treturn tOut;\n\t}\n\n\tfunction sdwns(channels, factor, stride, t0){\n\n\t\tif(t0.shape[1] % channels !== 0)\n\t\t\tthrow new Error(\"Second dimension of tensor must be a multiple of channels\");\n\n\t\tvar M = t0.shape[0],\n\t\t\tN = t0.shape[1] / channels;\n\n\t\tvar M_out = Math.floor((M - factor) / stride) + 1;\n\t\tvar N_out = Math.floor((N - factor) / stride) + 1;\n\n\t\t// create an empty output Tensor\n\t\tvar tOut = new Tensor([M_out, N_out * channels], null);\n\n\t\tsdwnscalculator.calculate(M, N, channels, factor, stride, t0.texture, tOut.texture);\n\n\t\treturn tOut;\n\t}\n\n\tfunction sclmp(a, b, t0){\n\n\t\ta = (a != null) ? a : Number.MIN_VALUE;\n\t\tb = (b != null) ? b : Number.MAX_VALUE;\n\n\t\tvar M = t0.shape[0],\n\t\t\tN = t0.shape[1];\n\n\t\t// create an empty output Tensor\n\t\tvar tOut = new Tensor([M, N], null);\n\n\t\tsclmpcalculator.calculate(M, N, a, b, t0.texture, tOut.texture);\n\n\t\treturn tOut;\n\t}\n\n\t/* Linearize onto Kernels, Transform input into one row per patch, for use in\n\t\tconvolution.\n\n\t\tchannels - number of channels in the input\n\t\tfactor - width (and height) of kernels (and patches)\n\t\tstride - number of elements between patches\n\t\tt0 - the input Tensor\n\t */\n\tfunction slokn(channels, factor, stride, margin, t0){\n\n\t\tif(t0.shape[1] % channels !== 0)\n\t\t\tthrow new Error(\"Second dimension of tensor must be a multiple of channels\");\n\n\t\tvar M = t0.shape[0],\n\t\t\tN = t0.shape[1] / channels;\n\n\t\tvar N_p, M_p;\n\n\t\t// number of patches (columns and rows)\n\t\tif(!margin){\n\t\t\tmargin = 0;\n\t\t\tN_p = Math.ceil((N - factor) / stride) + 1;\n\t\t\tM_p = Math.ceil((M - factor) / stride) + 1;\n\t\t} else {\n\t\t\tN_p = Math.ceil((N + (2 * margin) - factor) / stride) + 1;\n\t\t\tM_p = Math.ceil((M + (2 * margin) - factor) / stride) + 1;\n\t\t}\n\n\t\tvar P_p = factor * factor * channels; // elements per kernel\n\t\tvar M_out = (M_p * N_p),\n\t\t \tN_out = P_p;\n\n\t\t// create an empty output Tensor\n\t\tvar tOut = new Tensor([M_out, N_out], null);\n\n\t\tslokncalculator.calculate(M, N, channels, M_out, N_out, N_p, factor, stride, margin, t0.texture, tOut.texture);\n\n\t\treturn tOut;\n\t}\n}\n","var WebGL = require('./webgl');\n\n/*  a more general version of the BLAS Level 1 scale that works on matrices\n    and includes an elementwise scalar addition\n\n    a * X + b\n\n\twhere X is a matrix, a and b are scalars and operations are elementwise\n\n    to get the standard BLAS scal set M = 1 and b = 0\n\n\n\twebgl - a weblas.WebGL object\n\tstandalone - whether or not to automatically run the floating point encode\n\t\tstep for rendering to an UNSIGNED_BYTE texture (this is required for\n\t\tmobile, circa 2015) but can't be used as part of a pipeline.\n\n\t* uploads and downloads data\n\t* executes calculation\n */\nfunction SSCALCalculator(webgl, standalone){\n\tthis.webgl = webgl,\n\tthis.standalone = (standalone != null) ? standalone : true; // default to standalone mode\n\n\tvar s = \"precision highp float;\\n#define GLSLIFY 1\\n\\nvarying vec2      outTex;\\t// texture coords of row/column to calculate\\nuniform sampler2D X;\\t\\t// texture with data from padded X\\nuniform int       N;\\t\\t// number of columns\\nuniform int       pad;\\t\\t// additional columns to nearest multiple of four\\nuniform float     b; \\t\\t// additive term\\nuniform float     a; \\t\\t// multiplicative term\\n\\n// Render float to bytes according to IEEE 754 Floating Point\\nvec4 encode_float_1540259130(float val) {\\n\\n\\t// TODO: correctly handle denormal numbers\\n\\t// http://www.2ality.com/2012/04/number-encoding.html\\n\\tfloat a = abs(val);                           // encode absolute value + sign\\n\\tfloat exp = floor(log2(a));                 // number of powers of 2\\n\\tfloat mant = pow(2.,log2(a)-exp) * pow(2.,23.);  // multiply to fill 24 bits (implied leading 1)\\n\\tfloat mant1 = floor(mant / 256. / 256.);    // first 8 bits of mantissa\\n\\tfloat mant2 = mod(floor(mant / 256.),256.); // second 8 bits\\n\\tfloat mant3 = mod(mant,256.);               // third 8 bits\\n\\n\\thighp float sign = 128.-128.*(a/val);\\t\\t\\t// sign bit is 256 or 0\\n\\thighp float e = (sign+exp+127.)/510.;\\t\\t// exponent and sign\\n\\thighp float m1 = (mant1-(128.*(1.-mod(exp+127.,2.))))/255.; // handle leading bit\\n\\thighp float m2 = (mant2)/255.;\\t\\t\\t\\t// middle part\\n\\thighp float m3 = (mant3+.5)/255.;\\t\\t\\t// scale to 0 - 255\\n\\n\\treturn vec4(m3,m2,m1,e);\\n}\\n\\n// select an element from a vector based on index\\nfloat select_index_1604150559(vec4 v, int index){\\n\\tfloat val;\\n\\tif (index == 0) {\\n\\t\\tval = v.r;\\n\\t} else if(index == 1) {\\n\\t\\tval = v.g;\\n\\t} else if(index == 2) {\\n\\t\\tval = v.b;\\n\\t} else if(index == 3){\\n\\t\\tval = v.a;\\n\\t} else {\\n\\t\\t// should never be here\\n\\t\\tval = 0.0;\\n\\t}\\n\\n\\treturn val;\\n}\\n\\nvoid main(void) {\\n\\n\\t// get the implied row and column from .y and .x of passed (output)\\n\\t// texture coordinate. These map directly to input texture space when\\n\\t// the relevant dimensions are the same.\\n \\tfloat row = outTex.y;\\n\\tfloat col = outTex.x;\\n\\n\\t// direct usage of col requires output be padded exactly like input\\n\\tvec4 x = texture2D( X, vec2(col, row));\\n\\tvec4 sum_v = (a * x) + b;\\n\\tint channel = int(mod(col * float(N + pad), 4.0 ));\\n\\tfloat sum = select_index_1604150559(sum_v, channel);\\n\\n\\tif (sum == 0.) {\\n\\t\\tgl_FragColor = vec4(0.,0.,0.,0.);\\n\\t\\treturn;\\n\\t}\\n\\n \\t// output vec4 with bytes for an IEEE754 32-bit floating point number\\n\\tgl_FragColor = encode_float_1540259130(sum);\\n}\\n\",\n\t\tp = \"precision highp float;\\n#define GLSLIFY 1\\n\\nvarying vec2      outTex;\\t// texture coords of row/column to calculate\\nuniform sampler2D X;\\t\\t// texture with data from padded X\\nuniform int       N;\\t\\t// number of columns\\nuniform int       pad;\\t\\t// additional columns to nearest multiple of four\\nuniform float     b; \\t\\t// additive term\\nuniform float     a; \\t\\t// multiplicative term\\n\\n// set pad values to 0.0, if in padded region of output texture\\nvoid fix_pad_1540259130(inout vec4 v, int pad){\\n\\tv.a = 0.0;\\n\\tif(pad == 2){\\n\\t\\tv.b = 0.0;\\n\\t} else if(pad == 3){\\n\\t\\tv.b = 0.0;\\n\\t\\tv.g = 0.0;\\n\\t}\\n}\\n\\nvoid main(void) {\\n\\n\\t// get the implied row and column from .y and .x of passed (output)\\n\\t// texture coordinate. These map directly to input texture space when\\n\\t// the relevant dimensions are the same.\\n\\tfloat row_t = outTex.y;\\n\\tfloat col_t = outTex.x;\\n\\tfloat col = (col_t * float(N + pad) - 2.0); // index of first element in pixel (matrix space)\\n\\n\\t// direct usage of col requires output be padded exactly like input\\n\\tvec4 x = texture2D( X, vec2(col_t, row_t));\\n\\tvec4 sum_v = (a * x) + b;\\n\\n\\t// fix padded region\\n\\tif(pad > 0 && col + 4.0 > float(N) ) {\\n\\t\\tfix_pad_1540259130(sum_v, pad);\\n\\t}\\n\\n\\tgl_FragColor = sum_v;\\n}\\n\";\n\n\t// create the webgl shader program for this calculation\n\t// based on the specific fragment shader for this calculation\n\t// and the generic pass through shader\n\tif(this.standalone){\n\t\tthis.program = this.webgl.createProgram(s);\n\t} else {\n\t\tthis.program = this.webgl.createProgram(p);\n\t}\n}\n\nmodule.exports = SSCALCalculator;\n\n/* Names of the uniforms (variables) used in the shader program passed in on\n   each calculation.\n */\nSSCALCalculator.TEXTURE_UNIFORM_NAME_0 = \"X\";\nSSCALCalculator.LENGTH_UNIFORM_NAME = \"N\";\nSSCALCalculator.ADD_UNIFORM_NAME = \"b\";\nSSCALCalculator.MUL_UNIFORM_NAME = \"a\";\n\n/* Elementwise scale and offset a matrix\n\n\tM - number of rows in X\n\tN - number of columns in X\n\ta - scalar coefficient to X\n\tb - scalar offset of X\n\tX - matrix (texture)\n\tout - output (texture)\n\n  How this works:\n\n  1. Activate our shader program\n  2. Bind input textures\n  3. Set shader program parameters\n  4. Bind output texture\n  5. Activate calculation with `drawElements`\n\n */\nSSCALCalculator.prototype.calculate = function(M, N, a, b, X, out){\n\n\tvar gl = this.webgl.context;\n\n\tvar pad = this.webgl.getPad(N);\n\n\tthis.webgl.selectProgram(this.program);\n\n\t// create and bind our input texture using matrix data\n\tthis.bindInputTexture(X, gl.TEXTURE0, SSCALCalculator.TEXTURE_UNIFORM_NAME_0);\n\n\t// set the data specific variables in our shader program\n\tthis.bindUniforms(N, pad, a, b);\n\n\t// create our destination texture\n\tif(this.standalone){\n\t\tthis.webgl.bindOutputTexture(M, N + pad, out);\n\t} else {\n\t\tthis.webgl.bindOutputTexture(M, (N + pad)/ 4, out);\n\t}\n\n\n\t// initiate calculation\n\tgl.drawElements(gl.TRIANGLES, /*num items*/6, gl.UNSIGNED_SHORT, 0);\n\n\tthis.webgl.unbindInputTexture(gl.TEXTURE0);\n\n};\n\n/* Create a texture from the given texel data and bind it to our shader program.\n\n\ttexture - texture containing the data\n\ttextureUnit - the texture unit to bind to (gl.TEXTURE0, gl.TEXTURE1, etc)\n\tname - the uniform name to associate with (must match shader program)\n\n\tmust compile program (with createProgram) first\n*/\nSSCALCalculator.prototype.bindInputTexture = function(texture, textureUnit, name){\n\tvar gl = this.webgl.context,\n\t\tprogram = this.program;\n\n\tgl.activeTexture(textureUnit); // gl.TEXTURE0, gl.TEXTURE1, etc\n\tgl.bindTexture(\t  gl.TEXTURE_2D, texture);\n\n\tvar sampler = gl.getUniformLocation(program, name);\n\tgl.uniform1i(sampler, textureUnit - gl.TEXTURE0);\n\n};\n\n/* Set up inputs for the texture shader\n\n */\nSSCALCalculator.prototype.bindUniforms = function(N, pad, a, b) {\n\tvar gl = this.webgl.context;\n\n\t// get var locations\n\tvar N_gl = gl.getUniformLocation(this.program, SSCALCalculator.LENGTH_UNIFORM_NAME),\n\t\tb_gl = gl.getUniformLocation(this.program, SSCALCalculator.ADD_UNIFORM_NAME),\n\t\ta_gl = gl.getUniformLocation(this.program, SSCALCalculator.MUL_UNIFORM_NAME),\n\t\tpad_gl = gl.getUniformLocation(this.program, \"pad\");\n\n\t// bind length of shared dimension\n\tgl.uniform1i(N_gl, N);\n\tgl.uniform1i(pad_gl, pad);\n\tgl.uniform1f(a_gl, a);\n\tgl.uniform1f(b_gl, b);\n\n};\n","var WebGL = require('./webgl');\n\n/* A calculator object for the Float texture based GEMM\n\n\tGeneralized Matrix Multiply (GEMM):\n\n\tC = alpha * A * B + beta * C\n\n\twhere A * B is matrix multiplication\n\n\n\twebgl - a weblas.WebGL object\n\tstandalone - whether or not to automatically run the floating point encode\n\t\tstep for rendering to an UNSIGNED_BYTE texture (this is required for\n\t\tmobile, circa 2015) but can't be used as part of a pipeline.\n\n\t* uploads and downloads data\n\t* executes calculation\n */\nfunction SGEMMCalculator(webgl, standalone){\n\tthis.webgl = webgl,\n\tthis.standalone = (standalone != null) ? standalone : true; // default to standalone mode\n\n\t// read GLSL files\n\tvar s = \"// fragment shader that calculates the matrix product and renders each\\n// element to the bytes representing a 32-bit IEEE754 floating point in\\n// the output RGBA canvas.\\n// readPixel is used to read the bytes.\\n\\nprecision highp float;\\n#define GLSLIFY 1\\n\\nvarying vec2      outTex;\\t// texture coords of row/column to calculate\\nuniform sampler2D A;\\t\\t// texture with data from padded A\\nuniform sampler2D B_t;\\t\\t// texture with data from padded transpose of B\\nuniform int       K;\\t\\t// number of elements in shared dimension\\nuniform int       N;\\t\\t// number of columns in output\\nuniform int       pad;\\t\\t//\\nuniform float     alpha; \\t// coefficient to multiplication\\n\\n// sum of products between elements in row i (from A) x col j (from B)\\n\\n// Calculate the dot product between the row (from A) and column (from B)\\n// identified by the passed indeces (output texture coordinate space).\\n// We loop over elements in the row and column and sum the product\\n// using the glsl `dot` function to process four elements at a time.\\n// This four element optimization requires that the matrix B be\\n// transposed before texel packing and that both matrices be padded\\n// (with zeros) to a multiple of four (4) in their shared dimension.\\nfloat dot_rowcol_1540259130(float y, float x, sampler2D A, sampler2D B_t, int K) {\\n\\tfloat delta_t = 1./float(K);// space (on texture) between elements\\n\\tfloat sum = 0.;\\t\\t\\t// sum for this row/column pair\\n\\tfloat z = 0.5 * (4.0 * delta_t);// position for shared dimension on source textures\\n\\n\\tfor (int l=0 ; l<4096 ; ++l) {\\n\\t\\tif(l >= K / 4) break;    // stop when we finish the row/column\\n\\t\\t// l is in pixel space, so we divide by four\\n\\n\\t\\t// retrieve next four elements from each texture\\n\\t\\tvec4 a_ik = texture2D(  A, vec2(z, y));\\n\\t\\tvec4 b_kj = texture2D(B_t, vec2(z, x));\\n\\n\\t// use `dot` to process four elements at a time\\n\\t\\tsum +=  dot(a_ik, b_kj);\\n\\t\\tz += (4.0 * delta_t);      // (z + 0.5)*delta\\n\\t}\\n\\treturn sum;\\n}\\n\\n// Render float to bytes according to IEEE 754 Floating Point\\nvec4 encode_float_1604150559(float val) {\\n\\n\\t// TODO: correctly handle denormal numbers\\n\\t// http://www.2ality.com/2012/04/number-encoding.html\\n\\tfloat a = abs(val);                           // encode absolute value + sign\\n\\tfloat exp = floor(log2(a));                 // number of powers of 2\\n\\tfloat mant = pow(2.,log2(a)-exp) * pow(2.,23.);  // multiply to fill 24 bits (implied leading 1)\\n\\tfloat mant1 = floor(mant / 256. / 256.);    // first 8 bits of mantissa\\n\\tfloat mant2 = mod(floor(mant / 256.),256.); // second 8 bits\\n\\tfloat mant3 = mod(mant,256.);               // third 8 bits\\n\\n\\thighp float sign = 128.-128.*(a/val);\\t\\t\\t// sign bit is 256 or 0\\n\\thighp float e = (sign+exp+127.)/510.;\\t\\t// exponent and sign\\n\\thighp float m1 = (mant1-(128.*(1.-mod(exp+127.,2.))))/255.; // handle leading bit\\n\\thighp float m2 = (mant2)/255.;\\t\\t\\t\\t// middle part\\n\\thighp float m3 = (mant3+.5)/255.;\\t\\t\\t// scale to 0 - 255\\n\\n\\treturn vec4(m3,m2,m1,e);\\n}\\n\\nvoid main(void) {\\n\\n\\t// get the implied row and column from .y and .x of passed (output)\\n\\t// texture coordinate. These map directly to input texture space when\\n\\t// the relevant dimensions are the same.\\n\\tfloat row_t = outTex.y;\\n\\tfloat col_t = outTex.x;\\n\\n\\t// sum row x col for the passed pixel\\n\\tfloat sum = alpha * dot_rowcol_1540259130(row_t, col_t * float(N + pad)/float(N), A, B_t, K);\\n\\n\\tif (sum == 0.) {\\n\\t\\tgl_FragColor = vec4(0.,0.,0.,0.);\\n\\t\\treturn;\\n\\t}\\n\\n\\t// output vec4 with bytes for an IEEE754 32-bit floating point number\\n\\tgl_FragColor = encode_float_1604150559(sum);\\n}\\n\",\n\t\ts_c = \"// fragment shader that calculates the matrix product (with additive 'C' term)\\n// and renders each element to the bytes representing a 32-bit IEEE754 floating\\n// point in the output RGBA canvas.\\n// readPixel is used to read the bytes.\\n\\nprecision highp float;\\n#define GLSLIFY 1\\n\\nvarying vec2      outTex;\\t// texture coords of row/column to calculate\\nuniform sampler2D A;\\t\\t// texture with data from padded A\\nuniform sampler2D B_t;\\t\\t// texture with data from padded transpose of B\\nuniform sampler2D C;\\t\\t// texture with data from C\\nuniform int       K;\\t\\t// number of elements in shared dimension\\nuniform int       N;\\t\\t// number of columns in output\\nuniform int       pad;\\t\\t//\\nuniform float     alpha; \\t// coefficient to multiplication\\nuniform float     beta; \\t// coefficient to additive term\\n\\n// sum of products between elements in row i (from A) x col j (from B)\\n\\n// Calculate the dot product between the row (from A) and column (from B)\\n// identified by the passed indeces (output texture coordinate space).\\n// We loop over elements in the row and column and sum the product\\n// using the glsl `dot` function to process four elements at a time.\\n// This four element optimization requires that the matrix B be\\n// transposed before texel packing and that both matrices be padded\\n// (with zeros) to a multiple of four (4) in their shared dimension.\\nfloat dot_rowcol_1540259130(float y, float x, sampler2D A, sampler2D B_t, int K) {\\n\\tfloat delta_t = 1./float(K);// space (on texture) between elements\\n\\tfloat sum = 0.;\\t\\t\\t// sum for this row/column pair\\n\\tfloat z = 0.5 * (4.0 * delta_t);// position for shared dimension on source textures\\n\\n\\tfor (int l=0 ; l<4096 ; ++l) {\\n\\t\\tif(l >= K / 4) break;    // stop when we finish the row/column\\n\\t\\t// l is in pixel space, so we divide by four\\n\\n\\t\\t// retrieve next four elements from each texture\\n\\t\\tvec4 a_ik = texture2D(  A, vec2(z, y));\\n\\t\\tvec4 b_kj = texture2D(B_t, vec2(z, x));\\n\\n\\t// use `dot` to process four elements at a time\\n\\t\\tsum +=  dot(a_ik, b_kj);\\n\\t\\tz += (4.0 * delta_t);      // (z + 0.5)*delta\\n\\t}\\n\\treturn sum;\\n}\\n\\n// Render float to bytes according to IEEE 754 Floating Point\\nvec4 encode_float_1117569599(float val) {\\n\\n\\t// TODO: correctly handle denormal numbers\\n\\t// http://www.2ality.com/2012/04/number-encoding.html\\n\\tfloat a = abs(val);                           // encode absolute value + sign\\n\\tfloat exp = floor(log2(a));                 // number of powers of 2\\n\\tfloat mant = pow(2.,log2(a)-exp) * pow(2.,23.);  // multiply to fill 24 bits (implied leading 1)\\n\\tfloat mant1 = floor(mant / 256. / 256.);    // first 8 bits of mantissa\\n\\tfloat mant2 = mod(floor(mant / 256.),256.); // second 8 bits\\n\\tfloat mant3 = mod(mant,256.);               // third 8 bits\\n\\n\\thighp float sign = 128.-128.*(a/val);\\t\\t\\t// sign bit is 256 or 0\\n\\thighp float e = (sign+exp+127.)/510.;\\t\\t// exponent and sign\\n\\thighp float m1 = (mant1-(128.*(1.-mod(exp+127.,2.))))/255.; // handle leading bit\\n\\thighp float m2 = (mant2)/255.;\\t\\t\\t\\t// middle part\\n\\thighp float m3 = (mant3+.5)/255.;\\t\\t\\t// scale to 0 - 255\\n\\n\\treturn vec4(m3,m2,m1,e);\\n}\\n\\n// select an element from a vector based on index\\nfloat select_index_1604150559(vec4 v, int index){\\n\\tfloat val;\\n\\tif (index == 0) {\\n\\t\\tval = v.r;\\n\\t} else if(index == 1) {\\n\\t\\tval = v.g;\\n\\t} else if(index == 2) {\\n\\t\\tval = v.b;\\n\\t} else if(index == 3){\\n\\t\\tval = v.a;\\n\\t} else {\\n\\t\\t// should never be here\\n\\t\\tval = 0.0;\\n\\t}\\n\\n\\treturn val;\\n}\\n\\nvoid main(void) {\\n\\n\\t// get the implied row and column from .y and .x of passed (output)\\n\\t// texture coordinate. These map directly to input texture space when\\n\\t// the relevant dimensions are the same.\\n\\tfloat row_t = outTex.y;\\n\\tfloat col_t = outTex.x;\\n\\tvec4 c_vec = texture2D(C, vec2(col_t, 0.5));\\n\\n\\t// should be -0.5, but that subtly breaks at zero\\n\\tfloat col = col_t * float(N + pad); // index of first element in pixel (matrix space)\\n\\tint channel = int(mod(col, 4.0 ));\\n\\tfloat c = select_index_1604150559(c_vec, channel);\\n\\n\\t// sum row x col for the passed pixel\\n\\tfloat sum = alpha * dot_rowcol_1540259130(row_t, col_t * float(N + pad)/float(N), A, B_t, K);\\n\\tsum += beta * c;\\n\\n\\tif (sum == 0.) {\\n\\t\\tgl_FragColor = vec4(0.,0.,0.,0.);\\n\\t\\treturn;\\n\\t}\\n\\n\\t// output vec4 with bytes for an IEEE754 32-bit floating point number\\n\\tgl_FragColor = encode_float_1117569599(sum);\\n}\\n\",\n\t\tp = \"// fragment shader that calculates the matrix product and writes each\\n// element to a pixel component in a floating point texture.\\n// the output RGBA canvas.\\n// readPixel is used to read the bytes.\\n\\nprecision highp float;\\n#define GLSLIFY 1\\n\\nvarying vec2      outTex;\\t// texture coords of row/column to calculate\\nuniform sampler2D A;\\t\\t// texture with data from padded A\\nuniform sampler2D B_t;\\t\\t// texture with data from padded transpose of B\\nuniform int       K;\\t\\t// number of elements in shared dimension\\nuniform int       N;\\t\\t// number of columns in output\\nuniform int       pad;\\t\\t//\\nuniform float     alpha; \\t// coefficient to multiplication\\n\\n// sum of products between elements in row i (from A) x col j (from B)\\n\\n// Calculate the dot product between the row (from A) and column (from B)\\n// identified by the passed indeces (output texture coordinate space).\\n// We loop over elements in the row and column and sum the product\\n// using the glsl `dot` function to process four elements at a time.\\n// This four element optimization requires that the matrix B be\\n// transposed before texel packing and that both matrices be padded\\n// (with zeros) to a multiple of four (4) in their shared dimension.\\nfloat dot_rowcol_1540259130(float y, float x, sampler2D A, sampler2D B_t, int K) {\\n\\tfloat delta_t = 1./float(K);// space (on texture) between elements\\n\\tfloat sum = 0.;\\t\\t\\t// sum for this row/column pair\\n\\tfloat z = 0.5 * (4.0 * delta_t);// position for shared dimension on source textures\\n\\n\\tfor (int l=0 ; l<4096 ; ++l) {\\n\\t\\tif(l >= K / 4) break;    // stop when we finish the row/column\\n\\t\\t// l is in pixel space, so we divide by four\\n\\n\\t\\t// retrieve next four elements from each texture\\n\\t\\tvec4 a_ik = texture2D(  A, vec2(z, y));\\n\\t\\tvec4 b_kj = texture2D(B_t, vec2(z, x));\\n\\n\\t// use `dot` to process four elements at a time\\n\\t\\tsum +=  dot(a_ik, b_kj);\\n\\t\\tz += (4.0 * delta_t);      // (z + 0.5)*delta\\n\\t}\\n\\treturn sum;\\n}\\n\\nvoid main(void) {\\n\\n\\t// get the implied row and column from .y and .x of passed (output)\\n\\t// texture coordinate. These map directly to input texture space when\\n\\t// the relevant dimensions are the same.\\n\\tfloat row_t = outTex.y;\\n\\tfloat col_t = outTex.x;\\n\\n\\tvec4 sum_v = vec4(0.0, 0.0, 0.0, 0.0);\\n\\tfloat col = (col_t * float(N + pad) - 2.0); // index of first element in pixel (matrix space)\\n\\tsum_v.r = alpha * dot_rowcol_1540259130(row_t, (col + 0.5)/float(N), A, B_t, K);\\n\\t// is last element in pixel past row length?\\n\\tif(pad > 0 && (col + 4.0) > float(N) ) {\\n\\t\\t// compute elements in padded region\\n\\t\\tif(pad < 3){\\n\\t\\t\\tsum_v.g = alpha * dot_rowcol_1540259130(row_t, (col + 1.5)/float(N), A, B_t, K);\\n\\t\\t}\\n\\t\\tif(pad < 2){\\n\\t\\t\\tsum_v.b = alpha * dot_rowcol_1540259130(row_t, (col + 2.5)/float(N), A, B_t, K);\\n\\t\\t}\\n\\t} else {\\n\\t\\tsum_v.g = alpha * dot_rowcol_1540259130(row_t, (col + 1.5)/float(N), A, B_t, K);\\n\\t\\tsum_v.b = alpha * dot_rowcol_1540259130(row_t, (col + 2.5)/float(N), A, B_t, K);\\n\\t\\tsum_v.a = alpha * dot_rowcol_1540259130(row_t, (col + 3.5)/float(N), A, B_t, K);\\n\\t}\\n\\n\\tgl_FragColor = sum_v;\\n}\\n\",\n\t\tp_c = \"// fragment shader that calculates the matrix product and writes each\\n// element to a pixel component in a floating point texture.\\n// the output RGBA canvas.\\n// readPixel is used to read the bytes.\\n\\nprecision highp float;\\n#define GLSLIFY 1\\n\\nvarying vec2      outTex;\\t// texture coords of row/column to calculate\\nuniform sampler2D A;\\t\\t// texture with data from padded A\\nuniform sampler2D B_t;\\t\\t// texture with data from padded transpose of B\\nuniform sampler2D C;\\t\\t// texture with data from C\\nuniform int       K;\\t\\t// number of elements in shared dimension\\nuniform int       N;\\t\\t// number of columns in output\\nuniform int       pad;\\t\\t//\\nuniform float     alpha; \\t// coefficient to multiplication\\nuniform float     beta; \\t// coefficient to addition\\n\\n// sum of products between elements in row i (from A) x col j (from B)\\n\\n// Calculate the dot product between the row (from A) and column (from B)\\n// identified by the passed indeces (output texture coordinate space).\\n// We loop over elements in the row and column and sum the product\\n// using the glsl `dot` function to process four elements at a time.\\n// This four element optimization requires that the matrix B be\\n// transposed before texel packing and that both matrices be padded\\n// (with zeros) to a multiple of four (4) in their shared dimension.\\nfloat dot_rowcol_1540259130(float y, float x, sampler2D A, sampler2D B_t, int K) {\\n\\tfloat delta_t = 1./float(K);// space (on texture) between elements\\n\\tfloat sum = 0.;\\t\\t\\t// sum for this row/column pair\\n\\tfloat z = 0.5 * (4.0 * delta_t);// position for shared dimension on source textures\\n\\n\\tfor (int l=0 ; l<4096 ; ++l) {\\n\\t\\tif(l >= K / 4) break;    // stop when we finish the row/column\\n\\t\\t// l is in pixel space, so we divide by four\\n\\n\\t\\t// retrieve next four elements from each texture\\n\\t\\tvec4 a_ik = texture2D(  A, vec2(z, y));\\n\\t\\tvec4 b_kj = texture2D(B_t, vec2(z, x));\\n\\n\\t// use `dot` to process four elements at a time\\n\\t\\tsum +=  dot(a_ik, b_kj);\\n\\t\\tz += (4.0 * delta_t);      // (z + 0.5)*delta\\n\\t}\\n\\treturn sum;\\n}\\n\\nvoid main(void) {\\n\\n\\t// get the implied row and column from .y and .x of passed (output)\\n\\t// texture coordinate. These map directly to input texture space when\\n\\t// the relevant dimensions are the same.\\n\\tfloat row_t = outTex.y;\\n\\tfloat col_t = outTex.x;\\n\\tvec4 c_v = texture2D(C, vec2(col_t, 0.5));\\n\\n\\tvec4 sum_v = vec4(0.0, 0.0, 0.0, 0.0);\\n\\tfloat col = (col_t * float(N + pad) - 2.0); // index of first element in pixel (matrix space)\\n\\tsum_v.r = alpha * dot_rowcol_1540259130(row_t, (col + 0.5)/float(N), A, B_t, K);\\n\\t// in the padding region?\\n\\tif(pad > 0 && (col + 4.0) > float(N) ) {\\n\\t\\t// pad\\n\\t\\tif(pad < 3){\\n\\t\\t\\tsum_v.g = alpha * dot_rowcol_1540259130(row_t, (col + 1.5)/float(N), A, B_t, K);\\n\\t\\t}\\n\\t\\tif(pad < 2){\\n\\t\\t\\tsum_v.b = alpha * dot_rowcol_1540259130(row_t, (col + 2.5)/float(N), A, B_t, K);\\n\\t\\t}\\n\\t} else {\\n\\t\\tsum_v.g = alpha * dot_rowcol_1540259130(row_t, (col + 1.5)/float(N), A, B_t, K);\\n\\t\\tsum_v.b = alpha * dot_rowcol_1540259130(row_t, (col + 2.5)/float(N), A, B_t, K);\\n\\t\\tsum_v.a = alpha * dot_rowcol_1540259130(row_t, (col + 3.5)/float(N), A, B_t, K);\\n\\t}\\n\\n\\tgl_FragColor = sum_v + beta*c_v;\\n}\\n\";\n\n\t// create the webgl shader program for this calculation\n\t// based on the specific fragment shader for this calculation\n\t// and the generic pass through shader\n\tif(this.standalone){\n\t\tthis.program_ = this.webgl.createProgram(s);\n\t\tthis.program_c = this.webgl.createProgram(s_c);\n\t} else {\n\t\tthis.program_ = this.webgl.createProgram(p);\n\t\tthis.program_c = this.webgl.createProgram(p_c);\n\t}\n\n}\n\nmodule.exports = SGEMMCalculator;\n\n/* Names of the uniforms (variables) used in the shader program passed in on\n   each calculation.\n */\nSGEMMCalculator.TEXTURE_UNIFORM_NAME_0 = \"A\";\nSGEMMCalculator.TEXTURE_UNIFORM_NAME_1 = \"B_t\";\nSGEMMCalculator.TEXTURE_UNIFORM_NAME_2 = \"C\";\nSGEMMCalculator.SHARED_LENGTH_UNIFORM_NAME = \"K\";\nSGEMMCalculator.COLUMN_COUNT_UNIFORM_NAME = \"N\";\nSGEMMCalculator.PAD_UNIFORM_NAME = \"pad\";\nSGEMMCalculator.ALPHA_UNIFORM_NAME = \"alpha\";\nSGEMMCalculator.BETA_UNIFORM_NAME = \"beta\";\n\n/* Calculate the GEMM, with the given data.\n\n\tM - number of rows in A\n\tN - number of columns in B\n\tK - number of elements in shared dimension (including padding)\n\talpha - scalar for A\n\tA - left hand matrix (as padded texture)\n\tB - transpose of right hand matrix (as padded texture)\n\tbeta - scalar for C\n\tC - additive matrix (texture)\n\tout - output (texture)\n\n  How this works:\n\n  1. Activate our shader program\n  2. Bind input textures\n  3. Set shader program parameters\n  4. Bind output texture\n  5. Activate calculation with `drawElements`\n\n TODO: signature should look like this:\n ( TRANSA, TRANSB, M, N, K, ALPHA, A, LDA, B, LDB, BETA, C, LDC )\n http://www.math.utah.edu/software/lapack/lapack-blas/dgemm.html\n */\nSGEMMCalculator.prototype.calculate = function(M, N, K, alpha, A, B, beta, C, out){\n\n\tvar gl = this.webgl.context;\n\n\t/*\n\tvar h1 = M, w1 = K,\n\t\th2 = K, w2 = N;\n\t*/\n\n\t// set this calculator program as the active program\n\tif(C != null){\n\t\tthis.program = this.program_c;\n\t} else {\n\t\tbeta = null;\n\t\tthis.program = this.program_;\n\t\t//console.log(\"no C\");\n\t}\n\tthis.webgl.selectProgram(this.program);\n\n\t//  bind our input textures containing matrix data\n\tthis.bindInputTexture(A, gl.TEXTURE0, SGEMMCalculator.TEXTURE_UNIFORM_NAME_0);\n\tthis.bindInputTexture(B, gl.TEXTURE1, SGEMMCalculator.TEXTURE_UNIFORM_NAME_1);\n\tif(C != null){\n\t\tthis.bindInputTexture(C, gl.TEXTURE2, SGEMMCalculator.TEXTURE_UNIFORM_NAME_2);\n\t}\n\n\tvar kPad = this.webgl.getPad(K),\n\t\tnPad = this.webgl.getPad(N);\n\n\t// set the data specific variables in our shader program\n\tthis.bindUniforms(N, K + kPad, nPad, alpha, beta);\n\n\t// create our destination texture\n\tif(this.standalone){\n\t\tthis.webgl.bindOutputTexture(M, N + nPad, out);\n\t} else {\n\t\tthis.webgl.bindOutputTexture(M, (N + nPad)/ 4, out);\n\t}\n\n\t// initiate calculation\n\tgl.drawElements(gl.TRIANGLES, /*num items*/6, gl.UNSIGNED_SHORT, 0);\n\n\tthis.webgl.unbindInputTexture(gl.TEXTURE0);\n\tthis.webgl.unbindInputTexture(gl.TEXTURE1);\n\tthis.webgl.unbindInputTexture(gl.TEXTURE2);\n\n\t// result can now be read with gl.readResult, or more operations can be\n\t// performed on destination texture (in pipeline mode)\n};\n\n\n/* Create a texture from the given texel data and bind it to our shader program.\n\n\th - number of rows in input matrix\n\tw - number of cols in input matrix\n\ttexels - packed data\n\ttextureUnit - the texture unit to bind to (gl.TEXTURE0, gl.TEXTURE1, etc)\n\tname - the uniform name to associate with (must match shader program)\n\n\tmust compile program (with createProgram) first\n*/\nSGEMMCalculator.prototype.bindInputTexture = function(texture, textureUnit, name){\n\tvar gl = this.webgl.context,\n\t\tprogram = this.program;\n\n\tgl.activeTexture(textureUnit); // gl.TEXTURE0, gl.TEXTURE1, etc\n\tgl.bindTexture(\t  gl.TEXTURE_2D, texture);\n\n\tvar sampler = gl.getUniformLocation(program, name);\n\tgl.uniform1i(sampler, textureUnit - gl.TEXTURE0);\n\n};\n\n\n/* Set up inputs for the texture shader\n\n\tK - size of shared dimension for multiplied matrices\n */\nSGEMMCalculator.prototype.bindUniforms = function(N, K, pad, alpha, beta) {\n\tvar gl = this.webgl.context;\n\n\t// get var locations\n\tvar K_gl\t = gl.getUniformLocation(this.program, SGEMMCalculator.SHARED_LENGTH_UNIFORM_NAME),\n\t\talpha_gl = gl.getUniformLocation(this.program, SGEMMCalculator.ALPHA_UNIFORM_NAME),\n\t\tbeta_gl = gl.getUniformLocation(this.program, SGEMMCalculator.BETA_UNIFORM_NAME),\n\t\tN_gl = gl.getUniformLocation(this.program, SGEMMCalculator.COLUMN_COUNT_UNIFORM_NAME),\n\t\tpad_gl = pad_gl = gl.getUniformLocation(this.program, SGEMMCalculator.PAD_UNIFORM_NAME);\n\n\tgl.uniform1f(beta_gl, beta);\n\tgl.uniform1i(N_gl, N);\n\tgl.uniform1i(pad_gl, pad);\n\n\t// bind length of shared dimension\n\tgl.uniform1i(K_gl, K);\n\t// bind alpha\n\tgl.uniform1f(alpha_gl, alpha);\n\n};\n","var WebGL = require('./webgl');\n\n/* A calculator object for the Float texture based AXPY\n\n\ta times X plus Y (AXPY):\n\n\tY = a * X + Y\n\n\twhere X + Y is elementwise matrix addition\n\n\n\twebgl - a weblas.WebGL object\n\tstandalone - whether or not to automatically run the floating point encode\n\t\tstep for rendering to an UNSIGNED_BYTE texture (this is required for\n\t\tmobile, circa 2015) but can't be used as part of a pipeline.\n\n\t* uploads and downloads data\n\t* executes calculation\n */\nfunction SAXPYCalculator(webgl, standalone){\n\tthis.webgl = webgl,\n\tthis.standalone = standalone || true; // default to standalone mode\n\n\n\tvar s = \"precision highp float;\\n#define GLSLIFY 1\\n\\nvarying vec2      outTex;\\t// texture coords of row/column to calculate\\nuniform sampler2D X;\\t\\t// texture with data from padded A\\nuniform sampler2D Y;\\t\\t// texture with data from padded transpose of B\\nuniform int       N;\\nuniform float     a; \\t\\t// coefficient to multiplication\\n\\n// Render float to bytes according to IEEE 754 Floating Point\\nvec4 encode_float_1540259130(float val) {\\n\\n\\t// TODO: correctly handle denormal numbers\\n\\t// http://www.2ality.com/2012/04/number-encoding.html\\n\\tfloat a = abs(val);                           // encode absolute value + sign\\n\\tfloat exp = floor(log2(a));                 // number of powers of 2\\n\\tfloat mant = pow(2.,log2(a)-exp) * pow(2.,23.);  // multiply to fill 24 bits (implied leading 1)\\n\\tfloat mant1 = floor(mant / 256. / 256.);    // first 8 bits of mantissa\\n\\tfloat mant2 = mod(floor(mant / 256.),256.); // second 8 bits\\n\\tfloat mant3 = mod(mant,256.);               // third 8 bits\\n\\n\\thighp float sign = 128.-128.*(a/val);\\t\\t\\t// sign bit is 256 or 0\\n\\thighp float e = (sign+exp+127.)/510.;\\t\\t// exponent and sign\\n\\thighp float m1 = (mant1-(128.*(1.-mod(exp+127.,2.))))/255.; // handle leading bit\\n\\thighp float m2 = (mant2)/255.;\\t\\t\\t\\t// middle part\\n\\thighp float m3 = (mant3+.5)/255.;\\t\\t\\t// scale to 0 - 255\\n\\n\\treturn vec4(m3,m2,m1,e);\\n}\\n\\n// select an element from a vector based on index\\nfloat select_index_1604150559(vec4 v, int index){\\n\\tfloat val;\\n\\tif (index == 0) {\\n\\t\\tval = v.r;\\n\\t} else if(index == 1) {\\n\\t\\tval = v.g;\\n\\t} else if(index == 2) {\\n\\t\\tval = v.b;\\n\\t} else if(index == 3){\\n\\t\\tval = v.a;\\n\\t} else {\\n\\t\\t// should never be here\\n\\t\\tval = 0.0;\\n\\t}\\n\\n\\treturn val;\\n}\\n\\nvoid main(void) {\\n\\n\\t// get the implied row and column from .y and .x of passed (output)\\n\\t// texture coordinate. These map directly to input texture space when\\n\\t// the relevant dimensions are the same.\\n \\tfloat row = outTex.y;\\n\\tfloat col = outTex.x;\\n\\n\\t// direct usage of col requires output be padded exactly like input\\n\\tvec4 x = texture2D( X, vec2(col, row));\\n\\tvec4 y = texture2D( Y, vec2(col, row));\\n\\tvec4 sum_v = (a * x) + y;\\n\\tint channel = int(mod(col * float(N), 4.0 ));\\n\\tfloat sum = select_index_1604150559(sum_v, channel);\\n\\n\\tif (sum == 0.) {\\n\\t\\tgl_FragColor = vec4(0.,0.,0.,0.);\\n\\t\\treturn;\\n\\t}\\n\\n \\t// output vec4 with bytes for an IEEE754 32-bit floating point number\\n\\tgl_FragColor = encode_float_1540259130(sum);\\n}\\n\";\n\t//\tp = glslify('./glsl/saxpy/pipeline.glsl');\n\n\t// create the webgl shader program for this calculation\n\t// based on the specific fragment shader for this calculation\n\t// and the generic pass through shader\n\tif(this.standalone){\n\t\tthis.program = this.webgl.createProgram(s);\n\t} else {\n\t\tthis.program = this.webgl.createProgram(p);\n\t}\n}\n\nmodule.exports = SAXPYCalculator;\n\n/* Names of the uniforms (variables) used in the shader program passed in on\n   each calculation.\n */\nSAXPYCalculator.TEXTURE_UNIFORM_NAME_0 = \"X\";\nSAXPYCalculator.TEXTURE_UNIFORM_NAME_1 = \"Y\";\nSAXPYCalculator.LENGTH_UNIFORM_NAME = \"N\";\nSAXPYCalculator.COEFFICIENT_UNIFORM_NAME = \"a\";\n\n\n/* Calculate the AXPY, with the given data.\n\n\tN - number of elements in X and Y\n\ta - scalar coefficient to X\n\tX - left hand vector (texture)\n\tY - right hand vector (texture)\n\tout - output (texture)\n\n  How this works:\n\n  1. Activate our shader program\n  2. Bind input textures\n  3. Set shader program parameters\n  4. Bind output texture\n  5. Activate calculation with `drawElements`\n\n */\nSAXPYCalculator.prototype.calculate = function(N, a, X, Y, out){\n\n\tvar gl = this.webgl.context;\n\n\t/*\n\tvar h1 = M, w1 = K,\n\t\th2 = K, w2 = N;\n\t*/\n\n\tthis.webgl.selectProgram(this.program);\n\n\t// create and bind our input texture using matrix data\n\tthis.bindInputTexture(X, gl.TEXTURE0, SAXPYCalculator.TEXTURE_UNIFORM_NAME_0);\n\tthis.bindInputTexture(Y, gl.TEXTURE1, SAXPYCalculator.TEXTURE_UNIFORM_NAME_1);\n\n\n\tvar pad = this.webgl.getPad(N);\n\t// set the data specific variables in our shader program\n\tthis.bindUniforms(N + pad, a);\n\n\t// create our destination texture\n\tthis.webgl.bindOutputTexture(1, N + pad, out);\n\n\n\t// initiate calculation\n\tgl.drawElements(gl.TRIANGLES, /*num items*/6, gl.UNSIGNED_SHORT, 0);\n\n\tthis.webgl.unbindInputTexture(gl.TEXTURE0);\n\tthis.webgl.unbindInputTexture(gl.TEXTURE1);\n\n};\n\n/* Create a texture from the given texel data and bind it to our shader program.\n\n\th - number of rows in input matrix\n\tw - number of cols in input matrix\n\ttexels - packed data\n\ttextureUnit - the texture unit to bind to (gl.TEXTURE0, gl.TEXTURE1, etc)\n\tname - the uniform name to associate with (must match shader program)\n\n\tmust compile program (with createProgram) first\n*/\nSAXPYCalculator.prototype.bindInputTexture = function(texture, textureUnit, name){\n\tvar gl = this.webgl.context,\n\t\tprogram = this.program;\n\n\tgl.activeTexture(textureUnit); // gl.TEXTURE0, gl.TEXTURE1, etc\n\tgl.bindTexture(\t  gl.TEXTURE_2D, texture);\n\n\tvar sampler = gl.getUniformLocation(program, name);\n\tgl.uniform1i(sampler, textureUnit - gl.TEXTURE0);\n\n};\n\n/* Set up inputs for the texture shader\n\n */\nSAXPYCalculator.prototype.bindUniforms = function(N, a) {\n\tvar gl = this.webgl.context;\n\n\t// get var locations\n\tvar N_gl = gl.getUniformLocation(this.program, SAXPYCalculator.LENGTH_UNIFORM_NAME),\n\t\ta_gl = gl.getUniformLocation(this.program, SAXPYCalculator.COEFFICIENT_UNIFORM_NAME);\n\n\t// bind length of shared dimension\n\tgl.uniform1i(N_gl, N);\n\tgl.uniform1f(a_gl, a);\n\n};\n","var WebGL = require('./webgl');\n\n/*  Downsample an image (useful in pooling layers).\n\n\n\n\twebgl - a weblas.WebGL object\n\tstandalone - whether or not to automatically run the floating point encode\n\t\tstep for rendering to an UNSIGNED_BYTE texture (this is required for\n\t\tmobile, circa 2015) but can't be used as part of a pipeline.\n\n\t* uploads and downloads data\n\t* executes calculation\n */\nfunction DownsampleCalculator(webgl, standalone){\n\tthis.webgl = webgl,\n\tthis.standalone = (standalone != null) ? standalone : true; // default to standalone mode\n\n\tvar s = \"// TODO: unroll loop for stride == factor and small values (2, 3)\\nprecision highp float;\\n#define GLSLIFY 1\\n\\nvarying vec2      outTex;  // texture coords of row/column to calculate\\nuniform sampler2D X;       // texture with data from padded A\\nuniform int       factor;  // width of image patch\\nuniform float     stride;  // width between image patches\\nuniform float     C;       // number of channels\\nuniform float     M;\\nuniform float     N;\\nuniform float     N_out;\\nuniform float     M_out;\\n\\n// Render float to bytes according to IEEE 754 Floating Point\\nvec4 encode_float_1540259130(float val) {\\n\\n\\t// TODO: correctly handle denormal numbers\\n\\t// http://www.2ality.com/2012/04/number-encoding.html\\n\\tfloat a = abs(val);                           // encode absolute value + sign\\n\\tfloat exp = floor(log2(a));                 // number of powers of 2\\n\\tfloat mant = pow(2.,log2(a)-exp) * pow(2.,23.);  // multiply to fill 24 bits (implied leading 1)\\n\\tfloat mant1 = floor(mant / 256. / 256.);    // first 8 bits of mantissa\\n\\tfloat mant2 = mod(floor(mant / 256.),256.); // second 8 bits\\n\\tfloat mant3 = mod(mant,256.);               // third 8 bits\\n\\n\\thighp float sign = 128.-128.*(a/val);\\t\\t\\t// sign bit is 256 or 0\\n\\thighp float e = (sign+exp+127.)/510.;\\t\\t// exponent and sign\\n\\thighp float m1 = (mant1-(128.*(1.-mod(exp+127.,2.))))/255.; // handle leading bit\\n\\thighp float m2 = (mant2)/255.;\\t\\t\\t\\t// middle part\\n\\thighp float m3 = (mant3+.5)/255.;\\t\\t\\t// scale to 0 - 255\\n\\n\\treturn vec4(m3,m2,m1,e);\\n}\\n\\n// select an element from a vector based on index\\nfloat select_index_1604150559(vec4 v, int index){\\n\\tfloat val;\\n\\tif (index == 0) {\\n\\t\\tval = v.r;\\n\\t} else if(index == 1) {\\n\\t\\tval = v.g;\\n\\t} else if(index == 2) {\\n\\t\\tval = v.b;\\n\\t} else if(index == 3){\\n\\t\\tval = v.a;\\n\\t} else {\\n\\t\\t// should never be here\\n\\t\\tval = 0.0;\\n\\t}\\n\\n\\treturn val;\\n}\\n\\nvoid main(void) {\\n\\n\\t// get the implied row and column from .y and .x of passed (output)\\n\\t// texture coordinate and translate to output pixel space.\\n\\tfloat row = floor(outTex.y * M_out);   // row on output texture (matrix space)\\n\\tfloat col = floor(outTex.x * N_out); // column on output texture (matrix space)\\n\\tfloat vcol = floor(col / C);   // virtual column on output texture (matrix space)\\n\\tfloat vchannel = floor(mod(col, C)); // virtual channel on output texture\\n\\n\\tconst float min = -1.0e+08;\\n\\tvec4 currentMax = vec4(min, min, min, min);\\n\\n\\tfloat deltaY = 1.0/M;\\n\\tfloat deltaX = 1.0/N;\\n\\tfloat y = ((row * stride) + 0.5)*deltaY; // texture position of input row\\n\\tfloat x;\\n\\tfloat z = vchannel * deltaX;\\n\\tfor (int i = 0; i < 100; i += 1) {\\n\\t\\tif (i >= factor) {\\n\\t\\t\\tbreak;\\n\\t\\t}\\n\\t\\tx = ((vcol * stride * C) + 0.5) * deltaX; // texture position of input column\\n\\n\\t\\tfor (int j = 0; j < 100; j += 1) {\\n\\t\\t\\tif (j >= factor) {\\n\\t\\t\\t\\tbreak;\\n\\t\\t\\t}\\n\\n\\t\\t\\tvec2 coords = vec2(x + z, y);\\n\\t\\t\\tvec4 x_v = texture2D(X, coords);\\n\\t\\t\\tcurrentMax = max(currentMax, x_v);\\n\\n\\t\\t\\tx += (deltaX * C);\\n\\t\\t}\\n\\t\\ty += deltaY;\\n\\t}\\n\\tint chan = int(mod(outTex.x * N_out, 4.0 ));\\n\\tfloat val = select_index_1604150559(currentMax, int(chan));\\n\\tif (val == 0.) {\\n\\t\\tgl_FragColor = vec4(0.,0.,0.,0.);\\n\\t\\treturn;\\n\\t}\\n\\n\\tgl_FragColor = encode_float_1540259130(val);\\n}\\n\";\n\t\tp = \"// TODO: unroll loop for stride == factor and small values (2, 3)\\nprecision highp float;\\n#define GLSLIFY 1\\n\\nvarying vec2      outTex;  // texture coords of row/column to calculate\\nuniform sampler2D X;       // texture with data from padded A\\nuniform int       factor;  // width of image patch\\nuniform float     stride;  // width between image patches\\nuniform float     C;       // number of channels\\nuniform float     M;\\nuniform float     N;\\nuniform float     N_out;\\nuniform float     M_out;\\n\\nvoid main(void) {\\n\\n\\t// get the implied row and column from .y and .x of passed (output)\\n\\t// texture coordinate and translate to output pixel space.\\n\\tfloat row = floor(outTex.y * M_out);   // row on output texture (pixel space)\\n\\tfloat col = floor(outTex.x * N_out); // column on output texture (matrix space)\\n\\tfloat vcol = floor(col / C);   // virtual column on output texture (matrix space)\\n\\tfloat vchannel = floor(mod(col, C)); // virtual channel on output texture\\n\\n\\tconst float min = -1.0e+08;\\n\\tvec4 currentMax = vec4(min, min, min, min);\\n\\n\\tfloat deltaY = 1.0/M;\\n\\tfloat deltaX = 1.0/N;\\n\\tfloat y = ((row * stride) + 0.5)*deltaY; // texture position of input row\\n\\tfloat x;\\n\\tfloat z = vchannel * deltaX;\\n\\tfor (int i = 0; i < 100; i += 1) {\\n\\t\\tif (i >= factor) {\\n\\t\\t\\tbreak;\\n\\t\\t}\\n\\t\\tx = ((vcol * stride * C) + 0.5) * deltaX; // texture position of input column\\n\\n\\t\\tfor (int j = 0; j < 100; j += 1) {\\n\\t\\t\\tif (j >= factor) {\\n\\t\\t\\t\\tbreak;\\n\\t\\t\\t}\\n\\n\\t\\t\\tvec2 coords = vec2(x + z, y);\\n\\t\\t\\tvec4 x_v = texture2D(X, coords);\\n\\t\\t\\tcurrentMax = max(currentMax, x_v);\\n\\n\\t\\t\\tx += (deltaX * C);\\n\\t\\t}\\n\\t\\ty += deltaY;\\n\\t}\\n\\n\\tgl_FragColor = currentMax;\\n}\\n\";\n\n\t// create the webgl shader program for this calculation\n\t// based on the specific fragment shader for this calculation\n\t// and the generic pass through shader\n\tif(this.standalone){\n\t\tthis.program = this.webgl.createProgram(s);\n\t} else {\n\t\tthis.program = this.webgl.createProgram(p);\n\t}\n}\n\nmodule.exports = DownsampleCalculator;\n\n/* Names of the uniforms (variables) used in the shader program passed in on\n   each calculation.\n */\nDownsampleCalculator.TEXTURE_UNIFORM_NAME_0 = \"X\";\nDownsampleCalculator.INPUT_ROW_COUNT_UNIFORM_NAME = \"M\";\nDownsampleCalculator.INPUT_COLUMN_COUNT_UNIFORM_NAME = \"N\";\nDownsampleCalculator.OUTPUT_ROW_COUNT_UNIFORM_NAME = \"M_out\";\nDownsampleCalculator.OUTPUT_COLUMN_COUNT_UNIFORM_NAME = \"N_out\";\nDownsampleCalculator.FACTOR_UNIFORM_NAME = \"factor\";\nDownsampleCalculator.STRIDE_UNIFORM_NAME = \"stride\";\nDownsampleCalculator.CHANNEL_COUNT_UNIFORM_NAME = \"C\";\n\n\n/* Downsample (pool) the input using the maximum for each channel.\n\n\tM - rows in X\n\tN - columns in X\n\tc - (channels / 4) in X\n\tfactor - the number of pixels (width and height) to combine\n\tstride - amount between groups of pixels\n\tX - input matrix (texture)\n\tout - output (texture)\n\n  How this works:\n\n  1. Activate our shader program\n  2. Bind input textures\n  3. Set shader program parameters\n  4. Bind output texture\n  5. Activate calculation with `drawElements`\n\n */\nDownsampleCalculator.prototype.calculate = function(M, N, channels, factor, stride, X, out){\n\n\tif(channels % WebGL.COMPONENTS_PER_TEXEL != 0){\n\t\tthrow new Error(\"Channel count must be a multiple of \" + WebGL.COMPONENTS_PER_TEXEL);\n\t}\n\tvar gl = this.webgl.context;\n\n    var N_out = (Math.floor((N - factor) / stride) + 1) * channels;\n    var M_out = Math.floor((M - factor) / stride) + 1;\n\n\tthis.webgl.selectProgram(this.program);\n\n\t// create and bind our input texture using matrix data\n\tthis.bindInputTexture(X, gl.TEXTURE0, DownsampleCalculator.TEXTURE_UNIFORM_NAME_0);\n\n\n\t// set the data specific variables in our shader program\n\tthis.bindUniforms(M, N * channels, M_out, N_out, factor, stride, channels);\n\n\t// create our destination texture\n\tif(this.standalone){\n\t\tthis.webgl.bindOutputTexture(M_out, N_out, out);\n\t} else {\n\t\tthis.webgl.bindOutputTexture(M_out, N_out/WebGL.COMPONENTS_PER_TEXEL, out);\n\t}\n\n\n\t// initiate calculation\n\tgl.drawElements(gl.TRIANGLES, /*num items*/6, gl.UNSIGNED_SHORT, 0);\n\n\tthis.webgl.unbindInputTexture(gl.TEXTURE0);\n\n};\n\n/* Create a texture from the given texel data and bind it to our shader program.\n\n\ttexture - texture containing input values to bind\n\ttextureUnit - the texture unit to bind to (gl.TEXTURE0, gl.TEXTURE1, etc)\n\tname - the uniform name to associate with (must match shader program)\n\n\tmust compile program (with createProgram) first\n*/\nDownsampleCalculator.prototype.bindInputTexture = function(texture, textureUnit, name){\n\tvar gl = this.webgl.context,\n\t\tprogram = this.program;\n\n\tgl.activeTexture(textureUnit); // gl.TEXTURE0, gl.TEXTURE1, etc\n\tgl.bindTexture(\t  gl.TEXTURE_2D, texture);\n\n\tvar sampler = gl.getUniformLocation(program, name);\n\tgl.uniform1i(sampler, textureUnit - gl.TEXTURE0);\n\n};\n\n/* Set up inputs for the texture shader\n\n */\nDownsampleCalculator.prototype.bindUniforms = function(M, N, M_out, N_out, factor, stride, c) {\n\tvar gl = this.webgl.context;\n\n\t// get var locations\n\tvar M_gl = gl.getUniformLocation(this.program, DownsampleCalculator.INPUT_ROW_COUNT_UNIFORM_NAME),\n\t\tN_gl = gl.getUniformLocation(this.program, DownsampleCalculator.INPUT_COLUMN_COUNT_UNIFORM_NAME),\n\t\tM_out_gl = gl.getUniformLocation(this.program, DownsampleCalculator.OUTPUT_ROW_COUNT_UNIFORM_NAME),\n\t\tN_out_gl = gl.getUniformLocation(this.program, DownsampleCalculator.OUTPUT_COLUMN_COUNT_UNIFORM_NAME),\n\t\tfactor_gl = gl.getUniformLocation(this.program, DownsampleCalculator.FACTOR_UNIFORM_NAME),\n\t\tstride_gl = gl.getUniformLocation(this.program, DownsampleCalculator.STRIDE_UNIFORM_NAME),\n\t\tchannel_count_gl = gl.getUniformLocation(this.program, DownsampleCalculator.CHANNEL_COUNT_UNIFORM_NAME);\n\n\t// bind length of shared dimension\n\tgl.uniform1f(M_gl, M);\n\tgl.uniform1f(N_gl, N);\n\tgl.uniform1f(M_out_gl, M_out);\n\tgl.uniform1f(N_out_gl, N_out);\n\tgl.uniform1i(factor_gl, factor);\n\tgl.uniform1f(stride_gl, stride);\n\tgl.uniform1f(channel_count_gl, c);\n\n};\n","var WebGL = require('./webgl');\n\n/*  Elementwise clamp function for matrices on the interval [a, b]. Can also be\n\tused for min or max, by passing Number.MIN_VALUE for the first parameter and\n\tNumber.MAX_VALUE for the second parameter, respectively.\n\n\tPassing `null` for either of these parameters will default to it's\n\trespective min or max value.\n\n\tmax(a, min(b, x)) for each x in X\n\n\twhere X is a matrix, a and b are scalars\n\n\n\twebgl - a weblas.WebGL object\n\tstandalone - whether or not to automatically run the floating point encode\n\t\tstep for rendering to an UNSIGNED_BYTE texture (this is required for\n\t\tmobile, circa 2015) but can't be used as part of a pipeline.\n\n\t* uploads and downloads data\n\t* executes calculation\n */\nfunction SCLMPCalculator(webgl, standalone){\n\tthis.webgl = webgl,\n\tthis.standalone = (standalone != null) ? standalone : true; // default to standalone mode\n\n\tvar s = \"precision highp float;\\n#define GLSLIFY 1\\n\\nvarying vec2      outTex;\\t// texture coords of row/column to calculate\\nuniform sampler2D X;\\t\\t// texture with data from padded A\\nuniform int       N;\\t\\t// number of columns\\nuniform int       pad;\\t\\t// additional columns to nearest multiple of four\\nuniform float     a; \\t\\t// lower bound\\nuniform float     b; \\t\\t// upper bound\\n\\n// Render float to bytes according to IEEE 754 Floating Point\\nvec4 encode_float_1604150559(float val) {\\n\\n\\t// TODO: correctly handle denormal numbers\\n\\t// http://www.2ality.com/2012/04/number-encoding.html\\n\\tfloat a = abs(val);                           // encode absolute value + sign\\n\\tfloat exp = floor(log2(a));                 // number of powers of 2\\n\\tfloat mant = pow(2.,log2(a)-exp) * pow(2.,23.);  // multiply to fill 24 bits (implied leading 1)\\n\\tfloat mant1 = floor(mant / 256. / 256.);    // first 8 bits of mantissa\\n\\tfloat mant2 = mod(floor(mant / 256.),256.); // second 8 bits\\n\\tfloat mant3 = mod(mant,256.);               // third 8 bits\\n\\n\\thighp float sign = 128.-128.*(a/val);\\t\\t\\t// sign bit is 256 or 0\\n\\thighp float e = (sign+exp+127.)/510.;\\t\\t// exponent and sign\\n\\thighp float m1 = (mant1-(128.*(1.-mod(exp+127.,2.))))/255.; // handle leading bit\\n\\thighp float m2 = (mant2)/255.;\\t\\t\\t\\t// middle part\\n\\thighp float m3 = (mant3+.5)/255.;\\t\\t\\t// scale to 0 - 255\\n\\n\\treturn vec4(m3,m2,m1,e);\\n}\\n\\n// select an element from a vector based on index\\nfloat select_index_1540259130(vec4 v, int index){\\n\\tfloat val;\\n\\tif (index == 0) {\\n\\t\\tval = v.r;\\n\\t} else if(index == 1) {\\n\\t\\tval = v.g;\\n\\t} else if(index == 2) {\\n\\t\\tval = v.b;\\n\\t} else if(index == 3){\\n\\t\\tval = v.a;\\n\\t} else {\\n\\t\\t// should never be here\\n\\t\\tval = 0.0;\\n\\t}\\n\\n\\treturn val;\\n}\\n\\nvoid main(void) {\\n\\n\\t// get the implied row and column from .y and .x of passed (output)\\n\\t// texture coordinate. These map directly to input texture space when\\n\\t// the relevant dimensions are the same.\\n\\tfloat row = outTex.y;\\n\\tfloat col = outTex.x;\\n\\n\\t// return 0.0 if in padded region of output texture\\n\\tif(col * float(N + pad) > float(N) ) {\\n\\t\\tgl_FragColor = vec4(0.,0.,0.,0.);\\n\\t\\treturn;\\n\\t}\\n\\n\\t// direct usage of col requires output be padded exactly like input\\n\\tvec4 x = texture2D( X, vec2(col, row));\\n\\tvec4 val = clamp(x, a, b);\\n\\n\\t// select and output channel (standalone version only)\\n\\tint channel = int(mod(col * float(N + pad), 4.0));\\n\\tfloat sum = select_index_1540259130(val, channel);\\n\\n\\tif (sum == 0.) {\\n\\t\\tgl_FragColor = vec4(0.,0.,0.,0.);\\n\\t\\treturn;\\n\\t}\\n\\n\\t// output vec4 with bytes for an IEEE754 32-bit floating point number\\n\\tgl_FragColor = encode_float_1604150559(sum);\\n}\\n\",\n\t\tp = \"precision highp float;\\n#define GLSLIFY 1\\n\\nvarying vec2      outTex;\\t// texture coords of row/column to calculate\\nuniform sampler2D X;\\t\\t// texture with data from padded A\\nuniform int       N;\\t\\t// number of columns\\nuniform int       pad;\\t\\t// additional columns to nearest multiple of four\\nuniform float     a; \\t\\t// lower bound\\nuniform float     b; \\t\\t// upper bound\\n\\n// set pad values to 0.0, if in padded region of output texture\\nvoid fix_pad_1540259130(inout vec4 v, int pad){\\n\\tv.a = 0.0;\\n\\tif(pad == 2){\\n\\t\\tv.b = 0.0;\\n\\t} else if(pad == 3){\\n\\t\\tv.b = 0.0;\\n\\t\\tv.g = 0.0;\\n\\t}\\n}\\n\\nvoid main(void) {\\n\\n\\t// get the implied row and column from .y and .x of passed (output)\\n\\t// texture coordinate. These map directly to input texture space when\\n\\t// the relevant dimensions are the same.\\n\\tfloat row_t = outTex.y;\\n\\tfloat col_t = outTex.x;\\n\\tfloat col = (col_t * float(N + pad) - 2.0); // index of first element in pixel (matrix space)\\n\\n\\t// direct usage of col requires output be padded exactly like input\\n\\tvec4 x = texture2D( X, vec2(col_t, row_t));\\n\\tvec4 val_v = clamp(x, a, b);\\n\\n\\t// is last element in pixel past row length?\\n\\tif(pad > 0 && (col + 4.0) > float(N) ) {\\n\\t\\t// fix elements in padded region\\n\\t\\tfix_pad_1540259130(val_v, pad);\\n\\t}\\n\\n\\tgl_FragColor = val_v;\\n}\\n\";\n\n\t// create the webgl shader program for this calculation\n\t// based on the specific fragment shader for this calculation\n\t// and the generic pass through shader\n\tif(this.standalone){\n\t\tthis.program = this.webgl.createProgram(s);\n\t} else {\n\t\tthis.program = this.webgl.createProgram(p);\n\t}\n}\n\nmodule.exports = SCLMPCalculator;\n\n/* Names of the uniforms (variables) used in the shader program passed in on\n   each calculation.\n */\nSCLMPCalculator.TEXTURE_UNIFORM_NAME_0 = \"X\";\nSCLMPCalculator.LENGTH_UNIFORM_NAME = \"N\";\nSCLMPCalculator.LOWER_UNIFORM_NAME = \"a\";\nSCLMPCalculator.UPPER_UNIFORM_NAME = \"b\";\n\n\n/* Elementwise clamp a matrix to the interval [a, b]\n\n\tM - number of rows in X\n\tN - number of columns in X\n\ta - lower bound (inclusize)\n\tb - upper bound (inclusive)\n\tX - matrix (texture)\n\tout - output (texture)\n\n  How this works:\n\n  1. Activate our shader program\n  2. Bind input textures\n  3. Set shader program parameters\n  4. Bind output texture\n  5. Activate calculation with `drawElements`\n\n */\nSCLMPCalculator.prototype.calculate = function(M, N, a, b, X, out){\n\n\ta = (a != null) ? a : Number.MIN_VALUE;\n\tb = (b != null) ? b : Number.MAX_VALUE;\n\n\tvar gl = this.webgl.context;\n\n\tthis.webgl.selectProgram(this.program);\n\n\t// create and bind our input texture using matrix data\n\tthis.bindInputTexture(X, gl.TEXTURE0, SCLMPCalculator.TEXTURE_UNIFORM_NAME_0);\n\n\tvar nPad = this.webgl.getPad(N);\n\t// set the data specific variables in our shader program\n\tthis.bindUniforms(N, nPad, a, b);\n\n\t// create our destination texture\n\tif(this.standalone){\n\t\tthis.webgl.bindOutputTexture(M, N + nPad, out);\n\t} else {\n\t\tthis.webgl.bindOutputTexture(M, (N + nPad)/ 4, out);\n\t}\n\n\t// initiate calculation\n\tgl.drawElements(gl.TRIANGLES, /*num items*/6, gl.UNSIGNED_SHORT, 0);\n\n\tthis.webgl.unbindInputTexture(gl.TEXTURE0);\n\n};\n\n/* Create a texture from the given texel data and bind it to our shader program.\n\n\th - number of rows in input matrix\n\tw - number of cols in input matrix\n\ttexels - packed data\n\ttextureUnit - the texture unit to bind to (gl.TEXTURE0, gl.TEXTURE1, etc)\n\tname - the uniform name to associate with (must match shader program)\n\n\tmust compile program (with createProgram) first\n*/\nSCLMPCalculator.prototype.bindInputTexture = function(texture, textureUnit, name){\n\tvar gl = this.webgl.context,\n\t\tprogram = this.program;\n\n\tgl.activeTexture(textureUnit); // gl.TEXTURE0, gl.TEXTURE1, etc\n\tgl.bindTexture(\t  gl.TEXTURE_2D, texture);\n\n\tvar sampler = gl.getUniformLocation(program, name);\n\tgl.uniform1i(sampler, textureUnit - gl.TEXTURE0);\n\n};\n\n/* Set up inputs for the texture shader\n\n */\nSCLMPCalculator.prototype.bindUniforms = function(N, pad, a, b) {\n\tvar gl = this.webgl.context;\n\n\t// get var locations\n\tvar N_gl = gl.getUniformLocation(this.program, SCLMPCalculator.LENGTH_UNIFORM_NAME),\n\t\tb_gl = gl.getUniformLocation(this.program, SCLMPCalculator.UPPER_UNIFORM_NAME),\n\t\ta_gl = gl.getUniformLocation(this.program, SCLMPCalculator.LOWER_UNIFORM_NAME),\n\t\tpad_gl = gl.getUniformLocation(this.program, \"pad\");\n\n\t// bind length of shared dimension\n\tgl.uniform1i(N_gl, N);\n\tgl.uniform1i(pad_gl, pad);\n\tgl.uniform1f(a_gl, a);\n\tgl.uniform1f(b_gl, b);\n\n};\n","var globals = require(\"./globals\");\n\nvar gl = globals.gl;\n\n/* Create a new Tensor with the given shape and data, and upload\n\tthe resulting texture to the GPU.\n */\nfunction Tensor(shape, data){\n\tif(shape.length != 2)\n\t\tthrow new Error(\"Only Tensor of order two (matrix) is supported right now.\");\n\n\tvar M = shape[0],\n\t\tN = shape[1];\n\n\tthis.texture = gl.createDataTexture(M, N, data);\n\n\tthis.shape = [M, N];\n\n\tthis[Symbol.toStringTag] = 'Tensor';\n}\n\nmodule.exports = Tensor;\n\n/* delete the GPU resident texture */\nTensor.prototype.delete = function(){\n\tgl.context.deleteTexture(this.texture);\n\tthis.texture = null;\n\tthis.shape = null;\n};\n\n/* Extract the data from GPU memory and return as a Float32Array, optionally\n\tkeeping the data in GPU memory.\n */\nTensor.prototype.transfer = function(keep){\n\n\tvar M = this.shape[0],\n\t\tN = this.shape[1],\n\t\tout,\n\t\tresult;\n\n\t// create output texture\n\tout = gl.createOutputTexture(M, N);\n\n\t// float extraction\n\tgl.encode(M, N, this.texture, out);\n\n\tresult = new Float32Array(gl.readData(M, N));\n\n\t// clean up\n\tgl.context.deleteTexture(out);\n\n\tif(!keep){\n\t\tthis.delete();\n\t}\n\n\treturn result;\n};\n\nTensor.prototype.reshape = function(shape, keep){\n\n\tvar M = this.shape[0],\n\t\tN = this.shape[1],\n\t\tM_out = shape[0],\n\t\tN_out = shape[1];\n\n\t// create new texture to hold tranpose\n\tvar t0 = new Tensor(shape, null);\n\n\t// invoke shader\n\tgl.reshape(M, N, M_out, N_out, this.texture, t0.texture);\n\n\tif(!keep){\n\t\tthis.delete();\n\t}\n\n\treturn t0;\n};\n\nTensor.prototype.transpose = function(keep){\n\n\tvar M = this.shape[0],\n\t\tN = this.shape[1];\n\n\t// create new texture to hold tranpose\n\tvar tT = new Tensor([N, M], null);\n\n\t// invoke shader\n\tgl.transpose(M, N, this.texture, tT.texture);\n\n\tif(!keep){\n\t\tthis.delete();\n\t}\n\n\treturn tT;\n};\n\nTensor.prototype.split = function(stride, keep){\n\n\tvar M = this.shape[0],\n\t\tN = this.shape[1];\n\n\tif(N % 2 !== 0)\n\t\tthrow new Error(\"row count must be multiple of two.\");\n\n\n\t// create new texture to hold tranpose\n\tvar t0 = new Tensor([M, N/2], null),\n\t\tt1 = new Tensor([M, N/2], null);\n\n\tgl.submatrix(N, M, N/2, stride, 0, this.texture, t0.texture);\n\tgl.submatrix(N, M, N/2, stride, 1, this.texture, t1.texture);\n\n\tif(!keep){\n\t\tthis.delete();\n\t}\n\n\treturn [t0, t1];\n}\n\nTensor.combine = function(t0, t1, stride, keep){\n\n\tvar M = t0.shape[0],\n\t\tN = t0.shape[1];\n\n\tif(t0.shape[1] !== t1.shape[1] || t0.shape[0] !== t1.shape[0])\n\t\tthrow new Error(\"row and column counts must be equal.\");\n\n\tif(stride % 4 !== 0)\n\t\tthrow new Error(\"stride must be a multiple of four\");\n\n\t// create new texture to hold tranpose\n\tvar t2 = new Tensor([M, N * 2], null);\n\n\tgl.combine(M, N, stride, t0.texture, t1.texture, t2.texture);\n\n\tif(!keep){\n\t\tt0.delete();\n\t\tt1.delete();\n\t}\n\n\treturn t2;\n}\n","\n/*\nCopyright (c) 2015 Waylon Flinn\n\nwebgl.js\n\nmultiply matrices up to 4096 x 4096 on GPUs that support OES_texture_float\nextension. input is encoded into the red and green channels of an input texture and\ncalculations are done using a custom fragment shader.\n\n*/\n\n\n/*\n\tA WebGL context associated with a specific canvas element.\n\n\t* creates a canvas\n\t* sets up webgl context\n\t* translates numbers into textures\n\t* compiles shader programs for executing math (when supplied with an\n\t\toperation specific fragment shader)\n */\nfunction WebGL(options) {\n\n\tvar glOptions,\n\t\text;\n\n\toptions = options || {};\n\n\t// canvas\n\tif(typeof options.canvas === 'undefined')\n\t\tthis.canvas = document.createElement('canvas');\n\telse\n\t\tthis.canvas = options.canvas;\n\n\t// context\n\tglOptions = { premultipliedAlpha: false, preserveDrawingBuffer: false };\n\tthis.context = this.canvas.getContext(\"experimental-webgl\", glOptions);\n\n\tif (this.context == null)\n\t\tthrow new Error(\"No support for Webgl.\");\n\n\t// float texture extension\n\ttry {\n\t\text = this.context.getExtension('OES_texture_float');\n\t} catch(e) {\n\n\t}\n\tif (ext == null) {\n\t\tconsole.log(\"No support for OES_texture_float extension!\");\n\t\tthis.hasFloat = false;\n\t} else {\n\t\tthis.hasFloat = true;\n\t}\n\n\tvar highp = this.context.getShaderPrecisionFormat(this.context.FRAGMENT_SHADER, this.context.HIGH_FLOAT);\n\tthis.hasHighPrecision = highp.precision != 0;\n\tif(this.hasHighPrecision) this.highp = highp;\n\n\t// create pass through vertex shader\n\tvar passThrough = \"// vertex shader for a single quad\\n// work is performed in the operation specific texture shader\\n\\nprecision highp float;\\n#define GLSLIFY 1\\n\\nattribute vec3 pos;\\nattribute vec2 tex;\\nvarying vec2   outTex;\\nvoid main(void)\\n{\\n\\t// just pass the position and texture coords\\n\\tgl_Position = vec4(pos, 1.0);\\n\\toutTex = tex;\\n}\\n\";\n\tthis.vertexShader = this.context.createShader(this.context.VERTEX_SHADER);\n\tthis.context.shaderSource(this.vertexShader, passThrough);\n\tthis.context.compileShader(this.vertexShader);\n\n\tvar encode = \"\\nprecision highp float;\\n#define GLSLIFY 1\\n\\nvarying vec2      outTex;\\t// texture coords of row/column to calculate\\nuniform sampler2D A;\\t\\t// texture with data from padded A\\nuniform int       N;\\t\\t// number of columns in output\\nuniform int       pad;\\t\\t//\\n\\n// Render float to bytes according to IEEE 754 Floating Point\\nvec4 encode_float_1540259130(float val) {\\n\\n\\t// TODO: correctly handle denormal numbers\\n\\t// http://www.2ality.com/2012/04/number-encoding.html\\n\\tfloat a = abs(val);                           // encode absolute value + sign\\n\\tfloat exp = floor(log2(a));                 // number of powers of 2\\n\\tfloat mant = pow(2.,log2(a)-exp) * pow(2.,23.);  // multiply to fill 24 bits (implied leading 1)\\n\\tfloat mant1 = floor(mant / 256. / 256.);    // first 8 bits of mantissa\\n\\tfloat mant2 = mod(floor(mant / 256.),256.); // second 8 bits\\n\\tfloat mant3 = mod(mant,256.);               // third 8 bits\\n\\n\\thighp float sign = 128.-128.*(a/val);\\t\\t\\t// sign bit is 256 or 0\\n\\thighp float e = (sign+exp+127.)/510.;\\t\\t// exponent and sign\\n\\thighp float m1 = (mant1-(128.*(1.-mod(exp+127.,2.))))/255.; // handle leading bit\\n\\thighp float m2 = (mant2)/255.;\\t\\t\\t\\t// middle part\\n\\thighp float m3 = (mant3+.5)/255.;\\t\\t\\t// scale to 0 - 255\\n\\n\\treturn vec4(m3,m2,m1,e);\\n}\\n\\n// select an element from a vector based on index\\nfloat select_index_1604150559(vec4 v, int index){\\n\\tfloat val;\\n\\tif (index == 0) {\\n\\t\\tval = v.r;\\n\\t} else if(index == 1) {\\n\\t\\tval = v.g;\\n\\t} else if(index == 2) {\\n\\t\\tval = v.b;\\n\\t} else if(index == 3){\\n\\t\\tval = v.a;\\n\\t} else {\\n\\t\\t// should never be here\\n\\t\\tval = 0.0;\\n\\t}\\n\\n\\treturn val;\\n}\\n\\nvoid main(void) {\\n\\n\\t// get the implied row and column from .y and .x of passed (output)\\n\\t// texture coordinate. These map directly to input texture space when\\n\\t// the relevant dimensions are the same.\\n\\tfloat row_t = outTex.y;\\n\\tfloat col_t = outTex.x;\\n\\n\\tvec4 val_v = texture2D(A, vec2(col_t * float(N)/float(N + pad), row_t));\\n\\tint channel = int(mod(col_t * float(N), 4.0 ));\\n\\tfloat val = select_index_1604150559(val_v, channel);\\n\\n\\tif (val == 0.) {\\n\\t\\tgl_FragColor = vec4(0.,0.,0.,0.);\\n\\t\\treturn;\\n\\t}\\n\\n \\t// output vec4 with bytes for an IEEE754 32-bit floating point number\\n\\tgl_FragColor = encode_float_1540259130(val);\\n}\\n\",\n\t\ttranspose = \"\\nprecision highp float;\\n#define GLSLIFY 1\\n\\nvarying vec2      outTex;\\t// texture coords of row/column to calculate\\nuniform sampler2D A;\\t\\t// texture with data from padded A\\nuniform int       M;\\t\\t// number of rows in output\\nuniform int       N;\\t\\t// number of columns in output\\nuniform int       mpad;\\t\\t//\\nuniform int       npad;\\t\\t//\\n\\n// select an element from a vector based on index\\nfloat select_index_1540259130(vec4 v, int index){\\n\\tfloat val;\\n\\tif (index == 0) {\\n\\t\\tval = v.r;\\n\\t} else if(index == 1) {\\n\\t\\tval = v.g;\\n\\t} else if(index == 2) {\\n\\t\\tval = v.b;\\n\\t} else if(index == 3){\\n\\t\\tval = v.a;\\n\\t} else {\\n\\t\\t// should never be here\\n\\t\\tval = 0.0;\\n\\t}\\n\\n\\treturn val;\\n}\\n\\nvoid main(void) {\\n\\n\\t// get the implied row and column from .y and .x of passed (output)\\n\\t// texture coordinate. These map directly to input texture space when\\n\\t// the relevant dimensions are the same.\\n\\tfloat row_t = outTex.y;\\n\\tfloat col_t = outTex.x;\\n\\tfloat col = (col_t * float(N + npad) - 2.0); // index of first element in pixel (matrix space)\\n\\n\\t// get rows in the input, each containing one element in the output\\n\\tvec4 row_1 = texture2D(A, vec2((row_t * float(M))/float(M + mpad), (col + 0.5)/float(N)));\\n\\tvec4 row_2 = texture2D(A, vec2((row_t * float(M))/float(M + mpad), (col + 1.5)/float(N)));\\n\\tvec4 row_3 = texture2D(A, vec2((row_t * float(M))/float(M + mpad), (col + 2.5)/float(N)));\\n\\tvec4 row_4 = texture2D(A, vec2((row_t * float(M))/float(M + mpad), (col + 3.5)/float(N)));\\n\\n\\t// package into output vector\\n\\tint channel = int(mod(row_t * float(M), 4.0 ));\\n\\n\\tvec4 col_v = vec4(0.0, 0.0, 0.0, 0.0); // vec4 representing four elements in a column in the input\\n\\n\\t// extract relevent element from each input row\\n\\tcol_v.r = select_index_1540259130(row_1, channel);\\n\\tif(npad > 0 && (col + 4.0) > float(N) ) {\\n\\t\\t// compute elements in padded region\\n\\t\\tif(npad < 3){\\n\\t\\t\\tcol_v.g = select_index_1540259130(row_2, channel);\\n\\t\\t}\\n\\t\\tif(npad < 2){\\n\\t\\t\\tcol_v.b = select_index_1540259130(row_3, channel);\\n\\t\\t}\\n\\t} else {\\n\\t\\tcol_v.g = select_index_1540259130(row_2, channel);\\n\\t\\tcol_v.b = select_index_1540259130(row_3, channel);\\n\\t\\tcol_v.a = select_index_1540259130(row_4, channel);\\n\\t}\\n\\n\\tgl_FragColor = col_v;\\n}\\n\",\n\t\treshape = \"\\nprecision highp float;\\n#define GLSLIFY 1\\n\\nvarying vec2      outTex;\\t// texture coords of row/column to calculate\\nuniform sampler2D A;\\t\\t// texture with data from padded A\\nuniform float     M;\\t\\t// number of rows in output\\nuniform float     N;\\t\\t// number of columns in output\\nuniform float     pad;\\t\\t// column padding in output\\nuniform float     M_in;\\t\\t// number of rows in input\\nuniform float     N_in;\\t\\t// number of columns in input\\nuniform float     pad_in;\\t// column padding in input\\n\\n/* number of input pixels\\n   origin index (channel) for each\\n   termination index (channel) for each\\n   destination origin index (channel) for each\\n */\\n// select an element from a vector based on index\\nfloat select_index_1540259130(vec4 v, int index){\\n\\tfloat val;\\n\\tif (index == 0) {\\n\\t\\tval = v.r;\\n\\t} else if(index == 1) {\\n\\t\\tval = v.g;\\n\\t} else if(index == 2) {\\n\\t\\tval = v.b;\\n\\t} else if(index == 3){\\n\\t\\tval = v.a;\\n\\t} else {\\n\\t\\t// should never be here\\n\\t\\tval = 0.0;\\n\\t}\\n\\n\\treturn val;\\n}\\n\\n// set pad values to 0.0, if in padded region of output texture\\nvoid fix_pad_1604150559(inout vec4 v, int pad){\\n\\tv.a = 0.0;\\n\\tif(pad == 2){\\n\\t\\tv.b = 0.0;\\n\\t} else if(pad == 3){\\n\\t\\tv.b = 0.0;\\n\\t\\tv.g = 0.0;\\n\\t}\\n}\\n\\n// translate a linear index into x, y coordinates for a matrix\\nvec2 linear_index_coords_1117569599(float linear_index, float row_length){\\n\\tvec2 coords;\\n\\n\\tcoords.x = floor(mod(linear_index + 0.5, row_length)); // column\\n\\tcoords.y = floor((linear_index + 0.5) / row_length); // row\\n\\n\\treturn coords;\\n}\\n\\nvoid main(void) {\\n\\n\\t// get the implied row and column from .y and .x of passed (output)\\n\\t// texture coordinate. These map directly to input texture space when\\n\\t// the relevant dimensions are the same.\\n\\tfloat row_t = outTex.y;\\n\\tfloat col_t = outTex.x;\\n\\n\\tfloat row = floor(row_t * M);\\n\\tfloat col_0 = (col_t * (N + pad) - 2.0); // index of first element in pixel (matrix space)\\n\\t//float col_0 = floor(col_t * (N + pad)/4.0)*4.0; // index of first element in pixel (matrix space)\\n\\tfloat lin_index_0 = row * N + col_0; // linearized index of first element in pixel in output\\n\\n\\tvec4 pixel_in = vec4(0.0, 0.0, 0.0, 0.0);\\n\\tvec4 result = vec4(0.0, 0.0, 0.0, 0.0);\\n\\tvec2 coords = linear_index_coords_1117569599(lin_index_0, N_in);\\n\\tvec2 ncoords;\\n\\tint channel_in = int(mod(coords.x, 4.0));\\n\\n\\tvec2 scale_in = vec2(1.0/(N_in + pad_in), 1.0/M_in); // scale from matrix to input texture coords\\n\\tvec2 offset_in = vec2(0.5, 0.5); // move away from edge of pixel\\n\\tconst vec2 pixel_scale = vec2(1.0/4.0, 1.0); // scale from matrix to pixel coords\\n\\n\\tpixel_in = texture2D(A, (coords + offset_in) * scale_in);\\n\\n\\t// go through channels for current output pixel\\n\\tfor(int channel = 0; channel < 4; channel++){\\n\\n\\t\\t// are we on a new input pixel?\\n\\t\\tncoords = linear_index_coords_1117569599(lin_index_0 + float(channel), N_in);\\n\\t\\tif(floor(ncoords * pixel_scale) != floor(coords * pixel_scale)){\\n\\t\\t\\tcoords = ncoords;\\n\\t\\t\\tpixel_in = texture2D(A, (coords + offset_in) * scale_in);\\n\\t\\t\\tchannel_in = 0;\\n\\t\\t}\\n\\n\\t\\tif(channel == 0){\\n\\t\\t\\tresult.r = select_index_1540259130(pixel_in, channel_in);\\n\\t\\t} else if(channel == 1){\\n\\t\\t\\tresult.g = select_index_1540259130(pixel_in, channel_in);\\n\\t\\t} else if(channel == 2){\\n\\t\\t\\tresult.b = select_index_1540259130(pixel_in, channel_in);\\n\\t\\t} else {\\n\\t\\t\\tresult.a = select_index_1540259130(pixel_in, channel_in);\\n\\t\\t}\\n\\n\\t\\tchannel_in++;\\n\\t}\\n\\n\\t// are we in the padded (output) region?\\n\\tif(pad > 0.0 && col_0 + 3.5 > N ) {\\n\\t\\tfix_pad_1604150559(result, int(pad));\\n\\t}\\n\\n\\tgl_FragColor = result;\\n}\\n\",\n\t\treshape_simple = \"\\nprecision highp float;\\n#define GLSLIFY 1\\n\\nvarying vec2      outTex;\\t// texture coords of row/column to calculate\\nuniform sampler2D A;\\t\\t// texture with data from padded A\\nuniform float     M;\\t\\t// number of rows in output\\nuniform float     N;\\t\\t// number of columns in output\\nuniform float     M_in;\\t\\t// number of rows in input\\nuniform float     N_in;\\t\\t// number of columns in input\\n\\n// translate a linear index into x, y coordinates for a matrix\\nvec2 linear_index_coords_1540259130(float linear_index, float row_length){\\n\\tvec2 coords;\\n\\n\\tcoords.x = floor(mod(linear_index + 0.5, row_length)); // column\\n\\tcoords.y = floor((linear_index + 0.5) / row_length); // row\\n\\n\\treturn coords;\\n}\\n\\nvoid main(void) {\\n\\n\\t// get the implied row and column from .y and .x of passed (output)\\n\\t// texture coordinate. These map directly to input texture space when\\n\\t// the relevant dimensions are the same.\\n\\tfloat row_t = outTex.y;\\n\\tfloat col_t = outTex.x;\\n\\n\\tfloat row = floor(row_t * M);\\n\\tfloat col_0 = floor(col_t * N - 1.5); // index of first element in pixel (matrix space)\\n\\tfloat lin_index_0 = row * N + col_0; // linearized index of first element in pixel in output\\n\\n\\tvec4 result;\\n\\tvec2 coords = linear_index_coords_1540259130(lin_index_0, N_in);\\n\\n\\tvec2 scale_in = vec2(1.0/N_in, 1.0/M_in); // scale from matrix to input texture coords\\n\\tvec2 offset_in = vec2(0.5, 0.5); // move away from edge of pixel\\n\\n\\tresult = texture2D(A, (coords + offset_in) * scale_in);\\n\\n\\tgl_FragColor = result;\\n}\\n\",\n\t\tsubmatrix = \"precision highp float;\\n#define GLSLIFY 1\\n\\nvarying vec2      outTex;\\t// texture coords of row/column to calculate\\nuniform sampler2D X;\\t\\t// texture with data from padded X\\nuniform float     N;\\t\\t// number of columns\\nuniform float     pad;\\t\\t// additional columns to nearest multiple of four\\nuniform float     N_in;\\t\\t// number of columns (input)\\nuniform float     pad_in;\\t// additional columns to nearest multiple of four (input)\\nuniform float     stride;\\nuniform float     offset;   // zero or one\\n\\n// set pad values to 0.0, if in padded region of output texture\\nvoid fix_pad_1540259130(inout vec4 v, int pad){\\n\\tv.a = 0.0;\\n\\tif(pad == 2){\\n\\t\\tv.b = 0.0;\\n\\t} else if(pad == 3){\\n\\t\\tv.b = 0.0;\\n\\t\\tv.g = 0.0;\\n\\t}\\n}\\n\\n/* join parts of two pixels into one, selecting four continguous elements\\n  starting at channel.\\n*/\\nvoid join_pixels_1604150559(inout vec4 x, vec4 x0, vec4 x1, float channel){\\n\\tif(channel == 1.0){\\n\\t\\tx.rgb = x0.gba;\\n\\t\\tx.a = x1.r;\\n\\t} else if(channel == 2.0){\\n\\t\\tx.rg = x0.ba;\\n\\t\\tx.ba = x1.rg;\\n\\t} else if(channel == 3.0){\\n\\t\\tx.r = x0.a;\\n\\t\\tx.gba = x1.rgb;\\n\\t}\\n}\\n\\nvoid main(void) {\\n\\n\\t// get the implied row and column from .y and .x of passed (output)\\n\\t// texture coordinate. These map directly to input texture space when\\n\\t// the relevant dimensions are the same.\\n\\tfloat row_t = outTex.y;\\n\\tfloat col_t = outTex.x;\\n\\tfloat col = floor(col_t * (N + pad) - 1.5); // index of first element in pixel (output matrix space)\\n\\n\\tfloat stripe = floor(col / stride);\\n\\tfloat sub_col = floor(mod(col, stride));\\n\\n\\tfloat col_in = (offset + (2.0 * stripe)) * stride + sub_col;\\n\\n\\tvec4 x;\\n\\tfloat channel = mod(col_in, 4.0); // channel in the input of first element in output\\n\\n\\t// are we at the beggining of an input pixel?\\n\\tif(channel == 0.0){\\n\\t\\t// yes, select the whole thing\\n\\t\\tx = texture2D( X, vec2((col_in + 2.0 - channel) / (N_in + pad_in) , row_t));\\n\\t} else {\\n\\t\\t// no, select parts from two pixels\\n\\t\\tvec4 x0, x1;\\n\\t\\tx0 = texture2D( X, vec2((col_in + 2.0 - channel) / (N_in + pad_in) , row_t));\\n\\t\\tx1 = texture2D( X, vec2((col_in + 6.0 - channel) / (N_in + pad_in) , row_t));\\n\\n\\t\\tjoin_pixels_1604150559(x, x0, x1, channel);\\n\\n\\t}\\n\\n\\t// fix padded region\\n\\tif(pad > 0.0 && col + 4.0 > N ) {\\n\\t\\tfix_pad_1540259130(x, int(pad));\\n\\t}\\n\\n\\tgl_FragColor = x;\\n}\\n\",\n\t\tcombine = \"precision highp float;\\n#define GLSLIFY 1\\n\\nvarying vec2      outTex;\\t// texture coords of row/column to calculate\\nuniform sampler2D A;\\t\\t// texture with data from padded A\\nuniform sampler2D B;\\t\\t// texture with data from padded B\\nuniform float     N_in;\\t\\t// number of columns\\nuniform float     pad_in;\\t// additional columns to nearest multiple of four\\nuniform float     stride;\\n\\n// set pad values to 0.0, if in padded region of output texture\\nvoid fix_pad_1540259130(inout vec4 v, int pad){\\n\\tv.a = 0.0;\\n\\tif(pad == 2){\\n\\t\\tv.b = 0.0;\\n\\t} else if(pad == 3){\\n\\t\\tv.b = 0.0;\\n\\t\\tv.g = 0.0;\\n\\t}\\n}\\n\\nvoid main(void) {\\n\\n\\t// get the implied row and column from .y and .x of passed (output)\\n\\t// texture coordinate. These map directly to input texture space when\\n\\t// the relevant dimensions are the same.\\n\\tfloat row_t = outTex.y;\\n\\tfloat col_t = outTex.x;\\n\\tfloat N = N_in * 2.0;\\n\\tfloat pad = mod(N, 4.0);\\n\\tfloat col = floor(col_t * (N + pad) - 1.5); // index of first element in pixel (output matrix space)\\n\\n\\tfloat stripe = floor(col / stride);\\n\\tfloat sub_col = floor(mod(col, stride));\\n\\n\\tfloat tex_select = mod(stripe, 2.0);\\n\\tfloat col_in = floor(stripe / 2.0) * stride + sub_col;\\n\\n\\tvec4 x;\\n\\tfloat channel = mod(col_in, 4.0); // channel in the input of first element in output\\n\\n\\t// which input texture are we getting this pixel from?\\n\\tif(tex_select == 0.0){\\n\\t\\tx = texture2D( A, vec2((col_in + 2.0) / (N_in + pad_in) , row_t));\\n\\t} else {\\n\\t\\tx = texture2D( B, vec2((col_in + 2.0) / (N_in + pad_in) , row_t));\\n\\t}\\n\\n\\t// fix padded region\\n\\tif(pad > 0.0 && col + 4.0 > N ) {\\n\\t\\tfix_pad_1540259130(x, int(pad));\\n\\t}\\n\\n\\tgl_FragColor = x;\\n}\\n\";\n\n\tthis.encode_program = this.createProgram(encode);\n\tthis.transpose_program = this.createProgram(transpose);\n\tthis.reshape_program = this.createProgram(reshape);\n\tthis.reshape_simple_program = this.createProgram(reshape_simple);\n\tthis.submatrix_program = this.createProgram(submatrix);\n\tthis.combine_program = this.createProgram(combine);\n};\n\nmodule.exports = WebGL;\n\n// RGBA is the standard input/ouput texture\nWebGL.COMPONENTS_PER_TEXEL = 4;\n\nWebGL.POSITION_UNIFORM_NAME = \"pos\";\nWebGL.TEXTURE_UNIFORM_NAME = \"tex\";\n\n\nWebGL.prototype.encode = function(M, N, texture0, out){\n\n\tthis.program = this.encode_program;\n\tthis.selectProgram(this.program);\n\n\tvar pad = this.getPad(N);\n\n\tvar N_gl = this.context.getUniformLocation(this.program, \"N\"),\n\t\tpad_gl = this.context.getUniformLocation(this.program, \"pad\");\n\n\tthis.context.uniform1i(N_gl, N);\n\tthis.context.uniform1i(pad_gl, pad);\n\n\tthis.bindInputTexture(texture0, this.context.TEXTURE0, \"A\");\n\n\tthis.bindOutputTexture(M, N, out);\n\n\tthis.context.drawElements(this.context.TRIANGLES, /*num items*/6, this.context.UNSIGNED_SHORT, 0);\n\n\tthis.unbindInputTexture(this.context.TEXTURE0);\n}\n\n/* tranpose a texture where input has M rows and N columns\n */\nWebGL.prototype.transpose = function(M, N, texture0, out){\n\n\tthis.program = this.transpose_program;\n\tthis.selectProgram(this.program);\n\n\tvar npad = this.getPad(N),\n\t\tmpad = this.getPad(M);\n\n\t// in the shader M and N describe rows and columns in the *output*, respectively\n\tvar N_gl = this.context.getUniformLocation(this.program, \"N\"),\n\t\tnpad_gl = this.context.getUniformLocation(this.program, \"npad\"),\n\t\tM_gl = this.context.getUniformLocation(this.program, \"M\"),\n\t\tmpad_gl = this.context.getUniformLocation(this.program, \"mpad\");\n\n\tthis.context.uniform1i(N_gl, M);\n\tthis.context.uniform1i(npad_gl, mpad);\n\tthis.context.uniform1i(M_gl, N);\n\tthis.context.uniform1i(mpad_gl, npad);\n\n\tthis.bindInputTexture(texture0, this.context.TEXTURE0, \"A\");\n\n\tthis.bindOutputTexture(N, (M + mpad)/4, out);\n\n\tthis.context.drawElements(this.context.TRIANGLES, /*num items*/6, this.context.UNSIGNED_SHORT, 0);\n\n\tthis.unbindInputTexture(this.context.TEXTURE0);\n};\n\n/* tranpose a texture where input has M rows and N columns\n */\nWebGL.prototype.reshape = function(M, N, M_out, N_out, texture0, out){\n\n\tvar pad = this.getPad(N),\n\t\tpad_out = this.getPad(N_out);\n\n\tif(pad == 0 && pad_out == 0){\n\t\tthis.program = this.reshape_simple_program;\n\t} else {\n\t\tthis.program = this.reshape_program;\n\t\tconsole.log(\"# WARNING: using slow reshape shader.\");\n\t}\n\n\tthis.selectProgram(this.program);\n\n\n\t// in the shader M and N describe rows and columns in the *output*, respectively\n\tvar M_gl = this.context.getUniformLocation(this.program, \"M\"),\n\t\tN_gl = this.context.getUniformLocation(this.program, \"N\"),\n\t\tpad_gl = this.context.getUniformLocation(this.program, \"pad\"),\n\t\tM_in_gl = this.context.getUniformLocation(this.program, \"M_in\"),\n\t\tN_in_gl = this.context.getUniformLocation(this.program, \"N_in\"),\n\t\tpad_in_gl = this.context.getUniformLocation(this.program, \"pad_in\");\n\n\tthis.context.uniform1f(M_gl, M_out);\n\tthis.context.uniform1f(N_gl, N_out);\n\tthis.context.uniform1f(pad_gl, pad_out);\n\tthis.context.uniform1f(M_in_gl, M);\n\tthis.context.uniform1f(N_in_gl, N);\n\tthis.context.uniform1f(pad_in_gl, pad);\n\n\tthis.bindInputTexture(texture0, this.context.TEXTURE0, \"A\");\n\n\tthis.bindOutputTexture(M_out, (N_out + pad_out)/4, out);\n\n\tthis.context.drawElements(this.context.TRIANGLES, /*num items*/6, this.context.UNSIGNED_SHORT, 0);\n\n\tthis.unbindInputTexture(this.context.TEXTURE0);\n};\n\n/* extract a portion of a texture into another texture\n */\nWebGL.prototype.submatrix = function(N, M_out, N_out, stride, offset, texture0, out){\n\n\tthis.program = this.submatrix_program;\n\tthis.selectProgram(this.program);\n\n\tvar pad = this.getPad(N),\n\t\tpad_out = this.getPad(N_out);\n\n\t// in the shader M and N describe rows and columns in the *output*, respectively\n\tvar N_gl = this.context.getUniformLocation(this.program, \"N\"),\n\t\tpad_gl = this.context.getUniformLocation(this.program, \"pad\"),\n\t\tN_in_gl = this.context.getUniformLocation(this.program, \"N_in\"),\n\t\tpad_in_gl = this.context.getUniformLocation(this.program, \"pad_in\"),\n\t\toffset_gl = this.context.getUniformLocation(this.program, \"offset\");\n\t\tstride_gl = this.context.getUniformLocation(this.program, \"stride\");\n\n\tthis.context.uniform1f(N_gl, N_out);\n\tthis.context.uniform1f(pad_gl, pad_out);\n\tthis.context.uniform1f(N_in_gl, N);\n\tthis.context.uniform1f(pad_in_gl, pad);\n\tthis.context.uniform1f(stride_gl, stride);\n\tthis.context.uniform1f(offset_gl, offset);\n\n\tthis.bindInputTexture(texture0, this.context.TEXTURE0, \"X\");\n\n\tthis.bindOutputTexture(M_out, (N_out + pad_out)/4, out);\n\n\tthis.context.drawElements(this.context.TRIANGLES, /*num items*/6, this.context.UNSIGNED_SHORT, 0);\n\n\tthis.unbindInputTexture(this.context.TEXTURE0);\n};\n\n/* combine two smaller textures into a larger texture\n   M - input rows\n   N - input columns\n */\nWebGL.prototype.combine = function(M, N, stride, texture0, texture1, out){\n\n\tthis.program = this.combine_program;\n\tthis.selectProgram(this.program);\n\n\tvar N_out = N * 2,\n\t\tpad = this.getPad(N),\n\t\tpad_out = this.getPad(N_out); // = (pad * 2) % 4\n\n\t// in the shader M and N describe rows and columns in the *output*, respectively\n\tvar N_in_gl = this.context.getUniformLocation(this.program, \"N_in\"),\n\t\tpad_in_gl = this.context.getUniformLocation(this.program, \"pad_in\"),\n\t\tstride_gl = this.context.getUniformLocation(this.program, \"stride\");\n\n\tthis.context.uniform1f(N_in_gl, N);\n\tthis.context.uniform1f(pad_in_gl, pad);\n\tthis.context.uniform1f(stride_gl, stride);\n\n\tthis.bindInputTexture(texture0, this.context.TEXTURE0, \"A\");\n\tthis.bindInputTexture(texture1, this.context.TEXTURE1, \"B\");\n\n\tthis.bindOutputTexture(M, (N_out + pad_out)/4, out);\n\n\tthis.context.drawElements(this.context.TRIANGLES, /*num items*/6, this.context.UNSIGNED_SHORT, 0);\n\n\tthis.unbindInputTexture(this.context.TEXTURE0);\n};\n\nWebGL.prototype.bindInputTexture = function(texture, textureUnit, name){\n\tvar gl = this.context,\n\t\tprogram = this.program;\n\n\tgl.activeTexture(textureUnit); // gl.TEXTURE0, gl.TEXTURE1, etc\n\tgl.bindTexture(\t  gl.TEXTURE_2D, texture);\n\n\tvar sampler = gl.getUniformLocation(program, name);\n\tgl.uniform1i(sampler, textureUnit - gl.TEXTURE0);\n\n};\n\n/*  Create a shader program based on a pass through vertex shader and\n\tthe supplied operation specific fragment shader.\n\n\tfragmentShaderSource - string containing the fragment shader source code.\n\tshader will recieve `vec2 outTex` with texture coordinates from the pass\n\tthrough vertex shader.\n */\nWebGL.prototype.createProgram = function(fragmentShaderSource){\n\tvar gl = this.context,\n\t\tfragmentShader;\n\n\t// compile the provided fragment/texture shader\n\tfragmentShader = gl.createShader(gl.FRAGMENT_SHADER);\n\tgl.shaderSource(fragmentShader, fragmentShaderSource);\n\tgl.compileShader(fragmentShader);\n\n\t// did it compile correctly?\n\tif (gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS) == 0)\n\t\tthrow new Error(gl.getShaderInfoLog(fragmentShader));\n\n\t// link the program specific fragment shader and the generic pass through\n\t// shader into a program\n\tvar program = gl.createProgram();\n\tgl.attachShader(program, this.vertexShader);\n\tgl.attachShader(program, fragmentShader);\n\tgl.linkProgram(program);\n\n\treturn program;\n};\n\nWebGL.prototype.selectProgram = function(program){\n\n\tvar gl = this.context;\n\n\t// set calculator program to current shader program\n\tgl.useProgram(program);\n\n\tthis.bindVertices(program);\n};\n\n/* setup required to draw a square to our vertex shader and have\n   fragment shader called for each pixel\n */\nWebGL.prototype.bindVertices = function(program) {\n\tvar gl = this.context,\n\t\trenderer = program;\n\n\t// bind vertices\n\tvar position = gl.getAttribLocation(renderer, WebGL.POSITION_UNIFORM_NAME);\n\tvar vertexBuffer = gl.createBuffer();\n\tgl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);\n\n\t// define a square that covers the screen\n\tvar vertices = [-1.0, -1.0, 0.0,\t// bottom left\n\t\t\t\t\t 1.0, -1.0, 0.0,\t// bottom right\n\t\t\t\t\t 1.0,  1.0, 0.0,\t// top right\n\t\t\t\t\t-1.0,  1.0, 0.0];\t// top left\n\tgl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);\n\tgl.vertexAttribPointer(position, /*item size*/3, gl.FLOAT, false, 0, 0);\n\tgl.enableVertexAttribArray(position);\n\n\t// bind texture cords\n\tvar texture = gl.getAttribLocation(renderer, WebGL.TEXTURE_UNIFORM_NAME);\n\tvar texCoords = gl.createBuffer();\n\tgl.bindBuffer(gl.ARRAY_BUFFER, texCoords);\n\tvar textureCoords = [0.0, 0.0,\n\t\t\t\t\t\t 1.0, 0.0,\n\t\t\t\t\t\t 1.0, 1.0,\n\t\t\t\t\t\t 0.0, 1.0];\n\tgl.bufferData(gl.ARRAY_BUFFER, new Float32Array(textureCoords), gl.STATIC_DRAW);\n\tgl.vertexAttribPointer(texture, /*item size*/2, gl.FLOAT, false, 0, 0);\n\tgl.enableVertexAttribArray(texture);\n\n\t// index to vertices\n\tvar indices = gl.createBuffer();\n\tgl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indices);\n\t// tesselate square into triangles\n\t// indeces into vertex array creating triangles, with counter-clockwise winding\n\tvar vertexIndices = [0, 1, 2,\t// bottom right triangle\n\t\t\t\t\t\t 0, 2, 3];\t// top left triangle\n\tgl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(vertexIndices), gl.STATIC_DRAW);\n};\n\n/* create RGBA texture of width w/4 from given texels\n   padding the width of each row to a multiple of 4, where necessary.\n\n   if texels is null, an empty texture is created.\n\n   alternative to textures?\n   http://stackoverflow.com/questions/17203508/webgl-hardware-skinning-with-a-bone-texture\n */\nWebGL.prototype.createDataTexture = function(h, w, texels){\n\n\tvar gl = this.context;\n\n\tvar PAD_TEMPLATE = [0.0, 0.0, 0.0, 0.0]; // value to pad remainder with\n\n\tvar rem = (w % WebGL.COMPONENTS_PER_TEXEL),\n\t\tpad = rem == 0 ? 0 : WebGL.COMPONENTS_PER_TEXEL - rem;\n\n\t// create the texture from our floats\n\tvar texture = gl.createTexture();\n\n\tgl.bindTexture(\t  gl.TEXTURE_2D, texture);\n\t/*\n\t// https://www.opengl.org/wiki/GLAPI/glPixelStore\n    gl.pixelStorei(gl.UNPACK_ROW_LENGTH, w/4);\n    gl.pixelStorei(gl.UNPACK_ALIGNMENT, 1);\n\n\tsee also: https://www.opengl.org/wiki/Common_Mistakes#Creating_a_complete_texture\n\t*/\n\tif(pad == 0 || texels == null || typeof texels === 'undefined'){\n\t\t// no padding required, write directly from input array\n\t\tgl.texImage2D(\t  gl.TEXTURE_2D, 0, gl.RGBA, (w + pad) / WebGL.COMPONENTS_PER_TEXEL, h, 0,\n\t\t\t\t\t\t  gl.RGBA, gl.FLOAT, texels);\n\n\t} else {\n\t\t// must pad each row\n\n\t\t// create empty texture\n\t\tgl.texImage2D(\t  gl.TEXTURE_2D, 0, gl.RGBA, (w + pad) / WebGL.COMPONENTS_PER_TEXEL, h, 0,\n\t\t\t\t\t\t  gl.RGBA, gl.FLOAT, null);\n\n\t\tvar full_texel_row_len = w - rem,\n\t\t\tfull_row_texture_width = full_texel_row_len / WebGL.COMPONENTS_PER_TEXEL;\n\n\t\tvar row_start = 0;\n\t\tvar last_texel = new Float32Array(PAD_TEMPLATE);\n\t\tvar row, remainder;\n\n\t\t// set texture data, one row at a time, padding each row to a multiple\n\t\t// of the texel length\n\t\tfor(var i = 0; i < h; i++){\n\t\t\trow_start = i * w;\n\t\t\tfull_texel_row_end = row_start + full_texel_row_len;\n\t\t\trow = new Float32Array(texels.buffer, row_start * texels.BYTES_PER_ELEMENT, full_texel_row_len);\n\t\t\tif(full_texel_row_len > 0){\n\t\t\t\t// https://www.khronos.org/registry/webgl/specs/latest/1.0/index.html#TEXSUBIMAGE2D\n\t\t\t\tgl.texSubImage2D(gl.TEXTURE_2D,\n\t\t\t\t\t 0,\t\t\t\t\t// mip-map level\n\t\t\t\t\t 0,\t\t\t\t\t// x-offset\n\t\t\t\t\t i,\t\t\t\t\t// y-offset\n\t\t\t\t\t full_row_texture_width,\t// width\n\t\t\t\t\t 1,\t\t\t\t\t// height\n\t\t\t\t\t gl.RGBA,\t\t\t// format\n\t\t\t\t\t gl.FLOAT,\t\t\t// type\n\t\t\t\t\t row\t\t\t// data\n\t\t\t\t );\n\t\t\t}\n\n\t\t\tremainder = new Float32Array(texels.buffer, full_texel_row_end * texels.BYTES_PER_ELEMENT, rem);\n\t\t\tlast_texel.set(remainder); // copy remaining data\n\n\t\t\tgl.texSubImage2D(gl.TEXTURE_2D,\n\t\t\t\t 0,\t\t\t\t// mip-map level\n\t\t\t\t full_row_texture_width, // x-offset\n\t\t\t\t i,\t\t\t\t// y-offset\n\t\t\t\t 1,\t\t\t\t// width\n\t\t\t\t 1,\t\t\t\t// height\n\t\t\t\t gl.RGBA,\t\t// format\n\t\t\t\t gl.FLOAT,\t\t// type\n\t\t\t\t last_texel\t\t// data\n\t\t\t );\n\t\t}\n\t}\n\n\t// clamp to edge to support non-power of two textures\n\tgl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);\n\tgl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);\n\n\t// don't interpolate when getting data from texture\n\tgl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);\n\tgl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);\n\n\t// we're done with setup, so unbind current texture\n\tgl.bindTexture(gl.TEXTURE_2D, null);\n\n\treturn texture;\n};\n\n/* Create a (padded) texture suitable for reading into an array with readPixels.\n\tUNSIGNED_BYTE\n   Can be passed to bindDestinationTexture.\n\n   Returns an unsigned byte RGBA texture (other formats are not yet supported\n\ton most platforms, see WEBGL_color_buffer_float extension)\n */\nWebGL.prototype.createOutputTexture = function(h, w) {\n\tvar gl = this.context;\n\n\tvar pad = this.getPad(w);\n\n\t// create and bind texture to render to\n\tvar destTexture = gl.createTexture();\n\t//gl.activeTexture(gl.TEXTURE2);\n\tgl.bindTexture(gl.TEXTURE_2D, destTexture);\n\tgl.texImage2D(gl.TEXTURE_2D,/*level*/0, gl.RGBA, w + pad, h, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);\n\n\t// clamp to edge to support non-power of two textures\n\tgl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);\n\tgl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);\n\t// don't interpolate when getting data from texture\n\tgl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);\n\tgl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);\n\n\t// we're done with setup, so unbind current texture\n\tgl.bindTexture(gl.TEXTURE_2D, null);\n\n\treturn destTexture;\n};\n\n/* Set up output\n\n\tM - number of rows in output\n\tN - number of columns in output\n\tdstTex - texture for holding the output\n */\nWebGL.prototype.bindOutputTexture = function(M, N, texture) {\n\tvar gl = this.context;\n\n\t// set canvas and viewport size\n\tthis.canvas.height = M;\n\tthis.canvas.width = N;\n\tgl.viewport(0, 0, N, M);\n\n\t// create and bind framebuffer\n\tthis.framebuffer = this.framebuffer || gl.createFramebuffer();\n\n\tgl.bindFramebuffer(gl.FRAMEBUFFER, this.framebuffer);\n\n\tgl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, /*level*/0);\n\n\n\tif( gl.checkFramebufferStatus(gl.FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE)\n\t\tthrow new Error(\"Bound framebuffer is not complete.\");\n\n\treturn this.framebuffer;\n};\n\nWebGL.prototype.unbindInputTexture = function(textureUnit){\n\tvar gl = this.context;\n\n\tgl.activeTexture(textureUnit);\n\tgl.bindTexture(gl.TEXTURE_2D, null);\n};\n\n/* Read data out as unsigned bytes */\nWebGL.prototype.readData = function(M, N){\n\tvar gl = this.context;\n\n\t// create destination buffer\n\trawbuffer = new ArrayBuffer(M*N*Float32Array.BYTES_PER_ELEMENT);\n\n\t// read the result into our buffer, as bytes\n\tprod = new Uint8Array(rawbuffer);\n\tgl.readPixels(0, 0, N, M, gl.RGBA, gl.UNSIGNED_BYTE, prod);\n\n\t// return raw result bytes\n\treturn rawbuffer; // M x N\n};\n\n// how many extra elements do we need to fill up a pixel?\nWebGL.prototype.getPad = function(N){\n\n\tvar rem = (N % WebGL.COMPONENTS_PER_TEXEL),\n\t\tpad = rem == 0 ? 0 : WebGL.COMPONENTS_PER_TEXEL - rem;\n\n\treturn pad;\n};\n","var WebGL = require('./webgl');\n\n/*  Linearize onto Kernels, a transformation similar to im2col, which\n\ttransforms the input to a convolution kernel into a row.\n\n\tX - input data\n\tk - kernal width\n\tstride - number of elements between beginnings of patches\n\n\n\twebgl - a weblas.WebGL object\n\tstandalone - whether or not to automatically run the floating point encode\n\t\tstep for rendering to an UNSIGNED_BYTE texture (this is required for\n\t\tmobile, circa 2015) but can't be used as part of a pipeline.\n\n\t* uploads and downloads data\n\t* executes calculation\n */\nfunction SLOKNCalculator(webgl, standalone){\n\tthis.webgl = webgl,\n\tthis.standalone = (standalone != null) ? standalone : true; // default to standalone mode\n\n\tvar p = \"precision highp float;\\n#define GLSLIFY 1\\n\\nvarying vec2      outTex;  // texture coords of row/column to calculate\\nuniform sampler2D X;       // texture with data from padded A\\nuniform float     factor;  // width of image patch\\nuniform float     stride;  // width between image patches\\nuniform float     margin;\\nuniform float     N_p;     // patches across\\nuniform float     M;\\nuniform float     N;\\nuniform float     pad;\\nuniform float     M_in;\\nuniform float     N_in;\\nuniform float     C;       // number of channels in input\\nuniform float     pad_in;\\n\\n// select an element from a vector based on index\\nfloat select_index_1540259130(vec4 v, int index){\\n\\tfloat val;\\n\\tif (index == 0) {\\n\\t\\tval = v.r;\\n\\t} else if(index == 1) {\\n\\t\\tval = v.g;\\n\\t} else if(index == 2) {\\n\\t\\tval = v.b;\\n\\t} else if(index == 3){\\n\\t\\tval = v.a;\\n\\t} else {\\n\\t\\t// should never be here\\n\\t\\tval = 0.0;\\n\\t}\\n\\n\\treturn val;\\n}\\n\\n// translate a linear index into x, y coordinates for a matrix\\nvec2 linear_index_coords_1604150559(float linear_index, float row_length){\\n\\tvec2 coords;\\n\\n\\tcoords.x = floor(mod(linear_index + 0.5, row_length)); // column\\n\\tcoords.y = floor((linear_index + 0.5) / row_length); // row\\n\\n\\treturn coords;\\n}\\n\\n// set pad values to 0.0, if in padded region of output texture\\nvoid fix_pad_1117569599(inout vec4 v, int pad){\\n\\tv.a = 0.0;\\n\\tif(pad == 2){\\n\\t\\tv.b = 0.0;\\n\\t} else if(pad == 3){\\n\\t\\tv.b = 0.0;\\n\\t\\tv.g = 0.0;\\n\\t}\\n}\\n\\nvoid main(void) {\\n\\n\\t// get the implied row and column from .y and .x of passed (output)\\n\\t// texture coordinate\\n\\tfloat row_t = outTex.y;\\n\\tfloat col_t = outTex.x;\\n\\n\\t// row corresponds to patch\\n\\tfloat row = floor(row_t * M) + 0.5;\\n\\t// column corresponds to placement in patch\\n\\tfloat col_0 = floor(col_t * (N + pad) - 1.5); // index of first element in output pixel (matrix space)\\n\\n\\t// N_p = patches across\\n\\tfloat col_patch = floor(mod(row, N_p)); // column index in grid of patches\\n\\tfloat row_patch = floor(row / N_p); // row index in grid of patches\\n\\tfloat col_in_0 = (col_patch * stride - margin) * C; // input column index of left element in patch\\n\\tfloat row_in_0 = row_patch * stride - margin; // input row index of top element in patch\\n\\n\\tvec4 pixel_in;\\n\\tvec4 result = vec4(0.0, 0.0, 0.0, 0.0);\\n\\tvec2 coords = linear_index_coords_1604150559(col_0, factor * C); // coords inside patch\\n\\tvec2 ncoords;\\n\\tint channel_in = int(mod(col_in_0 + coords.x, 4.0));\\n\\tvec2 scale_in = vec2(1.0/(N_in + pad_in), 1.0/M_in); // scale from matrix to input texture coords\\n\\tvec2 offset_in = vec2(col_in_0 + 2.0 - float(channel_in), row_in_0 + 0.5); // offset into patch (and pixel)\\n\\n\\tconst vec2 pixel_scale = vec2(1.0/4.0, 1.0); // scale from matrix to pixel coords\\n\\n\\tpixel_in = texture2D(X, (coords + offset_in) * scale_in);\\n\\n\\t// go through channels for current output pixel\\n\\tfor(int channel = 0; channel < 4; channel++){\\n\\n\\t\\t// are we on a new input pixel?\\n\\t\\tncoords = linear_index_coords_1604150559(col_0 + float(channel), factor * C);\\n\\n\\t\\t// are we in the margin or outside the input texture?\\n\\t\\tif((col_in_0 + ncoords.x + 0.5 < 0.0) || (row_in_0 + ncoords.y + 0.5 < 0.0) ||\\n\\t\\t   (col_in_0 + ncoords.x + 0.5) > (N_in) || row_in_0 + ncoords.y + 0.5 > M_in){\\n\\t\\t\\t// yes, create a virtual pixel\\n\\t\\t\\tpixel_in = vec4(0.0, 0.0, 0.0, 0.0);\\n\\t\\t} else if(floor(ncoords * pixel_scale) != floor(coords * pixel_scale)){\\n\\t\\t\\t// no, get the get the next real pixel\\n\\t\\t\\tcoords = ncoords;\\n\\t\\t\\toffset_in.x += float(channel_in);\\n\\t\\t\\tchannel_in = 0;\\n\\t\\t\\tpixel_in = texture2D(X, (coords + offset_in) * scale_in);\\n\\t\\t}\\n\\n\\t\\tif(channel == 0){\\n\\t\\t\\tresult.r = select_index_1540259130(pixel_in, channel_in);\\n\\t\\t} else if(channel == 1){\\n\\t\\t\\tresult.g = select_index_1540259130(pixel_in, channel_in);\\n\\t\\t} else if(channel == 2){\\n\\t\\t\\tresult.b = select_index_1540259130(pixel_in, channel_in);\\n\\t\\t} else {\\n\\t\\t\\tresult.a = select_index_1540259130(pixel_in, channel_in);\\n\\t\\t}\\n\\n\\t\\tchannel_in++;\\n\\t\\toffset_in.x -= 1.0;\\n\\t}\\n\\n\\t// fix padded region\\n\\tif(pad > 0.0 && col_0 + 4.0 > N ) {\\n\\t\\tfix_pad_1117569599(result, int(pad));\\n\\t}\\n\\n\\t//gl_FragColor = vec4(row_in_0, col_in_0, channel_in, N_p);\\n\\tgl_FragColor = result;\\n}\\n\";\n\n\t// create the webgl shader program for this calculation\n\t// based on the specific fragment shader for this calculation\n\t// and the generic pass through shader\n\tif(this.standalone){\n\t\tthis.program = this.webgl.createProgram(s);\n\t} else {\n\t\tthis.program = this.webgl.createProgram(p);\n\t}\n}\n\nmodule.exports = SLOKNCalculator;\n\n/* Names of the uniforms (variables) used in the shader program passed in on\n   each calculation.\n */\nSLOKNCalculator.TEXTURE_UNIFORM_NAME_0 = \"X\";\nSLOKNCalculator.STRIDE_UNIFORM_NAME = \"stride\";\nSLOKNCalculator.KERNEL_WIDTH_UNIFORM_NAME = \"factor\";\n\n/* Elementwise scale and offset a matrix\n\n\tM - number of rows in X\n\tN - number of columns in X\n\ta - scalar coefficient to X\n\tb - scalar offset of X\n\tX - matrix (texture)\n\tout - output (texture)\n\n  How this works:\n\n  1. Activate our shader program\n  2. Bind input textures\n  3. Set shader program parameters\n  4. Bind output texture\n  5. Activate calculation with `drawElements`\n\n */\nSLOKNCalculator.prototype.calculate = function(M, N, channels, M_out, N_out, N_p, factor, stride, margin, X, out){\n\n\tvar gl = this.webgl.context;\n\n\tvar pad = this.webgl.getPad(N * channels),\n\t\tpad_out = this.webgl.getPad(N_out);\n\n\tthis.webgl.selectProgram(this.program);\n\n\t// create and bind our input texture using matrix data\n\tthis.bindInputTexture(X, gl.TEXTURE0, SLOKNCalculator.TEXTURE_UNIFORM_NAME_0);\n\n\t// set the data specific variables in our shader program\n\tthis.bindUniforms(M_out, N_out, pad_out, M, N * channels, channels, pad, N_p, factor, stride, margin);\n\n\t// create our destination texture\n\tif(this.standalone){\n\t\tthis.webgl.bindOutputTexture(M_out, N_out + pad_out, out);\n\t} else {\n\t\tthis.webgl.bindOutputTexture(M_out, (N_out + pad_out)/ 4, out);\n\t}\n\n\n\t// initiate calculation\n\tgl.drawElements(gl.TRIANGLES, /*num items*/6, gl.UNSIGNED_SHORT, 0);\n\n\tthis.webgl.unbindInputTexture(gl.TEXTURE0);\n\n};\n\n/* Create a texture from the given texel data and bind it to our shader program.\n\n\ttexture - texture containing the data\n\ttextureUnit - the texture unit to bind to (gl.TEXTURE0, gl.TEXTURE1, etc)\n\tname - the uniform name to associate with (must match shader program)\n\n\tmust compile program (with createProgram) first\n*/\nSLOKNCalculator.prototype.bindInputTexture = function(texture, textureUnit, name){\n\tvar gl = this.webgl.context,\n\t\tprogram = this.program;\n\n\tgl.activeTexture(textureUnit); // gl.TEXTURE0, gl.TEXTURE1, etc\n\tgl.bindTexture(\t  gl.TEXTURE_2D, texture);\n\n\tvar sampler = gl.getUniformLocation(program, name);\n\tgl.uniform1i(sampler, textureUnit - gl.TEXTURE0);\n\n};\n\n/* Set up inputs for the texture shader\n\n */\nSLOKNCalculator.prototype.bindUniforms = function(M, N, pad, M_in, N_in, channels, pad_in, N_p, factor, stride, margin) {\n\tvar gl = this.webgl.context;\n\n\t// get var locations\n\tvar M_gl = gl.getUniformLocation(this.program, \"M\"),\n\t\tN_gl = gl.getUniformLocation(this.program, \"N\"),\n\t\tc_gl = gl.getUniformLocation(this.program, \"C\"),\n\t\tM_in_gl = gl.getUniformLocation(this.program, \"M_in\"),\n\t\tN_in_gl = gl.getUniformLocation(this.program, \"N_in\"),\n\t\tstride_gl = gl.getUniformLocation(this.program, SLOKNCalculator.STRIDE_UNIFORM_NAME),\n\t\tfactor_gl = gl.getUniformLocation(this.program, SLOKNCalculator.KERNEL_WIDTH_UNIFORM_NAME),\n\t\tpad_gl = gl.getUniformLocation(this.program, \"pad\"),\n\t\tpad_in_gl = gl.getUniformLocation(this.program, \"pad_in\"),\n\t\tN_p_gl = gl.getUniformLocation(this.program, \"N_p\");\n\t\tmargin_gl = gl.getUniformLocation(this.program, \"margin\");\n\n\t// bind length of shared dimension\n\tgl.uniform1f(M_gl, M);\n\tgl.uniform1f(N_gl, N);\n\tgl.uniform1f(pad_gl, pad);\n\tgl.uniform1f(M_in_gl, M_in);\n\tgl.uniform1f(N_in_gl, N_in);\n\tgl.uniform1f(c_gl, channels);\n\tgl.uniform1f(pad_in_gl, pad_in);\n\tgl.uniform1f(N_p_gl, N_p);\n\tgl.uniform1f(factor_gl, factor);\n\tgl.uniform1f(stride_gl, stride);\n\tgl.uniform1f(margin_gl, margin);\n\n};\n"]}