Skip to content

Commit

Permalink
Added CircuitEvalContext.applyOperation
Browse files Browse the repository at this point in the history
  • Loading branch information
Strilanc committed Oct 16, 2016
1 parent 10a283e commit aef92c6
Show file tree
Hide file tree
Showing 18 changed files with 84 additions and 63 deletions.
3 changes: 1 addition & 2 deletions src/circuit/CircuitDefinition.js
Original file line number Diff line number Diff line change
Expand Up @@ -778,8 +778,7 @@ class CircuitDefinition {

for (let [i, j] of this.columns[colIndex].swapPairs()) {
//noinspection JSUnusedAssignment
ctx.stateTrader.shadeAndTrade(
CircuitShaders.swap(ctx.withRow(i + ctx.row), j + ctx.row));
ctx.applyOperation(CircuitShaders.swap(ctx.withRow(i + ctx.row), j + ctx.row));
}
}

Expand Down
11 changes: 11 additions & 0 deletions src/circuit/CircuitEvalContext.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import {WglConfiguredShader} from "src/webgl/WglConfiguredShader.js"

/**
* Values used by the various gate effects.
*
Expand Down Expand Up @@ -39,6 +41,15 @@ class CircuitEvalContext {
this.customContextFromGates = customContextFromGates;
}

/**
* @param {!WglConfiguredShader|!function(!CircuitEvalContext) : !WglConfiguredShader} operation
* @return {void}
*/
applyOperation(operation) {
let configuredShader = operation instanceof WglConfiguredShader ? operation : operation(this);
this.stateTrader.shadeAndTrade(configuredShader);
}

