suite.testUsingWebGLFloatTextures("data-floats", () => { let data2x2 = new Float32Array([ 0, 0.003, 42, -5, Math.PI, Math.E, Math.sqrt(2), 0.1, 1, 0.5, -1, -2, Math.log(3), Math.sin(5), Math.cos(7), Math.exp(11) ]); assertThat(Shaders.data(data2x2).readRawFloatOutputs(2)).isEqualTo(data2x2); let data2x4 = new Float32Array(Seq.range(2*4*4).map(e => e*e + (e - Math.sqrt(2)) / 3).toArray()); assertThat(Shaders.data(data2x4).readRawFloatOutputs(3)).isEqualTo(data2x4); assertThrows(() => Shaders.data(data2x4).readRawFloatOutputs(2)); });
suite.testUsingWebGL("sumFold", () => { let raws = makePseudoShaderWithInputsAndOutputAndCode([], Outputs.float(), ` float outputFor(float k) { return k*k; } `)().toVecFloatTexture(3); assertThat(Shaders.sumFoldFloat(raws).readVecFloatOutputs(2)).isEqualTo(new Float32Array([ 16, 1+25, 4+36, 9+49 ])); assertThat(Shaders.sumFoldFloatAdjacents(raws).readVecFloatOutputs(2)).isEqualTo(new Float32Array([ 1, 4+9, 16+25, 36+49 ])); raws.deallocByDepositingInPool(); let coords = makePseudoShaderWithInputsAndOutputAndCode([], Outputs.vec2(), ` vec2 outputFor(float k) { return vec2(mod(k, 2.0), floor(k/2.0)); } `)().toVec2Texture(3); assertThat(Shaders.sumFoldVec2(coords).readVec2Outputs(2)).isEqualTo(new Float32Array([ 0,2, 2,2, 0,4, 2,4 ])); assertThat(Shaders.sumFoldVec2Adjacents(coords).readVec2Outputs(2)).isEqualTo(new Float32Array([ 1,0, 1,2, 1,4, 1,6, ])); coords.deallocByDepositingInPool(); let solid = makePseudoShaderWithInputsAndOutputAndCode([], Outputs.vec4(), ` vec4 outputFor(float k) { return vec4(2.0, 3.0, 5.0, 7.0); } `)().toVec4Texture(2); assertThat(Shaders.sumFoldVec4(solid).readVec4Outputs(1)).isEqualTo(new Float32Array([ 4,6,10,14, 4,6,10,14 ])); solid.deallocByDepositingInPool(); });
suite.testUsingWebGL("amplitudesToProbabilities", () => { let inp = Shaders.vec2Data(new Float32Array([ 2, 3, 4, 5, 6, 7, 8, 9, 1/2, 0, 0, 1/4, 0, 1/8, 1/16, 0 ])).toVec2Texture(3); let con = CircuitShaders.controlMask(Controls.NONE).toBoolTexture(3); assertThat(amplitudesToProbabilities(inp, con).readVecFloatOutputs(3)).isApproximatelyEqualTo(new Float32Array([ 4+9, 16+25, 36+49, 64+81, 1/4, 1/16, 1/64, 1/256 ])); inp.deallocByDepositingInPool(); con.deallocByDepositingInPool(); });
assertThrows(() => { let tex = Shaders.data(new Uint8Array([0, 0, 0, 0])).toRawByteTexture(0); try { SHADER_CODER_FLOATS.vec4.inputPartGetter('a').argsFor(tex); } finally { tex.deallocByDepositingInPool(); } });
suite.testUsingWebGLFloatTextures("color", () => { assertThat(Shaders.color(2, 3, -5, 7.5).readRawFloatOutputs(2)).isEqualTo(new Float32Array([ 2, 3, -5, 7.5, 2, 3, -5, 7.5, 2, 3, -5, 7.5, 2, 3, -5, 7.5 ])); assertThat(Shaders.color(1.5, 2, 0, 121).readRawFloatOutputs(3)).isEqualTo(new Float32Array([ 1.5, 2, 0, 121, 1.5, 2, 0, 121, 1.5, 2, 0, 121, 1.5, 2, 0, 121, 1.5, 2, 0, 121, 1.5, 2, 0, 121, 1.5, 2, 0, 121, 1.5, 2, 0, 121 ])); });
CircuitShaders.controlMask = controlMask => { if (controlMask.isEqualTo(Controls.NONE)) { return Shaders.color(1, 0, 0, 0); } return CONTROL_MASK_SHADER( WglArg.float('used', controlMask.inclusionMask), WglArg.float('desired', controlMask.desiredValueMask)); };
CircuitShaders.controlSelect = (controlMask, dataTexture) => { if (controlMask.isEqualTo(Controls.NONE)) { return Shaders.passthrough(dataTexture); } return CONTROL_SELECT_SHADER( dataTexture, WglArg.float('used', controlMask.inclusionMask), WglArg.float('desired', controlMask.desiredValueMask)); };
suite.testUsingWebGLFloatTextures("vec4Input", () => { let param = currentShaderCoder().vec4.inputPartGetter('test_input'); let shader = combinedShaderPartsWithCode([param], ` void main() { vec2 xy = gl_FragCoord.xy - vec2(0.5, 0.5); float k = xy.y * 4.0 + xy.x; gl_FragColor = read_test_input(k); }`); let floats = randomFloat32Array(64); let spread = currentShaderCoder().vec4.dataToPixels(floats); let texSquare = Shaders.data(spread).toVec4Texture(4); assertThat(shader.withArgs(...param.argsFor(texSquare)).readRawFloatOutputs(4)).isEqualTo(floats); texSquare.deallocByDepositingInPool(); });
/** * @param {function(!CircuitEvalContext)} updateAction * @param {!Matrix} matrix * @param {!number|undefined=} forcedTime */ function assertThatCircuitMutationActsLikeMatrix_single(updateAction, matrix, forcedTime=undefined) { let qubitSpan = Math.round(Math.log2(matrix.height())); let extraWires = Math.floor(Math.random()*5); let time = Math.random(); let qubitIndex = Math.floor(Math.random() * extraWires); if (USE_SIMPLE_VALUES) { extraWires = 0; time = 0; qubitIndex = 0; } if (forcedTime !== undefined) { time = forcedTime; } let wireCount = qubitSpan + extraWires; let controls = Controls.NONE; for (let i = 0; i < extraWires; i++) { if (Math.random() < 0.5) { controls = controls.and(Controls.bit(i + (i < qubitIndex ? 0 : qubitSpan), Math.random() < 0.5)); } } let ampCount = 1 << wireCount; let inVec = Matrix.generate(1, ampCount, () => USE_SIMPLE_VALUES ? (Math.random() < 0.5 ? 1 : 0) : new Complex(Math.random()*10 - 5, Math.random()*10 - 5)); let tex = Shaders.vec2Data(inVec.rawBuffer()).toVec2Texture(wireCount); let trader = new WglTextureTrader(tex); let controlsTexture = CircuitShaders.controlMask(controls).toBoolTexture(wireCount); let ctx = new CircuitEvalContext( time, qubitIndex, wireCount, controls, controlsTexture, trader, new Map()); updateAction(ctx); controlsTexture.deallocByDepositingInPool(); let outData = KetTextureUtil.tradeTextureForVec2Output(trader); let outVec = new Matrix(1, ampCount, outData); let expectedOutVec = matrix.applyToStateVectorAtQubitWithControls(inVec, qubitIndex, controls); assertThat(outVec).withInfo({matrix, inVec, ctx}).isApproximatelyEqualTo(expectedOutVec, 0.005); }
suite.testUsingWebGLFloatTextures("boolInputs", () => { let inp = BOOL_TYPE_CODER.inputPartGetter('a'); let shader = combinedShaderPartsWithCode([inp], ` void main() { vec2 xy = gl_FragCoord.xy - vec2(0.5, 0.5); float k = xy.y * 4.0 + xy.x; gl_FragColor = vec4(read_a(k), k, 0.0, 0.0); }`); let tex = Shaders.data(new Uint8Array([255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 0, 0, 0])).toRawByteTexture(2); assertThat(shader.withArgs(...inp.argsFor(tex)).readRawFloatOutputs(2)).isEqualTo(new Float32Array([ 1, 0, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 1, 3, 0, 0 ])); tex.deallocByDepositingInPool(); });
/** * @param {!int} wireCount The number of wires in the circuit. * @param {!function(!CircuitEvalContext)} updateAction The actual update action. * @param {!function(!int) : !int} permutation The expected permutation. * @param {*} permuteInfo Debug info included when the assertion fails. */ function assertThatCircuitUpdateActsLikePermutation(wireCount, updateAction, permutation, permuteInfo=undefined) { let time = Math.random(); let ampCount = 1 << wireCount; let inVec = Matrix.generate(1, ampCount, r => new Complex(r + Math.random(), Math.random()*1000)); let tex = Shaders.vec2Data(inVec.rawBuffer()).toVec2Texture(wireCount); let trader = new WglTextureTrader(tex); let controlsTexture = CircuitShaders.controlMask(Controls.NONE).toBoolTexture(wireCount); let ctx = new CircuitEvalContext( time, 0, wireCount, Controls.NONE, controlsTexture, trader, new Map()); updateAction(ctx); controlsTexture.deallocByDepositingInPool(); let outData = KetTextureUtil.tradeTextureForVec2Output(trader); let outVec = new Matrix(1, ampCount, outData); for (let i = 0; i < ampCount; i++) { let j = permutation(i); let inVal = inVec.cell(0, i); let outVal = outVec.cell(0, j); if (!outVal.isApproximatelyEqualTo(inVal, 0.001)) { let actualIn = Math.floor(outVec.cell(0, j).real); let actualOut = Seq.range(ampCount).filter(k => Math.floor(outVec.cell(0, k).real) === i).first('[NONE]'); assertThat(outVal). withInfo({i, j, actualIn, actualOut, permuteInfo}). isApproximatelyEqualTo(inVal, 0.01); } } // Increment assertion count. assertTrue(true); }
suite.testUsingWebGLFloatTextures("passthrough", () => { let coords = new WglShader(` void main() { gl_FragColor = vec4(gl_FragCoord.x-0.5, gl_FragCoord.y-0.5, 0.0, 0.0); }`).withArgs(); let input = new WglTexture(2, 4, WebGLRenderingContext.FLOAT); coords.renderTo(input); let result = new WglTexture(2, 4, WebGLRenderingContext.FLOAT); Shaders.passthrough(input).renderTo(result); assertThat(result.readPixels()).isEqualTo(new Float32Array([ 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 2, 0, 0, 1, 2, 0, 0, 0, 3, 0, 0, 1, 3, 0, 0 ])); input.ensureDeinitialized(); result.ensureDeinitialized(); });
suite.testUsingWebGL("data-bytes", () => { let bytes4x4 = new Uint8Array(Seq.range(4*4*4).map(e => Math.floor(Math.random() * 256)).toArray()); assertThat(Shaders.data(bytes4x4).readRawByteOutputs(4)).isEqualTo(bytes4x4); });
assertThrows(() => Shaders.data(data2x4).readRawFloatOutputs(2));