/**
* @returns {!CircuitEvalContext}
* @private
Expand Down
1 change: 1 addition & 0 deletions src/circuit/CircuitShaders.js
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ const CONTROL_SELECT_SHADER = makePseudoShaderWithInputsAndOutputAndCode(
*
* @param {!CircuitEvalContext} ctx
* @param {!int} otherRow
* @returns {!WglConfiguredShader}
*/
CircuitShaders.swap = (ctx, otherRow) =>
SWAP_QUBITS_SHADER.withArgs(...ketArgs(ctx, otherRow - ctx.row + 1));
Expand Down
2 changes: 1 addition & 1 deletion src/circuit/Gate.js
Original file line number Diff line number Diff line change
Expand Up @@ -446,7 +446,7 @@ class Gate {
withCustomShaders(shaderFuncs) {
return this.withCustomOperation(ctx => {
for (let shaderFunc of shaderFuncs) {
ctx.stateTrader.shadeAndTrade(_ => shaderFunc(ctx));
ctx.applyOperation(shaderFunc);
}
});
}
Expand Down
13 changes: 6 additions & 7 deletions src/circuit/GateShaders.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,20 +21,19 @@ class GateShaders {}
*
* @param {!CircuitEvalContext} ctx
* @param {!Matrix} matrix
* @returns {!WglConfiguredShader}
*/
let singleQubitOperationFunc = (ctx, matrix) => {
function _applySingleQubitOperationFunc(ctx, matrix) {
if (matrix.width() !== 2 || matrix.height() !== 2) {
throw new DetailedError("Not a single-qubit operation.", {matrix});
}
let [ar, ai, br, bi, cr, ci, dr, di] = matrix.rawBuffer();
return CUSTOM_SINGLE_QUBIT_OPERATION_SHADER.withArgs(
ctx.applyOperation(CUSTOM_SINGLE_QUBIT_OPERATION_SHADER.withArgs(
...ketArgs(ctx),
WglArg.vec2("a", ar, ai),
WglArg.vec2("b", br, bi),
WglArg.vec2("c", cr, ci),
WglArg.vec2("d", dr, di));
};
WglArg.vec2("d", dr, di)));
}

const CUSTOM_SINGLE_QUBIT_OPERATION_SHADER = ketShader(
'uniform vec2 a, b, c, d;',
Expand Down Expand Up @@ -73,7 +72,7 @@ const matrix_operation_shaders = [
*/
GateShaders.applyMatrixOperation = (ctx, matrix) => {
if (matrix.width() === 2) {
ctx.stateTrader.shadeAndTrade(_ => singleQubitOperationFunc(ctx, matrix));
_applySingleQubitOperationFunc(ctx, matrix);
return;
}
if (!Util.isPowerOf2(matrix.width())) {
Expand All @@ -83,7 +82,7 @@ GateShaders.applyMatrixOperation = (ctx, matrix) => {
throw new DetailedError("Matrix is past 4 qubits. Too expensive.", {ctx, matrix});
}
let shader = matrix_operation_shaders[Math.round(Math.log2(matrix.width())) - 2];
ctx.stateTrader.shadeAndTrade(_ => shader.withArgs(
ctx.applyOperation(shader.withArgs(
...ketArgs(ctx),
WglArg.float_array("coefs", matrix.rawBuffer())));
};
Expand Down
6 changes: 3 additions & 3 deletions src/gates/FourierTransformGates.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import {WglConfiguredShader} from "src/webgl/WglConfiguredShader.js"
* @param {!number=} factor Scaling factor for the applied phases.
*/
function applyControlledPhaseGradient(ctx, qubitSpan, factor=1) {
ctx.stateTrader.shadeAndTrade(_ => CONTROLLED_PHASE_GRADIENT_SHADER.withArgs(
ctx.applyOperation(CONTROLLED_PHASE_GRADIENT_SHADER.withArgs(
...ketArgs(ctx, qubitSpan),
WglArg.float("factor", factor)));
}
Expand All @@ -45,7 +45,7 @@ let FourierTransformGates = {};
*/
function applyForwardGradientShaders(ctx, span) {
if (span > 1) {
ctx.stateTrader.shadeAndTrade(_ => reverseShaderForSize(span)(ctx));
ctx.applyOperation(reverseShaderForSize(span));
}
for (let i = 0; i < span; i++) {
if (i > 0) {
Expand All @@ -67,7 +67,7 @@ function applyBackwardGradientShaders(ctx, span) {
}
}
if (span > 1) {
ctx.stateTrader.shadeAndTrade(_ => reverseShaderForSize(span)(ctx));
ctx.applyOperation(reverseShaderForSize(span));
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/gates/ReverseBitsGate.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ let reverseShaders = Seq.range(Config.MAX_WIRE_COUNT).map(_generateReverseShader

/**
* @param {!int} span
* @returns {!function(!CircuitEvalContext) : void}
* @returns {!function(!CircuitEvalContext) : !WglConfiguredShader}
*/
let reverseShaderForSize = span => ctx => reverseShaders[span].withArgs(...ketArgs(ctx, span));

Expand Down
8 changes: 5 additions & 3 deletions src/webgl/WglTextureTrader.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {WglTexture} from "src/webgl/WglTexture.js"
import {Shaders} from "src/webgl/Shaders.js"
import {WglConfiguredShader} from "src/webgl/WglConfiguredShader.js"
import {WglTexture} from "src/webgl/WglTexture.js"
import {WglTexturePool} from "src/webgl/WglTexturePool.js"

/**
Expand Down Expand Up @@ -34,7 +35,7 @@ class WglTextureTrader {
* Applies the given shader function to the trader's old texture, renders it onto a new texture, deallocs the old
* texture, and finally holds on to the new texture.
*
* @param {!function(!WglTexture) : !WglConfiguredShader} shaderFunc
* @param {!WglConfiguredShader|!function(!WglTexture) : !WglConfiguredShader} shaderFunc
* @param {undefined|!WglTexture} newTexture The texture to take and shade. If undefined, a texture matching the old
* texture is taken from the texture pool.
* @returns {void}
Expand All @@ -44,7 +45,8 @@ class WglTextureTrader {
let deallocSrc = !this._dontDeallocFlag;
let dst = newTexture || WglTexturePool.takeSame(src);

shaderFunc(src).renderTo(dst);
let configuredShader = shaderFunc instanceof WglConfiguredShader ? shaderFunc : shaderFunc(src);
configuredShader.renderTo(dst);

this.currentTexture = dst;
this._dontDeallocFlag = false;
Expand Down
22 changes: 11 additions & 11 deletions test/CircuitOperationTestUtil.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,29 +22,29 @@ if (USE_SIMPLE_VALUES) {
* @param {!Matrix} matrix
* @param {!int=} repeats
*/
function assertThatRandomTestOfCircuitShaderActsLikeMatrix(shaderFunc, matrix, repeats=5) {
assertThatRandomTestOfCircuitOperationActsLikeMatrix(
ctx => ctx.stateTrader.shadeAndTrade(_ => shaderFunc(ctx)),
function assertThatCircuitShaderActsLikeMatrix(shaderFunc, matrix, repeats=5) {
assertThatCircuitUpdateActsLikeMatrix(
ctx => ctx.applyOperation(shaderFunc),
matrix,
repeats);
}

/**
* @param {function(!CircuitEvalContext) : void} operation
* @param {function(!CircuitEvalContext) : void} updateAction
* @param {!Matrix} matrix
* @param {!int=} repeats
*/
function assertThatRandomTestOfCircuitOperationActsLikeMatrix(operation, matrix, repeats=5) {
function assertThatCircuitUpdateActsLikeMatrix(updateAction, matrix, repeats=5) {
for (let i = 0; i < repeats; i++) {
assertThatRandomTestOfCircuitOperationActsLikeMatrix_single(operation, matrix);
assertThatCircuitMutationActsLikeMatrix_single(updateAction, matrix);
}
}

/**
* @param {function(!CircuitEvalContext) : void} operation
* @param {function(!CircuitEvalContext) : void} updateAction
* @param {!Matrix} matrix
*/
function assertThatRandomTestOfCircuitOperationActsLikeMatrix_single(operation, matrix) {
function assertThatCircuitMutationActsLikeMatrix_single(updateAction, matrix) {
let qubitSpan = Math.round(Math.log2(matrix.height()));
let extraWires = Math.floor(Math.random()*5);
let time = Math.random();
Expand Down Expand Up @@ -78,7 +78,7 @@ function assertThatRandomTestOfCircuitOperationActsLikeMatrix_single(operation,
controlsTexture,
trader,
new Map());
operation(ctx);
updateAction(ctx);

let outData = workingShaderCoder.unpackVec2Data(trader.currentTexture.readPixels());
let outVec = new Matrix(1, ampCount, outData);
Expand All @@ -91,6 +91,6 @@ function assertThatRandomTestOfCircuitOperationActsLikeMatrix_single(operation,
}

export {
assertThatRandomTestOfCircuitOperationActsLikeMatrix,
assertThatRandomTestOfCircuitShaderActsLikeMatrix
assertThatCircuitUpdateActsLikeMatrix,
assertThatCircuitShaderActsLikeMatrix
}
21 changes: 15 additions & 6 deletions test/circuit/CircuitComputeUtil.test.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {Suite, assertThat, assertThrows, assertTrue, assertFalse} from "test/TestUtil.js"
import {CircuitDefinition} from "src/circuit/CircuitDefinition.js"
import {circuitDefinitionToGate, advanceStateWithCircuit} from "src/circuit/CircuitComputeUtil.js"
import {assertThatRandomTestOfCircuitOperationActsLikeMatrix} from "test/CircuitOperationTestUtil.js"
import {assertThatCircuitUpdateActsLikeMatrix} from "test/CircuitOperationTestUtil.js"

import {Complex} from "src/math/Complex.js"
import {Controls} from "src/circuit/Controls.js"
Expand Down Expand Up @@ -40,7 +40,7 @@ suite.webGlTest("nestedControls", () => {
-?-
-/-`, ['?', cnot]);
let ccnot_matrix = Matrix.PAULI_X.expandedForQubitInRegister(2, 3, new Controls(3, 3));
assertThatRandomTestOfCircuitOperationActsLikeMatrix(
assertThatCircuitUpdateActsLikeMatrix(
ctx => advanceStateWithCircuit(ctx, ccnot_circuit, false),
ccnot_matrix);
});
Expand All @@ -59,7 +59,7 @@ suite.webGlTest("multiNestedControls", () => {
-/-
-•-`, ['?', i_notcc]);
let shifted_notccc_matrix = Matrix.PAULI_X.expandedForQubitInRegister(2, 6, new Controls(7<<3, 7<<3));
assertThatRandomTestOfCircuitOperationActsLikeMatrix(
assertThatCircuitUpdateActsLikeMatrix(
ctx => advanceStateWithCircuit(ctx, shifted_notccc_circuit, false),
shifted_notccc_matrix);
});
Expand All @@ -71,7 +71,7 @@ suite.webGlTest("innerAndOuterInputs", () => {
-/-
-b-`, ['?', plus_a_times]);
let notcc_matrix = Matrix.PAULI_X.expandedForQubitInRegister(0, 3, new Controls(6, 6));
assertThatRandomTestOfCircuitOperationActsLikeMatrix(
assertThatCircuitUpdateActsLikeMatrix(
ctx => advanceStateWithCircuit(ctx, notcc_circuit, false),
notcc_matrix);
});
Expand All @@ -87,7 +87,7 @@ suite.webGlTest("doublyNestedInputs", () => {
-/-
-/-`, ['?', plus_a_times_b]);
let shifted_notcc_matrix = Matrix.PAULI_X.expandedForQubitInRegister(1, 4, new Controls(12, 12));
assertThatRandomTestOfCircuitOperationActsLikeMatrix(
assertThatCircuitUpdateActsLikeMatrix(
ctx => advanceStateWithCircuit(ctx, shifted_notcc_circuit, false),
shifted_notcc_matrix);
});
Expand All @@ -108,7 +108,16 @@ suite.webGlTest("rawAddition", () => {
a &= 15;
return a | (b << 4);
});
assertThatRandomTestOfCircuitOperationActsLikeMatrix(
assertThatCircuitUpdateActsLikeMatrix(
ctx => advanceStateWithCircuit(ctx, adder, false),
matrix);
});


suite.webGlTest('swap', () => {
let circ = circuit(`-S-
-S-`, ['S', Gates.Special.SwapHalf]);
assertThatCircuitUpdateActsLikeMatrix(
ctx => advanceStateWithCircuit(ctx, circ, false),
Gates.Special.SwapHalf.knownMatrixAt(0));
});
6 changes: 3 additions & 3 deletions test/circuit/CircuitShaders.test.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {Suite, assertThat, assertThrows} from "test/TestUtil.js"
import {assertThatRandomTestOfCircuitShaderActsLikeMatrix} from "test/CircuitOperationTestUtil.js"
import {assertThatCircuitShaderActsLikeMatrix} from "test/CircuitOperationTestUtil.js"
import {CircuitShaders} from "src/circuit/CircuitShaders.js"

import {Complex} from "src/math/Complex.js"
Expand Down Expand Up @@ -333,15 +333,15 @@ suite.webGlTest("qubitDensities", () => {
});

suite.webGlTest("swap", () => {
assertThatRandomTestOfCircuitShaderActsLikeMatrix(
assertThatCircuitShaderActsLikeMatrix(
ctx => CircuitShaders.swap(ctx, ctx.row + 1),
Matrix.square(
1,0,0,0,
0,0,1,0,
0,1,0,0,
0,0,0,1));

assertThatRandomTestOfCircuitShaderActsLikeMatrix(
assertThatCircuitShaderActsLikeMatrix(
ctx => CircuitShaders.swap(ctx, ctx.row + 2),
Matrix.square(
1,0,0,0,0,0,0,0,
Expand Down
4 changes: 2 additions & 2 deletions test/circuit/GateShaders.test.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {Suite, assertThat, assertThrows} from "test/TestUtil.js"
import {CircuitShaders} from "src/circuit/CircuitShaders.js"
import {GateShaders} from "src/circuit/GateShaders.js"
import {assertThatRandomTestOfCircuitOperationActsLikeMatrix} from "test/CircuitOperationTestUtil.js"
import {assertThatCircuitUpdateActsLikeMatrix} from "test/CircuitOperationTestUtil.js"

import {Complex} from "src/math/Complex.js"
import {Controls} from "src/circuit/Controls.js"
Expand Down Expand Up @@ -30,7 +30,7 @@ suite.webGlTest("matrixOperation", () => {
for (let size = 1; size < 5; size++) {
let d = 1<<size;
let matrix = Matrix.generate(d, d, () => new Complex(Math.random() - 0.5, Math.random() - 0.5));
assertThatRandomTestOfCircuitOperationActsLikeMatrix(
assertThatCircuitUpdateActsLikeMatrix(
ctx => GateShaders.applyMatrixOperation(ctx, matrix),
matrix,
repeats);
Expand Down
8 changes: 4 additions & 4 deletions test/circuit/KetShaderUtil.test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {Suite, assertThat, assertThrows, assertTrue, assertFalse} from "test/TestUtil.js"
import {ketArgs, ketShader, ketShaderPermute, ketShaderPhase} from "src/circuit/KetShaderUtil.js"
import {assertThatRandomTestOfCircuitShaderActsLikeMatrix} from "test/CircuitOperationTestUtil.js"
import {assertThatCircuitShaderActsLikeMatrix} from "test/CircuitOperationTestUtil.js"
import {Complex} from "src/math/Complex.js"
import {Matrix} from "src/math/Matrix.js"
import {WglArg} from "src/webgl/WglArg.js"
Expand All @@ -12,7 +12,7 @@ suite.webGlTest("ketShader", () => {
'uniform vec2 a, b, c, d;',
'return cmul(inp(0.0), a+(c-a)*out_id) + cmul(inp(1.0), b+(d-b)*out_id);',
1);
assertThatRandomTestOfCircuitShaderActsLikeMatrix(
assertThatCircuitShaderActsLikeMatrix(
ctx => shader.withArgs(
...ketArgs(ctx),
WglArg.vec2("a", 2, 3),
Expand All @@ -27,7 +27,7 @@ suite.webGlTest("ketShaderPermute", () => {
'',
'return mod(out_id + 1.0, 4.0);',
2);
assertThatRandomTestOfCircuitShaderActsLikeMatrix(
assertThatCircuitShaderActsLikeMatrix(
ctx => shader.withArgs(...ketArgs(ctx)),
Matrix.generateTransition(4, i => (i - 1) & 3));
});
Expand All @@ -37,7 +37,7 @@ suite.webGlTest("ketShaderPhase", () => {
'',
'return vec2(cos(out_id/10.0), sin(out_id/10.0));',
3);
assertThatRandomTestOfCircuitShaderActsLikeMatrix(
assertThatCircuitShaderActsLikeMatrix(
ctx => shader.withArgs(...ketArgs(ctx)),
Matrix.generateDiagonal(8, i => Complex.polar(1, i/10)));
});
12 changes: 6 additions & 6 deletions test/gates/ArithmeticGates.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import {Suite} from "test/TestUtil.js"
import {incrementShaderFunc, ArithmeticGates} from "src/gates/ArithmeticGates.js"
import {InputGates} from "src/gates/InputGates.js"
import {
assertThatRandomTestOfCircuitShaderActsLikeMatrix,
assertThatRandomTestOfCircuitOperationActsLikeMatrix
assertThatCircuitShaderActsLikeMatrix,
assertThatCircuitUpdateActsLikeMatrix
} from "test/CircuitOperationTestUtil.js"
import {advanceStateWithCircuit} from "src/circuit/CircuitComputeUtil.js"

Expand All @@ -14,17 +14,17 @@ import {Matrix} from "src/math/Matrix.js"
let suite = new Suite("ArithmeticGates");

suite.webGlTest('increment', () => {
assertThatRandomTestOfCircuitShaderActsLikeMatrix(
assertThatCircuitShaderActsLikeMatrix(
ctx => incrementShaderFunc(ctx, 3, 5),
Matrix.generateTransition(8, e => (e+5)&7));

assertThatRandomTestOfCircuitShaderActsLikeMatrix(
assertThatCircuitShaderActsLikeMatrix(
ctx => incrementShaderFunc(ctx, 2, -3),
Matrix.generateTransition(4, e => (e-3)&3));
});

suite.webGlTest('plus_A', () => {
assertThatRandomTestOfCircuitOperationActsLikeMatrix(
assertThatCircuitUpdateActsLikeMatrix(
ctx => advanceStateWithCircuit(
ctx,
new CircuitDefinition(4, [new GateColumn([
Expand All @@ -38,7 +38,7 @@ suite.webGlTest('plus_A', () => {
});

suite.webGlTest('minus_A', () => {
assertThatRandomTestOfCircuitOperationActsLikeMatrix(
assertThatCircuitUpdateActsLikeMatrix(
ctx => advanceStateWithCircuit(
ctx,
new CircuitDefinition(4, [new GateColumn([
Expand Down
Loading

0 comments on commit aef92c6

Please sign in to comment.